Rev 114 | Go to most recent revision | 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_BOTH 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 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();
HANDLE hSimConnect = NULL;
bool keep_going = false;
bool Paused = true;
char string[80];
bool updateLeds = true;
char ledStatus = 0x00;
struct Struct1 {
double comm_1;
double comm_2;
double comm_both;
};
static enum DATA_DEFINE_ID {
DEFINITION_1,
};
static enum DATA_REQUEST_ID {
REQUEST_1,
};
static enum EVENT_ID {
EVENT_BRAKES,
EVENT_COM1_TRANSMIT_SELECT,
EVENT_COM2_TRANSMIT_SELECT,
EVENT_COM_RECEIVE_ALL_TOGGLE,
};
static enum INPUT_ID {
INPUT0,
};
static enum GROUP_ID {
GROUP0,
};
int main(int argc, char **argv) {
usb_dev_handle *handle = NULL;
handle = usbOpenDevice(0x4242, "newioit.com.au", 0xe231, "Comm Selector");
if(handle == NULL) {
fprintf(stderr, "Could not find USB device\n");
exit(1);
}
//testCode(handle);
Connect();
if (hSimConnect != NULL) {
keep_going = true;
int nBytes = 0;
char buffer[16];
int i;
for (i = 0; i < 15; i++) {
buffer[i] = 0x00;
}
nBytes = usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_LEDS_SET, ledStatus, 0, (char *)buffer, sizeof(buffer), 5000);
unsigned int lastButtons = 0;
while(keep_going)
{
HRESULT hr;
// Put this in an 'On Event' thing later...
hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_1, DEFINITION_1, 0, SIMCONNECT_SIMOBJECT_TYPE_USER);
nBytes = usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_LEDS_SET, ledStatus, 0, (char *)buffer, sizeof(buffer), 5000);
nBytes = usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
USB_STATE_READ, 0, 0, (char *)buffer, sizeof(buffer), 5000);
unsigned int buttons = (unsigned int)buffer[1];
if (rbi(buttons, BUTTONS_COM1) && rbi(lastButtons, BUTTONS_COM1) == 0) {
sbi(lastButtons, BUTTONS_COM1);
hr = SimConnect_TransmitClientEvent(hSimConnect,0,EVENT_COM1_TRANSMIT_SELECT, 1 ,SIMCONNECT_GROUP_PRIORITY_STANDARD,SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
printf("\n%s COM1 pressed.", Format_SOL(M_IN));
}
if (rbi(lastButtons, BUTTONS_COM1) && rbi(buttons, BUTTONS_COM1) == 0x00) {
cbi(lastButtons, BUTTONS_COM1);
printf("\n%s COM1 released.", Format_SOL(M_IN));
}
if (rbi(buttons, BUTTONS_COM2) && rbi(lastButtons, BUTTONS_COM2) == 0) {
sbi(lastButtons, BUTTONS_COM2);
hr = SimConnect_TransmitClientEvent(hSimConnect,0,EVENT_COM2_TRANSMIT_SELECT, 1 ,SIMCONNECT_GROUP_PRIORITY_STANDARD,SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
printf("\n%s COM2 pressed.", Format_SOL(M_IN));
}
if (rbi(lastButtons, BUTTONS_COM2) && rbi(buttons, BUTTONS_COM2) == 0x00) {
cbi(lastButtons, BUTTONS_COM2);
printf("\n%s COM2 released.", Format_SOL(M_IN));
}
if (rbi(buttons, BUTTONS_BOTH) && rbi(lastButtons, BUTTONS_BOTH) == 0) {
sbi(lastButtons, BUTTONS_BOTH);
hr = SimConnect_TransmitClientEvent(hSimConnect,0,EVENT_COM_RECEIVE_ALL_TOGGLE, 1 ,SIMCONNECT_GROUP_PRIORITY_STANDARD,SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
printf("\n%s BOTH pressed.", Format_SOL(M_IN));
}
if (rbi(lastButtons, BUTTONS_BOTH) && rbi(buttons, BUTTONS_BOTH) == 0x00) {
cbi(lastButtons, BUTTONS_BOTH);
printf("\n%s BOTH released.", Format_SOL(M_IN));
}
if (rbi(buttons, BUTTONS_NAV1) && rbi(lastButtons, BUTTONS_NAV1) == 0) {
sbi(lastButtons, BUTTONS_NAV1);
hr = SimConnect_TransmitClientEvent(hSimConnect,0,EVENT_BRAKES, 1 ,SIMCONNECT_GROUP_PRIORITY_STANDARD,SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
printf("\n%s Buttons brakes engaged.", Format_SOL(M_IN));
}
if (rbi(lastButtons, BUTTONS_NAV1) && rbi(buttons, BUTTONS_NAV1) == 0x00) {
cbi(lastButtons, BUTTONS_NAV1);
printf("\n%s Button brakes released.", Format_SOL(M_IN));
}
SimConnect_CallDispatch(hSimConnect, dispatchProc, NULL);
Sleep(1);
}
Disconnect();
} else {
// Implement retrying
}
// Keeps the window open. Uses old test code
// so state of CommSelector can be tested
//testCode(handle);
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 while opening a SimConnect connection", 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;
keep_going = false;
}
void CALLBACK dispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
{
switch(pData->dwID)
{
case SIMCONNECT_RECV_ID_QUIT:
// FSX is stopping
Process_FSX_Quit();
break;
case SIMCONNECT_RECV_ID_OPEN:
// the connection process is complete
Process_Connected();
break;
case SIMCONNECT_RECV_ID_EVENT: {
SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*)pData;
switch (evt->uEventID) {
case EVENT_BRAKES:
printf("\nEvent brakes: %d", evt->dwData);
break;
case EVENT_COM1_TRANSMIT_SELECT:
printf("\nEvent com1 select: %d", evt->dwData);
break;
case EVENT_COM2_TRANSMIT_SELECT:
printf("\nEvent com1 select: %d", evt->dwData);
break;
case EVENT_COM_RECEIVE_ALL_TOGGLE:
printf("\nEvent com1 select: %d", evt->dwData);
break;
default:
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;
Struct1 *pS = (Struct1*)&pObjData->dwData;
if (pS->comm_1)
sbi(ledStatus, BUTTONS_COM1);
else
cbi(ledStatus, BUTTONS_COM1);
if (pS->comm_2)
sbi(ledStatus, BUTTONS_COM2);
else
cbi(ledStatus, BUTTONS_COM2);
if (pS->comm_both)
sbi(ledStatus, BUTTONS_BOTH);
else
cbi(ledStatus, BUTTONS_BOTH);
updateLeds = true;
//printf("\nTransmit Both: %f", pS->comm_both );
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_SIMOBJECT_DATA:
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 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_BRAKES, "brakes");
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_AddClientEventToNotificationGroup(hSimConnect, GROUP0, EVENT_BRAKES);
hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP0, EVENT_COM1_TRANSMIT_SELECT);
hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP0, EVENT_COM2_TRANSMIT_SELECT);
hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP0, EVENT_COM_RECEIVE_ALL_TOGGLE);
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_MapInputEventToClientEvent(hSimConnect, INPUT0, "shift+ctrl+u", EVENT_BRAKES);
//hr = SimConnect_SetInputGroupState(hSimConnect, INPUT0, SIMCONNECT_STATE_ON);
}
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 ***
*/
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;
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", buffer[i]);
}
printf("\n");
}
Sleep(1);
}
}