Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
Diff: main.cpp
- Revision:
- 86:e30a1f60f783
- Parent:
- 85:3c28aee81cde
- Child:
- 87:8d35c74403af
--- a/main.cpp Fri Apr 14 17:56:54 2017 +0000 +++ b/main.cpp Fri Apr 21 18:50:37 2017 +0000 @@ -3811,6 +3811,21 @@ tv_relay->write(tv_relay_state != 0); } +// Does the current power status allow a reboot? We shouldn't reboot +// in certain power states, because some states are purely internal: +// we can't get enough information from the external power sensor to +// return to the same state later. Code that performs discretionary +// reboots should always check here first, and delay any reboot until +// we say it's okay. +static inline bool powerStatusAllowsReboot() +{ + // The only safe state for rebooting is state 1, idle/default. + // In other states, we can't reboot, because the external sensor + // and latch circuit doesn't give us enough information to return + // to the same state later. + return psu2_state == 1; +} + // PSU2 Status update routine. The main loop calls this from time // to time to update the power sensing state and carry out TV ON // functions. @@ -4082,23 +4097,21 @@ // NVM nvm; -// Configuration save state -const uint8_t SAVE_CONFIG_IDLE = 0; // no config save work pending -const uint8_t SAVE_CONFIG_ONLY = 1; // save is pending -const uint8_t SAVE_CONFIG_AND_REBOOT = 2; // save is pending, reboot after save -const uint8_t SAVE_CONFIG_REBOOT = 3; // save done, reboot is pending -uint8_t saveConfigState = SAVE_CONFIG_IDLE; - -// Save Config post-processing time, in seconds. -// -// If saveConfigState == SAVE_CONFIG_AND_REBOOT, we reboot after this -// time elapses. Otherwise, we simply clear the timer and clear the -// "succeeded" flag. -uint8_t saveConfigPostTime; +// Save Config followup time, in seconds. After a successful save, +// we leave the success flag on in the status for this interval. At +// the end of the interval, we reboot the device if requested. +uint8_t saveConfigFollowupTime; + +// is a reboot pending at the end of the config save followup interval? +uint8_t saveConfigRebootPending; // status flag for successful config save - set to 0x40 on success uint8_t saveConfigSucceededFlag; +// Timer for configuration change followup timer +ExtTimer saveConfigFollowupTimer; + + // For convenience, a macro for the Config part of the NVM structure #define cfg (nvm.d.c) @@ -4164,8 +4177,12 @@ return nvm_valid; } -// save the config - returns true on success, false on failure -bool saveConfigToFlash() +// Save the config. Returns true on success, false on failure. +// 'tFollowup' is the follow-up time in seconds. If the write is +// successful, we'll turn on the success flag in the status reports +// and leave it on for this interval. If 'reboot' is true, we'll +// also schedule a reboot at the end of the followup interval. +bool saveConfigToFlash(int tFollowup, bool reboot) { // make sure the plunger sensor isn't busy waitPlungerIdle(); @@ -4174,7 +4191,25 @@ uint32_t addr = uint32_t(configFlashAddr()); // save the data - return nvm.save(iap, addr); + if (nvm.save(iap, addr)) + { + // success - report the successful save in the status flags + saveConfigSucceededFlag = 0x40; + + // start the followup timer + saveConfigFollowupTimer.start(); + + // if a reboot is pending, flag it + saveConfigRebootPending = reboot; + + // return success + return true; + } + else + { + // return failure + return false; + } } // --------------------------------------------------------------------------- @@ -4373,6 +4408,9 @@ plungerSensor = new PlungerSensorNull(); break; } + + // set the jitter filter + plungerSensor->setJitterWindow(cfg.plunger.jitterWindow); } // Global plunger calibration mode flag @@ -4438,9 +4476,6 @@ // no history yet histIdx = 0; - - // clear the jitter filter - jfLow = jfHigh = 0; } // Collect a reading from the plunger sensor. The main loop calls @@ -4459,7 +4494,7 @@ { // Pull the previous reading from the history const PlungerReading &prv = nthHist(0); - + // If the new reading is within 1ms of the previous reading, // ignore it. We require a minimum time between samples to // ensure that we have a usable amount of precision in the @@ -4806,17 +4841,14 @@ hist[histIdx] = r; if (++histIdx >= countof(hist)) histIdx = 0; - - // apply the jitter filter - zf = jitterFilter(z); } } // Get the current value to report through the joystick interface int16_t getPosition() { - // return the last filtered reading - return zf; + // return the last reading + return z; } // get the timestamp of the current joystick report (microseconds) @@ -4910,35 +4942,6 @@ bool isFiring() { return firing == 3; } private: - // Apply the jitter filter - int jitterFilter(int z) - { - // If the new reading is within the current window, simply re-use - // the last filtered reading. - if (z >= jfLow && z <= jfHigh) - return zf; - - // The new reading is outside the current window. Push the window - // over so that the new reading is at the outside edge. - if (z < jfLow) - { - // the new reading is below the current window, so move the - // window such that the new reading is at the bottom of the window - jfLow = z; - jfHigh = z + cfg.plunger.jitterWindow; - } - else - { - // the new reading is above the current window, so move the - // window such that the new reading is at the top of the window - jfHigh = z; - jfLow = z - cfg.plunger.jitterWindow; - } - - // use the new reading exactly as read from the sensor - return z; - } - // Calibration state. During calibration mode, we watch for release // events, to measure the time it takes to complete the release // motion; and we watch for the plunger to come to reset after a @@ -4969,9 +4972,6 @@ // Auto-zeroing timer Timer autoZeroTimer; - // Current jitter filter window - int jfLow, jfHigh; - // set a firing mode inline void firingMode(int m) { @@ -5074,12 +5074,9 @@ // freely. PlungerReading f3r; - // next raw (unfiltered) Z value to report to the joystick interface - // (in joystick distance units) + // next Z value to report to the joystick interface (in joystick + // distance units) int z; - - // next filtered Z value to report to the joystick interface - int zf; }; // plunger reader singleton @@ -5414,16 +5411,15 @@ // we save the *nominal* unit number 1-16 in the config uint8_t newUnitNo = (data[2] & 0x0f) + 1; - // we'll need a reset if the LedWiz unit number is changing - bool needReset = (newUnitNo != cfg.psUnitNo); + // we'll need a reboot if the LedWiz unit number is changing + bool reboot = (newUnitNo != cfg.psUnitNo); // set the configuration parameters from the message cfg.psUnitNo = newUnitNo; cfg.plunger.enabled = data[3] & 0x01; // set the flag to do the save - saveConfigState = needReset ? SAVE_CONFIG_AND_REBOOT : SAVE_CONFIG_ONLY; - saveConfigPostTime = 0; + saveConfigToFlash(0, reboot); } break; @@ -5475,9 +5471,7 @@ // data[2] = delay time in seconds // data[3] = flags: // 0x01 -> do not reboot - saveConfigState = - (data[3] & 0x01) != 0 ? SAVE_CONFIG_ONLY : SAVE_CONFIG_AND_REBOOT; - saveConfigPostTime = data[2]; + saveConfigToFlash(data[2], !(data[3] & 0x01)); break; case 7: @@ -5579,6 +5573,11 @@ // to update, and the remaining bytes give the new value, // in a variable-dependent format. configVarSet(data); + + // If updating the jitter window (variable 19), apply it immediately + // to the plunger sensor object + if (data[1] == 19) + plungerSensor->setJitterWindow(cfg.plunger.jitterWindow); } else if (data[0] == 67) { @@ -5836,8 +5835,10 @@ // reboot. Some PCs won't reconnect if we were left plugged in // during a power cycle on the PC, but fortunately a reboot on // the KL25Z will make the host notice us and trigger a reconnect. + // Don't do this if we're in a non-recoverable PSU2 power state. if (cfg.disconnectRebootTimeout != 0 - && connTimeoutTimer.read() > cfg.disconnectRebootTimeout) + && connTimeoutTimer.read() > cfg.disconnectRebootTimeout + && powerStatusAllowsReboot()) reboot(js, false, 0); // update the PSU2 power sensing status @@ -5933,9 +5934,6 @@ // start the PWM update polling timer polledPwmTimer.start(); - // Timer for configuration change followup timer - ExtTimer saveConfigPostTimer; - // we're all set up - now just loop, processing sensor reports and // host requests for (;;) @@ -6048,7 +6046,7 @@ // save the updated configuration cfg.plunger.cal.calibrated = 1; - saveConfigToFlash(); + saveConfigToFlash(0, false); } else if (calBtnState != 3) { @@ -6264,46 +6262,33 @@ } // if we have a reboot timer pending, check for completion - if (saveConfigPostTimer.isRunning() - && saveConfigPostTimer.read() > saveConfigPostTime) + if (saveConfigFollowupTimer.isRunning() + && saveConfigFollowupTimer.read() > saveConfigFollowupTime) { // if a reboot is pending, execute it now - if (saveConfigState == SAVE_CONFIG_REBOOT) - reboot(js); - - // done with the timer - reset it - saveConfigPostTimer.stop(); - saveConfigPostTimer.reset(); - - // clear the save-config success flag - saveConfigSucceededFlag = 0; - } - - // if a config save is pending, do it now - if (saveConfigState == SAVE_CONFIG_ONLY - || saveConfigState == SAVE_CONFIG_AND_REBOOT) - { - // save the configuration - if (saveConfigToFlash()) + if (saveConfigRebootPending) { - // report success in the status flags - saveConfigSucceededFlag = 0x40; - - // start the followup timer - saveConfigPostTimer.start(); - - // The save is no longer pending. Switch to reboot pending - // mode if desired. - saveConfigState = (saveConfigState == SAVE_CONFIG_AND_REBOOT ? - SAVE_CONFIG_REBOOT : SAVE_CONFIG_IDLE); + // Only reboot if the PSU2 power state allows it. If it + // doesn't, suppress the reboot for now, but leave the boot + // flags set so that we keep checking on future rounds. + // That way we should eventually reboot when the power + // status allows it. + if (powerStatusAllowsReboot()) + reboot(js); } else { - // save failed - return to idle state - saveConfigState = SAVE_CONFIG_IDLE; + // No reboot required. Exit the timed post-save state. + + // stop and reset the post-save timer + saveConfigFollowupTimer.stop(); + saveConfigFollowupTimer.reset(); + + // clear the post-save success flag + saveConfigSucceededFlag = 0; } } - + // if we're disconnected, initiate a new connection if (!connected) { @@ -6358,9 +6343,12 @@ // rebooting Windows, cycling power on the PC, or just a lost // USB connection. Rebooting the KL25Z seems to be the most // reliable way to get Windows to notice us again after one - // of these events and make it reconnect. + // of these events and make it reconnect. Only reboot if + // the PSU2 power status allows it - if not, skip it on this + // round and keep waiting. if (cfg.disconnectRebootTimeout != 0 - && reconnTimeoutTimer.read() > cfg.disconnectRebootTimeout) + && reconnTimeoutTimer.read() > cfg.disconnectRebootTimeout + && powerStatusAllowsReboot()) reboot(js, false, 0); // update the PSU2 power sensing status @@ -6409,8 +6397,10 @@ // The reboot timeout is in effect. If we've been incommunicado for // longer than the timeout, reboot. If we haven't reached the time // limit, keep running for now, and leave the OK timer running so - // that we can continue to monitor this. - if (jsOKTimer.read() > cfg.disconnectRebootTimeout) + // that we can continue to monitor this. Only reboot if the PSU2 + // power status allows it. + if (jsOKTimer.read() > cfg.disconnectRebootTimeout + && powerStatusAllowsReboot()) reboot(js, false, 0); } else