From 6dc54042d3da8534c1c9d56bf5db551a7847a513 Mon Sep 17 00:00:00 2001 From: Erland Lewin Date: Sun, 25 Jan 2015 23:02:34 +0100 Subject: [PATCH 1/2] Added code for Joystick and Consumer Control. Untested. Code from: * http://stefanjones.ca/blog/arduino-leonardo-remote-multimedia-keys/ * http://www.imaginaryindustries.com/blog/?p=80 --- hardware/arduino/avr/cores/arduino/HID.cpp | 288 +++++++++++++++++++- hardware/arduino/avr/cores/arduino/USBAPI.h | 82 ++++++ 2 files changed, 367 insertions(+), 3 deletions(-) diff --git a/hardware/arduino/avr/cores/arduino/HID.cpp b/hardware/arduino/avr/cores/arduino/HID.cpp index 75c37b24b2f..3ea72face3c 100644 --- a/hardware/arduino/avr/cores/arduino/HID.cpp +++ b/hardware/arduino/avr/cores/arduino/HID.cpp @@ -1,5 +1,3 @@ - - /* Copyright (c) 2011, Peter Barrett ** ** Permission to use, copy, modify, and/or distribute this software for @@ -23,10 +21,12 @@ //#define RAWHID_ENABLED -// Singletons for mouse and keyboard +// Singletons for mouse, keyboard and joystick Mouse_ Mouse; Keyboard_ Keyboard; +Joystick_ Joystick; +Remote_ Remote; //================================================================================ //================================================================================ @@ -124,6 +124,136 @@ const u8 _hidReportDescriptor[] = { 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) + + // 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 + + //----------------------------------------------------------------------------- + + /* Cross-platform support for controls found on IR Remotes */ + + 0x05, 0x0c, //Usage Page (Consumer Devices) + 0x09, 0x01, //Usage (Consumer Control) + 0xa1, 0x01, //Collection (Application) + 0x85, 0x04, //REPORT_ID (4) + 0x15, 0x00, //Logical Minimum (0) + 0x25, 0x01, //Logical Maximum (1) + 0x09, 0xe9, //Usage (Volume Up) + 0x09, 0xea, //Usage (Volume Down) + 0x75, 0x01, //Report Size (1) + 0x95, 0x02, //Report Count (2) + 0x81, 0x06, //Input (Data, Variable, Relative) + + 0x09, 0xe2, //Usage (Mute) + 0x95, 0x01, //Report Count (1) + 0x81, 0x06, //Input (Data, Variable, Relative) + + 0x09, 0xb0, //Usage (Play) + 0x95, 0x01, //Report Count (1) + 0x81, 0x06, //Input (Data, Variable, Relative) + + 0x09, 0xb1, //Usage (Pause) + 0x95, 0x01, //Report Count (1) + 0x81, 0x06, //Input (Data, Variable, Relative) + + 0x09, 0xb7, //Usage (Stop) + 0x95, 0x01, //Report Count (1) + 0x81, 0x06, //Input (Data, Variable, Relative) + + 0x09, 0xb5, //Usage (Next) + 0x95, 0x01, //Report Count (1) + 0x81, 0x06, //Input (Data, Variable, Relative) + + 0x09, 0xb6, //Usage (Previous) + 0x95, 0x01, //Report Count (1) + 0x81, 0x06, //Input (Data, Variable, Relative) + + 0x09, 0xb3, //Usage (Fast Forward) + 0x95, 0x01, //Report Count (1) + 0x81, 0x06, //Input (Data, Variable, Relative) + + 0x09, 0xb4, //Usage (Rewind) + 0x95, 0x01, //Report Count (1) + 0x81, 0x06, //Input (Data, Variable, Relative) + + 0x95, 0x06, //Report Count (6) Number of bits remaining in byte + 0x81, 0x07, //Input (Constant, Variable, Relative) + 0xc0 //End Collection }; extern const HIDDescriptor _hidInterface PROGMEM; @@ -195,6 +325,54 @@ bool WEAK HID_Setup(Setup& setup) return false; } +//================================================================================ +//================================================================================ +//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 +} + + //================================================================================ //================================================================================ // Mouse @@ -513,6 +691,110 @@ size_t Keyboard_::write(uint8_t c) return p; // just return the result of press() since release() almost always returns 1 } +//================================================================================ +//================================================================================ +//Remote + +Remote_::Remote_(void) +{ +} + +void Remote_::begin(void) +{ +} + +void Remote_::end(void) +{ +} + +void Remote_::increase(void) +{ + u8 m[2]; + m[0] = VOLUME_UP; + m[1] = 0; + HID_SendReport(4,m,2); +} + +void Remote_::decrease(void) +{ + u8 m[2]; + m[0] = VOLUME_DOWN; + m[1] = 0; + HID_SendReport(4,m,2); +} + +void Remote_::mute(void) +{ + u8 m[2]; + m[0] = VOLUME_MUTE; + m[1] = 0; + HID_SendReport(4,m,2); +} + +void Remote_::play(void) +{ + u8 m[2]; + m[0] = REMOTE_PLAY; + m[1] = 0; + HID_SendReport(4,m,2); +} + +void Remote_::pause(void) +{ + u8 m[2]; + m[0] = REMOTE_PAUSE; + m[1] = 0; + HID_SendReport(4,m,2); +} + +void Remote_::stop(void) +{ + u8 m[2]; + m[0] = REMOTE_STOP; + m[1] = 0; + HID_SendReport(4,m,2); +} + +void Remote_::next(void) +{ + u8 m[2]; + m[0] = REMOTE_NEXT; + m[1] = 0; + HID_SendReport(4,m,2); +} + +void Remote_::previous(void) +{ + u8 m[2]; + m[0] = REMOTE_PREVIOUS; + m[1] = 0; + HID_SendReport(4,m,2); +} + +void Remote_::forward(void) +{ + u8 m[2]; + m[0] = 0; + m[1] = REMOTE_FAST_FORWARD >> 8; + HID_SendReport(4,m,2); +} + +void Remote_::rewind(void) +{ + u8 m[2]; + m[0] = 0; + m[1] = REMOTE_REWIND >> 8; + HID_SendReport(4,m,2); +} + +void Remote_::clear(void) +{ + u8 m[2]; + m[0] = 0; + m[1] = 0; + HID_SendReport(4,m,2); +} + #endif #endif /* if defined(USBCON) */ diff --git a/hardware/arduino/avr/cores/arduino/USBAPI.h b/hardware/arduino/avr/cores/arduino/USBAPI.h index 2fab957f930..5fa92f85fc8 100644 --- a/hardware/arduino/avr/cores/arduino/USBAPI.h +++ b/hardware/arduino/avr/cores/arduino/USBAPI.h @@ -183,6 +183,88 @@ class Keyboard_ : public Print }; extern Keyboard_ Keyboard; +//================================================================================ +//================================================================================ +//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_txAxis; + uint8_tyAxis; + uint8_tzAxis; + + uint8_txRotAxis; + uint8_tyRotAxis; + uint8_tzRotAxis; + + uint8_tthrottle; + uint8_trudder; + + uint8_thatSw1; + uint8_thatSw2; + + uint32_tbuttons;// 32 general buttons + +} JoyState_t; + +class Joystick_ +{ + public: + Joystick_(); + + void setState(JoyState_t *joySt); + +}; +extern Joystick_ Joystick; + +//================================================================================ +//================================================================================ +//Remote + +#define REMOTE_CLEAR 0 +#define VOLUME_UP 1 +#define VOLUME_DOWN 2 +#define VOLUME_MUTE 4 +#define REMOTE_PLAY 8 +#define REMOTE_PAUSE 16 +#define REMOTE_STOP 32 +#define REMOTE_NEXT 64 +#define REMOTE_PREVIOUS 128 +#define REMOTE_FAST_FORWARD 256 +#define REMOTE_REWIND 512 + +class Remote_ +{ + private: + public: + Remote_(void); + void begin(void); + void end(void); + + // Volume + void increase(void); + void decrease(void); + void mute(void); + + // Playback + void play(void); + void pause(void); + void stop(void); + + // Track Controls + void next(void); + void previous(void); + void forward(void); + void rewind(void); + + // Send an empty report to prevent repeated actions + void clear(void); +}; +extern Remote_ Remote; + //================================================================================ //================================================================================ // Low level API From b8af6ffc39165448c61bd9934eb743a5cc06cad5 Mon Sep 17 00:00:00 2001 From: Erland Lewin Date: Sun, 25 Jan 2015 23:21:40 +0100 Subject: [PATCH 2/2] Fixed syntax errors in previous commit --- hardware/arduino/avr/cores/arduino/HID.cpp | 4 ++-- hardware/arduino/avr/cores/arduino/USBAPI.h | 22 ++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/hardware/arduino/avr/cores/arduino/HID.cpp b/hardware/arduino/avr/cores/arduino/HID.cpp index 3ea72face3c..547a21ab1ba 100644 --- a/hardware/arduino/avr/cores/arduino/HID.cpp +++ b/hardware/arduino/avr/cores/arduino/HID.cpp @@ -122,7 +122,7 @@ const u8 _hidReportDescriptor[] = { 0x95, 64, // report count RX 0x09, 0x02, // usage 0x91, 0x02, // Output (array) - 0xC0 // end collection + 0xC0, // end collection #endif // *** Here is where the RAW_HID has been converted to a Joystick device // *** Inspired by helmpcb.com/electronics/usb-joystick @@ -201,7 +201,7 @@ const u8 _hidReportDescriptor[] = { 0x81, 0x02,// INPUT (Data,Var,Abs) 0xc0,// END_COLLECTION - 0xc0// END_COLLECTION + 0xc0,// END_COLLECTION //----------------------------------------------------------------------------- diff --git a/hardware/arduino/avr/cores/arduino/USBAPI.h b/hardware/arduino/avr/cores/arduino/USBAPI.h index 5fa92f85fc8..1d75564ed22 100644 --- a/hardware/arduino/avr/cores/arduino/USBAPI.h +++ b/hardware/arduino/avr/cores/arduino/USBAPI.h @@ -192,21 +192,21 @@ extern Keyboard_ Keyboard; typedef struct JoyState // Pretty self explanitory. Simple state to store all the joystick parameters { - uint8_txAxis; - uint8_tyAxis; - uint8_tzAxis; + uint8_t xAxis; + uint8_t yAxis; + uint8_t zAxis; - uint8_txRotAxis; - uint8_tyRotAxis; - uint8_tzRotAxis; + uint8_t xRotAxis; + uint8_t yRotAxis; + uint8_t zRotAxis; - uint8_tthrottle; - uint8_trudder; + uint8_t throttle; + uint8_t rudder; - uint8_thatSw1; - uint8_thatSw2; + uint8_t hatSw1; + uint8_t hatSw2; - uint32_tbuttons;// 32 general buttons + uint32_t buttons;// 32 general buttons } JoyState_t;