Anyone able to help me adapt Teensy code for Pro Micro to use Thrustmaster F-16 FLCS?
-
I bought this Thrustmaster F-16 FLCS stick cheap s/h, originally with the idea to just take the handle and merge it with my MS Sidewinder FFB2 on an extension, to use with choppers in DCS.
However, I’ve now decided I’d rather just convert it into a USB stick using an Arduino Pro Micro to use it with BMS. I found this code for Teensy http://forum.il2sturmovik.com/topic/1790-there-any-better-joystick-ms-sidewinder-force-feedback-2/#entry46472 which obviously relies on the “Joystick” code built-in to the Teensy. (the Pitch/Yaw pots would just connect to a couple of analog inputs on the Pro Micro I presume).
/* USB FLCS Grip You must select Joystick from the "Tools > USB Type" menu */ // Buttons are muxed into shift registers, use the SPI protocol to read them #include <spi.h> const int slaveSelectPin = 0; unsigned int buttonInputs1; // data read from SPI unsigned int buttonInputs2; unsigned int buttonInputs3; // Use some macros to clean things up #define S3 !(buttonInputs1 & 0x80) /* Pinky Switch */ #define TG1 !(buttonInputs1 & 0x40) /* Trigger 1 */ #define TG2 !(buttonInputs1 & 0x20) /* Trigger 2 */ #define S1 !(buttonInputs1 & 0x10) /* Nose Wheel Steering */ #define S4 !(buttonInputs1 & 0x08) /* Paddle Switch */ #define S2 !(buttonInputs1 & 0x04) /* Pickle */ #define H1D !(buttonInputs2 & 0x80) /* Trim */ #define H1R !(buttonInputs2 & 0x40) #define H1U !(buttonInputs2 & 0x20) #define H1L !(buttonInputs2 & 0x10) #define H4U !(buttonInputs2 & 0x08) /* CMS */ #define H4L !(buttonInputs2 & 0x04) #define H4D !(buttonInputs2 & 0x02) #define H4R !(buttonInputs2 & 0x01) #define H3D !(buttonInputs3 & 0x80) /* DMS */ #define H3R !(buttonInputs3 & 0x40) #define H3U !(buttonInputs3 & 0x20) #define H3L !(buttonInputs3 & 0x10) #define H2D !(buttonInputs3 & 0x08) /* TMS */ #define H2R !(buttonInputs3 & 0x04) #define H2U !(buttonInputs3 & 0x02) #define H2L !(buttonInputs3 & 0x01) // setup() runs once on boot void setup() { // set the slaveSelectPin as an output: pinMode (slaveSelectPin, OUTPUT); // start the SPI library: SPI.begin(); // configure the joystick to manual send mode. This gives precise // control over when the computer receives updates, but it does // require you to manually call Joystick.send_now(). Joystick.useManualSend(true); } // loop() runs for as long as power is applied void loop() { // take the SS pin low to select the chip digitalWrite(slaveSelectPin,LOW); // send a value of 0 to read the SPI bytes buttonInputs1 = SPI.transfer(0x00); buttonInputs2 = SPI.transfer(0x00); buttonInputs3 = SPI.transfer(0x00); // take the SS pin high to de-select the chip: digitalWrite(slaveSelectPin,HIGH); // Write to joystick buttons Joystick.button(1, TG1); Joystick.button(2, S2); Joystick.button(3, S3); Joystick.button(4, S4); Joystick.button(5, S1); Joystick.button(6, TG2); Joystick.button(7, H2U); Joystick.button(8, H2R); Joystick.button(9, H2D); Joystick.button(10, H2L); Joystick.button(11, H3U); Joystick.button(12, H3R); Joystick.button(13, H3D); Joystick.button(14, H3L); Joystick.button(15, H4U); Joystick.button(16, H4R); Joystick.button(17, H4D); Joystick.button(18, H4L); //Joystick.button(19, H1U); //Joystick.button(20, H1R); //Joystick.button(21, H1D); //Joystick.button(22, H1L); // Determine Joystick Hat Position int angle = -1; if (H1U) { if (H1R) { angle = 45; } else if (H1L) { angle = 315; } else { angle = 0; } } else if (H1D) { if (H1R) { angle = 135; } else if (H1L) { angle = 225; } else { angle = 180; } } else if (H1R) { angle = 90; } else if (H1L) { angle = 270; } Joystick.hat(angle); // Because setup configured the Joystick manual send, // the computer does not see any of the changes yet. // This send_now() transmits everything all at once. Joystick.send_now(); }</spi.h>
I found this code for using a Leonardo as a USB Joystick http://www.imaginaryindustries.com/blog/?p=80 and tested it with my Pro Micro and it works as expected and sends random output to Windows joystick control panel. I have no idea how to merge the two sets of code to achieve what I want though, so was wondering if there’s anyone here with some understanding of Arduino code who could help me?
I don’t really know where to start but in USBAPI.h, the main joystick-related code seems to be:
// Joystick // Implemented in HID.cpp // The list of parameters here needs to match the implementation in HID.cpp typedef struct JoyState // Pretty self explanitory. Simple state to store all the joystick parameters { uint8_t xAxis; uint8_t yAxis; uint8_t zAxis; uint8_t xRotAxis; uint8_t yRotAxis; uint8_t zRotAxis; uint8_t throttle; uint8_t rudder; uint8_t hatSw1; uint8_t hatSw2; uint32_t buttons; // 32 general buttons } JoyState_t; class Joystick_ { public: Joystick_(); void setState(JoyState_t *joySt); }; extern Joystick_ Joystick;
and in HID.cpp:
// Joystick // Usage: Joystick.move(inputs go here) // // The report data format must match the one defined in the descriptor exactly // or it either won't work, or the pc will make a mess of unpacking the data // Joystick_::Joystick_() { } #define joyBytes 13 // should be equivalent to sizeof(JoyState_t) void Joystick_::setState(JoyState_t *joySt) { uint8_t data[joyBytes]; uint32_t buttonTmp; buttonTmp = joySt->buttons; data[0] = buttonTmp & 0xFF; // Break 32 bit button-state out into 4 bytes, to send over USB buttonTmp >>= 8; data[1] = buttonTmp & 0xFF; buttonTmp >>= 8; data[2] = buttonTmp & 0xFF; buttonTmp >>= 8; data[3] = buttonTmp & 0xFF; data[4] = joySt->throttle; // Throttle data[5] = joySt->rudder; // Steering data[6] = (joySt->hatSw2 << 4) | joySt->hatSw1; // Pack hat-switch states into a single byte data[7] = joySt->xAxis; // X axis data[8] = joySt->yAxis; // Y axis data[9] = joySt->zAxis; // Z axis data[10] = joySt->xRotAxis; // rX axis data[11] = joySt->yRotAxis; // rY axis data[12] = joySt->zRotAxis; // rZ axis //HID_SendReport(Report number, array of values in same order as HID descriptor, length) HID_SendReport(3, data, joyBytes); // The joystick is specified as using report 3 in the descriptor. That's where the "3" comes from }
-
I’m Actually planning to do the same in the future. (but for a cougar throttle)
I’ve booked marked it and will try and have a look at it during the day.
the problem is probably not the Arduino code but the HID descriptor and the joySt object structure. -
Thanks, that’ll be great if you can help me out as it just makes my head spin trying to work out how to combine the two sets of code into something usable
-
Just to let you know I gave in and bought a Teensy 3.1 for £19.80, so I can get on with sorting out the stick and try and get to grips with BMS
-
I’ve got the Teensy 3.1 now but I’m not having much luck with that either!
As per what that guy worked out and the 3.1 pinout https://www.pjrc.com/teensy/td_libs_SPI.html I’ve wired Brown to Vin, Green to GND, Orange to SCK (Pin 13), Red to SS (Pin 10) and Yellow to DIN/MISO (12).
I’m using this code:
/* USB FLCS Grip
You must select Joystick from the “Tools > USB Type” menu
*/// Buttons are muxed into shift registers, use the SPI protocol to read them
#include <spi.h>const int slaveSelectPin = 10;unsigned int buttonInputs1; // data read from SPI
unsigned int buttonInputs2;
unsigned int buttonInputs3;// Use some macros to clean things up
#define S3 !(buttonInputs1 & 0x80) /* Pinky Switch /
#define TG1 !(buttonInputs1 & 0x40) / Trigger 1 /
#define TG2 !(buttonInputs1 & 0x20) / Trigger 2 /
#define S1 !(buttonInputs1 & 0x10) / Nose Wheel Steering /
#define S4 !(buttonInputs1 & 0x08) / Paddle Switch /
#define S2 !(buttonInputs1 & 0x04) / Pickle */#define H1D !(buttonInputs2 & 0x80) /* Trim /
#define H1R !(buttonInputs2 & 0x40)
#define H1U !(buttonInputs2 & 0x20)
#define H1L !(buttonInputs2 & 0x10)
#define H4U !(buttonInputs2 & 0x08) / CMS */
#define H4L !(buttonInputs2 & 0x04)
#define H4D !(buttonInputs2 & 0x02)
#define H4R !(buttonInputs2 & 0x01)#define H3D !(buttonInputs3 & 0x80) /* DMS /
#define H3R !(buttonInputs3 & 0x40)
#define H3U !(buttonInputs3 & 0x20)
#define H3L !(buttonInputs3 & 0x10)
#define H2D !(buttonInputs3 & 0x08) / TMS */
#define H2R !(buttonInputs3 & 0x04)
#define H2U !(buttonInputs3 & 0x02)
#define H2L !(buttonInputs3 & 0x01)// setup() runs once on boot
void setup() {
// set the slaveSelectPin as an output:
pinMode (slaveSelectPin, OUTPUT);
// start the SPI library:
SPI.begin();
// configure the joystick to manual send mode. This gives precise
// control over when the computer receives updates, but it does
// require you to manually call Joystick.send_now().
Joystick.useManualSend(true);
}// loop() runs for as long as power is applied
void loop() {
// take the SS pin low to select the chip
digitalWrite(slaveSelectPin,LOW);
// send a value of 0 to read the SPI bytes
buttonInputs1 = SPI.transfer(0x00);
buttonInputs2 = SPI.transfer(0x00);
buttonInputs3 = SPI.transfer(0x00);
// take the SS pin high to de-select the chip:
digitalWrite(slaveSelectPin,HIGH);// Write to joystick buttons
Joystick.button(1, TG1);
Joystick.button(2, S2);
Joystick.button(3, S3);
Joystick.button(4, S4);
Joystick.button(5, S1);
Joystick.button(6, TG2);
Joystick.button(7, H2U);
Joystick.button(8, H2R);
Joystick.button(9, H2D);
Joystick.button(10, H2L);
Joystick.button(11, H3U);
Joystick.button(12, H3R);
Joystick.button(13, H3D);
Joystick.button(14, H3L);
Joystick.button(15, H4U);
Joystick.button(16, H4R);
Joystick.button(17, H4D);
Joystick.button(18, H4L);
//Joystick.button(19, H1U);
//Joystick.button(20, H1R);
//Joystick.button(21, H1D);
//Joystick.button(22, H1L);// Determine Joystick Hat Position
int angle = -1;if (H1U) {
if (H1R) {
angle = 45;
} else if (H1L) {
angle = 315;
} else {
angle = 0;
}
} else if (H1D) {
if (H1R) {
angle = 135;
} else if (H1L) {
angle = 225;
} else {
angle = 180;
}
} else if (H1R) {
angle = 90;
} else if (H1L) {
angle = 270;
}
Joystick.hat(angle);// Because setup configured the Joystick manual send,
// the computer does not see any of the changes yet.
// This send_now() transmits everything all at once.
Joystick.send_now();
}Unfortunately, that doesn’t work and the only one that does anything is the red pinky button at the base of the stick, which triggers on all buttons 1-18 and upper-right diagonal on the hat as well!
The only pin that seems to be defined in the code is SS, which I’ve set to 10. I imagine the +ve and GND must be right or it wouldn’t even be doing this and I’ve got no reason to doubt the other wires are correct as well.
The guides all seem to say to select USB - Joystick in Arduino but I don’t have that, only “Keyboard + Mouse + Joystick” or “Serial + Keyboard + Mouse + Joystick”, but I imagine either of those should work just as well and it is seen as a joystick in Windows.
Does anyone know about Teensy and SPI specifically and can think what might cause this behaviour? Would it happen if one of the SPI wires wasn’t connected properly or would nothing at all happen then?
I don’t really want to dismantle the handle to check the wiring inside that, as I can picture all the buttons/hats falling off and being a nightmare to put back together, so if there’s an electronic way to diagnose the problem I’d rather do that.</spi.h>
-
For anyone who comes across this, I finally got it working by changing the code under the void loop() line as explained here (see post #23): https://forum.pjrc.com/threads/26900-Trouble-reading-joystick-buttons-with-SPI?p=67963&viewfull=1#post67963