Commit Graph
94 Commits
Author SHA1 Message Date
liquidraver 9d6b21a264 comment diet vol.2 2026-10-06 21:43:35 +02:00
liquidraver e016fe1760 qspi power down on repeaters 2026-10-06 13:27:58 +02:00
Pieter ViljoenandClaude Opus 5.5 8190b4018e cli: reject a negative sensor list start index
`sensor list <start>` parsed start with _atoi(), whose uint32_t goes
negative as an int: a start of 4294967295 is -1 and 2147483648 is
INT_MIN. Both passed the `start >= end` guard, so the loop asked the
sensor manager for a negative index and passed the NULL it returned
to "%s=%s", undefined behaviour that picolibc happens to print as
"(null)". Rejecting a negative start closes it: ZephyrSensorManager
has one setting, so only index 0 is ever requested.

The same defect as meshcore-dev/MeshCore#3433.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 12:14:47 -07:00
liquidraver 52644a80a4 make gps standby command universal 2026-10-05 14:00:13 +02:00
liquidraver f9d01cf33a upstream sync and gps stuff 2026-10-02 23:10:09 +02:00
liquidraver 2e0f765036 vanilla dev sync 2026-09-27 16:33:58 +02:00
liquidraver d2d786517b power & storage: ESP32 light sleep that sleeps and wakes; less flash wear
ESP32 light sleep (devdocs/lld/13-power-management.md)

Light sleep on the S3 repeaters never worked as designed, for two
independent reasons:

- No S3 repeater ever slept. Every one carries WiFi OTA, the WiFi
  driver starts WiFi at boot (NULL mode), and a started WiFi library
  holds its modem PM lock. Measured on the XIAO: zero sleep entries
  with WiFi compiled in. helpers/pm_esp32_wake.c now stops WiFi at
  boot on PM builds; `start ota` and a station connect start it again
  (verified: AP up, sleep blocked for the session, sleeping after
  `stop ota`).
- DIO1 was not a wake source. GPIO_INT_WAKEUP means EXT1 in Zephyr's
  ESP32 driver: RTC pads only, one trigger polarity for all pins on
  the S3, and pads left on the RTC mux after every sleep. Since 1.17.1
  pm_esp32.overlay also armed the active-low user button; gpio-keys
  configures first, so the driver refused the active-high DIO1.

The new helper arms the radio IRQ line and the user button (sw0) as
per-pin level GPIO wakes (ESP-IDF gpio_wakeup_enable, any pad) for the
length of each sleep, masks their CPU interrupt while in level mode,
and re-raises the interrupt a sleep swallowed through status_w1ts, so
the radio's dio1_isr and gpio-keys run as usual. EXT1 is no longer
used: patch 0003 configures DIO1 as a plain input again and drops the
d7cc4cb pad-restore notifier (preamble section rewritten). Non-RTC
DIO1 boards (XIAO GPIO39, Station G2 GPIO48) can now light-sleep.
Each light sleep is also bounded by the next esp_timer alarm
(pm_policy_next_custom_ticks, CONFIG_PM_CUSTOM_TICKS_HOOK), as ESP-IDF
does; the BLE controller's modem-sleep wake timer lives there.

Light sleep isolates every pad that is not held, RTC or digital, while
the radio keeps receiving. Holds (ESP32_GPIO_SLEEP_HOLD_EN, inert
without PM) now live in each board's own files: NSS and RESET on all
PM-capable boards, VFEM_Ctrl (GPIO7) and Vext on V4/V4.3/V4 R8/WTv2,
CPS on V4, RXEN on the XIAO. The shared overlay keeps only &rtc_timer
and the GPIO wake source; the wrong RTC_PERIPH explanations are gone.

Also:
- `powersaving` (upstream's command and replies) gates light sleep;
  light-sleep builds default to on, and a stored 0 without the new
  pwr_sav_set marker (the field did nothing before) becomes on once.
  `powersaving off` persists and keeps the node (and its USB) awake.
- `get pm`: asleep %, sleeps, wake causes, per-pin wake counts.
- The console window reopens on every user-button press.
- XIAO ESP32-S3: GPIO21 is both the kit's user button and the board's
  led0; the heartbeat drove it low and every sleep woke as a button
  press. led0 is deleted, the button gets a pull-up.
- Station G2: button active-low with pull-up, as upstream reads it
  (was active-high). Untested on hardware.

Verified on the XIAO ESP32-S3 as a light-sleep repeater on the live
mesh (repeat off, 2 dBm) against a T1000-E on the same channel: awake
20 min, ratio of floods heard 0.95; asleep 30.5 min (96.6 % of
uptime), 119 vs 119, ratio 1.00. TX: sent == flood + direct. Heltec
boards: build-only (no unit on the bench).

Companion light sleep stays off by default; the esp_timer bound makes
it possible. Spike on the XIAO (pm_esp32.conf by hand, BLE only): a
held connection survives, 35 min with a poll every minute and no
miss, the SoC asleep ~91 % between connection events, LoRa RX 130 vs
~130 on the T1000-E. Pairing while asleep fails; USB CDC and UI still
need locks before companions can ship with it.

Flash wear (storage)

The companion marked contacts dirty on is_new, but upstream's is_new
means "not in contacts[]": auto-add declined the node (type filter,
hop limit, full table). Every advert from such a node forced a 5 s
full rewrite of an unchanged contacts3, while a contact that really
was just added only got the liveness deadline. onAdvertRecv now
snapshots the stored record first. is_new never dirties. An addition
or a changed name, type or position flushes in 5 s, and a plain
re-advert waits the liveness deadline, now 1 h instead of 10 min.

A new weak hook, zephcore_persist_before_off(), flushes the deferred
writes before every clean reboot and power-off. It is called from
zephcore_power_off(), the ZephyrBoard reboot, bootloader and BLE-OTA
paths, the UI save-and-restart, the joystick restart and wifi_ota.
Off the main thread it posts MESH_EVENT_PERSIST and waits up to 5 s.
Before this, only CMD_REBOOT flushed.

The repeater saved its ACL on every admin login. It now saves only
when the role or secret changed; the secret is the ECDH of two fixed
keys, so re-logins store nothing new. The room server likewise skips
the lazy write unless the role, sync_since or secret changed.
zephcore_prefs_json_save() compares the serialised JSON with the file
and skips an identical rewrite. Not tested on hardware.

Builds and tests: role_builds.sh 10/10; the ESP32 PM set on the
combined tree (five Heltec repeaters, V4 R8, Station G2, XIAO repeater
and companion) 9/9, repeaters at 69-71 % dram0; board_manifest check
clean; host tests quick 114/114. heltec_companion dram0 at 99.80 %
(776 B left, +88 B for both changes together).
2026-09-26 16:49:17 +02:00
liquidraver d5bd805710 peripherals & power: GPS fixes, poweroff/pwrmgt, upstream SensorManager telemetry
- gps: servers honour gps_enabled at boot (was lost on reboot; zc.gps_set
  upgrades older prefs to on once); sleep lock only while acquiring;
  gps off works on boards without a power line (UART sleep); UI toggles
  and fixes handled on the main thread; configure only after a good init;
  observer parks its GPS; one interval clamp (clampGpsInterval); one
  nav-mode knob (room servers on Air530Z now stationary); GNSS UARTE from DT
- gps: split into ZephyrGPSManager / gps_power / gps_module_cfg
  (+gps_internal.h); dead driver branches, gps_get_diag, sats_* removed
- clock: ZephyrRTCClock writes the hardware RTC itself (clkreboot now
  resets it); MESH_EVENT_RTC_SAVE gone
- power: one power-off path (zephcore_power_off, ZephyrBoard::powerOff),
  poweroff/shutdown CLI, get pwrmgt.*, crash record kept across reboot,
  battery reading cached 10 s, fuel gauge on the current API
- telemetry: upstream SensorManager + CayenneLPP (rounded to nearest),
  one builder for all roles; per-sensor channels, MCU temp always,
  guest gating and inverse mask on servers; sensor list/get/set work;
  BME280/BMP280 also probed at 0x77
- CLI: gps in upstream's form, get gps detail, gps sync
2026-09-25 17:56:34 +02:00
liquidraver e6d6ecef80 doom: fix reboot, unreachable L1 demon and no exit; get mem: don't lock IRQs
- doom: each turn shrank the view vectors (cos = 1 - ROT/8, scale
  ~0.993, plus fixed-point truncation), so the level seemed to grow
  and after ~10 turns a zero wall height was divided by: usage fault,
  reboot. The view is renormalised to unit length after every turn;
  the ray step and wall height are clamped
- doom: the L1 demon spawned inside a wall tile, so it could not be shot
  and the portal never opened; it now mirrors the imp at (11,4)
- doom: the 60 s UI lock engaged mid-game, so the exit tap went to the
  lock screen; the Doom tick now keeps the lock and auto-off timers
  alive. The user button no longer also fires (joystick press does)
- doom: sprites keep a brightness floor at distance (L2 boss is still
  hard to see; open)
- get mem (MEM_STATS builds): walk threads with k_thread_foreach_unlocked;
  the stack scan under the thread-list spinlock held IRQs off long
  enough to trip the BLE controller's radio-ISR latency assert
2026-09-25 10:48:20 +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
liquidraver fd2cbe9d62 radio: extract CadController and NoiseFloorEstimator, one prefs source
- CadController (stats, window, re-anchor, visits, staircase, safety,
  starvation relax) and NoiseFloorEstimator split out of LoRaRadioBase
  behind a 4-call CadHw interface; Zephyr-free, host unit tests added
- prefs mandatory: setPrefs() before begin(), LoRaConfig fallbacks and the
  companion/observer placeholder prefs removed; LoRaConfig is the one
  defaults source (invalid-prefs fallback now uses the board TX default)
- TX-wait thread stack owned by the base; reconfigureWithParams removed
- driver extension headers on the public include path
  (zephyr/drivers/lora/*.h); patch 0003 include updated
- comment diet (image-identical); rationale moved to devdocs LLD 03
2026-09-23 14:33:29 +02:00
liquidraver ad23dcbdb6 self-limiting handlers fix 2026-09-20 22:21:29 +02:00
liquidraver edcc40a884 track zephyr main 3e8f38faf93: rebase patches, lora 0.9 api, nrf clock split, s3 heap, lr11xx/lr20xx dc preamble guard, usb kick loop fix 2026-09-19 16:46:14 +02:00
liquidraver 39b9584b20 .editorconfig and .gitattributes 2026-09-18 21:25:19 +02:00
liquidraver da0450e511 upstream sync + wio tracker 1w 2026-09-16 11:29:45 +02:00
liquidraver 8c21a1609b lr2021 2.4ghz and seeed evk button fix 2026-09-12 19:46:43 +02:00
liquidraver 69cc148fbe properly reset CAD offset when needed 2026-09-10 21:56:52 +02:00
liquidraver eef6a488a2 esp flash fix 2026-09-04 12:14:05 +02:00
liquidraver 1633274e4f leds refactor/improvement 2026-09-03 14:34:12 +02:00
liquidraver 81a43f6dd1 west update and upstream dev sync 2026-09-02 10:01:34 +02:00
liquidraver 1db0a14c4b get cad fix 2026-09-02 08:42:51 +02:00
liquidraver ba33cebf6a cad improvements 2026-09-01 22:05:29 +02:00
liquidraver ccb7fc748d command fixes 2026-08-30 09:27:20 +02:00
liquidraver 5372f1d8a2 auto-enable esp32s3 USB CDC companion in CMakeLists; board.overlay first in overlay order; esp32s3 download-mode reboot 2026-08-28 10:32:49 +02:00
liquidraver 2e3f5f3f59 display/input rotate 2026-08-25 15:19:11 +02:00
liquidraver f550d06c19 sync some cli responses to upstream 2026-08-24 11:04:26 +02:00
liquidraver b1f30ff389 clock display fix 2026-08-24 10:54:50 +02:00
liquidraver 7eb5f3832c port artifact cleanup 2026-08-22 18:17:42 +02:00
liquidraver 7d695872d4 implement radio.fem.rxgain 2026-08-22 17:32:41 +02:00
liquidraver 9ba23afbe2 vcontact improvements 2026-08-22 10:50:02 +02:00
liquidraver 1b12354b85 bugfixes, improvements and release notes updates 2026-08-21 15:22:27 +02:00
liquidraver 5c4ac21bd4 refactor patches and bump to 1.17.2 2026-08-20 17:50:48 +02:00
liquidraver ee90693c89 lr20xx: add freq-error summary log and get freqerr CLI 2026-08-12 15:12:43 +02:00
liquidraver 3494411f83 x1 debug 2026-08-10 19:15:26 +02:00
liquidraver 41cc786496 the repo is radiating seeed X1 vibes 2026-08-08 15:19:20 +02:00
liquidraver f83ce0bed4 gps fiddling 2026-08-04 16:04:05 +02:00
liquidraver 4e880df81a set leds on/off 2026-07-31 08:27:10 +02:00
liquidraver a705d5b5ce refactor / unify probes 2026-07-29 12:30:47 +02:00
liquidraver fe6e585eb6 get rid of housekeeping tick and AGC reset 2026-07-28 14:12:40 +02:00
liquidraver cc3cd402af companion adc prefs bug 2026-07-22 14:50:13 +02:00
liquidraver 13b5e2fcf3 scrub APC and bump to 1.16.6 2026-07-20 09:55:32 +02:00
liquidraver b58994661b revork normalization for vContact 2026-07-19 19:48:18 +02:00
liquidraver 434a49375e try to improve APC 2026-07-17 08:35:08 +02:00
liquidraver eb055e2f6b Merge pull request #52 from spinkham/fix-set-freq-clobber
fix(cli): persist 'set freq' across a later savePrefs()
2026-07-13 14:23:42 +02:00
liquidraver 432336867b add cad.busycap knob for hilltop repeaters 2026-07-13 10:29:50 +02:00
liquidraver 722ca66cf0 fix build warnings 2026-07-12 14:35:54 +02:00
liquidraver a320a7646d SmartCAD p2 2026-07-12 14:18:07 +02:00
liquidraver dc1239537e SmartCAD p1 2026-07-12 10:48:37 +02:00
Steve PinkhamandClaude Opus 4.8 8cde6d83f3 fix(cli): persist 'set freq' across a later savePrefs()
The `set freq <mhz>` handler saved the new frequency to prefs, then
reverted _prefs->freq to the old value in RAM to keep the running radio
on the old params until reboot. But _prefs is the source of truth for
every savePrefs(), so:
  - `get freq` / `get radio` reported the old value right after a
    successful `set freq`;
  - the next savePrefs() from any other `set` command (e.g. `set rxduty`)
    rewrote the old freq back over the persisted new one, losing the
    change on reboot.

Mirror the `set radio` handler: keep _prefs->freq = f and freeze the
running radio on the old freq via freezeRadioParams() instead of
reverting the pref. Semantics unchanged (applies at reboot; the live
radio stays on the old freq until then); _prefs now correctly retains
the new value so `get` reflects it and later saves can't clobber it.
freezeRadioParams() is implemented for the Repeater and Room Server
roles; the CommonCLI base default is a no-op, so other roles are
unaffected.

Verified on Seeed XIAO MG24 + Wio-SX1262 (Repeater role, built from
release v20260704.220543 + this patch): `set freq 903.0` is retained by
`get freq` immediately and survives an intervening `set rxduty` + reboot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 17:19:00 -04:00
liquidraver 6ef03fb10e Merge branch 'master' into dev 2026-07-03 19:58:07 +02:00