Document the GPS layer, add T-Deck HIL coverage, fix VALSET on real silicon
Add the u-blox M10 introspection chip page and index row, and a HIL suite
(test_gps_layer.py) exercised on the real T-Deck module. The first hardware
run surfaced three genuine M10 behaviors the unit tests could not:
- UBX-CFG-VALSET layers is a bitmask (RAM = bit 0 = 0x01), not the VALGET
layer enum: an all-zero mask writes nowhere and never ACKs, so every
GPSCFG set! silently failed. Fixed + native regression test.
- readStatus must enable periodic NAV-PVT/NAV-SAT/MON-HW UART1 output first:
the M10 boots NMEA-only and ignores on-demand status polls.
- Config/ACK timeouts raised and a VALSET resend budget added, since VALGET/
VALSET now compete with that periodic stream.
Fleet 43/43 -Werror, native 1716/1716, clang-tidy 0, doxygen 0. HIL on the
real u-blox M10: 6 passed / 1 skip (GPSPROBE u-blox M10, GPSSYNC_OK via NVS
fast-path, GPSCFG dump/get/critical-bang read-back-safe, GPSMON).
Claude-Session: https://claude.ai/code/session_01SV58JXhfxhhc9DC6vdjBo4
Add "GPS time sync" settings action and progress overlay (HAS_GPS boards)
Settings -> Device gains a one-shot "GPS time sync" row on HAS_GPS boards
(DEVICE reaches exactly kSettingsMaxItems there; GPS-less boards keep the
4-item layout with RESTART last). Selecting it opens GpsSyncController, a
thin overlay over the gps:: sync engine: it polls syncPoll, refreshes the
elapsed/timeout countdown once per second, and closes on fix (success
toast), timeout acknowledgement, or cancel (B-long on button boards, Esc
on keyboard boards). Every UI exit path — including overlay idle-sleep and
the parent reset — funnels through reset(), whose syncCancel powers the
receiver down. The trailing settings value surfaces the last clock-set
provenance (ClockSource).
Long-press edges are polled before short-click polls on the same button,
matching the documented ButtonInput call order.
Carried polish: the UART facade begin() now releases the TX/RX pads on its
partial-failure branch, syncCancel documents the Core-1 owning-task
contract, and the stale SyncPhase::Idle doc phrase is reworded.
Claude-Session: https://claude.ai/code/session_01SV58JXhfxhhc9DC6vdjBo4
Fix the GPS baud (T-Deck runs at 38400) and add a GPSDIAG probe
The GPS time sync never fixed on the T-Deck Plus: the driver opened the
UART at 9600 (the generic datasheet default) but the fitted module runs
at 38400, so the firmware only ever read framing garbage. Root-caused on
hardware with the new GPSDIAG probe (bytes>0 but nmea_ok=0 across every
baud but 38400) and validated end-to-end: GPSSYNC_OK, clock set from a
real GN fix, src=gps, trust=volatile.
- GPS_BAUD_RATE is now a per-variant constant (device::kGpsBaudRate),
38400 for the T-Deck, 9600 default elsewhere.
- syncPoll drains the whole RX ring each pass, not one 128-byte chunk:
a multi-GNSS module at 38400 outruns a single read per poll interval
and would overflow the ring, shredding the RMC/ZDA sentences.
- GPSDIAG [seconds] [baud]: a read-only receiver-state probe (raw NMEA
echo, or a 5-second acquisition monitor on long windows) reporting
bytes/NMEA/UBX presence, satellites in view / tracked / max C/N0, and
fix type — a serial GPS health check in the spirit of REGS?/RTC?.
native 1704, tdeck/sticks3/cardputer/coreink -Werror, clang-tidy 0,
variant/conditional guards clean.
Claude-Session: https://claude.ai/code/session_01U878bNJtg9bCvAMM8CFKqS
Document the GPS layer, add T-Deck HIL coverage, fix VALSET on real silicon
Add the u-blox M10 introspection chip page and index row, and a HIL suite
(test_gps_layer.py) exercised on the real T-Deck module. The first hardware
run surfaced three genuine M10 behaviors the unit tests could not:
- UBX-CFG-VALSET layers is a bitmask (RAM = bit 0 = 0x01), not the VALGET
layer enum: an all-zero mask writes nowhere and never ACKs, so every
GPSCFG set! silently failed. Fixed + native regression test.
- readStatus must enable periodic NAV-PVT/NAV-SAT/MON-HW UART1 output first:
the M10 boots NMEA-only and ignores on-demand status polls.
- Config/ACK timeouts raised and a VALSET resend budget added, since VALGET/
VALSET now compete with that periodic stream.
Fleet 43/43 -Werror, native 1716/1716, clang-tidy 0, doxygen 0. HIL on the
real u-blox M10: 6 passed / 1 skip (GPSPROBE u-blox M10, GPSSYNC_OK via NVS
fast-path, GPSCFG dump/get/critical-bang read-back-safe, GPSMON).
Claude-Session: https://claude.ai/code/session_01SV58JXhfxhhc9DC6vdjBo4
Document the GPS layer, add T-Deck HIL coverage, fix VALSET on real silicon
Add the u-blox M10 introspection chip page and index row, and a HIL suite
(test_gps_layer.py) exercised on the real T-Deck module. The first hardware
run surfaced three genuine M10 behaviors the unit tests could not:
- UBX-CFG-VALSET layers is a bitmask (RAM = bit 0 = 0x01), not the VALGET
layer enum: an all-zero mask writes nowhere and never ACKs, so every
GPSCFG set! silently failed. Fixed + native regression test.
- readStatus must enable periodic NAV-PVT/NAV-SAT/MON-HW UART1 output first:
the M10 boots NMEA-only and ignores on-demand status polls.
- Config/ACK timeouts raised and a VALSET resend budget added, since VALGET/
VALSET now compete with that periodic stream.
Fleet 43/43 -Werror, native 1716/1716, clang-tidy 0, doxygen 0. HIL on the
real u-blox M10: 6 passed / 1 skip (GPSPROBE u-blox M10, GPSSYNC_OK via NVS
fast-path, GPSCFG dump/get/critical-bang read-back-safe, GPSMON).
Claude-Session: https://claude.ai/code/session_01SV58JXhfxhhc9DC6vdjBo4