diff --git a/hardware/arduino/avr/cores/arduino/HID.cpp b/hardware/arduino/avr/cores/arduino/HID.cpp index 75c37b24b2f..ead1d311aaf 100644 --- a/hardware/arduino/avr/cores/arduino/HID.cpp +++ b/hardware/arduino/avr/cores/arduino/HID.cpp @@ -16,18 +16,27 @@ ** SOFTWARE. */ +#include "Platform.h" #include "USBAPI.h" +#include "USBDesc.h" #if defined(USBCON) #ifdef HID_ENABLED +// *** This used to be RAWHID_ENABLED //#define RAWHID_ENABLED +//#define KBAM_ENABLED +#define JOYHID_ENABLED // Singletons for mouse and keyboard Mouse_ Mouse; Keyboard_ Keyboard; +// *** Add a joystick too + +Joystick_ Joystick; + //================================================================================ //================================================================================ @@ -123,6 +132,91 @@ const u8 _hidReportDescriptor[] = { 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 }; @@ -143,6 +237,7 @@ u8 _hid_idle = 1; #define WEAK __attribute__ ((weak)) + int WEAK HID_GetInterface(u8* interfaceNum) { interfaceNum[0] += 1; // uses 1 @@ -195,12 +290,63 @@ 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 Mouse_::Mouse_(void) : _buttons(0) { + } void Mouse_::begin(void) diff --git a/hardware/arduino/avr/cores/arduino/USBAPI.h b/hardware/arduino/avr/cores/arduino/USBAPI.h index 2fab957f930..92448d77c13 100644 --- a/hardware/arduino/avr/cores/arduino/USBAPI.h +++ b/hardware/arduino/avr/cores/arduino/USBAPI.h @@ -69,13 +69,16 @@ class Serial_ : public Stream { private: int peek_buffer; + ring_buffer *_cdc_rx_buffer; public: Serial_() { peek_buffer = -1; }; void begin(unsigned long); void begin(unsigned long, uint8_t); + void begin(uint16_t baud_count); void end(void); virtual int available(void); + virtual void accept(void); virtual int peek(void); virtual int read(void); virtual void flush(void); @@ -90,7 +93,42 @@ class Serial_ : public Stream }; extern Serial_ Serial; -#define HAVE_CDCSERIAL +//================================================================================ +//================================================================================ +// 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; //================================================================================ //================================================================================ @@ -111,7 +149,7 @@ class Mouse_ void begin(void); void end(void); void click(uint8_t b = MOUSE_LEFT); - void move(signed char x, signed char y, signed char wheel = 0); + void move(signed char x, signed char y, signed char wheel = 0); void press(uint8_t b = MOUSE_LEFT); // press LEFT by default void release(uint8_t b = MOUSE_LEFT); // release LEFT by default bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default diff --git a/hardware/arduino/sam/cores/arduino/USB/HID.cpp b/hardware/arduino/sam/cores/arduino/USB/HID.cpp index c243f495142..516a33e172e 100644 --- a/hardware/arduino/sam/cores/arduino/USB/HID.cpp +++ b/hardware/arduino/sam/cores/arduino/USB/HID.cpp @@ -14,17 +14,27 @@ ** SOFTWARE. */ -#include "Arduino.h" +#include "Platform.h" +#include "USBAPI.h" +#include "USBDesc.h" +#if defined(USBCON) #ifdef HID_ENABLED +// *** This used to be RAWHID_ENABLED //#define RAWHID_ENABLED +//#define KBAM_ENABLED +#define JOYHID_ENABLED // Singletons for mouse and keyboard Mouse_ Mouse; Keyboard_ Keyboard; +// *** Add a joystick too + +Joystick_ Joystick; + //================================================================================ //================================================================================ @@ -118,6 +128,91 @@ extern const uint8_t _hidReportDescriptor[] = { 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 }; @@ -197,12 +292,63 @@ 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 Mouse_::Mouse_(void) : _buttons(0) { + } void Mouse_::begin(void) @@ -278,6 +424,9 @@ void Keyboard_::sendReport(KeyReport* keys) HID_SendReport(2,keys,sizeof(KeyReport)); } +extern +const uint8_t _asciimap[128] PROGMEM; + #define SHIFT 0x80 extern const uint8_t _asciimap[128] = { @@ -516,3 +665,5 @@ size_t Keyboard_::write(uint8_t c) } #endif + +#endif /* if defined(USBCON) */ diff --git a/hardware/arduino/sam/cores/arduino/USB/USBAPI.h b/hardware/arduino/sam/cores/arduino/USB/USBAPI.h index 3cf601e9e87..e3975cb3443 100644 --- a/hardware/arduino/sam/cores/arduino/USB/USBAPI.h +++ b/hardware/arduino/sam/cores/arduino/USB/USBAPI.h @@ -20,7 +20,7 @@ #define __USBAPI__ #if defined __cplusplus - +#if defined(USBCON) #include "RingBuffer.h" //================================================================================ @@ -64,6 +64,43 @@ class Serial_ : public Stream }; extern Serial_ SerialUSB; +//================================================================================ +//================================================================================ +// 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; + //================================================================================ //================================================================================ // Mouse @@ -199,6 +236,7 @@ bool CDC_Setup(Setup& setup); //================================================================================ //================================================================================ +#define TRANSFER_PGM 0x80 #define TRANSFER_RELEASE 0x40 #define TRANSFER_ZERO 0x20 @@ -207,7 +245,14 @@ int USBD_SendControl(uint8_t flags, const void* d, uint32_t len); int USBD_RecvControl(void* d, uint32_t len); int USBD_SendInterfaces(void); bool USBD_ClassInterfaceRequest(Setup& setup); +int USB_SendControl(uint8_t flags, const void* d, int len); +int USB_RecvControl(void* d, int len); +uint8_t USB_Available(uint8_t ep); +int USB_Send(uint8_t ep, const void* data, int len); // blocking +int USB_Recv(uint8_t ep, void* data, int len); // non-blocking +int USB_Recv(uint8_t ep); // non-blocking +void USB_Flush(uint8_t ep); uint32_t USBD_Available(uint32_t ep); uint32_t USBD_SendSpace(uint32_t ep); @@ -219,3 +264,4 @@ uint32_t USBD_Connected(void); #endif #endif +#endif /* if defined(USBCON) */