Files
roro9stack/docs/milestones/M0.md
T

90 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M0 — Skeleton: Launcher, Status Bar, Settings, battery
**Status:** done on 2026-10-02, tagged `v0.1.0`.
## Outcome
Every "Done when" item below works on the device, apart from the gaps listed here. Changes made along the way:
- **Not done, carried over:**
- **Charging indicator:** the battery voltage alone can't tell charging apart reliably. Revisit if the hardware exposes a charger status.
- **Waking from power-off with a keyboard key:** G0 only for now.
- **Status Bar placeholders** for GNSS, mesh, Wi-Fi and unread count are left out until those Services exist (M1, M2, M4).
- **Added:**
- **SD card erase**, in Settings → Storage.
- **A Notification wakes an Off screen** (dimmed) while its Toast shows.
- **Navigation arrows without Fn** outside Text Entry.
- **Serial dev commands** and `scripts/serial_log.sh`.
- **Measured on the device:**
- About 225 KB free heap with the 64 KB frame buffer.
- About 15 ms per frame.
- 19% of the app flash used.
**Goal:** a firmware you can flash and hold. It boots to a Launcher, shows a live Status Bar, navigates with the keyboard and saves Settings. It proves the App/Service architecture that every later milestone plugs into.
## Done when
- Building, testing and flashing each work with one command, run inside a local Docker container (no toolchain on the host).
- First boot runs the setup wizard (names, Region, timezone), and later boots skip it.
- The Launcher lists Apps. Enter starts one, `` ` `` goes back, and Fn+`` ` `` returns home from anywhere.
- The Status Bar shows battery %, a charging indicator and the clock (relative until set), with placeholders for GNSS, mesh, Wi-Fi and unread count.
- The Settings App edits and persists: long and short name, Region, timezone, brightness, dim and off timeouts, sound on/off, and probe-request MAC handling (raw by default).
- An About screen shows the version, free heap, battery voltage, SD status and usage, and uptime.
- The screen dims at 30 s and turns off at 60 s. Any key wakes it without the key also acting on the App.
- A long press of G0 powers off (deep sleep). G0 or a key wakes the device.
- The Compose Key types accented characters in the line editor (`opt` `'` `e` → é).
- Toast Notifications work. A demo App can raise one, with a beep and LED flash.
- SD usage is watched: a Storage Warning appears once per boot above 80%. The Log-write cutoff flag is set at 90%, with no Log writers yet.
## Out of scope for M0
Storage Clean-up screen (M1, once IRC Logs exist), any radio, GNSS, Wi-Fi.
## Work breakdown
1. **Project scaffold**
- PlatformIO project with the pioarduino platform (Arduino-ESP32 3.x on ESP-IDF 5.x). Board `m5stack-stamps3`, 8 MB partitions, USB-CDC on boot.
- Dependencies: `M5Cardputer` (pulls in M5Unified and M5GFX).
- `LICENSE` (GPL-3.0), `README.md` with build and flash steps, a version string injected from git at build time (semver tags).
- A `native` environment for host-side unit tests (Unity).
- **Local CI** in a Docker image with PlatformIO. One script builds the firmware and runs the native tests, and the same container flashes over USB. The repo is hosted on self-hosted Gitea, and a Gitea Actions workflow can reuse this image later.
2. **Hardware bring-up checks** (manual, on the device)
- Display, keyboard (TCA8418) and speaker through M5Cardputer.
- Confirm there's no PSRAM, and record the heap at boot.
- Investigate the G38 backlight/LED power-rail coupling, then decide how dimming works without killing the LED.
- Battery ADC on G10 (×2 divider): calibrate the voltage-to-% curve.
- SD card mount on the shared SPI bus (CS=12), behind a bus lock ready for the LoRa radio in M3.
3. **Core runtime**
- **Event bus:** Services publish events (battery changed, notification, storage threshold), and the UI consumes them on the UI task.
- **Service interface:** start, stop, periodic tick, state snapshot for the Status Bar.
- **App interface:** enter, exit, key event, draw. Plus a registry, so adding an App means one file and one registration line.
- **App lifecycle:** one foreground App; Home and Back handling.
4. **Services for M0**
- **Settings store:** typed keys in NVS (internal flash), with defaults and change events.
- **Battery Service:** sampled voltage, smoothed %, charging detection if the hardware allows it.
- **Clock Service:** no time source yet. API for "set from source X", plus relative-time formatting and Europe/Brussels conversion.
- **Storage Service:** SD present/absent, usage %, 80% and 90% thresholds raising events, Log-write permission flag.
- **Power Service:** dim and off timers, wake-key swallowing, G0 long-press → deep sleep.
5. **Widget kit** (ADR 0002): an off-screen buffer pushed to the display.
- Status Bar, list, text view, line editor (with the Compose Key), dialog and Toast.
- A Latin-1 font set.
6. **Input layer**
- Map key events to logical keys: arrows (Fn + `;` `.` `,` `/`), Back, Home, Select.
- Compose Key dead-key state machine. This is pure logic, unit-tested on the host.
7. **Apps:** Launcher, Settings (including About), first-boot wizard, and a hidden Demo App for exercising Toasts and widgets.
8. **Docs:** a short walkthrough for a first-time setup: install PlatformIO, USB permissions on Linux, flash, recover via download mode.
## Host-tested logic (TDD candidates)
- Compose Key state machine
- Battery voltage → % curve and smoothing
- Storage threshold and once-per-boot warning logic
- Relative-time formatting and timezone conversion
- Settings defaults and validation (e.g. Region must be confirmed before any transmit flag)
## Risks to resolve early
- **G38 shared rail:** if the backlight and LED really share power, "screen off" may also need to turn the LED off.
- **RAM headroom:** the off-screen buffer is 240×135×2 ≈ 64 KB at 16-bit, or about 32 KB at 8-bit. Measure the free heap now, because Wi-Fi + TLS (M1) is the tightest point.
- **Keyboard library maturity** for the ADV's TCA8418 in `M5Cardputer`. Fall back to Adafruit_TCA8418 directly if needed.