Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
Diff: main.cpp
- Revision:
- 99:8139b0c274f4
- Parent:
- 98:4df3c0f7e707
- Child:
- 100:1ff35c07217c
--- a/main.cpp Fri Mar 01 23:53:59 2019 +0000 +++ b/main.cpp Sat Mar 02 21:05:43 2019 +0000 @@ -10,7 +10,7 @@ * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILIT Y, FITNESS FOR A PARTICULAR PURPOSE AND +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -1066,12 +1066,9 @@ // for the PWM duty cycle of the physical output. uint8_t params; - // Full-power time mapping. This maps from the 4-bit (0..15) time value - // in the parameters to the number of microseconds. - static const uint32_t paramToTime_us[]; - - // Figure the initial full-power time in microseconds - inline uint32_t fullPowerTime_us() const { return paramToTime_us[params >> 4]; } + // Figure the initial full-power time in microseconds: 50ms * (1+N), + // where N is the high 4 bits of the parameter byte. + inline uint32_t fullPowerTime_us() const { return 50000*(1 + ((params >> 4) & 0x0F)); } // Figure the hold power PWM level (0-255) inline uint8_t holdPower() const { return (params & 0x0F) * 17; } @@ -1093,37 +1090,15 @@ Timer LwFlipperLogicOut::timer; LwFlipperLogicOut **LwFlipperLogicOut::pending; uint8_t LwFlipperLogicOut::nPending; -const uint32_t LwFlipperLogicOut::paramToTime_us[] = { - 1000, - 2000, - 5000, - 10000, - 20000, - 40000, - 80000, - 100000, - 150000, - 200000, - 300000, - 400000, - 500000, - 600000, - 700000, - 800000 -}; - -// Minimum On Time output. This is a filter output that we layer on -// a physical output to force the underlying output to stay on for a -// minimum interval. This can be used for devices that need to be on -// for a certain amount of time to trigger their full effect, such as -// slower solenoids or contactors. -class LwMinTimeOut: public LwOut + +// Chime Logic. This is a filter output that we layer on a physical +// output to set a minimum and maximum ON time for the output. +class LwChimeLogicOut: public LwOut { public: - // Set up the output. 'param' is the configuration parameter - // for the mininum time span. - LwMinTimeOut(LwOut *o, uint8_t param) - : out(o), param(param) + // Set up the output. 'params' encodes the minimum and maximum time. + LwChimeLogicOut(LwOut *o, uint8_t params) + : out(o), params(params) { // initially OFF state = 0; @@ -1190,13 +1165,42 @@ break; case 3: - // We're out of the minimum ON interval, so we can set any new - // level, including fully off. Pass the new power level through - // to the port. + // We're after the minimum ON interval and before the maximum + // ON time limit. We can set any new level, including fully off. + // Pass the new power level through to the port. out->set(level); // if the port is now off, return to state 0 (OFF) if (level == 0) + { + // return to the OFF state + state = 0; + + // If we have a timer pending, remove it. A timer will be + // pending if we have a non-infinite maximum on time for the + // port. + for (int i = 0 ; i < nPending ; ++i) + { + // is this us? + if (pending[i] == this) + { + // remove myself by replacing the slot with the + // last list entry + pending[i] = pending[--nPending]; + + // no need to look any further + break; + } + } + } + break; + + case 4: + // We're after the maximum ON time. The physical port stays off + // during this interval, so we don't pass any changes through to + // the physical port. When the client sets the level to 0, we + // turn off the logical port and reset to state 0. + if (level == 0) state = 0; break; } @@ -1213,12 +1217,12 @@ { // if this port is active and marked as Flipper Logic, count it if (cfg.outPort[i].typ != PortTypeDisabled - && (cfg.outPort[i].flags & PortFlagMinOnTime) != 0) + && (cfg.outPort[i].flags & PortFlagChimeLogic) != 0) ++n; } // allocate space for the pending timer list - pending = new LwMinTimeOut*[n]; + pending = new LwChimeLogicOut*[n]; // there's nothing in the pending list yet nPending = 0; @@ -1239,27 +1243,36 @@ for (int i = 0 ; i < nPending ; ) { // get the port - LwMinTimeOut *port = pending[i]; + LwChimeLogicOut *port = pending[i]; // assume we'll keep it bool remove = false; - // check if we're in the minimum ON period for the port - if (port->state == 1 || port->state == 2) + // check our state + switch (port->state) { - // we are - check if the minimum ON time has elapsed + case 1: // initial minimum ON time, port logically on + case 2: // initial minimum ON time, port logically off + // check if the minimum ON time has elapsed if (uint32_t(t - port->t0) > port->minOnTime_us()) { // This port has completed its initial ON interval, so // it advances to the next state. if (port->state == 1) { - // The port is logically on, so advance to state 3, - // "on past minimum initial time". The underlying - // port is already at its proper level, since we pass - // through non-zero power settings to the underlying - // port throughout the initial ON interval. + // The port is logically on, so advance to state 3. + // The underlying port is already at its proper level, + // since we pass through non-zero power settings to the + // underlying port throughout the initial minimum time. + // The timer stays active into state 3. port->state = 3; + + // Special case: maximum on time 0 means "infinite". + // There's no need for a timer in this case; we'll + // just stay in state 3 until the client turns the + // port off. + if (port->maxOnTime_us() == 0) + remove = true; } else { @@ -1272,11 +1285,29 @@ // return to state 0 (OFF) port->state = 0; + + // we're done with the timer + remove = true; } + } + break; + + case 3: // between minimum ON time and maximum ON time + // check if the maximum ON time has expired + if (uint32_t(t - port->t0) > port->maxOnTime_us()) + { + // The maximum ON time has expired. Turn off the physical + // port. + port->out->set(0); - // we're done with the timer + // Switch to state 4 (logically ON past maximum time) + port->state = 4; + + // Remove the timer on this port. This port simply stays + // in state 4 until the client turns off the port. remove = true; } + break; } // if desired, remove the port from the timer list @@ -1308,14 +1339,36 @@ // Current port state: // // 0 = off - // 1 = initial minimum ON interval, logical port is ON - // 2 = initial minimum ON interval, logical port is OFF - // 3 = past the minimum ON interval + // 1 = in initial minimum ON interval, logical port is on + // 2 = in initial minimum ON interval, logical port is off + // 3 = in interval between minimum and maximum ON times + // 4 = after the maximum ON interval + // + // The "logical" on/off state of the port is the state set by the + // client. The "physical" state is the state of the underlying port. + // The relationships between logical and physical port state, and the + // effects of updates by the client, are as follows: + // + // State | Logical | Physical | Client set on | Client set off + // ----------------------------------------------------------- + // 0 | Off | Off | phys on, -> 1 | no effect + // 1 | On | On | no effect | -> 2 + // 2 | Off | On | -> 1 | no effect + // 3 | On | On | no effect | phys off, -> 0 + // 4 | On | On | no effect | phys off, -> 0 + // + // The polling routine makes the following transitions when the current + // time limit expires: + // + // 1: at end of minimum ON, -> 3 (or 4 if max == infinity) + // 2: at end of minimum ON, port off, -> 0 + // 3: at end of maximum ON, port off, -> 4 // uint8_t state; - // Configuration parameter. This encodes the minimum ON time. - uint8_t param; + // Configuration parameters byte. This encodes the minimum and maximum + // ON times. + uint8_t params; // Timer. This is a shared timer for all of the minimum ON time ports. // When we transition from OFF to ON, we note the current time on this @@ -1325,22 +1378,30 @@ // translaton table from timing parameter in config to minimum ON time static const uint32_t paramToTime_us[]; - // Figure the minimum ON time - inline uint32_t minOnTime_us() const { return paramToTime_us[param & 0x0F]; } + // Figure the minimum ON time. The minimum ON time is given by the + // low-order 4 bits of the parameters byte, which serves as an index + // into our time table. + inline uint32_t minOnTime_us() const { return paramToTime_us[params & 0x0F]; } + + // Figure the maximum ON time. The maximum time is the high 4 bits + // of the parameters byte. This is an index into our time table, but + // 0 has the special meaning "infinite". + inline uint32_t maxOnTime_us() const { return paramToTime_us[((params >> 4) & 0x0F)]; } // Pending timer list. Whenever one of our ports transitions from OFF // to ON, we add it to this list. We scan this list in our polling // routine to find ports that have reached the ends of their initial // ON intervals. - static LwMinTimeOut **pending; + static LwChimeLogicOut **pending; static uint8_t nPending; }; // Min Time Out statics -Timer LwMinTimeOut::timer; -LwMinTimeOut **LwMinTimeOut::pending; -uint8_t LwMinTimeOut::nPending; -const uint32_t LwMinTimeOut::paramToTime_us[] = { +Timer LwChimeLogicOut::timer; +LwChimeLogicOut **LwChimeLogicOut::pending; +uint8_t LwChimeLogicOut::nPending; +const uint32_t LwChimeLogicOut::paramToTime_us[] = { + 0, // for the max time, this means "infinite" 1000, 2000, 5000, @@ -1349,7 +1410,6 @@ 40000, 80000, 100000, - 150000, 200000, 300000, 400000, @@ -1847,7 +1907,7 @@ int activeLow = flags & PortFlagActiveLow; int gamma = flags & PortFlagGamma; int flipperLogic = flags & PortFlagFlipperLogic; - int hasMinOnTime = flags & PortFlagMinOnTime; + int chimeLogic = flags & PortFlagChimeLogic; // cancel gamma on flipper logic ports if (flipperLogic) @@ -1964,9 +2024,11 @@ if (flipperLogic) lwp = new LwFlipperLogicOut(lwp, pc.flipperLogic); - // Layer on the Minimum On Time if desired - if (hasMinOnTime) - lwp = new LwMinTimeOut(lwp, pc.minOnTime); + // Layer on Chime Logic if desired. Note that Chime Logic and + // Flipper Logic are mutually exclusive, and Flipper Logic takes + // precedence, so ignore the Chime Logic bit if both are set. + if (chimeLogic && !flipperLogic) + lwp = new LwChimeLogicOut(lwp, pc.flipperLogic); // If it's a noisemaker, layer on a night mode switch if (noisy) @@ -1996,9 +2058,9 @@ // initialize the output pin array void initLwOut(Config &cfg) { - // Initialize the Flipper Logic and Minimum On Time outputs + // Initialize the Flipper Logic and Chime Logic outputs LwFlipperLogicOut::classInit(cfg); - LwMinTimeOut::classInit(cfg); + LwChimeLogicOut::classInit(cfg); // Count the outputs. The first disabled output determines the // total number of ports. @@ -6025,7 +6087,7 @@ true, // we support the new accelerometer settings true, // we support the "flash write ok" status bit in joystick reports true, // we support the configurable joystick report timing features - true, // we use the new flipper logic timing table + true, // chime logic is supported mallocBytesFree()); // remaining memory size break; @@ -6609,9 +6671,9 @@ // update PWM outputs pollPwmUpdates(); - // update Flipper Logic and Min On Time outputs + // update Flipper Logic and Chime Logic outputs LwFlipperLogicOut::poll(); - LwMinTimeOut::poll(); + LwChimeLogicOut::poll(); // poll the accelerometer accel.poll(); @@ -6980,9 +7042,9 @@ // try to recover the connection js.recoverConnection(); - // update Flipper Logic and Min Out Time outputs + // update Flipper Logic and Chime Logic outputs LwFlipperLogicOut::poll(); - LwMinTimeOut::poll(); + LwChimeLogicOut::poll(); // send TLC5940 data if necessary if (tlc5940 != 0)