Giter Site home page Giter Site logo

go-nmea's Introduction

go-nmea

CI Go Report Card Coverage Status GoDoc

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) 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.

Examples

Built-in message parsing

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.

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:

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.

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:

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.

go-nmea's People

Contributors

adrianmo avatar aldas avatar bertoldvdb avatar bezineb5 avatar bmurray avatar borud avatar buxtronix avatar calmh avatar fhedberg avatar icholy avatar kamil-krawczyk avatar krasi-georgiev avatar maescool avatar mholt avatar quartercastle avatar simeonmiteff avatar skladd avatar sthorshaug avatar tzneal avatar yavosh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-nmea's Issues

Doesn't handle null fields.

I have the following sentence:

$GPRMC,142754.0,A,4302.539570,N,07920.379823,W,0.0,,070617,0.0,E,A*3F

Which fails to parse with: GPRMC decode course error: due to the parser not handling null fields correctly. The easiest solution would be to use 0 when there's a null field, but idk if that's a good idea.

https://www.trimble.com/OEM_ReceiverHelp/V4.44/en/NMEA-0183messages_MessageOverview.html

All messages conform to the NMEA-0183 version 3.01 format. All begin with $ and end with a carriage return and a line feed. Data fields follow comma (,) delimiters and are variable in length. Null fields still follow comma (,) delimiters, but contain no information.

Trouble using - nmea.Sentence is nmea.GPVTG, not nmea.GPRMC

When I am trying to parse the serial output of an u-blox USB GPS Interface, I get the following message, along other checksum warnings.

2018/07/17 11:24:37 $GPRMC,092441.00,V,,,,,,,170718,,,N*7F
panic: interface conversion: nmea.Sentence is nmea.GPVTG, not nmea.GPRMC
--
2018/07/17 11:25:42 $GPRMC,092546.00,V,,,,,,,170718,,,N*79
]018/07/17 11:25:42 nmea: sentence checksum mismatch [79 != 79
--
2018/07/17 11:59:10 NMEA RAW is: '$GPVTG,,,,,,,,,N*30'
panic: interface conversion: nmea.Sentence is nmea.GPVTG, not nmea.GPRMC

Fails to parse correct RMC sentence

As of version 1.5.0 and higher, I get the following when parsing data from my boat:

  • Sentence: $YDRMC,050700.00,A,5524.8683,N,01255.7938,E,0.2,181.3,230623,4.3,E,A,C*5F
  • Error: nmea: YDRMC invalid navigation status: C

sentence checksum error reported, though both values seem the same

I am running your example code on GNRMC data received from my GNSS module.
On nmea.Parse(sentence) I get:

]019/06/17 21:26:23 Couldn't parse GPS data: nmea: sentence checksum mismatch [79 != 79
2019/06/17 21:26:24 $GNRMC,192624.000,A,5327.813301,N,01432.630601,E,0.00,325.41,170619,,,A*7E
]019/06/17 21:26:24 Couldn't parse GPS data: nmea: sentence checksum mismatch [7E != 7E
2019/06/17 21:26:25 $GNRMC,192625.000,A,5327.813301,N,01432.630601,E,0.00,325.41,170619,,,A*7F
]019/06/17 21:26:25 Couldn't parse GPS data: nmea: sentence checksum mismatch [7F != 7F
^C2019/06/17 21:26:25 main: Got signal: interrupt
2019/06/17 21:26:26 $GNRMC,192626.000,A,5327.813301,N,01432.630601,E,0.00,325.41,170619,,,A*7C
]019/06/17 21:26:26 Couldn't parse GPS data: nmea: sentence checksum mismatch [7C != 7C
^C2019/06/17 21:26:27 $GNRMC,192627.000,A,5327.813301,N,01432.630601,E,0.00,325.41,170619,,,A*7D
]019/06/17 21:26:27 Couldn't parse GPS data: nmea: sentence checksum mismatch [7D != 7D

Both checksums seem the same to me in the output above.
The place I pasted your example code:

https://github.com/madwizard/zut_wifi_logger/blob/2aead364882076d5a836c105a30cb6760d14c266/gps.go#L42

possibility to make CRC check optional for certain sentences

Older devices sometimes do not implement NMEA0183 correctly by omitting CRC. It would be nice if there would be way to make parser ignore CRC mismatches for certain sentences.

We are retrofitting 2005 built vessel that has GPS device sending sentences without CRC. Our navigation engineers say it is not very rare to have older devices like that. So for example devices reading/receiving NMEA0183 sentences have sometimes option to disable CRC checks because of this sad reality.

Fails to parse IIXDR

occur error when parsing data.
i received error message, "nmea: IIXDR invalid transducer type: A"

my gps data sender is providing bellow data
$IIXDR, A, 0.0, D, ROLL, A, 0.0, D, PITCH*15

Default value for empty string

When a value is missing in a nmea string the float or int value in the parsed sentence is set to 0. This way it is hard to determine if the value is really 0 or the data was missing. E.g. $GPVTG,0.3,T,,M,,N,12.6,K*78 would result in GroundSpeedKnots: 0 and GroundSpeedKPH: 12.6. Now it is easy to guess that that GroundSpeedKnots is invalid, but for TrueTrack: 0.3 and MagneticTrack: 0 it is not possible.

Is there a specific reason why this is done in this way?

I would suggest to add getters to the sentences for all the value like:

func (s VTG) GetTrueTrack() (float64, error) {
	if s.hasValidTrueTrack {
		return s.TrueTrack, nil
	}
	return 0, fmt.Errorf("TrueTrack is missing in the nmea string")
}

These getters can check an internal state for each value and return an error if the value was not available in the original nmea string. This will also not break existing code because it is still possible to use TrueTrack, MagneticTrack etc directly.

Make `ParseSentence` function unexported

Judging by #18, it looks like the ParseSentence function is causing confusion when using the library. Making it unexported would remove this potential confusion.

In a first inspection, I didn't see any reason to export the function as it's only used internally.

@icholy any thoughts?

feature: could sentence expose list of field names it has

I am creating application to read nmea values and send them to NATS message bus and I one feature that I have is that user can provide configuration (file) that has list of sentences and fields that should filter out of stream of NMEA messages it receives.

For example - we have GPS, Echosounder, Wind sensor all multiplexed into NMEA0183 bus we read. Sometimes we only want to filter GPS RMC messages but sometimes we want other hardware messages also. As this library evolves more and more supported sentences will be added. For each of those messages we would need to create if/switch to be able to read it - pack all fields of message into custom struct we have. We can not just marshall current nmea.Sentence as our schema is different from what marshalling nmea.Sentence creates.

So it would be nice if there would be way to get list of field names that sentence has and then we can pair them with nmea.BaseSentence.Fields slice values to our own schema.

Maybe that context argument that is used when adding field to sentence, could be stored and exposed as public slice

go-nmea/rmc.go

Line 34 in a4c9590

Latitude: p.LatLong(2, 3, "latitude"),

or there would be some method on Sentence what would return list/map of fieldname+fieldvalue (ala map[string]interface{}) so you could "dynamically" get all fields and filter what you need.

Parse latitude and longitude along with the context of the direction

Version 2.x should take into account that geographical coordinate parsing must always be done in the context of the direction. Latitude and longitude have different ranges. In addition, currently only the Decimal format stores information about the direction of a given coordinate (positive / negative values). Parsing data in other formats loses direction information.

processing multiline / segmented messages

I could not find an example for processing AIS 5 message here. This type of message has more than one line for example:

\g:1-2-3730,s:43576,c:1654340281,t:165434038119!AIVDM,2,1,7,,569EH`8000009aGUB20IF1UD4r1UF3OK7>22220N4PT38t0000000000,042

\g:2-2-37305A!AIVDM,2,2,7,,000000000000000,262

Is there any way to process such cases?

Update example in readme file

Update the example to show how to access sentence fields.

E.g.:

package main

import (
	"fmt"
	"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"
	m, err := nmea.Parse(sentence)
	if err == nil {
		s := m.(nmea.GPRMC)
		fmt.Printf("Raw sentence: %v\n", s)
		fmt.Printf("Time: %v\n", s.Time.String())
		fmt.Printf("Validity: %v\n", s.Validity)
		fmt.Printf("Latitude GPS: %v\n", s.Latitude.PrintGPS())
		fmt.Printf("Latitude DMS: %v\n", s.Latitude.PrintDMS())
		fmt.Printf("Longitude GPS: %v\n", s.Longitude.PrintGPS())
		fmt.Printf("Longitude DMS: %v\n", s.Longitude.PrintDMS())
		fmt.Printf("Speed: %v\n", s.Speed)
		fmt.Printf("Course: %v\n", s.Course)
		fmt.Printf("Date: %v\n", s.Date.String())
		fmt.Printf("Variation: %v\n", s.Variation)
	} else {
		panic(err)
	}
}

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.8
Course: 231.8
Date: 13/06/94
Variation: -4.2

Convert nmea.Date and nmea.Time to time.Time

First, thank you for this excellent package. 🙏 It's perfectly what I need, and I'm relieved to see it maintained, esp. from developers I recognize!

I'm using it to parse GPS log data from amateur radios.

In particular, I'm finding that it's common to encounter GGA and RMC sentences alternating in a log file. RMC lines have time and date fields; GGA only has time.

I'm wondering if there's a convenient function (or one could be created) that takes both nmea.Date and nmea.Time and returns a time.Time. Once I get my spike code up and running I could contribute this if you think it'd be a good addition.

Edit: Haven't run this yet, but is it just:

time.Date(2000+s.Date.YY, time.Month(s.Date.MM), s.Date.DD,
    s.Time.Hour, s.Time.Minute, s.Time.Second, 0,
    time.UTC)

? Or is there more nuance to it?

PS. How do you know the first two digits of the year? I guess by now we can assume the 2000s, but is it possible that any data was collected in the 20th century?

DPT third field depends on nmea version?

DPT documentation refers to https://gpsd.gitlab.io/gpsd/NMEA.html#_dpt_depth_of_water and in that is example $INDPT,2.3,0.0*46

that example is not parseable by the library. I get nmea: INDPT invalid range scale: index out of range

Some other documents ala https://www.tronico.fi/OH6NT/docs/NMEA0183.pdf
describe DPT as
image

or https://www.eye4software.com/hydromagic/documentation/nmea0183/ as Example: $SDDPT,3.6,0.0*52

It would be nice if DTP parsing can handle 2 and 3 fields gracefully without erroring.

$AIVDM, etc

Hey, thanks for a nice and clean NMEA parser library!

We run into occasional malformed messages with encapsulated sentences prefixed with non-encapsulated start-tokens. Here's an excerpt from real-world data:

$AIVDM,1,1,,A,13Ho=R7000Of7DbKI<etrRbT1000,0*6B
$AIVDM,1,1,,A,13Ho=R7000Of7DbKI<etrRbT1>@<,0*19
$AIVDM,1,1,,A,13Ho=R7000Of7DbKI<etrRbT1>`<,0*39
$AIVDM,1,1,,A,B3HvLWP00?sQHD6nC?wQ3wUUn006,0*2D
$AIVDM,1,1,,A,B3HwU?00;OsPQ4Vn;=hD;wQ5n006,0*52
$AIVDM,1,1,,A,B3I2kGP0;OsQhAVmnBC4Wwi5n006,0*5B
$AIVDM,1,1,,A,B3I7Dt004gsP9KVn6TucwweQl000,0*3F
$AIVDM,1,1,,A,B3I7Dt009gsP;1Vn5>;M3wc1l000,0*61
$AIVDM,1,1,,A,B3I7Dt00;?sP=K6n7Fl;WwWQl000,0*4C

These messages are formally wrong, they should have ! as the leading character.

I was considering adding a flag to SentenceParser to allow this anomaly. Thoughts? We might also look into preprocessing messages to replace $ by ! where applicable.

Thanks!

nmea.ParseSentence output

Hi, i am newbie on Golang and the NMEA library too.

I have a question about the output when i use nmea.ParseSentence.

this is the code, i changed nmea.Parse to nmea.ParseSentence

package main

import (
"fmt"
"github.com/adrianmo/go-nmea"
)

func main() {
m, err := nmea.ParseSentence("$GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70")

if err == nil {
fmt.Printf("%+v\n", m)
}
}

but the output still same with nmea.Parse. The output:
$GPRMC,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W*70
is it the right output?
I want to parse that NMEA, so i choose the ParseSentence.

Thanks for your help

Accept other talkers than "GP"

The NMEA 0183 protocol offers multiple talkers based on which equipment generated the message.
GP indicates a GPS receiver, GL a GLONASS receiver, GN a combined GNSS receiver, IN an integrated navigation receiver and so forth. See here for examples of different talkers.

As of today, go-nmea only accepts GP for most messages as talker. Is there an easy way of allowing different talkers for all NMEA messages, or is it necessary to implement specific functions for all talkers?

A concrete example is the HDT, which in many cases is HEHDT and INHDT.

An easy (but dirty) way is of course to manipulate the talker into GP.

Document message specification

Since there's no public canonical nmea reference, we've been linking to different resources on the web. It would be better to maintain our own copy of the message specifications that we implement.

Support custom message types

I would like to extend this lib to support custom message parsing, is this something you would consider merging. We are using this to parse some custom message which are not part of the NMEA standard. The idea is to have a way to register parsers for new message types.

parsing errors

About errors. When parsing fails currently only first error is stored and all subsequent errors are discarded. I propose if p.EnumString and other parsing method errors would be distinguishable from each other and parsers would store all errors. it would allow you to introspect what went wrong and some circumstances ignore some error types and still use the parsed sentence.

maybe just wrapping them (or storing into slice or multierror)

func (p *Parser) SetErr(context, value string) {
	if p.err == nil {
		p.err = fmt.Errorf("nmea: %s invalid %s: %s", p.Prefix(), context, value)
	} else {
		p.err = fmt.Errorf("nmea: %s invalid %s: %s, err: %w", p.Prefix(), context, value, p.err)
	}
}

1.0 API Freeze

I think the API is in a good place right now and we should tag a 1.0 release. No more breaking changes after that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.