Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
main.cpp
00001 /* Modified for RetroPie MW 2016 */ 00002 /* Copyright 2014 M J Roberts, MIT License 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 // 00021 // - Button input wiring. 24 of the KL25Z's GPIO ports are mapped as digital inputs 00022 // for buttons and switches. The software reports these as joystick buttons when 00023 // it sends reports to the PC. These can be used to wire physical pinball-style 00024 // buttons in the cabinet (e.g., flipper buttons, the Start button) and miscellaneous 00025 // switches (such as a tilt bob) to the PC. Visual Pinball can use joystick buttons 00026 // for input - you just have to assign a VP function to each button using VP's 00027 // keyboard options dialog. To wire a button physically, connect one terminal of 00028 // the button switch to the KL25Z ground, and connect the other terminal to the 00029 // the GPIO port you wish to assign to the button. See the buttonMap[] array 00030 // below for the available GPIO ports and their assigned joystick button numbers. 00031 // If you're not using a GPIO port, you can just leave it unconnected - the digital 00032 // inputs have built-in pull-up resistors, so an unconnected port is the same as 00033 // an open switch (an "off" state for the button). 00034 // 00035 // 00036 // STATUS LIGHTS: The on-board LED on the KL25Z flashes to indicate the current 00037 // device status. The flash patterns are: 00038 // 00039 // two short red flashes = the device is powered but hasn't successfully 00040 // connected to the host via USB (either it's not physically connected 00041 // to the USB port, or there was a problem with the software handshake 00042 // with the USB device driver on the computer) 00043 // 00044 // short red flash = the host computer is in sleep/suspend mode 00045 // 00046 // long red/green = the LedWiz unti number has been changed, so a reset 00047 // is needed. You can simply unplug the device and plug it back in, 00048 // or presss and hold the reset button on the device for a few seconds. 00049 // 00050 // long yellow/green = everything's working, but the plunger hasn't 00051 // been calibrated; follow the calibration procedure described above. 00052 // This flash mode won't appear if the CCD has been disabled. Note 00053 // that the device can't tell whether a CCD is physically attached; 00054 // if you don't have a CCD attached, you can set the appropriate option 00055 // in config.h or use the Windows config tool to disable the CCD 00056 // software features. 00057 // 00058 // alternating blue/green = everything's working 00059 // 00060 #include "mbed.h" 00061 #include "math.h" 00062 #include "USBGamepad.h" 00063 00064 00065 #define DECL_EXTERNS 00066 #include "config.h" 00067 00068 00069 // --------------------------------------------------------------------------- 00070 // utilities 00071 00072 // number of elements in an array 00073 #define countof(x) (sizeof(x)/sizeof((x)[0])) 00074 00075 // -------------------------------------------------------------------------- 00076 // 00077 // 00078 // Build the full USB product ID. If we're using the LedWiz compatible 00079 // vendor ID, the full product ID is the combination of the LedWiz base 00080 // product ID (0x00F0) and the 0-based unit number (0-15). If we're not 00081 // trying to be LedWiz compatible, we just use the exact product ID 00082 // specified in config.h. 00083 #define MAKE_USB_PRODUCT_ID(vid, pidbase, unit) \ 00084 ((vid) == 0xFAFA && (pidbase) == 0x00F0 ? (pidbase) | (unit) : (pidbase)) 00085 00086 00087 // -------------------------------------------------------------------------- 00088 // 00089 // Joystick axis report range - we report from -JOYMAX to +JOYMAX 00090 // 00091 #define JOYMAX 4096 00092 00093 00094 // --------------------------------------------------------------------------- 00095 // 00096 // On-board RGB LED elements - we use these for diagnostic displays. 00097 // 00098 //TODO: FIXME for Nucleo 00099 DigitalOut ledR(LED1), ledG(LED2), ledB(LED3); 00100 00101 // --------------------------------------------------------------------------- 00102 // 00103 // Button input 00104 // 00105 00106 // button input map array 00107 00108 DigitalIn *buttonDigIn[NUM_OF_BUTTONS]; // config.h 00109 00110 // button state 00111 struct ButtonState 00112 { 00113 // current on/off state 00114 int pressed; 00115 00116 // Sticky time remaining for current state. When a 00117 // state transition occurs, we set this to a debounce 00118 // period. Future state transitions will be ignored 00119 // until the debounce time elapses. 00120 int t; 00121 } buttonState[NUM_OF_BUTTONS]; 00122 00123 // timer for button reports 00124 static Timer buttonTimer; 00125 00126 // initialize the button inputs 00127 void initButtons() 00128 { 00129 // create the digital inputs 00130 for (int i = 0 ; i < countof(buttonDigIn) ; ++i) 00131 { 00132 if (i < countof(buttonMap) && buttonMap[i] != NC) 00133 buttonDigIn[i] = new DigitalIn(buttonMap[i]); 00134 else 00135 buttonDigIn[i] = 0; 00136 } 00137 00138 // start the button timer 00139 buttonTimer.start(); 00140 } 00141 00142 00143 // read the button input state 00144 uint32_t readButtons() 00145 { 00146 // start with all buttons off 00147 uint32_t buttons = 0; 00148 00149 // figure the time elapsed since the last scan 00150 int dt = buttonTimer.read_ms(); 00151 00152 // reset the timef for the next scan 00153 buttonTimer.reset(); 00154 00155 // scan the button list 00156 uint32_t bit = 1; 00157 DigitalIn **di = buttonDigIn; 00158 ButtonState *bs = buttonState; 00159 for (int i = 0 ; i < countof(buttonDigIn) ; ++i, ++di, ++bs, bit <<= 1) 00160 { 00161 // read this button 00162 if (*di != 0) 00163 { 00164 // deduct the elapsed time since the last update 00165 // from the button's remaining sticky time 00166 bs->t -= dt; 00167 if (bs->t < 0) 00168 bs->t = 0; 00169 00170 // If the sticky time has elapsed, note the new physical 00171 // state of the button. If we still have sticky time 00172 // remaining, ignore the physical state; the last state 00173 // change persists until the sticky time elapses so that 00174 // we smooth out any "bounce" (electrical transients that 00175 // occur when the switch contact is opened or closed). 00176 if (bs->t == 0) 00177 { 00178 // get the new physical state 00179 int pressed = !(*di)->read(); 00180 00181 // update the button's logical state if this is a change 00182 if (pressed != bs->pressed) 00183 { 00184 // store the new state 00185 bs->pressed = pressed; 00186 00187 // start a new sticky period for debouncing this 00188 // state change 00189 bs->t = 25; 00190 } 00191 } 00192 00193 // if it's pressed, OR its bit into the state 00194 if (bs->pressed) 00195 buttons |= bit; 00196 } 00197 } 00198 00199 // return the new button list 00200 return buttons; 00201 } 00202 00203 // --------------------------------------------------------------------------- 00204 // 00205 // Customization joystick subbclass 00206 // 00207 00208 class MyUSBGamepad: public USBGamepad 00209 { 00210 public: 00211 MyUSBGamepad(uint16_t vendor_id, uint16_t product_id, uint16_t product_release) 00212 : USBGamepad(vendor_id, product_id, product_release, true) 00213 { 00214 suspended_ = false; 00215 } 00216 00217 // are we connected? 00218 int isConnected() { return configured(); } 00219 00220 // Are we in suspend mode? 00221 int isSuspended() const { return suspended_; } 00222 00223 protected: 00224 virtual void suspendStateChanged(unsigned int suspended) 00225 { suspended_ = suspended; } 00226 00227 // are we suspended? 00228 int suspended_; 00229 }; 00230 00231 00232 00233 // --------------------------------------------------------------------------- 00234 // 00235 // Main program loop. This is invoked on startup and runs forever. Our 00236 // main work is to read our devices, process 00237 // the readings into nudge and plunger position data, and send the results 00238 // to the host computer via the USB joystick interface. 00239 // 00240 int main(void) 00241 { 00242 // turn off our on-board indicator LED 00243 ledR = 1; 00244 ledG = 1; 00245 ledB = 1; 00246 00247 // we're not connected/awake yet 00248 bool connected = false; 00249 time_t connectChangeTime = time(0); 00250 00251 // initialize the button input ports 00252 initButtons(); 00253 00254 // we don't need a reset yet 00255 bool needReset = false; 00256 // Create the joystick USB client. 00257 MyUSBGamepad js(USB_VENDOR_ID,USB_PRODUCT_ID,USB_PRODUCT_VER); // vendor, product, product release 00258 00259 // last report timer - we use this to throttle reports, since VP 00260 // doesn't want to hear from us more than about every 10ms 00261 Timer reportTimer; 00262 reportTimer.start(); 00263 00264 // set up a timer for our heartbeat indicator 00265 Timer hbTimer; 00266 hbTimer.start(); 00267 int hb = 0; 00268 uint16_t hbcnt = 0; 00269 00270 // we're all set up - now just loop, processing sensor reports and 00271 // host requests 00272 for (;;) 00273 { 00274 00275 // update the buttons 00276 uint32_t buttons = readButtons(); 00277 00278 00279 // don't poll too fast, this can outrun the host 00280 if (reportTimer.read_ms() > 15) 00281 { 00282 js.update(buttons); 00283 // we've just started a new report interval, so reset the timer 00284 reportTimer.reset(); 00285 } 00286 00287 00288 00289 #ifdef DEBUG_PRINTF 00290 if (x != 0 || y != 0) 00291 printf("%d,%d\r\n", x, y); 00292 #endif 00293 00294 // check for connection status changes 00295 int newConnected = js.isConnected() && !js.isSuspended(); 00296 if (newConnected != connected) 00297 { 00298 // give it a few seconds to stabilize 00299 time_t tc = time(0); 00300 if (tc - connectChangeTime > 3) 00301 { 00302 // note the new status 00303 connected = newConnected; 00304 connectChangeTime = tc; 00305 } 00306 } 00307 00308 // provide a visual status indication on the on-board LED 00309 if (hbTimer.read_ms() > 1000) 00310 { 00311 if (!newConnected) 00312 { 00313 // suspended - turn off the LED 00314 ledR = 1; 00315 ledG = 1; 00316 ledB = 1; 00317 00318 // show a status flash every so often 00319 if (hbcnt % 3 == 0) 00320 { 00321 // disconnected = red/red flash; suspended = red 00322 for (int n = js.isConnected() ? 1 : 2 ; n > 0 ; --n) 00323 { 00324 ledR = 0; 00325 wait(0.05); 00326 ledR = 1; 00327 wait(0.25); 00328 } 00329 } 00330 } 00331 else if (needReset) 00332 { 00333 // connected, need to reset due to changes in config parameters - 00334 // flash red/green 00335 hb = !hb; 00336 ledR = (hb ? 0 : 1); 00337 ledG = (hb ? 1 : 0); 00338 ledB = 0; 00339 } 00340 else 00341 { 00342 // connected - flash blue/green 00343 hb = !hb; 00344 ledR = 1; 00345 ledG = (hb ? 0 : 1); 00346 ledB = (hb ? 1 : 0); 00347 } 00348 00349 // reset the heartbeat timer 00350 hbTimer.reset(); 00351 ++hbcnt; 00352 } 00353 00354 } 00355 }
Generated on Fri Jul 15 2022 06:19:56 by
1.7.2