Skip to content

Commit

Permalink
Return sentence index instead of rest
Browse files Browse the repository at this point in the history
  • Loading branch information
icholy committed Jul 6, 2024
1 parent 7295c89 commit 59d2eca
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 38 deletions.
5 changes: 3 additions & 2 deletions sentence.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,16 @@ func (p *SentenceParser) parseBaseSentence(raw string) (BaseSentence, error) {
if raw == "" {
return BaseSentence{}, errors.New("nmea: can not parse empty input")
}
tagBlock, raw, ok, err := ParseTagBlock(raw)
tagBlock, sentenceStartIndex, err := ParseTagBlock(raw)
if err != nil {
return BaseSentence{}, err
}
if ok && p.OnTagBlock != nil {
if sentenceStartIndex > 0 && p.OnTagBlock != nil {
if err := p.OnTagBlock(tagBlock); err != nil {
return BaseSentence{}, err
}
}
raw = raw[sentenceStartIndex:]

startIndex := strings.IndexAny(raw, SentenceStart+SentenceStartEncapsulated)
if startIndex != 0 {
Expand Down
23 changes: 11 additions & 12 deletions tagblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,25 @@ type TagBlock struct {
}

// ParseTagBlock parses tag blocks from a sentence string.
// The second return value contains the sentence with tag block removed.
// The third return value indicates if a tag block was found.
// The second return value is the index where the sentence starts.
// See: https://gpsd.gitlab.io/gpsd/AIVDM.html#_nmea_tag_blocks
func ParseTagBlock(raw string) (TagBlock, string, bool, error) {
func ParseTagBlock(raw string) (TagBlock, int, error) {
startOfTagBlock := strings.IndexByte(raw, TagBlockSep)
if startOfTagBlock == -1 {
return TagBlock{}, raw, false, nil
return TagBlock{}, 0, nil
}
// tag block is always at the start of line (unless IEC 61162-450). Starts with `\` and ends with `\` and has valid sentence
// following or <CR><LF>
//
// Note: tag block group can span multiple lines but we only parse ones that have sentence
endOfTagBlock := strings.LastIndexByte(raw, TagBlockSep)
if endOfTagBlock <= startOfTagBlock {
return TagBlock{}, "", false, fmt.Errorf("nmea: sentence tag block is missing '\\' at the end")
return TagBlock{}, 0, fmt.Errorf("nmea: sentence tag block is missing '\\' at the end")
}
tags := raw[startOfTagBlock+1 : endOfTagBlock]
sumSepIndex := strings.Index(tags, ChecksumSep)
if sumSepIndex == -1 {
return TagBlock{}, "", false, fmt.Errorf("nmea: tagblock does not contain checksum separator")
return TagBlock{}, 0, fmt.Errorf("nmea: tagblock does not contain checksum separator")
}

var (
Expand All @@ -50,21 +49,21 @@ func ParseTagBlock(raw string) (TagBlock, string, bool, error) {

// Validate the checksum
if checksum != checksumRaw {
return TagBlock{}, "", false, fmt.Errorf("nmea: tagblock checksum mismatch [%s != %s]", checksum, checksumRaw)
return TagBlock{}, 0, 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{}, "", false, fmt.Errorf("nmea: tagblock field is malformed (should be <key>:<value>) [%s]", item)
return TagBlock{}, 0, 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{}, "", false, err
return TagBlock{}, 0, err
}
case "d": // Destination ID
tagBlock.Destination = value
Expand All @@ -73,20 +72,20 @@ func ParseTagBlock(raw string) (TagBlock, string, bool, error) {
case "n": // Line count
tagBlock.LineCount, err = parseInt64(value)
if err != nil {
return TagBlock{}, "", false, err
return TagBlock{}, 0, err
}
case "r": // Relative time
tagBlock.RelativeTime, err = parseInt64(value)
if err != nil {
return TagBlock{}, "", false, err
return TagBlock{}, 0, err
}
case "s": // Source ID
tagBlock.Source = value
case "t": // Text string
tagBlock.Text = value
}
}
return tagBlock, raw[endOfTagBlock+1:], true, nil
return tagBlock, endOfTagBlock + 1, nil
}

func parseInt64(raw string) (int64, error) {
Expand Down
39 changes: 15 additions & 24 deletions tagblock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import (
)

var tagblocktests = []struct {
name string
raw string
err string
block TagBlock
ok bool
remaining string
name string
raw string
err string
block TagBlock
index int
}{
{

Expand All @@ -22,8 +21,7 @@ var tagblocktests = []struct {
Time: 1553390539,
Source: "Satelite_1",
},
ok: true,
remaining: "!AIVDM,1,2,3",
index: 30,
},
{

Expand All @@ -33,8 +31,7 @@ var tagblocktests = []struct {
Time: 1564827317,
Source: "satelite",
},
ok: true,
remaining: "!AIVDM,1,2,3",
index: 28,
},
{

Expand All @@ -44,8 +41,7 @@ var tagblocktests = []struct {
Time: 1564827317,
Source: "",
},
ok: true,
remaining: "!AIVDM,1,2,3",
index: 28,
},
{
name: "Test unix timestamp",
Expand All @@ -54,8 +50,7 @@ var tagblocktests = []struct {
Time: 1564827317,
Source: "",
},
ok: true,
remaining: "!AIVDM,1,2,3",
index: 28,
},
{

Expand All @@ -65,8 +60,7 @@ var tagblocktests = []struct {
Time: 1564827317000,
Source: "",
},
ok: true,
remaining: "!AIVDM,1,2,3",
index: 31,
},
{

Expand All @@ -81,8 +75,7 @@ var tagblocktests = []struct {
Text: "helloworld",
LineCount: 13,
},
ok: true,
remaining: "!AIVDM,1,2,3",
index: 72,
},
{

Expand Down Expand Up @@ -121,24 +114,22 @@ var tagblocktests = []struct {
err: "nmea: tagblock unable to parse uint64 [gjadslkg]",
},
{
name: "Test no tagblock",
raw: "!AIVDM,1,2,3",
remaining: "!AIVDM,1,2,3",
name: "Test no tagblock",
raw: "!AIVDM,1,2,3",
},
}

func TestParseTagBlock(t *testing.T) {
for _, tt := range tagblocktests {
t.Run(tt.name, func(t *testing.T) {
b, remaining, ok, err := ParseTagBlock(tt.raw)
b, index, err := ParseTagBlock(tt.raw)
if tt.err != "" {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, tt.block, b)
assert.Equal(t, tt.remaining, remaining)
assert.Equal(t, tt.ok, ok)
assert.Equal(t, tt.index, index)
})
}
}

0 comments on commit 59d2eca

Please sign in to comment.