This is a work in progress. Trying to make a working arcade button to USB interface with the Nucleo F411RE.

Dependencies:   USBDevice mbed

This project was inspired by USB Joystick Device

The goal of this project is to build an simple interface that I will connect numerous Arcade buttons and joysticks to the Nucleo board, and the Nucleo will present itself as a USB Gamepad to Windows or Linux. The joysticks are Arcade joysticks that have four switches, up/down/left/right. It is not an analog joystick, just a set of switches. These will be connected to the Nucleo's pins configured as inputs.

The code will then continuously loop and test which buttons are closed, and transfer this data to the host via USBGamepad protocol.

Much thanks to Wim Huiskamp for his original project, documentation, and later reaching out to me to guide me to solving a last minute problem. Wim clued me into the fact that I needed a 1k5 pullup resistor between the 3v3 pin and the PA_12/D+ pin. Once I did this Windows detected the device as a Gamepad and registered it correctly! Yay!

Connecting USB cable to the board is as follows:

You will need a USB data cable (the one I used had a micro usb on one end and regular usb on the other). I cut off the micro USB end, and cut the insulation back about 30mm. This exposed four wires, Red, Black, White and Green. You will then either crimp some header connectors or solder directly to the Nucleo header pins as follows:

  • Green USB D+ to PA_12
  • White USB D- to PA_11
  • Red USB 5V to E5V (with jumper JP5 set to E5V)
  • Black USB GND to GND

As an extra debugging measure, you can connect both the ST/Link USB and the PA_12/11 USB to the Windows machine to run both at the same time, and you can see printf messages from within ST/Link.

We can verify the HID Vendor and Product IDs by looking at the Device Manager, and look for the HID Game Controller:

/media/uploads/thetazzbot/arcade_controller_hid.jpg

I used pid.codes to register my own Vendor_ID and Product_ID

If you go to the USB Game Controller control panel widget, you will see the new entry for Arcade Gamepad:

/media/uploads/thetazzbot/arcade_controller_controlpanel.jpg

And here we can see all 32 buttons:

/media/uploads/thetazzbot/arcade_controller_buttons.jpg

On the Nucleo board you may have difficulties depending on the revision. The board I am using is an STM32F411RE Revision C03, which has resistors and solder joints (bottom) to allow the use of the Crystal on the STLink board for USB purposes. After programming via STLink, remove the USB cable from the STLink, the jumper must be set to E5V to power the board from the PC's usb port. Plug the new cable into the PC.

When you're ready to install it in the arcade cabinet, or project, just remember to setup the jumper JP5 to E5V and you only need the single USB connection to the host.

Here are some useful links that I used to grasp all the little things involved in this project:

Committer:
thetazzbot
Date:
Wed Dec 14 00:49:38 2016 +0000
Revision:
4:05f4ace9508a
Parent:
2:bdf03de86660
Refactored code for Gamepad vs Joystic, and corrected usb descriptor

Who changed what in which revision?

UserRevisionLine numberNew contents of line
thetazzbot 1:ad6066c16dbd 1 /* Modified for RetroPie MW 2016 */
thetazzbot 1:ad6066c16dbd 2 /* Copyright 2014 M J Roberts, MIT License
thetazzbot 1:ad6066c16dbd 3 *
thetazzbot 1:ad6066c16dbd 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
thetazzbot 1:ad6066c16dbd 5 * and associated documentation files (the "Software"), to deal in the Software without
thetazzbot 1:ad6066c16dbd 6 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
thetazzbot 1:ad6066c16dbd 7 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
thetazzbot 1:ad6066c16dbd 8 * Software is furnished to do so, subject to the following conditions:
thetazzbot 1:ad6066c16dbd 9 *
thetazzbot 1:ad6066c16dbd 10 * The above copyright notice and this permission notice shall be included in all copies or
thetazzbot 1:ad6066c16dbd 11 * substantial portions of the Software.
thetazzbot 1:ad6066c16dbd 12 *
thetazzbot 1:ad6066c16dbd 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
thetazzbot 1:ad6066c16dbd 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
thetazzbot 1:ad6066c16dbd 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
thetazzbot 1:ad6066c16dbd 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
thetazzbot 1:ad6066c16dbd 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
thetazzbot 1:ad6066c16dbd 18 */
thetazzbot 1:ad6066c16dbd 19
thetazzbot 1:ad6066c16dbd 20 //
thetazzbot 1:ad6066c16dbd 21 // - Button input wiring. 24 of the KL25Z's GPIO ports are mapped as digital inputs
thetazzbot 1:ad6066c16dbd 22 // for buttons and switches. The software reports these as joystick buttons when
thetazzbot 1:ad6066c16dbd 23 // it sends reports to the PC. These can be used to wire physical pinball-style
thetazzbot 1:ad6066c16dbd 24 // buttons in the cabinet (e.g., flipper buttons, the Start button) and miscellaneous
thetazzbot 1:ad6066c16dbd 25 // switches (such as a tilt bob) to the PC. Visual Pinball can use joystick buttons
thetazzbot 1:ad6066c16dbd 26 // for input - you just have to assign a VP function to each button using VP's
thetazzbot 1:ad6066c16dbd 27 // keyboard options dialog. To wire a button physically, connect one terminal of
thetazzbot 1:ad6066c16dbd 28 // the button switch to the KL25Z ground, and connect the other terminal to the
thetazzbot 1:ad6066c16dbd 29 // the GPIO port you wish to assign to the button. See the buttonMap[] array
thetazzbot 1:ad6066c16dbd 30 // below for the available GPIO ports and their assigned joystick button numbers.
thetazzbot 1:ad6066c16dbd 31 // If you're not using a GPIO port, you can just leave it unconnected - the digital
thetazzbot 1:ad6066c16dbd 32 // inputs have built-in pull-up resistors, so an unconnected port is the same as
thetazzbot 1:ad6066c16dbd 33 // an open switch (an "off" state for the button).
thetazzbot 1:ad6066c16dbd 34 //
thetazzbot 1:ad6066c16dbd 35 //
thetazzbot 1:ad6066c16dbd 36 // STATUS LIGHTS: The on-board LED on the KL25Z flashes to indicate the current
thetazzbot 1:ad6066c16dbd 37 // device status. The flash patterns are:
thetazzbot 1:ad6066c16dbd 38 //
thetazzbot 1:ad6066c16dbd 39 // two short red flashes = the device is powered but hasn't successfully
thetazzbot 1:ad6066c16dbd 40 // connected to the host via USB (either it's not physically connected
thetazzbot 1:ad6066c16dbd 41 // to the USB port, or there was a problem with the software handshake
thetazzbot 1:ad6066c16dbd 42 // with the USB device driver on the computer)
thetazzbot 1:ad6066c16dbd 43 //
thetazzbot 1:ad6066c16dbd 44 // short red flash = the host computer is in sleep/suspend mode
thetazzbot 1:ad6066c16dbd 45 //
thetazzbot 1:ad6066c16dbd 46 // long red/green = the LedWiz unti number has been changed, so a reset
thetazzbot 1:ad6066c16dbd 47 // is needed. You can simply unplug the device and plug it back in,
thetazzbot 1:ad6066c16dbd 48 // or presss and hold the reset button on the device for a few seconds.
thetazzbot 1:ad6066c16dbd 49 //
thetazzbot 1:ad6066c16dbd 50 // long yellow/green = everything's working, but the plunger hasn't
thetazzbot 1:ad6066c16dbd 51 // been calibrated; follow the calibration procedure described above.
thetazzbot 1:ad6066c16dbd 52 // This flash mode won't appear if the CCD has been disabled. Note
thetazzbot 1:ad6066c16dbd 53 // that the device can't tell whether a CCD is physically attached;
thetazzbot 1:ad6066c16dbd 54 // if you don't have a CCD attached, you can set the appropriate option
thetazzbot 1:ad6066c16dbd 55 // in config.h or use the Windows config tool to disable the CCD
thetazzbot 1:ad6066c16dbd 56 // software features.
thetazzbot 1:ad6066c16dbd 57 //
thetazzbot 1:ad6066c16dbd 58 // alternating blue/green = everything's working
thetazzbot 1:ad6066c16dbd 59 //
thetazzbot 1:ad6066c16dbd 60 #include "mbed.h"
thetazzbot 1:ad6066c16dbd 61 #include "math.h"
thetazzbot 4:05f4ace9508a 62 #include "USBGamepad.h"
thetazzbot 1:ad6066c16dbd 63
thetazzbot 1:ad6066c16dbd 64
thetazzbot 1:ad6066c16dbd 65 #define DECL_EXTERNS
thetazzbot 1:ad6066c16dbd 66 #include "config.h"
thetazzbot 1:ad6066c16dbd 67
thetazzbot 1:ad6066c16dbd 68
thetazzbot 1:ad6066c16dbd 69 // ---------------------------------------------------------------------------
thetazzbot 1:ad6066c16dbd 70 // utilities
thetazzbot 1:ad6066c16dbd 71
thetazzbot 1:ad6066c16dbd 72 // number of elements in an array
thetazzbot 1:ad6066c16dbd 73 #define countof(x) (sizeof(x)/sizeof((x)[0]))
thetazzbot 1:ad6066c16dbd 74
thetazzbot 1:ad6066c16dbd 75 // --------------------------------------------------------------------------
thetazzbot 1:ad6066c16dbd 76 //
thetazzbot 1:ad6066c16dbd 77 //
thetazzbot 1:ad6066c16dbd 78 // Build the full USB product ID. If we're using the LedWiz compatible
thetazzbot 1:ad6066c16dbd 79 // vendor ID, the full product ID is the combination of the LedWiz base
thetazzbot 1:ad6066c16dbd 80 // product ID (0x00F0) and the 0-based unit number (0-15). If we're not
thetazzbot 1:ad6066c16dbd 81 // trying to be LedWiz compatible, we just use the exact product ID
thetazzbot 1:ad6066c16dbd 82 // specified in config.h.
thetazzbot 1:ad6066c16dbd 83 #define MAKE_USB_PRODUCT_ID(vid, pidbase, unit) \
thetazzbot 1:ad6066c16dbd 84 ((vid) == 0xFAFA && (pidbase) == 0x00F0 ? (pidbase) | (unit) : (pidbase))
thetazzbot 1:ad6066c16dbd 85
thetazzbot 1:ad6066c16dbd 86
thetazzbot 1:ad6066c16dbd 87 // --------------------------------------------------------------------------
thetazzbot 1:ad6066c16dbd 88 //
thetazzbot 1:ad6066c16dbd 89 // Joystick axis report range - we report from -JOYMAX to +JOYMAX
thetazzbot 1:ad6066c16dbd 90 //
thetazzbot 1:ad6066c16dbd 91 #define JOYMAX 4096
thetazzbot 1:ad6066c16dbd 92
thetazzbot 1:ad6066c16dbd 93
thetazzbot 1:ad6066c16dbd 94 // ---------------------------------------------------------------------------
thetazzbot 1:ad6066c16dbd 95 //
thetazzbot 1:ad6066c16dbd 96 // On-board RGB LED elements - we use these for diagnostic displays.
thetazzbot 1:ad6066c16dbd 97 //
thetazzbot 1:ad6066c16dbd 98 //TODO: FIXME for Nucleo
thetazzbot 1:ad6066c16dbd 99 DigitalOut ledR(LED1), ledG(LED2), ledB(LED3);
thetazzbot 1:ad6066c16dbd 100
thetazzbot 1:ad6066c16dbd 101 // ---------------------------------------------------------------------------
thetazzbot 1:ad6066c16dbd 102 //
thetazzbot 1:ad6066c16dbd 103 // Button input
thetazzbot 1:ad6066c16dbd 104 //
thetazzbot 1:ad6066c16dbd 105
thetazzbot 1:ad6066c16dbd 106 // button input map array
thetazzbot 1:ad6066c16dbd 107
thetazzbot 1:ad6066c16dbd 108 DigitalIn *buttonDigIn[NUM_OF_BUTTONS]; // config.h
thetazzbot 1:ad6066c16dbd 109
thetazzbot 1:ad6066c16dbd 110 // button state
thetazzbot 1:ad6066c16dbd 111 struct ButtonState
thetazzbot 1:ad6066c16dbd 112 {
thetazzbot 1:ad6066c16dbd 113 // current on/off state
thetazzbot 1:ad6066c16dbd 114 int pressed;
thetazzbot 1:ad6066c16dbd 115
thetazzbot 1:ad6066c16dbd 116 // Sticky time remaining for current state. When a
thetazzbot 1:ad6066c16dbd 117 // state transition occurs, we set this to a debounce
thetazzbot 1:ad6066c16dbd 118 // period. Future state transitions will be ignored
thetazzbot 1:ad6066c16dbd 119 // until the debounce time elapses.
thetazzbot 1:ad6066c16dbd 120 int t;
thetazzbot 1:ad6066c16dbd 121 } buttonState[NUM_OF_BUTTONS];
thetazzbot 1:ad6066c16dbd 122
thetazzbot 1:ad6066c16dbd 123 // timer for button reports
thetazzbot 1:ad6066c16dbd 124 static Timer buttonTimer;
thetazzbot 1:ad6066c16dbd 125
thetazzbot 1:ad6066c16dbd 126 // initialize the button inputs
thetazzbot 1:ad6066c16dbd 127 void initButtons()
thetazzbot 1:ad6066c16dbd 128 {
thetazzbot 1:ad6066c16dbd 129 // create the digital inputs
thetazzbot 1:ad6066c16dbd 130 for (int i = 0 ; i < countof(buttonDigIn) ; ++i)
thetazzbot 1:ad6066c16dbd 131 {
thetazzbot 1:ad6066c16dbd 132 if (i < countof(buttonMap) && buttonMap[i] != NC)
thetazzbot 1:ad6066c16dbd 133 buttonDigIn[i] = new DigitalIn(buttonMap[i]);
thetazzbot 1:ad6066c16dbd 134 else
thetazzbot 1:ad6066c16dbd 135 buttonDigIn[i] = 0;
thetazzbot 1:ad6066c16dbd 136 }
thetazzbot 1:ad6066c16dbd 137
thetazzbot 1:ad6066c16dbd 138 // start the button timer
thetazzbot 1:ad6066c16dbd 139 buttonTimer.start();
thetazzbot 1:ad6066c16dbd 140 }
thetazzbot 1:ad6066c16dbd 141
thetazzbot 1:ad6066c16dbd 142
thetazzbot 1:ad6066c16dbd 143 // read the button input state
thetazzbot 1:ad6066c16dbd 144 uint32_t readButtons()
thetazzbot 1:ad6066c16dbd 145 {
thetazzbot 1:ad6066c16dbd 146 // start with all buttons off
thetazzbot 1:ad6066c16dbd 147 uint32_t buttons = 0;
thetazzbot 1:ad6066c16dbd 148
thetazzbot 1:ad6066c16dbd 149 // figure the time elapsed since the last scan
thetazzbot 1:ad6066c16dbd 150 int dt = buttonTimer.read_ms();
thetazzbot 1:ad6066c16dbd 151
thetazzbot 1:ad6066c16dbd 152 // reset the timef for the next scan
thetazzbot 1:ad6066c16dbd 153 buttonTimer.reset();
thetazzbot 1:ad6066c16dbd 154
thetazzbot 1:ad6066c16dbd 155 // scan the button list
thetazzbot 1:ad6066c16dbd 156 uint32_t bit = 1;
thetazzbot 1:ad6066c16dbd 157 DigitalIn **di = buttonDigIn;
thetazzbot 1:ad6066c16dbd 158 ButtonState *bs = buttonState;
thetazzbot 1:ad6066c16dbd 159 for (int i = 0 ; i < countof(buttonDigIn) ; ++i, ++di, ++bs, bit <<= 1)
thetazzbot 1:ad6066c16dbd 160 {
thetazzbot 1:ad6066c16dbd 161 // read this button
thetazzbot 1:ad6066c16dbd 162 if (*di != 0)
thetazzbot 1:ad6066c16dbd 163 {
thetazzbot 1:ad6066c16dbd 164 // deduct the elapsed time since the last update
thetazzbot 1:ad6066c16dbd 165 // from the button's remaining sticky time
thetazzbot 1:ad6066c16dbd 166 bs->t -= dt;
thetazzbot 1:ad6066c16dbd 167 if (bs->t < 0)
thetazzbot 1:ad6066c16dbd 168 bs->t = 0;
thetazzbot 1:ad6066c16dbd 169
thetazzbot 1:ad6066c16dbd 170 // If the sticky time has elapsed, note the new physical
thetazzbot 1:ad6066c16dbd 171 // state of the button. If we still have sticky time
thetazzbot 1:ad6066c16dbd 172 // remaining, ignore the physical state; the last state
thetazzbot 1:ad6066c16dbd 173 // change persists until the sticky time elapses so that
thetazzbot 1:ad6066c16dbd 174 // we smooth out any "bounce" (electrical transients that
thetazzbot 1:ad6066c16dbd 175 // occur when the switch contact is opened or closed).
thetazzbot 1:ad6066c16dbd 176 if (bs->t == 0)
thetazzbot 1:ad6066c16dbd 177 {
thetazzbot 1:ad6066c16dbd 178 // get the new physical state
thetazzbot 1:ad6066c16dbd 179 int pressed = !(*di)->read();
thetazzbot 1:ad6066c16dbd 180
thetazzbot 1:ad6066c16dbd 181 // update the button's logical state if this is a change
thetazzbot 1:ad6066c16dbd 182 if (pressed != bs->pressed)
thetazzbot 1:ad6066c16dbd 183 {
thetazzbot 1:ad6066c16dbd 184 // store the new state
thetazzbot 1:ad6066c16dbd 185 bs->pressed = pressed;
thetazzbot 1:ad6066c16dbd 186
thetazzbot 1:ad6066c16dbd 187 // start a new sticky period for debouncing this
thetazzbot 1:ad6066c16dbd 188 // state change
thetazzbot 1:ad6066c16dbd 189 bs->t = 25;
thetazzbot 1:ad6066c16dbd 190 }
thetazzbot 1:ad6066c16dbd 191 }
thetazzbot 1:ad6066c16dbd 192
thetazzbot 1:ad6066c16dbd 193 // if it's pressed, OR its bit into the state
thetazzbot 1:ad6066c16dbd 194 if (bs->pressed)
thetazzbot 1:ad6066c16dbd 195 buttons |= bit;
thetazzbot 1:ad6066c16dbd 196 }
thetazzbot 1:ad6066c16dbd 197 }
thetazzbot 1:ad6066c16dbd 198
thetazzbot 1:ad6066c16dbd 199 // return the new button list
thetazzbot 1:ad6066c16dbd 200 return buttons;
thetazzbot 1:ad6066c16dbd 201 }
thetazzbot 1:ad6066c16dbd 202
thetazzbot 1:ad6066c16dbd 203 // ---------------------------------------------------------------------------
thetazzbot 1:ad6066c16dbd 204 //
thetazzbot 1:ad6066c16dbd 205 // Customization joystick subbclass
thetazzbot 1:ad6066c16dbd 206 //
thetazzbot 1:ad6066c16dbd 207
thetazzbot 4:05f4ace9508a 208 class MyUSBGamepad: public USBGamepad
thetazzbot 1:ad6066c16dbd 209 {
thetazzbot 1:ad6066c16dbd 210 public:
thetazzbot 4:05f4ace9508a 211 MyUSBGamepad(uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
thetazzbot 4:05f4ace9508a 212 : USBGamepad(vendor_id, product_id, product_release, true)
thetazzbot 1:ad6066c16dbd 213 {
thetazzbot 1:ad6066c16dbd 214 suspended_ = false;
thetazzbot 1:ad6066c16dbd 215 }
thetazzbot 1:ad6066c16dbd 216
thetazzbot 1:ad6066c16dbd 217 // are we connected?
thetazzbot 1:ad6066c16dbd 218 int isConnected() { return configured(); }
thetazzbot 1:ad6066c16dbd 219
thetazzbot 1:ad6066c16dbd 220 // Are we in suspend mode?
thetazzbot 1:ad6066c16dbd 221 int isSuspended() const { return suspended_; }
thetazzbot 1:ad6066c16dbd 222
thetazzbot 1:ad6066c16dbd 223 protected:
thetazzbot 1:ad6066c16dbd 224 virtual void suspendStateChanged(unsigned int suspended)
thetazzbot 1:ad6066c16dbd 225 { suspended_ = suspended; }
thetazzbot 1:ad6066c16dbd 226
thetazzbot 1:ad6066c16dbd 227 // are we suspended?
thetazzbot 1:ad6066c16dbd 228 int suspended_;
thetazzbot 1:ad6066c16dbd 229 };
thetazzbot 1:ad6066c16dbd 230
thetazzbot 1:ad6066c16dbd 231
thetazzbot 1:ad6066c16dbd 232
thetazzbot 1:ad6066c16dbd 233 // ---------------------------------------------------------------------------
thetazzbot 1:ad6066c16dbd 234 //
thetazzbot 1:ad6066c16dbd 235 // Main program loop. This is invoked on startup and runs forever. Our
thetazzbot 1:ad6066c16dbd 236 // main work is to read our devices, process
thetazzbot 1:ad6066c16dbd 237 // the readings into nudge and plunger position data, and send the results
thetazzbot 1:ad6066c16dbd 238 // to the host computer via the USB joystick interface.
thetazzbot 1:ad6066c16dbd 239 //
thetazzbot 1:ad6066c16dbd 240 int main(void)
thetazzbot 1:ad6066c16dbd 241 {
thetazzbot 1:ad6066c16dbd 242 // turn off our on-board indicator LED
thetazzbot 1:ad6066c16dbd 243 ledR = 1;
thetazzbot 1:ad6066c16dbd 244 ledG = 1;
thetazzbot 1:ad6066c16dbd 245 ledB = 1;
thetazzbot 1:ad6066c16dbd 246
thetazzbot 1:ad6066c16dbd 247 // we're not connected/awake yet
thetazzbot 1:ad6066c16dbd 248 bool connected = false;
thetazzbot 1:ad6066c16dbd 249 time_t connectChangeTime = time(0);
thetazzbot 1:ad6066c16dbd 250
thetazzbot 1:ad6066c16dbd 251 // initialize the button input ports
thetazzbot 1:ad6066c16dbd 252 initButtons();
thetazzbot 1:ad6066c16dbd 253
thetazzbot 1:ad6066c16dbd 254 // we don't need a reset yet
thetazzbot 1:ad6066c16dbd 255 bool needReset = false;
thetazzbot 1:ad6066c16dbd 256 // Create the joystick USB client.
thetazzbot 4:05f4ace9508a 257 MyUSBGamepad js(USB_VENDOR_ID,USB_PRODUCT_ID,USB_PRODUCT_VER); // vendor, product, product release
thetazzbot 1:ad6066c16dbd 258
thetazzbot 1:ad6066c16dbd 259 // last report timer - we use this to throttle reports, since VP
thetazzbot 1:ad6066c16dbd 260 // doesn't want to hear from us more than about every 10ms
thetazzbot 1:ad6066c16dbd 261 Timer reportTimer;
thetazzbot 1:ad6066c16dbd 262 reportTimer.start();
thetazzbot 1:ad6066c16dbd 263
thetazzbot 1:ad6066c16dbd 264 // set up a timer for our heartbeat indicator
thetazzbot 1:ad6066c16dbd 265 Timer hbTimer;
thetazzbot 1:ad6066c16dbd 266 hbTimer.start();
thetazzbot 1:ad6066c16dbd 267 int hb = 0;
thetazzbot 1:ad6066c16dbd 268 uint16_t hbcnt = 0;
thetazzbot 4:05f4ace9508a 269
thetazzbot 1:ad6066c16dbd 270 // we're all set up - now just loop, processing sensor reports and
thetazzbot 1:ad6066c16dbd 271 // host requests
thetazzbot 1:ad6066c16dbd 272 for (;;)
thetazzbot 1:ad6066c16dbd 273 {
thetazzbot 2:bdf03de86660 274
thetazzbot 1:ad6066c16dbd 275 // update the buttons
thetazzbot 1:ad6066c16dbd 276 uint32_t buttons = readButtons();
thetazzbot 1:ad6066c16dbd 277
thetazzbot 4:05f4ace9508a 278
thetazzbot 4:05f4ace9508a 279 // don't poll too fast, this can outrun the host
thetazzbot 1:ad6066c16dbd 280 if (reportTimer.read_ms() > 15)
thetazzbot 1:ad6066c16dbd 281 {
thetazzbot 4:05f4ace9508a 282 js.update(buttons);
thetazzbot 1:ad6066c16dbd 283 // we've just started a new report interval, so reset the timer
thetazzbot 1:ad6066c16dbd 284 reportTimer.reset();
thetazzbot 1:ad6066c16dbd 285 }
thetazzbot 1:ad6066c16dbd 286
thetazzbot 1:ad6066c16dbd 287
thetazzbot 1:ad6066c16dbd 288
thetazzbot 1:ad6066c16dbd 289 #ifdef DEBUG_PRINTF
thetazzbot 1:ad6066c16dbd 290 if (x != 0 || y != 0)
thetazzbot 1:ad6066c16dbd 291 printf("%d,%d\r\n", x, y);
thetazzbot 1:ad6066c16dbd 292 #endif
thetazzbot 1:ad6066c16dbd 293
thetazzbot 1:ad6066c16dbd 294 // check for connection status changes
thetazzbot 1:ad6066c16dbd 295 int newConnected = js.isConnected() && !js.isSuspended();
thetazzbot 1:ad6066c16dbd 296 if (newConnected != connected)
thetazzbot 1:ad6066c16dbd 297 {
thetazzbot 1:ad6066c16dbd 298 // give it a few seconds to stabilize
thetazzbot 1:ad6066c16dbd 299 time_t tc = time(0);
thetazzbot 1:ad6066c16dbd 300 if (tc - connectChangeTime > 3)
thetazzbot 1:ad6066c16dbd 301 {
thetazzbot 1:ad6066c16dbd 302 // note the new status
thetazzbot 1:ad6066c16dbd 303 connected = newConnected;
thetazzbot 1:ad6066c16dbd 304 connectChangeTime = tc;
thetazzbot 1:ad6066c16dbd 305 }
thetazzbot 1:ad6066c16dbd 306 }
thetazzbot 1:ad6066c16dbd 307
thetazzbot 1:ad6066c16dbd 308 // provide a visual status indication on the on-board LED
thetazzbot 1:ad6066c16dbd 309 if (hbTimer.read_ms() > 1000)
thetazzbot 1:ad6066c16dbd 310 {
thetazzbot 1:ad6066c16dbd 311 if (!newConnected)
thetazzbot 1:ad6066c16dbd 312 {
thetazzbot 1:ad6066c16dbd 313 // suspended - turn off the LED
thetazzbot 1:ad6066c16dbd 314 ledR = 1;
thetazzbot 1:ad6066c16dbd 315 ledG = 1;
thetazzbot 1:ad6066c16dbd 316 ledB = 1;
thetazzbot 1:ad6066c16dbd 317
thetazzbot 1:ad6066c16dbd 318 // show a status flash every so often
thetazzbot 1:ad6066c16dbd 319 if (hbcnt % 3 == 0)
thetazzbot 1:ad6066c16dbd 320 {
thetazzbot 1:ad6066c16dbd 321 // disconnected = red/red flash; suspended = red
thetazzbot 1:ad6066c16dbd 322 for (int n = js.isConnected() ? 1 : 2 ; n > 0 ; --n)
thetazzbot 1:ad6066c16dbd 323 {
thetazzbot 1:ad6066c16dbd 324 ledR = 0;
thetazzbot 1:ad6066c16dbd 325 wait(0.05);
thetazzbot 1:ad6066c16dbd 326 ledR = 1;
thetazzbot 1:ad6066c16dbd 327 wait(0.25);
thetazzbot 1:ad6066c16dbd 328 }
thetazzbot 1:ad6066c16dbd 329 }
thetazzbot 1:ad6066c16dbd 330 }
thetazzbot 1:ad6066c16dbd 331 else if (needReset)
thetazzbot 1:ad6066c16dbd 332 {
thetazzbot 1:ad6066c16dbd 333 // connected, need to reset due to changes in config parameters -
thetazzbot 1:ad6066c16dbd 334 // flash red/green
thetazzbot 1:ad6066c16dbd 335 hb = !hb;
thetazzbot 1:ad6066c16dbd 336 ledR = (hb ? 0 : 1);
thetazzbot 1:ad6066c16dbd 337 ledG = (hb ? 1 : 0);
thetazzbot 1:ad6066c16dbd 338 ledB = 0;
thetazzbot 1:ad6066c16dbd 339 }
thetazzbot 1:ad6066c16dbd 340 else
thetazzbot 1:ad6066c16dbd 341 {
thetazzbot 1:ad6066c16dbd 342 // connected - flash blue/green
thetazzbot 1:ad6066c16dbd 343 hb = !hb;
thetazzbot 1:ad6066c16dbd 344 ledR = 1;
thetazzbot 1:ad6066c16dbd 345 ledG = (hb ? 0 : 1);
thetazzbot 1:ad6066c16dbd 346 ledB = (hb ? 1 : 0);
thetazzbot 1:ad6066c16dbd 347 }
thetazzbot 1:ad6066c16dbd 348
thetazzbot 1:ad6066c16dbd 349 // reset the heartbeat timer
thetazzbot 1:ad6066c16dbd 350 hbTimer.reset();
thetazzbot 1:ad6066c16dbd 351 ++hbcnt;
thetazzbot 1:ad6066c16dbd 352 }
thetazzbot 1:ad6066c16dbd 353
thetazzbot 1:ad6066c16dbd 354 }
thetazzbot 1:ad6066c16dbd 355 }