1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
|
# go-nmea
[](https://github.com/adrianmo/go-nmea/actions/workflows/ci.yml) [](https://goreportcard.com/report/github.com/adrianmo/go-nmea) [](https://coveralls.io/github/adrianmo/go-nmea?branch=master) [](https://godoc.org/github.com/adrianmo/go-nmea)
This is a NMEA library for the Go programming language (Golang).
## Features
- 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
## Installing
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.
### Staying up to date
To update go-nmea to the latest version, use `go get -u github.com/adrianmo/go-nmea`.
## Supported sentences
Sentence with link is supported by this library. NMEA0183 sentences list is based
on [IEC 61162-1:2016 (Edition 5.0 2016-08)](https://webstore.iec.ch/publication/25754) table of contents.
| Sentence | Description | References |
|--------------------|---------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
| [AAM](./aam.go) | Waypoint arrival alarm | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_aam_waypoint_arrival_alarm) |
| ABK | AIS addressed and binary broadcast acknowledgement | |
| [ABM](./abm.go) | AIS addressed binary and safety related message | |
| ACA | AIS channel assignment message | |
| [ACK](./ack.go) | Acknowledge alarm | |
| [ACN](./acn.go) | Alert command | |
| ACS | AIS channel management information source | |
| AIR | AIS interrogation request | |
| AKD | Acknowledge detail alarm condition | |
| [ALA](./ala.go) | Report detailed alarm condition | |
| [ALC](./alc.go) | Cyclic alert list | |
| [ALF](./alf.go) | Alert sentence | |
| [ALR](./alr.go) | Set alarm state | |
| [APB](./apb.go) | Heading/track controller (autopilot) sentence B | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_apb_autopilot_sentence_b) |
| [ARC](./arc.go) | Alert command refused | |
| [BBM](./bbm.go) | AIS broadcast binary message | |
| [BEC](./bec.go) | Bearing and distance to waypoint, Dead reckoning | [1](http://www.nmea.de/nmea0183datensaetze.html#bec) |
| [BOD](./bod.go) | Bearing origin to destination | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_bod_bearing_waypoint_to_waypoint) |
| [BWC](./bwc.go) | Bearing and distance to waypoint, Great circle | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_bwc_bearing_distance_to_waypoint_great_circle) |
| [BWR](./bwr.go) | Bearing and distance to waypoint, Rhumb line | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_bwr_bearing_and_distance_to_waypoint_rhumb_line) |
| [BWW](./bww.go) | Bearing waypoint to waypoint | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_bww_bearing_waypoint_to_waypoint) |
| CUR | Water current layer, Multi-layer water current data | |
| [DBK](./dbk.go) | Depth Below Keel (obsolete, use DPT instead) | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_dbk_depth_below_keel) |
| [DBS](./dbs.go) | Depth below transducer | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_dbs_depth_below_surface) |
| [DBT](./dbt.go) | Depth below transducer | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_dbt_depth_below_transducer) |
| DDC | Display dimming control | |
| [DOR](./dor.go) | Door status detection | |
| [DPT](./dpt.go) | Depth | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_dpt_depth_of_water) |
| [DSC](./dsc.go) | Digital selective calling information | |
| [DSE](./dse.go) | Expanded digital selective calling | |
| [DTM](./dtm.go) | Datum reference | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_dtm_datum_reference) |
| EPV | Command or report equipment property value | |
| ETL | Engine telegraph operation status | |
| [EVE](./eve.go) | General event message | |
| [FIR](./fir.go) | Fire detection | |
| FSI | Frequency set information | |
| GBS | GNSS satellite fault detection | |
| GEN | Generic binary information | |
| GFA | GNSS fix accuracy and integrity | |
| [GGA](./gga.go) | Global positioning system (GPS) fix data | [1](http://aprs.gids.nl/nmea/#gga) |
| [GLL](./gll.go) | Geographic position, Latitude/longitude | [1](http://aprs.gids.nl/nmea/#gll) |
| [GNS](./gns.go) | GNSS fix data | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_gns_fix_data) |
| GRS | GNSS range residuals | |
| [GSA](./gsa.go) | GNSS DOP and active satellites | [1](http://aprs.gids.nl/nmea/#gsa) |
| GST | GNSS pseudorange noise statistics | |
| [GSV](./gsv.go) | GNSS satellites in view | [1](http://aprs.gids.nl/nmea/#gsv) |
| [HBT](./hbt.go) | Heartbeat supervision sentence | |
| HCR | Heading correction report | |
| [HDG](./hdg.go) | Heading, deviation and variation | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_hdg_heading_deviation_variation) |
| HDM | Heading - Magnetic | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_hdm_heading_magnetic) |
| [HDT](./hdt.go) | Heading true | [gpsd](http://aprs.gids.nl/nmea/#hdt) |
| HMR | Heading monitor receive | |
| HMS | Heading monitor set | |
| HRM | heel angle, roll period and roll amplitude measurement device | |
| [HSC](./hsc.go) | Heading steering command | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_hsc_heading_steering_command) |
| 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](./mda.go) | Meteorological Composite | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_mda_meteorological_composite) |
| [MTA](./mta.go) | Air Temperature (obsolete, use XDR instead) | |
| MOB | Man over board notification | |
| MSK | MSK receiver interface | |
| MSS | MSK receiver signal status | |
| [MTW](./mtw.go) | Water temperature | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_mtw_mean_temperature_of_water) |
| [MWD](./mwd.go) | Wind direction and speed | [1](https://www.tronico.fi/OH6NT/docs/NMEA0183.pdf) |
| [MWV](./mwv.go) | Wind speed and angle | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_mwv_wind_speed_and_angle) |
| NAK | Negative acknowledgement | |
| NRM | NAVTEX receiver mask | |
| NRX | NAVTEX received message | |
| NSR | Navigation status report | |
| [OSD](./osd.go) | Own ship data | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_osd_own_ship_data) |
| 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](./rmb.go) | Recommended minimum navigation information | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_rmb_recommended_minimum_navigation_information) |
| [RMC](./rmc.go) | Recommended minimum specific GNSS data | [1](http://aprs.gids.nl/nmea/#rmc) |
| ROR | Rudder order status | |
| [ROT](./rot.go) | Rate of turn | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_rot_rate_of_turn) |
| RRT | Report route transfer | |
| [RPM](./rpm.go) | Revolutions | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_rpm_revolutions) |
| [RSA](./rsa.go) | Rudder sensor angle | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_rsa_rudder_sensor_angle) |
| [RSD](./rsd.go) | Radar system data | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_rsd_radar_system_data) |
| [RTE](./rte.go) | Routes | [1](http://aprs.gids.nl/nmea/#rte) |
| 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](./ths.go) | True heading and status | [1](http://www.nuovamarea.net/pytheas_9.html) |
| [TLB](./tlb.go) | Target label | |
| [TLL](./tll.go) | Target latitude and longitude | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_tll_target_latitude_and_longitude) |
| TRC | Thruster control data | |
| TRL | AIS transmitter-non-functioning log | |
| TRD | Thruster response data | |
| [TTD](./ttd.go) | Tracked target data | |
| [TTM](./ttm.go) | Tracked target message | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_ttm_tracked_target_message) |
| TUT | Transmission of multi-language text | |
| [TXT](./txt.go) | Text transmission | [NMEA](https://www.nmea.org/Assets/20160520%20txt%20amendment.pdf) |
| UID | User identification code transmission | |
| [VBW](./vbw.go) | Dual ground/water speed | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_vbw_dual_groundwater_speed) |
| [VDM](./vdmvdo.go) | AIS VHF data-link message | [gpsd](https://gpsd.gitlab.io/gpsd/AIVDM.html) |
| [VDO](./vdmvdo.go) | AIS VHF data-link own-vessel report | [gpsd](https://gpsd.gitlab.io/gpsd/AIVDM.html) |
| [VDR](./vdr.go) | Set and drift | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_vdr_set_and_drift) |
| VER | Version | |
| [VHW](./vhw.go) | Water speed and heading | [1](https://www.tronico.fi/OH6NT/docs/NMEA0183.pdf) |
| [VLW](./vlw.go) | Dual ground/water distance | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_vlw_distance_traveled_through_water) |
| [VPW](./vpw.go) | Speed measured parallel to wind | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_vpw_speed_measured_parallel_to_wind) |
| [VSD](./vsd.go) | AIS voyage static data | |
| [VTG](./vtg.go) | Course over ground and ground speed | [1](http://aprs.gids.nl/nmea/#vtg) |
| VWR | Relative Wind Speed and Angle | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_vwr_relative_wind_speed_and_angle) |
| VWT | True Wind Speed and Angle | |
| WAT | Water level detection | |
| WCV | Waypoint closure velocity | |
| WNC | Distance waypoint to waypoint | |
| [WPL](./wpl.go) | Waypoint location | [1](http://aprs.gids.nl/nmea/#wpl) |
| [XDR](./xdr.go) | Transducer measurements | [gpsd](https://gpsd.gitlab.io/gpsd/NMEA.html#_xdr_transducer_measurement) |
| [XTE](./xte.go) | Cross-track error, measured | |
| XTR | Cross-track error, dead reckoning | |
| [ZDA](./zda.go) | Time and date | [1](http://aprs.gids.nl/nmea/#zda) |
| 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](./pgn.go) | Transfer NMEA2000 frame as NMEA0183 sentence (ShipModul MiniPlex-3) | [1](https://opencpn.org/wiki/dokuwiki/lib/exe/fetch.php?media=opencpn:software:mxpgn_sentence.pdf) |
| [PCDIN](./pcdin.go) | Transfer NMEA2000 frame as NMEA0183 sentence (SeaSmart.Net Protocol) | [1](http://www.seasmart.net/pdf/SeaSmart_HTTP_Protocol_RevG_043012.pdf) |
| [PGRME](./pgrme.go) | Estimated Position Error (Garmin proprietary sentence) | [1](http://aprs.gids.nl/nmea/#rme) |
| [PHTRO](./phtro.go) | Vessel pitch and roll (Xsens IMU/VRU/AHRS) | |
| [PMTK001](./pmtk.go) | Acknowledgement of previously sent command/packet | [1](https://www.rhydolabz.com/documents/25/PMTK_A11.pdf) |
| [PRDID](./prdid.go) | Vessel pitch, roll and heading (Xsens IMU/VRU/AHRS) | |
| [PSKPDPT](./pskpdpt.go) | Depth of Water for multiple transducer installation | |
| [PSONCMS](./psoncms.go) | 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](#custom-message-parsing). 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.
## Examples
### Built-in message parsing
```go
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
```
### Customize sentence parser
Parser logic can be customized by creating `nmea.SentenceParser` instance and by providing callback implementations.
```go
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")
```
### TAG Blocks
NMEA 4.10 TAG Block values can be accessed via the message's `TagBlock` struct:
```go
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
```
### Custom message parsing
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.
```go
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
```
### Message parsing with optional values
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:
```go
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}
```
## Contributing
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.
## License
Check [LICENSE](LICENSE).
|