Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions examples/gps/uart/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,31 @@ import (
)

func main() {
println("GPS UART Example")
machine.UART1.Configure(machine.UARTConfig{BaudRate: 9600})
ublox := gps.NewUART(machine.UART1)
parser := gps.NewParser()
var fix gps.Fix
for {
s, err := ublox.NextSentence()
if err != nil {
println(err)
continue
switch err {
case gps.ErrUnknownNMEASentence, gps.ErrInvalidNMEASentence, gps.ErrInvalidNMEASentenceLength:
continue
default:
println("sentence error:", err)
continue
}
}

fix, err = parser.Parse(s)
if err != nil {
println(err)
continue
switch err {
case gps.ErrUnknownNMEASentence, gps.ErrInvalidNMEASentence, gps.ErrInvalidNMEASentenceLength:
continue
default:
println("parse error:", err)
continue
}
}
if fix.Valid {
print(fix.Time.Format("15:04:05"))
Expand All @@ -43,7 +52,7 @@ func main() {
}
println()
} else {
println("No fix")
println("Waiting for fix...")
}
time.Sleep(200 * time.Millisecond)
}
Expand Down
44 changes: 10 additions & 34 deletions gps/gps.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,17 @@ import (
)

var (
errInvalidNMEASentenceLength = errors.New("invalid NMEA sentence length")
errInvalidNMEAChecksum = errors.New("invalid NMEA sentence checksum")
errEmptyNMEASentence = errors.New("cannot parse empty NMEA sentence")
errUnknownNMEASentence = errors.New("unsupported NMEA sentence type")
ErrInvalidNMEASentenceLength = errors.New("invalid NMEA sentence length")
ErrInvalidNMEASentence = errors.New("invalid NMEA sentence format")
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")
errInvalidGLLSentence = errors.New("invalid GLL NMEA sentence")
errGPSCommandRejected = errors.New("GPS command rejected (NAK)")
errNoACKToGPSCommand = errors.New("no ACK to GPS command")
)

type GPSError struct {
Err error
Info string
Sentence string
}

func newGPSError(err error, sentence string, info string) GPSError {
return GPSError{
Info: info,
Err: err,
Sentence: sentence,
}
}

func (ge GPSError) Error() string {
return ge.Err.Error() + " " + ge.Info + " " + ge.Sentence
}

func (ge GPSError) Unwrap() error {
return ge.Err
}

const (
minimumNMEALength = 7
startingDelimiter = '$'
Expand All @@ -50,19 +30,18 @@ const (

// Device wraps a connection to a GPS device.
type Device struct {
buffer []byte
bufIdx int
sentence strings.Builder
uart drivers.UART
bus drivers.I2C
address uint16
buffer [bufferSize]byte
}

// NewUART creates a new UART GPS connection. The UART must already be configured.
func NewUART(uart drivers.UART) Device {
return Device{
uart: uart,
buffer: make([]byte, bufferSize),
bufIdx: bufferSize,
sentence: strings.Builder{},
}
Expand All @@ -79,7 +58,6 @@ func NewI2CWithAddress(bus drivers.I2C, i2cAddress uint16) Device {
return Device{
bus: bus,
address: i2cAddress,
buffer: make([]byte, bufferSize),
bufIdx: bufferSize,
sentence: strings.Builder{},
}
Expand Down Expand Up @@ -172,17 +150,15 @@ func (gps *Device) WriteBytes(bytes []byte) {
// It has to end with a '*' character following by a checksum.
func validSentence(sentence string) error {
if len(sentence) < minimumNMEALength || sentence[0] != startingDelimiter || sentence[len(sentence)-3] != checksumDelimiter {
return errInvalidNMEASentenceLength
return ErrInvalidNMEASentenceLength
}
var cs byte = 0
for i := 1; i < len(sentence)-3; i++ {
cs ^= sentence[i]
}
checksum := strings.ToUpper(hex.EncodeToString([]byte{cs}))
if checksum != sentence[len(sentence)-2:len(sentence)] {
return newGPSError(errInvalidNMEAChecksum, sentence,
"expected "+sentence[len(sentence)-2:len(sentence)]+
" got "+checksum)
if checksum != sentence[len(sentence)-2:] {
return ErrInvalidNMEASentence
}

return nil
Expand Down
6 changes: 3 additions & 3 deletions gps/gpsparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ func NewParser() Parser {
func (parser *Parser) Parse(sentence string) (Fix, error) {
var fix Fix
if sentence == "" {
return fix, errEmptyNMEASentence
return fix, ErrEmptyNMEASentence
}
if len(sentence) < 6 {
return fix, errInvalidNMEASentenceLength
return fix, ErrInvalidNMEASentenceLength
}
typ := sentence[3:6]
switch typ {
Expand Down Expand Up @@ -104,7 +104,7 @@ func (parser *Parser) Parse(sentence string) (Fix, error) {
return fix, nil
}

return fix, newGPSError(errUnknownNMEASentence, sentence, typ)
return fix, ErrUnknownNMEASentence
}

// findTime returns the time from an NMEA sentence:
Expand Down
6 changes: 3 additions & 3 deletions gps/gpsparser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import (
)

func TestParseUnknownSentence(t *testing.T) {
c := qt.New(t)

p := NewParser()

val := "$GPGSV,3,1,09,07,14,317,22,08,31,284,25,10,32,133,39,16,85,232,29*7F"
_, err := p.Parse(val)
c.Assert(err.Error(), qt.Contains, "unsupported NMEA sentence type")
if err == nil {
t.Error("should have unknown sentence err")
}
}

func TestParseGGA(t *testing.T) {
Expand Down
Loading