oss

gpsd makes one receiver a shared sensor—and keeps the pulse separate

8 sources 0 primary sources August 26, 2026

Text
Two Navcom GNSS receivers flank a Garmin handheld, with cables and a glowing Bluetooth serial adapter visible against an evening sky.

Two Navcom SF-2040G receivers, a Garmin 12XL, and a Bluetooth serial adapter photographed in 2006. The hardware variety is the point: gpsd puts a stable client boundary in front of changing receivers, links, and wire protocols. Photograph by Wsx2.[8]

A GNSS receiver looks like a location API only from a great distance. Up close, it is a scarce device file emitting reports on its own schedule: perhaps NMEA sentences, perhaps a vendor's binary packets, perhaps a mixture of navigation and status messages over serial, USB, Bluetooth, TCP, or another transport. One application can open that stream directly. A second application then has to share it, proxy it, or lose.

gpsd solves that plumbing problem by putting a durable service boundary between receiver-specific bytes and location-aware programs. It recognizes packets, chooses a user-space driver, accumulates per-device state, and publishes device-independent reports to multiple clients. The architecture matters because it keeps three things that are often blurred together visibly separate: what the receiver said, what a client can currently know, and how a precise one-pulse-per-second edge becomes a clock input.[1][2][3]

The cover photograph shows why that indirection earns its keep. Two survey-oriented Navcom receivers sit beside a Garmin handheld; one Navcom has a Bluetooth serial adapter attached.[8] They are not interchangeable appliances, yet downstream software should not need a new parser merely because the physical link or receiver dialect changed.

Four stages stand between the wire and the client

The current Hacker's Guide divides gpsd into four pieces: packet sniffer, drivers, core library, and multiplexer.[2] Following a byte through those pieces explains more than a feature list.

First, the packet sniffer finds framed, checksummed packets in an incoming byte stream. It does not assume that the first recognized packet type will remain the only one. A receiver can change between NMEA and a vendor binary mode; an AIS device can emit more than one protocol on the same wire. Treating recognition as a continuing state-machine job, rather than a one-time startup guess, keeps transport discovery outside application code.[2]

Second, a driver interprets the recognized payload. Drivers know chipset or protocol details: how to turn a sentence or binary structure into time-position-velocity fields, status, satellite observations, or device information. They do not own client sockets. That boundary is what lets gpsd support NMEA variants and binary formats from vendors including Garmin, Navcom, SiRF, Trimble, and u-blox without asking each consuming application to carry the same protocol collection.[2][6]

Third, the core library manages a device session. It opens the path, searches baud rate and serial framing when needed, asks the sniffer what arrived, selects the matching driver, and maintains the session state. The session is per device. If two receivers are attached, gpsd can label their reports separately; it does not silently fuse them into a synthetic “best” position.[2][4]

Finally, the multiplexer handles client sessions, watch policies, hotplug notifications, and report delivery. The default socket service listens on TCP port 2947, normally on loopback. A client connects, receives a VERSION object, and asks to stream reports with a command such as ?WATCH={"enable":true,"json":true}. Multiple programs can then observe one receiver without racing to own /dev/ttyUSB0.[1][3][6]

This division also keeps power behavior legible. gpsd can leave a receiver closed until a client requests a watch, which matters for hardware that enters a lower-power state when its serial port is not held open. Time-service deployments are the opposite case: the -n option tells gpsd not to wait for a client because clock input must continue even when no location application is connected.[3][5][6]

JSON makes absence part of the contract

Once a client enables watcher mode, gpsd emits a stream of JSON objects rather than one perpetually complete location record. TPV carries time, position, and velocity; SKY carries satellite-view information; DEVICE describes a source; PPS and TOFF represent timing events when requested and available. Every object has a class, so a consumer can dispatch on meaning rather than infer it from field shape.[4]

The most important protocol choice is what happens when data is missing. gpsd does not fill unknown values with comforting zeros or JSON null; optional attributes are omitted. A TPV.mode value distinguishes unknown, no fix, two-dimensional fix, and three-dimensional fix, while individual fields such as altitude, speed, or error estimates remain conditional. The specification also warns that many receiver-supplied error estimates do not disclose their confidence convention, so gpsd cannot turn them into stronger evidence merely by normalizing their names.[4]

That forces a good client to be state-aware. It must check the fix mode and field validity before using latitude, altitude, time, or uncertainty. It must also remember which device produced a report. The client libraries exist partly to absorb protocol evolution and turn the object stream into native structures, but they cannot make an absent fix present or make stale accumulated state current.[3][4]

There is a lower-level failure boundary too. A JSON response is capped at 10,240 characters in the current protocol, and an overlong response can be truncated into invalid JSON. A slow watcher can eventually fill its socket buffer and be disconnected. These are unusual at ordinary GNSS report rates, but they reveal the correct implementation posture: read continuously, treat each object as a bounded message, use the library where practical, and reconnect deliberately rather than assuming the socket is an immortal in-memory variable.[3][4]

The sentence names the second; the pulse marks its edge

Navigation time and precision timing enter through the same receiver, but they are not the same signal.

An in-band NMEA or binary report can state the UTC time associated with a fix. Its delivery is comparatively coarse: the receiver computes, buffers, and transmits a sentence burst, while serial framing, USB polling, kernel scheduling, and receiver behavior add variable latency. The gpsd time-service guide reports that fix messages may trail the actual measurement by hundreds of milliseconds and that the delay can change. That makes the message useful for identifying the second, but a poor marker of the exact boundary between seconds.[5]

A PPS-capable receiver supplies a separate electrical edge once per second. With Linux kernel PPS support—typically CONFIG_PPS plus an appropriate client such as CONFIG_PPS_CLIENT_LDISC or a GPIO PPS client—the kernel can timestamp that edge nearer to the interrupt than a user-space thread can. The time-service guide describes microsecond-class results under suitable hardware and load, while also making clear that USB polling, cable wiring, driver support, and host latency can widen the error budget.[5]

The two inputs therefore complement each other. The serial report says which second the receiver means; PPS says where its edge occurred with much lower jitter. PPS by itself is not a full UTC label, and a beautifully parsed timestamp is not automatically a precise pulse.

gpsd's role ends at a deliberate handoff. It can export in-band time and PPS timing through shared memory or chrony sockets such as /run/chrony.ttyS0.sock and /run/chrony.pps0.sock. chronyd or ntpd then evaluates reference sources and disciplines the system clock. gpsd is the receiver translator and timing-event supplier, not the clock-control algorithm.[5][6]

This boundary changes troubleshooting. If cgps shows no valid three-dimensional fix, the problem is still at the receiver, antenna, sky view, or decoded navigation layer. If navigation reports arrive but gpsmon or ppscheck sees no PPS, inspect receiver capability, the control-line wiring, /dev/pps0, kernel configuration, permissions, and the serial or USB driver. If both reach gpsd but chronyc sources does not select the reference, the remaining problem belongs to chrony configuration and source comparison. “GPS time is broken” is too coarse a diagnosis; the layers provide a sequence of falsifiable checks.[5]

Zero configuration is a design choice, not a universal promise

gpsd is optimized for a particular bargain: plug in a supported receiver, let hotplug and protocol discovery do the routine work, and give multiple applications a stable time-and-location service. Its project documentation explicitly favors autobauding and self-configuration, even when that means declining awkward hardware that would require weakening packet validation or adding device-specific startup switches.[1][2]

That bargain is excellent for a mobile Linux host, marine computer, field logger, robotics platform, or small observatory where a receiver feeds several read-only consumers. It is less complete when the job is to configure every advanced feature of modern GNSS hardware. James Clark's independent 2026 comparison with SatPulse identifies the boundary precisely: gpsd offers a device-independent model for periodic receiver data but only limited device-independent configuration; vendor-specific tasks may move into tools such as ubxtool.[7]

This is not a defect that a wrapper script automatically repairs. A timing appliance that must set antenna delay, pulse width, fixed-position timing mode, constellations, RTK behavior, or nonvolatile receiver state needs an explicit configuration owner. Mixing those writes with a zero-configuration read service can make startup order and recovery ambiguous. Use gpsd when normalization and sharing are the central problem; evaluate a configuration-centered design when programming the receiver is itself the product.[7]

Network exposure deserves the same clarity. Loopback is the default. -G changes the listener to all addresses, and the gpsd manual warns that doing so discloses current position to reachable clients.[6] A remote feed can be useful on a trusted instrument network, but it should be an intentional service boundary with firewalling and privacy review—not a convenient flag added because another machine could not open the serial port.

Rehearse the bad minute, not only the good fix

A useful pilot can fit on one Linux host, one supported receiver, and two deliberately different clients. Start with the daemon local to the hardware. Confirm the physical device path and use gpsmon to see raw packet recognition and driver selection. Use cgps for normalized fix and sky state. Then run a second client, such as a small libgps program or gpspipe, and verify that both can consume the receiver without either owning the serial device directly.[1][2][3]

Next, record a short raw packet log and replay it with gpsfake. A service whose value is hardware normalization should be testable without waiting for the same satellite geometry and field conditions to return. Assert behavior across no fix, two-dimensional fix, three-dimensional fix, absent altitude, device disconnect, reconnect, and a client that starts after the receiver is already reporting. Check the device field and validity state, not merely whether a latitude appeared.[2][4]

For a time-service use case, add PPS only after the navigation path is understood. Verify the pulse at the kernel and gpsd layers, confirm the separate in-band and PPS sources in chronyc sources or the corresponding NTP tooling, and keep independent network time sources available during the trial. Then obstruct the antenna or disconnect the receiver long enough to observe holdover and source rejection. A green clock while the sky is clear proves less than a clean transition when the reference disappears.[5]

The adoption boundary is modest. One engineer can own gpsd on a field device when the operating system, receiver model, and consumers are known. A fleet needs more: stable /dev/serial/by-id/ naming, package-version control, raw-log capture for regressions, alerts on lost fix and PPS, a documented privacy posture for port 2947, and a replacement receiver tested against the same log and client suite. Teams that cannot observe those states should not promote a single successful cgps screen into a positioning or timing service.

gpsd's durable idea is not that navigation hardware can be made uniform. It is that hardware difference can be contained. Receiver bytes remain receiver bytes; drivers translate them; JSON reports expose what is known and omit what is not; PPS stays distinct from the sentence that labels it; and clock discipline belongs to another daemon. That is enough separation for one awkward serial device to become dependable shared infrastructure—without pretending the physical world has become an API.

Sources

  1. GPSD project, “GPSd — Put your GPS on the net!” — shared sensor access, client libraries, hotplug behavior, and automatic receiver detection.
  2. GPSD project, “Hacker's Guide to GPSD” — current packet-sniffer, driver, core-library, multiplexer, autoconfiguration, and regression-testing boundaries.
  3. GPSD project, “GPSD Client HOWTO” — asynchronous receiver behavior, port 2947, WATCH, client libraries, device state, and slow-reader handling.
  4. GPSD project, gpsd_json(5) — JSON classes, optional-field semantics, TPV fix modes, watch policy, timing objects, and message-size limit.
  5. Gary E. Miller and Eric S. Raymond, “GPSD Time Service HOWTO” — in-band timing latency, PPS and kernel PPS, chrony/NTP handoff, diagnostics, and failure modes.
  6. GPSD project, gpsd(8) — supported receiver protocols, -n, loopback-by-default socket behavior, -G privacy boundary, and PPS export.
  7. James Clark, “Design of SatPulse compared with GPSd,” April 11, 2026 — independent comparison of gpsd's service, zero-configuration, receiver-sharing, and configuration boundaries.
  8. Wsx2, “Navcom GPS Receivers,” Wikimedia Commons — 2006 photograph of two Navcom receivers, a Garmin 12XL, and a Bluetooth serial adapter.
Previous Open seismology lets an earthquake catalog change its mind

Recommended In oss

Matched by subject and format