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.
Dependencies: FastAnalogIn FastIO USBDevice mbed FastPWM SimpleDMA
Fork of Pinscape_Controller by
Diff: main.cpp
- Revision:
- 18:5e890ebd0023
- Parent:
- 17:ab3cec0c8bf4
- Child:
- 19:054f8af32fce
--- a/main.cpp Fri Feb 27 04:14:04 2015 +0000
+++ b/main.cpp Fri Feb 27 07:41:29 2015 +0000
@@ -153,9 +153,10 @@
// long yellow/green = everything's working, but the plunger hasn't
// been calibrated; follow the calibration procedure described above.
// This flash mode won't appear if the CCD has been disabled. Note
-// that the device can't tell whether a CCD is physically attached,
-// so you should use the config command to disable the CCD software
-// features if you won't be attaching a CCD.
+// that the device can't tell whether a CCD is physically attached;
+// if you don't have a CCD attached, you can set the appropriate option
+// in config.h or use the Windows config tool to disable the CCD
+// software features.
//
// alternating blue/green = everything's working
//
@@ -442,6 +443,19 @@
// button input map array
DigitalIn *buttonDigIn[32];
+// button state
+struct ButtonState
+{
+ // current on/off state
+ int pressed;
+
+ // Sticky time remaining for current state. When a
+ // state transition occurs, we set this to a debounce
+ // period. Future state transitions will be ignored
+ // until the debounce time elapses.
+ int t;
+} buttonState[32];
+
// timer for button reports
static Timer buttonTimer;
@@ -462,24 +476,67 @@
}
-// read the raw button input state
-uint32_t readButtonsRaw()
+// read the button input state
+uint32_t readButtons()
{
// start with all buttons off
uint32_t buttons = 0;
+ // figure the time elapsed since the last scan
+ int dt = buttonTimer.read_ms();
+
+ // reset the timef for the next scan
+ buttonTimer.reset();
+
// scan the button list
uint32_t bit = 1;
- for (int i = 0 ; i < countof(buttonDigIn) ; ++i, bit <<= 1)
+ DigitalIn **di = buttonDigIn;
+ ButtonState *bs = buttonState;
+ for (int i = 0 ; i < countof(buttonDigIn) ; ++i, ++di, ++bs, bit <<= 1)
{
- if (buttonDigIn[i] != 0 && !buttonDigIn[i]->read())
- buttons |= bit;
+ // read this button
+ if (*di != 0)
+ {
+ // deduct the elapsed time since the last update
+ // from the button's remaining sticky time
+ bs->t -= dt;
+ if (bs->t < 0)
+ bs->t = 0;
+
+ // If the sticky time has elapsed, note the new physical
+ // state of the button. If we still have sticky time
+ // remaining, ignore the physical state; the last state
+ // change persists until the sticky time elapses so that
+ // we smooth out any "bounce" (electrical transients that
+ // occur when the switch contact is opened or closed).
+ if (bs->t == 0)
+ {
+ // get the new physical state
+ int pressed = !(*di)->read();
+
+ // update the button's logical state if this is a change
+ if (pressed != bs->pressed)
+ {
+ // store the new state
+ bs->pressed = pressed;
+
+ // start a new sticky period for debouncing this
+ // state change
+ bs->t = 1000;
+ }
+ }
+
+ // if it's pressed, OR its bit into the state
+ if (bs->pressed)
+ buttons |= bit;
+ }
}
- // return the button list
+ // return the new button list
return buttons;
}
+#if 0
// Read buttons with debouncing.
//
// Debouncing is the process of filtering out transients from button
@@ -505,7 +562,7 @@
uint32_t b;
// Change mask at this report. This is a bit mask of the buttons
- // that *didn't* change on this report. AND this mask with a
+ // that changed on this report. AND the NOT of this mask with a
// new reading to filter buttons out of the new reading that
// changed on this report.
uint32_t m;
@@ -524,19 +581,20 @@
// start timing the next interval
buttonTimer.reset();
- // mask out changes for any buttons that changed state within the
- // past 50ms
- for (int i = 1 ; i < countof(readings) && ms < 50 ; ++i)
+ // Mask out changes for any buttons that changed state within the
+ // past 50ms. This ensures that each state change sticks for at
+ // least 50ms, which should be long enough to be sure that a change
+ // that reverses a prior change isn't just a transient.
+ for (int i = 1, j = ri - 1 ; i < countof(readings) && ms < 50 ; ++i, --j)
{
// find the next prior reading, wrapping in the circular buffer
- int j = ri - i;
if (j < 0)
j = countof(readings) - 1;
reading *rj = &readings[j];
// For any button that changed state in the prior reading 'rj',
// remove any new change and restore it to its 'rj' state.
- b &= rj->m;
+ b &= ~rj->m;
b |= rj->b;
// add in the time to the next prior report
@@ -547,7 +605,7 @@
uint32_t m = b ^ bPrv;
// save the change mask and changed button vector in our history entry
- r->m = ~m;
+ r->m = m;
r->b = b & m;
// save this as the prior report
@@ -561,6 +619,7 @@
// return the debounced result
return b;
}
+#endif
// ---------------------------------------------------------------------------
//
@@ -917,21 +976,6 @@
// ---------------------------------------------------------------------------
//
-// CCD read interval callback. When reading the CCD, we'll call this
-// several times over the course of the read loop to refresh the button
-// states. This allows us to debounce the buttons while the long CCD
-// read cycle is taking place, so that we can reliably report button
-// states after each CCD read cycle. (The read cycle takes about 30ms,
-// which should be enough time to reliably debounce the buttons.)
-//
-void ccdReadCB(void *)
-{
- // read the keyboard
- readButtonsDebounced();
-}
-
-// ---------------------------------------------------------------------------
-//
// Include the appropriate plunger sensor definition. This will define a
// class called PlungerSensor, with a standard interface that we use in
// the main loop below. This is *kind of* like a virtual class interface,
@@ -1185,6 +1229,11 @@
Timer lbTimer;
lbTimer.start();
+ // Launch Ball simulated push timer. We start this when we simulate
+ // the button push, and turn off the simulated button when enough time
+ // has elapsed.
+ Timer lbBtnTimer;
+
// Simulated button states. This is a vector of button states
// for the simulated buttons. We combine this with the physical
// button states on each USB joystick report, so we will report
@@ -1245,12 +1294,11 @@
// host requests
for (;;)
{
- // Look for an incoming report. Continue processing input as
- // long as there's anything pending - this ensures that we
- // handle input in as timely a fashion as possible by deferring
- // output tasks as long as there's input to process.
+ // Look for an incoming report. Process a few input reports in
+ // a row, but stop after a few so that a barrage of inputs won't
+ // starve our output event processing.
HID_REPORT report;
- while (js.readNB(&report))
+ for (int rr = 0 ; rr < 4 && js.readNB(&report) ; ++rr)
{
// all Led-Wiz reports are 8 bytes exactly
if (report.length == 8)
@@ -1559,8 +1607,10 @@
}
// Check for a simulated Launch Ball button press, if enabled
- if (ZBLaunchBallPort != 0 && wizOn[ZBLaunchBallPort-1])
+ if (ZBLaunchBallPort != 0)
{
+ const int cockThreshold = JOYMAX/3;
+ const int pushThreshold = int(-JOYMAX/3 * LaunchBallPushDistance);
int newState = lbState;
switch (lbState)
{
@@ -1568,9 +1618,9 @@
// Base state. If the plunger is pulled back by an inch
// or more, go to "cocked" state. If the plunger is pushed
// forward by 1/4" or more, go to "launch" state.
- if (znew >= JOYMAX/3)
+ if (znew >= cockThreshold)
newState = 1;
- else if (znew < -JOYMAX/12)
+ else if (znew <= pushThreshold)
newState = 3;
break;
@@ -1582,7 +1632,7 @@
// to trigger a launch.
if (firing || znew <= 0)
newState = 3;
- else if (znew < JOYMAX/3)
+ else if (znew < cockThreshold)
newState = 2;
break;
@@ -1590,8 +1640,11 @@
// Uncocked state. If the plunger is more than an inch
// retracted, return to cocked state. If we've been in
// the uncocked state for more than half a second, return
- // to the base state.
- if (znew >= JOYMAX/3)
+ // to the base state. This allows the user to return the
+ // plunger to rest without triggering a launch, by moving
+ // it at manual speed to the rest position rather than
+ // releasing it.
+ if (znew >= cockThreshold)
newState = 1;
else if (lbTimer.read_ms() > 500)
newState = 0;
@@ -1600,7 +1653,7 @@
case 3:
// Launch state. If the plunger is no longer pushed
// forward, switch to launch rest state.
- if (znew > -JOYMAX/24)
+ if (znew >= 0)
newState = 4;
break;
@@ -1609,7 +1662,7 @@
// again, switch back to launch state. If not, and we've
// been in this state for at least 200ms, return to the
// default state.
- if (znew < -JOYMAX/12)
+ if (znew <= pushThreshold)
newState = 3;
else if (lbTimer.read_ms() > 200)
newState = 0;
@@ -1617,11 +1670,18 @@
}
// change states if desired
+ const uint32_t lbButtonBit = (1 << (LaunchBallButton - 1));
if (newState != lbState)
{
- // if we're entering Launch state, press the Launch Ball button
- if (newState == 3 && lbState != 4)
- simButtons |= (1 << (LaunchBallButton - 1));
+ // if we're entering Launch state, and the ZB Launch Ball
+ // LedWiz signal is turned on, simulate a Launch Ball button
+ // press
+ if (newState == 3 && lbState != 4 && wizOn[ZBLaunchBallPort-1])
+ {
+ lbBtnTimer.reset();
+ lbBtnTimer.start();
+ simButtons |= lbButtonBit;
+ }
// if we're switching to state 0, release the button
if (newState == 0)
@@ -1633,6 +1693,17 @@
// start timing in the new state
lbTimer.reset();
}
+
+ // if the simulated Launch Ball button press is in effect,
+ // and either it's been in effect too long or the ZB Launch
+ // Ball signal is no longer active, turn off the button
+ if ((simButtons & lbButtonBit) != 0
+ && (!wizOn[ZBLaunchBallPort-1] || lbBtnTimer.read_ms() > 250))
+ {
+ lbBtnTimer.stop();
+ simButtons &= ~lbButtonBit;
+ }
+
}
// If a firing event is in progress, generate synthetic reports to
@@ -1719,7 +1790,7 @@
}
// update the buttons
- uint32_t buttons = readButtonsDebounced();
+ uint32_t buttons = readButtons();
// If it's been long enough since our last USB status report,
// send the new report. We throttle the report rate because
