Commit Graph
110 Commits
Author SHA1 Message Date
liquidraver dc1239537e SmartCAD p1 2026-07-12 10:48:37 +02:00
liquidraver 0d70256d2e vcontact p2 2026-07-11 21:21:47 +02:00
liquidraver 0e7a9b7285 vcontact p1 2026-07-11 16:28:27 +02:00
liquidraver a03856cb34 gps cli commands fix and e-ink sats count clear 2026-07-08 09:16:47 +02:00
liquidraver 38b8ff07cf rework refresh display 2026-07-04 14:15:31 +02:00
liquidraver 74aa3810ee Merge pull request #47 from matthew73210/master
Reworked the screen pages
2026-07-04 12:51:15 +02:00
Matthew Burton d5efd3351a fixed apc text on screen 2026-07-04 07:42:10 +02:00
liquidraver 6ef03fb10e Merge branch 'master' into dev 2026-07-03 19:58:07 +02:00
liquidraver 14cb8c61f9 meshtimesync p1 2026-07-03 09:11:43 +02:00
liquidraver fc940d27ba sync with dev 2026-07-02 13:13:26 +02:00
liquidraver 3af781ee87 get rid of flash writes initiated by ZephyrGPSManager 2026-07-02 09:20:10 +02:00
Matthew Burton 43f455393e added colour and fixed set tx adc not sticking 2026-06-29 20:22:52 +02:00
liquidraver bd363781ac companion hybrid refactor v1 2026-06-23 22:45:25 +02:00
liquidraver 906ef08b05 3 way FS self-heal 2026-06-17 22:05:21 +02:00
liquidraver c4a1777956 refactor gps manager 2026-06-17 15:42:50 +02:00
liquidraver b4a7a4b6c1 fix mismatched guards 2026-06-15 15:29:32 +02:00
liquidraver a03390baa7 guard TRACE path append, multi-ack len, runt flood ACK (core-mesh audit) 2026-06-11 08:43:00 +02:00
liquidraver 0ce847b9bb small fixes 2026-06-11 07:32:50 +02:00
liquidraver f9bc6934b9 initial_advert_work race 2026-06-08 10:21:55 +02:00
liquidraver 7e00a6682d ble race fixes 2026-06-08 09:57:58 +02:00
liquidraver 6861822127 route zephcore_rtc_save() through the deferred-to-main-thread mechanism 2026-06-08 09:01:18 +02:00
liquidraver 2ad185bab4 license "refactor" :) 2026-06-07 22:47:17 +02:00
liquidraver 01fd56a573 wire up RTC to out-of-the-box capable nodes 2026-06-07 12:00:05 +02:00
liquidraver 9ef6774d6a add legacy nordic DFU service 2026-06-06 23:55:15 +02:00
liquidraver ffe9ea652d sync to vanilla 1.16 2026-06-06 16:42:39 +02:00
liquidraver d13d6f4621 version to 1.15.9 2026-06-05 14:59:12 +02:00
liquidraver 28a8a6999d nrf companion auto-shutdown 2026-06-05 09:27:24 +02:00
liquidraver eda46166b4 companion CLI 2026-06-04 22:43:01 +02:00
liquidraver 8761a82d93 fix USB protocol handling and bump version 2026-06-03 10:09:43 +02:00
liquidraver ad4c28cdb0 unbreak build #1 2026-06-03 07:25:24 +02:00
rlwilliamson-dev 58dbba7f3b room-server: drive push engine on a timer + cut delivery latency
Two hardware-found fixes after on-air testing on the GAT562 kit:

- Add a 500ms push timer in main_room_server.cpp so the post-sync
  engine advances at its intended cadence. ZephCore is event-driven
  (no Arduino superloop), so without this the engine only ran on the
  5s housekeeping tick — posts dripped out every ~5s and transmits
  bunched up, causing timeouts/resends.

- Lower the post-sync hold from upstream's conservative defaults
  (POST_SYNC_DELAY 6s -> 2s, PUSH_NOTIFY 2000ms -> 1000ms). These are
  server-side timing only (no wire-format change), and take measured
  delivery from ~6-7s down to ~2s.

Verified on hardware (910.525/62.5/SF7/CR8, two clients): normal-pace
messages deliver in ~2s with clean ACKs. Rapid-fire bursts can still
drop out-of-order messages via the per-client timestamp replay check
(unchanged from upstream) — left as-is to stay upstream-compatible.
2026-06-02 14:12:08 -05:00
rlwilliamson-dev bb6d9c60e1 app: add Room Server (BBS) role
Add the MeshCore Room Server role to ZephCore — a store-and-forward
shared message room. Clients log in with an admin or guest password
and post messages; the server pushes each new post to all other
logged-in clients (round-robin, per-client sync cursor, ACK + retry,
3-strike eviction).

Ported from upstream MeshCore's simple_room_server, structured as a
near-clone of RepeaterMesh so it reuses the proven ACL, region
filtering, CLI, adverts and telemetry; the post buffer + push engine
are the only net-new pieces:
- RoomServerMesh: PostInfo ring (MAX_UNSYNCED_POSTS=32), addPost,
  pushPostToClient, getUnsyncedCount, processAck, onAckRecv, the
  loop() push driver; room login (onAnonDataRecv parses the
  sync_since cursor); posts/admin-CLI/keep-alive (onPeerDataRecv);
  ADV_TYPE_ROOM advert; ServerStats wire layout; disable_fwd=1.
- main_room_server.cpp: event-loop entry (USB serial CLI, no BLE).
- Kconfig: ZEPHCORE_ROLE_ROOM_SERVER + ZEPHCORE_MAX_UNSYNCED_POSTS.
- CMakeLists role gating; boards/common/room_server.conf.

Post frame, SHA-256 ACK and login-reply layouts match upstream for
MeshCore app compatibility. Builds for gat562_30s
(FLASH 30.95% / RAM 32.46%). Not yet hardware-tested.
2026-06-02 13:02:57 -05:00
liquidraver 09074d8852 refactor(crypto): replace orlp/ed25519 with Monocypher 4.0.2
Swap the vendored orlp/ed25519 (frozen ~2017 ref10) for Monocypher
4.0.2, an actively maintained, audited, single-file implementation.

The persisted private key keeps its 64-byte expanded layout
(clamped SHA-512(seed) scalar a || nonce prefix), so identities
written by older firmware load, sign, verify and key-exchange
unchanged -- no re-key, no storage migration, full wire
compatibility with the existing mesh and Arduino MeshCore.

Because the stored key carries no seed for Monocypher's high-level
EdDSA API, Identity drives signing from the low-level primitives
(crypto_sha512 + crypto_eddsa_reduce/scalarbase/mul_add); verify
uses crypto_ed25519_check and ECDH uses crypto_eddsa_to_x25519 +
crypto_x25519. Nonce material is now wiped after signing.

Validated byte-for-byte against the previous orlp output via a
known-answer harness (keygen, sign-from-expanded-key, verify
accept/reject, X25519-over-Ed25519 shared secret) before the swap.

Frees ~42 KB of flash: orlp linked ~55 KB (dominated by its ~30 KB
ref10 precomputed tables); the Monocypher Ed25519/X25519/SHA-512
paths link ~14 KB, with --gc-sections dropping all unused algos.
wio_tracker_l1 pristine build: FLASH 54.14%, links clean.

Monocypher is CC0-1.0 OR BSD-2-Clause.
2026-05-31 22:07:43 +02:00
liquidraver ec982ca15f fix(dispatcher): wake the loop for zero-delay sends
Companion BLE/USB direct & zero-hop sends enqueue with delay 0 from
sysworkq, off the main loop. Since 57b971f dropped the per-frame RX
wake, fire the tx-queued callback for delay 0 too so they actually
drain (USB companion has no tx-idle backstop and would stall).
2026-05-31 15:36:41 +02:00
liquidraver 553b71c44a Make production the default build; decouple USB companion from CONFIG_LOG
Production (LOG=n, ASSERT=n, RTT=n, reboot-on-fatal) is now the prj.conf
default; debug.conf is the opt-in bundle. Removed prod.conf and the
logging.conf auto-include; relocated RTT/ASSERT out of the always-on
platform confs so they no longer override the prod defaults.

Add CONFIG_ZEPHCORE_COMPANION_USB so the USB CDC companion transport
compiles independently of logging (default-y on USB-capable companions,
opt-in on ESP32-S3 via esp32s3_usb.conf). Gate all USB sites behind one
ZEPHCORE_USB_STACK macro.

Rework BLE/USB interface arbitration to first-come-first-served: neither
transport evicts a live session. Make active_iface mutation thread-safe
(mutex + atomic claim) across the BLE callback thread and USB workqueue.

Share the ESP32-S3 USB OTG / console DTS via common dtsi includes; enable
uart0 (GPIO43/44) on station_g2 and xiao so the console reroute works.
2026-05-30 21:05:42 +02:00
liquidraver 7d7a64ff5a fix: airtime LDRO threshold must track driver (was BW-blind sf>=11)
getEstAirtimeFor() set LDRO from `sf >= 11`, correct only at BW125. Now
matches the driver's should_enable_ldro() (t_sym > 16.38 ms) so the
estimate's DE tracks hardware DE on every SF/BW. Also drop dead
calcRxDelay() + unused MAX_RX_DELAY_MILLIS.
2026-05-29 15:48:48 +02:00
liquidraver 94dcf61715 simplify app layer: dedup response/telemetry/JSON builders
- CompanionMesh: sendPacketSent() helper, collapse sendFloodScoped
  overloads, share self-telemetry LPP builder
- Mesh: shared computeAdaptive{Flood,Direct}Delay (was duplicated in
  Companion + Repeater)
- ObserverMesh/RepeaterMesh: shared helpers/MeshcoreJson.h builders;
  drop dead sign_input_len
2026-05-29 12:54:52 +02:00
liquidraver b1f1c77b88 simplify packet manager and dispatcher 2026-05-29 09:09:00 +02:00
liquidraver 799d694914 crypto: simplify entropy path after audit review
- Lift duplicated identity-gen block from main_companion.cpp +
  main_repeater.cpp into ZephyrRNG::generateFirstBootIdentity().
  Both mains shrink from ~40 lines to a 3-line helper call.
- Add LocalIdentity::fromSeed() so seed-derived keygen doesn't need
  a one-shot RNG wrapper; delete SeededRNG.
- Drop the per-byte ADC sampling loop: getBattMilliVolts() does an
  8-sample average + 10ms regulator settle internally, costing
  300-480ms of real wall-time and actively destroying the LSB jitter
  it was meant to harvest. Jitter mixer already dwarfs it.
- Centralize the printk + sys_reboot pattern as
  Utils::cryptoPanicReboot(); drop the 2000ms pre-reboot k_msleep
  (printk is synchronous, sleep just blocked the mesh thread on
  the ZephyrRNG::random() retry-failure path).
- Inline sample_cpu_jitter health check via online scalars instead
  of a 512-byte deltas[] array. Saves 1.5KB stack churn across boot
  and tracks every sample instead of only the first 128.
- extract_via_aes_ctr now uses Utils::sha256 instead of open-coding
  psa_hash_compute.
2026-05-29 07:58:54 +02:00
liquidraver b692ca72ed crypto: harden all crypto-sensitive memcmp + memset sites
Audit-driven sweep found additional compiler-optimization-sensitive
patterns beyond the login password compare just fixed:

P4.F3 (HIGH) — Utils::MACThenDecrypt verified packet MACs with
plain memcmp. Runs on EVERY encrypted-then-MAC'd packet in the
mesh; a timing oracle here lets attackers forge MACs byte-by-byte
across the whole mesh layer. Replaced with constantTimeEqual.

P4.F4 (MEDIUM) — Multiple memset(secret, 0, ...) calls on
stack-resident crypto buffers (Ed25519 seed, ADC noise pool, AES
key derived in extract_via_aes_ctr, HWINFO unique ID) were
subject to dead-store elimination under -Os. GCC/Clang routinely
elide these when the buffer is never read after; the wipe vanishes
and the secret persists on stack until next call overwrites.
Replaced with secureZeroize using volatile pointer writes.

P4.F5 (LOW) — Identity::validatePrivateKey boot self-test compared
shared secrets with plain memcmp. Boot-only, no attacker
observation channel, but hygiene matters and the fix is one line.
Also added secret-wipe for ss1/ss2 on all return paths.

Promoted the local ct_memeq() previously added to RepeaterMesh.cpp
into Utils::constantTimeEqual + Utils::secureZeroize (Utils.h/cpp)
so the login compare and MAC compare share the same audited helper.

Both helpers verified by Thumb-2 disassembly on rak3401_1watt:
- constantTimeEqual: loop branches on iterator, accumulator
  load-modify-stored to stack every iteration, final return uses
  CLZ+LSR (no conditional branch on result).
- secureZeroize: STRB.W to memory in a counted loop, not replaced
  with memset builtin and not eliminated.
2026-05-28 13:26:20 +02:00
liquidraver 515f3610e1 crypto: harden first-boot identity entropy + 3 RNG fixes
Adds a layered entropy mixer for first-boot identity Ed25519 keygen,
primarily to address ESP32 where the hardware TRNG (WDEV_RND_REG) is
only fed real entropy once the internal WiFi/BT radio is enabled —
but identity gen runs before that on companion and indefinitely
before that on a bare repeater. ESP-IDF's bootloader_random_enable()
is not compiled by Zephyr-Espressif HAL, ruling out that workaround.
Design reviewed with nextgens (author of upstream meshcore-dev/
MeshCore#2280 which fixes the same issue via BT/WiFi init/pull/deinit).

ZephyrRNG::random — retry sys_csrand_get up to 4x with k_msleep
backoff; cold-reboot on persistent failure. Previously fell back
silently to sys_rand_get (xoshiro PRNG), which would have produced
a weak Ed25519 seed on CSPRNG error. BUILD_ASSERT enforces
CONFIG_CSPRNG_ENABLED.

ZephyrRNG::mixIdentitySeed — layered entropy mixer for one-shot
identity keygen. Combines sys_csrand_get (early + late),
HWINFO unique device ID, caller-supplied ADC LSB noise, 200ms of
CPU cycle-counter jitter (NIST SP 800-90B class source), and
50ms more jitter in an independent timing window. Conditioned via
AES-256-CTR (NIST SP 800-108 KDF-in-Counter-Mode): SHA-256 of the
pool extracts a 32-byte AES key; AES-256-ECB on an incrementing
128-bit counter expands to the requested output length. Uses PSA
crypto already enabled in zephcore_common.conf. NIST-style
repetition-count + variance health check on jitter samples;
reboot on degenerate output. ~280ms one-time cost at first boot.
LoRa radio TRNG was considered as an additional source but rejected
on expert advice — radio sources are attacker-influenceable
(jamming/spoofing).

ui-joystick BLE passkey — switch from sys_rand32_get (non-crypto
xoshiro) to sys_csrand_get. The 6-digit passkey is the MITM
protection the rest of the BLE config enforces; predictable PINs
weaken it.

Identity reserved-prefix loop — replace the silent 10-attempt cap
(which committed whatever it had on fall-through) with a
bounded-retry-then-reboot pattern.

Also: fix a pre-existing scope bug at main_companion.cpp:357 in
the MESH_EVENT_PREFS_DIRTY handler — data_store was referenced
inside mesh_event_loop() but declared 50+ lines later. Moved the
call into a forward-declared helper defined after the statics.
Unrelated to crypto work but uncovered during build verification;
every companion build was broken.
2026-05-28 09:34:43 +02:00
liquidraver 57b971fc2c remove redundant main thread wakeups 2026-05-27 09:46:48 +02:00
liquidraver f06c472e87 usb: unify companion + repeater CDC ACM init, drop boot waits
Single ZephyrUSBCDC module owns the usbd context, 1200-baud DFU
detection, and DTR transitions for both roles. The boot banner
now blocks on a k_event signalled by the usbd_msg_callback when
DTR transitions high — host attached → wakes immediately; no host
→ bounded timeout (2 s repeater, 1 s companion). Replaces the
fixed k_sleep delays in both mains.

Deletes the companion's 10 s DTR-polling work — line state changes
arrive as events now, same callback handles disconnect (resets V3
parser, flips active_iface) and DFU touch (reboots to bootloader).

Side effect: prod companion no longer enumerates a phantom CDC ACM
port (CONFIG_LOG=n skips the whole stack instead of auto-initing
an unused device).
2026-05-27 09:04:32 +02:00
liquidraver 051adef93e native linux initial commit 2026-05-24 20:06:49 +02:00
liquidraver 6b624a69e5 sync with vnailla dev 2026-05-22 14:42:12 +02:00
liquidraver 094ea6e8a3 joystick UI:
- track real RTC sync source on the joystick Time screen
- gate joystick-only UI helpers behind stub headers so non-joystick builds skip the extra code without #ifdef at every call site.
2026-05-22 11:38:51 +02:00
liquidraver 322460fa78 joystick UI:
make UI show actual time source
2026-05-22 11:29:25 +02:00
liquidraver 03fcc60fa9 joystick UI: channel-send heard-repeat feedback
After broadcasting a group message, wait 5s to see if any neighbor
repeated the flood and use the outcome to mark the on-device entry
and the BLE-app mirror.

  - ContentionTracker gets extractDupeCount(hash): finds the tracked
    entry, captures dupe_count, finalizes (folds into EMA, marks
    inactive), returns the count or -1.
  - BaseChatMesh::sendGroupMessage gains an optional out_hash param;
    when set, the FNV-1a packet hash is also pre-registered with the
    contention tracker so heard retransmits get counted (originated
    floods weren't tracked before, only relays).
  - Mesh::getContentionTracker() promoted to public so the UI can
    query after the feedback window.

JoystickUITask grows a 4-slot pending-channel table with per-slot
k_timer (5s one-shot). startPendingChannel() broadcasts, adds the
local _ch_previews entry with path_len = OUT_PATH_SENT, and starts
the feedback timer. The timer ISR sets a feedback_due flag; the
loop's processPendingChannelFeedback() picks it up, calls
extractDupeCount(), and rewrites the preview's path_len to
OUT_PATH_SENT_HEARD (0xFD) or OUT_PATH_SENT_UNHEARD (0xFC) — which
formatHopCount renders as "sent+" / "sent?".

The deferred BLE-app mirror queues only on outcome with body prefix
"(>>✓) " (heard) or "(>>✗) " (not heard). queueLocalSentChannelMessage
gains a heard_repeat parameter for the selection.

Both channel send entry points (sendComposedMessage's channel branch
and sendChannelMessage) now route through startPendingChannel().
2026-05-21 22:24:26 +02:00
liquidraver 07efffc417 zephcore_ble_is_enabled → zephcore_ble_is_enabled().
The watchdog now actually honors the disabled state instead of re-enabling BLE on every housekeeping tick.
2026-05-21 21:46:49 +02:00
Steve Calvário 5caf53a496 Add GPS altitude support, add channel “reply to” targeting, fix snake wall collisions, fix unread navigation incorrectly returning to home, and fix BLE continuing to advertise after being disabled 2026-05-21 17:09:13 +01:00