Skip to content

v0.4.9

Choose a tag to compare

@mcdax mcdax released this 10 May 09:03
· 14 commits to main since this release

Fixed

Two regressions where belt_state derived as STOPPED after a successful pause instead of PAUSED. Both were found by running tests/stress_dynamic.py against a real KS-HD-Z1D and verified by the pause_resume scenario invariants (16/16 OK after the fixes; ~50% before).

  1. _paused deceleration race in _on_treadmill_data. The previous version cleared _paused on every Treadmill Data frame with speed > 0. Pause sets the flag at speed ≈ 2.5; the ~5–10 s deceleration to zero emits dozens of speed > 0 frames, each clearing the flag, so by the time speed reached 0 the _paused branch was dead and belt_state derived as STOPPED. The flag is now set/cleared exclusively by _on_machine_status in response to FM Status events; _on_treadmill_data only reads it.

  2. "First 2ADA event after subscribe" filter dropped genuine ack state. The defensive filter that drops the first 2ADA event (added because the firmware replays its prior state on CCCD-subscribe, which would flap last_fm_event on every reconnect) over-filtered when the user's first command after a fresh connect produced an ack as the first event — e.g. pause() right after a reconnect → FM Status STOPPED_OR_PAUSED + PAUSE arrives as the first event. The ack waiter got woken (so pause() returned True), but _paused was never set, and belt_state derived as STOPPED. Heuristic: if the first event matches _status_ack_expected_opcode, treat as the real ack and apply state. Otherwise skip as before.

Refs walkingpad-controller#2.