This is a NMEA library for the Go programming language (Golang).
- Parse individual NMEA 0183 sentences
- Support for sentences with NMEA 4.10 "TAG Blocks"
- Register custom parser for unsupported sentence types
- User-friendly MIT license
To install go-nmea use go get
:
go get github.com/adrianmo/go-nmea
This will then make the github.com/adrianmo/go-nmea
package available to you.
To update go-nmea to the latest version, use go get -u github.com/adrianmo/go-nmea
.
Sentence with link is supported by this library. NMEA0183 sentences list is based on IEC 61162-1:2016 (Edition 5.0 2016-08) table of contents.
Sentence | Description | References |
---|---|---|
AAM | Waypoint arrival alarm | gpsd |
ABK | AIS addressed and binary broadcast acknowledgement | |
ABM | AIS addressed binary and safety related message | |
ACA | AIS channel assignment message | |
ACK | Acknowledge alarm | |
ACN | Alert command | |
ACS | AIS channel management information source | |
AIR | AIS interrogation request | |
AKD | Acknowledge detail alarm condition | |
ALA | Report detailed alarm condition | |
ALC | Cyclic alert list | |
ALF | Alert sentence | |
ALR | Set alarm state | |
APB | Heading/track controller (autopilot) sentence B | gpsd |
ARC | Alert command refused | |
BBM | AIS broadcast binary message | |
BEC | Bearing and distance to waypoint, Dead reckoning | 1 |
BOD | Bearing origin to destination | gpsd |
BWC | Bearing and distance to waypoint, Great circle | gpsd |
BWR | Bearing and distance to waypoint, Rhumb line | gpsd |
BWW | Bearing waypoint to waypoint | gpsd |
CUR | Water current layer, Multi-layer water current data | |
DBK | Depth Below Keel (obsolete, use DPT instead) | gpsd |
DBS | Depth below transducer | gpsd |
DBT | Depth below transducer | gpsd |
DDC | Display dimming control | |
DOR | Door status detection | |
DPT | Depth | gpsd |
DSC | Digital selective calling information | |
DSE | Expanded digital selective calling | |
DTM | Datum reference | gpsd |
EPV | Command or report equipment property value | |
ETL | Engine telegraph operation status | |
EVE | General event message | |
FIR | Fire detection | |
FSI | Frequency set information | |
GBS | GNSS satellite fault detection | |
GEN | Generic binary information | |
GFA | GNSS fix accuracy and integrity | |
GGA | Global positioning system (GPS) fix data | 1 |
GLL | Geographic position, Latitude/longitude | 1 |
GNS | GNSS fix data | gpsd |
GRS | GNSS range residuals | |
GSA | GNSS DOP and active satellites | 1 |
GST | GNSS pseudorange noise statistics | |
GSV | GNSS satellites in view | 1 |
HBT | Heartbeat supervision sentence | |
HCR | Heading correction report | |
HDG | Heading, deviation and variation | gpsd |
HDM | Heading - Magnetic | gpsd |
HDT | Heading true | gpsd |
HMR | Heading monitor receive | |
HMS | Heading monitor set | |
HRM | heel angle, roll period and roll amplitude measurement device | |
HSC | Heading steering command | gpsd |
HSS | Hull stress surveillance systems | |
HTC | Heading/track control command | |
HTD | Heading /track control data | |
LR1 | AIS long-range reply sentence 1 | |
LR2 | AIS long-range reply sentence 2 | |
LR3 | AIS long-range reply sentence 3 | |
LRF | AIS long-range function | |
LRI | AIS long-range interrogation | |
MDA | Meteorological Composite | gpsd |
MTA | Air Temperature (obsolete, use XDR instead) | |
MOB | Man over board notification | |
MSK | MSK receiver interface | |
MSS | MSK receiver signal status | |
MTW | Water temperature | gpsd |
MWD | Wind direction and speed | 1 |
MWV | Wind speed and angle | gpsd |
NAK | Negative acknowledgement | |
NRM | NAVTEX receiver mask | |
NRX | NAVTEX received message | |
NSR | Navigation status report | |
OSD | Own ship data | gpsd |
POS | Device position and ship dimensions report or configuration command | |
PRC | Propulsion remote control status | |
RLM | Return link message | |
RMA | Recommended minimum specific LORAN-C data | |
RMB | Recommended minimum navigation information | gpsd |
RMC | Recommended minimum specific GNSS data | 1 |
ROR | Rudder order status | |
ROT | Rate of turn | gpsd |
RRT | Report route transfer | |
RPM | Revolutions | gpsd |
RSA | Rudder sensor angle | gpsd |
RSD | Radar system data | gpsd |
RTE | Routes | 1 |
SFI | Scanning frequency information | |
SMI | SafetyNET Message, All Ships/NavArea | |
SM2 | SafetyNET Message, Coastal Warning Area | |
SM3 | SafetyNET Message, Circular Area address | |
SM4 | SafetyNET Message, Rectangular Area Address | |
SMB | IMO SafetyNET Message Body | |
SPW | Security password sentence | |
SSD | AIS ship static data | |
STN | Multiple data ID | |
THS | True heading and status | 1 |
TLB | Target label | |
TLL | Target latitude and longitude | gpsd |
TRC | Thruster control data | |
TRL | AIS transmitter-non-functioning log | |
TRD | Thruster response data | |
TTD | Tracked target data | |
TTM | Tracked target message | gpsd |
TUT | Transmission of multi-language text | |
TXT | Text transmission | NMEA |
UID | User identification code transmission | |
VBW | Dual ground/water speed | gpsd |
VDM | AIS VHF data-link message | gpsd |
VDO | AIS VHF data-link own-vessel report | gpsd |
VDR | Set and drift | gpsd |
VER | Version | |
VHW | Water speed and heading | 1 |
VLW | Dual ground/water distance | gpsd |
VPW | Speed measured parallel to wind | gpsd |
VSD | AIS voyage static data | |
VTG | Course over ground and ground speed | 1 |
VWR | Relative Wind Speed and Angle | gpsd |
VWT | True Wind Speed and Angle | |
WAT | Water level detection | |
WCV | Waypoint closure velocity | |
WNC | Distance waypoint to waypoint | |
WPL | Waypoint location | 1 |
XDR | Transducer measurements | gpsd |
XTE | Cross-track error, measured | |
XTR | Cross-track error, dead reckoning | |
ZDA | Time and date | 1 |
ZDL | Time and distance to variable point | |
ZFO | UTC and time from origin waypoint | |
ZTG | UTC and time to destination waypoint |
Proprietary sentence type | Description | References |
---|---|---|
PNG | Transfer NMEA2000 frame as NMEA0183 sentence (ShipModul MiniPlex-3) | 1 |
PCDIN | Transfer NMEA2000 frame as NMEA0183 sentence (SeaSmart.Net Protocol) | 1 |
PGRME | Estimated Position Error (Garmin proprietary sentence) | 1 |
PHTRO | Vessel pitch and roll (Xsens IMU/VRU/AHRS) | |
PMTK001 | Acknowledgement of previously sent command/packet | 1 |
PRDID | Vessel pitch, roll and heading (Xsens IMU/VRU/AHRS) | |
PSKPDPT | Depth of Water for multiple transducer installation | |
PSONCMS | Quaternion, acceleration, rate of turn, magnetic field, sensor temperature (Xsens IMU/VRU/AHRS) |
If you need to parse a message that contains an unsupported sentence type you can implement and register your own message parser and get yourself unblocked immediately. Check the example below to know how to implement and register a custom message parser. However, if you think your custom message parser could be beneficial to other users we encourage you to contribute back to the library by submitting a PR and get it included in the list of supported sentences.
package main
import (
"fmt"
"log"
"github.com/adrianmo/go-nmea"
)
func main() {
sentence := "$GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70"
s, err := nmea.Parse(sentence)
if err != nil {
log.Fatal(err)
}
if s.DataType() == nmea.TypeRMC {
m := s.(nmea.RMC)
fmt.Printf("Raw sentence: %v\n", m)
fmt.Printf("Time: %s\n", m.Time)
fmt.Printf("Validity: %s\n", m.Validity)
fmt.Printf("Latitude GPS: %s\n", nmea.FormatGPS(m.Latitude))
fmt.Printf("Latitude DMS: %s\n", nmea.FormatDMS(m.Latitude))
fmt.Printf("Longitude GPS: %s\n", nmea.FormatGPS(m.Longitude))
fmt.Printf("Longitude DMS: %s\n", nmea.FormatDMS(m.Longitude))
fmt.Printf("Speed: %f\n", m.Speed)
fmt.Printf("Course: %f\n", m.Course)
fmt.Printf("Date: %s\n", m.Date)
fmt.Printf("Variation: %f\n", m.Variation)
}
}
Output:
$ go run main/main.go
Raw sentence: $GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70
Time: 22:05:16.0000
Validity: A
Latitude GPS: 5133.8200
Latitude DMS: 51° 33' 49.200000"
Longitude GPS: 042.2400
Longitude DMS: 0° 42' 14.400000"
Speed: 173.800000
Course: 231.800000
Date: 13/06/94
Variation: -4.200000
Parser logic can be customized by creating nmea.SentenceParser
instance and by providing callback implementations.
p := nmea.SentenceParser{
CustomParsers: nil,
ParsePrefix: nil,
CheckCRC: nil,
OnTagBlock: nil,
}
s, err := p.Parse("$GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70")
NMEA 4.10 TAG Block values can be accessed via the message's TagBlock
struct:
package main
import (
"fmt"
"log"
"time"
"github.com/adrianmo/go-nmea"
)
func main() {
sentence := "\\s:Satelite_1,c:1553390539*62\\!AIVDM,1,1,,A,13M@ah0025QdPDTCOl`K6`nV00Sv,0*52"
s, err := nmea.Parse(sentence)
if err != nil {
log.Fatal(err)
}
parsed := s.(nmea.VDMVDO)
fmt.Printf("TAG Block timestamp: %v\n", time.Unix(parsed.TagBlock.Time, 0))
fmt.Printf("TAG Block source: %v\n", parsed.TagBlock.Source)
}
Output (locale/time zone dependent):
$ go run main/main.go
TAG Block timestamp: 2019-03-24 14:22:19 +1300 NZDT
TAG Block source: Satelite_1
If you need to parse a message not supported by the library you can implement your own message parsing. The following example implements a parser for the hypothetical XYZ NMEA sentence type.
package main
import (
"fmt"
"github.com/adrianmo/go-nmea"
)
// A type to hold the parsed record
type XYZType struct {
nmea.BaseSentence
Time nmea.Time
Counter int64
Label string
Value float64
}
func main() {
// Do this once it will error if you register the same type multiple times
err := nmea.RegisterParser("XYZ", func(s nmea.BaseSentence) (nmea.Sentence, error) {
// This example uses the package builtin parsing helpers
// you can implement your own parsing logic also
p := nmea.NewParser(s)
return XYZType{
BaseSentence: s,
Time: p.Time(0, "time"),
Label: p.String(1, "label"),
Counter: p.Int64(2, "counter"),
Value: p.Float64(3, "value"),
}, p.Err()
})
if err != nil {
panic(err)
}
sentence := "$00XYZ,220516,A,23,5133.82,W*42"
s, err := nmea.Parse(sentence)
if err != nil {
panic(err)
}
switch m := s.(type) {
case XYZType:
fmt.Printf("Raw sentence: %v\n", m)
fmt.Printf("Time: %s\n", m.Time)
fmt.Printf("Label: %s\n", m.Label)
fmt.Printf("Counter: %d\n", m.Counter)
fmt.Printf("Value: %f\n", m.Value)
default:
panic("Could not parse XYZ sentence")
}
}
Output:
$ go run main/main.go
Raw sentence: $AAXYZ,220516,A,23,5133.82,W*42
Time: 22:05:16.0000
Label: A
Counter: 23
Value: 5133.820000
Some messages have optional fields. By default, omitted numeric values are set to 0. In situations where you need finer
control to distinguish between an undefined value and an actual 0, you can register types overriding existing sentences,
using nmea.Int64
and nmea.Float64
instead of int64
and float64
. The matching parsing methods
are (*Parser).NullInt64
and (*Parser).NullFloat64
. Both nmea.Int64
and nmea.Float64
contains a numeric
field Value
which is defined only if the field Valid
is true
.
See below example for a modified VTG sentence parser:
package main
import (
"fmt"
"github.com/adrianmo/go-nmea"
)
// VTG represents track & speed data.
// http://aprs.gids.nl/nmea/#vtg
type VTG struct {
nmea.BaseSentence
TrueTrack nmea.Float64
MagneticTrack nmea.Float64
GroundSpeedKnots nmea.Float64
GroundSpeedKPH nmea.Float64
}
func main() {
nmea.MustRegisterParser("VTG", func(s nmea.BaseSentence) (nmea.Sentence, error) {
p := nmea.NewParser(s)
return VTG{
BaseSentence: s,
TrueTrack: p.NullFloat64(0, "true track"),
MagneticTrack: p.NullFloat64(2, "magnetic track"),
GroundSpeedKnots: p.NullFloat64(4, "ground speed (knots)"),
GroundSpeedKPH: p.NullFloat64(6, "ground speed (km/h)"),
}, p.Err()
})
sentence := "$GPVTG,140.88,T,,M,8.04,N,14.89,K,D*05"
s, err := nmea.Parse(sentence)
if err != nil {
panic(err)
}
m, ok := s.(VTG)
if !ok {
panic("Could not parse VTG sentence")
}
fmt.Printf("Raw sentence: %v\n", m)
fmt.Printf("TrueTrack: %v\n", m.TrueTrack)
fmt.Printf("MagneticTrack: %v\n", m.MagneticTrack)
fmt.Printf("GroundSpeedKnots: %v\n", m.GroundSpeedKnots)
fmt.Printf("GroundSpeedKPH: %v\n", m.GroundSpeedKPH)
}
Output:
$ go run main/main.go
Raw sentence: $GPVTG,140.88,T,,M,8.04,N,14.89,K,D*05
TrueTrack: {140.88 true}
MagneticTrack: {0 false}
GroundSpeedKnots: {8.04 true}
GroundSpeedKPH: {14.89 true}
Please feel free to submit issues or fork the repository and send pull requests to update the library and fix bugs, implement support for new sentence types, refactor code, etc.
Check LICENSE.