docs: clock tools + e-ink input handling; v1.21 release notes

- release-notes v1.21: add Clock tools (alarm/timer/stopwatch) to What's new,
  e-ink button responsiveness + double-tap debounce to Fixes, and the input
  edge-capture/key-queue and hardware-timer ringtone notes to Under the hood.
- README: note clock tools on the Clock Screen entries.
- solo_ui_framework: document the hardware->handleInput path (mandatory
  begin() per button, IRQ edge capture, key queue + coalesced redraw).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MarekZegare4
2026-06-30 22:40:44 +02:00
parent f31596da1a
commit 7e0dbe4afc
3 changed files with 31 additions and 2 deletions

View File

@@ -47,7 +47,7 @@ All firmware files are published on the [releases page](https://github.com/Marek
- [Settings Screen](./docs/solo_features/settings_screen/settings_screen.md) — configure display, sound, home page order, radio and system settings - [Settings Screen](./docs/solo_features/settings_screen/settings_screen.md) — configure display, sound, home page order, radio and system settings
- [Clock Screen](./docs/solo_features/clock_screen/clock_screen.md) — view time and date plus up to three configurable data fields - [Clock Screen](./docs/solo_features/clock_screen/clock_screen.md) — view time and date plus up to three configurable data fields, with built-in clock tools (one-shot alarm, countdown timer, stopwatch)
- [Screen Lock](./docs/solo_features/screen_lock/screen_lock.md) — lock the device to prevent accidental keypresses, with a lock screen showing time and sensor data - [Screen Lock](./docs/solo_features/screen_lock/screen_lock.md) — lock the device to prevent accidental keypresses, with a lock screen showing time and sensor data
@@ -96,7 +96,7 @@ Updating to a newer version usually does not require erasing flash unless the re
| -------------------------------------------------------------------------- | --------------------------------------------------------------------- | | -------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| [Messages Screen](./docs/solo_features/message_screen/message_screen.md) | Sending messages, context menus, reply, navigate to / save shared locations, Notif/Melody overrides | | [Messages Screen](./docs/solo_features/message_screen/message_screen.md) | Sending messages, context menus, reply, navigate to / save shared locations, Notif/Melody overrides |
| [Favourites Dial](./docs/solo_features/favourites_dial/favourites_dial.md) | Pinned contacts grid, unread badges, pin/unpin | | [Favourites Dial](./docs/solo_features/favourites_dial/favourites_dial.md) | Pinned contacts grid, unread badges, pin/unpin |
| [Clock Screen](./docs/solo_features/clock_screen/clock_screen.md) | Clock page, date, configurable data fields | | [Clock Screen](./docs/solo_features/clock_screen/clock_screen.md) | Clock page, date, configurable data fields, alarm / timer / stopwatch |
| [Settings Screen](./docs/solo_features/settings_screen/settings_screen.md) | All settings sections with values and interactions | | [Settings Screen](./docs/solo_features/settings_screen/settings_screen.md) | All settings sections with values and interactions |
| [Screen Lock](./docs/solo_features/screen_lock/screen_lock.md) | Lock/unlock sequence, lock screen, auto-lock | | [Screen Lock](./docs/solo_features/screen_lock/screen_lock.md) | Lock/unlock sequence, lock screen, auto-lock |
| [Tools Screen](./docs/solo_features/tools_screen/tools_screen.md) | GPS trail & waypoints, compass, navigation, nearby nodes, ringtone editor, auto-reply bot, auto-advert, live location sharing, locator, diagnostics, repeater | | [Tools Screen](./docs/solo_features/tools_screen/tools_screen.md) | GPS trail & waypoints, compass, navigation, nearby nodes, ringtone editor, auto-reply bot, auto-advert, live location sharing, locator, diagnostics, repeater |

View File

@@ -236,6 +236,31 @@ encoder-next). `KEY_CANCEL` and `KEY_CONTEXT_MENU` stay screen-specific. Joystic
rotation is handled upstream (`rotateJoystickKey`) — screens see already-rotated rotation is handled upstream (`rotateJoystickKey`) — screens see already-rotated
keys. keys.
### From hardware to `handleInput`
Each physical button is a `MomentaryButton` (`src/helpers/ui/MomentaryButton.h`);
`UITask::begin()` must call `begin()` on **every** one (the joystick directions
and Back included, not just the user button) — that sets `pinMode` and, where
enabled, claims the interrupt. `UITask::loop()` polls each button, maps its event
to a `KEY_*` code, and dispatches it to the current screen.
Two mechanisms keep input responsive when **`endFrame()` blocks the loop** for a
slow e-ink refresh:
- **IRQ edge capture** (`-D BUTTON_USE_INTERRUPTS`, e-ink boards). A GPIO
interrupt latches each press/release edge into a per-button ring buffer with
its own timestamp, so taps that land *during* a refresh aren't lost; `check()`
replays them afterwards. The nRF52 has only 8 GPIOTE channels (the radio takes
one) — if none is free a button silently falls back to polling, so it still
works, just without mid-refresh capture.
- **Key queue + coalesced redraw.** `loop()` drains *all* pending events from the
buttons into a small key FIFO, applies the whole burst (`handleInput` per key),
then redraws **once**. So three joystick flicks captured during one refresh move
the selection three steps for the cost of a single panel update, instead of
collapsing into an ignored multi-click or one-step-per-refresh. Buttons created
with `multiclick=false` therefore emit one discrete `CLICK` per release;
`multiclick=true` buttons still report double/triple-click.
--- ---
## 8. Persistence ## 8. Persistence

View File

@@ -9,6 +9,7 @@
- **Map & status-bar upgrades** — the home mini-map gains a **north marker** and a **scale tick**; the status line shows the tracked-node count and, with a fix, an **arrow + distance to the nearest tracked contact** (e.g. `Track:3 →120m`); a **GPS fix icon** sits in the top status bar (boxed once a fix is valid, plain while searching), shown only on GPS boards while **GPS** is enabled in Settings. - **Map & status-bar upgrades** — the home mini-map gains a **north marker** and a **scale tick**; the status line shows the tracked-node count and, with a fix, an **arrow + distance to the nearest tracked contact** (e.g. `Track:3 →120m`); a **GPS fix icon** sits in the top status bar (boxed once a fix is valid, plain while searching), shown only on GPS boards while **GPS** is enabled in Settings.
- **Trail auto-pause** — recording **freezes on stops** (banking elapsed time and breaking the map line across the idle gap) and **resumes on movement** without ending the session; the home-screen blink keeps going while paused. - **Trail auto-pause** — recording **freezes on stops** (banking elapsed time and breaking the map line across the idle gap) and **resumes on movement** without ending the session; the home-screen blink keeps going while paused.
- **Collapsible Tools** — tools are grouped into fold-in-place **Location / Comms / System** sections, the same model as Settings (Tools always opens folded to the section list), and the home carousel now uses **page-indicator icons** instead of dots. - **Collapsible Tools** — tools are grouped into fold-in-place **Location / Comms / System** sections, the same model as Settings (Tools always opens folded to the section list), and the home carousel now uses **page-indicator icons** instead of dots.
- **Clock tools — alarm, timer, stopwatch** — press **Enter** on the Clock page for three time utilities: a **one-shot wake alarm** (set hour/minute with the digit editor; a **bell** marks it on the clock face and the status bar while armed), a **countdown timer** (full **HH:MM:SS**, single-digit cursor), and a **stopwatch**. The alarm and timer **ring with a melody — overriding mute** — and are silenced by **any key**. They keep running with the display off or locked, and the alarm is scheduled as an **absolute instant** so it survives the clock re-syncs the mesh / app / GPS / CLI can trigger at any time (it can't wake the device from a full Shutdown, where the CPU is off).
- **Waypoint coordinate editor** — add a waypoint by scroll-editing its latitude/longitude digit by digit. - **Waypoint coordinate editor** — add a waypoint by scroll-editing its latitude/longitude digit by digit.
- **On-device room login with saved passwords** — log in to a room server straight from the device (no phone app): pick the room and the password prompt appears automatically (a blank password works for open rooms), or re-login any time via the room's **context-menu "Login…"**. The password is **remembered across reboots**, so a room you've used before logs back in without retyping; a failed login (e.g. the server's password changed) forgets the stale password so the next attempt prompts again. Room passwords entered via the **phone app** are saved on the device too, so it can post to that room standalone after a reboot. Saved passwords are written with the same atomic, crash-safe persistence as contacts and channels. - **On-device room login with saved passwords** — log in to a room server straight from the device (no phone app): pick the room and the password prompt appears automatically (a blank password works for open rooms), or re-login any time via the room's **context-menu "Login…"**. The password is **remembered across reboots**, so a room you've used before logs back in without retyping; a failed login (e.g. the server's password changed) forgets the stale password so the next attempt prompts again. Room passwords entered via the **phone app** are saved on the device too, so it can post to that room standalone after a reboot. Saved passwords are written with the same atomic, crash-safe persistence as contacts and channels.
@@ -23,11 +24,14 @@
- **GPS status icon** is hidden when GPS is turned off in Settings, instead of sitting there empty. - **GPS status icon** is hidden when GPS is turned off in Settings, instead of sitting there empty.
- **Trail — start with GPS off** now prompts **"GPS is off — Enable GPS & start"** instead of silently starting a session that shows "Waiting for GPS fix" forever and records nothing. - **Trail — start with GPS off** now prompts **"GPS is off — Enable GPS & start"** instead of silently starting a session that shows "Waiting for GPS fix" forever and records nothing.
- Null-guarded the Locator target picker and clamped the loc-share channel index on load. - Null-guarded the Locator target picker and clamped the loc-share channel index on load.
- **e-ink button responsiveness** — joystick and Back presses are no longer dropped during a slow panel refresh. The directional buttons were never initialised for interrupt edge-capture (only the user button was), so they silently stayed on the polling path; now every button is initialised, and a burst of taps captured while the panel is refreshing replays as **discrete navigation steps** instead of collapsing into a single ignored multi-click. Edge capture and the live-pin self-heal are both debounced, so **contact bounce can't surface one press as a double-tap** (e.g. start+stop on the stopwatch).
### Under the hood ### Under the hood
- **Streaming trail simplification** — GPS points are simplified as they're recorded via a fixed-corridor (ReumannWitkam) pass: straight runs collapse to their two endpoints while curves stay bounded to within the **Min dist** tolerance of the real track, so the 512-point buffer covers a far longer route than a flat point budget would suggest. The buffer is kept at 512 points to bound the static RAM footprint on nRF52. - **Streaming trail simplification** — GPS points are simplified as they're recorded via a fixed-corridor (ReumannWitkam) pass: straight runs collapse to their two endpoints while curves stay bounded to within the **Min dist** tolerance of the real track, so the 512-point buffer covers a far longer route than a flat point budget would suggest. The buffer is kept at 512 points to bound the static RAM footprint on nRF52.
- A UITask-decoupled active-target resolver (`resolvePersonPos` / `activeTargetPos`) replaces the duplicated target-resolution logic that lived separately in the Locator, Navigate and Map entry points. - A UITask-decoupled active-target resolver (`resolvePersonPos` / `activeTargetPos`) replaces the duplicated target-resolution logic that lived separately in the Locator, Navigate and Map entry points.
- `-Os` size optimisation on the e-ink and GAT562 30S solo envs to keep them within the flash budget. - `-Os` size optimisation on the e-ink and GAT562 30S solo envs to keep them within the flash budget.
- **Input edge-capture + key queue** — on e-ink, button edges are latched by a GPIO interrupt during the blocking `endFrame()` refresh and replayed once the loop runs again; `loop()` then drains the whole burst into a small key FIFO and applies every key before a **single** redraw. Rapid navigation neither gets lost nor costs one slow refresh per step. (Buttons fall back to polling automatically if no GPIOTE channel is free.)
- **Ringtone player on a hardware timer** — note advance moved off the `loop()` poll onto an nRF52 TIMER1 compare interrupt, so a blocking e-ink refresh can no longer stretch or skip a note; alarm/timer melodies stay on tempo regardless of render cadence.
> **Upgrade note:** if a previous version lost your contacts after a hang, you'll need to re-add them once — the atomic-save protection applies from this release onward. > **Upgrade note:** if a previous version lost your contacts after a hang, you'll need to re-add them once — the atomic-save protection applies from this release onward.