diff --git a/docs/milestones/M0.md b/docs/milestones/M0.md new file mode 100644 index 0000000..13f5858 --- /dev/null +++ b/docs/milestones/M0.md @@ -0,0 +1,69 @@ +# M0 — Skeleton: Launcher, Status Bar, Settings, battery + +**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.