Bare-Metal Ada on the ESP32-S3 A step-by-step guide to running Ada on the ESP32-S3 with no ESP-IDF, no FreeRTOS, and no Python.

Step 38 of 56

GPS: a background service, not a device handle

The one driver here you do not poll through a handle. A task owns the UART, decodes NMEA continuously, and publishes into a protected store that timestamps its own staleness.

A different shape entirely

Every other device driver in this guide hands you a Device and lets you poll it. This one does not. It is a singleton background service: a library-level task owns one UART for its lifetime, continuously reads the receiver's NMEA-0183 stream, decodes it, and publishes results into a protected store. The application just reads that store. There is no handle.

That follows from the device: a GPS talks whenever it likes, so something has to be listening the whole time. This is the concrete case for interrupt-driven RX — a receiver that streams asynchronously is exactly what would overflow a polled FIFO.

procedure Setup (...);          --  call once at startup; Rx is the only pin needed

function Current_Position return Position_Reading;
function Current_Fix      return Fix_Reading;
function Current_Time     return Time_Reading;
function Current_Date     return Date_Reading;
--  ... plus velocity, signal and PPS readings

Why a fix is one record

Latitude and longitude are a single Position record updated by one protected action. Split across two variables, a reader could catch a new latitude with an old longitude — a coordinate that describes somewhere you have never been, with nothing to signal it is wrong. Every published value is written and read under the store's lock, so a reader never sees a half-updated value, and a fix is always a consistent pair.

Staleness is explicit

Each value group carries the Ada.Real_Time.Time at which it was last refreshed, and the driver only refreshes a group from a valid sentence — a lost fix is not written at all.

So a stale group keeps its old timestamp rather than being cleared, and Current_Position will happily return a position from twenty minutes ago that reads as perfectly plausible. Compare Age (R.Updated_At) against your own tolerance before trusting any reading. The API cannot decide for you how old is too old — that depends on whether you are tracking a ship or a pedestrian.

type Fix_Quality is (No_Fix, GPS_Fix, DGPS_Fix);
type Fix_Type    is (Fix_None, Fix_2D, Fix_3D);
type GNSS_System is (GPS, GLONASS, Galileo, BeiDou, QZSS, Other);

The satellite list and GNSS_System reflect that a modern receiver tracks several constellations at once. Uses the controlled UART session plus a task and protected objects, so it is embedded/full only.