Skip to content

Fix battery-sleep reboot loop: sample tach idle level before arming SENSE - #114

Merged
TheAngryRaven merged 1 commit into
BETAfrom
claude/sleep-mode-battery-reboot-srcygo
Aug 2, 2026
Merged

Fix battery-sleep reboot loop: sample tach idle level before arming SENSE#114
TheAngryRaven merged 1 commit into
BETAfrom
claude/sleep-mode-battery-reboot-srcygo

Conversation

@TheAngryRaven

Copy link
Copy Markdown
Owner

Summary

Sleeping on battery reboot-looped within a second: System OFF entry hardcoded the tach wake pin as SENSE-LOW (assuming an idle-high line), but the tach pickup's Schmitt-inverter + optocoupler output stage idles the line low — DETECT was satisfied the instant System OFF was entered and the chip wake-reset immediately. USB sleep never showed it (a present cable parks in the charging loop, System OFF is never entered), and runtime RPM counting can't expose the polarity (one falling edge per spark pulse either way).

shutdownSystemOff() now samples the parked tach line (15 reads over ~30 ms) and arms SENSE for the opposite of the observed idle level, so both output-stage polarities sleep and wake correctly. The majority vote lives in the host-tested wake_cause unit (tachIdleIsHigh()); ties and floating/disconnected inputs resolve to idle-high, preserving the original SENSE-LOW arm. Buttons stay fixed SENSE-LOW (active-low by wiring).

Type of change

  • Bug fix (no user-visible behavior change beyond the fix)
  • New feature / behavior
  • Refactor (no behavior change)
  • Tests only
  • CI / tooling / docs
  • Breaking change (track files, log format, BLE protocol, or a removed mode)

How it was verified

  • Host unit tests pass (ctest --test-dir tests/build) — including new tachIdleIsHigh() cases (clear majorities, single-blip noise rejection, tie/empty-burst default)
  • clang-tidy clean (CI)
  • Compiles for the XIAO nRF52840 Sense (CI)
  • Tested on real hardware — please verify: sleep on battery stays asleep, and a pull-start wakes into race mode (proves the sampled-polarity wake fires on a real spark pulse)

Checklist

  • CHANGELOG.md updated under [Unreleased] (if user-visible)
  • ARCHITECTURE.md / CLAUDE.md updated (if a module or interface changed)
  • New testable logic has a matching test in tests/
  • Branch is focused — refactors / behavior / tests are not mixed together

Related issues

None filed — reported directly (battery-only instant reboot after sleep entry).

🤖 Generated with Claude Code

https://claude.ai/code/session_01BNr2KMMP1yjhPgdaUXHmGt


Generated by Claude Code

…ENSE

System OFF entry hardcoded the tach wake pin as SENSE-LOW, assuming the
line idles high under the pull-up. The tach pickup's Schmitt-inverter +
optocoupler output stage can idle low, in which case DETECT is satisfied
the instant System OFF is entered and the device wake-resets within a
second whenever it sleeps on battery. USB sleep was unaffected because a
present cable parks in the charging loop and never enters System OFF,
and runtime RPM counting can't expose the polarity (a spark pulse yields
exactly one falling edge either way), so only battery sleep showed it.

Shutdown now samples the parked tach line (15 reads over ~30 ms) and
arms SENSE for the opposite of the observed idle level. The majority
vote lives in the host-tested wake_cause unit (tachIdleIsHigh); a tie or
floating input resolves to idle-high, preserving the original SENSE-LOW
arm. Buttons stay fixed SENSE-LOW (active-low by wiring).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNr2KMMP1yjhPgdaUXHmGt
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Coverage — host-testable units

📂 Overall coverage

Metric Coverage
Lines 🟢 791/801 (98.8%)
Functions 🟢 83/83 (100.0%)
Branches 🟢 618/687 (90.0%)

📄 File coverage

File Lines Functions Branches
BirdsEye/camera_fsm.cpp 🟢 222/230 (96.5%) 🟢 20/20 (100.0%) 🟡 126/144 (87.5%)
BirdsEye/crc32.cpp 🟢 30/30 (100.0%) 🟢 4/4 (100.0%) 🟢 24/24 (100.0%)
BirdsEye/dovex_header.cpp 🟢 100/101 (99.0%) 🟢 6/6 (100.0%) 🔴 61/92 (66.3%)
BirdsEye/filename_validator.cpp 🟢 14/14 (100.0%) 🟢 1/1 (100.0%) 🟢 30/30 (100.0%)
BirdsEye/gps_stats.cpp 🟢 25/25 (100.0%) 🟢 3/3 (100.0%) 🟢 8/8 (100.0%)
BirdsEye/gps_status_page.cpp 🟢 25/25 (100.0%) 🟢 3/3 (100.0%) 🟢 24/24 (100.0%)
BirdsEye/gps_time.cpp 🟢 45/45 (100.0%) 🟢 6/6 (100.0%) 🟢 30/32 (93.8%)
BirdsEye/gps_validation.cpp 🟢 24/24 (100.0%) 🟢 2/2 (100.0%) 🟢 66/66 (100.0%)
BirdsEye/haversine.cpp 🟢 8/8 (100.0%) 🟢 1/1 (100.0%) ⚫ 0/0 (0.0%)
BirdsEye/insta360_protocol.cpp 🟢 140/140 (100.0%) 🟢 16/16 (100.0%) 🟡 86/98 (87.8%)
BirdsEye/lap_format.cpp 🟢 18/18 (100.0%) 🟢 1/1 (100.0%) 🟢 9/9 (100.0%)
BirdsEye/sat_bars.cpp 🟢 33/33 (100.0%) 🟢 2/2 (100.0%) 🟢 51/54 (94.4%)
BirdsEye/sd_access_policy.cpp 🟢 9/9 (100.0%) 🟢 3/3 (100.0%) 🟢 18/18 (100.0%)
BirdsEye/sd_format_page.cpp 🟢 25/25 (100.0%) 🟢 3/3 (100.0%) 🟢 25/26 (96.2%)
BirdsEye/sensoregg_protocol.cpp 🟢 44/45 (97.8%) 🟢 7/7 (100.0%) 🟢 33/34 (97.1%)
BirdsEye/tach_filter.cpp 🟢 15/15 (100.0%) 🟢 3/3 (100.0%) 🟡 7/8 (87.5%)
BirdsEye/wake_cause.cpp 🟢 14/14 (100.0%) 🟢 2/2 (100.0%) 🟢 20/20 (100.0%)

@TheAngryRaven
TheAngryRaven merged commit 4686121 into BETA Aug 2, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants