Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
294 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package nmea | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// TagBlock struct | ||
type TagBlock struct { | ||
Time int64 // TypeUnixTime unix timestamp (unit is likely to be s, but might be ms, YMMV), parameter: -c | ||
RelativeTime int64 // TypeRelativeTime relative time, parameter: -r | ||
Destination string // TypeDestinationID destination identification 15 char max, parameter: -d | ||
Grouping string // TypeGrouping sentence grouping, parameter: -g | ||
LineCount int64 // TypeLineCount line count, parameter: -n | ||
Source string // TypeSourceID source identification 15 char max, parameter: -s | ||
Text string // TypeTextString valid character string, parameter -t | ||
} | ||
|
||
func parseInt64(raw string) (int64, error) { | ||
i, err := strconv.ParseInt(raw, 10, 64) | ||
if err != nil { | ||
return 0, fmt.Errorf("nmea: tagblock unable to parse uint64 [%s]", raw) | ||
} | ||
return i, nil | ||
} | ||
|
||
// parseTagBlock adds support for tagblocks | ||
// https://gpsd.gitlab.io/gpsd/AIVDM.html#_nmea_tag_blocks | ||
func parseTagBlock(tags string) (TagBlock, error) { | ||
sumSepIndex := strings.Index(tags, ChecksumSep) | ||
if sumSepIndex == -1 { | ||
return TagBlock{}, fmt.Errorf("nmea: tagblock does not contain checksum separator") | ||
} | ||
|
||
var ( | ||
fieldsRaw = tags[0:sumSepIndex] | ||
checksumRaw = strings.ToUpper(tags[sumSepIndex+1:]) | ||
checksum = Checksum(fieldsRaw) | ||
tagBlock TagBlock | ||
err error | ||
) | ||
|
||
// Validate the checksum | ||
if checksum != checksumRaw { | ||
return TagBlock{}, fmt.Errorf("nmea: tagblock checksum mismatch [%s != %s]", checksum, checksumRaw) | ||
} | ||
|
||
items := strings.Split(tags[:sumSepIndex], ",") | ||
for _, item := range items { | ||
parts := strings.SplitN(item, ":", 2) | ||
if len(parts) != 2 { | ||
return TagBlock{}, | ||
fmt.Errorf("nmea: tagblock field is malformed (should be <key>:<value>) [%s]", item) | ||
} | ||
key, value := parts[0], parts[1] | ||
switch key { | ||
case "c": // UNIX timestamp | ||
tagBlock.Time, err = parseInt64(value) | ||
if err != nil { | ||
return TagBlock{}, err | ||
} | ||
case "d": // Destination ID | ||
tagBlock.Destination = value | ||
case "g": // Grouping | ||
tagBlock.Grouping = value | ||
case "n": // Line count | ||
tagBlock.LineCount, err = parseInt64(value) | ||
if err != nil { | ||
return TagBlock{}, err | ||
} | ||
case "r": // Relative time | ||
tagBlock.RelativeTime, err = parseInt64(value) | ||
if err != nil { | ||
return TagBlock{}, err | ||
} | ||
case "s": // Source ID | ||
tagBlock.Source = value | ||
case "t": // Text string | ||
tagBlock.Text = value | ||
} | ||
} | ||
return tagBlock, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package nmea | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
var tagblocktests = []struct { | ||
name string | ||
raw string | ||
err string | ||
msg TagBlock | ||
}{ | ||
{ | ||
|
||
name: "Test NMEA tag block", | ||
raw: "s:Satelite_1,c:1553390539*62", | ||
msg: TagBlock{ | ||
Time: 1553390539, | ||
Source: "Satelite_1", | ||
}, | ||
}, | ||
{ | ||
|
||
name: "Test NMEA tag block with head", | ||
raw: "s:satelite,c:1564827317*25", | ||
msg: TagBlock{ | ||
Time: 1564827317, | ||
Source: "satelite", | ||
}, | ||
}, | ||
{ | ||
|
||
name: "Test unknown tag", | ||
raw: "x:NorSat_1,c:1564827317*42", | ||
msg: TagBlock{ | ||
Time: 1564827317, | ||
Source: "", | ||
}, | ||
}, | ||
{ | ||
name: "Test unix timestamp", | ||
raw: "x:NorSat_1,c:1564827317*42", | ||
msg: TagBlock{ | ||
Time: 1564827317, | ||
Source: "", | ||
}, | ||
}, | ||
{ | ||
|
||
name: "Test milliseconds timestamp", | ||
raw: "x:NorSat_1,c:1564827317000*72", | ||
msg: TagBlock{ | ||
Time: 1564827317000, | ||
Source: "", | ||
}, | ||
}, | ||
{ | ||
|
||
name: "Test all input types", | ||
raw: "s:satelite,c:1564827317,r:1553390539,d:ara,g:bulk,n:13,t:helloworld*3F", | ||
msg: TagBlock{ | ||
Time: 1564827317, | ||
RelativeTime: 1553390539, | ||
Destination: "ara", | ||
Grouping: "bulk", | ||
Source: "satelite", | ||
Text: "helloworld", | ||
LineCount: 13, | ||
}, | ||
}, | ||
{ | ||
|
||
name: "Test empty tag in tagblock", | ||
raw: "s:satelite,,r:1553390539,d:ara,g:bulk,n:13,t:helloworld*68", | ||
err: "nmea: tagblock field is malformed (should be <key>:<value>) []", | ||
}, | ||
{ | ||
|
||
name: "Test Invalid checksum", | ||
raw: "s:satelite,c:1564827317*49", | ||
err: "nmea: tagblock checksum mismatch [25 != 49]", | ||
}, | ||
{ | ||
|
||
name: "Test no checksum", | ||
raw: "s:satelite,c:156482731749", | ||
err: "nmea: tagblock does not contain checksum separator", | ||
}, | ||
{ | ||
|
||
name: "Test invalid timestamp", | ||
raw: "s:satelite,c:gjadslkg*30", | ||
err: "nmea: tagblock unable to parse uint64 [gjadslkg]", | ||
}, | ||
{ | ||
|
||
name: "Test invalid linecount", | ||
raw: "s:satelite,n:gjadslkg*3D", | ||
err: "nmea: tagblock unable to parse uint64 [gjadslkg]", | ||
}, | ||
{ | ||
|
||
name: "Test invalid relative time", | ||
raw: "s:satelite,r:gjadslkg*21", | ||
err: "nmea: tagblock unable to parse uint64 [gjadslkg]", | ||
}, | ||
} | ||
|
||
func TestTagBlock(t *testing.T) { | ||
for _, tt := range tagblocktests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
m, err := parseTagBlock(tt.raw) | ||
if tt.err != "" { | ||
assert.Error(t, err) | ||
assert.EqualError(t, err, tt.err) | ||
} else { | ||
assert.NoError(t, err) | ||
assert.Equal(t, tt.msg, m) | ||
} | ||
}) | ||
} | ||
} |