Arnaud VALLEY / Mbed 2 deprecated Pinscape_Controller_V2_arnoz

Dependencies:   mbed FastIO FastPWM USBDevice

Revision:
62:f071ccde32a0
Parent:
61:3c7e6e9ec355
Child:
63:5cd1a5f3a41b
diff -r 3c7e6e9ec355 -r f071ccde32a0 USBJoystick/USBJoystick.cpp
--- a/USBJoystick/USBJoystick.cpp	Thu Jun 02 18:58:52 2016 +0000
+++ b/USBJoystick/USBJoystick.cpp	Thu Jun 02 22:52:25 2016 +0000
@@ -31,8 +31,6 @@
 // Maximum report sizes
 const int MAX_REPORT_JS_TX = reportLen;
 const int MAX_REPORT_JS_RX = 8;
-const int MAX_REPORT_KB_TX = 8;
-const int MAX_REPORT_KB_RX = 4;
 
 bool USBJoystick::update(int16_t x, int16_t y, int16_t z, uint32_t buttons, uint16_t status) 
 {
@@ -49,24 +47,26 @@
 
 bool USBJoystick::update() 
 {
+   // start the report with the report ID
    HID_REPORT report;
-
+   report.data[0] = REPORT_ID_JS;
+   
    // Fill the report according to the Joystick Descriptor
 #define put(idx, val) (report.data[idx] = (val) & 0xff, report.data[(idx)+1] = ((val) >> 8) & 0xff)
 #define putbe(idx, val) (report.data[(idx)+1] = (val) & 0xff, report.data[idx] = ((val) >> 8) & 0xff)
 #define putl(idx, val) (put(idx, val), put((idx)+2, (val) >> 16))
 #define putlbe(idx, val) (putbe((idx)+2, val), putbe(idx, (val) >> 16))
-   put(0, _status);
-   put(2, 0);  // second word of status - zero in high bit identifies as normal joystick report
-   put(4, _buttonsLo);
-   put(6, _buttonsHi);
-   put(8, _x);
-   put(10, _y);
-   put(12, _z);
+   put(1, _status);
+   put(3, 0);  // second word of status - zero in high bit identifies as normal joystick report
+   put(5, _buttonsLo);
+   put(7, _buttonsHi);
+   put(9, _x);
+   put(11, _y);
+   put(13, _z);
    
    // important: keep reportLen in sync with the actual byte length of
    // the reports we build here
-   report.length = reportLen;
+   report.length = reportLen + 1;
  
    // send the report
    return sendTO(&report, 100);
@@ -99,14 +99,16 @@
 bool USBJoystick::sendPlungerStatus(
     int npix, int edgePos, int dir, uint32_t avgScanTime, uint32_t processingTime)
 {
+    // set up the report ID
     HID_REPORT report;
+    report.data[0] = REPORT_ID_STAT;
     
     // Set the special status bits to indicate it's an extended
     // exposure report.
-    put(0, 0x87FF);
+    put(1, 0x87FF);
     
     // start at the second byte
-    int ofs = 2;
+    int ofs = 3;
     
     // write the report subtype (0) to byte 2
     report.data[ofs++] = 0;
@@ -143,25 +145,26 @@
     report.data[ofs++] = (t >> 16) & 0xff;
     
     // send the report
-    report.length = reportLen;
+    report.length = reportLen + 1;
     return sendTO(&report, 100);
 }
 
 bool USBJoystick::sendPlungerPix(int &idx, int npix, const uint8_t *pix)
 {
     HID_REPORT report;
+    report.data[0] = REPORT_ID_STAT;
     
     // Set the special status bits to indicate it's an exposure report.
     // The high 5 bits of the status word are set to 10000, and the
     // low 11 bits are the current pixel index.
     uint16_t s = idx | 0x8000;
-    put(0, s);
+    put(1, s);
     
     // start at the second byte
-    int ofs = 2;
+    int ofs = 3;
     
     // now fill out the remaining bytes with exposure values
-    report.length = reportLen;
+    report.length = reportLen + 1;
     for ( ; ofs < report.length ; ++ofs)
         report.data[ofs] = (idx < npix ? pix[idx++] : 0);
     
@@ -176,21 +179,24 @@
     // initially fill the report with zeros
     memset(report.data, 0, sizeof(report.data));
     
+    // set the report ID
+    report.data[0] = REPORT_ID_STAT;
+    
     // Set the special status bits to indicate that it's an ID report
     uint16_t s = 0x9000;
-    put(0, s);
+    put(1, s);
     
     // add the requested ID index
-    report.data[2] = (uint8_t)index;
+    report.data[3] = (uint8_t)index;
     
     // figure out which ID we're reporting
     switch (index)
     {
     case 1:
         // KL25Z CPU ID
-        putbe(3, SIM->UIDMH);
-        putlbe(5, SIM->UIDML);
-        putlbe(9, SIM->UIDL);
+        putbe(4, SIM->UIDMH);
+        putlbe(6, SIM->UIDML);
+        putlbe(10, SIM->UIDL);
         break;
         
     case 2:
@@ -199,12 +205,12 @@
         // 80 bits = 10 bytes.  So skip ahead 16 and back up 10 to get
         // the starting point.)
         extern const char *getOpenSDAID();
-        memcpy(&report.data[3], getOpenSDAID() + 16 - 10, 10);
+        memcpy(&report.data[4], getOpenSDAID() + 16 - 10, 10);
         break;
     }
     
     // send the report
-    report.length = reportLen;
+    report.length = reportLen + 1;
     return sendTO(&report, 100);
 }
 
@@ -215,10 +221,13 @@
     // initially fill the report with zeros
     memset(report.data, 0, sizeof(report.data));
     
+    // set the report ID
+    report.data[0] = REPORT_ID_STAT;
+    
     // Set the special status bits to indicate that it's a build
     // info report
     uint16_t s = 0xA000;
-    put(0, s);
+    put(1, s);
     
     // Parse the date.  This is given in the standard __DATE__ " " __TIME
     // macro format, "Mon dd yyyy hh:mm:ss" (e.g., "Feb 16 2016 12:15:06").
@@ -244,11 +253,11 @@
         + (atol(date+18));
     
     // store the build date and time
-    putl(2, dd);
-    putl(6, tt);
+    putl(3, dd);
+    putl(7, tt);
     
     // send the report
-    report.length = reportLen;
+    report.length = reportLen + 1;
     return sendTO(&report, 100);
 }
 
@@ -259,16 +268,19 @@
     // initially fill the report with zeros
     memset(report.data, 0, sizeof(report.data));
     
+    // set the report ID
+    report.data[0] = REPORT_ID_STAT;
+    
     // Set the special status bits to indicate that it's a config 
     // variable report
     uint16_t s = 0x9800;
-    put(0, s);
+    put(1, s);
     
     // Copy the variable data (7 bytes, starting with the variable ID)
-    memcpy(report.data + 2, data, 7);
+    memcpy(report.data + 3, data, 7);
     
     // send the report
-    report.length = reportLen;
+    report.length = reportLen + 1;
     return sendTO(&report, 100);
 }
 
@@ -282,27 +294,30 @@
     // initially fill the report with zeros
     memset(report.data, 0, sizeof(report.data));
     
+    // set the report ID
+    report.data[0] = REPORT_ID_STAT;
+    
     // Set the special status bits to indicate that it's a config report.
     uint16_t s = 0x8800;
-    put(0, s);
+    put(1, s);
     
     // write the number of configured outputs
-    put(2, numOutputs);
+    put(3, numOutputs);
     
     // write the unit number
-    put(4, unitNo);
+    put(5, unitNo);
     
     // write the plunger zero and max values
-    put(6, plungerZero);
-    put(8, plungerMax);
-    report.data[10] = uint8_t(plungerRlsTime);
+    put(7, plungerZero);
+    put(9, plungerMax);
+    report.data[11] = uint8_t(plungerRlsTime);
     
     // write the status bits: 
     //  0x01  -> configuration loaded
-    report.data[11] = (configured ? 0x01 : 0x00);
+    report.data[12] = (configured ? 0x01 : 0x00);
     
     // send the report
-    report.length = reportLen;
+    report.length = reportLen + 1;
     return sendTO(&report, 100);
 }
 
@@ -330,11 +345,15 @@
 {
    HID_REPORT report;
 
-   // Fill the report according to the Joystick Descriptor
-#define put(idx, val) (report.data[idx] = (val) & 0xff, report.data[(idx)+1] = ((val) >> 8) & 0xff)
-   memset(report.data, 0, reportLen);
-   put(0, status);
-   report.length = reportLen;
+   // clear the report
+   memset(report.data, 0,  sizeof(report.data));
+   
+   // set the report ID
+   report.data[0] = REPORT_ID_STAT;
+   
+   // Indicate that it's a status report
+   put(1, status);
+   report.length = reportLen + 1;
  
    // send the report
    return sendTO(&report, 100);
@@ -353,185 +372,205 @@
  
 // --------------------------------------------------------------------------
 //
-// USB HID Report Descriptor - Joystick
+// USB HID Report Descriptors
 //
-static const uint8_t reportDescriptorJS[] = 
-{         
-    USAGE_PAGE(1), 0x01,            // Generic desktop
-    USAGE(1), 0x04,                 // Joystick
-    COLLECTION(1), 0x01,            // Application
-     
-        // input report (device to host)
 
-        USAGE_PAGE(1), 0x06,        // generic device controls - for config status
-        USAGE(1), 0x00,             // undefined device control
-        LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
-        LOGICAL_MAXIMUM(1), 0xFF,
-        REPORT_SIZE(1), 0x08,       // 8 bits per report
-        REPORT_COUNT(1), 0x04,      // 4 reports (4 bytes)
-        INPUT(1), 0x02,             // Data, Variable, Absolute
+#define HID_REPORT_JS \
+    USAGE_PAGE(1), 0x01,            /* Generic desktop */ \
+    USAGE(1), 0x04,                 /* Joystick */ \
+    COLLECTION(1), 0x01,            /* Application */ \
+        /* input report (device to host) */ \
+        REPORT_ID(1), REPORT_ID_JS, \
+        USAGE_PAGE(1), 0x06,        /* generic device controls - for config status */ \
+        USAGE(1), 0x00,             /* undefined device control */ \
+        LOGICAL_MINIMUM(1), 0x00,   /* 8-bit values */ \
+        LOGICAL_MAXIMUM(1), 0xFF, \
+        REPORT_SIZE(1), 0x08,       /* 8 bits per report */ \
+        REPORT_COUNT(1), 0x04,      /* 4 reports (4 bytes) */ \
+        INPUT(1), 0x02,             /* Data, Variable, Absolute */ \
+        \
+        USAGE_PAGE(1), 0x09,        /* Buttons */ \
+        USAGE_MINIMUM(1), 0x01,     /* { buttons } */ \
+        USAGE_MAXIMUM(1), 0x20,     /* {  1-32   } */ \
+        LOGICAL_MINIMUM(1), 0x00,   /* 1-bit buttons - 0... */ \
+        LOGICAL_MAXIMUM(1), 0x01,   /* ...to 1 */ \
+        REPORT_SIZE(1), 0x01,       /* 1 bit per report */ \
+        REPORT_COUNT(1), 0x20,      /* 32 reports */ \
+        UNIT_EXPONENT(1), 0x00,     /* Unit_Exponent (0) */ \
+        UNIT(1), 0x00,              /* Unit (None) */ \
+        INPUT(1), 0x02,             /* Data, Variable, Absolute */ \
+         \
+        USAGE_PAGE(1), 0x01,        /* Generic desktop */ \
+        USAGE(1), 0x30,             /* X axis */ \
+        USAGE(1), 0x31,             /* Y axis */ \
+        USAGE(1), 0x32,             /* Z axis */ \
+        LOGICAL_MINIMUM(2), 0x00,0xF0,   /* each value ranges -4096 */ \
+        LOGICAL_MAXIMUM(2), 0x00,0x10,   /* ...to +4096 */ \
+        REPORT_SIZE(1), 0x10,       /* 16 bits per report */ \
+        REPORT_COUNT(1), 0x03,      /* 3 reports (X, Y, Z) */ \
+        INPUT(1), 0x02,             /* Data, Variable, Absolute */ \
+        \
+        /* output report (host to device) */ \
+        REPORT_ID(1), REPORT_ID_JS, \
+        REPORT_SIZE(1), 0x08,       /* 8 bits per report */ \
+        REPORT_COUNT(1), 0x08,      /* output report count - 8-byte LedWiz format */ \
+        0x09, 0x01,                 /* usage */ \
+        0x91, 0x01,                 /* Output (array) */ \
+        \
+    END_COLLECTION(0)
+
+
+#define HID_REPORT_STAT \
+    USAGE_PAGE(1), 0x01,            /* Generic desktop */ \
+    USAGE(1), 0x00,                 /* Undefined */ \
+    COLLECTION(1), 0x01,            /* Application */ \
+        REPORT_ID(1), REPORT_ID_STAT, \
+        USAGE_PAGE(1), 0x06,        /* generic device controls */ \
+        USAGE(1), 0x00,             /* undefined device control */ \
+        LOGICAL_MINIMUM(1), 0x00,   /* 8-bit value range */ \
+        LOGICAL_MAXIMUM(1), 0xFF, \
+        REPORT_SIZE(1), 0x08,       /* 8 bits per report */ \
+        REPORT_COUNT(1), reportLen, /* 'reportLen' reports==bytes */ \
+        INPUT(1), 0x02,             /* Data, Variable, Absolute */ \
+    END_COLLECTION(0)
 
-        USAGE_PAGE(1), 0x09,        // Buttons
-        USAGE_MINIMUM(1), 0x01,     // { buttons }
-        USAGE_MAXIMUM(1), 0x20,     // {  1-32   }
-        LOGICAL_MINIMUM(1), 0x00,   // 1-bit buttons - 0...
-        LOGICAL_MAXIMUM(1), 0x01,   // ...to 1
-        REPORT_SIZE(1), 0x01,       // 1 bit per report
-        REPORT_COUNT(1), 0x20,      // 32 reports
-        UNIT_EXPONENT(1), 0x00,     // Unit_Exponent (0)
-        UNIT(1), 0x00,              // Unit (None)                                           
-        INPUT(1), 0x02,             // Data, Variable, Absolute
-       
-        USAGE_PAGE(1), 0x01,        // Generic desktop
-        USAGE(1), 0x30,             // X axis
-        USAGE(1), 0x31,             // Y axis
-        USAGE(1), 0x32,             // Z axis
-        LOGICAL_MINIMUM(2), 0x00,0xF0,   // each value ranges -4096
-        LOGICAL_MAXIMUM(2), 0x00,0x10,   // ...to +4096
-        REPORT_SIZE(1), 0x10,       // 16 bits per report
-        REPORT_COUNT(1), 0x03,      // 3 reports (X, Y, Z)
-        INPUT(1), 0x02,             // Data, Variable, Absolute
-         
-        // output report (host to device)
-        REPORT_SIZE(1), 0x08,       // 8 bits per report
-        REPORT_COUNT(1), 0x08,      // output report count - 8-byte LedWiz format
-        0x09, 0x01,                 // usage
-        0x91, 0x01,                 // Output (array)
+#define HID_REPORT_KB \
+    USAGE_PAGE(1), 0x01,            /* Generic Desktop */ \
+    USAGE(1), 0x06,                 /* Keyboard */ \
+    \
+    /* Keyboard keys */ \
+    COLLECTION(1), 0x01,            /* Application */ \
+        REPORT_ID(1), REPORT_ID_KB, \
+        \
+        /* input report (device to host) - regular keys */ \
+        REPORT_COUNT(1), 0x06, \
+        REPORT_SIZE(1), 0x08, \
+        LOGICAL_MINIMUM(1), 0x00, \
+        LOGICAL_MAXIMUM(1), 0x65, \
+        USAGE_PAGE(1), 0x07,        /* Key Codes */ \
+        USAGE_MINIMUM(1), 0x00, \
+        USAGE_MAXIMUM(1), 0x65, \
+        INPUT(1), 0x00,             /* Data, Array */ \
+        \
+        /* input report (device to host) - modifier keys */ \
+        USAGE_PAGE(1), 0x07,        /* Key Codes */ \
+        USAGE_MINIMUM(1), 0xE0, \
+        USAGE_MAXIMUM(1), 0xE7, \
+        LOGICAL_MINIMUM(1), 0x00, \
+        LOGICAL_MAXIMUM(1), 0x01, \
+        REPORT_SIZE(1), 0x01, \
+        REPORT_COUNT(1), 0x08, \
+        INPUT(1), 0x02,             /* Data, Variable, Absolute */ \
+        REPORT_COUNT(1), 0x01, \
+        REPORT_SIZE(1), 0x08, \
+        INPUT(1), 0x01,             /* Constant */ \
+        \
+        /* output report (host to device) - LED status */ \
+        REPORT_COUNT(1), 0x05, \
+        REPORT_SIZE(1), 0x01, \
+        USAGE_PAGE(1), 0x08,        /* LEDs */ \
+        USAGE_MINIMUM(1), 0x01, \
+        USAGE_MAXIMUM(1), 0x05, \
+        OUTPUT(1), 0x02,            /* Data, Variable, Absolute */ \
+        REPORT_COUNT(1), 0x01, \
+        REPORT_SIZE(1), 0x03, \
+        OUTPUT(1), 0x01,            /* Constant */ \
+    END_COLLECTION(0), \
+    \
+    /* Media Control Keys */ \
+    USAGE_PAGE(1), 0x0C, \
+    USAGE(1), 0x01, \
+    COLLECTION(1), 0x01, \
+        /* input report (device to host) */ \
+        REPORT_ID(1), REPORT_ID_MEDIA, \
+        USAGE_PAGE(1), 0x0C, \
+        LOGICAL_MINIMUM(1), 0x00, \
+        LOGICAL_MAXIMUM(1), 0x01, \
+        REPORT_SIZE(1), 0x01, \
+        REPORT_COUNT(1), 0x07, \
+        USAGE(1), 0xE2,             /* Mute -> 0x01 */ \
+        USAGE(1), 0xE9,             /* Volume Up -> 0x02 */ \
+        USAGE(1), 0xEA,             /* Volume Down -> 0x04 */ \
+        USAGE(1), 0xB5,             /* Next Track -> 0x08 */ \
+        USAGE(1), 0xB6,             /* Previous Track -> 0x10 */ \
+        USAGE(1), 0xB7,             /* Stop -> 0x20 */ \
+        USAGE(1), 0xCD,             /* Play / Pause -> 0x40 */ \
+        INPUT(1), 0x02,             /* Input (Data, Variable, Absolute) -> 0x80 */ \
+        REPORT_COUNT(1), 0x01, \
+        INPUT(1), 0x01, \
+    END_COLLECTION(0)
 
+#define HID_REPORT_LW \
+    USAGE_PAGE(1), 0x01,            /* Generic desktop */ \
+    USAGE(1), 0x00,                 /* Undefined */ \
+    COLLECTION(1), 0x01,            /* Application */ \
+        /* output report (host to device) */ \
+        REPORT_ID(1), REPORT_ID_JS, \
+        REPORT_SIZE(1), 0x08,       /* 8 bits per report */ \
+        REPORT_COUNT(1), 0x08,      /* output report count (LEDWiz messages) */ \
+        0x09, 0x01,                 /* usage */ \
+        0x91, 0x01,                 /* Output (array) */ \
+    END_COLLECTION(0)
+
+
+// Joystick + Keyboard + LedWiz
+static const uint8_t reportDescriptorJS[] = 
+{
+    USAGE_PAGE(1), 0x01,            /* Generic desktop */ \
+    USAGE(1), 0x04,                 /* Joystick */ \
+    COLLECTION(1), 0x01,            /* Application */ \
+
+    HID_REPORT_JS,
+    HID_REPORT_STAT,
+    HID_REPORT_KB,
+    
     END_COLLECTION(0)
 };
 
-// 
-// USB HID Report Descriptor - Keyboard/Media Control
-//
+// Keyboard + LedWiz
 static const uint8_t reportDescriptorKB[] = 
 {
-    USAGE_PAGE(1), 0x01,                    // Generic Desktop
-    USAGE(1), 0x06,                         // Keyboard
-    COLLECTION(1), 0x01,                    // Application
-        REPORT_ID(1), REPORT_ID_KB,
-
-        USAGE_PAGE(1), 0x07,                    // Key Codes
-        USAGE_MINIMUM(1), 0xE0,
-        USAGE_MAXIMUM(1), 0xE7,
-        LOGICAL_MINIMUM(1), 0x00,
-        LOGICAL_MAXIMUM(1), 0x01,
-        REPORT_SIZE(1), 0x01,
-        REPORT_COUNT(1), 0x08,
-        INPUT(1), 0x02,                         // Data, Variable, Absolute
-        REPORT_COUNT(1), 0x01,
-        REPORT_SIZE(1), 0x08,
-        INPUT(1), 0x01,                         // Constant
-
-        REPORT_COUNT(1), 0x05,
-        REPORT_SIZE(1), 0x01,
-        USAGE_PAGE(1), 0x08,                    // LEDs
-        USAGE_MINIMUM(1), 0x01,
-        USAGE_MAXIMUM(1), 0x05,
-        OUTPUT(1), 0x02,                        // Data, Variable, Absolute
-        REPORT_COUNT(1), 0x01,
-        REPORT_SIZE(1), 0x03,
-        OUTPUT(1), 0x01,                        // Constant
-
-        REPORT_COUNT(1), 0x06,
-        REPORT_SIZE(1), 0x08,
-        LOGICAL_MINIMUM(1), 0x00,
-        LOGICAL_MAXIMUM(1), 0x65,
-        USAGE_PAGE(1), 0x07,                    // Key Codes
-        USAGE_MINIMUM(1), 0x00,
-        USAGE_MAXIMUM(1), 0x65,
-        INPUT(1), 0x00,                         // Data, Array
-    END_COLLECTION(0),
-
-    // Media Control
-    USAGE_PAGE(1), 0x0C,
-    USAGE(1), 0x01,
-    COLLECTION(1), 0x01,
-        REPORT_ID(1), REPORT_ID_MEDIA,
-        USAGE_PAGE(1), 0x0C,
-        LOGICAL_MINIMUM(1), 0x00,
-        LOGICAL_MAXIMUM(1), 0x01,
-        REPORT_SIZE(1), 0x01,
-        REPORT_COUNT(1), 0x07,
-        USAGE(1), 0xE2,             // Mute -> 0x01
-        USAGE(1), 0xE9,             // Volume Up -> 0x02
-        USAGE(1), 0xEA,             // Volume Down -> 0x04
-        USAGE(1), 0xB5,             // Next Track -> 0x08
-        USAGE(1), 0xB6,             // Previous Track -> 0x10
-        USAGE(1), 0xB7,             // Stop -> 0x20
-        USAGE(1), 0xCD,             // Play / Pause -> 0x40
-        INPUT(1), 0x02,             // Input (Data, Variable, Absolute) -> 0x80
-        REPORT_COUNT(1), 0x01,
-        INPUT(1), 0x01,
-    END_COLLECTION(0),
+    HID_REPORT_LW,
+    HID_REPORT_STAT,
+    HID_REPORT_KB
 };
 
-// 
-// USB HID Report Descriptor - LedWiz only, with no joystick or keyboard
-// input reporting
-//
-static const uint8_t reportDescriptorLW[] = 
-{         
-    USAGE_PAGE(1), 0x01,            // Generic desktop
-    USAGE(1), 0x00,                 // Undefined
-
-    COLLECTION(1), 0x01,            // Application
-     
-        // input report (device to host)
-        USAGE_PAGE(1), 0x06,        // generic device controls - for config status
-        USAGE(1), 0x00,             // undefined device control
-        LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
-        LOGICAL_MAXIMUM(1), 0xFF,
-        REPORT_SIZE(1), 0x08,       // 8 bits per report
-        REPORT_COUNT(1), reportLen, // standard report length (same as if we were in joystick mode)
-        INPUT(1), 0x02,             // Data, Variable, Absolute
-
-        // output report (host to device)
-        REPORT_SIZE(1), 0x08,       // 8 bits per report
-        REPORT_COUNT(1), 0x08,      // output report count (LEDWiz messages)
-        0x09, 0x01,                 // usage
-        0x91, 0x01,                 // Output (array)
-
-    END_COLLECTION(0)
+// LedWiz only
+static const uint8_t reportDescriptorLW[] =
+{
+    HID_REPORT_LW,
+    HID_REPORT_STAT
 };
 
-
 const uint8_t *USBJoystick::reportDesc(int idx, uint16_t &len) 
 {    
-    switch (idx)
+    // we only have one interface (#0)
+    if (idx != 0)
     {
-    case 0:
-        // If the joystick is enabled, this is the joystick.
-        // Otherwise, it's the plain LedWiz control interface.
-        if (enableJoystick)
-        {
-            len = sizeof(reportDescriptorJS);
-            return reportDescriptorJS;
-        }
-        else
-        {
-            len = sizeof(reportDescriptorLW);
-            return reportDescriptorLW;
-        }
-        
-    case 1:
-        // This is the keyboard, if enabled.
-        if (useKB)
-        {
-            len = sizeof(reportDescriptorKB);
-            return reportDescriptorKB;
-        }
-        else
-        {
-            len = 0;
-            return 0;
-        }
-        
-    default:
-        // Unknown interface ID
         len = 0;
         return 0;
     }
+    
+    // figure which type of reports we generate according to which
+    // features are enabled
+    if (enableJoystick)
+    {
+        // joystick enabled - use the JS + KB + LW descriptor
+        len = sizeof(reportDescriptorJS);
+        return reportDescriptorJS;
+    }
+    else if (useKB)
+    {
+        // joystick disabled, keyboard enabled - use KB + LW
+        len = sizeof(reportDescriptorKB);
+        return reportDescriptorKB;
+    }
+    else
+    {
+        // joystick and keyboard disabled - LW only
+        len = sizeof(reportDescriptorLW);
+        return reportDescriptorLW;
+    }
 } 
  
  const uint8_t *USBJoystick::stringImanufacturerDesc() {
@@ -572,10 +611,18 @@
     // the interfaces once the information is cached, causing connection failures.
     // The cache key includes the device serial number, though, so this can be 
     // resolved by changing the serial number when the interface setup changes.
+    //
+    // The version suffix serves a similar purpose, to force a new Windows cache
+    // key whenever we make changes in the USB descriptors that require a refresh
+    // on the Windows side.  The version here is completely unrelated to any other
+    // version numbers throughout the system; it's purely internal to this class
+    // and doesn't have to be synced to anything else.  There aren't any particular 
+    // rules about when it needs to be changed; we'll change it as needed when we
+    // observe the need for it due to caching problems on Windows.
     char xbuf[numChars + 1];
     uint32_t x = SIM->UIDML;
     static char ifcCode[] = "LJKC";
-    sprintf(xbuf, "PSC%08lX%08lX%c008",
+    sprintf(xbuf, "PSC%08lX%08lX%c009",
         SIM->UIDML, 
         SIM->UIDL, 
         ifcCode[(enableJoystick ? 0x01 : 0x00) | (useKB ? 0x02 : 0x00)]);
@@ -607,165 +654,67 @@
 
 const uint8_t *USBJoystick::configurationDesc() 
 {
-    int rptlen0 = reportDescLength(0);
-    int rptlen1 = reportDescLength(1);
-    if (useKB)
+    int rptlen = reportDescLength(0);
+    const int cfglen = 
+        ((1 * CONFIGURATION_DESCRIPTOR_LENGTH)
+         + (1 * INTERFACE_DESCRIPTOR_LENGTH)
+         + (1 * HID_DESCRIPTOR_LENGTH)
+         + (2 * ENDPOINT_DESCRIPTOR_LENGTH));
+    static uint8_t configurationDescriptor[] = 
     {
-        const int cfglenKB = 
-            ((1 * CONFIGURATION_DESCRIPTOR_LENGTH)
-             + (2 * INTERFACE_DESCRIPTOR_LENGTH)
-             + (2 * HID_DESCRIPTOR_LENGTH)
-             + (4 * ENDPOINT_DESCRIPTOR_LENGTH));
-        static uint8_t configurationDescriptorWithKB[] = 
-        {
-            CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
-            CONFIGURATION_DESCRIPTOR,       // bDescriptorType
-            LSB(cfglenKB),                  // wTotalLength (LSB)
-            MSB(cfglenKB),                  // wTotalLength (MSB)
-            0x02,                           // bNumInterfaces - TWO INTERFACES (JOYSTICK + KEYBOARD)
-            DEFAULT_CONFIGURATION,          // bConfigurationValue
-            0x00,                           // iConfiguration
-            C_RESERVED | C_SELF_POWERED,    // bmAttributes
-            C_POWER(0),                     // bMaxPower
-        
-            // ***** INTERFACE 0 - JOYSTICK/LEDWIZ ******
-            INTERFACE_DESCRIPTOR_LENGTH,    // bLength
-            INTERFACE_DESCRIPTOR,           // bDescriptorType
-            0x00,                           // bInterfaceNumber
-            0x00,                           // bAlternateSetting
-            0x02,                           // bNumEndpoints
-            HID_CLASS,                      // bInterfaceClass
-            HID_SUBCLASS_NONE,              // bInterfaceSubClass
-            HID_PROTOCOL_NONE,              // bInterfaceProtocol
-            0x00,                           // iInterface
-        
-            HID_DESCRIPTOR_LENGTH,          // bLength
-            HID_DESCRIPTOR,                 // bDescriptorType
-            LSB(HID_VERSION_1_11),          // bcdHID (LSB)
-            MSB(HID_VERSION_1_11),          // bcdHID (MSB)
-            0x00,                           // bCountryCode
-            0x01,                           // bNumDescriptors
-            REPORT_DESCRIPTOR,              // bDescriptorType
-            LSB(rptlen0),                   // wDescriptorLength (LSB)
-            MSB(rptlen0),                   // wDescriptorLength (MSB)
-        
-            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
-            ENDPOINT_DESCRIPTOR,            // bDescriptorType
-            PHY_TO_DESC(EPINT_IN),          // bEndpointAddress - EPINT == EP1
-            E_INTERRUPT,                    // bmAttributes
-            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
-            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
-            1,                              // bInterval (milliseconds)
-        
-            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
-            ENDPOINT_DESCRIPTOR,            // bDescriptorType
-            PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress - EPINT == EP1
-            E_INTERRUPT,                    // bmAttributes
-            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
-            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
-            1,                              // bInterval (milliseconds)
-            
-            // ****** INTERFACE 1 - KEYBOARD ******
-            INTERFACE_DESCRIPTOR_LENGTH,    // bLength
-            INTERFACE_DESCRIPTOR,           // bDescriptorType
-            0x01,                           // bInterfaceNumber
-            0x00,                           // bAlternateSetting
-            0x02,                           // bNumEndpoints
-            HID_CLASS,                      // bInterfaceClass
-            HID_SUBCLASS_BOOT,              // bInterfaceSubClass
-            HID_PROTOCOL_KB,                // bInterfaceProtocol
-            0x00,                           // iInterface
-        
-            HID_DESCRIPTOR_LENGTH,          // bLength
-            HID_DESCRIPTOR,                 // bDescriptorType
-            LSB(HID_VERSION_1_11),          // bcdHID (LSB)
-            MSB(HID_VERSION_1_11),          // bcdHID (MSB)
-            0x00,                           // bCountryCode
-            0x01,                           // bNumDescriptors
-            REPORT_DESCRIPTOR,              // bDescriptorType
-            LSB(rptlen1),                   // wDescriptorLength (LSB)
-            MSB(rptlen1),                   // wDescriptorLength (MSB)
-        
-            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
-            ENDPOINT_DESCRIPTOR,            // bDescriptorType
-            PHY_TO_DESC(EP4IN),             // bEndpointAddress
-            E_INTERRUPT,                    // bmAttributes
-            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
-            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
-            1,                              // bInterval (milliseconds)
-        
-            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
-            ENDPOINT_DESCRIPTOR,            // bDescriptorType
-            PHY_TO_DESC(EP4OUT),            // bEndpointAddress
-            E_INTERRUPT,                    // bmAttributes
-            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
-            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
-            1,                              // bInterval (milliseconds)
+        // Configuration descriptor
+        CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
+        CONFIGURATION_DESCRIPTOR,       // bDescriptorType
+        LSB(cfglen),                    // wTotalLength (LSB)
+        MSB(cfglen),                    // wTotalLength (MSB)
+        0x01,                           // bNumInterfaces
+        DEFAULT_CONFIGURATION,          // bConfigurationValue
+        0x00,                           // iConfiguration
+        C_RESERVED | C_SELF_POWERED,    // bmAttributes
+        C_POWER(0),                     // bMaxPower
+    
+        // Interface descriptor
+        INTERFACE_DESCRIPTOR_LENGTH,    // bLength
+        INTERFACE_DESCRIPTOR,           // bDescriptorType
+        0x00,                           // bInterfaceNumber
+        0x00,                           // bAlternateSetting
+        0x02,                           // bNumEndpoints
+        HID_CLASS,                      // bInterfaceClass
+        HID_SUBCLASS_NONE,              // bInterfaceSubClass
+        HID_PROTOCOL_NONE,              // bInterfaceProtocol
+        0x00,                           // iInterface
+    
+        // HID descriptor, with link to report descriptor
+        HID_DESCRIPTOR_LENGTH,          // bLength
+        HID_DESCRIPTOR,                 // bDescriptorType
+        LSB(HID_VERSION_1_11),          // bcdHID (LSB)
+        MSB(HID_VERSION_1_11),          // bcdHID (MSB)
+        0x00,                           // bCountryCode
+        0x01,                           // bNumDescriptors
+        REPORT_DESCRIPTOR,              // bDescriptorType
+        LSB(rptlen),                    // wDescriptorLength (LSB)
+        MSB(rptlen),                    // wDescriptorLength (MSB)
+    
+        // IN endpoint descriptor
+        ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+        ENDPOINT_DESCRIPTOR,            // bDescriptorType
+        PHY_TO_DESC(EPINT_IN),          // bEndpointAddress - EPINT == EP1
+        E_INTERRUPT,                    // bmAttributes
+        LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+        1,                              // bInterval (milliseconds)
+    
+        // OUT endpoint descriptor
+        ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+        ENDPOINT_DESCRIPTOR,            // bDescriptorType
+        PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress - EPINT == EP1
+        E_INTERRUPT,                    // bmAttributes
+        LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+        1                               // bInterval (milliseconds)
+    };
 
-        };
-
-        // Keyboard + joystick interfaces
-        return configurationDescriptorWithKB;
-    }
-    else
-    {
-        // No keyboard - joystick interface only
-        const int cfglenNoKB = 
-            ((1 * CONFIGURATION_DESCRIPTOR_LENGTH)
-              + (1 * INTERFACE_DESCRIPTOR_LENGTH)
-              + (1 * HID_DESCRIPTOR_LENGTH)
-              + (2 * ENDPOINT_DESCRIPTOR_LENGTH));
-        static uint8_t configurationDescriptorNoKB[] = 
-        {
-            CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
-            CONFIGURATION_DESCRIPTOR,       // bDescriptorType
-            LSB(cfglenNoKB),                // wTotalLength (LSB)
-            MSB(cfglenNoKB),                // wTotalLength (MSB)
-            0x01,                           // bNumInterfaces
-            DEFAULT_CONFIGURATION,          // bConfigurationValue
-            0x00,                           // iConfiguration
-            C_RESERVED | C_SELF_POWERED,    // bmAttributes
-            C_POWER(0),                     // bMaxPower
-        
-            INTERFACE_DESCRIPTOR_LENGTH,    // bLength
-            INTERFACE_DESCRIPTOR,           // bDescriptorType
-            0x00,                           // bInterfaceNumber
-            0x00,                           // bAlternateSetting
-            0x02,                           // bNumEndpoints
-            HID_CLASS,                      // bInterfaceClass
-            HID_SUBCLASS_NONE,              // bInterfaceSubClass
-            HID_PROTOCOL_NONE,              // bInterfaceProtocol (keyboard)
-            0x00,                           // iInterface
-        
-            HID_DESCRIPTOR_LENGTH,          // bLength
-            HID_DESCRIPTOR,                 // bDescriptorType
-            LSB(HID_VERSION_1_11),          // bcdHID (LSB)
-            MSB(HID_VERSION_1_11),          // bcdHID (MSB)
-            0x00,                           // bCountryCode
-            0x01,                           // bNumDescriptors
-            REPORT_DESCRIPTOR,              // bDescriptorType
-            (uint8_t)(LSB(rptlen0)),        // wDescriptorLength (LSB)
-            (uint8_t)(MSB(rptlen0)),        // wDescriptorLength (MSB)
-        
-            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
-            ENDPOINT_DESCRIPTOR,            // bDescriptorType
-            PHY_TO_DESC(EPINT_IN),          // bEndpointAddress
-            E_INTERRUPT,                    // bmAttributes
-            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
-            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
-            1,                              // bInterval (milliseconds)
-        
-            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
-            ENDPOINT_DESCRIPTOR,            // bDescriptorType
-            PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress
-            E_INTERRUPT,                    // bmAttributes
-            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
-            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
-            1                               // bInterval (milliseconds)
-        };
-
-        return configurationDescriptorNoKB;
-    }
+    return configurationDescriptor;
 }
 
 // Set the configuration.  We need to set up the endpoints for
@@ -776,19 +725,10 @@
     if (configuration != DEFAULT_CONFIGURATION)
         return false;
         
-    // Configure endpoint 1 - we use this in all cases, for either
-    // the combined joystick/ledwiz interface or just the ledwiz interface
+    // Configure endpoint 1
     addEndpoint(EPINT_IN, MAX_REPORT_JS_TX + 1);
     addEndpoint(EPINT_OUT, MAX_REPORT_JS_RX + 1);
     readStart(EPINT_OUT, MAX_REPORT_JS_TX + 1);
-    
-    // if the keyboard is enabled, configure endpoint 4 for the kb interface
-    if (useKB)
-    {
-        addEndpoint(EP4IN, MAX_REPORT_KB_TX + 1);
-        addEndpoint(EP4OUT, MAX_REPORT_KB_RX + 1);
-        readStart(EP4OUT, MAX_REPORT_KB_TX + 1);
-    }
 
     // success
     return true;
@@ -806,33 +746,31 @@
 bool USBJoystick::EP1_OUT_callback()
 {
     // Read this message
-    union {
-        LedWizMsg msg;
-        uint8_t buf[MAX_HID_REPORT_SIZE];
-    } buf;
+    uint8_t buf[MAX_HID_REPORT_SIZE];
     uint32_t bytesRead = 0;
-    USBDevice::readEP(EP1OUT, buf.buf, &bytesRead, MAX_HID_REPORT_SIZE);
+    USBDevice::readEP(EP1OUT, buf, &bytesRead, MAX_HID_REPORT_SIZE);
     
-    // if it's the right length, queue it to our circular buffer
-    if (bytesRead == 8)
-        lwbuf.write(buf.msg);
+    // check the report type
+    switch (buf[0])
+    {
+    case REPORT_ID_JS:
+        // Joystick/ledwiz.  These are LedWiz or private protocol command
+        // messages.  Queue to the incoming LW command list.
+        if (bytesRead == 9)
+            lwbuf.write((LedWizMsg *)&buf[1]);
+        break;
+        
+    case REPORT_ID_KB:
+        // Keyboard.  These are standard USB keyboard protocol messages,
+        // telling us the shift key LED status.  We don't do anything with
+        // these; just accept and ignore them.
+        break;
+        
+    default:
+        // Other report types are unexpected; just ignore them.
+        break;
+    }
 
     // start the next read
     return readStart(EP1OUT, MAX_HID_REPORT_SIZE);
 }
-
-// Handle incoming messages on the keyboard interface = endpoint 4.
-// The host uses this to send updates for the keyboard indicator LEDs
-// (caps lock, num lock, etc).  We don't do anything with these, but
-// we have to read them to keep the pipe open.
-bool USBJoystick::EP4_OUT_callback() 
-{
-    // read this message
-    uint32_t bytesRead = 0;
-    uint8_t led[MAX_HID_REPORT_SIZE];
-    USBDevice::readEP(EP4OUT, led, &bytesRead, MAX_HID_REPORT_SIZE);
-
-    // start the next read
-    return readStart(EP4OUT, MAX_HID_REPORT_SIZE);
-}
-