mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-16 21:03:23 +00:00
gps: improve error handling
Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
+25
-4
@@ -13,8 +13,28 @@ import (
|
|||||||
var (
|
var (
|
||||||
errInvalidNMEASentenceLength = errors.New("invalid NMEA sentence length")
|
errInvalidNMEASentenceLength = errors.New("invalid NMEA sentence length")
|
||||||
errInvalidNMEAChecksum = errors.New("invalid NMEA sentence checksum")
|
errInvalidNMEAChecksum = errors.New("invalid NMEA sentence checksum")
|
||||||
|
errEmptyNMEASentence = errors.New("cannot parse empty NMEA sentence")
|
||||||
|
errUnknownNMEASentence = errors.New("unsupported NMEA sentence type")
|
||||||
|
errInvalidGGASentence = errors.New("invalid GGA NMEA sentence")
|
||||||
|
errInvalidRMCSentence = errors.New("invalid RMC NMEA sentence")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type GPSError struct {
|
||||||
|
Info string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGPSError(err error, info string) GPSError {
|
||||||
|
return GPSError{
|
||||||
|
Info: info,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ge GPSError) Error() string {
|
||||||
|
return ge.Err.Error() + " " + ge.Info
|
||||||
|
}
|
||||||
|
|
||||||
// Device wraps a connection to a GPS device.
|
// Device wraps a connection to a GPS device.
|
||||||
type Device struct {
|
type Device struct {
|
||||||
buffer []byte
|
buffer []byte
|
||||||
@@ -127,16 +147,17 @@ func (gps *Device) WriteBytes(bytes []byte) {
|
|||||||
|
|
||||||
// validSentence checks if a sentence has been received uncorrupted
|
// validSentence checks if a sentence has been received uncorrupted
|
||||||
func validSentence(sentence string) error {
|
func validSentence(sentence string) error {
|
||||||
if len(sentence) < 4 || sentence[0] != '$' || sentence[len(sentence)-3] != '*' {
|
if len(sentence) < 7 || sentence[0] != '$' || sentence[len(sentence)-3] != '*' {
|
||||||
return errInvalidNMEASentenceLength
|
return errInvalidNMEASentenceLength
|
||||||
}
|
}
|
||||||
var cs byte = 0
|
var cs byte = 0
|
||||||
for i := 1; i < len(sentence)-3; i++ {
|
for i := 1; i < len(sentence)-3; i++ {
|
||||||
cs ^= sentence[i]
|
cs ^= sentence[i]
|
||||||
}
|
}
|
||||||
checksum := hex.EncodeToString([]byte{cs})
|
checksum := strings.ToUpper(hex.EncodeToString([]byte{cs}))
|
||||||
if (checksum[0] != sentence[len(sentence)-2]) || (checksum[1] != sentence[len(sentence)-1]) {
|
if checksum != sentence[len(sentence)-2:len(sentence)] {
|
||||||
return errInvalidNMEAChecksum
|
return newGPSError(errInvalidNMEAChecksum, "expected "+sentence[len(sentence)-2:len(sentence)]+
|
||||||
|
" got "+checksum)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+19
-20
@@ -1,19 +1,11 @@
|
|||||||
package gps
|
package gps
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errEmptyNMEASentence = errors.New("cannot parse empty NMEA sentence")
|
|
||||||
errUnknownNMEASentence = errors.New("unsupported NMEA sentence type")
|
|
||||||
errInvalidGGASentence = errors.New("invalid GGA NMEA sentence")
|
|
||||||
errInvalidRMCSentence = errors.New("invalid RMC NMEA sentence")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Parser for GPS NMEA sentences.
|
// Parser for GPS NMEA sentences.
|
||||||
type Parser struct {
|
type Parser struct {
|
||||||
}
|
}
|
||||||
@@ -51,18 +43,20 @@ func NewParser() Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses a NMEA sentence looking for fix info.
|
// Parse parses a NMEA sentence looking for fix info.
|
||||||
func (parser *Parser) Parse(sentence string) (fix Fix, err error) {
|
func (parser *Parser) Parse(sentence string) (Fix, error) {
|
||||||
|
var fix Fix
|
||||||
if sentence == "" {
|
if sentence == "" {
|
||||||
err = errEmptyNMEASentence
|
return fix, errEmptyNMEASentence
|
||||||
return
|
}
|
||||||
|
if len(sentence) < 6 {
|
||||||
|
return fix, errInvalidNMEASentenceLength
|
||||||
}
|
}
|
||||||
typ := sentence[3:6]
|
typ := sentence[3:6]
|
||||||
switch typ {
|
switch typ {
|
||||||
case "GGA":
|
case "GGA":
|
||||||
fields := strings.Split(sentence, ",")
|
fields := strings.Split(sentence, ",")
|
||||||
if len(fields) != 15 {
|
if len(fields) != 15 {
|
||||||
err = errInvalidGGASentence
|
return fix, errInvalidGGASentence
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fix.Altitude = findAltitude(fields[9])
|
fix.Altitude = findAltitude(fields[9])
|
||||||
@@ -71,11 +65,12 @@ func (parser *Parser) Parse(sentence string) (fix Fix, err error) {
|
|||||||
fix.Latitude = findLatitude(fields[2], fields[3])
|
fix.Latitude = findLatitude(fields[2], fields[3])
|
||||||
fix.Time = findTime(fields[1])
|
fix.Time = findTime(fields[1])
|
||||||
fix.Valid = (fix.Altitude != -99999) && (fix.Satellites > 0)
|
fix.Valid = (fix.Altitude != -99999) && (fix.Satellites > 0)
|
||||||
|
|
||||||
|
return fix, nil
|
||||||
case "RMC":
|
case "RMC":
|
||||||
fields := strings.Split(sentence, ",")
|
fields := strings.Split(sentence, ",")
|
||||||
if len(fields) != 13 {
|
if len(fields) != 13 {
|
||||||
err = errInvalidRMCSentence
|
return fix, errInvalidRMCSentence
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fix.Longitude = findLongitude(fields[5], fields[6])
|
fix.Longitude = findLongitude(fields[5], fields[6])
|
||||||
@@ -83,11 +78,12 @@ func (parser *Parser) Parse(sentence string) (fix Fix, err error) {
|
|||||||
fix.Time = findTime(fields[1])
|
fix.Time = findTime(fields[1])
|
||||||
fix.Speed = findSpeed(fields[7])
|
fix.Speed = findSpeed(fields[7])
|
||||||
fix.Heading = findHeading(fields[8])
|
fix.Heading = findHeading(fields[8])
|
||||||
fix.Valid = (len(fields[2]) > 0 && fields[2][0:1] == "A")
|
fix.Valid = (len(fields[2]) > 0 && fields[2] == "A")
|
||||||
default:
|
|
||||||
err = errUnknownNMEASentence
|
return fix, nil
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
return fix, newGPSError(errUnknownNMEASentence, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// findTime returns the time from an NMEA sentence:
|
// findTime returns the time from an NMEA sentence:
|
||||||
@@ -100,7 +96,10 @@ func findTime(val string) time.Time {
|
|||||||
h, _ := strconv.ParseInt(val[0:2], 10, 8)
|
h, _ := strconv.ParseInt(val[0:2], 10, 8)
|
||||||
m, _ := strconv.ParseInt(val[2:4], 10, 8)
|
m, _ := strconv.ParseInt(val[2:4], 10, 8)
|
||||||
s, _ := strconv.ParseInt(val[4:6], 10, 8)
|
s, _ := strconv.ParseInt(val[4:6], 10, 8)
|
||||||
ms, _ := strconv.ParseInt(val[7:10], 10, 16)
|
ms := int64(0)
|
||||||
|
if len(val) == 10 {
|
||||||
|
ms, _ = strconv.ParseInt(val[7:10], 10, 16)
|
||||||
|
}
|
||||||
t := time.Date(0, 0, 0, int(h), int(m), int(s), int(ms), time.UTC)
|
t := time.Date(0, 0, 0, int(h), int(m), int(s), int(ms), time.UTC)
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
|||||||
Reference in New Issue
Block a user