Documentation
¶
Overview ¶
Package gps provides a unified GPS position cache with NMEA-serial and gpsd (TCP JSON) reader implementations. Beacon schedulers, SmartBeaconing, and REST endpoints read the latest fix through the PositionCache interface; reader goroutines push updates via Update.
Index ¶
- func ReadNMEAStream(ctx context.Context, r io.Reader, cache PositionCache, logger *slog.Logger, ...) error
- func RunGPSD(ctx context.Context, cfg GPSDConfig, cache PositionCache, logger *slog.Logger) error
- func RunSerial(ctx context.Context, cfg SerialConfig, cache PositionCache, ...) error
- type Fix
- type GPSDConfig
- type MemCache
- type NMEAOptions
- type PositionCache
- type PositionSource
- type SatelliteCache
- type SatelliteInfo
- type SatelliteView
- type SerialConfig
- type SerialPortInfo
- type StationPos
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ReadNMEAStream ¶
func ReadNMEAStream(ctx context.Context, r io.Reader, cache PositionCache, logger *slog.Logger, opts NMEAOptions) error
ReadNMEAStream consumes NMEA sentences from r line-by-line, parses them, and pushes accepted fixes into cache. It handles partial lines across reads (bufio.Scanner) and logs malformed sentences at debug level, with a 1-minute rate-limited warn log for parse failures so an operator sees the first one of each surge without the log flooding. It returns when ctx is cancelled or r hits EOF.
func RunGPSD ¶
func RunGPSD(ctx context.Context, cfg GPSDConfig, cache PositionCache, logger *slog.Logger) error
RunGPSD dials gpsd, issues ?WATCH={"enable":true,"json":true}, and feeds TPV reports into cache until ctx is cancelled.
func RunSerial ¶
func RunSerial(ctx context.Context, cfg SerialConfig, cache PositionCache, logger *slog.Logger) error
RunSerial opens the serial port and feeds NMEA sentences into cache until ctx is cancelled. The port is always closed on return. On I/O error it returns the error; callers (cmd/graywolf) implement retry with backoff.
Types ¶
type Fix ¶
type Fix struct {
Latitude float64 // degrees, north positive
Longitude float64 // degrees, east positive
Altitude float64 // metres above MSL
HasAlt bool
Speed float64 // knots (APRS/NMEA canonical unit)
Heading float64 // degrees true, 0..360
HasCourse bool // true if Speed/Heading are valid for this fix
Timestamp time.Time // UTC
FixMode int // 0=unknown, 1=no fix, 2=2D, 3=3D (from GSA)
PDOP float64 // position dilution of precision
HDOP float64 // horizontal dilution of precision
VDOP float64 // vertical dilution of precision
HasDOP bool // true if DOP values are valid
}
Fix is a single GPS observation. Zero Timestamp indicates "no fix yet".
func ParseNMEA ¶
ParseNMEA parses a single NMEA sentence into a Fix. The input may optionally include the leading '$' and trailing "*HH" checksum; both styles are accepted. Returns an error if the checksum is invalid or the sentence type is unsupported/malformed. The returned bool reports whether the sentence contained an active fix (some RMC sentences are status='V' for "void").
type GPSDConfig ¶
type GPSDConfig struct {
Host string // default "localhost"
Port int // default 2947
// OnParseError, if non-nil, is invoked for every JSON line that
// fails to unmarshal into a TPV report. source is always "gpsd"
// for the caller's convenience so the same callback can be shared
// between the gpsd and NMEA readers.
OnParseError func(source string)
}
GPSDConfig configures a gpsd (TCP JSON) reader.
type MemCache ¶
type MemCache struct {
// contains filtered or unexported fields
}
MemCache is a sync.RWMutex-protected in-memory PositionCache. The zero value is a valid empty cache.
func (*MemCache) GetSatellites ¶
func (c *MemCache) GetSatellites() (SatelliteView, bool)
GetSatellites returns the latest satellite view.
func (*MemCache) Update ¶
Update replaces the stored fix. A Fix with zero Timestamp is stamped with time.Now() so downstream code always sees a monotonic freshness.
func (*MemCache) UpdateSatellites ¶
func (c *MemCache) UpdateSatellites(v SatelliteView)
UpdateSatellites replaces the stored satellite view.
type NMEAOptions ¶
type NMEAOptions struct {
OnParseError func(source string)
}
NMEAOptions configures ReadNMEAStream. OnParseError is optional and, when non-nil, is invoked once per malformed sentence — wired to the shared gps parse-errors counter in production. Kept as a separate option struct so adding more knobs later doesn't require a breaking signature change on every caller.
type PositionCache ¶
type PositionCache interface {
// Get returns the latest fix and whether any fix has been stored.
Get() (Fix, bool)
// Update stores a new fix. Readers call this from their goroutines.
Update(Fix)
}
PositionCache is the read/write contract shared by readers and consumers. Implementations MUST be safe for concurrent use.
type PositionSource ¶
type PositionSource int
PositionSource indicates where a position came from.
const ( SourceNone PositionSource = iota // no position available SourceGPS // live GPS receiver SourceFixed // static beacon coordinates )
type SatelliteCache ¶
type SatelliteCache interface {
GetSatellites() (SatelliteView, bool)
UpdateSatellites(SatelliteView)
}
SatelliteCache provides read/write access to satellite visibility data. Implementations MUST be safe for concurrent use.
type SatelliteInfo ¶
type SatelliteInfo struct {
PRN int // satellite PRN/ID number
Elevation int // degrees above horizon (0-90)
Azimuth int // degrees from true north (0-359)
SNR int // signal-to-noise dB-Hz (0-99), -1 if not tracking
}
SatelliteInfo describes a single satellite visible to the receiver.
type SatelliteView ¶
type SatelliteView struct {
Satellites []SatelliteInfo
UpdatedAt time.Time
}
SatelliteView is a snapshot of all satellites visible to the receiver, assembled from one or more complete GSV sentence cycles.
type SerialConfig ¶
type SerialConfig struct {
Device string // e.g. /dev/ttyUSB0
BaudRate int // e.g. 4800, 9600, 38400
// OnParseError, if non-nil, is invoked for every NMEA sentence
// that fails to parse. source is always "nmea".
OnParseError func(source string)
}
SerialConfig configures a NMEA-over-serial reader.
type SerialPortInfo ¶
type SerialPortInfo struct {
Path string `json:"path"` // device path, e.g. /dev/cu.usbserial-110
Name string `json:"name"` // basename of path
Description string `json:"description"` // human-readable description
IsUSB bool `json:"is_usb"`
VID string `json:"vid,omitempty"`
PID string `json:"pid,omitempty"`
SerialNumber string `json:"serial_number,omitempty"`
Product string `json:"product,omitempty"`
// Recommended is true for the device path users should pick. On macOS
// we recommend the /dev/cu.* callout device over /dev/tty.* (which
// blocks until DCD is asserted).
Recommended bool `json:"recommended"`
// Warning is set when there's a known gotcha with this path (e.g. the
// macOS tty.* / cu.* distinction).
Warning string `json:"warning,omitempty"`
}
SerialPortInfo describes one detected serial port for the web UI. Fields mirror the JSON shape returned by GET /api/gps/available.
func EnumerateSerialPorts ¶
func EnumerateSerialPorts() ([]SerialPortInfo, error)
EnumerateSerialPorts returns the list of serial ports visible to the OS. Implementation is pure Go (no cgo) so it cross-compiles cleanly. On Linux we read /sys/class/tty/*/device to enrich USB devices with VID/PID/product strings; other platforms get the path-based heuristics only.
type StationPos ¶
type StationPos struct {
// contains filtered or unexported fields
}
StationPos is a PositionCache that layers a GPS cache over an optional fixed fallback position. Get returns the GPS fix when available; otherwise it returns the fallback (typically the station's fixed beacon coordinates). Update delegates to the underlying GPS cache.
func NewStationPos ¶
func NewStationPos(gps *MemCache) *StationPos
NewStationPos wraps a GPS cache with an optional fixed-position fallback. The fallback is initially empty; call SetFallback to populate it from beacon configs.
func (*StationPos) Get ¶
func (s *StationPos) Get() (Fix, bool)
Get returns the latest GPS fix if available, otherwise the fallback.
func (*StationPos) GetSatellites ¶
func (s *StationPos) GetSatellites() (SatelliteView, bool)
GetSatellites delegates to the underlying GPS cache.
func (*StationPos) GetWithSource ¶
func (s *StationPos) GetWithSource() (Fix, PositionSource)
GetWithSource is like Get but also reports the position source.
func (*StationPos) SetFallback ¶
func (s *StationPos) SetFallback(f *Fix)
SetFallback sets the fixed-position fallback from a beacon's static coordinates. Pass nil to clear.
func (*StationPos) Update ¶
func (s *StationPos) Update(f Fix)
Update delegates to the underlying GPS cache.
func (*StationPos) UpdateSatellites ¶
func (s *StationPos) UpdateSatellites(v SatelliteView)
UpdateSatellites delegates to the underlying GPS cache.