feat(USB): runtime wired CRSF disable + ESP-NOW TX diag counters#10
Open
snokvist wants to merge 2 commits intofeature/parser-state-quiet-gatefrom
Open
feat(USB): runtime wired CRSF disable + ESP-NOW TX diag counters#10snokvist wants to merge 2 commits intofeature/parser-state-quiet-gatefrom
snokvist wants to merge 2 commits intofeature/parser-state-quiet-gatefrom
Conversation
Adds two diagnostic / triage knobs surfacing a separate observed bug:
when the wired CRSF receiver is connected (UART1 RX active, drainer
emitting `MSP_WAYBEAM_WIRED_CRSF` 0x0044 over USB-CDC at ~50 Hz),
ESP-NOW outbound `MSP_ELRS_BACKPACK_SET_PTR` (0x0383) and
`MSP_ELRS_BACKPACK_SET_HEAD_TRACKING` (0x030D) injection from the host
no longer reaches the bound peer. Disconnecting the GPIO 20 RX wire
restores ESP-NOW immediately. Existing comment at OnDataRecv flags the
same C3-single-core sensitivity ("we DO NOT call Serial.write from this
WiFi-task callback because that starves the main loop's Serial.read")
— this looks like the symmetric problem: heavy main-loop Serial.write
from the wired drainer starving the WiFi task's ESP-NOW outbound queue.
This commit ships the diagnostic surface and a triage gate; the actual
root-cause fix (most likely a `taskYIELD()` / `vTaskDelay(1)` after
each drain + batched writes to cut the call rate) is a follow-up that
the diagnostics here will validate.
* `MSP_WAYBEAM_WIRED_CRSF_CTRL` (0x0046) — host <-> device. Empty
payload = query, `[1]`/`[0]` = enable/disable. Reply mirrors current
state. Persisted to NVS namespace `waybeam_bp` key `wired_en` so a
disable survives reboot. When disabled: `WiredCrsfPoll()` returns
immediately, no UART1 reads, no `0x0044` emit, no Serial.write from
this path. Backwards-compat default = enabled.
* `MSP_WAYBEAM_DIAG` (0x0047) — host -> device query. Reply payload:
u32 espnow_tx_ok, u32 espnow_tx_fail, i32 espnow_tx_last_err, u8
wired_crsf_enabled. Counters bumped inside `sendMSPViaEspnow` from
the previously-discarded `esp_now_send` return code.
* `tools/backpack_cli.py wired on|off|<empty>` and
`tools/backpack_cli.py diag` (in companion Android repo).
Build clean: ESP32C3_TX_Backpack_via_USB env, flash unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
WiredCrsfSetEnabled previously only gated the app-level poll + drainer. The UART1 hardware was still attached to GPIO 20/21 with the RX ISR firing on every received byte. That made the runtime disable silently ineffective for any test that involved a connected ELRS RX still clocking data into GPIO 20. Now SetEnabled(false) calls gWiredUart.end() — full driver teardown, pins released, no RX ISR. SetEnabled(true) re-attaches via begin(). WiredCrsfInit also respects the persisted state at boot: when NVS says disabled, UART1 is never even attached. Required for the runtime A/B test to be a real off-switch: with this in place, software disable is equivalent to physically pulling the GPIO 20 wire. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two diagnostic / deployment knobs that fell out of an investigation into ESP-NOW silently failing under load. The investigation itself did not find a firmware bug — root cause turned out to be RF interference between an ELRS receiver placed too close to the C3 SuperMini's WiFi antenna (
espnow_tx_okclimbed cleanly while the bound peer received nothing). Even though we don't need either knob to fix the RFI issue, both are independently valuable enough to ship:MSP_WAYBEAM_WIRED_CRSF_CTRL(0x0046) — runtime enable/disable for the wired CRSF receiver path, persisted to NVS (waybeam_bp/wired_en). Empty payload = query;[1]/[0]= set; reply mirrors current state. Useful as a deployment knob: builds without a wired CRSF receiver shouldn't pay the UART1 polling cost, and there's no way to opt out at runtime today.MSP_WAYBEAM_DIAG(0x0047) — read-only firmware counters:espnow_tx_ok(u32),espnow_tx_fail(u32),espnow_tx_last_err(i32),wired_crsf_enabled(u8). Counters bumped from the previously-discardedesp_now_sendreturn code. Useful as production observability: separates queue-acceptance from radio-level failure, which is exactly the diagnostic that ruled out queue starvation in this investigation.Behaviour notes
The disable toggle is a hard hardware off-switch:
WiredCrsfSetEnabled(false)callsgWiredUart.end()— pins released, RX ISR detached.WiredCrsfInit()honours the persisted disable state and never callsgWiredUart.begin()at boot when disabled.0x0044emit, no Serial.write from this path. Software disable is equivalent to physically pulling the GPIO 20 wire (verified empirically).Companion: Android tooling
tools/backpack_cli.py wired on|off(or no-arg query) andtools/backpack_cli.py diaginsnokvist/Waybeam-backpack-android— quick CLI access from a host plugged into the C3.Targeting
This PR targets
feature/parser-state-quiet-gate(the open #9), notmaster, because both branches have to merge together — they shareTx_main.cpplines. After #9 merges to master, I'll retarget this PR tomaster.Test plan
ESP32C3_TX_Backpack_via_USBenv, flash unchanged.MSP_WAYBEAM_DIAGcounters round-trip and increment.Memory note
backpack_rx_close_rf_interference.mdinwaybeam-coordinationrecords the RFI lesson so future investigations don't burn the same hours we did.🤖 Generated with Claude Code