-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added support for TagBlocks #59
Closed
Closed
Changes from 4 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
2ffc4bc
Added support for TagBlocks
klyve 83a54df
Added tests for linecount and relative time
klyve 30fd183
Early exit if no matches in tagblock
klyve e7a1392
Fixed PR comments
klyve d2c4cad
Renamed parseUint to parseInt64
klyve 60b3520
Added validation for timestamp according to nmea spec
klyve 1dea5fa
Merge branch 'master' into master
adrianmo 7ae4adf
Fix checksum ref after branch update
adrianmo 75d6121
changed go mod to fork
klyve 1270711
Merge branch 'master' of github.com:klyve/go-nmea
klyve File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package nmea | ||
|
||
import ( | ||
"fmt" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
const ( | ||
// TypeUnixTime unix timestamp, parameter: -c | ||
TypeUnixTime = "c" | ||
// TypeDestinationID destination identification 15char max, parameter: -d | ||
TypeDestinationID = "d" | ||
// TypeGrouping sentence grouping, parameter: -g | ||
TypeGrouping = "g" | ||
// TypeLineCount linecount, parameter: -n | ||
TypeLineCount = "n" | ||
// TypeRelativeTime relative time time, paremeter: -r | ||
TypeRelativeTime = "r" | ||
// TypeSourceID source identification 15char max, paremter: -s | ||
TypeSourceID = "s" | ||
// TypeTextString valid character string, parameter -t | ||
TypeTextString = "t" | ||
) | ||
|
||
var ( | ||
// tagBlockRegexp matches nmea tag blocks | ||
tagBlockRegexp = regexp.MustCompile(`^(.*)\\(\S+)\\(.*)`) | ||
) | ||
|
||
// TagBlock struct | ||
type TagBlock struct { | ||
Head string // * | ||
Time int64 // -c | ||
RelativeTime int64 // -r | ||
Destination string // -d 15 char max | ||
Grouping string // -g nummeric string | ||
LineCount int64 // -n int | ||
Source string // -s 15 char max | ||
Text string // -t Variable length text | ||
} | ||
|
||
func parseUint(raw string) (int64, error) { | ||
klyve marked this conversation as resolved.
Show resolved
Hide resolved
|
||
i, err := strconv.ParseInt(raw[2:], 10, 32) | ||
if err != nil { | ||
return 0, fmt.Errorf("nmea: tagblock unable to parse uint32 [%s]", raw) | ||
} | ||
return i, nil | ||
} | ||
|
||
// parseTagBlock adds support for tagblocks | ||
// https://rietman.wordpress.com/2016/09/17/nemastudio-now-supports-the-nmea-0183-tag-block/ | ||
func parseTagBlock(raw string) (TagBlock, string, error) { | ||
matches := tagBlockRegexp.FindStringSubmatch(raw) | ||
if matches == nil { | ||
return TagBlock{}, raw, nil | ||
} | ||
|
||
tagBlock := TagBlock{} | ||
raw = matches[3] | ||
tags := matches[2] | ||
tagBlock.Head = matches[1] | ||
|
||
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 = xorChecksum(fieldsRaw) | ||
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 { | ||
if len(item) == 0 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be Actually, I think a cleaner way would be to just use parts := strings.SplitN(item, ":", 2)
if len(parts) != 2 {
continue
}
key, value := parts[0], parts[1] |
||
continue | ||
} | ||
switch item[:1] { | ||
case TypeUnixTime: | ||
tagBlock.Time, err = parseUint(item) | ||
if err != nil { | ||
return tagBlock, raw, err | ||
} | ||
case TypeDestinationID: | ||
tagBlock.Destination = item[2:] | ||
case TypeGrouping: | ||
tagBlock.Grouping = item[2:] | ||
case TypeLineCount: | ||
tagBlock.LineCount, err = parseUint(item) | ||
if err != nil { | ||
return tagBlock, raw, err | ||
} | ||
case TypeRelativeTime: | ||
tagBlock.RelativeTime, err = parseUint(item) | ||
if err != nil { | ||
return tagBlock, raw, err | ||
} | ||
case TypeSourceID: | ||
tagBlock.Source = item[2:] | ||
case TypeTextString: | ||
tagBlock.Text = item[2:] | ||
} | ||
} | ||
return tagBlock, raw, 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,121 @@ | ||
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\\!AIVDM,1,1,,A,13M@ah0025QdPDTCOl`K6`nV00Sv,0*52", | ||
msg: TagBlock{ | ||
Time: 1553390539, | ||
Source: "Satelite_1", | ||
}, | ||
}, | ||
{ | ||
|
||
name: "Test NMEA tag block with head", | ||
raw: "UdPbC?\\s:satelite,c:1564827317*25\\!AIVDM,1,1,,A,19NSRaP02A0fo91kwnaMKbjR08:J,0*15", | ||
msg: TagBlock{ | ||
Time: 1564827317, | ||
Source: "satelite", | ||
Head: "UdPbC?", | ||
}, | ||
}, | ||
{ | ||
|
||
name: "Test unknown tag", | ||
raw: "UdPbC?\\x:NorSat_1,c:1564827317*42\\!AIVDM,1,1,,A,19NSRaP02A0fo91kwnaMKbjR08:J,0*15", | ||
msg: TagBlock{ | ||
Time: 1564827317, | ||
Source: "", | ||
Head: "UdPbC?", | ||
}, | ||
}, | ||
{ | ||
|
||
name: "Test all input types", | ||
raw: "UdPbC?\\s:satelite,c:1564827317,r:1553390539,d:ara,g:bulk,n:13,t:helloworld*3F\\!AIVDM,1,1,,A,19NSRaP02A0fo91kwnaMKbjR08:J,0*15", | ||
msg: TagBlock{ | ||
Time: 1564827317, | ||
RelativeTime: 1553390539, | ||
Destination: "ara", | ||
Grouping: "bulk", | ||
Source: "satelite", | ||
Head: "UdPbC?", | ||
Text: "helloworld", | ||
LineCount: 13, | ||
}, | ||
}, | ||
{ | ||
|
||
name: "Test empty tag in tagblock", | ||
raw: "UdPbC?\\s:satelite,,r:1553390539,d:ara,g:bulk,n:13,t:helloworld*68\\!AIVDM,1,1,,A,19NSRaP02A0fo91kwnaMKbjR08:J,0*15", | ||
msg: TagBlock{ | ||
Time: 0, | ||
RelativeTime: 1553390539, | ||
Destination: "ara", | ||
Grouping: "bulk", | ||
Source: "satelite", | ||
Head: "UdPbC?", | ||
Text: "helloworld", | ||
LineCount: 13, | ||
}, | ||
//err: "nmea: tagblock checksum mismatch [25 != 49]", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't commit commented-out code |
||
}, | ||
{ | ||
|
||
name: "Test Invalid checksum", | ||
raw: "UdPbC?\\s:satelite,c:1564827317*49\\!AIVDM,1,1,,A,19NSRaP02A0fo91kwnaMKbjR08:J,0*15", | ||
err: "nmea: tagblock checksum mismatch [25 != 49]", | ||
}, | ||
{ | ||
|
||
name: "Test no checksum", | ||
raw: "UdPbC?\\s:satelite,c:156482731749\\!AIVDM,1,1,,A,19NSRaP02A0fo91kwnaMKbjR08:J,0*15", | ||
err: "nmea: tagblock does not contain checksum separator", | ||
}, | ||
{ | ||
|
||
name: "Test invalid timestamp", | ||
raw: "UdPbC?\\s:satelite,c:gjadslkg*30\\!AIVDM,1,1,,A,19NSRaP02A0fo91kwnaMKbjR08:J,0*15", | ||
err: "nmea: tagblock unable to parse uint32 [c:gjadslkg]", | ||
}, | ||
{ | ||
|
||
name: "Test invalid linecount", | ||
raw: "UdPbC?\\s:satelite,n:gjadslkg*3D\\!AIVDM,1,1,,A,19NSRaP02A0fo91kwnaMKbjR08:J,0*15", | ||
err: "nmea: tagblock unable to parse uint32 [n:gjadslkg]", | ||
}, | ||
{ | ||
|
||
name: "Test invalid relative time", | ||
raw: "UdPbC?\\s:satelite,r:gjadslkg*21\\!AIVDM,1,1,,A,19NSRaP02A0fo91kwnaMKbjR08:J,0*15", | ||
err: "nmea: tagblock unable to parse uint32 [r:gjadslkg]", | ||
}, | ||
} | ||
|
||
func TestTagBlock(t *testing.T) { | ||
for _, tt := range tagblocktests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
m, err := Parse(tt.raw) | ||
if tt.err != "" { | ||
assert.Error(t, err) | ||
assert.EqualError(t, err, tt.err) | ||
} else { | ||
assert.NoError(t, err) | ||
vdm := m.(VDMVDO) | ||
assert.Equal(t, tt.msg, vdm.BaseSentence.TagBlock) | ||
} | ||
}) | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need these constants in the public API. Since they're only used in the one spot, I think it would be better to just inline them into the switch.
Move the comments from these types to the
TagBlock
struct fields.