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.h Source File

USBJoystick.h

00001 /* USBJoystick.h */
00002 /* USB device example: Joystick*/
00003 /* Copyright (c) 2011 ARM Limited. All rights reserved. */
00004 /* Modified Mouse code for Joystick - WH 2012 */
00005  
00006 #ifndef USBJOYSTICK_H
00007 #define USBJOYSTICK_H
00008  
00009 #include "USBHID.h"
00010 #include "circbuf.h"
00011 
00012 // Bufferd incoming LedWiz message structure
00013 struct LedWizMsg
00014 {
00015     uint8_t data[8];
00016 };
00017 
00018 // interface IDs
00019 const uint8_t IFC_ID_JS = 0;        // joystick + LedWiz interface
00020 const uint8_t IFC_ID_KB = 1;        // keyboard interface
00021 
00022 // keyboard interface report IDs 
00023 const uint8_t REPORT_ID_KB = 1;
00024 const uint8_t REPORT_ID_MEDIA = 2;
00025 
00026 /* Common usage */
00027 enum JOY_BUTTON {
00028      JOY_B0 = 0x0001,
00029      JOY_B1 = 0x0002,
00030      JOY_B2 = 0x0004,
00031      JOY_B3 = 0x0008,
00032      JOY_B4 = 0x0010,
00033      JOY_B5 = 0x0020,
00034      JOY_B6 = 0x0040,
00035      JOY_B7 = 0x0080,
00036      JOY_B8 = 0x0100,
00037      JOY_B9 = 0x0200,
00038      JOY_B10 = 0x0400,
00039      JOY_B11 = 0x0800,
00040      JOY_B12 = 0x1000,
00041      JOY_B13 = 0x2000,
00042      JOY_B14 = 0x4000,
00043      JOY_B15 = 0x8000
00044 };
00045  
00046 /**
00047  *
00048  * USBJoystick example
00049  * @code
00050  * #include "mbed.h"
00051  * #include "USBJoystick.h"
00052  *
00053  * USBJoystick joystick;
00054  *
00055  * int main(void)
00056  * {
00057  *   while (1)
00058  *   {
00059  *      joystick.move(20, 0);
00060  *      wait(0.5);
00061  *   }
00062  * }
00063  *
00064  * @endcode
00065  *
00066  *
00067  * @code
00068  * #include "mbed.h"
00069  * #include "USBJoystick.h"
00070  * #include <math.h>
00071  *
00072  * USBJoystick joystick;
00073  *
00074  * int main(void)
00075  * {   
00076  *   while (1) {
00077  *       // Basic Joystick
00078  *       joystick.update(tx, y, z, buttonBits);
00079  *       wait(0.001);
00080  *   }
00081  * }
00082  * @endcode
00083  */
00084  
00085  
00086 class USBJoystick: public USBHID 
00087 {
00088 public:
00089     // Length of our joystick reports.  Important: This must be kept in sync 
00090     // with the actual joystick report format sent in update().
00091     static const int reportLen = 14;
00092     
00093     // Joystick axis report format
00094     static const int AXIS_FORMAT_XYZ    = 0;    // nudge on X/Y, plunger on Z
00095     static const int AXIS_FORMAT_RXRYRZ = 1;    // nudge on Rx/Ry, plunger on Rz
00096 
00097     /**
00098      *   Constructor
00099      *
00100      * @param vendor_id Your vendor_id (default: 0x1234)
00101      * @param product_id Your product_id (default: 0x0002)
00102      * @param product_release Your product_release (default: 0x0001)
00103      * @param waitforConnect don't return until the connection is established
00104      * @param enableJoystick enable the joystick interface (if false, uses the OUT-only LedWiz-style interface)
00105      * @param axisFormat an AXIS_FORMAT_xxx value specifying the joystick axis report format
00106      * @param useKB enable the USB keyboard reporting interface
00107      */
00108     USBJoystick(uint16_t vendor_id, uint16_t product_id, uint16_t product_release, 
00109         int waitForConnect, bool enableJoystick, int axisFormat, bool useKB)
00110         : USBHID(16, 64, vendor_id, product_id, product_release, false)
00111     { 
00112         _init();
00113         this->useKB = useKB;
00114         this->enableJoystick = enableJoystick;
00115         this->axisFormat = axisFormat;
00116         connect(waitForConnect);
00117     };
00118 
00119     /* read a report from the LedWiz buffer */
00120     bool readLedWizMsg(LedWizMsg &msg)
00121     {
00122         return lwbuf.read(msg);
00123     }
00124      
00125     /* get the idle time settings, in milliseconds */
00126     uint32_t getKbIdle() const { return kbIdleTime * 4UL; }
00127     uint32_t getMediaIdle() const { return mediaIdleTime * 4UL; }
00128      
00129 
00130     /**
00131      * Send a keyboard report.  The argument gives the key state, in the standard
00132      * 6KRO USB keyboard report format: byte 0 is the modifier key bit mask, byte 1
00133      * is reserved (must be 0), and bytes 2-6 are the currently pressed keys, as
00134      * USB key codes.
00135      */
00136     bool kbUpdate(uint8_t data[8]);
00137      
00138     /**
00139      * Send a media key update.  The argument gives the bit mask of media keys
00140      * currently pressed.  See the HID report descriptor for the order of bits.
00141      */
00142     bool mediaUpdate(uint8_t data);
00143      
00144     /**
00145      * Update the joystick status
00146      *
00147      * @param x x-axis position
00148      * @param y y-axis position
00149      * @param z z-axis position
00150      * @param buttons buttons state, as a bit mask (combination with '|' of JOY_Bn values)
00151      * @returns true if there is no error, false otherwise
00152      */
00153     bool update(int16_t x, int16_t y, int16_t z, uint32_t buttons, uint16_t status);
00154      
00155     /**
00156      * Update just the status
00157      */
00158     bool updateStatus(uint32_t stat);
00159      
00160     /**
00161      * Write the plunger status report header.
00162      *
00163      * Note that we automatically add the "calibration mode" bit to the flags,
00164      * so the caller doesn't have to include this.  The caller only has to
00165      * include the sensor-specific flags.
00166      *
00167      * @param npix number of pixels in the sensor (0 for non-imaging sensors)
00168      * @param pos the decoded plunger position, or -1 if none detected
00169      * @param flags (see USBProtocol.h, message type 2A, "byte 7" bit flags)
00170      * @param avgScanTime average sensor scan time in microseconds
00171      * @param processingTime time in microseconds to process the current frame
00172      */
00173     bool sendPlungerStatus(int npix, int flags, int dir, 
00174         uint32_t avgScanTime, uint32_t processingTime);
00175         
00176     /**
00177       * Send a secondary plunger status report header.
00178       *
00179       * @param nativeScale upper bound of the sensor's native reading scale
00180       * @param jitterLo low end of jitter filter window (in sensor native scale units)
00181       * @param jitterHi high end of jitter filter window
00182       * @param rawPos raw position reading, before applying jitter filter
00183       * @param axcTime auto-exposure time in microseconds
00184       */
00185     bool sendPlungerStatus2(
00186         int nativeScale, int jitterLo, int jitterHi, int rawPos, int axcTime);
00187         
00188     /**
00189      * Send a barcode plunger status report header.
00190      *
00191      * @param nbits number of bits in bar code
00192      * @param codetype bar code type (1=Gray code/Manchester bit coding)
00193      * @param pixofs pixel offset of first bit
00194      * @param raw raw bar code bits
00195      * @param mask mask of successfully read bar code bits
00196      */
00197     bool sendPlungerStatusBarcode(
00198         int nbits, int codetype, int startOfs, int pixPerBit, int raw, int mask);
00199         
00200     /**
00201      * Send a quadrature sensor status report header.
00202      *
00203      * @param chA channel "A" reading
00204      * @param chB channel "B" reading
00205      */
00206     bool sendPlungerStatusQuadrature(int chA, int chB);
00207     
00208     /**
00209      * Write an exposure report.  We'll fill out a report with as many pixels as
00210      * will fit in the packet, send the report, and update the index to the next
00211      * pixel to send.  The caller should call this repeatedly to send reports for
00212      * all pixels.
00213      *
00214      * @param idx current index in pixel array, updated to point to next pixel to send
00215      * @param npix number of pixels in the overall array
00216      * @param pix pixel array
00217      */
00218     bool sendPlungerPix(int &idx, int npix, const uint8_t *pix);
00219      
00220     /**
00221      * Write a configuration report.
00222      *
00223      * @param numOutputs the number of configured output channels
00224      * @param unitNo the device unit number
00225      * @param plungerZero plunger zero calibration point
00226      * @param plungerMax plunger max calibration point
00227      * @param plungerRlsTime measured plunger release time, in milliseconds
00228      * @param configured true if a configuration has been saved to flash from the host
00229      * @param sbxpbx true if this firmware version supports SBX/PBX protocol extensions
00230      * @param newAccelFeatures true if this firmware version supports the new accelerometer
00231      *        features (adjustable dynamic range, adjustable auto-centering mode time,
00232      *        auto-centering mode on/off)
00233      * @param flashStatusFeature true if this firmware version supports the flash write
00234      *        success flags in the status bits
00235      * @param reportTimingFeatures true if this firmware version supports configurable
00236      *        joystick report timing
00237      * @param chimeLogicFeature true if this firmware version supports Chime Logic
00238      * @param freeHeapBytes number of free bytes in the malloc heap
00239      */
00240     bool reportConfig(int numOutputs, int unitNo, 
00241         int plungerZero, int plungerMax, int plunterRlsTime, 
00242         bool configured, bool sbxpbx, bool newAccelFeatures, 
00243         bool flashStatusFeature, bool reportTimingFeatures,
00244         bool chimeLogicFeature, size_t freeHeapBytes);
00245         
00246     /**
00247      * Write a configuration variable query report.
00248      *
00249      * @param data the 7-byte data variable buffer, starting with the variable ID byte
00250      */
00251     bool reportConfigVar(const uint8_t *data);
00252      
00253     /**
00254      * Write a device ID report.
00255      */
00256     bool reportID(int index);
00257      
00258     /**
00259      * Write a build data report
00260      *
00261      * @param date build date plus time, in __DATE__ " " __TIME__ macro format ("Mon dd, yyyy hh:mm:ss")
00262      */
00263     bool reportBuildInfo(const char *date);
00264      
00265     /**
00266       * Write a physical button status report.
00267       *
00268       * @param numButtons the number of buttons
00269       * @param state the button states, 1 bit per button, 8 buttons per byte,
00270       *        starting with button 0 in the low-order bit (0x01) of the 
00271       *        first byte
00272       */
00273     bool reportButtonStatus(int numButtons, const uint8_t *state);
00274     
00275     /**
00276      * Write an IR raw sensor input report.  This reports a set of raw
00277      * timing reports for input read from the IR sensor, for learning
00278      * remote purposes.
00279      *
00280      * @param n number of items to report, up to maxRawIR
00281      * @param data items to report; each is a timing reading, in 2us
00282      *        increments, with the low bit in each report set to 0 for
00283      *        a "space" (IR off) or 1 for a "mark" (IR on)
00284      */
00285     bool reportRawIR(int n, const uint16_t *data);
00286     
00287     /**
00288      * Maximum number of raw IR readings that can be sent in one report
00289      * via reportRawIR().
00290      */
00291     static const int maxRawIR = (reportLen - 3)/2;
00292     
00293     /**
00294      * Write an IR input report.  This reports a decoded command read in
00295      * learning mode to the host.
00296      *
00297      * @param pro protocol ID (see IRProtocolID.h)
00298      * @param flags bit flags: 0x02 = protocol uses dittos
00299      * @param code decoded command code
00300      */
00301     bool reportIRCode(uint8_t pro, uint8_t flags, uint64_t code);
00302 
00303     /**
00304      * Send a joystick report to the host
00305      *
00306      * @returns true if there is no error, false otherwise
00307      */
00308     bool update();
00309      
00310     /**
00311      * Move the cursor to (x, y)
00312      *
00313      * @param x x-axis position
00314      * @param y y-axis position
00315      * @returns true if there is no error, false otherwise
00316      */
00317     bool move(int16_t x, int16_t y);
00318      
00319     /**
00320      * Set the z position
00321      *
00322      * @param z z-axis osition
00323      */
00324     bool setZ(int16_t z);
00325      
00326     /**
00327      * Press one or several buttons
00328      *
00329      * @param buttons button state, as a bitwise combination of JOY_Bn values
00330      * @returns true if there is no error, false otherwise
00331      */
00332     bool buttons(uint32_t buttons);
00333 
00334     /* USB descriptor overrides */
00335     virtual const uint8_t *configurationDesc();
00336     virtual const uint8_t *reportDesc(int idx, uint16_t &len);
00337 
00338     /* USB descriptor string overrides */
00339     virtual const uint8_t *stringImanufacturerDesc();
00340     virtual const uint8_t *stringIserialDesc();
00341     virtual const uint8_t *stringIproductDesc();
00342      
00343     /* set/get idle time */
00344     virtual void setIdleTime(int ifc, int rptid, int t)
00345     {
00346         // Remember the new value if operating on the keyboard.  Remember
00347         // separate keyboard and media control idle times, in case the
00348         // host wants separate report rates.
00349         if (ifc == IFC_ID_KB)
00350         {
00351             if (rptid == REPORT_ID_KB)
00352                 kbIdleTime = t;
00353             else if (rptid == REPORT_ID_MEDIA)
00354                 mediaIdleTime = t;
00355         }
00356     }
00357     virtual uint8_t getIdleTime(int ifc, int rptid)
00358     {
00359         // Return the kb idle time if the kb interface is the one requested.
00360         if (ifc == IFC_ID_KB)
00361         {
00362             if (rptid == REPORT_ID_KB)
00363                return kbIdleTime;
00364             if (rptid == REPORT_ID_MEDIA)
00365                return mediaIdleTime;
00366         }
00367         
00368         // we don't use idle times for other interfaces or report types
00369         return 0;
00370     }
00371      
00372     /* callback overrides */
00373     virtual bool USBCallback_setConfiguration(uint8_t configuration);
00374     virtual bool USBCallback_setInterface(uint16_t interface, uint8_t alternate)
00375         { return interface == 0 || interface == 1; }
00376         
00377     virtual bool EP1_OUT_callback();
00378     virtual bool EP4_OUT_callback();
00379      
00380 private:
00381 
00382     // Incoming LedWiz message buffer.  Each LedWiz message is exactly 8 bytes.
00383     CircBuf<LedWizMsg, 16> lwbuf;
00384      
00385     // enable the joystick interface
00386     bool enableJoystick;
00387     
00388     // joystick axis reporting format
00389     bool axisFormat;
00390     
00391     // enable the keyboard interface for button inputs
00392     bool useKB;
00393     
00394     // keyboard maximum idle time between reports
00395     uint8_t kbIdleTime;
00396     
00397     // media maximum idle time between reports
00398     uint8_t mediaIdleTime;
00399     
00400     // current X, Y, Z axis values
00401     int16_t _x;                       
00402     int16_t _y;     
00403     int16_t _z;
00404     
00405     // joystick button status bits
00406     uint16_t _buttonsLo;
00407     uint16_t _buttonsHi;
00408     
00409     // special status flag bits
00410     uint16_t _status;
00411 
00412     void _init();                 
00413 };
00414  
00415 #endif