Companion CAD runtime toggle
Problem
The companion firmware hardcodes MyMesh::getCADEnabled() to return true
(examples/companion_radio/MyMesh.cpp), so hardware Channel Activity Detection
before TX is always on with no way to turn it off at runtime. Repeaters, room
servers, and sensors already expose get cad / set cad on|off through
CommonCLI backed by NodePrefs.cad_enabled, but the companion has no text CLI
and a separate NodePrefs struct, so it never got the toggle.
Goal
Make CAD a persisted, runtime-toggleable setting on the companion, reachable both from apps (binary frame protocol) and on-device (UI menu), defaulting to on so current behavior is preserved. Document the frame protocol addition so third-party companion apps can add the toggle.
Non-goals
- Changing the repeater/room/sensor CAD path (already works).
- Adding a general text CLI to the companion.
- Shipping the mobile app UI control. This spec covers firmware only; the official app and third-party apps consume the documented frame fields.
Delivery
Two phases. Phase 1 lands first and is independently useful.
- Phase 1 (frame protocol first): persisted pref,
getCADEnabled()reads it, live apply, frame get/set, docs. - Phase 2: on-device UI toggle across all four UI variants.
Design
Persisted preference (phase 1)
- Add
uint8_t cad_enabled = 1;toexamples/companion_radio/NodePrefs.h. - Persist in
examples/companion_radio/DataStore.cppby appending one byte afterdefault_scope_keyin bothsavePrefsandloadPrefsInt. - Appending at the end keeps existing saved-prefs files readable. A short read (old file with no CAD byte) leaves the default value 1 in place, so upgraders keep CAD on and gain the ability to turn it off.
- Initialize
cad_enabled = 1in the fresh-boot defaults path alongside the other prefs defaults.
Apply the preference (phase 1)
MyMesh::getCADEnabled()returns_prefs.cad_enabledinstead oftrue.- On change, apply live without a reboot by calling the radio wrapper's
setCADEnabled()(the same callDispatchermakes at init via_radio->setCADEnabled(getCADEnabled())). Confirm the exact accessor fromMyMeshduring implementation. - Remove the stale
// disabled by default, until configurablecomment.
App control surface: tuning-params frames (phase 1)
The companion is driven by binary frames. Wire CAD into the existing tuning-params get/set pair, both backward-compatibly.
CMD_SET_TUNING_PARAMS: read an optional trailing byte, length gated, for cad on/off. Apps that send only rx + af are unaffected. Save prefs and apply live.CMD_GET_TUNING_PARAMS/RESP_CODE_TUNING_PARAMS: append a trailing cad byte. Old apps read rx + af and ignore the extra byte.
Rationale for tuning-params over CMD_SET_OTHER_PARAMS: the "other params"
group is read back through RESP_CODE_SELF_INFO, which ends in an unbounded
node-name field, so there is no clean place for a trailing byte without
shifting existing fields and breaking current app parsers.
On-device UI toggle (phase 2)
- Add a CAD on/off item to the settings menu in all four UI variants:
ui-touch,ui-tiny,ui-orig,ui-new. - The item writes
_prefs.cad_enabled, saves prefs, and applies live, matching the pattern used by existing boolean toggles (for example GPS enabled).
Documentation (phase 1)
- Document the new CAD field in the companion frame-protocol reference so third-party app authors (for example Remote-Terminal-for-MeshCore) can add the toggle. Confirm the exact doc file during planning.
Backward compatibility
- Existing prefs files load unchanged. Missing CAD byte defaults to on.
- Existing apps keep working. Optional set byte and appended get byte are ignored by older clients.
- Default on preserves the behavior shipped by commit "enabled CAD for companion by default".
Testing
- Prefs round-trip: save then load preserves cad_enabled both on and off.
- Old-file load: a prefs file without the CAD byte loads with cad_enabled = 1.
- Frame set: sending
CMD_SET_TUNING_PARAMSwith and without the optional byte behaves correctly and toggles the radio live. - Frame get:
CMD_GET_TUNING_PARAMSreturns the appended byte; a legacy-length parser still reads rx + af. - Manual on-device: UI toggle flips CAD and persists across reboot (phase 2).
- Build check: companion firmware compiles for at least one representative env.