Commit Graph
69 Commits
Author SHA1 Message Date
liquidraver 9eb33e27dc cad, meshamerica flasher and other polishes 2026-07-13 09:00:14 +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 000f6ed494 fix some text in docs and comments 2026-07-04 16:47:46 +02:00
liquidraver 46d27a0144 meshtimesync p2 2026-07-03 19:30:53 +02:00
liquidraver 14cb8c61f9 meshtimesync p1 2026-07-03 09:11:43 +02:00
liquidraver 4d16dc7589 fix send retry bug in CompanionMesh 2026-07-02 09:29:37 +02:00
liquidraver f1124e6783 Fix path-discovery response wrongly rejected at non-default path_hash_mode (2/3-byte hashes) 2026-07-01 21:03:35 +02:00
liquidraver 2f86310500 port lora e5 mini 2026-06-21 20:38:57 +02:00
liquidraver dc7a2827a3 sync with vanilla dev 2026-06-15 15:25:04 +02:00
liquidraver 5fc8fd1ead shared canonical path for UI adverts 2026-06-14 22:25:32 +02:00
liquidraver 2ad185bab4 license "refactor" :) 2026-06-07 22:47:17 +02:00
liquidraver 7c46f4a343 legacy code cleanup 2026-06-07 13:02:07 +02:00
liquidraver 01fd56a573 wire up RTC to out-of-the-box capable nodes 2026-06-07 12:00:05 +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 8761a82d93 fix USB protocol handling and bump version 2026-06-03 10:09:43 +02: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 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 99279fd9fa sync with vanilla dev 2026-05-24 21:07:38 +02:00
liquidraver 051adef93e native linux initial commit 2026-05-24 20:06:49 +02:00
liquidraver c7a00b9533 update version 2026-05-22 15:39:07 +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 4f388c0b98 companion: fix "62 hops" garbage in local-sent BLE mirror frames
The phone app interprets path_len with an unconditional `& 63`, so
the OUT_PATH_SENT (0xFE) sentinel we were writing into the
offline-queue frame became "62 hops" + 4 bogus path bytes in the
app's UI. There are 0 LoRa hops between the sender (us) and the
phone viewing the message — path_len = 0 is both correct and
renders cleanly as "direct / 0 hops". The "(>>✓) " / "(>>✗) " body
prefix still distinguishes wio-originated messages from incoming.

OUT_PATH_SENT remains the marker for the joystick UI's own local
entries (UnreadScreen, _ch_previews) — formatHopCount handles it
explicitly so it's safe there.
2026-05-22 09:11:12 +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 8e5e54a61e joystick UI: DM retry, force-flood fallback, BLE mirror on outcome
Outgoing DMs now go through a 4-slot pending-send table with per-slot
one-shot k_timer. On no-ACK the message retries (up to 5 attempts,
0-indexed); attempt 4 clears recipient.out_path_len + markContactsDirty
so the last try forces flood and future DMs re-discover the path.

ACK dispatch: CompanionMesh::processAck tries _ack_table first
(phone-initiated sends), then ui_joystick_try_match_ack() for joystick-
initiated sends, then falls through to connection-keepalive ACKs.

BLE-app mirror is now deferred until outcome is known. The body prefix
in the offline-queue frame is "(>>✓) " on delivery or "(>>✗) " on
failure, replacing the previous unconditional "(>>) ". UnreadScreen's
sent-entry origin prefix is updated in place via markSentEntryStatus()
to "(>>+) " / "(>>X) " (ASCII for the OLED font).

queueLocalSentContactMessage gains a 'delivered' parameter to pick the
prefix; markContactsDirtyPublic() exposes the lazy-write trigger so
the joystick's path-clear persists.
2026-05-21 22:09:56 +02:00
liquidraver ec2ae31b67 joystick UI: prefix sender to mirrored channel sends for BLE app
BaseChatMesh::sendGroupMessage wraps the body as "<sender_name>: <body>"
before transmitting (the receiver's onChannelMessageRecv sees the full
"USER: MSG" string, which CompanionMesh queues as-is for the phone).
queueLocalSentChannelMessage was queuing just the raw body, so the
phone parsed an empty sender and lost the body. Prepend
"<prefs.node_name>: " to mirror the wire format.

joystick UI: prefix DM mirrors to phone with sent-marker

DM offline-queue frames identify the sender by pubkey field, not by
in-text prefix. queueLocalSentContactMessage was queuing with the
contact's pubkey + raw body, so the phone app rendered wio-originated
DMs identically to incoming ones from that contact. Prepend "(>>) "
to the body so sent messages are visually distinguishable; matches
the joystick UI's own sent indicator (UnreadScreen::addPreview).
2026-05-21 13:41:13 +02:00
liquidraver 3de179f9bc joystick UI: lock-screen info, BLE-aware unread, mirror local sends
- Lock overlay: show battery % + unread count between title and unlock
  sequence; ui_invalidate_battery_cache() on screen wake forces a fresh
  ADC sample so the user sees current data immediately
- UnreadScreen::addPreview gains initially_read; received msgs pass
  _ble_connected (don't count unread when phone is syncing); sent msgs
  pass true (you sent it, you know it)
- CompanionMesh::queueLocalSent{Contact,Channel}Message + PUSH_CODE_MSG_WAITING
  on wio-originated sends so a connected phone app sees them via the
  normal offline-queue flow (path_len = OUT_PATH_SENT marker)
- OUT_PATH_SENT moved back from joystick_defs.h to ContactInfo.h
  (now a wire-format value, not UI-only)
2026-05-21 09:37:24 +02:00
liquidraver e36d9b33a3 companion: scope joystick-only state to joystick builds
- #ifdef-gate _pending_joystick_{ping,admin}_tag fields + setters
  under CONFIG_ZEPHCORE_UI_DESIGN_JOYSTICK (saves 8 bytes per
  CompanionMesh instance on button-UI builds)
- gate logTx ui_notify_packet_sent() to joystick builds only;
  was firing on every TX for any UI variant (dead code on button UI)
- drop redundant _pending_login manual set in CMD_SEND_LOGIN;
  BaseChatMesh::sendLogin's onLoginSent hook owns it now, just
  clear the other pending fields explicitly
2026-05-21 09:06:55 +02:00
Steve Calvário 56b10f70a1 Init 2026-05-20 20:40:58 +01:00
liquidraver 0ba2721b40 refactor(companion): tighten Phase 2F polish — error codes, length checks, build assert
Three small correctness/polish improvements from BLE audit Phase 2F:

1. Five handlers (CMD_APP_START, CMD_GET_CHANNEL, CMD_SET_CHANNEL,
   CMD_DEVICE_QUERY, CMD_SEND_CHANNEL_TXT_MSG) previously responded
   with ERR_UNSUPPORTED on short-frame validation failure (because
   they fell through to the dispatcher's default break, which the
   caller converts to "unknown command"). They now explicitly
   sendPacketError(ERR_ILLEGAL_ARG) — the semantically correct code
   for "known cmd, bad frame".

2. CMD_SET_TUNING_PARAMS previously returned PACKET_OK on short
   frames without applying any change. Now sends ERR_ILLEGAL_ARG so
   the phone learns the change didn't take.

3. Added static_assert that CONFIG_ZEPHCORE_BOARD_NAME fits in 40
   bytes including its null terminator, so a future too-long board
   name fails at build time instead of producing an unterminated
   wire-format response.
2026-05-20 15:54:20 +02:00
liquidraver b39483add3 fix(companion): null-terminate contact name in CMD_ADD_UPDATE_CONTACT
The wire format reserves a 32-byte name field; if the phone sends 32
non-null bytes, ContactInfo::name has no terminator. Subsequent
LOG_INF/LOG_DBG sites using %s with contact.name then read past the
field into adjacent struct bytes (type, flags, out_path_len, ...)
until the first null. No memory corruption — serializeContact uses
StrHelper::strzcpy which is length-bounded — but log output gets
garbage and a paired peer could probe a few bytes of the struct
through log capture.

Sibling handler CMD_SET_CHANNEL at :1593-1594 already does this
defensively. Match the pattern.
2026-05-20 15:40:18 +02:00
liquidraver 988b438ec3 refactor(companion): harden telemetry buffer sizing and custom-vars snprintf
Two polish items from BLE audit Phase 2B:

1. CMD_SEND_TELEMETRY_REQ self-response buffer was uint8_t rsp[96]
   with a comment claiming 70 B worst case. Actual worst case at
   POWER_MAX_CHANNELS=4 is 82 B; if the channel cap ever grew the
   buffer would silently overflow. Replaced with a sizeof-style
   expression that tracks POWER_MAX_CHANNELS, plus an 8-byte safety
   pad. No size change today (90 vs. 96) but the upper bound auto-
   tracks any future bump.

2. CMD_GET_CUSTOM_VARS used `dp += snprintf(dp, 20, ...)` which
   advances by the would-be-written length, not bytes actually
   written. Currently safe only because gps_interval is capped
   ≤86400, but if either cap drifted or a new key was added the
   length passed to writeFrame would include uninitialized stack
   bytes between the truncation point and the (over-advanced) dp.
   Now tracks rsp_end, computes remaining per snprintf, and only
   advances dp on real progress.

Both are correctness polish, not exploitable today.
2026-05-20 11:57:37 +02:00
liquidraver bd1e022e88 fix(security): close OOB read in path-decoding callers (BLE + LoRa-anon)
Both mesh::Packet::writePath and ::copyPath did a raw memcpy of the
decoded hash_count*hash_size bytes from src to dest with no bound on
src. Two call sites used phone-supplied or LoRa-anon-supplied buffers
where the path_len byte was attacker-controlled:

  - CompanionMesh CMD_SEND_CHANNEL_DATA accepted len>=4 and called
    writePath with no src bound; a paired phone could leak up to ~65
    bytes of syswq stack into the outgoing LoRa channel-data frame.

  - RepeaterMesh handleAnonRegionsReq / handleAnonOwnerReq /
    handleAnonClockReq read reply_path_len from an unauthenticated
    LoRa anon-request payload and called copyPath without any src
    bound. Any LoRa neighbor could leak repeater stack into the
    reply path.

Hardened the API: both functions now require an explicit src_len
and reject (return 0) when the decoded byte count exceeds it.
Updated all 14 call sites across Packet/Mesh/Dispatcher/BaseChatMesh/
CompanionMesh/RepeaterMesh. Trusted callers (internal MAX_PATH_SIZE
buffers) pass MAX_PATH_SIZE; untrusted callers pass real remaining
length. Added len-5 plumbing through the anon-handler signatures.

CMD_SEND_CHANNEL_DATA also gained a local len>=5 + path_bytes
sanity check for early rejection.
2026-05-20 11:52:39 +02:00
liquidraver d7e420bf2f fix(ble,usb): three bugs from BLE audit
1. USB takeover opcode mismatch
   ZephyrCompanionUSB.cpp checked payload[0] == 0x03 with a comment
   claiming CMD_APP_START, but CMD_APP_START is 0x01 (0x03 is
   CMD_SEND_CHANNEL_TXT_MSG). The USB handshake silently dropped the
   companion app's first frame on every connection; the app appeared
   broken over USB until the user happened to send a channel message.

2. CMD_SET_ADVERT_NAME didn't propagate to BLE adv data
   Name changes were persisted to prefs but the advertising payload
   and GATT device name kept the old value until reboot. Added
   zephcore_ble_update_name() and called it from the handler.

3. No advertising-health watchdog
   If bt_le_adv_start() ever failed transiently (HCI timeout,
   controller pacing), the device would silently stop advertising
   and stay undiscoverable until reboot. Added an adv_running flag
   and a 5s watchdog in the companion housekeeping handler that
   nudges adv back on if it stops outside a connection. Tracks
   Arduino nrf52's equivalent 10s watchdog.
2026-05-20 11:09:45 +02:00
liquidraver 2ee0fffa69 sync with vanilla 2026-05-08 10:13:42 +02:00
liquidraver 147ac462b3 fix deleting public channel could wipe all other channels on reboot 2026-05-07 21:43:48 +02:00
liquidraver 28e12c7eef initial companion jitter lowering 2026-05-05 14:52:12 +02:00
liquidraver 62232bf609 small ble fixes 2026-04-30 09:23:56 +02:00
liquidraver 5dc07d78ba force unscoped send on magic scope word: "none" even if there is a default scope 2026-04-29 13:17:04 +02:00
liquidraver b84830b3b3 (greatly) improve our BLE 2026-04-29 12:09:21 +02:00
liquidraver 1092c49a7d port vanilla duty cycling logic 2026-04-28 14:43:12 +02:00
liquidraver e18d017b2c refactor repeater prefs changes 2026-04-28 13:49:08 +02:00
liquidraver bf9ad0ef40 tune delay knobs 2026-04-28 13:49:08 +02:00
liquidraver d5f260c1c9 Fix ESP OTA functions 2026-04-25 14:52:45 +02:00
liquidraver 78561036d0 bump version to match vanilla 2026-04-19 10:16:59 +02:00
liquidraver d2cec84100 sync with vanilla dev 2026-04-17 13:21:30 +02:00
liquidraver ba4b86752d acw: airtime-scale jitter caps, companion surroundings awareness
- flood retransmit jitter now capped at min(2000ms, 6·airtime) instead of
  fixed 2000ms — spreads tighter at SF7, unchanged at SF8
- reactive per-dupe backoff cap now min(2000ms, 12·airtime), keeps
  semantic of "push past ~12 relay slots"
- contention ring 16 → 24 for 50-neighbor hilltops
- companions passively track heard floods (warms EMA without forwarding)
  and spread their own TX by up to min(1000ms, 3·airtime), hopefully
  fixing repeaters missing companion's first transmission

config cleanup:
- move BLE TX buffer bumps (ACL_TX=12 etc.) from zephcore_common.conf to
  esp32_common.conf — the Espressif blob needs them, nRF doesn't, and
  the bumps were overflowing nRF52840 RAM
- remove CONFIG_ZEPHCORE_MAX_CONTACTS=510 overrides from 5 nRF52840
  companion boards; Kconfig default of 350 fits with comfortable margin
  (wio prod: 91% → 79% RAM)
2026-04-17 10:24:12 +02:00