The GNSS Service reads the receiver (UART 15/13, 115200, 1 KB buffer) from its 50 ms tick and feeds the NMEA parser. With a Fix it sets the clock (GNSS is the most trusted TimeSource) and refreshes it every 10 min. Settings gets GNSS On/Off and the coordinate format (Q64). Off puts the receiver in standby with $PCAS12,65535, renewed hourly; On wakes it with a hot start, $PCAS10,0. Both measured on the device: the output stops within a second, and a command wakes it within a second. Commands: gnss status (Fix, satellites per constellation, bytes and sentences), gnss nmea on|off, gnss send <sentence>, gnss restart. The probe is gone; never drive GPIO 15 (the receiver's output): the first probe's swapped-pin attempt silenced it until a power cycle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
4.9 KiB
M2 — GNSS
Goal: the device knows where it is and what time it is without a network: a GNSS Service in the background, a GNSS App with the position and a sky view of the satellites, the clock set from satellites when there's no NTP, and Tracks recorded to the SD card.
Hardware: the Cap LoRa-1262 carries an ATGM336H-6N (AT6668), multi-constellation (GPS, BeiDou, Galileo, GLONASS, QZSS), with a ceramic antenna. NMEA over UART, 115200 8N1. Measured (step 1, gnss probe): RX GPIO 15, TX GPIO 13, 115200 8N1, as in Meshtastic's board file; M5Stack's page names GPIO 8 and 9, which are the internal I2C bus the keyboard controller sits on. Output is NMEA 4.10 style: GN RMC, VTG and GGA, one GSA per constellation with the system ID (1 GPS, 2 GLONASS, 3 Galileo, 4 BeiDou, 5 QZSS) in its last field, and a GSV sequence per constellation and signal (GP, GL, GA, …) with the signal ID last. RMC carries a time even without a Fix (status V), so only a Fix makes it trustworthy.
Decisions (design round 2026-10-04)
| # | Decision |
|---|---|
| Q58 | Settings has a GNSS On/Off switch, On by default. Off puts the receiver in standby. Measured: $PCAS12,<seconds> (CASIC) stops its output within a second, for up to at least 65535 s, and any command wakes it within a second; Off sends PCAS12,65535 (renewed hourly), On sends a hot start, PCAS10,0. |
| Q59 | The GNSS App has two views, switched with Tab. Position: latitude, longitude, altitude, speed, course, Fix (none / 2D / 3D), satellites used and in view, HDOP, UTC time. Sky: the satellites placed by azimuth and elevation, coloured by constellation, filled when used in the Fix. |
| Q60 | "Radar" in M2 means the Sky view. A radar of other Nodes by distance and bearing needs the mesh: M4. |
| Q61 | The Status Bar shows a GNSS mark: absent when off, muted while searching, normal with a 2D Fix, with the satellite count with a 3D Fix. |
| Q62 | GNSS time sets the clock once there's a Fix, and refreshes it every 10 minutes. Revised in step 3: the clock's trust order from M0 (Mesh < NTP < GNSS) already ranks GNSS above NTP, which is right: GNSS time is at least as accurate. So GNSS also corrects a clock NTP set, not only an unset one. |
| Q63 | A Track is started and stopped in the GNSS App. It's written as GPX to /gnss/tracks/<YYYYMMDD-HHMMSS>.gpx, a point every 5 s when the position moved more than 5 m. It keeps recording with the App closed, with a Toast on start and stop and a Status Bar mark, and gets its own Storage Clean-up category. |
| Q64 | Coordinates in decimal degrees plus the Maidenhead locator; a Settings switch for degrees, minutes and seconds. Metric units only. |
| Q65 | The position never leaves the device in M2. Sharing it over the mesh, and at what precision, is decided in M4. |
| Q66 | Our own NMEA parser, host-tested: RMC, GGA, GSA and GSV, with each talker ID mapped to its constellation. TinyGPSPlus (named in ADR 0001) doesn't track the satellite list across constellations, which the Sky view needs. |
| Q67 | The receiver keeps its defaults (all constellations, 1 Hz). No receiver settings. Time to first fix is measured and recorded here. |
| Q68 | Debug aids: gnss status, and gnss nmea on/off to stream the raw sentences to the console (USB serial and Debug Console). Raw NMEA is never written to the card. |
Lesson (step 3): the first probe also tried the pins swapped, driving the receiver's output line from the ESP32 for about a second. The receiver then went silent until a full power cycle (an ESP32 restart doesn't cut the Cap's power). Never drive GPIO 15.
Done when
- The GNSS Service reads NMEA in the background whatever App is on screen, and a 3D Fix appears outdoors.
- The GNSS App shows the Position and Sky views, both live.
- The Status Bar shows the GNSS mark per Q61.
- With no Wi-Fi, the clock is set from GNSS after the first Fix.
- A Track records while the App is closed, survives the screen turning off, and opens as valid GPX on the PC.
- Settings → GNSS Off stops it (and the Status Bar mark goes away); On brings it back.
- Free heap stays above about 40 KB with GNSS, Wi-Fi, IRC on TLS and the UI running.
Work breakdown
- Hardware check: a
gnss probecommand reads the candidate UART pins and reports which carries NMEA, at what baud rate, and which talker IDs. Then the standby command (Q58) and a first time to first fix. - NMEA parser (host-tested): checksum, RMC, GGA, GSA, GSV across constellations, merged into one GNSS state (Fix, position, time, satellites).
- GNSS Service: UART on its own task, the parser,
gnss statusandgnss nmea, Settings On/Off. - Clock from GNSS (Q62), and the Status Bar mark (Q61).
- GNSS App: Position view, Maidenhead and coordinate formats (host-tested), then the Sky view.
- Tracks: the 5 s / 5 m rule and GPX writing (host-tested), background recording, Clean-up category.