Commit Graph
28 Commits
Author SHA1 Message Date
MarekZegare4andClaude Opus 4.8 6e4177f3d6 feat(ui): proportional scrollbar with mini-icon caps; reclaim row space
Replace the text ^/v scroll arrows with a font-scaling indicator drawn in
icons.h: a proportional thumb between fixed up/down triangle mini-icon caps.
drawScrollIndicator() lives in a ~5px right-edge column and scales via
miniIconScale (1x OLED, 2x landscape e-ink).

- Mini-icons: ICON_SCROLL_UP/DOWN; miniIconDrawTop (exact placement) and
  miniIconDrawHalo (shape-hugging 1px DARK halo, clip_top to spare the header
  separator) so caps stay visible on the LIGHT selection bar without a box.
- Thumb is 3*s wide so it centres on the triangle column; caps are static end
  markers (always drawn) so neither vanishes at the extremes.
- scrollIndicatorReserve(): right-edge gutter (0 when the list fits). Content,
  the selection bar and the message-history bubbles are all narrowed by it so
  nothing renders under the scrollbar. Portrait e-ink wrap width subtracts the
  reserve in both the box-height pass and render so wrapped text can't spill.
- Drop the redundant ">" selection marker (the highlight bar already shows
  selection) and shift rows to x=2, reclaiming left-edge space.
- Wire the indicator into every scrollable list (Bot, Settings, Nearby, Tools,
  Trail, QuickMsg lists + DM/channel history) and add one to WaypointsView,
  which scrolled with no indicator before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:41:46 +02:00
MarekZegare4andClaude Opus 4.8 8bd6fbf1cb feat(bot): hardening + auto-responder, query commands, quiet hours
Reply-bot overhaul on top of the trigger/reply auto-reply:

Robustness
- single botTriggerMatches() shared by DM/channel paths; named constants
  (BOT_REPLY_COOLDOWN_MS / BOT_SCRATCH) replace magic numbers.
- per-contact DM throttle (8-entry ring) so a second sender isn't starved
  while one contact is on cooldown.
- channel anti-loop: skip only when an incoming message equals our own reply
  (was: any reply containing the trigger word — which silently killed channel
  replies for the common "trigger word in reply" setup).

Features
- away / reply-to-all: a lone "*" trigger matches every message.
- independent DM vs channel triggers (bot_trigger / bot_trigger_ch); "*" works
  on the channel too, bounded by cooldown + echo guard.
- query commands: a DM or monitored-channel message is scanned for "!word"
  tokens — !ping/!batt/!loc/!time/!temp/!hops/!status/!help — merged into one
  combined reply. DM = per-contact throttle, ignores quiet hours; channel =
  broadcast, per-channel cooldown, respects quiet hours. !hops uses
  getPathHashCount() (0 = direct).
- quiet hours (bot_quiet_start/end, local, wraps midnight) silence push replies.
- reply counter shown in the BotScreen header.

UI / storage
- BotScreen: 9 rows, scrolling list (no more cramming), field I/O via
  fieldBuf()/fieldCap().
- prefs bot_commands_enabled / bot_quiet_start / bot_quiet_end / bot_trigger_ch
  persisted; schema 0xC0DE000A → 0xC0DE000C with clamping + migration
  (bot_trigger_ch seeded from bot_trigger on upgrade).
- docs: tools_screen bot section rewritten; FEATURES.md refreshed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:57:27 +02:00
MarekZegare4andClaude Opus 4.8 8c0ccaed73 feat(ui): keyboard overhaul — shared instance, icon keys, symbols page
- Unify on the shared keyboard: WaypointsView drives UITask::keyboard()
  instead of its own instance; openKb() clears {loc}/{time} for literal
  fields (labels, coordinates). Reclaims the duplicate widget from the heap.
- Icon glyphs on the special row: caps ⇧, space ⎵ (two halves), delete ⌫,
  OK ✓ (reuses ICON_CHECK); {} and the page toggle stay text.
- Second character page (symbols), toggled by a "#@"/"abc" key. Tidy the
  letters page: drop the duplicate grid space, add the comma, group
  punctuation as . , ! ?
- Harden the preview buffers (KB_PREVIEW_CAP) against very wide displays.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 10:47:50 +02:00
MarekZegare4andClaude Opus 4.8 4145185031 chore: address code-audit hygiene (stale refs, dead TODO, popup scroll)
- FEATURES audit: refresh references the Nearby/Trail refactors made stale —
  M4 (renderDiscoverDetail → renderScanDetail), L1 (SNR %.1f now in scan detail
  + ping; list cards show RSSI), Trail grid (round-step renderGrid + MIN_GRID_PX).
- MyMesh: drop the obsolete `// TODO: add expected ACK to table` — the code
  right below already populates expected_ack_table.
- PopupMenu: render() is now the single source of truth for _scroll, clamping
  the selection into view from the live-height cap, so handleInput() only moves
  _sel and never depends on a stale _cap (M3). Behaviour-preserving.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 10:00:48 +02:00
MarekZegare4andClaude Opus 4.8 27d88bed52 docs: sync docs with shipped state (Nearby menu, design status, delivery)
- tools_screen (Nearby): drop the removed "Filter…" Options action; filtering
  is LEFT/RIGHT on the list only. Sort is adjusted in place via LEFT/RIGHT on
  its row, stored-source only; filter/sort persist across re-entry.
- nearby_redesign / trail_redesign: mark Status implemented (branches merged);
  record the Nearby deviations from the proposal.
- FEATURES: DM delivery status moved from idea to  shipped, with deltas.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 09:50:57 +02:00
MarekZegare4andClaude Opus 4.8 c05e722afc refactor(ui): readable compile-time icon authoring (ASCII-art + dims)
Author mini-icons as ASCII-art rows packed to bytes at compile time via
constexpr packRow(), so the glyph shape is visible in source while the
binary holds only the packed bytes (strings never reach flash, identical
to the previous hand-written hex).

Bundle each icon's width/height with its data through MiniIcon and the
MINI_ICON(name, width, ...) macro, so draw sites carry no magic numbers:
miniIconDraw(d, x, y, ICON_CHECK). Also add an unused-by-design skeleton
for full-size page icons (≤32 px): packRow32 / BigIcon / BIG_ICON /
bigIconDraw, for authoring a future big glyph the same readable way.
Existing XBM bitmaps left untouched.

Flash size unchanged; verified no ASCII-art strings reach the .elf.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 09:42:29 +02:00
MarekZegare4andClaude Opus 4.8 019f739b8b refactor(ui): reorganize Nearby Nodes (one list, two sources, unified menu)
Replace the many scrollable filter/sort categories and inconsistent popups
with a single list / detail / action-menu path over two sources (stored
contacts and live discover scan). Filter (type) and sort are independent
axes: LEFT/RIGHT cycle the type filter, the action menu's Sort row is
adjusted in-place with LEFT/RIGHT (not Enter). The active filter is shown
in the SCAN title and empty-list messages distinguish "no contacts" from
"filtered out". Filter/sort persist across re-entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 09:22:26 +02:00
MarekZegare4andClaude Opus 4.8 38e9273ec7 refactor(ui): reorganize Tools › Trail (popup, map, waypoints)
Tidies the Trail screen end to end, with no functional change beyond the
intended UX cleanups. Squashed from refactor/trail-screen.

Popup:
- Two-level action menu (Hold Enter): short main menu (Start/Stop, Mark
  here, Waypoints…, Trail file…, Settings…) plus "Trail file…" and
  "Settings…" submenus, replacing one flat ~12-item list that mixed
  settings and actions. One interaction pattern per level; Reset lives in
  Trail file…, away from a stray Enter. Settings submenu is view-aware
  (Grid only on Map, Readout only on Summary).

Map:
- MapProjection (geo→pixel) built once and shared by the map, grid and
  marker drawing — removes the duplicated projection math and renderGrid's
  11 scalar params.
- renderMap split into computeBounds() and drawMarkers() helpers.

Grid:
- Square cells fitted to the frame: the shorter side is divided into a
  whole number of equal cells (grid touches that pair of borders), and the
  longer side centres the whole cells that fit — square, symmetric, no
  one-sided drift. Drawn as one dot per intersection (legible on OLED).

Waypoints:
- Extracted the whole waypoint management UI (list / navigate / add-by-
  coords / mark / rename / delete / send) into a self-contained
  WaypointsView component that TrailScreen owns and delegates to.
- Dropped the redundant bulk "Clear all" (per-waypoint Delete covers it).

Docs updated (tools_screen.md) + design rationale (docs/design/
trail_redesign.md). Builds clean on solo envs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:05:49 +02:00
MarekZegare4andClaude Opus 4.8 bcf8774962 feat(ui): message delivery status (DM ACK + channel relay)
End-to-end delivery indicators on the device UI, drawn next to outgoing
messages and auto-scaled to the font (legible on landscape e-ink).

DM (and room servers, which share the DM path):
- Pending / delivered / failed marker driven by the real end-to-end ACK.
  Pending shows a row of dots — one per send — so auto-resend progress is
  visible before it resolves to ✓ / ✗.
- Auto-resend: new pref dm_resend_count (0-5, default 2), Settings ›
  Messages › Resend. A pending DM whose ACK times out is re-sent (reusing
  the original timestamp) until resends run out, then ✗. Driven from
  UITask::loop so it completes in the background, independent of screen.
- Incoming dedup: a retry reuses the sender timestamp + text but carries a
  fresh packet hash, so addDMMsg drops copies matching prefix+ts+text.

Channels (flood, no recipient ACK):
- ✓ only once a repeater echo confirms the send was relayed into the mesh;
  no echo is normal, not a failure (no pending/fail shown). A small ring
  tracks a burst of sends so each matches its echo. Receive-path hashing is
  gated so the hot flood path is untouched when idle.

Shared:
- Markers shown in both the history list and the fullscreen message view.
- Reusable scalable mini-icon facility in icons.h (bitmap + auto-scale);
  adding a new status icon is a bitmap plus one draw call.

No changes to the upstream mesh library (src/).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 23:33:16 +02:00
MarekZegare4andClaude Sonnet 4.6 8545454f5b docs(features): add unprioritised idea backlog (DM delivery status + 10 more)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 13:47:12 +02:00
MarekZegare4andClaude Sonnet 4.6 b8a7b5dcc0 refactor: dedup persistence header, harden action menu, tidy small items
- Persist.h: shared writeHeader()/readHeader() for the magic+version+count
  on-disk header; Waypoint and Trail snapshots now share one implementation
  (byte layout unchanged; each keeps its own count clamp/reject + extra fields).
- TrailScreen: pushAction() guards _act_map / PopupMenu capacity, so adding a
  new action can't silently overrun the fixed array.
- PopupMenu: add count()/setSelected() accessors; replace the remaining direct
  _sel/_count field pokes in NearbyScreen, TrailScreen and QuickMsgScreen.
- Trail summary: unit-suffixed time ("1h 05m" / "5m 03s") so hours can't be
  misread as minutes.
- Trail::haversineMeters delegates to geo::haversineKm — single Haversine
  implementation (also trims a little flash).

Verified: GAT562 (SSD1306) and WioTrackerL1Eink (GxEPD) solo builds compile clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 13:37:03 +02:00
MarekZegare4andClaude Sonnet 4.6 151892e1ce refactor(ui): extract shared helpers, dedup screens, GPS shutdown via provider
Pull repeated UI idioms into DisplayDriver and remove duplicated logic:

- DisplayDriver: add drawScrollArrows() and drawInvertedHeader(); replaces 11
  copy-pasted scroll-arrow blocks across 5 screens and 3 inverted title-bar
  blocks (NearbyScreen x2, NavView). Standardises the detail-view separator.
- useImperial(): single source on UITask; NearbyScreen/TrailScreen delegate
  instead of each re-reading NodePrefs.units_imperial.
- NearbyScreen: extract saveSelectedWaypoint() (two identical blocks -> one);
  drop the redundant local label buffer (WaypointStore truncates).
- UITask::shutdown(): power GPS off through LocationProvider::stop() instead of
  poking PIN_GPS_EN directly — centralises enable/reset-pin + active-level logic.

Net -58 lines. Verified: GAT562 (SSD1306) and WioTrackerL1Eink (GxEPD) solo
builds compile clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 13:21:59 +02:00
MarekZegare4andClaude Sonnet 4.6 1521be3803 fix(trail): check read() return for header bytes in readFrom/exportGpxFromFile
Mirrors the Waypoint::readFrom() hardening — reject a truncated trail
snapshot instead of proceeding with garbage header fields. Consistency
with the waypoint store's persistence path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 12:53:40 +02:00
MarekZegare4andClaude Sonnet 4.6 fcdacaa3bc fix: GPS shutdown active-level, buzzer octave-8 consistency, waypoint header read checks
- UITask::shutdown(): power GPS off using !PIN_GPS_EN_ACTIVE instead of hardcoded
  LOW, matching MicroNMEALocationProvider::stop() (still LOW on current active-high
  devices, but correct for a future active-low GPS).
- buzzer _noteFreq(): clamp octave to 8 instead of 7 so the parser's accepted range
  (4-8) is fully consumed; previously an octave-8 digit was clamped away and could
  leak into the stream as the next note's duration.
- Waypoint::readFrom(): check read() return for version/reserved/count header bytes
  so a truncated file is rejected instead of using garbage count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 12:49:15 +02:00
MarekZegare4andClaude Sonnet 4.6 6c5a40a8ce fix(power): power off GPS before SYSTEMOFF to prevent battery drain on shutdown
NRF52 GPIO pins retain their last state in SYSTEMOFF. If GPS was active,
PIN_GPS_EN stays HIGH and the module keeps drawing ~20mA. gps_enabled is
already persisted to flash so applyGpsPrefs() restores the correct state
on next boot.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 12:29:33 +02:00
MarekZegare4andClaude Sonnet 4.6 2c847c996f docs(readme): rename to MeshCore Solo Companion Firmware, add supported devices table, consolidate solo tools section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 10:16:13 +02:00
MarekZegare4 be6767b0cb Merge remote-tracking branch 'upstream/main' 2026-06-14 09:57:48 +02:00
MarekZegare4andClaude Sonnet 4.6 2766a098a5 fix(bot): preserve trigger case, lowercase only at match time
Trigger is now stored as typed (e.g. "Ping" stays "Ping").
Case-insensitive matching is preserved by lowercasing both
the trigger and incoming message at comparison time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 09:53:09 +02:00
MarekZegare4andClaude Sonnet 4.6 ec4b7d625f fix(ui): force immediate refresh when BLE disconnects
UITask.onBLEDisconnected() sets _next_refresh=0 so the BLE icon
updates instantly instead of waiting for the next polling cycle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 12:59:41 +02:00
MarekZegare4andClaude Sonnet 4.6 a1fc67ed96 feat(variants): enable ENABLE_SCREENSHOT on all solo_dual builds
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 09:50:31 +02:00
MarekZegare4andClaude Sonnet 4.6 5ec61477e6 feat(ui): simplify solo splash label, remove outdated WIOTRACKER_L1.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 09:46:45 +02:00
MarekZegare4 ea9681075d Merge remote-tracking branch 'upstream/main' 2026-06-11 13:09:31 +02:00
MarekZegare4andClaude Sonnet 4.6 99a35cade7 fix(ci): strip _companion from solo firmware filenames
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 11:02:59 +02:00
MarekZegare4andClaude Sonnet 4.6 e83b2f706c fix(ci): search variant subdirs for _solo_dual envs in matrix generation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 10:57:01 +02:00
MarekZegare4andClaude Sonnet 4.6 8261c3c364 feat(ci): dynamic solo firmware build workflow, add _solo_dual envs for Wio Tracker L1
- Add build-solo-firmwares.yml: auto-detects all _solo_dual envs from platformio.ini, builds in parallel, publishes uf2 files to draft release
- Remove build-wio-tracker-l1-firmwares.yml (replaced by solo workflow)
- Add WioTrackerL1_companion_solo_dual and WioTrackerL1Eink_companion_solo_dual envs
- Wire build-solo-firmwares command in build.sh using _solo_dual suffix

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 10:43:33 +02:00
MarekZegare4 b0de91e416 polishing v2 2026-05-28 20:37:20 +02:00
MarekZegare4 c1e713c7b4 polishing v1 2026-05-28 12:44:23 +02:00
MarekZegare4 149693c928 docs refactor 2026-05-28 10:54:09 +02:00