Pages: [1]   Go Down
Author Topic: FAST HID Joystick converter for 2 digital joysticks  (Read 4168 times)
0 Members and 1 Guest are viewing this topic.
Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
//   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:

    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:
   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





* IMG_2753.jpg (66.45 KB, 648x484 - viewed 104 times.)

* IMG_2763.jpg (82.7 KB, 648x484 - viewed 162 times.)
« Last Edit: December 04, 2013, 06:40:11 am by olaf » Logged

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

Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

update: 2nd button added
Logged

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

Offline Offline
Newbie
*
Karma: 0
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-sad
i need only buttons and encoders my computer.
analog can take old joystick.mean usb board if need,
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
// 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;

  }

}

Logged

Pages: [1]   Go Up
Jump to: