Rev 116 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <lusb0_usb.h>
#include "SimConnect.h"
#define sbi(sfr, bit) ((sfr) |= 1 << bit)
#define cbi(sfr, bit) ((sfr) &= ~(1 << bit))
#define xbi(sfr, bit) ((sfr) ^= 1 << bit)
#define rbi(sfr, bit) (((sfr) >> (bit)) & 0x01)
// Same as in main.c
#define USB_STATE_READ 100
#define USB_LEDS_SET 101
// Console symbols
char* M_OUT = " :<- "; // message outbound
char* M_IN = "->: "; // message inbound
char* M_NO = " : "; // not a message
char* I_SP = " "; // space
char* I_OK = "+"; // ignored, ok
char* I_NEX = "?"; // ignored, unexpected
char* I_EXE = "e"; // exception
char* X_SEP = "|"; // separator
#define BUTTONS_COM1 0
#define BUTTONS_COM2 1
#define BUTTONS_COMB 2
#define BUTTONS_NAV1 3
#define BUTTONS_NAV2 4
#define BUTTONS_MKR 5
#define BUTTONS_DME 6
#define BUTTONS_ADF 7
static usb_dev_handle * usbOpenDevice(int vendor, char *vendorName, int product, char *productName);
static int usbGetDescriptorString(usb_dev_handle *dev, int index, int langid, char *buf, int buflen);
void testCode(usb_dev_handle *handle);
void setLed(double value, int bit);
void usbPushLeds(void);
void usbGetState(void);
void CALLBACK dispatchProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext);
void Process_Exception(SIMCONNECT_RECV* pData);
void Process_Connected();
void Process_FSX_Quit();
char* Exception_String(DWORD Recv_Exception);
char* RECV_Msg_String(DWORD Recv_ID);
char* Format_SOL(char* Direction);
char* Format_SOL(char* Direction, char* Importance);
void Connect();
void Disconnect();
usb_dev_handle *handle = NULL;
HANDLE hSimConnect = NULL;
bool keep_going = false;
bool Paused = true;
char string[80];
bool updateLeds = true;
char ledStatus = 0x00;
int nBytes = 0;
unsigned char buffer[16];
struct CommSelectData {
double com1;
double com2;
double comb;
double vor1;
double vor2;
double mkr;
double dme;
double adf;
};
static enum DATA_DEFINE_ID {
DEFINITION_1,
};
static enum DATA_REQUEST_ID {
REQUEST_1,
};
static enum EVENT_ID {
EVENT_COM1_TRANSMIT_SELECT,
EVENT_COM2_TRANSMIT_SELECT,
EVENT_COM_RECEIVE_ALL_TOGGLE,
EVENT_RADIO_VOR1_IDENT_TOGGLE,
EVENT_RADIO_VOR2_IDENT_TOGGLE,
EVENT_MARKER_SOUND_TOGGLE,
EVENT_RADIO_DME1_IDENT_TOGGLE,
EVENT_RADIO_ADF_IDENT_TOGGLE,
};
static enum INPUT_ID {
INPUT0,
};
static enum GROUP_ID {
GROUP0,
};
int main(int argc, char **argv) {
handle = usbOpenDevice(0x4242, "newioit.com.au", 0xe231, "Comm Selector");
if(handle == NULL) {
fprintf(stderr, "Could not find USB device\n");
exit(1);
}
//testCode(handle);
//exit(0);
int i;
for (i = 0; i < 15; i++) {
buffer[i] = 0x00;
}
usbPushLeds();
while (hSimConnect == NULL) {
Connect();
if (hSimConnect == NULL)
Sleep(10000);
}
keep_going = true;
unsigned int lastButtons = 0;
while(keep_going) {
HRESULT hr;
usbGetState();
unsigned char buttons = (unsigned char)buffer[1];
for (i=0; i<=7; i++) {
if (rbi(buttons, i) && rbi(lastButtons, i) == 0) {
sbi(lastButtons, i);
hr = SimConnect_TransmitClientEvent(hSimConnect,0, i, 1 ,
SIMCONNECT_GROUP_PRIORITY_STANDARD,SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
}
if (rbi(lastButtons, i) && ! rbi(buttons, i))
cbi(lastButtons, i);
}
SimConnect_CallDispatch(hSimConnect, dispatchProc, NULL);
Sleep(1);
}
Disconnect();
usb_close(handle);
return 0;
}
void Connect() {
HRESULT hr;
if (hSimConnect == NULL) {
printf("\n%s Requesting a SimConnect connection", Format_SOL(M_OUT));
hr = SimConnect_Open(&hSimConnect, "Comm Selector", NULL, 0, 0, 0);
if (hr != S_OK) {
// FSX may be inactive, or there is a problem
printf("\n%s Error %d: Sleeping 10 seconds and retrying", Format_SOL(M_IN, I_OK), hr);
} else {
// Connection to FSX initialized
printf("\n%s Connection request being processed (%d)", Format_SOL(M_IN), hSimConnect);
// (When connection process completes, an OPEN message will be received)
}
}
}
void Disconnect() {
HRESULT hr;
if (hSimConnect != NULL) {
if (hr = SimConnect_Close(hSimConnect) == S_OK) {
printf("\n%s Connection closed (%d).", Format_SOL(M_IN), hSimConnect);
} else {
printf("\n%s Error (%d) while closing the connection (%d).", Format_SOL(M_IN, I_NEX), hr, hSimConnect);
}
}
printf("\n%s Resetting internal status to disconnected.", Format_SOL(M_NO));
hSimConnect = NULL;
ledStatus = 0x00;
usbPushLeds();
keep_going = false;
}
void CALLBACK dispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
{
switch(pData->dwID)
{
case SIMCONNECT_RECV_ID_QUIT:
Process_FSX_Quit();
break;
case SIMCONNECT_RECV_ID_OPEN:
Process_Connected();
break;
case SIMCONNECT_RECV_ID_EVENT: {
SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*)pData;
/*
switch (evt->uEventID) {
default:
break;
}
*/
break;
}
case SIMCONNECT_RECV_ID_SIMOBJECT_DATA: {
SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE*)pData;
switch(pObjData->dwRequestID) {
case REQUEST_1: {
DWORD ObjectID = pObjData->dwObjectID;
CommSelectData *ps = (CommSelectData*)&pObjData->dwData;
setLed(ps->com1, BUTTONS_COM1);
setLed(ps->com2, BUTTONS_COM2);
setLed(ps->comb, BUTTONS_COMB);
setLed(ps->vor1, BUTTONS_NAV1);
setLed(ps->vor2, BUTTONS_NAV2);
setLed(ps->mkr, BUTTONS_MKR);
setLed(ps->dme, BUTTONS_DME);
setLed(ps->adf, BUTTONS_ADF);
usbPushLeds();
break;
}
}
break;
}
case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE: {
SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE*)pData;
switch(pObjData->dwRequestID) {
case REQUEST_1: {
DWORD ObjectID = pObjData->dwObjectID;
CommSelectData *pS = (CommSelectData*)&pObjData->dwData;
HRESULT hr;
hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, ObjectID,
SIMCONNECT_PERIOD_SIM_FRAME, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);
break;
}
}
break;
}
/* Not found
case SIMCONNECT_RECV_ID_EVENT_WEATHER_MODE:
case SIMCONNECT_RECV_ID_AIRPORT_LIST:
case SIMCONNECT_RECV_ID_VOR_LIST:
case SIMCONNECT_RECV_ID_NDB_LIST:
case SIMCONNECT_RECV_ID_WAYPOINT_LIST:
case SIMCONNECT_RECV_ID_EVENT_MULTIPLAYER_SERVER_STARTED:
case SIMCONNECT_RECV_ID_EVENT_MULTIPLAYER_CLIENT_STARTED:
case SIMCONNECT_RECV_ID_EVENT_MULTIPLAYER_SESSION_ENDED:
case SIMCONNECT_RECV_ID_EVENT_RACE_END:
case SIMCONNECT_RECV_ID_EVENT_RACE_LAP: */
case SIMCONNECT_RECV_ID_EXCEPTION:
case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE:
case SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID:
case SIMCONNECT_RECV_ID_EVENT_FILENAME:
case SIMCONNECT_RECV_ID_EVENT_FRAME:
case SIMCONNECT_RECV_ID_WEATHER_OBSERVATION:
case SIMCONNECT_RECV_ID_CLOUD_STATE:
case SIMCONNECT_RECV_ID_RESERVED_KEY:
case SIMCONNECT_RECV_ID_CUSTOM_ACTION:
case SIMCONNECT_RECV_ID_SYSTEM_STATE:
case SIMCONNECT_RECV_ID_CLIENT_DATA:
printf("\n%s Message ignored (%s)", RECV_Msg_String(pData->dwID), Format_SOL(M_IN, I_OK));
break;
default:
printf("\n%s Message ignored (Unknown RECV_ID)", Format_SOL(M_IN, I_NEX));
}
}
void setLed(double value, int bit) {
if (value)
sbi(ledStatus, bit);
else
cbi(ledStatus, bit);
}
void Process_Exception(SIMCONNECT_RECV* pData) {
// SimConnect cannot process a client request
SIMCONNECT_RECV_EXCEPTION *except = (SIMCONNECT_RECV_EXCEPTION *) pData;
printf("\n%s Exception %d on packet %d, argument %d. (%s)", Format_SOL(M_IN, I_EXE),
except->dwException, except->dwSendID, except->dwIndex,
Exception_String(except->dwException));
}
void Process_Connected() {
printf("\n%s Connected.", Format_SOL(M_IN));
HRESULT hr;
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_COM1_TRANSMIT_SELECT, "COM1_TRANSMIT_SELECT");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_COM2_TRANSMIT_SELECT, "COM2_TRANSMIT_SELECT");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_COM_RECEIVE_ALL_TOGGLE, "COM_RECEIVE_ALL_TOGGLE");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_RADIO_VOR1_IDENT_TOGGLE, "RADIO_VOR1_IDENT_TOGGLE");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_RADIO_VOR2_IDENT_TOGGLE, "RADIO_VOR2_IDENT_TOGGLE");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_MARKER_SOUND_TOGGLE, "MARKER_SOUND_TOGGLE");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_RADIO_DME1_IDENT_TOGGLE, "RADIO_DME1_IDENT_TOGGLE");
hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_RADIO_ADF_IDENT_TOGGLE, "RADIO_ADF_IDENT_TOGGLE");
/*
hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP0, EVENT_COM1_TRANSMIT_SELECT);
hr = SimConnect_SetNotificationGroupPriority(hSimConnect, GROUP0, SIMCONNECT_GROUP_PRIORITY_HIGHEST);
*/
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "COM TRANSMIT:1", "Bool");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "COM TRANSMIT:2", "Bool");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "COM RECIEVE ALL", "Bool");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "NAV SOUND:1", "Bool");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "NAV SOUND:2", "Bool");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "MARKER SOUND", "Bool");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "DME SOUND", "Bool");
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "ADF SOUND:1", "Bool");
hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_1, DEFINITION_1, 0, SIMCONNECT_SIMOBJECT_TYPE_USER);
}
void Process_FSX_Quit() {
// Stop sending commands to SimConnect
keep_going = false;
}
char* Exception_String(DWORD Recv_Exception)
{
// Names of Exceptions
char* EXCEPTION_String[] =
{
"NONE", "ERROR", "SIZE_MISMATCH", "UNRECOGNIZED_ID", "UNOPENED", "VERSION_MISMATCH", "TOO_MANY_GROUPS",
"NAME_UNRECOGNIZED", "TOO_MANY_EVENT_NAMES", "EVENT_ID_DUPLICATE", "TOO_MANY_MAPS",
"TOO_MANY_OBJECTS", "TOO_MANY_REQUESTS", "WEATHER_INVALID_PORT", "WEATHER_INVALID_METAR",
"WEATHER_UNABLE_TO_GET_OBSERVATION", "WEATHER_UNABLE_TO_CREATE_STATION",
"WEATHER_UNABLE_TO_REMOVE_STATION", "INVALID_DATA_TYPE", "INVALID_DATA_SIZE",
"DATA_ERROR", "INVALID_ARRAY", "CREATE_OBJECT_FAILED", "LOAD_FLIGHTPLAN_FAILED",
"OPERATION_INVALID_FOR_OBJECT_TYPE", "ILLEGAL_OPERATION", "ALREADY_SUBSCRIBED", "INVALID_ENUM",
"DEFINITION_ERROR", "DUPLICATE_ID", "DATUM_ID", "OUT_OF_BOUNDS", "ALREADY_CREATED",
"OBJECT_OUTSIDE_REALITY_BUBBLE", "OBJECT_CONTAINER", "OBJECT_AI", "OBJECT_ATC", "OBJECT_SCHEDULE",
};
// Return "unknown" if out of bound
return Recv_Exception > ARRAYSIZE(EXCEPTION_String) ? "unknown" : EXCEPTION_String[Recv_Exception];
}
// Format the beginning of the console line, one argument
char* Format_SOL(char* Direction)
{
return Format_SOL(Direction, I_SP);
}
// Format the beginning of the console line, two arguments
char* Format_SOL(char* Direction, char* Importance)
{
strcpy_s( string, Direction);
strcat_s( string, Importance);
strcat_s( string, X_SEP);
return string;
}
// Returns the description of the message id
char* RECV_Msg_String(DWORD Recv_ID)
{
// Names of RECV_ID (type of message to dispatch)
char* RECV_ID_String[] =
{
"RECV_ID_EXCEPTION", "RECV_ID_OPEN", "RECV_ID_QUIT", "RECV_ID_EVENT",
"RECV_ID_EVENT_OBJECT_ADDREMOVE", "RECV_ID_EVENT_FILENAME", "RECV_ID_EVENT_FRAME",
"RECV_ID_SIMOBJECT_DATA", "RECV_ID_SIMOBJECT_DATA_BYTYPE",
"RECV_ID_WEATHER_OBSERVATION", "RECV_ID_CLOUD_STATE", "RECV_ID_ASSIGNED_OBJECT_ID",
"RECV_ID_RESERVED_KEY", "RECV_ID_CUSTOM_ACTION", "RECV_ID_SYSTEM_STATE",
"RECV_ID_CLIENT_DATA", "RECV_ID_EVENT_WEATHER_MODE", "RECV_ID_AIRPORT_LIST",
"RECV_ID_VOR_LIST", "RECV_ID_NDB_LIST", "RECV_ID_WAYPOINT_LIST",
"RECV_ID_EVENT_MULTIPLAYER_SERVER_STARTED", "RECV_ID_EVENT_MULTIPLAYER_CLIENT_STARTED",
"RECV_ID_EVENT_MULTIPLAYER_SESSION_ENDED", "RECV_ID_EVENT_RACE_END",
"RECV_ID_EVENT_RACE_LAP",
};
// Return "unknown" if out of bound
return Recv_ID > ARRAYSIZE(RECV_ID_String) ? "unknown" : RECV_ID_String[Recv_ID];
}
/*
* *** USB Functions ***
*/
void usbPushLeds() {
nBytes = usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_LEDS_SET, ledStatus, 0, (char *)buffer, sizeof(buffer), 5000);
}
void usbGetState() {
nBytes = usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_STATE_READ, 0, 0, (char *)buffer, sizeof(buffer), 5000);
}
static int usbGetDescriptorString(usb_dev_handle *dev, int index, int langid,
char *buf, int buflen) {
char buffer[256];
int rval, i;
// make standard request GET_DESCRIPTOR, type string and given index
// (e.g. dev->iProduct)
rval = usb_control_msg(dev,
USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid,
buffer, sizeof(buffer), 1000);
if(rval < 0) // error
return rval;
// rval should be bytes read, but buffer[0] contains the actual response size
if((unsigned char)buffer[0] < rval)
rval = (unsigned char)buffer[0]; // string is shorter than bytes read
if(buffer[1] != USB_DT_STRING) // second byte is the data type
return 0; // invalid return type
// we're dealing with UTF-16LE here so actual chars is half of rval,
// and index 0 doesn't count
rval /= 2;
/* lossy conversion to ISO Latin1 */
for(i = 1; i < rval && i < buflen; i++) {
if(buffer[2 * i + 1] == 0)
buf[i-1] = buffer[2 * i];
else
buf[i-1] = '?'; /* outside of ISO Latin1 range */
}
buf[i-1] = 0;
return i-1;
}
static usb_dev_handle * usbOpenDevice(int vendor, char *vendorName,
int product, char *productName) {
struct usb_bus *bus;
struct usb_device *dev;
char devVendor[256], devProduct[256];
usb_dev_handle * handle = NULL;
usb_init();
usb_find_busses();
usb_find_devices();
for(bus=usb_get_busses(); bus; bus=bus->next) {
for(dev=bus->devices; dev; dev=dev->next) {
if(dev->descriptor.idVendor != vendor ||
dev->descriptor.idProduct != product)
continue;
/* we need to open the device in order to query strings */
if(!(handle = usb_open(dev))) {
fprintf(stderr, "Warning: cannot open USB device: %s\n",
usb_strerror());
continue;
}
/* get vendor name */
if(usbGetDescriptorString(handle, dev->descriptor.iManufacturer, 0x4242, devVendor, sizeof(devVendor)) < 0) {
fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror());
usb_close(handle);
continue;
}
/* get product name */
if(usbGetDescriptorString(handle, dev->descriptor.iProduct, 0xe231, devProduct, sizeof(devVendor)) < 0) {
fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror()); usb_close(handle);
continue;
}
if(strcmp(devVendor, vendorName) == 0 && strcmp(devProduct, productName) == 0)
return handle;
else
usb_close(handle);
}
}
return NULL;
}
void testCode(usb_dev_handle *handle) {
int nBytes = 0;
unsigned char buffer[16];
int i;
for (i = 0; i < 15; i++) {
buffer[i] = 0x00;
}
char ledStatus = 0;
char keyIn = 0x00;
// Return to old testing code
printf("Press ESC to continue... (Or debug codes)\n");
while (1) {
keyIn = _getch();
printf("Key: %02X\n", keyIn);
if (keyIn == 0x1B || keyIn == 0x71) {
return;
} else if (keyIn >= 0x31 && keyIn <= 0x38) {
char j = atoi(&keyIn);
xbi(ledStatus, (j-1) );
nBytes = usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_LEDS_SET, ledStatus, 0, (char *)buffer, sizeof(buffer), 5000);
} else if(keyIn == 'r') {
nBytes = usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_STATE_READ, 0, 0, (char *)buffer, sizeof(buffer), 5000);
printf("Got %d bytes: %s\n", nBytes, buffer);
for (i = 0; i < 15; i++) {
if (i>0) printf(":");
printf("%02X", (unsigned char)buffer[i]);
}
printf("\n");
}
Sleep(1);
}
}