diff --git a/README.md b/README.md index c75159d8..7d622dc1 100644 --- a/README.md +++ b/README.md @@ -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 -- [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 @@ -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 | | [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 | | [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 | diff --git a/docs/design/solo_ui_framework.md b/docs/design/solo_ui_framework.md index ef3abbd9..9dd09df1 100644 --- a/docs/design/solo_ui_framework.md +++ b/docs/design/solo_ui_framework.md @@ -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 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 diff --git a/release-notes.md b/release-notes.md index d6a43596..536697fe 100644 --- a/release-notes.md +++ b/release-notes.md @@ -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. - **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. +- **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. - **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. - **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. +- **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 - **Streaming trail simplification** — GPS points are simplified as they're recorded via a fixed-corridor (Reumann–Witkam) 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. - `-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.