Files

6.0 KiB
Raw Permalink Blame History

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.