An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.

Dependencies:   mbed FastIO FastPWM USBDevice

Fork of Pinscape_Controller by Mike R

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBJoystick.cpp Source File

USBJoystick.cpp

00001 /* Copyright (c) 2010-2011 mbed.org, MIT License
00002 * Modified Mouse code for Joystick - WH 2012
00003 *
00004 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00005 * and associated documentation files (the "Software"), to deal in the Software without
00006 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
00007 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
00008 * Software is furnished to do so, subject to the following conditions:
00009 *
00010 * The above copyright notice and this permission notice shall be included in all copies or
00011 * substantial portions of the Software.
00012 *
00013 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00014 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00015 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00016 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00017 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00018 */
00019  
00020 #include "stdint.h"
00021 #include "USBJoystick.h"
00022 
00023 #include "config.h"  // Pinscape configuration
00024 
00025 
00026 
00027 // Maximum report sizes
00028 const int MAX_REPORT_JS_TX = USBJoystick::reportLen;
00029 const int MAX_REPORT_JS_RX = 8;
00030 const int MAX_REPORT_KB_TX = 8;
00031 const int MAX_REPORT_KB_RX = 4;
00032 
00033 bool USBJoystick::update(int16_t x, int16_t y, int16_t z, uint32_t buttons, uint16_t status) 
00034 {
00035    _x = x;
00036    _y = y;
00037    _z = z;
00038    _buttonsLo = (uint16_t)(buttons & 0xffff);
00039    _buttonsHi = (uint16_t)((buttons >> 16) & 0xffff);
00040    _status = status;
00041  
00042    // send the report
00043    return update();
00044 }
00045 
00046 bool USBJoystick::update() 
00047 {
00048    HID_REPORT report;
00049 
00050    // Fill the report according to the Joystick Descriptor
00051 #define put(idx, val) (report.data[idx] = (val) & 0xff, report.data[(idx)+1] = ((val) >> 8) & 0xff)
00052 #define putbe(idx, val) (report.data[(idx)+1] = (val) & 0xff, report.data[idx] = ((val) >> 8) & 0xff)
00053 #define putl(idx, val) (put(idx, val), put((idx)+2, (val) >> 16))
00054 #define putlbe(idx, val) (putbe((idx)+2, val), putbe(idx, (val) >> 16))
00055 #define put64(idx, val) (putl(idx, val), putl((idx)+4, (val) >> 32))
00056    put(0, _status);
00057    put(2, 0);  // second word of status - zero in high bit identifies as normal joystick report
00058    put(4, _buttonsLo);
00059    put(6, _buttonsHi);
00060    put(8, _x);
00061    put(10, _y);
00062    put(12, _z);
00063    
00064    // important: keep reportLen in sync with the actual byte length of
00065    // the reports we build here
00066    report.length = reportLen;
00067  
00068    // send the report
00069    return sendTO(&report, 100);
00070 }
00071 
00072 bool USBJoystick::kbUpdate(uint8_t data[8])
00073 {
00074     // set up the report
00075     HID_REPORT report;
00076     report.data[0] = REPORT_ID_KB;      // report ID = keyboard
00077     memcpy(&report.data[1], data, 8);   // copy the kb report data
00078     report.length = 9;                  // length = ID prefix + kb report length
00079     
00080     // send it to endpoint 4 (the keyboard interface endpoint)
00081     return writeTO(EP4IN, report.data, report.length, MAX_PACKET_SIZE_EPINT, 100);
00082 }
00083 
00084 bool USBJoystick::mediaUpdate(uint8_t data)
00085 {
00086     // set up the report
00087     HID_REPORT report;
00088     report.data[0] = REPORT_ID_MEDIA;   // report ID = media
00089     report.data[1] = data;              // key pressed bits
00090     report.length = 2;
00091     
00092     // send it
00093     return writeTO(EP4IN, report.data, report.length, MAX_PACKET_SIZE_EPINT, 100);
00094 }
00095  
00096 bool USBJoystick::sendPlungerStatus(
00097     int npix, int plungerPos, int flags, uint32_t avgScanTime, uint32_t processingTime)
00098 {
00099     HID_REPORT report;
00100     
00101     // Set the special status bits to indicate it's an extended
00102     // exposure report.
00103     put(0, 0x87FF);
00104     
00105     // start at the second byte
00106     int ofs = 2;
00107     
00108     // write the report subtype (0) to byte 2
00109     report.data[ofs++] = 0;
00110 
00111     // write the number of pixels to bytes 3-4
00112     put(ofs, uint16_t(npix));
00113     ofs += 2;
00114     
00115     // write the detected plunger position to bytes 5-6
00116     put(ofs, uint16_t(plungerPos));
00117     ofs += 2;
00118     
00119     // Add the calibration mode flag if applicable
00120     extern bool plungerCalMode;
00121     if (plungerCalMode) flags |= 0x04;
00122     
00123     // write the flags to byte 7
00124     report.data[ofs++] = flags;
00125     
00126     // write the average scan time in 10us intervals to bytes 8-10
00127     uint32_t t = uint32_t(avgScanTime / 10);
00128     report.data[ofs++] = t & 0xff;
00129     report.data[ofs++] = (t >> 8) & 0xff;
00130     report.data[ofs++] = (t >> 16) & 0xff;
00131     
00132     // write the processing time to bytes 11-13
00133     t = uint32_t(processingTime / 10);
00134     report.data[ofs++] = t & 0xff;
00135     report.data[ofs++] = (t >> 8) & 0xff;
00136     report.data[ofs++] = (t >> 16) & 0xff;
00137     
00138     // send the report
00139     report.length = reportLen;
00140     return sendTO(&report, 100);
00141 }
00142 
00143 bool USBJoystick::sendPlungerStatus2(
00144     int nativeScale, 
00145     int jitterLo, int jitterHi, int rawPos,
00146     int axcTime)
00147 {
00148     HID_REPORT report;
00149     memset(report.data, 0, sizeof(report.data));
00150     
00151     // Set the special status bits to indicate it's an extended
00152     // exposure report.
00153     put(0, 0x87FF);
00154     
00155     // start at the second byte
00156     int ofs = 2;
00157     
00158     // write the report subtype (1) to byte 2
00159     report.data[ofs++] = 1;
00160 
00161     // write the native scale to bytes 3:4
00162     put(ofs, uint16_t(nativeScale));
00163     ofs += 2;
00164     
00165     // limit the jitter filter bounds to the native scale
00166     if (jitterLo < 0) 
00167         jitterLo = 0;
00168     else if (jitterLo > nativeScale) 
00169         jitterLo = nativeScale;
00170     if (jitterHi < 0)
00171         jitterHi = 0;
00172     else if (jitterHi > nativeScale)
00173         jitterHi = nativeScale;
00174     
00175     // write the jitter filter window bounds to 5:6 and 7:8
00176     put(ofs, uint16_t(jitterLo));
00177     ofs += 2;
00178     put(ofs, uint16_t(jitterHi));
00179     ofs += 2;
00180     
00181     // add the raw position
00182     put(ofs, uint16_t(rawPos));
00183     ofs += 2;
00184     
00185     // add the auto-exposure time
00186     put(ofs, uint16_t(axcTime));
00187     ofs += 2;
00188     
00189     // send the report
00190     report.length = reportLen;
00191     return sendTO(&report, 100);
00192 }
00193 
00194 bool USBJoystick::sendPlungerStatusBarcode(
00195         int nbits, int codetype, int startOfs, int pixPerBit, int raw, int mask)
00196 {
00197     HID_REPORT report;
00198     memset(report.data, 0, sizeof(report.data));
00199     
00200     // Set the special status bits to indicate it's an extended
00201     // status report for barcode sensors
00202     put(0, 0x87FF);
00203     
00204     // start at the second byte
00205     int ofs = 2;
00206     
00207     // write the report subtype (2) to byte 2
00208     report.data[ofs++] = 2;
00209 
00210     // write the bit count and code type
00211     report.data[ofs++] = nbits;
00212     report.data[ofs++] = codetype;
00213     
00214     // write the bar code starting pixel offset
00215     put(ofs, uint16_t(startOfs));
00216     ofs += 2;
00217     
00218     // write the pixel width per bit
00219     report.data[ofs++] = pixPerBit;
00220     
00221     // write the raw bar code and success bit mask
00222     put(ofs, uint16_t(raw));
00223     ofs += 2;
00224     put(ofs, uint16_t(mask));
00225     ofs += 2;
00226     
00227     // send the report
00228     report.length = reportLen;
00229     return sendTO(&report, 100);
00230 }
00231 
00232 bool USBJoystick::sendPlungerStatusQuadrature(int chA, int chB)
00233 {
00234     HID_REPORT report;
00235     memset(report.data, 0, sizeof(report.data));
00236     
00237     // set the status bits to indicate that it's an extended
00238     // status report for quadrature sensors
00239     put(0, 0x87FF);
00240     int ofs = 2;
00241     
00242     // write the report subtype (3)
00243     report.data[ofs++] = 3;
00244     
00245     // write the channel "A" and channel "B" values
00246     report.data[ofs++] = static_cast<uint8_t>(chA);
00247     report.data[ofs++] = static_cast<uint8_t>(chB);
00248     
00249     // send the report
00250     report.length = reportLen;
00251     return sendTO(&report, 100);
00252 }
00253 
00254 
00255 bool USBJoystick::sendPlungerPix(int &idx, int npix, const uint8_t *pix)
00256 {
00257     HID_REPORT report;
00258     
00259     // Set the special status bits to indicate it's an exposure report.
00260     // The high 5 bits of the status word are set to 10000, and the
00261     // low 11 bits are the current pixel index.
00262     uint16_t s = idx | 0x8000;
00263     put(0, s);
00264     
00265     // start at the second byte
00266     int ofs = 2;
00267     
00268     // now fill out the remaining bytes with exposure values
00269     report.length = reportLen;
00270     for ( ; ofs < report.length ; ++ofs)
00271         report.data[ofs] = (idx < npix ? pix[idx++] : 0);
00272     
00273     // send the report
00274     return sendTO(&report, 100);
00275 }
00276 
00277 bool USBJoystick::reportID(int index)
00278 {
00279     HID_REPORT report;
00280 
00281     // initially fill the report with zeros
00282     memset(report.data, 0, sizeof(report.data));
00283     
00284     // Set the special status bits to indicate that it's an ID report
00285     uint16_t s = 0x9000;
00286     put(0, s);
00287     
00288     // add the requested ID index
00289     report.data[2] = (uint8_t)index;
00290     
00291     // figure out which ID we're reporting
00292     switch (index)
00293     {
00294     case 1:
00295         // KL25Z CPU ID
00296         putbe(3, SIM->UIDMH);
00297         putlbe(5, SIM->UIDML);
00298         putlbe(9, SIM->UIDL);
00299         break;
00300         
00301     case 2:
00302         // OpenSDA ID.  Copy the low-order 80 bits of the OpenSDA ID.
00303         // (The stored value is 128 bits = 16 bytes; we only want the last
00304         // 80 bits = 10 bytes.  So skip ahead 16 and back up 10 to get
00305         // the starting point.)
00306         extern const char *getOpenSDAID();
00307         memcpy(&report.data[3], getOpenSDAID() + 16 - 10, 10);
00308         break;
00309     }
00310     
00311     // send the report
00312     report.length = reportLen;
00313     return sendTO(&report, 100);
00314 }
00315 
00316 bool USBJoystick::reportBuildInfo(const char *date)
00317 {
00318     HID_REPORT report;
00319 
00320     // initially fill the report with zeros
00321     memset(report.data, 0, sizeof(report.data));
00322     
00323     // Set the special status bits to indicate that it's a build
00324     // info report
00325     uint16_t s = 0xA000;
00326     put(0, s);
00327     
00328     // Parse the date.  This is given in the standard __DATE__ " " __TIME
00329     // macro format, "Mon dd yyyy hh:mm:ss" (e.g., "Feb 16 2016 12:15:06").
00330     static const char mon[][4] = {
00331         "Jan", "Feb", "Mar", "Apr", "May", "Jun", 
00332         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 
00333     };
00334     long dd = (atol(date + 7) * 10000L) // YYYY0000
00335         + (atol(date + 4));             // 000000DD
00336     for (int i = 0 ; i < 12 ; ++i)
00337     {
00338         if (memcmp(mon[i], date, 3) == 0)
00339         {
00340             dd += (i+1)*100;         // 0000MM00
00341             break;
00342         }
00343     }
00344     
00345     // parse the time into a long formatted as decimal HHMMSS (e.g.,
00346     // "12:15:06" turns into 121506 decimal)
00347     long tt = (atol(date+12)*10000)
00348         + (atol(date+15)*100)
00349         + (atol(date+18));
00350     
00351     // store the build date and time
00352     putl(2, dd);
00353     putl(6, tt);
00354     
00355     // send the report
00356     report.length = reportLen;
00357     return sendTO(&report, 100);
00358 }
00359 
00360 bool USBJoystick::reportConfigVar(const uint8_t *data)
00361 {
00362     HID_REPORT report;
00363 
00364     // initially fill the report with zeros
00365     memset(report.data, 0, sizeof(report.data));
00366     
00367     // Set the special status bits to indicate that it's a config 
00368     // variable report
00369     uint16_t s = 0x9800;
00370     put(0, s);
00371     
00372     // Copy the variable data (7 bytes, starting with the variable ID)
00373     memcpy(report.data + 2, data, 7);
00374     
00375     // send the report
00376     report.length = reportLen;
00377     return sendTO(&report, 100);
00378 }
00379 
00380 bool USBJoystick::reportConfig(
00381     int numOutputs, int unitNo, 
00382     int plungerZero, int plungerMax, int plungerRlsTime,
00383     bool configured, bool sbxpbx, bool newAccelFeatures, 
00384     bool flashStatusFeature, bool reportTimingFeatures,
00385     bool chimeLogicFeature, size_t freeHeapBytes)
00386 {
00387     HID_REPORT report;
00388 
00389     // initially fill the report with zeros
00390     memset(report.data, 0, sizeof(report.data));
00391     
00392     // Set the special status bits to indicate that it's a config report.
00393     uint16_t s = 0x8800;
00394     put(0, s);
00395     
00396     // write the number of configured outputs
00397     put(2, numOutputs);
00398     
00399     // write the unit number
00400     put(4, unitNo);
00401     
00402     // write the plunger zero and max values
00403     put(6, plungerZero);
00404     put(8, plungerMax);
00405     report.data[10] = uint8_t(plungerRlsTime);
00406     
00407     // write the status bits: 
00408     //  0x01  -> configuration loaded
00409     //  0x02  -> SBX/PBX protocol extensions supported
00410     //  0x04  -> new accelerometer features supported
00411     //  0x08  -> flash status feature supported
00412     //  0x10  -> joystick report timing features supported
00413     //  0x20  -> chime logic feature supported
00414     report.data[11] = 
00415         (configured ? 0x01 : 0x00)
00416         | (sbxpbx ? 0x02 : 0x00)
00417         | (newAccelFeatures ? 0x04 : 0x00)
00418         | (flashStatusFeature ? 0x08 : 0x00)
00419         | (reportTimingFeatures ? 0x10 : 0x00)
00420         | (chimeLogicFeature ? 0x20 : 0x00);
00421     
00422     // write the free heap space
00423     put(12, freeHeapBytes);
00424 
00425     // send the report
00426     report.length = reportLen;
00427     return sendTO(&report, 100);
00428 }
00429 
00430 // report physical button status
00431 bool USBJoystick::reportButtonStatus(int numButtons, const uint8_t *state)
00432 {
00433     // initially fill the report with zeros
00434     HID_REPORT report;
00435     memset(report.data, 0, sizeof(report.data));
00436     
00437     // set the special status bits to indicate that it's a buton report
00438     uint16_t s = 0xA100;
00439     put(0, s);
00440     
00441     // write the number of buttons
00442     report.data[2] = uint8_t(numButtons);
00443     
00444     // Write the buttons - these are packed into ceil(numButtons/8) bytes.
00445     size_t btnBytes = (numButtons+7)/8;
00446     if (btnBytes + 3 > reportLen) btnBytes = reportLen - 3;
00447     memcpy(&report.data[3], state, btnBytes);
00448     
00449     // send the report
00450     report.length = reportLen;
00451     return sendTO(&report, 100);
00452 }
00453 
00454 // report raw IR timing codes (for learning mode)
00455 bool USBJoystick::reportRawIR(int n, const uint16_t *data)
00456 {
00457     // initially fill the report with zeros
00458     HID_REPORT report;
00459     memset(report.data, 0, sizeof(report.data));
00460     
00461     // set the special status bits to indicate that it's an IR report
00462     uint16_t s = 0xA200;
00463     put(0, s);
00464     
00465     // limit the number of items reported to the available space
00466     if (n > maxRawIR)
00467         n = maxRawIR;
00468     
00469     // write the number of codes
00470     report.data[2] = uint8_t(n);
00471     
00472     // write the codes
00473     for (int i = 0, ofs = 3 ; i < n ; ++i, ofs += 2)
00474         put(ofs, data[i]);
00475     
00476     // send the report
00477     report.length = reportLen;
00478     return sendTO(&report, 100);
00479 }
00480 
00481 // report a decoded IR command
00482 bool USBJoystick::reportIRCode(uint8_t pro, uint8_t flags, uint64_t code)
00483 {
00484     // initially fill the report with zeros
00485     HID_REPORT report;
00486     memset(report.data, 0, sizeof(report.data));
00487     
00488     // set the special status bits to indicate that it's an IR report
00489     uint16_t s = 0xA200;
00490     put(0, s);
00491     
00492     // set the raw count to 0xFF to flag that it's a decoded command
00493     report.data[2] = 0xFF;
00494     
00495     // write the data
00496     report.data[3] = pro;
00497     report.data[4] = flags;
00498     put64(5, code);
00499         
00500     // send the report
00501     report.length = reportLen;
00502     return sendTO(&report, 100);
00503 }
00504 
00505 bool USBJoystick::move(int16_t x, int16_t y) 
00506 {
00507      _x = x;
00508      _y = y;
00509      return update();
00510 }
00511 
00512 bool USBJoystick::setZ(int16_t z) 
00513 {
00514     _z = z;
00515     return update();
00516 }
00517  
00518 bool USBJoystick::buttons(uint32_t buttons) 
00519 {
00520      _buttonsLo = (uint16_t)(buttons & 0xffff);
00521      _buttonsHi = (uint16_t)((buttons >> 16) & 0xffff);
00522      return update();
00523 }
00524 
00525 bool USBJoystick::updateStatus(uint32_t status)
00526 {
00527    HID_REPORT report;
00528 
00529    // Fill the report according to the Joystick Descriptor
00530    memset(report.data, 0, reportLen);
00531    put(0, status);
00532    report.length = reportLen;
00533  
00534    // send the report
00535    return sendTO(&report, 100);
00536 }
00537 
00538 void USBJoystick::_init() {
00539  
00540    _x = 0;                       
00541    _y = 0;     
00542    _z = 0;
00543    _buttonsLo = 0x0000;
00544    _buttonsHi = 0x0000;
00545    _status = 0;
00546 }
00547  
00548  
00549 // --------------------------------------------------------------------------
00550 //
00551 // USB HID Report Descriptor - Joystick
00552 //
00553 static const uint8_t reportDescriptorJS[] = 
00554 {         
00555     USAGE_PAGE(1), 0x01,            // Generic desktop
00556     USAGE(1), 0x04,                 // Joystick
00557     COLLECTION(1), 0x01,            // Application
00558     
00559         // input report (device to host)
00560         USAGE_PAGE(1), 0x06,        // generic device controls - for config status
00561         USAGE(1), 0x00,             // undefined device control
00562         LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
00563         LOGICAL_MAXIMUM(1), 0xFF,
00564         REPORT_SIZE(1), 0x08,       // 8 bits per report
00565         REPORT_COUNT(1), 0x04,      // 4 reports (4 bytes)
00566         INPUT(1), 0x02,             // Data, Variable, Absolute
00567 
00568         USAGE_PAGE(1), 0x09,        // Buttons
00569         USAGE_MINIMUM(1), 0x01,     // { buttons }
00570         USAGE_MAXIMUM(1), 0x20,     // {  1-32   }
00571         LOGICAL_MINIMUM(1), 0x00,   // 1-bit buttons - 0...
00572         LOGICAL_MAXIMUM(1), 0x01,   // ...to 1
00573         REPORT_SIZE(1), 0x01,       // 1 bit per report
00574         REPORT_COUNT(1), 0x20,      // 32 reports
00575         UNIT_EXPONENT(1), 0x00,     // Unit_Exponent (0)
00576         UNIT(1), 0x00,              // Unit (None)                                           
00577         INPUT(1), 0x02,             // Data, Variable, Absolute
00578        
00579         USAGE_PAGE(1), 0x01,        // Generic desktop
00580         USAGE(1), 0x30,             // X axis
00581         USAGE(1), 0x31,             // Y axis
00582         USAGE(1), 0x32,             // Z axis
00583         LOGICAL_MINIMUM(2), 0x00,0xF0,   // each value ranges -4096
00584         LOGICAL_MAXIMUM(2), 0x00,0x10,   // ...to +4096
00585         REPORT_SIZE(1), 0x10,       // 16 bits per report
00586         REPORT_COUNT(1), 0x03,      // 3 reports (X, Y, Z)
00587         INPUT(1), 0x02,             // Data, Variable, Absolute
00588          
00589         // output report (host to device)
00590         REPORT_SIZE(1), 0x08,       // 8 bits per report
00591         REPORT_COUNT(1), 0x08,      // output report count - 8-byte LedWiz format
00592         0x09, 0x01,                 // usage
00593         0x91, 0x01,                 // Output (array)
00594 
00595     END_COLLECTION(0)
00596 };
00597 
00598 // Joystick report descriptor with "R" axis reports.  This version
00599 // uses Rx and Ry for the accelerometer readings and Rz for the
00600 // plunger, instead of the standard X/Y/Z axes.  This can be used
00601 // to avoid conflicts with other devices reporting on the normal
00602 // X/Y/Z axes.
00603 static const uint8_t reportDescriptorJS_RXRYRZ[] = 
00604 {         
00605     USAGE_PAGE(1), 0x01,            // Generic desktop
00606     USAGE(1), 0x04,                 // Joystick
00607     COLLECTION(1), 0x01,            // Application
00608     
00609         // input report (device to host)
00610         USAGE_PAGE(1), 0x06,        // generic device controls - for config status
00611         USAGE(1), 0x00,             // undefined device control
00612         LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
00613         LOGICAL_MAXIMUM(1), 0xFF,
00614         REPORT_SIZE(1), 0x08,       // 8 bits per report
00615         REPORT_COUNT(1), 0x04,      // 4 reports (4 bytes)
00616         INPUT(1), 0x02,             // Data, Variable, Absolute
00617 
00618         USAGE_PAGE(1), 0x09,        // Buttons
00619         USAGE_MINIMUM(1), 0x01,     // { buttons }
00620         USAGE_MAXIMUM(1), 0x20,     // {  1-32   }
00621         LOGICAL_MINIMUM(1), 0x00,   // 1-bit buttons - 0...
00622         LOGICAL_MAXIMUM(1), 0x01,   // ...to 1
00623         REPORT_SIZE(1), 0x01,       // 1 bit per report
00624         REPORT_COUNT(1), 0x20,      // 32 reports
00625         UNIT_EXPONENT(1), 0x00,     // Unit_Exponent (0)
00626         UNIT(1), 0x00,              // Unit (None)                                           
00627         INPUT(1), 0x02,             // Data, Variable, Absolute
00628        
00629         USAGE_PAGE(1), 0x01,        // Generic desktop
00630         USAGE(1), 0x33,             // Rx axis ("X rotation")
00631         USAGE(1), 0x34,             // Ry axis
00632         USAGE(1), 0x35,             // Rz axis
00633         LOGICAL_MINIMUM(2), 0x00,0xF0,   // each value ranges -4096
00634         LOGICAL_MAXIMUM(2), 0x00,0x10,   // ...to +4096
00635         REPORT_SIZE(1), 0x10,       // 16 bits per report
00636         REPORT_COUNT(1), 0x03,      // 3 reports (X, Y, Z)
00637         INPUT(1), 0x02,             // Data, Variable, Absolute
00638          
00639         // output report (host to device)
00640         REPORT_SIZE(1), 0x08,       // 8 bits per report
00641         REPORT_COUNT(1), 0x08,      // output report count - 8-byte LedWiz format
00642         0x09, 0x01,                 // usage
00643         0x91, 0x01,                 // Output (array)
00644 
00645     END_COLLECTION(0)
00646 };
00647 
00648 
00649 // 
00650 // USB HID Report Descriptor - Keyboard/Media Control
00651 //
00652 static const uint8_t reportDescriptorKB[] = 
00653 {
00654     USAGE_PAGE(1), 0x01,                    // Generic Desktop
00655     USAGE(1), 0x06,                         // Keyboard
00656     COLLECTION(1), 0x01,                    // Application
00657         REPORT_ID(1), REPORT_ID_KB,
00658 
00659         USAGE_PAGE(1), 0x07,                    // Key Codes
00660         USAGE_MINIMUM(1), 0xE0,
00661         USAGE_MAXIMUM(1), 0xE7,
00662         LOGICAL_MINIMUM(1), 0x00,
00663         LOGICAL_MAXIMUM(1), 0x01,
00664         REPORT_SIZE(1), 0x01,
00665         REPORT_COUNT(1), 0x08,
00666         INPUT(1), 0x02,                         // Data, Variable, Absolute
00667         REPORT_COUNT(1), 0x01,
00668         REPORT_SIZE(1), 0x08,
00669         INPUT(1), 0x01,                         // Constant
00670 
00671         REPORT_COUNT(1), 0x05,
00672         REPORT_SIZE(1), 0x01,
00673         USAGE_PAGE(1), 0x08,                    // LEDs
00674         USAGE_MINIMUM(1), 0x01,
00675         USAGE_MAXIMUM(1), 0x05,
00676         OUTPUT(1), 0x02,                        // Data, Variable, Absolute
00677         REPORT_COUNT(1), 0x01,
00678         REPORT_SIZE(1), 0x03,
00679         OUTPUT(1), 0x01,                        // Constant
00680 
00681         REPORT_COUNT(1), 0x06,
00682         REPORT_SIZE(1), 0x08,
00683         LOGICAL_MINIMUM(1), 0x00,
00684         LOGICAL_MAXIMUM(1), 0xA4,
00685         USAGE_PAGE(1), 0x07,                    // Key Codes
00686         USAGE_MINIMUM(1), 0x00,
00687         USAGE_MAXIMUM(1), 0xA4,
00688         INPUT(1), 0x00,                         // Data, Array
00689     END_COLLECTION(0),
00690 
00691     // Media Control
00692     USAGE_PAGE(1), 0x0C,
00693     USAGE(1), 0x01,
00694     COLLECTION(1), 0x01,
00695         REPORT_ID(1), REPORT_ID_MEDIA,
00696         USAGE_PAGE(1), 0x0C,
00697         LOGICAL_MINIMUM(1), 0x00,
00698         LOGICAL_MAXIMUM(1), 0x01,
00699         REPORT_SIZE(1), 0x01,
00700         REPORT_COUNT(1), 0x07,
00701         USAGE(1), 0xE2,             // Mute -> 0x01
00702         USAGE(1), 0xE9,             // Volume Up -> 0x02
00703         USAGE(1), 0xEA,             // Volume Down -> 0x04
00704         USAGE(1), 0xB5,             // Next Track -> 0x08
00705         USAGE(1), 0xB6,             // Previous Track -> 0x10
00706         USAGE(1), 0xB7,             // Stop -> 0x20
00707         USAGE(1), 0xCD,             // Play / Pause -> 0x40
00708         INPUT(1), 0x02,             // Input (Data, Variable, Absolute) -> 0x80
00709         REPORT_COUNT(1), 0x01,
00710         INPUT(1), 0x01,
00711     END_COLLECTION(0),
00712 };
00713 
00714 // 
00715 // USB HID Report Descriptor - LedWiz only, with no joystick or keyboard
00716 // input reporting
00717 //
00718 static const uint8_t reportDescriptorLW[] = 
00719 {         
00720     USAGE_PAGE(1), 0x01,            // Generic desktop
00721     USAGE(1), 0x00,                 // Undefined
00722 
00723     COLLECTION(1), 0x01,            // Application
00724      
00725         // input report (device to host)
00726         USAGE_PAGE(1), 0x06,        // generic device controls - for config status
00727         USAGE(1), 0x00,             // undefined device control
00728         LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
00729         LOGICAL_MAXIMUM(1), 0xFF,
00730         REPORT_SIZE(1), 0x08,       // 8 bits per report
00731         REPORT_COUNT(1), USBJoystick::reportLen, // standard report length (same as if we were in joystick mode)
00732         INPUT(1), 0x02,             // Data, Variable, Absolute
00733 
00734         // output report (host to device)
00735         REPORT_SIZE(1), 0x08,       // 8 bits per report
00736         REPORT_COUNT(1), 0x08,      // output report count (LEDWiz messages)
00737         0x09, 0x01,                 // usage
00738         0x91, 0x01,                 // Output (array)
00739 
00740     END_COLLECTION(0)
00741 };
00742 
00743 
00744 const uint8_t *USBJoystick::reportDesc(int idx, uint16_t &len) 
00745 {    
00746     switch (idx)
00747     {
00748     case 0:
00749         // If the joystick is enabled, this is the joystick.
00750         // Otherwise, it's the plain LedWiz control interface.
00751         if (enableJoystick)
00752         {
00753             switch (axisFormat)
00754             {
00755             case AXIS_FORMAT_XYZ:
00756             default:
00757                 len = sizeof(reportDescriptorJS);
00758                 return reportDescriptorJS;
00759                 
00760             case AXIS_FORMAT_RXRYRZ:
00761                 len = sizeof(reportDescriptorJS_RXRYRZ);
00762                 return reportDescriptorJS_RXRYRZ;
00763             }
00764         }
00765         else
00766         {
00767             len = sizeof(reportDescriptorLW);
00768             return reportDescriptorLW;
00769         }
00770         
00771     case 1:
00772         // This is the keyboard, if enabled.
00773         if (useKB)
00774         {
00775             len = sizeof(reportDescriptorKB);
00776             return reportDescriptorKB;
00777         }
00778         else
00779         {
00780             len = 0;
00781             return 0;
00782         }
00783         
00784     default:
00785         // Unknown interface ID
00786         len = 0;
00787         return 0;
00788     }
00789 } 
00790  
00791  const uint8_t *USBJoystick::stringImanufacturerDesc() {
00792     static const uint8_t stringImanufacturerDescriptor[] = {
00793         0x0E,                                            /* bLength */
00794         STRING_DESCRIPTOR,                               /* bDescriptorType 0x03 (String Descriptor) */
00795         'm',0,'j',0,'r',0,'n',0,'e',0,'t',0              /* bString iManufacturer - mjrnet */
00796     };
00797     return stringImanufacturerDescriptor;
00798 }
00799 
00800 const uint8_t *USBJoystick::stringIserialDesc() 
00801 {
00802     // set up a buffer with space for the length prefix byte, descriptor type
00803     // byte, and serial number (as a wide-character string)
00804     const int numChars = 3 + 16 + 1 + 1 + 3;
00805     static uint8_t buf[2 + numChars*2];
00806     uint8_t *dst = buf;
00807     
00808     // store a placeholder for the length, followed by the descriptor type byte
00809     *dst++ = 0;
00810     *dst++ = STRING_DESCRIPTOR;
00811 
00812     // Create an ASCII version of our unique serial number string:
00813     //
00814     //   PSCxxxxxxxxxxxxxxxxi[a]vvv
00815     //
00816     // where:
00817     //   
00818     //   xxx... = decimal representation of low 64 bits of CPU ID (16 hex digits)
00819     //   i      = interface type:  first character is J if joystick is enabled,
00820     //             L = LedWiz/control interface only, no input
00821     //             J = Joystick + LedWiz
00822     //             K = Keyboard + LedWiz
00823     //             C = Joystick + Keyboard + LedWiz ("C" for combo)
00824     //   a      = joystick axis types:
00825     //             <empty> = X,Y,Z, or no joystick interface at all
00826     //             A       = Rx,Ry,Rz
00827     //   vvv    = version suffix
00828     //
00829     // The suffix for the interface type resolves a problem on some Windows systems
00830     // when switching between interface types.  Windows can cache device information
00831     // that includes the interface descriptors, and it won't recognize a change in
00832     // the interfaces once the information is cached, causing connection failures.
00833     // The cache key includes the device serial number, though, so this can be 
00834     // resolved by changing the serial number when the interface setup changes.
00835     char xbuf[numChars + 1];
00836     uint32_t x = SIM->UIDML;
00837     static char ifcCode[] = "LJKC";
00838     static const char *axisCode[] = { "", "A" };
00839     sprintf(xbuf, "PSC%08lX%08lX%c%s008",
00840         SIM->UIDML, 
00841         SIM->UIDL, 
00842         ifcCode[(enableJoystick ? 0x01 : 0x00) | (useKB ? 0x02 : 0x00)],
00843         axisCode[(enableJoystick ? axisFormat : 0)]);
00844 
00845     // copy the ascii bytes into the descriptor buffer, converting to unicode
00846     // 16-bit little-endian characters
00847     for (char *src = xbuf ; *src != '\0' && dst < buf + sizeof(buf) ; )
00848     {
00849         *dst++ = *src++;
00850         *dst++ = '\0';
00851     }
00852     
00853     // store the final length (in bytes) in the length prefix byte
00854     buf[0] = dst - buf;
00855     
00856     // return the buffer    
00857     return buf;
00858 }
00859 
00860 const uint8_t *USBJoystick::stringIproductDesc() {
00861     static const uint8_t stringIproductDescriptor[] = {
00862         0x28,                                                       /*bLength*/
00863         STRING_DESCRIPTOR,                                          /*bDescriptorType 0x03*/
00864         'P',0,'i',0,'n',0,'s',0,'c',0,'a',0,'p',0,'e',0,
00865         ' ',0,'C',0,'o',0,'n',0,'t',0,'r',0,'o',0,'l',0,
00866         'l',0,'e',0,'r',0                                           /*String iProduct */
00867     };
00868     return stringIproductDescriptor;
00869 }
00870 
00871 #define DEFAULT_CONFIGURATION (1)
00872 
00873 const uint8_t *USBJoystick::configurationDesc() 
00874 {
00875     int rptlen0 = reportDescLength(0);
00876     int rptlen1 = reportDescLength(1);
00877     if (useKB)
00878     {
00879         const int cfglenKB = 
00880             ((1 * CONFIGURATION_DESCRIPTOR_LENGTH)
00881              + (2 * INTERFACE_DESCRIPTOR_LENGTH)
00882              + (2 * HID_DESCRIPTOR_LENGTH)
00883              + (4 * ENDPOINT_DESCRIPTOR_LENGTH));
00884         static uint8_t configurationDescriptorWithKB[] = 
00885         {
00886             CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
00887             CONFIGURATION_DESCRIPTOR,       // bDescriptorType
00888             LSB(cfglenKB),                  // wTotalLength (LSB)
00889             MSB(cfglenKB),                  // wTotalLength (MSB)
00890             0x02,                           // bNumInterfaces - TWO INTERFACES (JOYSTICK + KEYBOARD)
00891             DEFAULT_CONFIGURATION,          // bConfigurationValue
00892             0x00,                           // iConfiguration
00893             C_RESERVED | C_SELF_POWERED,    // bmAttributes
00894             C_POWER(0),                     // bMaxPower
00895         
00896             // ***** INTERFACE 0 - JOYSTICK/LEDWIZ ******
00897             INTERFACE_DESCRIPTOR_LENGTH,    // bLength
00898             INTERFACE_DESCRIPTOR,           // bDescriptorType
00899             0x00,                           // bInterfaceNumber
00900             0x00,                           // bAlternateSetting
00901             0x02,                           // bNumEndpoints
00902             HID_CLASS,                      // bInterfaceClass
00903             HID_SUBCLASS_NONE,              // bInterfaceSubClass
00904             HID_PROTOCOL_NONE,              // bInterfaceProtocol
00905             0x00,                           // iInterface
00906         
00907             HID_DESCRIPTOR_LENGTH,          // bLength
00908             HID_DESCRIPTOR,                 // bDescriptorType
00909             LSB(HID_VERSION_1_11),          // bcdHID (LSB)
00910             MSB(HID_VERSION_1_11),          // bcdHID (MSB)
00911             0x00,                           // bCountryCode
00912             0x01,                           // bNumDescriptors
00913             REPORT_DESCRIPTOR,              // bDescriptorType
00914             LSB(rptlen0),                   // wDescriptorLength (LSB)
00915             MSB(rptlen0),                   // wDescriptorLength (MSB)
00916         
00917             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00918             ENDPOINT_DESCRIPTOR,            // bDescriptorType
00919             PHY_TO_DESC(EPINT_IN),          // bEndpointAddress - EPINT == EP1
00920             E_INTERRUPT,                    // bmAttributes
00921             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00922             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00923             1,                              // bInterval (milliseconds)
00924         
00925             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00926             ENDPOINT_DESCRIPTOR,            // bDescriptorType
00927             PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress - EPINT == EP1
00928             E_INTERRUPT,                    // bmAttributes
00929             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00930             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00931             1,                              // bInterval (milliseconds)
00932             
00933             // ****** INTERFACE 1 - KEYBOARD ******
00934             INTERFACE_DESCRIPTOR_LENGTH,    // bLength
00935             INTERFACE_DESCRIPTOR,           // bDescriptorType
00936             0x01,                           // bInterfaceNumber
00937             0x00,                           // bAlternateSetting
00938             0x02,                           // bNumEndpoints
00939             HID_CLASS,                      // bInterfaceClass
00940             HID_SUBCLASS_BOOT,              // bInterfaceSubClass
00941             HID_PROTOCOL_KB,                // bInterfaceProtocol
00942             0x00,                           // iInterface
00943         
00944             HID_DESCRIPTOR_LENGTH,          // bLength
00945             HID_DESCRIPTOR,                 // bDescriptorType
00946             LSB(HID_VERSION_1_11),          // bcdHID (LSB)
00947             MSB(HID_VERSION_1_11),          // bcdHID (MSB)
00948             0x00,                           // bCountryCode
00949             0x01,                           // bNumDescriptors
00950             REPORT_DESCRIPTOR,              // bDescriptorType
00951             LSB(rptlen1),                   // wDescriptorLength (LSB)
00952             MSB(rptlen1),                   // wDescriptorLength (MSB)
00953         
00954             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00955             ENDPOINT_DESCRIPTOR,            // bDescriptorType
00956             PHY_TO_DESC(EP4IN),             // bEndpointAddress
00957             E_INTERRUPT,                    // bmAttributes
00958             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00959             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00960             1,                              // bInterval (milliseconds)
00961         
00962             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00963             ENDPOINT_DESCRIPTOR,            // bDescriptorType
00964             PHY_TO_DESC(EP4OUT),            // bEndpointAddress
00965             E_INTERRUPT,                    // bmAttributes
00966             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00967             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00968             1,                              // bInterval (milliseconds)
00969 
00970         };
00971 
00972         // Keyboard + joystick interfaces
00973         return configurationDescriptorWithKB;
00974     }
00975     else
00976     {
00977         // No keyboard - joystick interface only
00978         const int cfglenNoKB = 
00979             ((1 * CONFIGURATION_DESCRIPTOR_LENGTH)
00980               + (1 * INTERFACE_DESCRIPTOR_LENGTH)
00981               + (1 * HID_DESCRIPTOR_LENGTH)
00982               + (2 * ENDPOINT_DESCRIPTOR_LENGTH));
00983         static uint8_t configurationDescriptorNoKB[] = 
00984         {
00985             CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
00986             CONFIGURATION_DESCRIPTOR,       // bDescriptorType
00987             LSB(cfglenNoKB),                // wTotalLength (LSB)
00988             MSB(cfglenNoKB),                // wTotalLength (MSB)
00989             0x01,                           // bNumInterfaces
00990             DEFAULT_CONFIGURATION,          // bConfigurationValue
00991             0x00,                           // iConfiguration
00992             C_RESERVED | C_SELF_POWERED,    // bmAttributes
00993             C_POWER(0),                     // bMaxPower
00994         
00995             INTERFACE_DESCRIPTOR_LENGTH,    // bLength
00996             INTERFACE_DESCRIPTOR,           // bDescriptorType
00997             0x00,                           // bInterfaceNumber
00998             0x00,                           // bAlternateSetting
00999             0x02,                           // bNumEndpoints
01000             HID_CLASS,                      // bInterfaceClass
01001             HID_SUBCLASS_NONE,              // bInterfaceSubClass
01002             HID_PROTOCOL_NONE,              // bInterfaceProtocol (keyboard)
01003             0x00,                           // iInterface
01004         
01005             HID_DESCRIPTOR_LENGTH,          // bLength
01006             HID_DESCRIPTOR,                 // bDescriptorType
01007             LSB(HID_VERSION_1_11),          // bcdHID (LSB)
01008             MSB(HID_VERSION_1_11),          // bcdHID (MSB)
01009             0x00,                           // bCountryCode
01010             0x01,                           // bNumDescriptors
01011             REPORT_DESCRIPTOR,              // bDescriptorType
01012             (uint8_t)(LSB(rptlen0)),        // wDescriptorLength (LSB)
01013             (uint8_t)(MSB(rptlen0)),        // wDescriptorLength (MSB)
01014         
01015             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
01016             ENDPOINT_DESCRIPTOR,            // bDescriptorType
01017             PHY_TO_DESC(EPINT_IN),          // bEndpointAddress
01018             E_INTERRUPT,                    // bmAttributes
01019             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
01020             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
01021             1,                              // bInterval (milliseconds)
01022         
01023             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
01024             ENDPOINT_DESCRIPTOR,            // bDescriptorType
01025             PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress
01026             E_INTERRUPT,                    // bmAttributes
01027             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
01028             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
01029             1                               // bInterval (milliseconds)
01030         };
01031 
01032         return configurationDescriptorNoKB;
01033     }
01034 }
01035 
01036 // Set the configuration.  We need to set up the endpoints for
01037 // our active interfaces.
01038 bool USBJoystick::USBCallback_setConfiguration(uint8_t configuration) 
01039 {
01040     // we only have one valid configuration
01041     if (configuration != DEFAULT_CONFIGURATION)
01042         return false;
01043         
01044     // Configure endpoint 1 - we use this in all cases, for either
01045     // the combined joystick/ledwiz interface or just the ledwiz interface
01046     addEndpoint(EPINT_IN, MAX_REPORT_JS_TX + 1);
01047     addEndpoint(EPINT_OUT, MAX_REPORT_JS_RX + 1);
01048     readStart(EPINT_OUT, MAX_REPORT_JS_TX + 1);
01049     
01050     // if the keyboard is enabled, configure endpoint 4 for the kb interface
01051     if (useKB)
01052     {
01053         addEndpoint(EP4IN, MAX_REPORT_KB_TX + 1);
01054         addEndpoint(EP4OUT, MAX_REPORT_KB_RX + 1);
01055         readStart(EP4OUT, MAX_REPORT_KB_TX + 1);
01056     }
01057 
01058     // success
01059     return true;
01060 }
01061 
01062 // Handle incoming messages on the joystick/LedWiz interface = endpoint 1.
01063 // This interface receives LedWiz protocol commands and commands using our
01064 // custom LedWiz protocol extensions.
01065 //
01066 // We simply queue the messages in our circular buffer for processing in 
01067 // the main loop.  The circular buffer object is designed for safe access
01068 // from the interrupt handler using the rule that only the interrupt 
01069 // handler can change the write pointer, and only the regular code can
01070 // change the read pointer.
01071 bool USBJoystick::EP1_OUT_callback()
01072 {
01073     // Read this message
01074     union {
01075         LedWizMsg msg;
01076         uint8_t buf[MAX_HID_REPORT_SIZE];
01077     } buf;
01078     uint32_t bytesRead = 0;
01079     USBDevice::readEP(EP1OUT, buf.buf, &bytesRead, MAX_HID_REPORT_SIZE);
01080     
01081     // if it's the right length, queue it to our circular buffer
01082     if (bytesRead == 8)
01083         lwbuf.write(buf.msg);
01084 
01085     // start the next read
01086     return readStart(EP1OUT, MAX_HID_REPORT_SIZE);
01087 }
01088 
01089 // Handle incoming messages on the keyboard interface = endpoint 4.
01090 // The host uses this to send updates for the keyboard indicator LEDs
01091 // (caps lock, num lock, etc).  We don't do anything with these, but
01092 // we have to read them to keep the pipe open.
01093 bool USBJoystick::EP4_OUT_callback() 
01094 {
01095     // read this message
01096     uint32_t bytesRead = 0;
01097     uint8_t led[MAX_HID_REPORT_SIZE];
01098     USBDevice::readEP(EP4OUT, led, &bytesRead, MAX_HID_REPORT_SIZE);
01099 
01100     // start the next read
01101     return readStart(EP4OUT, MAX_HID_REPORT_SIZE);
01102 }
01103