Go packages

The Go packages are organized into three main hierarchies: gps/ for GPS processing (no external dependencies), time/ for time synchronization (depends on gps/), and internal/ for satpulsetool subcommands (depends on both).

Within each hierarchy, packages are organized into layers where each layer depends only on packages in the same or lower layers.

Command-line layer provides the user interface to the programs, including the command-line interface and the configuration file.

Application layer provides the main blocks of the applications.

Domain layer provides packages using domain-specific abstractions that are used by the application layer. These packages have mutual dependencies. They do not make use of goroutines nor do they perform logging.

Library layer provides a library of packages, which are potentially useful outside satpulse. There are few mutual dependencies. These packages do not make use of goroutines nor do they perform logging.

The following sections describe each directory that contains packages.

cmd/

These packages provide entry points for the SatPulse executables. They are in the command-line layer.

cmd/satpulsed provides main for satpulsed.

cmd/satpulsetool provides main for satpulsetool.

cmd/ifwait provides a program that waits for a network interface to become ready. It exercises the functionality of the time/lib/ifwait package.

gps/

These packages provide the public API for GPS processing. They are in the domain layer.

gps/ptime provides a Time type that represents time in the PTP timescale (nanoseconds in TAI timescale since 1970-01-01T00:00:00 TAI). This is used throughout the domain layer and higher level layers.

gps/scan provides a Packet type representing a packet of GPS data in some protocol. It also provides a scan function to split up a stream of bytes into packets. It does not interpret the content of the packet.

gps/gpsprot abstracts a GPS protocol such as UBX or NMEA. This operates in two phases: configuration and post-configuration. The post-configuration part of this defines types that represent the information contained in GPS messages in a protocol-independent way.

gps/gpsreg provides a registry for the various implementations of the gps/gpsprot layer. Higher layers avoid interacting with the implementations for specific protocols as much as possible. Generally the command-line layer interacts with gps/gpsreg, and passes the appropriate implementations into lower layers.

gps/gpsdecode decodes binary GPS packets into JSON-serializable maps derived from the Go structs defined in the library layer packages.

gps/msgfile parses TOML message files that describe GPS messages to send to a receiver. It handles multiple protocol types (UBX, CASBIN, ASBIN, NMEA, line, binary), applies per-type defaults, and converts typed messages into raw bytes ready to send. Messages are organized by tags for selective sending.

gps/app/

These packages provide GPS orchestration and CLI infrastructure. They are in the application layer.

gps/app/gpsio implements a goroutine that reads input from the GPS, splits it into packets and sends those packets to a channel. It provides an abstraction for performing IO on a GPS, which can work either over a serial connection (using gps/lib/term) or over a network connection. The input is split into packets using the gps/scan package.

gps/app/gpscfg drives the GPS configuration process. It combines gps/app/gpsio and gps/gpsprot.

gps/app/cmd provides some common functionality used for command-line interfaces.

gps/app/logfile provides utility functions for opening and reopening log files.

gps/app/bcast provides a concurrency abstraction that broadcasts a channel to multiple other channels. This is used for routing packets inside the application. At the moment it is used by satpulsed rather than satpulsetool, but it is useful for applications dealing with GPS packets.

gps/internal/

These packages implement the gpsprot interface for specific protocols. They are in the domain layer and are not importable outside gps/.

gps/internal/ubx implements gps/gpsprot abstractions for the UBX protocol. It uses gps/lib/ubxbin and gps/lib/ubxcfgval to do this.

gps/internal/nmea implements gps/gpsprot abstractions for the NMEA protocol.

gps/internal/rtcm implements gps/gpsprot abstractions for the RTCM protocol.

gps/internal/casic implements gps/gpsprot abstractions for the CASIC binary protocol. It uses gps/lib/casbin to do this.

gps/internal/unc implements gps/gpsprot abstractions for the Unicore protocol. It uses gps/lib/uncmsg to parse Unicore binary and ASCII message formats.

gps/internal/nov implements gps/gpsprot abstractions for the NovAtel protocol. It uses gps/lib/novmsg to parse binary and ASCII NovAtel packets.

gps/internal/sino provides satellite numbering schemes for SinoGNSS receivers, defining NMEA satellite ID mappings for GLONASS, NavIC, Galileo, QZSS, BeiDou, and SBAS.

gps/internal/as provides NMEA satellite numbering configuration for Allystar GPS receivers.

gps/internal/scantest provides utility functions for testing GPS packet format implementations. It includes functions to find packets within buffers and insert random data prefixes for robustness testing.

gps/lib/

These packages are reusable libraries for GPS processing. They are in the library layer.

gps/lib/ubxbin translates binary packets in the UBX protocol to and from Go structs.

gps/lib/ubxcfgval handles the 9th generation UBX format for configuration data that is payload for UBX-CFG-VALGET/VALSET messages.

gps/lib/ubxcfgval/cfgschema contains a YAML schema for configuration data handled by gps/lib/ubxcfgval. This is used to generate code in the gps/lib/ubxcfgval package.

gps/lib/casbin translates binary packets in the CASIC protocol to and from Go structs.

gps/lib/asbin translates binary packets in the Allystar binary protocol to and from Go structs.

gps/lib/novmsg provides parsing and serialization of NovAtel GPS receiver messages in binary and ASCII formats. It defines message header and body types and implements CRC32 validation.

gps/lib/uncmsg parses Unicore protocol messages in binary and ASCII formats. It defines message structures and provides parsing/serialization using gps/lib/novmsg.

gps/lib/nmeamsg analyzes NMEA sentence syntax and computes checksums.

gps/lib/geopos converts between positions in the ECEF and LLH geodetic coordinate systems. This is used by the web interface to link to Google maps.

gps/lib/fieldenc provides reflection-based encoding and decoding of Go structs to and from ordered string field arrays. It supports standard types and custom TextMarshaler/TextUnmarshaler implementations.

gps/lib/ntptime reads the Linux kernel’s NTP synchronization state via the adjtimex syscall and exposes it as platform-independent types. It provides information about system clock synchronization and leap second status.

gps/lib/term provides access to the Linux terminal interface, which provides access to serial devices. This is similar to github.com/pkg/term, but provides additional Linux-specific functionality.

time/

These packages provide the public API for time synchronization. They are in the domain layer.

time/phc provides low level abstractions to access the PTP hardware clock. It is highly Linux dependent. It uses gps/ptime.

time/sockrefclock implements the chrony refclock protocol. It uses gps/ptime.

time/clocksim provides discrete-time simulation of PTP hardware clocks and GNSS PPS signals. It includes simulator functions for oscillators (modeling frequency errors like white noise, flicker noise, random walk, drift) and for GPS/PPS timing errors (jitter, sawtooth, sinusoids, colored noise).

time/phctime provides an Era type used for managing stepping of a PHC and types that combine Era with ptime.Time.

time/app/

These packages provide daemon orchestration and CLI. They are in the command layer.

time/app/daemon implements the satpulsed daemon. It orchestrates all the parts of the satpulsed program. It also handles the TOML config file and provides HTTP endpoints for the web interface and metrics.

time/app/syncsimcmd implements the syncsim subcommand of satpulsetool. It parses configuration and command-line arguments, then orchestrates a discrete-event simulation of the synchronization system using time/internal/syncsim.

time/internal/

These packages are the main building blocks for satpulsed; they are in the application layer and are not importable outside time/.

time/internal/ts implements a goroutine that reads external timestamps from the PTP hardware clock and sends those to a channel. These external timestamps are the time pulses emitted by the GPS receiver.

time/internal/gpsevent provides the main event handling loop after GPS configuration is done. It receives GPS packets from gps/app/gpsio and then uses the appropriate protocol implementation to construct protocol-independent messages that it passes to time/internal/phcsync. It also receives timestamps from time/internal/ts and passes them to time/internal/phcsync.

time/internal/phcsync provides the core functionality of synchronizing the PTP hardware clock. It receives timestamps from gpsevent and accesses GPS messages via time/internal/timemsg.

time/internal/timemsg buffers recent GPS time messages from a receiver and provides methods to retrieve consecutive, second-aligned messages and pulse offset corrections for time synchronization. It receives messages from time/internal/gpsevent and provides them to time/internal/phcsync. It isolates time/internal/phcsync from the complexities of gps/gpsprot.

time/internal/ptpgm manages the PTP grandmaster state and synchronization status as seen by ptp4l. It provides a worker goroutine that sends updates to ptp4l via the PTP management protocol.

time/internal/refclock provides abstractions for sending clock synchronization samples to external time synchronization services like chrony. It includes a worker goroutine that processes samples from a channel and delivers them to configured refclock implementations.

time/internal/syncsim provides a discrete-event simulator for testing the phcsync controller with configurable error models for GPS PPS timing and PHC oscillator characteristics. It generates synthetic pulses, messages, and ticks under various fault conditions and measures controller performance.

time/internal/obs provides unified observability interfaces including Observer (which extends phcsync.Sampler and gpsprot.Handler) for receiving both clock synchronization samples and GPS protocol messages.

time/internal/sseobs implements the Observer interface to generate Server-Sent Events data that the daemon uses for the web interface.

time/internal/promobs implements the Observer interface to collect Prometheus metrics that the daemon exposes via HTTP handlers.

time/internal/logobs implements the Observer interface to record clock synchronization samples to log files and emit statistical summaries via structured logging. It provides ClockLogObserver for per-sample clock data and StatsLogObserver for interval-based summaries.

time/internal/statsobs accumulates clock synchronization statistics including phase offset (maximum, mean, RMS), frequency deviation (mean, standard deviation), and frequency delta characteristics. It implements phcsync.Sampler for data collection.

time/internal/proxy implements proxying of GPS packets to TCP and Unix domain sockets.

time/lib/

These packages are reusable libraries for time synchronization. They are in the library layer.

time/lib/pmc implements a PTP management client.

time/lib/ifwait uses the Linux kernel’s netlink subsystem to wait for changes in a network interface’s status.

time/lib/devnotify uses the Linux kernel’s netlink subsystem to listen for creation of new devices by udev. (This is not used currently.)

time/lib/sse marshals data into the format of HTML SSE (server-sent events).

time/lib/allan computes Allan deviations. (This is not used currently.)

time/lib/check validates struct fields against constraints specified in struct tags using reflection. It supports numeric types with comparison operators (>, >=, <, <=) and recursively validates nested structs.

time/lib/circbuf provides a generic circular buffer that maintains a sliding window of recent samples. It supports appending with automatic overflow handling and reverse chronological iteration.

time/lib/fuser finds processes that have a specific file or directory open by examining the Linux /proc filesystem. It provides functionality similar to the Unix fuser utility.

time/lib/median provides efficient median computation for a fixed-size moving window using a circular buffer with a sorted index array. It supports 64-bit integers, floats, and time.Duration.

internal/

These packages implement subcommands of satpulsetool. They are in the command-line layer and can import from both gps/ and time/.

internal/gpscmd implements gps subcommand of satpulsetool.

internal/decodecmd implements decode subcommand of satpulsetool. It decodes binary GPS packets from hex strings or annotates JSONL packet logs with decoded payload fields.

internal/pmccmd implements pmc subcommand of satpulsetool.

internal/sdpcmd implements the sdp subcommand of satpulsetool. It provides interfaces to manage software-defined pins (SDPs) on PTP hardware clocks, including listing available interfaces and pins, capturing external timestamps, configuring periodic output, and disabling pins.

web/

This package provides the web interface. It is in the application layer.

web embeds the HTML/JavaScript code for the web interface. This code is transpiled from TypeScript and uses Preact JavaScript library.