Created
May 13, 2015 02:20
-
-
Save SenpaiSilver/d3aa26c6f42dec8d191a to your computer and use it in GitHub Desktop.
Joystick Emulation for Leonardo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//#define RAWHID_ENABLED | |
#define JOYHID_ENABLED | |
Joystick_ Joystick; | |
const u8 _hidReportDescriptor[] = { | |
// Mouse | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 54 | |
0x09, 0x02, // USAGE (Mouse) | |
0xa1, 0x01, // COLLECTION (Application) | |
0x09, 0x01, // USAGE (Pointer) | |
0xa1, 0x00, // COLLECTION (Physical) | |
0x85, 0x01, // REPORT_ID (1) | |
0x05, 0x09, // USAGE_PAGE (Button) | |
0x19, 0x01, // USAGE_MINIMUM (Button 1) | |
0x29, 0x03, // USAGE_MAXIMUM (Button 3) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x01, // LOGICAL_MAXIMUM (1) | |
0x95, 0x03, // REPORT_COUNT (3) | |
0x75, 0x01, // REPORT_SIZE (1) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0x95, 0x01, // REPORT_COUNT (1) | |
0x75, 0x05, // REPORT_SIZE (5) | |
0x81, 0x03, // INPUT (Cnst,Var,Abs) | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
0x09, 0x30, // USAGE (X) | |
0x09, 0x31, // USAGE (Y) | |
0x09, 0x38, // USAGE (Wheel) | |
0x15, 0x81, // LOGICAL_MINIMUM (-127) | |
0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x95, 0x03, // REPORT_COUNT (3) | |
0x81, 0x06, // INPUT (Data,Var,Rel) | |
0xc0, // END_COLLECTION | |
0xc0, // END_COLLECTION | |
// Keyboard | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) // 47 | |
0x09, 0x06, // USAGE (Keyboard) | |
0xa1, 0x01, // COLLECTION (Application) | |
0x85, 0x02, // REPORT_ID (2) | |
0x05, 0x07, // USAGE_PAGE (Keyboard) | |
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) | |
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x01, // LOGICAL_MAXIMUM (1) | |
0x75, 0x01, // REPORT_SIZE (1) | |
0x95, 0x08, // REPORT_COUNT (8) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0x95, 0x01, // REPORT_COUNT (1) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x81, 0x03, // INPUT (Cnst,Var,Abs) | |
0x95, 0x06, // REPORT_COUNT (6) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x65, // LOGICAL_MAXIMUM (101) | |
0x05, 0x07, // USAGE_PAGE (Keyboard) | |
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) | |
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) | |
0x81, 0x00, // INPUT (Data,Ary,Abs) | |
0xc0, // END_COLLECTION | |
#ifdef RAWHID_ENABLED | |
// RAW HID | |
0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 | |
0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), | |
0xA1, 0x01, // Collection 0x01 | |
0x85, 0x03, // REPORT_ID (3) | |
0x75, 0x08, // report size = 8 bits | |
0x15, 0x00, // logical minimum = 0 | |
0x26, 0xFF, 0x00, // logical maximum = 255 | |
0x95, 64, // report count TX | |
0x09, 0x01, // usage | |
0x81, 0x02, // Input (array) | |
0x95, 64, // report count RX | |
0x09, 0x02, // usage | |
0x91, 0x02, // Output (array) | |
0xC0 // end collection | |
#endif | |
// *** Here is where the RAW_HID has been converted to a Joystick device | |
// *** Inspired by helmpcb.com/electronics/usb-joystick | |
// *** Check out www.usb.org/developers/hidpage/ for more than you'll ever need to know about USB HID | |
// *** HID descriptor created using the HID descriptor tool from www.usb.org/developers/hidpage/dt2_4.zip (win32) | |
#ifdef JOYHID_ENABLED | |
// 32 buttons (and a throttle - just in case the game doesn't recognise a joystick with no analog axis) | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
0x09, 0x04, // USAGE (Joystick) | |
0xa1, 0x01, // COLLECTION (Application) | |
0x85, 0x03, // REPORT_ID (3) (This is important when HID_SendReport() is called) | |
//Buttons: | |
0x05, 0x09, // USAGE_PAGE (Button) | |
0x19, 0x01, // USAGE_MINIMUM (Button 1) | |
0x29, 0x20, // USAGE_MAXIMUM (Button 32) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x01, // LOGICAL_MAXIMUM (1) | |
0x75, 0x01, // REPORT_SIZE (1) | |
0x95, 0x20, // REPORT_COUNT (32) | |
0x55, 0x00, // UNIT_EXPONENT (0) | |
0x65, 0x00, // UNIT (None) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
// 8 bit Throttle and Steering | |
0x05, 0x02, // USAGE_PAGE (Simulation Controls) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) | |
0xA1, 0x00, // COLLECTION (Physical) | |
0x09, 0xBB, // USAGE (Throttle) | |
0x09, 0xBA, // USAGE (Steering) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x95, 0x02, // REPORT_COUNT (2) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0xc0, // END_COLLECTION | |
// Two Hat switches | |
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |
0x09, 0x39, // USAGE (Hat switch) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x07, // LOGICAL_MAXIMUM (7) | |
0x35, 0x00, // PHYSICAL_MINIMUM (0) | |
0x46, 0x3B, 0x01, // PHYSICAL_MAXIMUM (315) | |
0x65, 0x14, // UNIT (Eng Rot:Angular Pos) | |
0x75, 0x04, // REPORT_SIZE (4) | |
0x95, 0x01, // REPORT_COUNT (1) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0x09, 0x39, // USAGE (Hat switch) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x25, 0x07, // LOGICAL_MAXIMUM (7) | |
0x35, 0x00, // PHYSICAL_MINIMUM (0) | |
0x46, 0x3B, 0x01, // PHYSICAL_MAXIMUM (315) | |
0x65, 0x14, // UNIT (Eng Rot:Angular Pos) | |
0x75, 0x04, // REPORT_SIZE (4) | |
0x95, 0x01, // REPORT_COUNT (1) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0x15, 0x00, // LOGICAL_MINIMUM (0) | |
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) | |
0x75, 0x08, // REPORT_SIZE (8) | |
0x09, 0x01, // USAGE (Pointer) | |
0xA1, 0x00, // COLLECTION (Physical) | |
0x09, 0x30, // USAGE (x) | |
0x09, 0x31, // USAGE (y) | |
0x09, 0x32, // USAGE (z) | |
0x09, 0x33, // USAGE (rx) | |
0x09, 0x34, // USAGE (ry) | |
0x09, 0x35, // USAGE (rz) | |
0x95, 0x06, // REPORT_COUNT (2) | |
0x81, 0x02, // INPUT (Data,Var,Abs) | |
0xc0, // END_COLLECTION | |
0xc0 // END_COLLECTION | |
#endif | |
}; | |
//================================================================================ | |
//================================================================================ | |
// 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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
JoyState_t joySt; | |
void setup() { | |
// put your setup code here, to run once: | |
pinMode(13, OUTPUT); | |
} | |
void loop() { | |
// put your main code here, to run repeatedly: | |
joySt.xAxis = random(255); | |
joySt.yAxis = random(255); | |
joySt.zAxis = random(255); | |
joySt.xRotAxis = random(255); | |
joySt.yRotAxis = random(255); | |
joySt.zRotAxis = random(255); | |
//joySt.throttle = random(255); | |
joySt.rudder = random(255); | |
joySt.throttle++; | |
joySt.buttons <<= 1; | |
if (joySt.buttons == 0) | |
joySt.buttons = 1; | |
joySt.hatSw1++; | |
joySt.hatSw2--; | |
if (joySt.hatSw1 > 8) | |
joySt.hatSw1 = 0; | |
if (joySt.hatSw2 > 8) | |
joySt.hatSw2 = 8; | |
delay(100); | |
if (joySt.throttle > 127) | |
digitalWrite(13, HIGH); | |
else | |
digitalWrite(13, LOW); | |
// Call Joystick.move | |
Joystick.setState(&joySt); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//================================================================================ | |
//================================================================================ | |
// 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; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment