Button Press detector

Looks like that one used SPI_MODE0 where I guessed SPI_MODE3 in the other one.
MSBFIRST/LSBFIRST tells SPI the order of the bits, that is if I output an 0x01 are the bits output: 0 0 0 0 0 0 0 1 or is it 1 0 0 0 0 0 0 0
(Most Significant Bit first) or (Least Significant bit first)

I believe you can just do something like joysitck.button(13, joyBtnState);
 
Thank you.


Reading on SPI's, is 1000Hz vs 4000MHz going to make a difference to the functions?

Is windows Power Management more liekly to step in an power off the device if there's a slwoer rate?
 
Last edited:
Code:
/* Byte 1
 * 7 - 1
 * 6 - 0
 * 5 - 0
 * 4 - 0
 * 3 - 0
 * 2 - 1
 * 1 - 0
 * 0 - Button 6
 * 
 * Byte 2
 * 7 - Button 2
 * 6 - Button 5
 * 5 - Button 9
 * 4 - 1 = HatPush?
 * 3 - Button 7
 * 2 - Button 13
 * 1 - Button 8
 * 0 - 1 = HatPush?               
 * 
 * Byte 3
 * 7 - Button 3
 * 6 - Button 10
 * 5 - HatLeft
 * 4 - HatUp
 * 3 - HatRight
 * 2 - HatDown
 * 1 - Button 4
 * 0 - Button 1
*/

#include <SPI.h>
#include <Joystick.h>

const int slaveSelectPin = 10;
byte pos[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
byte currBytes[] = {0x00, 0x00, 0x00, 0x00};
byte prevBytes[] = {0x00, 0x00, 0x00};
bool btnState, joyBtnState, prevJoyBtnState;
[COLOR="#FF0000"]int bit2btn[] = {-1,-1,-1,-1,-1,-1,-1,8,  -1,2,1,-1,5,7,6,5,  4,0,11,9,12,10,3,-1};                 //number the buttons - Needs editing? New doesn't match original[/COLOR]

void setup() {
//input from wheel
  Serial.begin(9600);
  SPI.beginTransaction(SPISettings());
  SPI.begin();                     
  pinMode(slaveSelectPin, OUTPUT);
//output to joystick
  Joystick.begin();
}

void loop() {
// tell the wheel, that we are ready to read the data now
  digitalWrite(slaveSelectPin, LOW);
  
[COLOR="#FF0000"]//read the next 4 bytes (get 2's compliment) - Why read 4 bytes? Only 3 are being sent[/COLOR]
  for(int i=0; i<4; i++) 
    currBytes[i] = ~SPI.transfer(0x00);
  
[COLOR="#FF0000"]//deal with the buttons first - Basically, this whole section until //release the wheel looks a bit unfinished.[/COLOR]
  for(int i=0; i<3; i++)                                                                            //process the three bytes
    for(int b=0; b<8; b++)                                                                          //one bit at a time
      if((btnState=currBytes[i] & pos[b])!=(prevBytes[i] & pos[b]))
[COLOR="#FF0000"]      Joystick.begin(); - ALready did this in void setup, necessary?[/COLOR]
        Joystick.button(13, joyBtnState);                                                           //if the bit has changed send the update     
  
  joyBtnState = (currBytes[3] & pos[0]) && !(currBytes[2] & 0x3c);  
    if(joyBtnState != prevJoyBtnState)
      Joystick.button(13, joyBtnState);
  
  for(int i=0;i<3;i++)
    prevBytes[i] = currBytes[i];                                                                    //finally update the just read input to the the previous input for the next cycle
      prevJoyBtnState = joyBtnState;

//release the wheel
  digitalWrite(slaveSelectPin, HIGH);
  }

I get ZERO output from htis.

Compiles nicely, uploads nicely. Is readable via usbviewer, recognised as a windows device...
Doesn't do anything else. No button presses registered.
 
Last edited:
There are 2 versions of this original sketch, both of which contain

Code:
#include <SPI.h>
#include <Joystick.h>

[COLOR="#FF0000"]Joystick_ Joystick(
  JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 14, 0,
  false, false, false, false, false, false,
  false, false, false, false, false); [/COLOR]
  
const int slaveSelectPin = 7;

Is this necessary? Can it be replicated TeensyLC?
 
Googled 'arduino, bit2btn' ... just turned up a goldmine:

once again using:

"
Joystick_ Joystick(
JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 21, 1, // 21 buttons, 1 hatswitch
false, false, false, false, false, false,
false, false, false, false, false);
"

Code:
/*
 * Code by Insert Coin
 * V1.01 February 2022
 * Code is an enhanced version of Noel McCullagh's code (see https://www.noelmccullagh.com)
 * which he based on Taras' code at http://rr-m.org
 * So thank you both :-)
 * Enhancements: 
 *  - supports hot swapping of Thrustmaster R383, F1 and Ferrari 599xx wheels
 *  - all buttons are working
 *  - button numbering is the same as when the wheels are on a Thrustmaster base
 *    (paddles are always buttons 1 and 2 for example)
 *    
 * V1.01 October 2022: tiny bug fixed, 'button pressed' was sent continuously over USB as long as
 * a button was pressed (telling 'button pressed' once is enough)
*/

/*
* On Arduino Pro Micro side it must be connected as follows:
 *          ----___----
 *        / 6   [ ]   5 \
 *       |      [_]      |   (as seen from the female front of the connector)
 *       | 4           3 |
 *        \___       ___/
 *            |2   1|
 *            \_____/
 *            
 * 1              -> not used (or can be connected to arduino MOSI pin 16)
 * 2 Green - GND  -> Arduino Pro Micro GND pin
 * 3 White - MISO -> Arduino Pro Micro pin 14
 * 4 Yellow - SS  -> Arduino Pro Micro pin 7
 * 5 Black - SCK  -> Arduino Pro Micro pin 15
 * 6 Red - +VCC   -> Arduino +5V pin (or RAW if USB current is +5V already)
 * 
 * Wheels and official Thrustmaster button numbers:
 * 
 * R383 wheel                     F1 wheel                       Ferrari 599xx
 * ----------------------------   ----------------------------   --------------------------------
 * Byte 1                         Byte 1                         Byte 1
 * 7 - constant 0                 7 - DRS (5)    (yes, odd)      7 - constant 1
 * 6 - constant 0                 6 - constant 0                 6 - constant 0
 * 5 - constant 1                 5 - constant 1                 5 - constant 1
 * 4 - constant 1                 4 - constant 1                 4 - left paddle (1)
 * 3 - constant 0                 3 - left paddle (1)            3 - right paddle (2)
 * 2 - constant 1                 2 - right paddle (2)           2 - PIT (blue upper left) (3)
 * 1 - constant 0                 1 - N (3)                      1 - WASH (blue down left) (4)
 * 0 - bottom right yellow (6)    0 - PIT (4)                    0 - RADIO (blue upper right) (5)
 * 
 * Byte 2                         Byte 2                         Byte 2
 * 7 - right paddle (2)           7 - START (13)                 7 - black down left (6)
 * 6 - top right black (5)        6 - 10+ (6)                    6 - MAIN left (7)
 * 5 - top right red (9)          5 - B0 (7)                     5 - MAIN right (8)
 * 4 - constant 0                 4 - WET (8)                    4 - SCROLL (red upper right) (9)
 * 3 - bottom left red (7)        3 - PL (9)                     3 - FLASH (red upper left) (10)
 * 2 - bottom right white (13)    2 - K (10)                     2 - constant 0
 * 1 - bottom right red (8)       1 - PUMP (11)                  1 - constant -
 * 0 - constant 0                 0 - 1- (12)                    0 - MAIN pushed in (13)
 * 
 * Byte 3                         Byte 3                         Byte 3
 * 7 - bottom left yellow (3)     7 - right Dpad up (18)         7 - Dpad down
 * 6 - top left red (10)          6 - left Dpad down             6 - Dpad right
 * 5 - Dpad left                  5 - left Dpad right            5 - Dpad left
 * 4 - Dpad up                    4 - left Dpad left             4 - Dpad up
 * 3 - Dpad right                 3 - left Dpad up               3 - constant 0
 * 2 - Dpad down                  2 - right Dpad down (19)       2 - constant 0
 * 1 - bottom left yellow (4)     1 - right Dpad right (20)      1 - constant 0
 * 0 - left paddle                0 - right Dpad left (21)       0 - constant 0
 * 
 * Byte 4                         Byte 4
 * 7 - 1 when Dpad pressed        7 - 
 * 6 - 1 when Dpad pressed        6 - CHRG down (16)
 * 5 - 1 when Dpad pressed        5 - DIF IN up (14)
 * 4 - 1 when Dpad pressed        4 - DIF IN down (15)
 * 3 - 1 when Dpad pressed        3 - CHRG up (17)
 * 2 - 1 when Dpad pressed        2 - 
 * 1 - 1 when Dpad pressed        1 - 
 * 0 - 1 when Dpad pressed        0 -
*/

#include <SPI.h>
#include <Joystick.h>

const int slaveSelectPin = 10;
byte pos[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
byte currBytes[] = {0x00, 0x00, 0x00, 0x00, 0x00};
byte prevBytes[] = {0x00, 0x00, 0x00, 0x00, 0x00};
int wheelbyte, fourthbyte, fifthbyte, wheelID;
bool btnState, joyBtnState, prevJoyBtnState, buttonsreset, wheelIdentified;
const bool debugging = false; // Set to true to see wheel bits debug messages on the com port
int bit2btn[] = {-1,-1,-1,-1,-1,-1,-1,-1,  -1,-1,-1,-1,-1,-1,-1,-1,  -1,-1,-1,-1,-1,-1,-1,-1,  -1,-1,-1,-1,-1,-1,-1,-1}; // working array of buttons
int F599Btn[] = {-1,-1,-1,0,1,2,3,4,  5,6,7,8,9,-1,-1,12,  33,32,34,31,-1,-1,-1,-1,  -1,-1,-1,-1,-1,-1,-1,-1}; // button numbers 599xx wheel
int R383Btn[] = {-1,-1,-1,-1,-1,-1,-1,5,  1,4,8,-1,6,12,7,-1,  2,9,34,31,32,33,3,0,  -1,-1,-1,-1,-1,-1,-1,-1}; // button numbers R383 wheel
int F1Btn[] = {4,-1,-1,-1,0,1,2,3,  12,5,6,7,8,9,10,11,  17,33,32,34,31,18,19,20,  -1,15,13,14,16,-1,-1,-1}; // button numbers F1 wheel

void setup() {
  //input from wheel
  Serial.begin(9600);
  SPCR |= _BV(CPHA);
  SPCR |= _BV(CPOL);
  SPI.beginTransaction(SPISettings(40000, MSBFIRST, SPI_MODE0));
  SPI.begin();                     
  pinMode(slaveSelectPin, OUTPUT);

  //output to joystick
  Joystick.begin();
}

// print byte as binary, zero padded if needed 
// "127" -> "01111111"
void printBinary(byte data) {
 for(int i=7; i>0; i--) {
   if (data >> i == 0) {
     Serial.print("0");
   } else {
     break;
   }
 }
 Serial.print(data,BIN);
 Serial.print(" ");
}

void loop() {
  // tell the wheel, that we are ready to read the data now
  digitalWrite(slaveSelectPin, LOW);
  // the chips in the wheel need some time to wake up
  delayMicroseconds(40);
  
  //read the wheel's 5 bytes
  for(int i=0; i<5; i++) {
    currBytes[i] = ~SPI.transfer(0x00);
    delayMicroseconds(40);
  }

  // release the wheel
  digitalWrite(slaveSelectPin, HIGH);
  delayMicroseconds(40);
  
  if (debugging) {
    for(int i=0; i<5; i++) {
      printBinary(currBytes[i]);
      Serial.print("\t");
    }
    Serial.println();
  }

  // Check for sane input: is the wheel plugged in?
  // Unplugged: first byte has all bits set or unset
  // When plugged in F1 and Ferrari 599xx wheel has bits 7, 6, 5 set as 101 (160 dec)
  // Sparco R383 has bits 7, 6, 5 set as 001 (32 dec)
  wheelbyte = currBytes[0] & B11100000;
  fourthbyte = currBytes[3] & B00100000;
  fifthbyte = currBytes[4] & B00001111;
  buttonsreset = false;
  
  while ((wheelbyte != 192) and (wheelbyte != 160) and (wheelbyte != 32)) {  // unknown wheel or wheel unplugged

     wheelIdentified = false;
        
     // Reset all buttons to avoid stuck buttons when unplugged
     if (buttonsreset == false) {
        for(int b=0; b<21; b++)        // one button at a time
        buttonsreset = true;           // do it just once
     }
     
     if (debugging) Serial.println("Wheel not plugged in, waiting...");

     // tell the wheel, that we are ready to read the data now
     digitalWrite(slaveSelectPin, LOW);
     // the chips in the wheel need some time to wake up
     delayMicroseconds(40); 
     
     // read the wheel's 5 bytes
     for(int i=0; i<5; i++) {
       currBytes[i] = ~SPI.transfer(0x00);
       delayMicroseconds(40);
     }

     // release the wheel
     digitalWrite(slaveSelectPin, HIGH);
     delayMicroseconds(40);

     if (debugging) for(int i=0; i<5; i++) {
       printBinary(currBytes[i]);
       Serial.print("\t");
     }
     if (debugging) Serial.println();

     wheelbyte = currBytes[0] & B11100000;  // same as above, for identifying the wheel below
     fourthbyte = currBytes[3] & B00100000;
     fifthbyte = currBytes[4] & B00001111;
     
     // Still no sane input? Wait...
     if ((wheelbyte != 192) and (wheelbyte != 160) and (wheelbyte != 32)) {
       delay(1000);
     }
  }

  if (wheelIdentified == false) {
    if ((wheelbyte == 160) and (fifthbyte == 0)) {
    wheelID = 2;                                           // Ferrari 599xx wheel
    memcpy(bit2btn,F599Btn,sizeof(F599Btn));               // button numbers 599xx wheel to working array
    wheelIdentified = true;
    } else if (wheelbyte == 32) {
             if (((fourthbyte == 0) and (fifthbyte == 0)) or ((currBytes[3] == 255) and (currBytes[4] == 255))) {
                wheelID = 3;                               // Sparco R383 connected
                memcpy(bit2btn,R383Btn,sizeof(R383Btn));   // button numbers R383 wheel to working array
                wheelIdentified = true;
             } else if ((wheelbyte == 32) and (fifthbyte == 15)) {      // F1 wheel sets last four bits of byte 5 as 1, 599xx wheel sets byte 5 as zero
                      wheelID = 1;                          // F1 wheel connected
                      memcpy(bit2btn,F1Btn,sizeof(F1Btn));  // button numbers F1 wheel to working array
                      wheelIdentified = true;
                    }
           }
  }

  if (debugging) { 
    Serial.print(wheelbyte);
    Serial.print("\t");
    Serial.println(wheelID);
  }
  
  // deal with the buttons first
  if (wheelIdentified) 
    for(int i=0; i<4; i++)      //process the four bytes
      for(int b=0; b<8; b++)     //one bit at a time
        if((currBytes[i] & pos[b])!=(prevBytes[i] & pos[b])) {  // if the buttonstate has changed
          btnState=currBytes[i] & pos[b];        
          if ((bit2btn[(i*8)+b] >= 31) and (bit2btn[(i*8)+b] <= 34)) {   // hatswitch (Dpad) pressed?
            if (btnState == 0)               // button released?
              Joystick.button(13, joyBtnState);      // send the update     
      
      }

  if ((wheelIdentified) and (wheelID == 3)) {                         // only for R383 wheel
    joyBtnState = (currBytes[3] & pos[0]) && !(currBytes[2] & 0x3c);  // if hatswitch is pressed in the middle
    if (joyBtnState != prevJoyBtnState)
      Joystick.button(13, joyBtnState);                            // press button 14
  }
  
  for(int i=0;i<5;i++)
    prevBytes[i] = currBytes[i];   // finally update the just read input to the the previous input for the next cycle

  prevJoyBtnState = joyBtnState;
        }}

It shows my wheel outputs 4 bytes, and the hat-swith 'push' is in that 4th byte, and which also fixes the 'int bit2btn[]' discrepancy.

There's obviously a ton of other stuff in here too, but 1 step at a time.
 
Last edited:
I can't get past bit2btn.

That above post I found is literally the only relevant google return.
Nothing in the Arduino reference.

and "Joystick_ Joystick..."... what is that even doing?
 
I can't get past bit2btn.

That above post I found is literally the only relevant google return.
Nothing in the Arduino reference.

and "Joystick_ Joystick..."... what is that even doing?

From your post #30 it is just an integer array: int bit2btn[] = {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1}; // working array of buttons
Note there is code in there that overwrites this array, I am guessing depending on which wheel or the like you are using...

My strong guess is that you have 4 bytes of data being returned. Each bit may correspond to a button, and this should do the mapping.

I would think something like one of these loops, should process the data, note for my own here I added in {} that the code above did not to make it clearer at least to me
Code:
    for(int i=0; i<4; i++)  {    //process the four bytes
      for(int b=0; b<8; b++) {    //one bit at a time
        if((currBytes[i] & pos[b])!=(prevBytes[i] & pos[b])) {  // if the buttonstate has changed
          btnState=currBytes[i] & pos[b]; 
          int b2bindex = i * 8 + b;
          if (bit2bnt[b2bindex] != -1) {
            joystick.button(bit2bnt[b2bindex], btnState);
          }
        }
      }
    }
Note typed on the fly so probably issues!

Note some of the code you posted makes no sense, like places that have, the iterations above, plus initial ifs...
Code:
          if ((bit2btn[(i*8)+b] >= 31) and (bit2btn[(i*8)+b] <= 34)) {   // hatswitch (Dpad) pressed?
            if (btnState == 0)               // button released?
              Joystick.button(13, joyBtnState);      // send the update
That is i goes from 0-3 and b goes 0-7, so the largest index is 3*8+7 or 31 so it could be only the last bit, but hat switch.
usually is 4 bits or an an angle. And the Joystick code wants an angle:
Joystick.hat(angle); // "angle" is 0,45,90,135,180,225,270,315,-1

So you will need to understand which bits (or is it a different byte?) correspond to UP/DOWN/LEFT/RIGHT and compute the angle to pass in or -1 to be centered.

More information on USB Joystick up at: https://www.pjrc.com/teensy/td_joystick.html
 
Thank you Kurt.

So, [int bit2btn] isn't saying 'these are the buttons and their current values', it's just 'here are some buttons?

Could I just use this from the Joystick Tutorial to set individual Byte/bit combos as a Joystick.button?

Code:
  Joystick.button(1, digitalRead(1));
  Joystick.button(2, digitalRead(1));

Maybe something like:
Code:
const int slaveSelectPin = 10;
Joystick.button(1, [byte/bitRead = x) ] ); //bearing i mind I don't know how this would really look... 'CurrByte & pos [b]' maybe?
Joystick.button(2, [byte/bitRead = y) ] );

void setup() {
//input from wheel
   Serial.begin(9600);
   SPI.beginTransaction(SPISettings());
   SPI.begin();
   pinMode(slaveSelectPin, OUTPUT);

//output to joystick
   Joystick.begin();
}

void loop() {
//tell the wheel, that we are ready to read the data now
   digitalWrite(slaveSelectPin, LOW);
}

//read the wheel's 5 bytes
   for (int i = 0; i < 5; i++) {
      currBytes[i] = ~SPI.transfer(0x00);

      if (joyBtnState != prevJoyBtnState)
         Joystick.button(13, joyBtnState);


//release the wheel
   digitalWrite(slaveSelectPin, HIGH);
 
I'm parsing #30 down to what seems like the bare bones.

I've commented out the "Joystick_ Joystick" stuff, because that looks like it's trying to draw on a a DynamicHID/PluggableUSB resource from the author's modded library... whih doesn't work on the TLC

Code:
#include <SPI.h>
#include <Joystick.h>

//Joystick_ Joystick(
//JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 21, 1,    // 21 buttons, 1 hatswitch
//false, false, false, false, false, false,
//false, false, false, false, false);

const int slaveSelectPin = 10;
byte pos[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
byte currBytes[] = {0x00, 0x00, 0x00, 0x00, 0x00};
byte prevBytes[] = {0x00, 0x00, 0x00, 0x00, 0x00};
int wheelID;
bool btnState, joyBtnState, prevJoyBtnState, buttonsreset, wheelIdentified;
const bool debugging = false; // Set to true to see wheel bits debug messages on the com port
int bit2btn[] = { -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1}; // working array of buttons

void setup() {
//input from wheel
Serial.begin(9600);
SPCR |= _BV(CPHA);
SPCR |= _BV(CPOL);
SPI.beginTransaction(SPISettings(40000, MSBFIRST, SPI_MODE0));
SPI.begin();
pinMode(slaveSelectPin, OUTPUT);

//output to joystick
Joystick.begin();
}

void loop() {
// tell the wheel, that we are ready to read the data now
digitalWrite(slaveSelectPin, LOW);
// the chips in the wheel need some time to wake up
delayMicroseconds(40);

//read the wheel
for (int i = 0; i < 4; i++) {
currBytes[i] = ~SPI.transfer(0x00);
delayMicroseconds(40);
}

// release the wheel
digitalWrite(slaveSelectPin, HIGH);
delayMicroseconds(40);

// tell the wheel, that we are ready to read the data now
digitalWrite(slaveSelectPin, LOW);
// the chips in the wheel need some time to wake up
delayMicroseconds(40);

// read the wheel
for (int i = 0; i < 4; i++) {
currBytes[i] = ~SPI.transfer(0x00);
delayMicroseconds(40);
}

// release the wheel
digitalWrite(slaveSelectPin, HIGH);
delayMicroseconds(40);

// deal with the buttons first

[COLOR="#B22222"]for (int i = 0; i < 4; i++) //process the four bytes
for (int b = 0; b < 8; b++) //one bit at a time
if ((currBytes[i] & pos[b]) != (prevBytes[i] & pos[b])) { // if the buttonstate has changed
btnState = currBytes[i] & pos[b];
if ((bit2btn[(i * 8) + b] >= 31) and (bit2btn[(i * 8) + b] <= 34)) { // hatswitch (Dpad) pressed?
if (btnState == 0)               // button released?
Joystick.button(i, LOW); // release hatswitch[/COLOR]
[COLOR="#008000"]else Joystick.button(i, (bit2btn[(i * 8) + b] - 31) * 90); // direction in 0, 90, 180, 270 degrees
} else Joystick.button(bit2btn[(i * 8) + b], btnState);  // send the update
[/COLOR]
}

[COLOR="#0000FF"]joyBtnState = (currBytes[3] & pos[0]) && !(currBytes[2] & 0x3c);  // if hatswitch is pressed in the middle
if (joyBtnState != prevJoyBtnState)
Joystick.button(14, 1);                            // press button 14[/COLOR]

for (int i = 0; i < 4; i++)
prevBytes[i] = currBytes[i];   // finally update the just read input to the the previous input for the next cycle

prevJoyBtnState = joyBtnState;

}

In #26 Kurt wrote "I believe you can just do something like joystick.button(13, joyBtnState);"

I thought 13 was an Arduino operation code... but that was just an example button number, right?

I'm having trouble understanding what's happening with the 'button - press loop'.
Is Joystick.button(i, ...) a thing? I want it to do the thing it needs to do, rather than explicitly telling it to [do this].

" if ((bit2btn[(i * 8) + b] >= 31) and (bit2btn[(i * 8) + b] <= 34)) { // hatswitch (Dpad) pressed?"
31 through 34... are these the numeric values of Byte 4?

Do I need to change that? My Byte 4 reads 00000000 when pressed... so a numeric value of 0?
Since all my buttons read 0 when pressed: HatUp, HatDown, HatLeft, HatRight... will also all read 0?

All my buttons will read 0?

e.g. in Blue above, $currBytes3 & pos 0 && currBytes2 & 0x3c

does that add up to 0 to press the Hat?

Further on the Hat
Code:
else Joystick.button(0, (bit2btn[(i * 8) + b] - 31) * 90); // direction in 0, 90, 180, 270 degrees
} else Joystick.button(bit2btn[(i * 8) + b], btnState);  // send the update

The hat angle code is in there at 90 deg increments. That switch is not a high quality item and is really finniky to use. I think all TM wheels have that switch set to a 4+Push rather than an actual Hat. The HatPush is in Byte 4. All of Byte 4.. and every Hatpress is combo with it.

11000101 11111111 11111111 11111111 - Nothing
11000101 11111111 11111111 00000000 - HatPush
11000101 11111111 11101111 00000000 - HatUp, no push
11000101 11111111 11011111 00000000 - HatLeftt, no push
11000101 11111111 11110111 00000000 - HatRight, no push
11000101 11111111 11111011 00000000 - HatDown, no push

I think it would be easier to forget this is a HatSwitch/D-Pad and treat it like 5 separate buttons if the way it's setup will allow?
 
Last edited:
....

all of which leaves me with this:
Code:
/*
   Byte 1                         Byte 2                        Byte 3                        Byte 4
   7 - constant 1                 7 - right paddle (2)          7 - bottom left yellow (3)    7 - 0 when Dpad pressed
   6 - constant 1                 6 - top right black (5)       6 - top left red (10)         6 - 0 when Dpad pressed
   5 - constant 0                 5 - top right red (9)         5 - Dpad left                 5 - 0 when Dpad pressed
   4 - constant 0                 4 - constant 1                4 - Dpad up                   4 - 0 when Dpad pressed
   3 - constant 0                 3 - bottom left red (7)       3 - Dpad right                3 - 0 when Dpad pressed
   2 - constant 1                 2 - bottom right white (13)   2 - Dpad down                 2 - 0 when Dpad pressed
   1 - constant 0                 1 - bottom right red (8)      1 - bottom left yellow (4)    1 - 0 when Dpad pressed
   0 - bottom right yellow (6)    0 - constant 1                0 - left paddle               0 - 0 when Dpad pressed
*/

#include <SPI.h>
#include <Joystick.h>

//Joystick_ Joystick(
//JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 21, 1,    // 21 buttons, 1 hatswitch
//false, false, false, false, false, false,
//false, false, false, false, false);

const int slaveSelectPin = 10;
byte pos[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
byte currBytes[] = {0x00, 0x00, 0x00, 0x00};
byte prevBytes[] = {0x00, 0x00, 0x00, 0x00};
bool btnState, joyBtnState, prevJoyBtnState, buttonsreset;
int bit2btn[] = { -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1}; // working array of buttons

void setup() {
  //input from wheel
  Serial.begin(9600);
  SPI.beginTransaction(SPISettings());
  SPI.begin();
  pinMode(slaveSelectPin, INPUT);

  //output to joystick
  Joystick.begin();
}

void loop() {
  // tell the wheel, that we are ready to read the data now
  digitalWrite(slaveSelectPin, HIGH);
  // the chips in the wheel need some time to wake up
  delayMicroseconds(40);

  // read the wheel
  for (int i = 0; i < 4; i++) {
    (currBytes[i]) = ~SPI.transfer(0x00);
    delayMicroseconds(40);
  }

  // release the wheel
  digitalWrite(slaveSelectPin, LOW);
  delayMicroseconds(40);

  // assign the buttons

  for (int i = 0; i < 4; i++) //process the four bytes
    for (int b = 0; b < 8; b++) //one bit at a time
      if ((currBytes[i] & pos[b]) != (prevBytes[i] & pos[b])) {                    // if the buttonstate has changed
        btnState = currBytes[i] & pos[b];
        if (btnState == 0)                                                         // button released?
          Joystick.button(bit2btn[(i * 8) + b], 1);                                // press button
        if (btnState >= 1)
          Joystick.button(bit2btn[(i * 8) + b], 0);                                //release button
      }

  for (int i = 0; i < 4; i++)
    prevBytes[i] = currBytes[i];   // finally update the just read input to the the previous input for the next cycle

  prevJoyBtnState = joyBtnState;
}

... and still no buttons.
 
Last edited:
Last revision before bed.

I think I'm starting to understand how the button press/release loop works,... but obviously not well enough.

"int R383Btn[]" has gone back in to give assignable button numbers
"memcpy" to translate (bit2btn->R383btn) is in the 'setup', might it be better after the 'read'?

I took "joyBtnState" out. But now I'm thinking that's what TLC sends to Windows, while "btnState" is what the wheel sends to TLC?

If any code fairies want to fix this while I'm sleeping, that'd be great cheers..

Code:
/*
   Byte 1                         Byte 2                        Byte 3                        Byte 4
   7 - constant 1                 7 - right paddle (2)          7 - bottom left yellow (3)    7 - 0 when Dpad pressed
   6 - constant 1                 6 - top right black (5)       6 - top left red (10)         6 - 0 when Dpad pressed
   5 - constant 0                 5 - top right red (9)         5 - Dpad left                 5 - 0 when Dpad pressed
   4 - constant 0                 4 - constant 1                4 - Dpad up                   4 - 0 when Dpad pressed
   3 - constant 0                 3 - bottom left red (7)       3 - Dpad right                3 - 0 when Dpad pressed
   2 - constant 1                 2 - bottom right white (13)   2 - Dpad down                 2 - 0 when Dpad pressed
   1 - constant 0                 1 - bottom right red (8)      1 - bottom left yellow (4)    1 - 0 when Dpad pressed
   0 - bottom right yellow (6)    0 - constant 1                0 - left paddle (1)           0 - 0 when Dpad pressed
*/

#include <SPI.h>
#include <Joystick.h>

//Joystick_ Joystick(
//JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 21, 1,                                                                                                // 21 buttons, 1 hatswitch
//false, false, false, false, false, false,
//false, false, false, false, false);

const int slaveSelectPin = 10;
byte pos[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
byte currBytes[] = {0x00, 0x00, 0x00, 0x00};
byte prevBytes[] = {0x00, 0x00, 0x00, 0x00};
bool btnState, prevBtnState;
int bit2btn[] = { -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1};      //working array of buttons
int R383Btn[] = { -1, -1, -1, -1, -1, -1, -1, 5,  1, 4, 8, -1, 6, 12, 7, -1,  2, 9, 34, 31, 32, 33, 3, 0,  -1, -1, -1, -1, -1, -1, -1, -1};                //R383 button numbers
//int R383Btn[] = {-1,-1,-1,-1,-1,-1,-1,6,  2,5,9,-1,7,13,8,-1,  3,10,12,13,14,15,4,1,  11,-1,-1,-1,-1,-1,-1,-1};                                          //TM R383 button numbers

void setup() {
  //input from wheel
  Serial.begin(9600);
  SPI.beginTransaction(SPISettings());
  pinMode(slaveSelectPin, OUTPUT);
  SPI.begin();
  //output to joystick
  memcpy(bit2btn, R383Btn, sizeof(R383Btn));                                                                                                               // Setup or Loop? Convert bit2btn
  Joystick.begin();

}

void loop() {
  // tell the wheel, that we are ready to read the data now
  digitalWrite(slaveSelectPin, LOW);
  // the chips in the wheel need some time to wake up
  delayMicroseconds(40);

  // read the wheel
  for (int i=0; i<4; i++) {
    (currBytes[i]) = ~SPI.transfer(0x00);
    delayMicroseconds(40);
  }

  // release the wheel
  digitalWrite(slaveSelectPin, HIGH);
  delayMicroseconds(40);

  // press/release loop

  for (int i=0; i<4; i++)                                                                                                                                  //process the four bytes
    for (int b=0; b<8; b++)                                                                                                                                //one bit at a time
      if ((currBytes[i] & pos[b]) != (prevBytes[i] & pos[b])) {                                                                                            // if the buttonstate has changed
        btnState = currBytes[i] & pos[b];
        Joystick.button(bit2btn[(i*8) + b], btnState);                                                                                                     // press/release button
      }

  for (int i=0; i<4; i++)
    prevBytes[i] = currBytes[i];                                                                                                                           // finally update the just read input to the the previous input for the next cycle
  prevBtnState = btnState;
}

It's a shame ↓this↓ doesn't work:
Code:
  // press/release loop

  for (int i=0; i<4; i++)                                                                                                                                                                         
    for (int b=0; b<8; b++)                                                                                                                                                                    
      if ((currBytes[i] & pos[b]) != (prevBytes[i] & pos[b])) {                                                                                                         
        btnState = currBytes[i] & pos[b];
        Joystick.button(bit2btn[(i*8) + b], btnState);                                                                                                                     
      }

I like how simple it is.
 
Last edited:
Code:
  if ((wheelIdentified) and (wheelID == 3)) {                         // only for R383 wheel
    joyBtnState = (currBytes[3] & pos[0]) && !(currBytes[2] & 0x3c);  // if hatswitch is pressed in the middle
    if (joyBtnState != prevJoyBtnState)
      Joystick.setButton(13, joyBtnState);                            // press button 14
  }

It looks like joyBtnState was used only for the hatswitch.

" Joystick.setButton(13, joyBtnState); // press button 14"

is that jsut a typo?
 
I've managed to get the code to the barest of bones:

Code:
JUST PRESS THE BUTTON!

I know TLC can read & process buttonstate and changes to buttonstate through Serial Print/Serial Monitor..
I've seen this in action.

... but I haven't seen TLC sending a buttonstate or changes to buttonstate to Windows.

So, I thought this would be a lot easier if I could [press the button], and then move on to the nuance of pressing a specific button at a particular time.

Code:
#include <SPI.h>
#include <Joystick.h>

const int slaveSelectPin = 10;

void setup() {
  Joystick.begin();
}

void loop() {
  Joystick.button(1, 1);
}
 
This should get all the button(x, 1) lit up, right?

Screenshot (1039).png
 
This is what USBView is seeing
Screenshot (1040).png
Code:
[Port8]  :  USB Composite Device


Is Port User Connectable:         yes
Is Port Debug Capable:            no
Companion Port Number:            0
Companion Hub Symbolic Link Name: 
Protocols Supported:
 USB 1.1:                         yes
 USB 2.0:                         yes
 USB 3.0:                         no

Device Power State:               PowerDeviceD0

       ---===>Device Information<===---
English product name: "Keyboard/Mouse/Joystick"

ConnectionStatus:                  
Current Config Value:              0x01  -> Device Bus Speed: Full (is not SuperSpeed or higher capable)
Device Address:                    0x54
Open Pipes:                           6

          ===>Device Descriptor<===
bLength:                           0x12
bDescriptorType:                   0x01
bcdUSB:                          0x0110
bDeviceClass:                      0x00  -> This is an Interface Class Defined Device
bDeviceSubClass:                   0x00
bDeviceProtocol:                   0x00
bMaxPacketSize0:                   0x40 = (64) Bytes
idVendor:                        0x16C0 = Van Ooijen Technische Informatica
idProduct:                       0x0482
bcdDevice:                       0x0273
iManufacturer:                     0x01
     English (United States)  "Teensyduino"
iProduct:                          0x02
     English (United States)  "Keyboard/Mouse/Joystick"
iSerialNumber:                     0x03
     English (United States)  "9364450"
bNumConfigurations:                0x01

          ---===>Open Pipes<===---

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x83  -> Direction: IN - EndpointID: 3
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0008 = 0x08 bytes
bInterval:                         0x01

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x85  -> Direction: IN - EndpointID: 5
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0008 = 0x08 bytes
bInterval:                         0x01

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x81  -> Direction: IN - EndpointID: 1
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0040 = 0x40 bytes
bInterval:                         0x01

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x02  -> Direction: OUT - EndpointID: 2
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0020 = 0x20 bytes
bInterval:                         0x02

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x84  -> Direction: IN - EndpointID: 4
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x000C = 0x0C bytes
bInterval:                         0x02

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x86  -> Direction: IN - EndpointID: 6
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0008 = 0x08 bytes
bInterval:                         0x04

       ---===>Full Configuration Descriptor<===---

          ===>Configuration Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x02
wTotalLength:                    0x008D  -> Validated
bNumInterfaces:                    0x05
bConfigurationValue:               0x01
iConfiguration:                    0x00
bmAttributes:                      0xC0  -> Self Powered
MaxPower:                          0x32 = 100 mA

          ===>Interface Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x04
bInterfaceNumber:                  0x00
bAlternateSetting:                 0x00
bNumEndpoints:                     0x01
bInterfaceClass:                   0x03  -> HID Interface Class
bInterfaceSubClass:                0x01
bInterfaceProtocol:                0x01
iInterface:                        0x00

          ===>HID Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x21
bcdHID:                          0x0111
bCountryCode:                      0x00
bNumDescriptors:                   0x01
bDescriptorType:                   0x22 (Report Descriptor)
wDescriptorLength:               0x003F

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x83  -> Direction: IN - EndpointID: 3
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0008 = 0x08 bytes
bInterval:                         0x01

          ===>Interface Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x04
bInterfaceNumber:                  0x01
bAlternateSetting:                 0x00
bNumEndpoints:                     0x01
bInterfaceClass:                   0x03  -> HID Interface Class
bInterfaceSubClass:                0x00
bInterfaceProtocol:                0x00
iInterface:                        0x00

          ===>HID Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x21
bcdHID:                          0x0111
bCountryCode:                      0x00
bNumDescriptors:                   0x01
bDescriptorType:                   0x22 (Report Descriptor)
wDescriptorLength:               0x0054

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x85  -> Direction: IN - EndpointID: 5
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0008 = 0x08 bytes
bInterval:                         0x01

          ===>Interface Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x04
bInterfaceNumber:                  0x02
bAlternateSetting:                 0x00
bNumEndpoints:                     0x02
bInterfaceClass:                   0x03  -> HID Interface Class
bInterfaceSubClass:                0x00
bInterfaceProtocol:                0x00
iInterface:                        0x00

          ===>HID Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x21
bcdHID:                          0x0111
bCountryCode:                      0x00
bNumDescriptors:                   0x01
bDescriptorType:                   0x22 (Report Descriptor)
wDescriptorLength:               0x0021

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x81  -> Direction: IN - EndpointID: 1
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0040 = 0x40 bytes
bInterval:                         0x01

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x02  -> Direction: OUT - EndpointID: 2
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0020 = 0x20 bytes
bInterval:                         0x02

          ===>Interface Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x04
bInterfaceNumber:                  0x03
bAlternateSetting:                 0x00
bNumEndpoints:                     0x01
bInterfaceClass:                   0x03  -> HID Interface Class
bInterfaceSubClass:                0x00
bInterfaceProtocol:                0x00
iInterface:                        0x00

          ===>HID Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x21
bcdHID:                          0x0111
bCountryCode:                      0x00
bNumDescriptors:                   0x01
bDescriptorType:                   0x22 (Report Descriptor)
wDescriptorLength:               0x0055

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x84  -> Direction: IN - EndpointID: 4
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x000C = 0x0C bytes
bInterval:                         0x02

          ===>Interface Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x04
bInterfaceNumber:                  0x04
bAlternateSetting:                 0x00
bNumEndpoints:                     0x01
bInterfaceClass:                   0x03  -> HID Interface Class
bInterfaceSubClass:                0x00
bInterfaceProtocol:                0x00
iInterface:                        0x00

          ===>HID Descriptor<===
bLength:                           0x09
bDescriptorType:                   0x21
bcdHID:                          0x0111
bCountryCode:                      0x00
bNumDescriptors:                   0x01
bDescriptorType:                   0x22 (Report Descriptor)
wDescriptorLength:               0x0028

          ===>Endpoint Descriptor<===
bLength:                           0x07
bDescriptorType:                   0x05
bEndpointAddress:                  0x86  -> Direction: IN - EndpointID: 6
bmAttributes:                      0x03  -> Interrupt Transfer Type
wMaxPacketSize:                  0x0008 = 0x08 bytes
bInterval:                         0x04
 
Sorry I don't really do that much with some of the different USB types...

But for me on a Teensy 3.2 I tried simple sketch:
Code:
uint8_t button_index = 1;
void setup() {
  pinMode(13, OUTPUT);
}
void loop() {
  digitalToggleFast(13);
  Joystick.button(button_index, 0);
  button_index = (button_index == 32)? 1 : button_index + 1;
  Joystick.button(button_index, 1);
  delay(250);
}

I built for usb type: keyboard, mouse, joystick...

I brought up the Gametroller or the like on Windows 11

And it does show it walking through the buttons...
Screenshot.jpg
 
Nice thank you Kurt.

I go this up and running:
Screenshot (1042).png

Unfortunately I also discovered the reason it wasn't working before:

IMG_20230118_151746_2.jpg

Hamfistedness is Key to understanding quite a few 'unexplained' problems I feel.
So, I'm going to have to work through everything from the beginning I think.
 
I dont know if these white text warnings matter, but during verify/upload, I'm ocassionally getting:

Code:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3\usb_keyboard.c: In function 'unicode_to_keycode':
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3\usb_keyboard.c:151:40: warning: large integer implicitly truncated to unsigned type [-Woverflow]
  if (cpoint == UNICODE_EXTRA00) return (KEYCODE_EXTRA00) & 0x3FFF;

I was specifically running ↓this↓, but I'm getting them regulalry, though not every time I verify/upload.

Code:
#include <Joystick.h>

void setup() {
  Joystick.begin();
}
void loop() {
  Joystick.button(1, 1);
}
 
I dont know if these white text warnings matter, but during verify/upload, I'm ocassionally getting:

Code:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3\usb_keyboard.c: In function 'unicode_to_keycode':
C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3\usb_keyboard.c:151:40: warning: large integer implicitly truncated to unsigned type [-Woverflow]
  if (cpoint == UNICODE_EXTRA00) return (KEYCODE_EXTRA00) & 0x3FFF;

I was specifically running ↓this↓, but I'm getting them regulalry, though not every time I verify/upload.

Code:
#include <Joystick.h>

void setup() {
  Joystick.begin();
}
void loop() {
  Joystick.button(1, 1);
}

My guess is Paul and/or someone who uses international keyboards should take a look at this.

I am assuming you are using a none US keyboard for this.
 
Yep, UK English.

Might it be a hardware related issue? Board currently wont run either of the [just press the button] scripts.
My hamfistedness could well have carried over into the repairs for my previous hamfistedness.

if (currHamfistedness >= prevHamfistedness)
bork;
 
Thank you Shawn. I've applied the changes, but I'm currently resoldering my board so I wont have any tests until this evening.
 
I am become coder

Screenshot (1043).jpg

Code:
/*
   Byte 1                         Byte 2                        Byte 3                        Byte 4
   7 - constant 1                 7 - right paddle (2)          7 - bottom left yellow (3)    7 - 0 when Dpad pressed
   6 - constant 1                 6 - top right black (5)       6 - top left red (10)         6 - 0 when Dpad pressed
   5 - constant 0                 5 - top right red (9)         5 - Dpad left                 5 - 0 when Dpad pressed
   4 - constant 0                 4 - constant 1                4 - Dpad up                   4 - 0 when Dpad pressed
   3 - constant 0                 3 - bottom left red (7)       3 - Dpad right                3 - 0 when Dpad pressed
   2 - constant 1                 2 - bottom right white (13)   2 - Dpad down                 2 - 0 when Dpad pressed
   1 - constant 0                 1 - bottom right red (8)      1 - bottom left yellow (4)    1 - 0 when Dpad pressed
   0 - bottom right yellow (6)    0 - constant 1                0 - left paddle               0 - 0 when Dpad pressed
*/

#include <SPI.h>
#include <Joystick.h>

//Joystick_ Joystick(
//JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 21, 1,                                                                                                // 21 buttons, 1 hatswitch
//false, false, false, false, false, false,
//false, false, false, false, false);

const int slaveSelectPin = 10;
byte pos[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
byte currBytes[] = {0x00, 0x00, 0x00, 0x00};
byte prevBytes[] = {0x00, 0x00, 0x00, 0x00};
bool btnState, prevBtnState, joyBtnState, prevJoyBtnState;
int bit2btn[] = { -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1,  -1, -1, -1, -1, -1, -1, -1, -1 } ;      //working array of buttons
int R383Btn[] = { -1, -1, -1, -1, -1, -1, -1, 8,  2, 11, 10, -1, 5, 7, 6, -1,  4, 9, 15, 12, 13, 14, 3, 1,  16, 16, 16, 16, 16, 16, 16, 16};                //R383 button numbers

void setup() {
  //input from wheel
  SPI.begin();
  SPI.beginTransaction(SPISettings());
  pinMode(slaveSelectPin, OUTPUT);

  //output to joystick
  Joystick.begin();
}

void loop() {
  // tell the wheel, that we are ready to read the data now
  digitalWrite(slaveSelectPin, LOW);
  // the chips in the wheel need some time to wake up
  delayMicroseconds(40);

  // read the wheel's 4 bytes
  for (int i = 0; i < 4; i++) {
    currBytes[i] = ~SPI.transfer(0x00);
    delayMicroseconds(40);
  }

  // release the wheel
  digitalWrite(slaveSelectPin, HIGH);
  delayMicroseconds(40); {

    memcpy(bit2btn, R383Btn, sizeof(R383Btn)); // button numbers R383 wheel to working array

    // deal with the buttons first
    for (int i = 0; i < 4; i++) //process the four bytes
      for (int b = 0; b < 8; b++) //one bit at a time
        if ((currBytes[i] & pos[b]) != (prevBytes[i] & pos[b])) { // if the buttonstate has changed
          btnState = currBytes[i] & pos[b];
          Joystick.button(bit2btn[(i * 8) + b], btnState);  // send the update
        }
        
    for (int i = 0; i < 4; i++)
      prevBytes[i] = currBytes[i];   // finally update the just read input to the the previous input for the next cycle

    prevJoyBtnState = joyBtnState;
  }
}


This is basically what I had in #37, I think. The hardware issues I've been having which caused the original look into this wheel might have been cropping up and I think I'm tracing those to my USB powered soundcard.
They've been messing, I htink, with the entire USB bus, and hoipefully moving that to a separate PCIe bus will solve the issues.

I have still to separate hatpress from hatpush, but Kurt, defrag and Shawn... thank you.
 
Back
Top