Go Down

Topic: FAST HID Joystick converter for 2 digital joysticks (Read 4953 times) previous topic - next topic

olaf

Nov 25, 2012, 12:17 pm Last Edit: Dec 04, 2013, 12:40 pm by olaf Reason: 1
Hi,
if you want to connect some oldshool digital joysticks like the competition pro to your pc, ps3, raspberry pi or whatever here's a simple and fast solution. It's also perfect to build your retro commodore amiga/c64/atari/sega...

This code transforms the arduino leonardo board into a HID joystick converter for two digital joysticks.


put this into your HID.cpp to create 2 HID Gamepads:
Code: [Select]

//   Commodore /  Atari Joystick 1

  0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
  0x09, 0x05,                    // USAGE (Game Pad)
  0xa1, 0x01,                    // COLLECTION (Application)
  0x85, 0x03,                    //   REPORT_ID (3)
  0x09, 0x01,                    //   USAGE (Pointer)
  0xa1, 0x00,                    //   COLLECTION (Physical)
  0x09, 0x30,                    //     USAGE (X)
  0x09, 0x31,                    //     USAGE (Y)
  0x15, 0xff,                    //     LOGICAL_MINIMUM (-1)
  0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
  0x95, 0x02,                    //     REPORT_COUNT (2)
  0x75, 0x02,                    //     REPORT_SIZE (2) ; two bits to represent each axis
  0x81, 0x02,                    //     INPUT (Data,Var,Abs)
  0xc0,                          //   END_COLLECTION
  0x05, 0x09,                    //   USAGE_PAGE (Button)
  0x19, 0x01,                    //   USAGE_MINIMUM (Button 1)
  0x29, 0x01,                    //   USAGE_MAXIMUM (Button 1)
  0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
  0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
  0x95, 0x01,                    //   REPORT_COUNT (1) ; 1 button
  0x75, 0x01,                    //   REPORT_SIZE (1)
  0x81, 0x02,                    //   INPUT (Data,Var,Abs)
  0x95, 0x02,                    //   REPORT_COUNT (2) ; to pad out the bits into a number divisible by 8
  0x81, 0x03,                    //   INPUT (Const,Var,Abs)
   0x05, 0x09,                    //   USAGE_PAGE (Button)
  0x19, 0x02,                    //   USAGE_MINIMUM (Button 2)
  0x29, 0x02,                    //   USAGE_MAXIMUM (Button 2)
  0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
  0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
  0x95, 0x01,                    //   REPORT_COUNT (1) ; 1 button
  0x75, 0x01,                    //   REPORT_SIZE (1)
  0x81, 0x02,                    //   INPUT (Data,Var,Abs)
  0xc0,                          // END_COLLECTION

//   Commodore /  Atari Joystick 2

  0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
  0x09, 0x05,                    // USAGE (Game Pad)
  0xa1, 0x01,                    // COLLECTION (Application)
  0x85, 0x04,                    //   REPORT_ID (4)
   0xa1, 0x00,                    //   COLLECTION (Physical)  
  0x05, 0x09,                    //   USAGE_PAGE (Button)
  0x19, 0x01,                    //   USAGE_MINIMUM (Button 1)
  0x29, 0x02,                    //   USAGE_MAXIMUM (Button 2)
  0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
  0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
  0x95, 0x02,                    //   REPORT_COUNT (2) ; 2 buttons
  0x75, 0x01,                    //   REPORT_SIZE (1)
  0x81, 0x02,                    //   INPUT (Data,Var,Abs)
   0x95, 0x02,                    //   REPORT_COUNT (2) ; to pad out the bits into a number divisible by 8
  0x81, 0x03,                    //   INPUT (Const,Var,Abs)
   0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
  0x09, 0x30,                    //     USAGE (X)
  0x09, 0x31,                    //     USAGE (Y)
  0x15, 0xff,                    //     LOGICAL_MINIMUM (-1)
  0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
  0x95, 0x02,                    //     REPORT_COUNT (2)
  0x75, 0x02,                    //     REPORT_SIZE (2) ; two bits to represent each axis
  0x81, 0x02,                    //     INPUT (Data,Var,Abs)
  0xc0,                          //   END_COLLECTION
  0xc0                           // END_COLLECTION    



merge this into your existing sketch or use it as a standalone solution:

Code: [Select]

   uint8_t Joy;
   uint8_t MemoJoy1 ;
   uint8_t MemoJoy2 ;

   void setup() {

     // Joystick 1
     pinMode(0, INPUT_PULLUP);                  // configure as DigIn  with pull up
     pinMode(1, INPUT_PULLUP);
     pinMode(2, INPUT_PULLUP);
     pinMode(3, INPUT_PULLUP);
     pinMode(4, INPUT_PULLUP);
     pinMode(5, INPUT_PULLUP);
   
     // Joystick 2
     pinMode(A0, INPUT_PULLUP);
     pinMode(A1, INPUT_PULLUP);
     pinMode(A2, INPUT_PULLUP);
     pinMode(A3, INPUT_PULLUP);
     pinMode(A4, INPUT_PULLUP);
     pinMode(A5, INPUT_PULLUP);

   }

   void loop()
   {         // Joystick 1
         Joy = ~PIND & 0b10011111;     // read Port D, invert logic, mask relevant bits
         if (Joy != MemoJoy1) {        // state changed?
           HID_SendReport(3, &Joy, 1); // send HID report
           MemoJoy1 = Joy;             // save last state
         }
        // Joystick 2
         Joy = ~PINF & 0b11110011;
         if (Joy != MemoJoy2) {
           HID_SendReport(4, &Joy, 1);
           MemoJoy2 = Joy;
         }
      }


Joystick 1 must be hooked up to digital inputs 0...5, joystck 2 to analog inputs A0...A5.
This is the pin assignment:

Code: [Select]
   Joystick 1

   IO DB9  Function

   1   1   Forward
   0   2   Back
   2   3   Left
   3   4   Right
       5   not connected
   4   6   Button1
   5V  7   +5V  ( only needed if the joystick contains circuits like autofire,.. )
   GND 8   Ground
   6   9   Button2 (optional)

   Joystick 2

   IO DB9  Function

   A0  1   Forward
   A1  2   Back
   A2  3   Left
   A3  4   Right
       5   not connected
   A5  6   Button1
   5V  7   +5V
   GND 8   Ground
   A4  9   Button2 (optional)


Together with the arduino keyboard interface http://forum.arduino.cc/index.php?topic=139358.0
you have the complete keyrah functionality for an Amiga 500/1000/2000.

Olaf



Dipl. Ing. (FH) Olaf Berthold
Hardware- und Softwareentwicklung


masavee

interesting but i ask now,i know can do but how (im newbie)
leonardo or uno who have better thats ?
i need 32 button interface hid interface
8 analog inbut and 16 encoder inbut.
how make hid interface to have all thats ?
ino to in arduino, what more need ?
i understand leonardo have hid ready board no need change bootloader, and uno no have hid compatiple need bootloader new write.

and hid device can adding 32 button, 16 encoder,8 analog inbut.
but how :(
i need only buttons and encoders my computer.
analog can take old joystick.mean usb board if need,

And implemented for Atari ST/TT/Falcon keyboards. Only works with joystick in port 1. Have to figure out how to read the data from the mouse/joystick0 port..



Code: [Select]
// Wiring
// ST --- Arduino
// 1   -  GND
// ( blank )
// 3   - FDD LED (Not used)
// 4   -  +5V
// 5   -  0
// 6   -  1
// 7   -  2
// 8   -  GND

void setup() {
  Serial1.begin(7812);
  delay(200);
  reset_st_keyboard();
  delay(200);
  while (Serial1.available() > 0) Serial1.read();
}

void reset_st_keyboard(void)
{
  Serial1.print(0x80);
  Serial1.print(1);
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(20);
  digitalWrite(2, LOW);
  delay(20);
  digitalWrite(2, HIGH);
}

int joy0 = 0;
int joy1 = 0;
int joy1button = 0b0;
int key;
int lastkey;

uint8_t joyCodes[] =
{
  0b0,
  0b1, // N
  0b11, // S
  0b00,
  0b1100, // W
  0b1101, // NW
  0b1111, // NE
  0b00,
  0b100, // E
  0b101, // NE
  0b111 // SE
};

void loop() {
  while (Serial1.available() > 0) {
    key = Serial1.read();
    switch ( lastkey ) {
    case 0xFF: // Joy 1
      Serial.println(joy1button, BIN);
      joy1 = joyCodes[key] | joy1button ;
      HID_SendReport(3, &joy1, 1);
      break;
    case 0xF9: // Joy1 button
      joy1button = 0b110000;
      joy1 = joy1 | 0b110000;
      HID_SendReport(3, &joy1, 1);

      break;
    case 0xF8: // Joy1 button
      joy1button = 0b0;
      joy1 = joy1 ^ 0b110000;
      HID_SendReport(3, &joy1, 1);
      break;
    default:
    }
    lastkey = key;

  }

}


Go Up