feat(companion): on-device scope + repeater scope filtering; fix CAD, UTF-8 truncation, Public channel, Nodes list, keyboard cursor

- Settings > Radio > Scope: type a community/region name on-device (derives
  the shared key the same "#name" -> SHA256 way as DEFAULT_FLOOD_SCOPE_NAME),
  previously only settable from a connected app.
- Tools > Repeater > Scope only + Extra scopes: only relay flood traffic
  matching the device's own scope or a comma-separated list of additional
  scopes, without changing what scope the device's own messages send under.
  No-op while unconfigured.
- getCADEnabled()/getInterferenceThreshold() were hardcoded off on
  companion_radio; CAD now auto-enables whenever RX power-save (duty-cycle)
  is active, since the noise floor isn't kept fresh during duty-cycle sleep.
- Message truncation to fit the send frame could split a multi-byte UTF-8
  character in half; now stops at the last complete character.
- The default "Public" channel was unconditionally re-added at every boot
  before the saved channel list was loaded, so deleting it never stuck.
  Only seeded now on a genuinely fresh device (no channel file yet).
- Tools > Nodes read contacts from the wrong starting offset, landing on
  internally-reserved bookkeeping slots instead of real contacts -- showed
  as blank "Unknown" rows and silently dropped that many real contacts off
  the end of the list.
- resetContacts() only cleared the first few reserved slots, not the whole
  contact table, contrary to its own comment; only reachable today via
  private-key import, fixed to match stated intent regardless.
- Keyboard's multi-line text preview could render the cursor on an empty
  line below short typed text instead of right after it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-08-21 10:40:50 +02:00
co-authored by Claude Sonnet 5
parent 7e10e0359c
commit f589b9b2d1
13 changed files with 283 additions and 27 deletions
@@ -540,8 +540,10 @@ Navigate with **UP/DOWN**; change a value with **LEFT/RIGHT** (or **Enter** for
| Yield | OFF / x2x9 | Scales the retransmit delay for **forwarded** floods only (your own sends are unaffected), so a mobile companion defers to better-sited fixed repeaters. Widens the window for **Suppress dup**. |
| Min SNR | OFF / 20…10 dB | Drop a flood copy received below this signal-to-noise threshold, so marginal fringe traffic isn't re-flooded. |
| Suppress dup | ON / OFF | If the same flood packet is overheard from another node while still queued to retransmit, cancel our copy — a peer already relayed it. Cuts redundant airtime in dense meshes; pairs with **Yield**. |
| Scope only | ON / OFF | Only forward flood traffic matching this device's own **Scope** (Settings Radio) or one of the **Extra scopes** below — drops unscoped floods and floods tagged for a different community. No-op while neither is set, so switching this on with no scope configured can't silently stop all relaying. |
| Extra scopes | text | Comma-separated extra region names this repeater also relays for (e.g. `eu,de`), on top of its own Settings Radio **Scope** — relay-only, never changes what scope this device's own messages send under. **Enter** opens the keyboard. |
The five flood filters are **opt-in** (default OFF, so a plain repeater is unaffected) and act on **flood** traffic only — on a direct route this node is the named next hop, so it never drops those.
The flood filters (**Skip advert** through **Scope only**) are **opt-in** (default OFF, so a plain repeater is unaffected) and act on **flood** traffic only — on a direct route this node is the named next hop, so it never drops those.
**Same network vs. separate network.** With **Network = Current** (or a Custom profile matching your companion settings) the repeater stays on your own network — you keep messaging while relaying. A *different* Custom profile moves the device entirely onto that network while relaying (one radio can't be on two at once), returning to your own network when switched off. The profile re-applies after a reboot if the repeater was left on.