at main
2 folders
7 files
Add the WiFi-station store and NTP clock-sync backend
From Settings (vault unlocked) the device can join a saved WiFi network
as a station, sync the clock via one-shot SNTP against trusted public
NTP servers, and always disconnect. Servers are LITERAL IPv4 only —
never a hostname, never DNS (esp_sntp is fed parsed addresses; a strict
dotted-quad validator gates every entry). Defaults are Cloudflare
(162.159.200.1, 162.159.200.123), Google (216.239.35.0) and NIST
(132.163.97.1), tried in order; the user can persist an override list
of up to four IPs so dead defaults never require a firmware update.
Saved networks (SSID+PSK, max 8) and the NTP server list live in a new
wifi.bin vault module using the standard envelope (AES-256-CBC +
HMAC-SHA256, encrypt-then-MAC, verify-before-decrypt, type-bound), only
readable with the vault unlocked, staged through the crash-safe rekey,
and crypto-erased by wipeAll. PSKs are zeroized after use and never
logged or echoed.
The sync engine runs on a Core-0 worker: BLE off, join the strongest
saved network, query servers in order, sanity-clamp the epoch and never
step backward past an armed lockout, commit via the rtc facade with a
new display-only src=ntp tag — clock TRUST is never elevated (NTP is
unauthenticated; the forward-jump lockout fail-closed model is the
spoofing defense) — then a RAII station guard tears WiFi down and
restores BLE on every exit path. The station facade stays a generic
transport for future consumers (on-device OTA).
Debug console gains WIFISCAN / WIFIADD / WIFILIST / WIFIDEL, NTPSYNC
(GPSSYNC-style blocking flow with machine-checkable teardown acks) and
NTPSERVERS? / NTPSERVERSET / NTPSERVERCLEAR — all DEBUG_SERIAL_BUTTONS
gated. HIL-verified end to end on the StickS3: real sync against the
default servers, user-list precedence across reboot, TEST-NET failure
paths, trust unchanged, BLE restored, store left clean.
Claude-Session: https://claude.ai/code/session_01SV58JXhfxhhc9DC6vdjBo4
feat(ui): add Phase 2 stateless reference components (ActionBar/Header/BrandMark/StatusChip)
First catalog components on the Canvas + DeviceProfile foundation
(plan/ui-library-modular-reimpl.md Phase 2). Stateless: props in ->
draw via Canvas -> return, reading the orthogonal DeviceProfile for
device adaptation. Purely additive — no existing screen/state/widget/
Canvas changed.
- ActionBar (action_bar_component): affordance-driven footer hints. The
same ActionBarProps render the device-correct presentation picked from
the profile capabilities — 2-button A/B, 3-button A/B/C, CoreInk dial
^/O/v, keyboard key hints, touch bare labels. Mono1/e-paper path uses a
top divider rule + cell inversion instead of the SURFACE fill + ACCENT
hold-fill.
- Header (header_component): title + subtitle + right-packed status
cluster (battery %, BLE, WiFi, lock). Density/orientation-aware via
LayoutContext; Mono1 uses a bottom divider rule, ink-only tokens.
- BrandMark (brand_mark_component): credential brand badge. Reuses the
brands::findBrand/drawBrand registry+atlas on device; falls back to a
deterministic per-domain letter tile (host-testable). Mono1 outlines.
- StatusChip (status_chip_component): self-sizing status pill using
radius.pill (clamped), token color per ChipStyle, knockout/outline text.
Tests (host, RecordingCanvas): 30 new cases across 4 suites, incl. the
per-affordance ActionBar assertions (2btn/3btn/dial/keyboard/touch), the
Mono1 branches, brand letter-fallback + deterministic color, and chip
sizing/geometry. Shared per-variant DeviceProfile factories in
test/support/device_profiles.h.
Verified: fleet 5/5 -Werror (sticks3/gray/cardputer/tdeck/m5core_ink),
native 720/720 (+30), pio check 3 pre-existing HIGH only, all guards +
pre-commit pass.
feat(ui): finalize 2-button text editors — fidelity, AA overlay focus box, slide animation
Polish the CharWheel (carousel; color devices) and CharGrid (mono/e-paper) text
editors to the approved mockups and fix the focus-box rendering + add selection
animation.
- Fidelity: enlarge the carousel selection box, add the wheel position dots,
switch the chip row to "ABC abc 123 -_. DEL OK" (utility chips), drop the
leading back cell; keep every grid glyph bright (box-only focus).
- Focus box: replace the stacked-1px outline (which left the right/bottom border
missing where neighbor cells overdrew it) with a single equal-weight AA stroke
drawn as a TOP overlay after the glyphs. Adds a thickness parameter to
ui::aa::strokeRoundRectAA + a Canvas::drawRoundRect(thickness) virtual — AA on
color panels, concentric crisp outlines on Mono1/e-paper.
- Animation: the selection slides via ui::Tween (Easing::InOutQuad, 150 ms, like
the menu highlight / tab pill) — the grid box slides cell->cell, the carousel
glyph ring slides through the fixed box; gated to color / Refresh::Instant,
snaps on mono / e-paper.
Native: 1040/1040. Builds: sticks3_debug, m5stack_gray. Verified on StickS3
(4-sided AA border on both editors + the cell/ring slide animation).