Only test/fixtures/cli_reply_text.json conflicted; messages and profiles
were identical, source token hashes regenerated for the merged sources.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lazy mode treated any failed read of /presets as an empty store, so the
next countdown, revert or commit save replaced the user's slots with a
fresh table. It now remembers whether /presets holds this node's table
(loaded at boot or saved since). Once stored, a failed read is
"unreadable": get/add/del/load preset reply "Error: presets unreadable",
the pending revert or commit still runs from the RAM mirror, and save()
refuses until a read succeeds, leaving the stored bytes untouched.
Seeding now follows resident exactly: begin() seeds an empty table; at
run time the default is only added while /presets was never written, so
a table emptied by "del preset" stays empty until reboot in both modes.
Lazy members are reordered and the flags packed so the object is 32 B on
32-bit targets (static_assert tightened to <= 32).
Tests (both modes): del-all stays empty until reboot. Lazy only: corrupt
store with a pending timeout, short store with a commit, store vanishing
with a pending load, and a never-stored missing store.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RAK_4631_repeater (both sensor + LoRa OTA qualification images) now
builds presets in lazy mode (MESH_RADIO_PRESETS_RESIDENT=0) instead of
dropping them. Full sensors runtime RAM: 83,164 available / 83,136
required (PASS; upstream 83,204). RAK_4631_companion_radio_full keeps
presets off (flash). Docs describe the storage switch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RAK_4631_companion_radio_full has no flash for presets (~3.9 KB over its
linker region even after shrinking), and the RAK_4631_repeater Full
sensors + LoRa OTA image has 68 bytes of runtime-RAM headroom against a
~220-byte resident preset table. Both set MESH_ENABLE_RADIO_PRESETS=0;
gates and reserves are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
They lacked the hosted-doc banner (CI hosted-doc-links) and are working
notes, not user documentation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Companions (T114, Cardputer) handle get/add/load/del preset from local
operators only: USB/TCP terminal, framed command 0x42, browser CLI and the
UI. An authorized LoRa CLI command (nonzero sender timestamp) is not
consumed, since companions have no revert path. Loads go through
applyAndSaveRadioParams with the same replies as "set radio". Exposes
loadRadioPreset/activeRadioPreset/radioPresetTable for the Cardputer UI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CommonCLI.cpp included RadioPresetFile.h only on nRF52/STM32; ESP32 and
RP2040 builds could not see the file helpers. Include it unconditionally.
- Room server and sensor now commit a pending remote preset load on a
successful strict-admin login, like the repeater; drop the doc caveat.
- Rename RadioPresetTable::NAME_MAX to MAX_NAME_LEN: newlib/ESP-IDF
<limits.h> defines NAME_MAX as a macro. Host harnesses now predefine
NAME_MAX so such collisions fail on host too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CommonCLI owns a RadioPresetCLI wired through static hook trampolines
(current/accepts/apply via the existing primary-radio save+apply path,
/presets storage via RadioPresetFile.h). begin() runs at the end of
loadPrefs, loop() next to the radio profiles, and dispatch precedes
radio profiles with remote = sender_timestamp != 0. A fresh strict-admin
repeater login (LoRa or ESP-NOW bridge) commits a pending remote load.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>