Commit Graph
3 Commits
Author SHA1 Message Date
ZephCore T096andClaude Sonnet 5 f8a4992ff0 prefs: encode led_brightness too, not just decode; fix pinned test layout
companionPrefsEncode()/serverPrefsEncode() never wrote the led_brightness
byte that companionPrefsDecode()/serverPrefsDecode() already read,
desyncing every field that follows it by one byte on the companion side
(wifi_enabled/wifi_ssid/wifi_pwd) and silently truncating the server
format by one byte. Caught by CI's ASan/UBSan run on the host regression
suite: an out-of-bounds read/write in the pinned layout tests.

Since led_brightness never existed upstream, nothing already accounted
for it: fixing only the encoder still leaves the pinned byte tables and
the documented 272/311-byte totals (COMPANION_PREFS_SIZE/
SERVER_PREFS_SIZE, used by the real prefs stores too, not just tests)
one byte short of what the encoder now actually produces.

- PrefsCodec.h: bump both size constants (272->273, 311->312).
- PrefsCodec.cpp: add the missing w.put() in both encoders, mirroring
  the position already used by both decoders.
- prefs_codec_tests.cpp: add led_brightness to both layout tables at its
  real file offset (shifts wifi_enabled/wifi_ssid/wifi_pwd by one byte
  on the companion side; server's is appended last, nothing else
  shifts), extend both historical-boundary length lists with the new
  full-format length, and give it a non-default value in sample() so
  the layout/roundtrip tests actually exercise it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-30 17:38:54 +02:00
ZephCore T096 1d33c7177f leds: persist brightness across reboots and firmware updates
leds.brightness (PWM-capable boards) was RAM-only since it was added: it
always reset to ZEPHCORE_LED_DEFAULT_BRIGHTNESS_PCT (10%) on every boot,
regardless of what a user had last set it to.

New field led_brightness on NodePrefs, following the exact same
append-only pattern as leds_radio_mode/leds_hb_mode added just before it:
offset 311 in RepeaterDataStore.cpp (repeater/room-server/observer,
shared file), offset 174 in ZephyrDataStore.cpp (companion). Both are
backward compatible by construction: a prefs file written before this
field existed simply leaves it at the initNodePrefs() default (10%),
which is exactly the behaviour every already-deployed node has today --
no special-casing needed to keep "10% on a new/not-yet-upgraded node" as
the effective default.

CommonCLI.cpp's "set leds.brightness" handler now writes the prefs field
and calls savePrefs(), same as the leds.radio/leds.hb handlers right
above it; "get leds.brightness" now reads from prefs instead of the RAM
getter directly, for the same reason those two already do (always in
sync, prefs is the source of truth). The four boot call sites
(main_companion.cpp, main_repeater.cpp, main_room_server.cpp,
main_observer.cpp) each gained a zephcore_led_set_brightness_pct() call
seeding the RAM cache from the persisted value, mirroring the existing
leds_radio_mode/leds_hb_mode lines right next to them.

Verified building for heltec_t096/nrf52840 (companion) and rak3401_1watt
(repeater), the two roles/datastores touched by this change.
2026-09-28 22:01:08 +02:00
liquidraver 38f815a0a1 server roles, event loops, companion transports, storage and prefs.json
Server roles (slice 7)
- CommonCLI split into upstream's shape; region CLI moved into CommonCLI;
  ClientACL, RegionMap, TransportKeyStore and both server meshes in
  upstream shape over an Arduino compat shim (helpers/compat: Arduino.h,
  Stream/Print, Serial, SHA256, FILESYSTEM/File over Zephyr fs)
- room server processAck port; `get acl` prints as upstream
- room: default name Room-XXXX, display/input rotation, live radio UI refresh

Event loops (slice 7b)
- repeater and room server share server_main_common with a ServerRole
  descriptor; shared event bits in src/mesh_events.h
- room server deadline-driven (idle wakes 2.2/s -> 0.08/s); companion
  loop() runs on housekeeping (closes the lazy contact-flush gap)
- `get loop.wakes` in debug builds (CONFIG_ZEPHCORE_LOOP_WAKE_STATS)

Companion transports and WiFi (slice 8)
- upstream MultiSerialInterface: BLE, USB/UART and TCP are each a
  BaseSerialInterface, every connected transport gets every frame;
  CompanionSerial holds a lossless reply; shared frame_txq for BLE/TCP
- SerialCompanionTransport and LinuxTCPTransport replaced by
  TcpCompanionTransport; ZephyrBLE split (gatt layout, DFU)
- WiFi companion (upstream wifi.ssid/pwd/enabled CLI, TCP port 5000) on
  boards declaring `capabilities: wifi` in zephcore.yml: the PSRAM
  ESP32-S3 boards, plus Heltec V3 (140 contacts), Wireless Tracker (130)
  and both C6 boards (280); ESP32-S3 without PSRAM gets bounded WiFi
  buffers and a measured 72 KB heap; PSRAM boards' internal heap 72 KB
- TCP queues: own depth (ZEPHCORE_TCP_QUEUE_SIZE=8), RX waits instead
  of dropping
- RAM: companion ClientACL dropped; main/BT-TX/TCP stacks sized from
  measured peaks (-7 KB nRF companions, -9 KB ESP32 companions)
- ESP32 WiFi stopped working under ~200 frames/s unicast. Fixed by:
  patches/zephyr/0017 never block the WiFi task in the RX callback;
  patches/zephyr/0018 lock shared_multi_heap (heap corruption with the
  WiFi heap in PSRAM); patches/modules/hal_espressif/0001 backport of
  hal_espressif af97fb02df (PSRAM realloc)

Storage and prefs (slice 9)
- prefs are now prefs.json through upstream's ConfigSerializer (ported
  verbatim), with upstream's key names for shared fields and ZephCore's
  own under "zc"; on first boot the binary new_prefs / repeater prefs is
  migrated and kept, so a downgrade still boots with the old settings
- helpers/PrefsCodec: both legacy binary layouts (companion 272 B,
  server 311 B) as Zephyr-free codecs; sanitizeNodePrefs is the only
  validator
- fix: server prefs could be replaced by a truncated file when a write
  failed; identity, prefs and channel writes go through one checked
  atomic replace (ZephyrFsUtil)
- fix: a corrupt cad_auto byte turned adaptive CAD off instead of the
  default on
- fix: a deliberate 300 s GPS duty on a repeater was rewritten to 48 h
  on every boot (that migration now runs on legacy files only)
- one identity loader for all roles (IdentityFile); an unusable key
  file is always parked as .bad before regenerating
- server store no longer stamps repeater defaults on room server and
  observer; companion first-boot volume policy moved into the store
  (adoptVolume)
- ZephyrDataStore 1435 -> ~850 lines
2026-09-25 08:34:21 +02:00