A fully-Android-compatible two joysticks USB driver for LPC1768. The joysticks have 1 hat, 6 buttons, and there are 1P, 2P buttons.

Dependencies:   mbed

Fork of app-board-Joystick by Chris Styles

Files at this revision

API Documentation at this revision

Comitter:
Alberto_Wino
Date:
Sat Dec 17 15:10:12 2016 +0000
Parent:
2:84ea6e2fb4b6
Commit message:
Added a two-interface configuration, which fully works on Android.

Changed in this revision

config.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
usbdc.cpp Show annotated file Show diff for this revision Revisions of this file
usbdc.h Show annotated file Show diff for this revision Revisions of this file
usbdevice.cpp Show annotated file Show diff for this revision Revisions of this file
usbdevice.h Show annotated file Show diff for this revision Revisions of this file
usbhid.cpp Show annotated file Show diff for this revision Revisions of this file
usbhid.h Show annotated file Show diff for this revision Revisions of this file
--- a/config.h	Sat Dec 17 13:13:59 2016 +0000
+++ b/config.h	Sat Dec 17 15:10:12 2016 +0000
@@ -5,12 +5,17 @@
 // This configuration declares one interface, and two reports. This works well
 // with SDL, but some applications may fail to detect the second set of buttons
 // and hat.
-//#define CONFIG_TWO_REPORTS
+//#define CONFIG_TWO_REPORTS 1
 
 
 // This configuration declares one interface, one reports. The second joystick
 // is declared as four buttons instead of an extra hat. Some applications
 // fail to detect more than 16 buttons, or be confused by them.
-//#define CONFIG_2ND_PAD_AS_BUTTONS
+//#define CONFIG_2ND_PAD_AS_BUTTONS 1
+
 
-#define CONFIG_TWO_INTERFACES
\ No newline at end of file
+// This configuration declares two interfaces, which should be the most
+// compatible mode.
+// Note! This is currently a bug that will make a joystick block if the other 
+// joystick is moved AND not being polled.
+#define CONFIG_TWO_INTERFACES 1
\ No newline at end of file
--- a/main.cpp	Sat Dec 17 13:13:59 2016 +0000
+++ b/main.cpp	Sat Dec 17 15:10:12 2016 +0000
@@ -2,8 +2,7 @@
 #include "mbed.h"
 #include "usbhid.h"
 
-
-#ifdef CONFIG_TWO_REPORTS
+#if CONFIG_TWO_REPORTS || CONFIG_TWO_INTERFACES
 BusIn buttonsL
 (
     p17, p16, p15, p20, // 3 top row, bottom-left
@@ -20,7 +19,7 @@
 BusIn stickR(p28, p26, p27, p29);
 #endif
 
-#ifdef CONFIG_2ND_PAD_AS_BUTTONS
+#if CONFIG_2ND_PAD_AS_BUTTONS
 BusIn buttonsL
 (
     p17, p16, p15, p20, // 3 top row, bottom-left
@@ -42,7 +41,7 @@
 int main()
 {
     uint8_t stickL_old = 0;
-#ifdef CONFIG_TWO_REPORTS
+#if CONFIG_TWO_REPORTS || CONFIG_TWO_INTERFACES
     uint8_t stickR_old = 0;
 #endif
     uint32_t buttonsL_old = 0;
@@ -51,13 +50,13 @@
     while(1)
     {
         const uint8_t stickL_new = stickL.read();
-#ifdef CONFIG_TWO_REPORTS
+#if CONFIG_TWO_REPORTS || CONFIG_TWO_INTERFACES
         const uint8_t stickR_new = stickR.read();
 #endif
         const uint32_t buttonsL_new = buttonsL.read();
         const uint32_t buttonsR_new = buttonsR.read();
 
-#ifdef CONFIG_TWO_REPORTS
+#if CONFIG_TWO_REPORTS || CONFIG_TWO_INTERFACES
         if ((stickL_old != stickL_new) || (buttonsL_old != buttonsL_new))
         {
             stickL_old = stickL_new;
@@ -73,7 +72,7 @@
         }
 #endif
 
-#ifdef CONFIG_2ND_PAD_AS_BUTTONS
+#if CONFIG_2ND_PAD_AS_BUTTONS
         if ((stickL_old != stickL_new) || (buttonsL_old != buttonsL_new) || (buttonsR_old != buttonsR_new))
         {
             const uint32_t buttons = buttonsL_new | (buttonsR_new << 7);
--- a/usbdc.cpp	Sat Dec 17 13:13:59 2016 +0000
+++ b/usbdc.cpp	Sat Dec 17 15:10:12 2016 +0000
@@ -143,7 +143,7 @@
     enableEvents();
 }
 
-void usbdc::connect(void)
+void usbdc::connect()
 {
     /* Connect USB device */
     unsigned char status;
@@ -152,7 +152,7 @@
     setDeviceStatus(status | SIE_DS_CON);
 }
 
-void usbdc::disconnect(void)
+void usbdc::disconnect()
 {
     /* Disconnect USB device */
     unsigned char status;
@@ -193,7 +193,7 @@
     SIEWriteData(status);
 }
 
-unsigned char usbdc::getDeviceStatus(void)
+unsigned char usbdc::getDeviceStatus()
 {
     /* Read SIE device status register */
     SIECommand(SIE_CMD_GET_DEVICE_STATUS);
@@ -233,14 +233,14 @@
 }
 #endif
 
-unsigned char usbdc::clearBuffer(void)
+unsigned char usbdc::clearBuffer()
 {
     /* SIE clear buffer command */
     SIECommand(SIE_CMD_CLEAR_BUFFER);
     return SIEReadData(SIE_CMD_CLEAR_BUFFER);
 }
 
-void usbdc::validateBuffer(void)
+void usbdc::validateBuffer()
 {
     /* SIE validate buffer command */
     SIECommand(SIE_CMD_VALIDATE_BUFFER);
@@ -283,7 +283,7 @@
 void usbdc::stallEndpoint(unsigned char endpoint)
 {
     /* Stall an endpoint */
-    if ( (endpoint==EP0IN) || (endpoint==EP0OUT) )
+    if ( (endpoint == EP0IN) || (endpoint == EP0OUT) )
     {
         /* Conditionally stall both control endpoints */
         setEndpointStatus(EP0OUT, SIE_SES_CND_ST);
@@ -312,14 +312,14 @@
     return endpointStallState & EP(endpoint);
 }
 
-void usbdc::configureDevice(void)
+void usbdc::configureDevice()
 {
     /* SIE Configure device command */
     SIECommand(SIE_CMD_CONFIGURE_DEVICE);
     SIEWriteData(SIE_CONF_DEVICE);
 }
 
-void usbdc::unconfigureDevice(void)
+void usbdc::unconfigureDevice()
 {
     /* SIE Configure device command */
     SIECommand(SIE_CMD_CONFIGURE_DEVICE);
@@ -329,35 +329,29 @@
 unsigned long usbdc::endpointRead(unsigned char endpoint, unsigned char *buffer)
 {
     /* Read from an OUT endpoint */
-    unsigned long size;
-    unsigned long i;
-    unsigned long data;
-    unsigned char offset;
-
     LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;
-    while (!(LPC_USB->USBRxPLen & PKT_RDY));
+    while(!(LPC_USB->USBRxPLen & PKT_RDY)) ;
 
-    size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;
-
-    offset = 0;
-
-    for (i=0; i<size; i++)
+    unsigned long size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;
+    unsigned char offset = 0;
+    unsigned long data;
+    for(unsigned long i = 0; i < size; i++)
     {
-        if (offset==0)
+        if (offset == 0)
         {
             /* Fetch up to four bytes of data as a word */
             data = LPC_USB->USBRxData;
         }
 
         /* extract a byte */
-        *buffer++ = data>>offset;
+        *buffer++ = data >> offset;
 
         /* move on to the next byte */
         offset = (offset + 8) % 32;
     }
 
     /* Clear RD_EN to cover zero length packet case */
-    LPC_USB->USBCtrl=0;
+    LPC_USB->USBCtrl = 0;
 
     selectEndpoint(endpoint);
     clearBuffer();
@@ -368,21 +362,17 @@
 void usbdc::endpointWrite(unsigned char endpoint, unsigned char *buffer, unsigned long size)
 {
     /* Write to an IN endpoint */
-    unsigned long temp, data;
-    unsigned char offset;
-
     LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;
-
     LPC_USB->USBTxPLen = size;
-    offset = 0;
-    data = 0;
-
-    if (size>0)
+    
+    unsigned char offset = 0;
+    unsigned long data = 0;
+    if (size > 0)
     {
         do
         {
             /* Fetch next data byte into a word-sized temporary variable */
-            temp = *buffer++;
+            unsigned long temp = *buffer++;
 
             /* Add to current data word */
             temp = temp << offset;
@@ -392,35 +382,35 @@
             offset = (offset + 8) % 32;
             size--;
 
-            if ((offset==0) || (size==0))
+            if ((offset == 0) || (size == 0))
             {
                 /* Write the word to the endpoint */
                 LPC_USB->USBTxData = data;
                 data = 0;
             }
-        } while (size>0);
+        } while(size > 0);
     }
 
     /* Clear WR_EN to cover zero length packet case */
-    LPC_USB->USBCtrl=0;
+    LPC_USB->USBCtrl = 0;
 
     selectEndpoint(endpoint);
     validateBuffer();
 }
 
-void usbdc::enableEvents(void)
+void usbdc::enableEvents()
 {
     /* Enable interrupt sources */
     LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT;
 }
 
-void usbdc::disableEvents(void)
+void usbdc::disableEvents()
 {
     /* Disable interrupt sources */
     LPC_USB->USBDevIntClr = EP_SLOW | DEV_STAT;
 }
 
-void usbdc::usbisr(void)
+void usbdc::usbisr()
 {
     unsigned char devStat;
 
@@ -461,9 +451,7 @@
                 endpointEventEP0Setup();
             }
             else
-            {
                 endpointEventEP0Out();
-            }
         }
 
         if (LPC_USB->USBEpIntSt & EP(EP0IN))
@@ -502,44 +490,17 @@
     }
 }
 
-
-void usbdc::_usbisr(void)
+void usbdc::_usbisr()
 {
     instance->usbisr();
 }
 
-void usbdc::deviceEventReset(void)
-{
-}
-
-void usbdc::deviceEventFrame(void)
-{
-}
-
-void usbdc::endpointEventEP0Setup(void)
-{
-}
-
-void usbdc::endpointEventEP0In(void)
-{
-}
-
-void usbdc::endpointEventEP0Out(void)
-{
-}
-
-void usbdc::endpointEventEP1In(void)
-{
-}
-
-void usbdc::endpointEventEP1Out(void)
-{
-}
-
-void usbdc::endpointEventEP2In(void)
-{
-}
-
-void usbdc::endpointEventEP2Out(void)
-{
-}
+void usbdc::deviceEventReset()      { }
+void usbdc::deviceEventFrame()      { }
+void usbdc::endpointEventEP0Setup() { }
+void usbdc::endpointEventEP0In()    { }
+void usbdc::endpointEventEP0Out()   { }
+void usbdc::endpointEventEP1In()    { }
+void usbdc::endpointEventEP1Out()   { }
+void usbdc::endpointEventEP2In()    { }
+void usbdc::endpointEventEP2Out()   { }
--- a/usbdc.h	Sat Dec 17 13:13:59 2016 +0000
+++ b/usbdc.h	Sat Dec 17 15:10:12 2016 +0000
@@ -2,25 +2,24 @@
 /* USB device controller */
 /* Copyright (c) Phil Wright 2008 */
 
-#ifndef USBDC_H
-#define USBDC_H
+#pragma once
 
 /* Endpoints */
 #define EP0OUT  (0) /* Control */
 #define EP0IN   (1) /* Control */
-#define EP1OUT  (2) /* Interrupt */
-#define EP1IN   (3) /* Interrupt */
-#define EP2OUT  (4) /* Bulk */
-#define EP2IN   (5) /* Bulk */
+#define EP1OUT  (2)
+#define EP1IN   (3)
+#define EP2OUT  (4)
+#define EP2IN   (5)
 
 #include "mbed.h"
 
-class usbdc //: public Base
+class usbdc
 {
 public:
     usbdc();
-    void connect(void);
-    void disconnect(void);
+    void connect();
+    void disconnect();
 protected:
     void setAddress(unsigned char address);
     void realiseEndpoint(unsigned char endpoint, unsigned long maxPacket);
@@ -29,36 +28,34 @@
     void stallEndpoint(unsigned char endpoint);
     void unstallEndpoint(unsigned char endpoint);
     bool getEndpointStallState(unsigned char endpoint);
-    void configureDevice(void);
-    void unconfigureDevice(void);
+    void configureDevice();
+    void unconfigureDevice();
     unsigned long endpointRead(unsigned char endpoint, unsigned char *buffer);
     void endpointWrite(unsigned char endpoint, unsigned char *buffer, unsigned long size);
-    void enableEvents(void);
-    void disableEvents(void);
-    virtual void deviceEventReset(void);
-    virtual void deviceEventFrame(void);
-    virtual void endpointEventEP0Setup(void);
-    virtual void endpointEventEP0In(void);
-    virtual void endpointEventEP0Out(void);
-    virtual void endpointEventEP1In(void);
-    virtual void endpointEventEP1Out(void);
-    virtual void endpointEventEP2In(void);
-    virtual void endpointEventEP2Out(void);
+    void enableEvents();
+    void disableEvents();
+    virtual void deviceEventReset();
+    virtual void deviceEventFrame();
+    virtual void endpointEventEP0Setup();
+    virtual void endpointEventEP0In();
+    virtual void endpointEventEP0Out();
+    virtual void endpointEventEP1In();
+    virtual void endpointEventEP1Out();
+    virtual void endpointEventEP2In();
+    virtual void endpointEventEP2Out();
 private:
     void SIECommand(unsigned long command);
     void SIEWriteData(unsigned char data);
     unsigned char SIEReadData(unsigned long command);
     void setDeviceStatus(unsigned char status);
     void setEndpointStatus(unsigned char endpoint, unsigned char status);
-    unsigned char getDeviceStatus(void);
+    unsigned char getDeviceStatus();
     unsigned char selectEndpoint(unsigned char endpoint);
     unsigned char selectEndpointClearInterrupt(unsigned char endpoint);
-    unsigned char clearBuffer(void);
-    void validateBuffer(void);
-    void usbisr(void);
+    unsigned char clearBuffer();
+    void validateBuffer();
+    void usbisr();
     unsigned long endpointStallState;
-    static void _usbisr(void);
+    static void _usbisr();
     static usbdc *instance;
 };
-
-#endif
\ No newline at end of file
--- a/usbdevice.cpp	Sat Dec 17 13:13:59 2016 +0000
+++ b/usbdevice.cpp	Sat Dec 17 15:10:12 2016 +0000
@@ -2,6 +2,8 @@
 /* Generic USB device */
 /* Copyright (c) Phil Wright 2008 */
 
+/* Modified by yours truly. */
+
 #include "mbed.h"
 #include "usbdevice.h"
 
@@ -94,9 +96,9 @@
     packet->bmRequestType.Type = (data[0] & 0x60) >> 5;
     packet->bmRequestType.Recipient = data[0] & 0x1f;
     packet->bRequest = data[1];
-    packet->wValue = (data[2] | (unsigned short)data[3] << 8);
-    packet->wIndex = (data[4] | (unsigned short)data[5] << 8);
-    packet->wLength = (data[6] | (unsigned short)data[7] << 8);
+    packet->wValue = (data[2] | (unsigned short) data[3] << 8);
+    packet->wIndex = (data[4] | (unsigned short) data[5] << 8);
+    packet->wLength = (data[6] | (unsigned short) data[7] << 8);
 }
 
 bool usbdevice::controlSetup()
@@ -123,7 +125,7 @@
     /* Check transfer size and direction  */
     if (transfer.setup.wLength > 0)
     {
-        if (transfer.setup.bmRequestType.dataTransferDirection==DEVICE_TO_HOST)
+        if (transfer.setup.bmRequestType.dataTransferDirection == DEVICE_TO_HOST)
         {
             /* IN data stage is required */
             if (transfer.direction != DEVICE_TO_HOST)
--- a/usbdevice.h	Sat Dec 17 13:13:59 2016 +0000
+++ b/usbdevice.h	Sat Dec 17 15:10:12 2016 +0000
@@ -2,8 +2,7 @@
 /* Generic USB device */
 /* Copyright (c) Phil Wright 2008 */
 
-#ifndef USBDEVICE_H
-#define USBDEVICE_H
+#pragma once
 
 #include "usbdc.h"
 
@@ -97,5 +96,3 @@
     bool controlSetup();
     void decodeSetupPacket(unsigned char *data, SETUP_PACKET *packet);
 };
-
-#endif
\ No newline at end of file
--- a/usbhid.cpp	Sat Dec 17 13:13:59 2016 +0000
+++ b/usbhid.cpp	Sat Dec 17 15:10:12 2016 +0000
@@ -2,7 +2,7 @@
 /* USB HID class device */
 /* Copyright (c) Phil Wright 2008 */
 
-/* Modified by yours truly */
+/* Modified by yours truly. */
 
 #include "config.h"
 #include "mbed.h"
@@ -111,7 +111,6 @@
 0x19, 0x01, //   USAGE_MINIMUM (Button 1)
 0x29, 0x12, //   USAGE_MAXIMUM (Button 18)
 0x81, 0x02, //   INPUT (Data,Var,Abs)
-// does not work, why????????
 0x95, 0x06, //   REPORT_COUNT (6)
 0x81, 0x01, //   INPUT (Cnst,Ary,Abs)
 0x05, 0x01, //   USAGE_PAGE (Generic Desktop)
@@ -139,10 +138,54 @@
 
 0xc0, // END_COLLECTION -- application
 };
+#endif
 
+#ifdef CONFIG_TWO_INTERFACES
+static uint8_t report_descriptor_joystick[] =
+{
+0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+0x09, 0x05, // USAGE (Gamepad)
+0xa1, 0x01, // COLLECTION (Application)
+
+0xa1, 0x00, // COLLECTION (Physical)
+0x15, 0x00, //   LOGICAL_MINIMUM (0)
+0x25, 0x01, //   LOGICAL_MAXIMUM (1)
+0x35, 0x00, //   PHYSICAL_MINIMUM (0)
+0x45, 0x01, //   PHYSICAL_MAXIMUM (1)
+0x75, 0x01, //   REPORT_SIZE (1)
+0x95, 0x08, //   REPORT_COUNT (8)
+0x05, 0x09, //   USAGE_PAGE (Button)
+0x19, 0x01, //   USAGE_MINIMUM (Button 1)
+0x29, 0x08, //   USAGE_MAXIMUM (Button 8)
+0x81, 0x02, //   INPUT (Data,Var,Abs)
+0x05, 0x01, //   USAGE_PAGE (Generic Desktop)
+0x25, 0x07, //   LOGICAL_MAXIMUM (7)
+0x46, 0x3b, 0x01, //   PHYSICAL_MAXIMUM (315)
+0x75, 0x04, //   REPORT_SIZE (4)
+0x95, 0x01, //   REPORT_COUNT (1)
+0x65, 0x14, //   UNIT (Eng Rot:Angular Pos)
+0x09, 0x39, //   USAGE (Hat switch)
+0x81, 0x42, //   INPUT (Data,Var,Abs,Null)
+0x65, 0x00, //   UNIT (None)
+0x95, 0x01, //   REPORT_COUNT (1)
+0x81, 0x01, //   INPUT (Cnst,Ary,Abs)
+0x26, 0xff, 0x00, //   LOGICAL_MAXIMUM (255)
+0x46, 0xff, 0x00, //   PHYSICAL_MAXIMUM (255)
+
+/* For some reason, this is necessary (though we never put it in the report). */
+0x09, 0x30, //   USAGE (X)
+0x09, 0x31, //   USAGE (Y)
+0x75, 0x04, //   REPORT_SIZE (4)
+0x95, 0x02, //   REPORT_COUNT (2)
+0x81, 0x02, //   INPUT (Data,Var,Abs)
+
+0xc0, // END_COLLECTION -- physical
+0xc0, // END_COLLECTION -- application
+};
 #endif
 
 
+
 /* Endpoint packet sizes */
 #define MAX_PACKET_SIZE_EP1 64
 
@@ -175,7 +218,79 @@
     0x00,                    /* iSerialNumber */ // string index
     0x01                     /* bNumConfigurations */
 };
+
+#ifdef CONFIG_TWO_INTERFACES
+unsigned char configurationDescriptor[] =
+{
+    0x09,                        /* bLength */
+    CONFIGURATION_DESCRIPTOR,    /* bDescriptorType */
+    0x00,                        /* wTotalLength (LSB), set later */
+    0x00,                        /* wTotalLength (MSB), set later */
+    0x02,                        /* bNumInterfaces */
+    0x01,                        /* bConfigurationValue */
+    0x00,                        /* iConfiguration */
+    0x80,                        /* bmAttributes */
+    0x32,                        /* bMaxPower */
+/*9*/
+    0x09,                        /* bLength */
+    INTERFACE_DESCRIPTOR,        /* bDescriptorType */
+    0x00,                        /* bInterfaceNumber */
+    0x00,                        /* bAlternateSetting */
+    0x01,                        /* bNumEndpoints */
+    HID_CLASS,                   /* bInterfaceClass */
+    HID_SUBCLASS_NONE,           /* bInterfaceSubClass */
+    HID_PROTOCOL_NONE,           /* bInterfaceProtocol */
+    0x00,                        /* iInterface */
+/*18*/
+    0x09,                        /* bLength */
+    HID_DESCRIPTOR,              /* bDescriptorType */
+    0x11,                        /* bcdHID (LSB) */
+    0x01,                        /* bcdHID (MSB) */
+    0x00,                        /* bCountryCode */
+    0x01,                        /* bNumDescriptors */
+    REPORT_DESCRIPTOR,           /* bDescriptorType */
+    sizeof(report_descriptor_joystick) & 0xff, /* wDescriptorLength (LSB) */
+    (sizeof(report_descriptor_joystick) >> 8) & 0xff, /* wDescriptorLength (MSB) */
+/*27*/
+    0x07,                        /* bLength */
+    ENDPOINT_DESCRIPTOR,         /* bDescriptorType */
+    0x81,                        /* bEndpointAddress */
+    0x03,                        /* bmAttributes */
+    MAX_PACKET_SIZE_EP1,         /* wMaxPacketSize (LSB) */
+    0x00,                        /* wMaxPacketSize (MSB) */
+    0x05,                        /* bInterval */
     
+/* second interface */
+    0x09,                        /* bLength */
+    INTERFACE_DESCRIPTOR,        /* bDescriptorType */
+    0x01,                        /* bInterfaceNumber */
+    0x00,                        /* bAlternateSetting */
+    0x01,                        /* bNumEndpoints */
+    HID_CLASS,                   /* bInterfaceClass */
+    HID_SUBCLASS_NONE,           /* bInterfaceSubClass */
+    HID_PROTOCOL_NONE,           /* bInterfaceProtocol */
+    0x00,                        /* iInterface */
+
+    0x09,                        /* bLength */
+    HID_DESCRIPTOR,              /* bDescriptorType */
+    0x11,                        /* bcdHID (LSB) */
+    0x01,                        /* bcdHID (MSB) */
+    0x00,                        /* bCountryCode */
+    0x01,                        /* bNumDescriptors */
+    REPORT_DESCRIPTOR,           /* bDescriptorType */
+    sizeof(report_descriptor_joystick) & 0xff, /* wDescriptorLength (LSB) */
+    (sizeof(report_descriptor_joystick) >> 8) & 0xff, /* wDescriptorLength (MSB) */
+
+    0x07,                        /* bLength */
+    ENDPOINT_DESCRIPTOR,         /* bDescriptorType */
+    0x82,                        /* bEndpointAddress */
+    0x03,                        /* bmAttributes */
+    MAX_PACKET_SIZE_EP1,         /* wMaxPacketSize (LSB) */
+    0x00,                        /* wMaxPacketSize (MSB) */
+    0x05                         /* bInterval */
+};
+
+#else    
 unsigned char configurationDescriptor[] =
 {
     0x09,                        /* bLength */
@@ -216,8 +331,12 @@
     0x00,                        /* wMaxPacketSize (MSB) */
     0x05                         /* bInterval */
 };
+#endif
 
 static volatile bool complete;
+#if CONFIG_TWO_INTERFACES
+static volatile bool complete_ep2;
+#endif
 static volatile bool configured;
 
 /* */
@@ -242,6 +361,12 @@
     /* Configure IN interrupt endpoint */
     realiseEndpoint(EP1IN, MAX_PACKET_SIZE_EP1);
     enableEndpointEvent(EP1IN);
+    
+#if CONFIG_TWO_INTERFACES
+    /* Configure second IN interrupt endpoint */
+    realiseEndpoint(EP2IN, MAX_PACKET_SIZE_EP1);
+    enableEndpointEvent(EP2IN);
+#endif
 
     /* Must call base class */
     result = usbdevice::requestSetConfiguration();
@@ -297,6 +422,11 @@
     complete = true;
 }
 
+void usbhid::endpointEventEP2In()
+{
+    complete_ep2 = true;
+}
+
 /* */
 USBJoystick::USBJoystick()
 {
@@ -319,33 +449,6 @@
     }
 }
 
-/*#define JOYSTICK_UP    (1<<0)
-#define JOYSTICK_DOWN  (1<<1)
-#define JOYSTICK_LEFT  (1<<2)
-#define JOYSTICK_RIGHT (1<<3)
-
-const uint8_t hat_map[8] =
-{
-    0xf, // 0: neutral 
-    0,   // 1: up
-    4,   // 2: down
-    0xf, // 3: n/a (up + down)
-    6,   // 4: left
-    7,   // 5: left + up
-    4,   // 6: left + down
-    6,   // 7: left (+ up + down)
-    2,   // 8: right
-    1,   // 9: right + up
-    3,   //10: right + down
-    2,   //11: right (+ up + down)
-    0xf, //12: n/a (left + right)
-    0,   //13: up (+ left + right)
-    4,   //14: down (+ left + right)
-    0    //15: n/a
-};
-*/
-
-
 bool USBJoystick::update(uint8_t gamepad_id, uint8_t stick, uint32_t buttons)
 {
     unsigned char hatswitch;
@@ -374,14 +477,23 @@
         hatswitch = 0xf;
 
     /* Prepare report */
-#ifdef CONFIG_TWO_REPORTS
+#if CONFIG_TWO_INTERFACES
+    const uint8_t report_size = 2;
+    unsigned char report[2];
+    report[0] = buttons;
+    report[1] = hatswitch;
+#endif
+ 
+#if CONFIG_TWO_REPORTS
+    const uint8_t report_size = 3;
     unsigned char report[3];
     report[0] = gamepad_id;
     report[1] = buttons;
     report[2] = hatswitch;
 #endif    
     
-#ifdef CONFIG_2ND_PAD_AS_BUTTONS
+#if CONFIG_2ND_PAD_AS_BUTTONS
+    const uint8_t report_size = 4;
     unsigned char report[4];
     report[0] = buttons & 0xff;
     report[1] = (buttons >> 8) & 0xff;
@@ -393,15 +505,25 @@
     while(!configured) ;
 
     /* Send report */
-    complete = false;
-    disableEvents();
-#ifdef CONFIG_TWO_REPORTS
-    endpointWrite(EP1IN, report, 3);
+    
+#if CONFIG_TWO_INTERFACES
+    if (gamepad_id == 2)
+        complete_ep2 = false;
+    else
 #endif
-#ifdef CONFIG_2ND_PAD_AS_BUTTONS
-    endpointWrite(EP1IN, report, 4);
-#endif
-
+    complete = false;
+    
+    disableEvents();
+#if CONFIG_TWO_INTERFACES
+    if (gamepad_id == 2)
+    {
+        endpointWrite(EP2IN, report, report_size);
+        enableEvents();
+        while(!complete_ep2 && configured) ;
+        return true;
+    }
+#endif        
+    endpointWrite(EP1IN, report, report_size);
     enableEvents();
 
     /* Wait for completion */
--- a/usbhid.h	Sat Dec 17 13:13:59 2016 +0000
+++ b/usbhid.h	Sat Dec 17 15:10:12 2016 +0000
@@ -2,8 +2,9 @@
 /* USB HID class device */
 /* Copyright (c) Phil Wright 2008 */
 
-#ifndef USBHID_H
-#define USBHID_H
+/* Modified by yours truly. */
+
+#pragma once
 
 #include "usbdevice.h"
 
@@ -15,6 +16,7 @@
 protected:
     virtual void deviceEventReset();
     virtual void endpointEventEP1In();
+    virtual void endpointEventEP2In();    
     virtual bool requestGetDescriptor();
     virtual bool requestSetConfiguration();
 };
@@ -32,5 +34,3 @@
 protected:
     virtual bool requestGetDescriptor();
 };
-
-#endif /* USBHID_H */
\ No newline at end of file