11/*
22 * Flight Simulator Instrument Data Link
3- * Copyright (c) 2023 Scott Vincent
3+ * Copyright (c) 2024 Scott Vincent
44 */
55
66#include < windows.h>
@@ -33,20 +33,23 @@ long networkIn;
3333long networkOut;
3434#endif
3535
36- // Comment the following line out if you don't want to reduce rudder sensitivity
37- // #define RUDDER_SENSITIVITY
36+ // Comment the following line out if you don't have a Raspberry Pi Pico USB device
37+ #define PICO_JOYSTICK
3838
39- #ifdef RUDDER_SENSITIVITY
39+ #ifdef PICO_JOYSTICK
4040#include < Mmsystem.h>
4141#include < joystickapi.h>
4242
43- void joystickInit ();
44- void joystickRefresh ();
43+ void picoInit ();
44+ void picoRefresh ();
4545
4646int joystickId = -1 ;
4747int joystickRetry = 5 ;
48+ bool zeroed = false ;
49+ double zeroPos[4 ];
50+ bool modeChange = false ;
51+ JOYCAPSA joyCaps;
4852JOYINFOEX joyInfo;
49- double rudderSensitivity = 1 ;
5053#endif
5154
5255enum FLIGHT_PHASE {
@@ -71,6 +74,8 @@ bool is747 = false;
7174bool isK100 = false ;
7275bool isPA28 = false ;
7376bool isAirliner = false ;
77+ bool isNewAircraft = false ;
78+ char prevAircraft[32 ] = " \0 " ;
7479double lastHeading = 0 ;
7580int lastSoftkey = 0 ;
7681int lastG1000Key = 0 ;
@@ -216,6 +221,12 @@ void CALLBACK MyDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void* pContex
216221 isK100 = false ;
217222 isPA28 = false ;
218223 isAirliner = false ;
224+ isNewAircraft = false ;
225+
226+ if (strcmp (simVars.aircraft , prevAircraft) != 0 ) {
227+ strcpy (prevAircraft, simVars.aircraft );
228+ isNewAircraft = true ;
229+ }
219230
220231 if (strncmp (simVars.aircraft , " A310" , 4 ) == 0 || strncmp (simVars.aircraft , " Airbus A310" , 11 ) == 0 ) {
221232 isA310 = true ;
@@ -403,6 +414,15 @@ void CALLBACK MyDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void* pContex
403414 completedTakeOff = false ;
404415 }
405416
417+ #ifdef PICO_JOYSTICK
418+ // Populate simvars for Pico USB switchbox
419+ picoRefresh ();
420+
421+ if (isNewAircraft) {
422+ simVars.sbMode = 0 ; // Default to autopilot
423+ }
424+ #endif
425+
406426 if (fixedPushback != -1 ) {
407427 // Pushback goes wrong sometimes (pushbackState == 4)
408428 fixedPushback++;
@@ -560,14 +580,6 @@ void init()
560580 addReadDefs ();
561581 mapEvents ();
562582
563- for (int i = 0 ; i < 7 ; i++) {
564- if (i < 4 ) {
565- simVars.sbEncoder [i] = 0 ;
566- }
567- simVars.sbButton [i] = 1 ;
568- }
569- simVars.sbMode = 3 ; // Autopilot / Radio / Instruments
570-
571583 // Start requesting data
572584 if (SimConnect_RequestDataOnSimObject (hSimConnect, REQ_ID, DEF_READ_ALL, SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD_VISUAL_FRAME, 0 , 0 , 0 , 0 ) != 0 ) {
573585 printf (" Failed to start requesting data\n " );
@@ -603,7 +615,7 @@ void cleanUp()
603615
604616int __cdecl _tmain (int argc, _TCHAR* argv[])
605617{
606- printf (" Instrument Data Link %s Copyright (c) 2023 Scott Vincent\n " , versionString);
618+ printf (" Instrument Data Link %s Copyright (c) 2024 Scott Vincent\n " , versionString);
607619
608620 // Yield so server can start
609621 Sleep (100 );
@@ -952,31 +964,6 @@ void processG1000Events()
952964 time (&lastG1000Press);
953965}
954966
955- void processSwitchBox (int joyNum)
956- {
957- switch (joyNum) {
958- case 1 : simVars.sbEncoder [0 ]++; break ;
959- case 2 : simVars.sbEncoder [0 ]--; break ;
960- case 3 : simVars.sbButton [0 ]++; break ;
961- case 4 : simVars.sbEncoder [1 ]++; break ;
962- case 5 : simVars.sbEncoder [1 ]--; break ;
963- case 6 : simVars.sbButton [1 ]++; break ;
964- case 7 : simVars.sbEncoder [2 ]++; break ;
965- case 8 : simVars.sbEncoder [2 ]--; break ;
966- case 9 : simVars.sbButton [2 ]++; break ;
967- case 10 : simVars.sbEncoder [3 ]++; break ;
968- case 11 : simVars.sbEncoder [3 ]--; break ;
969- case 12 : simVars.sbButton [3 ]++; break ;
970- case 13 : simVars.sbButton [4 ]++; break ;
971- case 14 : simVars.sbButton [5 ]++; break ;
972- case 15 : simVars.sbButton [6 ]++; break ;
973- case 17 : simVars.sbMode = 1 ; break ; // Autopilot
974- case 18 : simVars.sbMode = 2 ; break ; // Radio
975- case 19 : simVars.sbMode = 3 ; break ; // Instruments
976- case 20 : simVars.sbMode = 4 ; break ; // Navigation
977- }
978- }
979-
980967void processRequest (int bytes)
981968{
982969 // // For testing only - Leave commented out
@@ -1004,11 +991,6 @@ void processRequest(int bytes)
1004991 }
1005992 writeJetbridgeVar (A310_ENG_IGNITION, value);
1006993 }
1007- else {
1008- #ifdef RUDDER_SENSITIVITY
1009- rudderSensitivity = request.writeData .value + 1 ;
1010- #endif
1011- }
1012994 return ;
1013995 }
1014996
@@ -1114,22 +1096,7 @@ void processRequest(int bytes)
11141096 processG1000Events ();
11151097 }
11161098
1117- if (request.writeData .eventId == SWITCHBOX_JOY) {
1118- processSwitchBox (request.writeData .value );
1119- if (request.writeData .value > 16 ) {
1120- // Mode switch so send reply to client
1121- EVENT_ID event;
1122- if (strncmp (simVars.aircraft , " Cessna 152" , 10 ) == 0 ) {
1123- event = EVENT_IS_CESSNA_152;
1124- }
1125- else {
1126- event = EVENT_NOT_CESSNA_152;
1127- }
1128- sendto (sockfd, (char *)&event, sizeof (int ), 0 , (SOCKADDR*)&senderAddr, addrSize);
1129- }
1130- return ;
1131- }
1132- else if (request.writeData .eventId == EVENT_RESET_DRONE_FOV) {
1099+ if (request.writeData .eventId == EVENT_RESET_DRONE_FOV) {
11331100 writeJetbridgeVar (DRONE_CAMERA_FOV, 50 );
11341101 return ;
11351102 }
@@ -1316,10 +1283,6 @@ void server()
13161283 networkOut = 0 ;
13171284 }
13181285#endif
1319-
1320- #ifdef RUDDER_SENSITIVITY
1321- joystickRefresh ();
1322- #endif
13231286 }
13241287
13251288 free (deltaData);
@@ -1332,77 +1295,120 @@ void server()
13321295 printf (" Server stopped\n " );
13331296}
13341297
1335- #ifdef RUDDER_SENSITIVITY
1336- void joystickInit ()
1298+ #ifdef PICO_JOYSTICK
1299+ // / <summary>
1300+ // / Raspberry Pi Pico button box (4 encoders + 4 buttons) appears as a USB joystick
1301+ // / </summary>
1302+ void picoInit ()
13371303{
1338- joyInfo.dwSize = sizeof (joyInfo);
1339- joyInfo.dwFlags = JOY_RETURNU | JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ;
1304+ // Initialise simvars
1305+ simVars.sbMode = 0 ; // Default to autopilot
1306+ for (int i = 0 ; i < 7 ; i++) {
1307+ if (i < 4 ) {
1308+ simVars.sbEncoder [i] = 0 ;
1309+ }
1310+ simVars.sbButton [i] = 0 ;
1311+ }
1312+
1313+ JOYCAPSA joyCaps;
13401314
13411315 for (joystickId = 0 ; joystickId < 16 ; joystickId++) {
1342- MMRESULT res = joyGetPosEx (joystickId, &joyInfo );
1316+ MMRESULT res = joyGetDevCaps (joystickId, &joyCaps, sizeof (joyCaps) );
13431317 if (res != JOYERR_NOERROR) {
13441318 continue ;
13451319 }
13461320
1347- // Rudder pedal axis will be centred (and throttles won't be )
1348- if (joyInfo. dwUpos > 30000 && joyInfo. dwUpos < 36000 && (joyInfo. dwXpos != 32767 || joyInfo. dwYpos != 32767 || joyInfo. dwZpos != 32767 ) ) {
1321+ // Pico has 4 axes and 9 buttons (includes 4 buttons for clickable encoders + a dummy refresh button )
1322+ if (joyCaps. wNumAxes == 4 && joyCaps. wNumButtons == 9 ) {
13491323 break ;
13501324 }
1351-
1352- // printf("Joystick %d (%d, %d, %d, %d) does not have rudder pedal input\n", joystickId, joyInfo.dwUpos, joyInfo.dwXpos, joyInfo.dwYpos, joyInfo.dwZpos);
13531325 }
13541326
1355- joyInfo.dwFlags = JOY_RETURNU;
1356-
13571327 if (joystickId < 16 ) {
1358- printf (" Rudder pedal input found on joystick %d\n " , joystickId);
1328+ printf (" Found Pico joystick %d\n " , joystickId);
1329+ }
1330+ else if (joystickRetry > 0 ) {
1331+ joystickRetry--;
1332+ joystickId = -1 ;
13591333 }
13601334 else {
1361- if (joystickRetry > 0 ) {
1362- joystickRetry--;
1363- joystickId = -1 ;
1364- }
1365- else {
1366- joystickId = 1 ;
1367- printf (" Defaulting to joystick %d for rudder pedal input\n " , joystickId);
1368- }
1335+ joystickId = -2 ;
1336+ printf (" No Pico joystick connected\n " );
13691337 }
13701338}
13711339
1372- // / <summary>
1373- // / Reads the Rudder Pedal axis and sets vJoy axis 0 with reduced sensitivity.
1374- // / Sensitivity is reduced to one third until the extremes where it is linearly mapped back to the full value.
1375- // / To use: In FS2020, map vJoy axis 0 instead of the real rudder pedal axis.
1376- // / </summary>
1377- void joystickRefresh ()
1340+ void picoRefresh ()
13781341{
13791342 if (joystickId < 0 || joystickId > 15 ) {
13801343 if (joystickId == -1 ) {
1381- joystickInit ();
1382- vJoyInit ();
1344+ picoInit ();
13831345 }
13841346 return ;
13851347 }
13861348
1349+ JOYINFOEX joyInfo;
1350+ joyInfo.dwSize = sizeof (joyInfo);
1351+ joyInfo.dwFlags = JOY_RETURNALL;
1352+ joyInfo.dwButtons = 0xffffffffl ;
1353+
13871354 MMRESULT res = joyGetPosEx (joystickId, &joyInfo);
13881355 if (res != JOYERR_NOERROR) {
13891356 return ;
13901357 }
13911358
1392- const int centre = 32767 ;
1393-
1394- int rudderPos = joyInfo.dwUpos ;
1395- if (rudderSensitivity > 1 ) {
1396- // Reduce sensitivity
1397- rudderPos = centre + ((rudderPos - centre) / rudderSensitivity);
1359+ // First set of data with buttons = 256 (refresh button) will zeroise all axes
1360+ if (!zeroed && joyInfo.dwButtons == 256 ) {
1361+ zeroPos[0 ] = joyInfo.dwXpos ;
1362+ zeroPos[1 ] = joyInfo.dwYpos ;
1363+ zeroPos[2 ] = joyInfo.dwZpos ;
1364+ zeroPos[3 ] = joyInfo.dwRpos ;
1365+ zeroed = true ;
13981366 }
13991367
1400- #ifdef vJoyFallback
1401- // printf("rudder: %d adjusted to %d\n", joyInfo.dwUpos, rudderPos);
1402- vJoySetAxis (rudderPos);
1403- #else
1404- printf (" rudder not adjusted as no vJoy\n " );
1405- joystickId = 16 ;
1406- #endif
1368+ if (zeroed) {
1369+ // Set simvars
1370+ simVars.sbEncoder [0 ] = joyInfo.dwXpos - zeroPos[0 ];
1371+ simVars.sbEncoder [1 ] = joyInfo.dwYpos - zeroPos[1 ];
1372+ simVars.sbEncoder [2 ] = joyInfo.dwZpos - zeroPos[2 ];
1373+ simVars.sbEncoder [3 ] = joyInfo.dwRpos - zeroPos[3 ];
1374+ simVars.sbButton [0 ] = (joyInfo.dwButtons & 1 ) > 0 ;
1375+ simVars.sbButton [1 ] = (joyInfo.dwButtons & 2 ) > 0 ;
1376+ simVars.sbButton [2 ] = (joyInfo.dwButtons & 4 ) > 0 ;
1377+ double button3 = (joyInfo.dwButtons & 8 ) > 0 ;
1378+ simVars.sbButton [3 ] = (joyInfo.dwButtons & 16 ) > 0 ;
1379+ simVars.sbButton [4 ] = (joyInfo.dwButtons & 32 ) > 0 ;
1380+ simVars.sbButton [5 ] = (joyInfo.dwButtons & 64 ) > 0 ;
1381+ simVars.sbButton [6 ] = (joyInfo.dwButtons & 128 ) > 0 ;
1382+
1383+ // printf("Axes 0=%.0f, 1=%.0f, 2=%.0f, 3=%.0f buttons 0=%.0f, 1=%.0f, 2=%.0f, 3=%.0f, 4=%.0f, 5=%.0f, 6=%.0f, 7=%.0f, \n",
1384+ // simVars.sbEncoder[0], simVars.sbEncoder[1], simVars.sbEncoder[2], simVars.sbEncoder[3], simVars.sbButton[0], simVars.sbButton[1],
1385+ // simVars.sbButton[2], button3, simVars.sbButton[3], simVars.sbButton[4], simVars.sbButton[5], simVars.sbButton[6]);
1386+
1387+ // Check for mode switch press (plays a sound when switched)
1388+ if (button3 && !modeChange) {
1389+ modeChange = true ;
1390+ if (simVars.sbMode > 3 ) {
1391+ simVars.sbMode = 1 ;
1392+ }
1393+ else {
1394+ simVars.sbMode ++;
1395+ }
1396+
1397+ char soundFile[50 ];
1398+ switch (int (simVars.sbMode )) {
1399+ case 2 : strcpy (soundFile, " Sounds\\ Switchbox Radio.wav" ); break ;
1400+ case 3 : strcpy (soundFile, " Sounds\\ Switchbox Instruments.wav" ); break ;
1401+ case 4 : strcpy (soundFile, " Sounds\\ Switchbox Navigation.wav" ); break ;
1402+ default : strcpy (soundFile, " Sounds\\ Switchbox Autopilot.wav" ); break ;
1403+ }
1404+
1405+ PlaySound (soundFile, NULL , SND_FILENAME | SND_ASYNC);
1406+ }
1407+
1408+ // Check for mode switch release
1409+ if (modeChange && !button3) {
1410+ modeChange = false ;
1411+ }
1412+ }
14071413}
1408- #endif // RUDDER_SENSITIVTY
1414+ #endif // PICO_JOYSTICK
0 commit comments