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 bool USBJoystick::sendPlungerStatusVCNL4010(int filteredProxCount, int rawProxCount)
00255 {
00256     HID_REPORT report;
00257     memset(report.data, 0, sizeof(report.data));
00258     
00259     // set the status bits to indicate that it's an extended
00260     // status report for quadrature sensors
00261     put(0, 0x87FF);
00262     int ofs = 2;
00263     
00264     // write the report subtype (4)
00265     report.data[ofs++] = 4;
00266     
00267     // write the filtered and raw proximity count from the sensor
00268     put(ofs, static_cast<uint16_t>(filteredProxCount));
00269     put(ofs + 2, static_cast<uint16_t>(rawProxCount));
00270     
00271     // send the report
00272     report.length = reportLen;
00273     return sendTO(&report, 100);
00274 }
00275 
00276 
00277 bool USBJoystick::sendPlungerPix(int &idx, int npix, const uint8_t *pix)
00278 {
00279     HID_REPORT report;
00280     
00281     // Set the special status bits to indicate it's an exposure report.
00282     // The high 5 bits of the status word are set to 10000, and the
00283     // low 11 bits are the current pixel index.
00284     uint16_t s = idx | 0x8000;
00285     put(0, s);
00286     
00287     // start at the second byte
00288     int ofs = 2;
00289     
00290     // now fill out the remaining bytes with exposure values
00291     report.length = reportLen;
00292     for ( ; ofs < report.length ; ++ofs)
00293         report.data[ofs] = (idx < npix ? pix[idx++] : 0);
00294     
00295     // send the report
00296     return sendTO(&report, 100);
00297 }
00298 
00299 bool USBJoystick::reportID(int index)
00300 {
00301     HID_REPORT report;
00302 
00303     // initially fill the report with zeros
00304     memset(report.data, 0, sizeof(report.data));
00305     
00306     // Set the special status bits to indicate that it's an ID report
00307     uint16_t s = 0x9000;
00308     put(0, s);
00309     
00310     // add the requested ID index
00311     report.data[2] = (uint8_t)index;
00312     
00313     // figure out which ID we're reporting
00314     switch (index)
00315     {
00316     case 1:
00317         // KL25Z CPU ID
00318         putbe(3, SIM->UIDMH);
00319         putlbe(5, SIM->UIDML);
00320         putlbe(9, SIM->UIDL);
00321         break;
00322         
00323     case 2:
00324         // OpenSDA ID.  Copy the low-order 80 bits of the OpenSDA ID.
00325         // (The stored value is 128 bits = 16 bytes; we only want the last
00326         // 80 bits = 10 bytes.  So skip ahead 16 and back up 10 to get
00327         // the starting point.)
00328         extern const char *getOpenSDAID();
00329         memcpy(&report.data[3], getOpenSDAID() + 16 - 10, 10);
00330         break;
00331     }
00332     
00333     // send the report
00334     report.length = reportLen;
00335     return sendTO(&report, 100);
00336 }
00337 
00338 bool USBJoystick::reportBuildInfo(const char *date)
00339 {
00340     HID_REPORT report;
00341 
00342     // initially fill the report with zeros
00343     memset(report.data, 0, sizeof(report.data));
00344     
00345     // Set the special status bits to indicate that it's a build
00346     // info report
00347     uint16_t s = 0xA000;
00348     put(0, s);
00349     
00350     // Parse the date.  This is given in the standard __DATE__ " " __TIME
00351     // macro format, "Mon dd yyyy hh:mm:ss" (e.g., "Feb 16 2016 12:15:06").
00352     static const char mon[][4] = {
00353         "Jan", "Feb", "Mar", "Apr", "May", "Jun", 
00354         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 
00355     };
00356     long dd = (atol(date + 7) * 10000L) // YYYY0000
00357         + (atol(date + 4));             // 000000DD
00358     for (int i = 0 ; i < 12 ; ++i)
00359     {
00360         if (memcmp(mon[i], date, 3) == 0)
00361         {
00362             dd += (i+1)*100;         // 0000MM00
00363             break;
00364         }
00365     }
00366     
00367     // parse the time into a long formatted as decimal HHMMSS (e.g.,
00368     // "12:15:06" turns into 121506 decimal)
00369     long tt = (atol(date+12)*10000)
00370         + (atol(date+15)*100)
00371         + (atol(date+18));
00372     
00373     // store the build date and time
00374     putl(2, dd);
00375     putl(6, tt);
00376     
00377     // send the report
00378     report.length = reportLen;
00379     return sendTO(&report, 100);
00380 }
00381 
00382 bool USBJoystick::reportConfigVar(const uint8_t *data)
00383 {
00384     HID_REPORT report;
00385 
00386     // initially fill the report with zeros
00387     memset(report.data, 0, sizeof(report.data));
00388     
00389     // Set the special status bits to indicate that it's a config 
00390     // variable report
00391     uint16_t s = 0x9800;
00392     put(0, s);
00393     
00394     // Copy the variable data (7 bytes, starting with the variable ID)
00395     memcpy(report.data + 2, data, 7);
00396     
00397     // send the report
00398     report.length = reportLen;
00399     return sendTO(&report, 100);
00400 }
00401 
00402 bool USBJoystick::reportConfig(
00403     int numOutputs, int unitNo, 
00404     int plungerZero, int plungerMax, int plungerRlsTime,
00405     bool configured, bool sbxpbx, bool newAccelFeatures, 
00406     bool flashStatusFeature, bool reportTimingFeatures,
00407     bool chimeLogicFeature, size_t freeHeapBytes)
00408 {
00409     HID_REPORT report;
00410 
00411     // initially fill the report with zeros
00412     memset(report.data, 0, sizeof(report.data));
00413     
00414     // Set the special status bits to indicate that it's a config report.
00415     uint16_t s = 0x8800;
00416     put(0, s);
00417     
00418     // write the number of configured outputs
00419     put(2, numOutputs);
00420     
00421     // write the unit number
00422     put(4, unitNo);
00423     
00424     // write the plunger zero and max values
00425     put(6, plungerZero);
00426     put(8, plungerMax);
00427     report.data[10] = uint8_t(plungerRlsTime);
00428     
00429     // write the status bits: 
00430     //  0x01  -> configuration loaded
00431     //  0x02  -> SBX/PBX protocol extensions supported
00432     //  0x04  -> new accelerometer features supported
00433     //  0x08  -> flash status feature supported
00434     //  0x10  -> joystick report timing features supported
00435     //  0x20  -> chime logic feature supported
00436     report.data[11] = 
00437         (configured ? 0x01 : 0x00)
00438         | (sbxpbx ? 0x02 : 0x00)
00439         | (newAccelFeatures ? 0x04 : 0x00)
00440         | (flashStatusFeature ? 0x08 : 0x00)
00441         | (reportTimingFeatures ? 0x10 : 0x00)
00442         | (chimeLogicFeature ? 0x20 : 0x00);
00443     
00444     // write the free heap space
00445     put(12, freeHeapBytes);
00446 
00447     // send the report
00448     report.length = reportLen;
00449     return sendTO(&report, 100);
00450 }
00451 
00452 // report physical button status
00453 bool USBJoystick::reportButtonStatus(int numButtons, const uint8_t *state)
00454 {
00455     // initially fill the report with zeros
00456     HID_REPORT report;
00457     memset(report.data, 0, sizeof(report.data));
00458     
00459     // set the special status bits to indicate that it's a buton report
00460     uint16_t s = 0xA100;
00461     put(0, s);
00462     
00463     // write the number of buttons
00464     report.data[2] = uint8_t(numButtons);
00465     
00466     // Write the buttons - these are packed into ceil(numButtons/8) bytes.
00467     size_t btnBytes = (numButtons+7)/8;
00468     if (btnBytes + 3 > reportLen) btnBytes = reportLen - 3;
00469     memcpy(&report.data[3], state, btnBytes);
00470     
00471     // send the report
00472     report.length = reportLen;
00473     return sendTO(&report, 100);
00474 }
00475 
00476 // report raw IR timing codes (for learning mode)
00477 bool USBJoystick::reportRawIR(int n, const uint16_t *data)
00478 {
00479     // initially fill the report with zeros
00480     HID_REPORT report;
00481     memset(report.data, 0, sizeof(report.data));
00482     
00483     // set the special status bits to indicate that it's an IR report
00484     uint16_t s = 0xA200;
00485     put(0, s);
00486     
00487     // limit the number of items reported to the available space
00488     if (n > maxRawIR)
00489         n = maxRawIR;
00490     
00491     // write the number of codes
00492     report.data[2] = uint8_t(n);
00493     
00494     // write the codes
00495     for (int i = 0, ofs = 3 ; i < n ; ++i, ofs += 2)
00496         put(ofs, data[i]);
00497     
00498     // send the report
00499     report.length = reportLen;
00500     return sendTO(&report, 100);
00501 }
00502 
00503 // report a decoded IR command
00504 bool USBJoystick::reportIRCode(uint8_t pro, uint8_t flags, uint64_t code)
00505 {
00506     // initially fill the report with zeros
00507     HID_REPORT report;
00508     memset(report.data, 0, sizeof(report.data));
00509     
00510     // set the special status bits to indicate that it's an IR report
00511     uint16_t s = 0xA200;
00512     put(0, s);
00513     
00514     // set the raw count to 0xFF to flag that it's a decoded command
00515     report.data[2] = 0xFF;
00516     
00517     // write the data
00518     report.data[3] = pro;
00519     report.data[4] = flags;
00520     put64(5, code);
00521         
00522     // send the report
00523     report.length = reportLen;
00524     return sendTO(&report, 100);
00525 }
00526 
00527 bool USBJoystick::move(int16_t x, int16_t y) 
00528 {
00529      _x = x;
00530      _y = y;
00531      return update();
00532 }
00533 
00534 bool USBJoystick::setZ(int16_t z) 
00535 {
00536     _z = z;
00537     return update();
00538 }
00539  
00540 bool USBJoystick::buttons(uint32_t buttons) 
00541 {
00542      _buttonsLo = (uint16_t)(buttons & 0xffff);
00543      _buttonsHi = (uint16_t)((buttons >> 16) & 0xffff);
00544      return update();
00545 }
00546 
00547 bool USBJoystick::updateStatus(uint32_t status)
00548 {
00549    HID_REPORT report;
00550 
00551    // Fill the report according to the Joystick Descriptor
00552    memset(report.data, 0, reportLen);
00553    put(0, status);
00554    report.length = reportLen;
00555  
00556    // send the report
00557    return sendTO(&report, 100);
00558 }
00559 
00560 void USBJoystick::_init() {
00561  
00562    _x = 0;                       
00563    _y = 0;     
00564    _z = 0;
00565    _buttonsLo = 0x0000;
00566    _buttonsHi = 0x0000;
00567    _status = 0;
00568 }
00569  
00570  
00571 // --------------------------------------------------------------------------
00572 //
00573 // USB HID Report Descriptor - Joystick
00574 //
00575 static const uint8_t reportDescriptorJS[] = 
00576 {         
00577     USAGE_PAGE(1), 0x01,            // Generic desktop
00578     USAGE(1), 0x04,                 // Joystick
00579     COLLECTION(1), 0x01,            // Application
00580     
00581         // input report (device to host)
00582         USAGE_PAGE(1), 0x06,        // generic device controls - for config status
00583         USAGE(1), 0x00,             // undefined device control
00584         LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
00585         LOGICAL_MAXIMUM(1), 0xFF,
00586         REPORT_SIZE(1), 0x08,       // 8 bits per report
00587         REPORT_COUNT(1), 0x04,      // 4 reports (4 bytes)
00588         INPUT(1), 0x02,             // Data, Variable, Absolute
00589 
00590         USAGE_PAGE(1), 0x09,        // Buttons
00591         USAGE_MINIMUM(1), 0x01,     // { buttons }
00592         USAGE_MAXIMUM(1), 0x20,     // {  1-32   }
00593         LOGICAL_MINIMUM(1), 0x00,   // 1-bit buttons - 0...
00594         LOGICAL_MAXIMUM(1), 0x01,   // ...to 1
00595         REPORT_SIZE(1), 0x01,       // 1 bit per report
00596         REPORT_COUNT(1), 0x20,      // 32 reports
00597         UNIT_EXPONENT(1), 0x00,     // Unit_Exponent (0)
00598         UNIT(1), 0x00,              // Unit (None)                                           
00599         INPUT(1), 0x02,             // Data, Variable, Absolute
00600        
00601         USAGE_PAGE(1), 0x01,        // Generic desktop
00602         USAGE(1), 0x30,             // X axis
00603         USAGE(1), 0x31,             // Y axis
00604         USAGE(1), 0x32,             // Z axis
00605         LOGICAL_MINIMUM(2), 0x00,0xF0,   // each value ranges -4096
00606         LOGICAL_MAXIMUM(2), 0x00,0x10,   // ...to +4096
00607         REPORT_SIZE(1), 0x10,       // 16 bits per report
00608         REPORT_COUNT(1), 0x03,      // 3 reports (X, Y, Z)
00609         INPUT(1), 0x02,             // Data, Variable, Absolute
00610          
00611         // output report (host to device)
00612         REPORT_SIZE(1), 0x08,       // 8 bits per report
00613         REPORT_COUNT(1), 0x08,      // output report count - 8-byte LedWiz format
00614         0x09, 0x01,                 // usage
00615         0x91, 0x01,                 // Output (array)
00616 
00617     END_COLLECTION(0)
00618 };
00619 
00620 // Joystick report descriptor with "R" axis reports.  This version
00621 // uses Rx and Ry for the accelerometer readings and Rz for the
00622 // plunger, instead of the standard X/Y/Z axes.  This can be used
00623 // to avoid conflicts with other devices reporting on the normal
00624 // X/Y/Z axes.
00625 static const uint8_t reportDescriptorJS_RXRYRZ[] = 
00626 {         
00627     USAGE_PAGE(1), 0x01,            // Generic desktop
00628     USAGE(1), 0x04,                 // Joystick
00629     COLLECTION(1), 0x01,            // Application
00630     
00631         // input report (device to host)
00632         USAGE_PAGE(1), 0x06,        // generic device controls - for config status
00633         USAGE(1), 0x00,             // undefined device control
00634         LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
00635         LOGICAL_MAXIMUM(1), 0xFF,
00636         REPORT_SIZE(1), 0x08,       // 8 bits per report
00637         REPORT_COUNT(1), 0x04,      // 4 reports (4 bytes)
00638         INPUT(1), 0x02,             // Data, Variable, Absolute
00639 
00640         USAGE_PAGE(1), 0x09,        // Buttons
00641         USAGE_MINIMUM(1), 0x01,     // { buttons }
00642         USAGE_MAXIMUM(1), 0x20,     // {  1-32   }
00643         LOGICAL_MINIMUM(1), 0x00,   // 1-bit buttons - 0...
00644         LOGICAL_MAXIMUM(1), 0x01,   // ...to 1
00645         REPORT_SIZE(1), 0x01,       // 1 bit per report
00646         REPORT_COUNT(1), 0x20,      // 32 reports
00647         UNIT_EXPONENT(1), 0x00,     // Unit_Exponent (0)
00648         UNIT(1), 0x00,              // Unit (None)                                           
00649         INPUT(1), 0x02,             // Data, Variable, Absolute
00650        
00651         USAGE_PAGE(1), 0x01,        // Generic desktop
00652         USAGE(1), 0x33,             // Rx axis ("X rotation")
00653         USAGE(1), 0x34,             // Ry axis
00654         USAGE(1), 0x35,             // Rz axis
00655         LOGICAL_MINIMUM(2), 0x00,0xF0,   // each value ranges -4096
00656         LOGICAL_MAXIMUM(2), 0x00,0x10,   // ...to +4096
00657         REPORT_SIZE(1), 0x10,       // 16 bits per report
00658         REPORT_COUNT(1), 0x03,      // 3 reports (X, Y, Z)
00659         INPUT(1), 0x02,             // Data, Variable, Absolute
00660          
00661         // output report (host to device)
00662         REPORT_SIZE(1), 0x08,       // 8 bits per report
00663         REPORT_COUNT(1), 0x08,      // output report count - 8-byte LedWiz format
00664         0x09, 0x01,                 // usage
00665         0x91, 0x01,                 // Output (array)
00666 
00667     END_COLLECTION(0)
00668 };
00669 
00670 
00671 // 
00672 // USB HID Report Descriptor - Keyboard/Media Control
00673 //
00674 static const uint8_t reportDescriptorKB[] = 
00675 {
00676     USAGE_PAGE(1), 0x01,                    // Generic Desktop
00677     USAGE(1), 0x06,                         // Keyboard
00678     COLLECTION(1), 0x01,                    // Application
00679         REPORT_ID(1), REPORT_ID_KB,
00680 
00681         USAGE_PAGE(1), 0x07,                    // Key Codes
00682         USAGE_MINIMUM(1), 0xE0,
00683         USAGE_MAXIMUM(1), 0xE7,
00684         LOGICAL_MINIMUM(1), 0x00,
00685         LOGICAL_MAXIMUM(1), 0x01,
00686         REPORT_SIZE(1), 0x01,
00687         REPORT_COUNT(1), 0x08,
00688         INPUT(1), 0x02,                         // Data, Variable, Absolute
00689         REPORT_COUNT(1), 0x01,
00690         REPORT_SIZE(1), 0x08,
00691         INPUT(1), 0x01,                         // Constant
00692 
00693         REPORT_COUNT(1), 0x05,
00694         REPORT_SIZE(1), 0x01,
00695         USAGE_PAGE(1), 0x08,                    // LEDs
00696         USAGE_MINIMUM(1), 0x01,
00697         USAGE_MAXIMUM(1), 0x05,
00698         OUTPUT(1), 0x02,                        // Data, Variable, Absolute
00699         REPORT_COUNT(1), 0x01,
00700         REPORT_SIZE(1), 0x03,
00701         OUTPUT(1), 0x01,                        // Constant
00702 
00703         REPORT_COUNT(1), 0x06,
00704         REPORT_SIZE(1), 0x08,
00705         LOGICAL_MINIMUM(1), 0x00,
00706         LOGICAL_MAXIMUM(1), 0xA4,
00707         USAGE_PAGE(1), 0x07,                    // Key Codes
00708         USAGE_MINIMUM(1), 0x00,
00709         USAGE_MAXIMUM(1), 0xA4,
00710         INPUT(1), 0x00,                         // Data, Array
00711     END_COLLECTION(0),
00712 
00713     // Media Control
00714     USAGE_PAGE(1), 0x0C,
00715     USAGE(1), 0x01,
00716     COLLECTION(1), 0x01,
00717         REPORT_ID(1), REPORT_ID_MEDIA,
00718         USAGE_PAGE(1), 0x0C,
00719         LOGICAL_MINIMUM(1), 0x00,
00720         LOGICAL_MAXIMUM(1), 0x01,
00721         REPORT_SIZE(1), 0x01,
00722         REPORT_COUNT(1), 0x07,
00723         USAGE(1), 0xE2,             // Mute -> 0x01
00724         USAGE(1), 0xE9,             // Volume Up -> 0x02
00725         USAGE(1), 0xEA,             // Volume Down -> 0x04
00726         USAGE(1), 0xB5,             // Next Track -> 0x08
00727         USAGE(1), 0xB6,             // Previous Track -> 0x10
00728         USAGE(1), 0xB7,             // Stop -> 0x20
00729         USAGE(1), 0xCD,             // Play / Pause -> 0x40
00730         INPUT(1), 0x02,             // Input (Data, Variable, Absolute) -> 0x80
00731         REPORT_COUNT(1), 0x01,
00732         INPUT(1), 0x01,
00733     END_COLLECTION(0),
00734 };
00735 
00736 // 
00737 // USB HID Report Descriptor - LedWiz only, with no joystick or keyboard
00738 // input reporting
00739 //
00740 static const uint8_t reportDescriptorLW[] = 
00741 {         
00742     USAGE_PAGE(1), 0x01,            // Generic desktop
00743     USAGE(1), 0x00,                 // Undefined
00744 
00745     COLLECTION(1), 0x01,            // Application
00746      
00747         // input report (device to host)
00748         USAGE_PAGE(1), 0x06,        // generic device controls - for config status
00749         USAGE(1), 0x00,             // undefined device control
00750         LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
00751         LOGICAL_MAXIMUM(1), 0xFF,
00752         REPORT_SIZE(1), 0x08,       // 8 bits per report
00753         REPORT_COUNT(1), USBJoystick::reportLen, // standard report length (same as if we were in joystick mode)
00754         INPUT(1), 0x02,             // Data, Variable, Absolute
00755 
00756         // output report (host to device)
00757         REPORT_SIZE(1), 0x08,       // 8 bits per report
00758         REPORT_COUNT(1), 0x08,      // output report count (LEDWiz messages)
00759         0x09, 0x01,                 // usage
00760         0x91, 0x01,                 // Output (array)
00761 
00762     END_COLLECTION(0)
00763 };
00764 
00765 
00766 const uint8_t *USBJoystick::reportDesc(int idx, uint16_t &len) 
00767 {    
00768     switch (idx)
00769     {
00770     case 0:
00771         // If the joystick is enabled, this is the joystick.
00772         // Otherwise, it's the plain LedWiz control interface.
00773         if (enableJoystick)
00774         {
00775             switch (axisFormat)
00776             {
00777             case AXIS_FORMAT_XYZ:
00778             default:
00779                 len = sizeof(reportDescriptorJS);
00780                 return reportDescriptorJS;
00781                 
00782             case AXIS_FORMAT_RXRYRZ:
00783                 len = sizeof(reportDescriptorJS_RXRYRZ);
00784                 return reportDescriptorJS_RXRYRZ;
00785             }
00786         }
00787         else
00788         {
00789             len = sizeof(reportDescriptorLW);
00790             return reportDescriptorLW;
00791         }
00792         
00793     case 1:
00794         // This is the keyboard, if enabled.
00795         if (useKB)
00796         {
00797             len = sizeof(reportDescriptorKB);
00798             return reportDescriptorKB;
00799         }
00800         else
00801         {
00802             len = 0;
00803             return 0;
00804         }
00805         
00806     default:
00807         // Unknown interface ID
00808         len = 0;
00809         return 0;
00810     }
00811 } 
00812  
00813  const uint8_t *USBJoystick::stringImanufacturerDesc() {
00814     static const uint8_t stringImanufacturerDescriptor[] = {
00815         0x0E,                                            /* bLength */
00816         STRING_DESCRIPTOR,                               /* bDescriptorType 0x03 (String Descriptor) */
00817         'm',0,'j',0,'r',0,'n',0,'e',0,'t',0              /* bString iManufacturer - mjrnet */
00818     };
00819     return stringImanufacturerDescriptor;
00820 }
00821 
00822 const uint8_t *USBJoystick::stringIserialDesc() 
00823 {
00824     // set up a buffer with space for the length prefix byte, descriptor type
00825     // byte, and serial number (as a wide-character string)
00826     const int numChars = 3 + 16 + 1 + 1 + 3;
00827     static uint8_t buf[2 + numChars*2];
00828     uint8_t *dst = buf;
00829     
00830     // store a placeholder for the length, followed by the descriptor type byte
00831     *dst++ = 0;
00832     *dst++ = STRING_DESCRIPTOR;
00833 
00834     // Create an ASCII version of our unique serial number string:
00835     //
00836     //   PSCxxxxxxxxxxxxxxxxi[a]vvv
00837     //
00838     // where:
00839     //   
00840     //   xxx... = decimal representation of low 64 bits of CPU ID (16 hex digits)
00841     //   i      = interface type:  first character is J if joystick is enabled,
00842     //             L = LedWiz/control interface only, no input
00843     //             J = Joystick + LedWiz
00844     //             K = Keyboard + LedWiz
00845     //             C = Joystick + Keyboard + LedWiz ("C" for combo)
00846     //   a      = joystick axis types:
00847     //             <empty> = X,Y,Z, or no joystick interface at all
00848     //             A       = Rx,Ry,Rz
00849     //   vvv    = version suffix
00850     //
00851     // The suffix for the interface type resolves a problem on some Windows systems
00852     // when switching between interface types.  Windows can cache device information
00853     // that includes the interface descriptors, and it won't recognize a change in
00854     // the interfaces once the information is cached, causing connection failures.
00855     // The cache key includes the device serial number, though, so this can be 
00856     // resolved by changing the serial number when the interface setup changes.
00857     char xbuf[numChars + 1];
00858     uint32_t x = SIM->UIDML;
00859     static char ifcCode[] = "LJKC";
00860     static const char *axisCode[] = { "", "A" };
00861     sprintf(xbuf, "PSC%08lX%08lX%c%s008",
00862         SIM->UIDML, 
00863         SIM->UIDL, 
00864         ifcCode[(enableJoystick ? 0x01 : 0x00) | (useKB ? 0x02 : 0x00)],
00865         axisCode[(enableJoystick ? axisFormat : 0)]);
00866 
00867     // copy the ascii bytes into the descriptor buffer, converting to unicode
00868     // 16-bit little-endian characters
00869     for (char *src = xbuf ; *src != '\0' && dst < buf + sizeof(buf) ; )
00870     {
00871         *dst++ = *src++;
00872         *dst++ = '\0';
00873     }
00874     
00875     // store the final length (in bytes) in the length prefix byte
00876     buf[0] = dst - buf;
00877     
00878     // return the buffer    
00879     return buf;
00880 }
00881 
00882 const uint8_t *USBJoystick::stringIproductDesc() {
00883     static const uint8_t stringIproductDescriptor[] = {
00884         0x28,                                                       /*bLength*/
00885         STRING_DESCRIPTOR,                                          /*bDescriptorType 0x03*/
00886         'P',0,'i',0,'n',0,'s',0,'c',0,'a',0,'p',0,'e',0,
00887         ' ',0,'C',0,'o',0,'n',0,'t',0,'r',0,'o',0,'l',0,
00888         'l',0,'e',0,'r',0                                           /*String iProduct */
00889     };
00890     return stringIproductDescriptor;
00891 }
00892 
00893 #define DEFAULT_CONFIGURATION (1)
00894 
00895 const uint8_t *USBJoystick::configurationDesc() 
00896 {
00897     int rptlen0 = reportDescLength(0);
00898     int rptlen1 = reportDescLength(1);
00899     if (useKB)
00900     {
00901         const int cfglenKB = 
00902             ((1 * CONFIGURATION_DESCRIPTOR_LENGTH)
00903              + (2 * INTERFACE_DESCRIPTOR_LENGTH)
00904              + (2 * HID_DESCRIPTOR_LENGTH)
00905              + (4 * ENDPOINT_DESCRIPTOR_LENGTH));
00906         static uint8_t configurationDescriptorWithKB[] = 
00907         {
00908             CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
00909             CONFIGURATION_DESCRIPTOR,       // bDescriptorType
00910             LSB(cfglenKB),                  // wTotalLength (LSB)
00911             MSB(cfglenKB),                  // wTotalLength (MSB)
00912             0x02,                           // bNumInterfaces - TWO INTERFACES (JOYSTICK + KEYBOARD)
00913             DEFAULT_CONFIGURATION,          // bConfigurationValue
00914             0x00,                           // iConfiguration
00915             C_RESERVED | C_SELF_POWERED,    // bmAttributes
00916             C_POWER(0),                     // bMaxPower
00917         
00918             // ***** INTERFACE 0 - JOYSTICK/LEDWIZ ******
00919             INTERFACE_DESCRIPTOR_LENGTH,    // bLength
00920             INTERFACE_DESCRIPTOR,           // bDescriptorType
00921             0x00,                           // bInterfaceNumber
00922             0x00,                           // bAlternateSetting
00923             0x02,                           // bNumEndpoints
00924             HID_CLASS,                      // bInterfaceClass
00925             HID_SUBCLASS_NONE,              // bInterfaceSubClass
00926             HID_PROTOCOL_NONE,              // bInterfaceProtocol
00927             0x00,                           // iInterface
00928         
00929             HID_DESCRIPTOR_LENGTH,          // bLength
00930             HID_DESCRIPTOR,                 // bDescriptorType
00931             LSB(HID_VERSION_1_11),          // bcdHID (LSB)
00932             MSB(HID_VERSION_1_11),          // bcdHID (MSB)
00933             0x00,                           // bCountryCode
00934             0x01,                           // bNumDescriptors
00935             REPORT_DESCRIPTOR,              // bDescriptorType
00936             LSB(rptlen0),                   // wDescriptorLength (LSB)
00937             MSB(rptlen0),                   // wDescriptorLength (MSB)
00938         
00939             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00940             ENDPOINT_DESCRIPTOR,            // bDescriptorType
00941             PHY_TO_DESC(EPINT_IN),          // bEndpointAddress - EPINT == EP1
00942             E_INTERRUPT,                    // bmAttributes
00943             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00944             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00945             1,                              // bInterval (milliseconds)
00946         
00947             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00948             ENDPOINT_DESCRIPTOR,            // bDescriptorType
00949             PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress - EPINT == EP1
00950             E_INTERRUPT,                    // bmAttributes
00951             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00952             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00953             1,                              // bInterval (milliseconds)
00954             
00955             // ****** INTERFACE 1 - KEYBOARD ******
00956             INTERFACE_DESCRIPTOR_LENGTH,    // bLength
00957             INTERFACE_DESCRIPTOR,           // bDescriptorType
00958             0x01,                           // bInterfaceNumber
00959             0x00,                           // bAlternateSetting
00960             0x02,                           // bNumEndpoints
00961             HID_CLASS,                      // bInterfaceClass
00962             HID_SUBCLASS_BOOT,              // bInterfaceSubClass
00963             HID_PROTOCOL_KB,                // bInterfaceProtocol
00964             0x00,                           // iInterface
00965         
00966             HID_DESCRIPTOR_LENGTH,          // bLength
00967             HID_DESCRIPTOR,                 // bDescriptorType
00968             LSB(HID_VERSION_1_11),          // bcdHID (LSB)
00969             MSB(HID_VERSION_1_11),          // bcdHID (MSB)
00970             0x00,                           // bCountryCode
00971             0x01,                           // bNumDescriptors
00972             REPORT_DESCRIPTOR,              // bDescriptorType
00973             LSB(rptlen1),                   // wDescriptorLength (LSB)
00974             MSB(rptlen1),                   // wDescriptorLength (MSB)
00975         
00976             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00977             ENDPOINT_DESCRIPTOR,            // bDescriptorType
00978             PHY_TO_DESC(EP4IN),             // bEndpointAddress
00979             E_INTERRUPT,                    // bmAttributes
00980             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00981             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00982             1,                              // bInterval (milliseconds)
00983         
00984             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
00985             ENDPOINT_DESCRIPTOR,            // bDescriptorType
00986             PHY_TO_DESC(EP4OUT),            // bEndpointAddress
00987             E_INTERRUPT,                    // bmAttributes
00988             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
00989             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
00990             1,                              // bInterval (milliseconds)
00991 
00992         };
00993 
00994         // Keyboard + joystick interfaces
00995         return configurationDescriptorWithKB;
00996     }
00997     else
00998     {
00999         // No keyboard - joystick interface only
01000         const int cfglenNoKB = 
01001             ((1 * CONFIGURATION_DESCRIPTOR_LENGTH)
01002               + (1 * INTERFACE_DESCRIPTOR_LENGTH)
01003               + (1 * HID_DESCRIPTOR_LENGTH)
01004               + (2 * ENDPOINT_DESCRIPTOR_LENGTH));
01005         static uint8_t configurationDescriptorNoKB[] = 
01006         {
01007             CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
01008             CONFIGURATION_DESCRIPTOR,       // bDescriptorType
01009             LSB(cfglenNoKB),                // wTotalLength (LSB)
01010             MSB(cfglenNoKB),                // wTotalLength (MSB)
01011             0x01,                           // bNumInterfaces
01012             DEFAULT_CONFIGURATION,          // bConfigurationValue
01013             0x00,                           // iConfiguration
01014             C_RESERVED | C_SELF_POWERED,    // bmAttributes
01015             C_POWER(0),                     // bMaxPower
01016         
01017             INTERFACE_DESCRIPTOR_LENGTH,    // bLength
01018             INTERFACE_DESCRIPTOR,           // bDescriptorType
01019             0x00,                           // bInterfaceNumber
01020             0x00,                           // bAlternateSetting
01021             0x02,                           // bNumEndpoints
01022             HID_CLASS,                      // bInterfaceClass
01023             HID_SUBCLASS_NONE,              // bInterfaceSubClass
01024             HID_PROTOCOL_NONE,              // bInterfaceProtocol (keyboard)
01025             0x00,                           // iInterface
01026         
01027             HID_DESCRIPTOR_LENGTH,          // bLength
01028             HID_DESCRIPTOR,                 // bDescriptorType
01029             LSB(HID_VERSION_1_11),          // bcdHID (LSB)
01030             MSB(HID_VERSION_1_11),          // bcdHID (MSB)
01031             0x00,                           // bCountryCode
01032             0x01,                           // bNumDescriptors
01033             REPORT_DESCRIPTOR,              // bDescriptorType
01034             (uint8_t)(LSB(rptlen0)),        // wDescriptorLength (LSB)
01035             (uint8_t)(MSB(rptlen0)),        // wDescriptorLength (MSB)
01036         
01037             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
01038             ENDPOINT_DESCRIPTOR,            // bDescriptorType
01039             PHY_TO_DESC(EPINT_IN),          // bEndpointAddress
01040             E_INTERRUPT,                    // bmAttributes
01041             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
01042             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
01043             1,                              // bInterval (milliseconds)
01044         
01045             ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
01046             ENDPOINT_DESCRIPTOR,            // bDescriptorType
01047             PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress
01048             E_INTERRUPT,                    // bmAttributes
01049             LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
01050             MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
01051             1                               // bInterval (milliseconds)
01052         };
01053 
01054         return configurationDescriptorNoKB;
01055     }
01056 }
01057 
01058 // Set the configuration.  We need to set up the endpoints for
01059 // our active interfaces.
01060 bool USBJoystick::USBCallback_setConfiguration(uint8_t configuration) 
01061 {
01062     // we only have one valid configuration
01063     if (configuration != DEFAULT_CONFIGURATION)
01064         return false;
01065         
01066     // Configure endpoint 1 - we use this in all cases, for either
01067     // the combined joystick/ledwiz interface or just the ledwiz interface
01068     addEndpoint(EPINT_IN, MAX_REPORT_JS_TX + 1);
01069     addEndpoint(EPINT_OUT, MAX_REPORT_JS_RX + 1);
01070     readStart(EPINT_OUT, MAX_REPORT_JS_TX + 1);
01071     
01072     // if the keyboard is enabled, configure endpoint 4 for the kb interface
01073     if (useKB)
01074     {
01075         addEndpoint(EP4IN, MAX_REPORT_KB_TX + 1);
01076         addEndpoint(EP4OUT, MAX_REPORT_KB_RX + 1);
01077         readStart(EP4OUT, MAX_REPORT_KB_TX + 1);
01078     }
01079 
01080     // success
01081     return true;
01082 }
01083 
01084 // Handle incoming messages on the joystick/LedWiz interface = endpoint 1.
01085 // This interface receives LedWiz protocol commands and commands using our
01086 // custom LedWiz protocol extensions.
01087 //
01088 // We simply queue the messages in our circular buffer for processing in 
01089 // the main loop.  The circular buffer object is designed for safe access
01090 // from the interrupt handler using the rule that only the interrupt 
01091 // handler can change the write pointer, and only the regular code can
01092 // change the read pointer.
01093 bool USBJoystick::EP1_OUT_callback()
01094 {
01095     // Read this message
01096     union {
01097         LedWizMsg msg;
01098         uint8_t buf[MAX_HID_REPORT_SIZE];
01099     } buf;
01100     uint32_t bytesRead = 0;
01101     USBDevice::readEP(EP1OUT, buf.buf, &bytesRead, MAX_HID_REPORT_SIZE);
01102     
01103     // if it's the right length, queue it to our circular buffer
01104     if (bytesRead == 8)
01105         lwbuf.write(buf.msg);
01106 
01107     // start the next read
01108     return readStart(EP1OUT, MAX_HID_REPORT_SIZE);
01109 }
01110 
01111 // Handle incoming messages on the keyboard interface = endpoint 4.
01112 // The host uses this to send updates for the keyboard indicator LEDs
01113 // (caps lock, num lock, etc).  We don't do anything with these, but
01114 // we have to read them to keep the pipe open.
01115 bool USBJoystick::EP4_OUT_callback() 
01116 {
01117     // read this message
01118     uint32_t bytesRead = 0;
01119     uint8_t led[MAX_HID_REPORT_SIZE];
01120     USBDevice::readEP(EP4OUT, led, &bytesRead, MAX_HID_REPORT_SIZE);
01121 
01122     // start the next read
01123     return readStart(EP4OUT, MAX_HID_REPORT_SIZE);
01124 }
01125