Skip to content

Commit

Permalink
Merge branch 'adrianmo:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
tholok97 authored Mar 11, 2024
2 parents c3696ca + a60cdb4 commit 5c2b5f1
Show file tree
Hide file tree
Showing 164 changed files with 10,523 additions and 691 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: CI

on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
go: ["1.20", "1.19", "1.18", "1.17"]
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go }}

- name: Install dependencies
run: |
go install golang.org/x/lint/golint@latest
go install github.com/mattn/[email protected]
- name: Lint
run: |
go vet ./...
golint -set_exit_status ./...
- name: Test
run: |
go test -v -race -covermode=atomic -coverprofile=profile.cov ./...
- name: Coverage
run: |
goveralls -coverprofile=profile.cov -service=github -parallel -flagname="go-${{ matrix.go }}"
env:
COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24 changes: 0 additions & 24 deletions .travis.yml

This file was deleted.

18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.DEFAULT_GOAL := check
check: lint vet test ## Check project

lint: ## Lint the files
@golint -set_exit_status ./...

vet: ## Vet the files
@go vet ./...

test: ## Run tests with data race detector
@go test -race ./...

init:
@go install golang.org/x/lint/golint@latest

goversion ?= "1.19"
test_version: ## Run tests inside Docker with given version (defaults to 1.19). Example for Go1.15: make test_version goversion=1.15
@docker run --rm -it -v $(shell pwd):/project golang:$(goversion) /bin/sh -c "cd /project && make test"
329 changes: 290 additions & 39 deletions README.md

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions aam.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package nmea

const (
// TypeAAM type of AAM sentence for Waypoint Arrival Alarm
TypeAAM = "AAM"
)

// AAM - Waypoint Arrival Alarm
// This sentence is generated by some units to indicate the status of arrival (entering the arrival circle, or passing
// the perpendicular of the course line) at the destination waypoint (source: GPSD).
// https://gpsd.gitlab.io/gpsd/NMEA.html#_aam_waypoint_arrival_alarm
//
// Format: $--AAM,A,A,x.x,N,c--c*hh<CR><LF>
// Example: $GPAAM,A,A,0.10,N,WPTNME*43
type AAM struct {
BaseSentence
// StatusArrivalCircleEntered is warning of arrival to waypoint circle
// * A = Arrival Circle Entered
// * V = not entered
StatusArrivalCircleEntered string

// StatusPerpendicularPassed is warning for perpendicular passing of waypoint
// * A = Perpendicular passed at waypoint
// * V = not passed
StatusPerpendicularPassed string

// ArrivalCircleRadius is radius for arrival circle
ArrivalCircleRadius float64

// ArrivalCircleRadiusUnit is unit for arrival circle radius
ArrivalCircleRadiusUnit string

// DestinationWaypointID is destination waypoint ID
DestinationWaypointID string
}

// newAAM constructor
func newAAM(s BaseSentence) (Sentence, error) {
p := NewParser(s)
p.AssertType(TypeAAM)
return AAM{
BaseSentence: s,
StatusArrivalCircleEntered: p.EnumString(0, "arrival circle entered status", WPStatusArrivalCircleEnteredA, WPStatusArrivalCircleEnteredV),
StatusPerpendicularPassed: p.EnumString(1, "perpendicularly passed status", WPStatusPerpendicularPassedA, WPStatusPerpendicularPassedV),
ArrivalCircleRadius: p.Float64(2, "arrival circle radius"),
ArrivalCircleRadiusUnit: p.EnumString(3, "arrival circle radius units", DistanceUnitKilometre, DistanceUnitNauticalMile, DistanceUnitStatuteMile, DistanceUnitMetre),
DestinationWaypointID: p.String(4, "destination waypoint ID"),
}, p.Err()
}
56 changes: 56 additions & 0 deletions aam_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package nmea

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestAAM(t *testing.T) {
var tests = []struct {
name string
raw string
err string
msg AAM
}{
{
name: "good sentence",
raw: "$GPAAM,A,A,0.10,N,WPTNME*32",
msg: AAM{
StatusArrivalCircleEntered: WPStatusArrivalCircleEnteredA,
StatusPerpendicularPassed: WPStatusPerpendicularPassedA,
ArrivalCircleRadius: 0.1,
ArrivalCircleRadiusUnit: DistanceUnitNauticalMile,
DestinationWaypointID: "WPTNME",
},
},
{
name: "invalid nmea: StatusArrivalCircleEntered",
raw: "$GPAAM,x,A,0.10,N,WPTNME*0B",
err: "nmea: GPAAM invalid arrival circle entered status: x",
},
{
name: "invalid nmea: StatusPerpendicularPassed",
raw: "$GPAAM,A,x,0.10,N,WPTNME*0B",
err: "nmea: GPAAM invalid perpendicularly passed status: x",
},
{
name: "invalid nmea: DistanceUnitNauticalMile",
raw: "$GPAAM,A,A,0.10,x,WPTNME*04",
err: "nmea: GPAAM invalid arrival circle radius units: x",
},
}
for _, tt := range tests {
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)
aam := m.(AAM)
aam.BaseSentence = BaseSentence{}
assert.Equal(t, tt.msg, aam)
}
})
}
}
57 changes: 57 additions & 0 deletions abm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package nmea

const (
// TypeABM type of ABM sentence for AIS addressed binary and safety related message
TypeABM = "ABM"
)

// ABM - AIS addressed binary and safety related message
// https://fcc.report/FCC-ID/ADB9ZWRTR100/2768717.pdf (page 6) FURUNO MARINE RADAR, model FAR-15XX manual
//
// Format: !--ABM,x,x,x,xxxxxxxxx,x,xx,s--s,x,*hh<CR><LF>
// Example: !AIABM,26,2,1,3381581370,3,8,177KQJ5000G?tO`K>RA1wUbN0TKH,0*02
type ABM struct {
BaseSentence

// NumFragments is total number of fragments/sentences need to transfer the message (1 - 9)
NumFragments int64 // 0

// FragmentNumber is current fragment/sentence number (1 - 9)
FragmentNumber int64 // 1

// MessageID is sequential message identifier (0 - 3)
MessageID int64 // 2

// MMSI is The MMSI of destination AIS unit for the ITU-R M.1371 message (10 digits or empty)
MMSI string // 3

// Channel is AIS channel for broadcast of the radio message (0 - 3)
// 0 - no broadcast
// 1 - on AIS channel A
// 2 - on AIS channel B
// 3 - broadcast on both AIS channels
Channel string // 4

// VDLMessageNumber is VDL message number (6/12), see ITU-R M.1371
VDLMessageNumber int64 // 5

// Payload is encapsulated data (6 bit binary-converted data) (1 - 63 bytes)
Payload []byte // 6
// 7 - Number of fill bits (0 - 5)
}

// newABM constructor
func newABM(s BaseSentence) (Sentence, error) {
p := NewParser(s)
p.AssertType(TypeABM)
return ABM{
BaseSentence: s,
NumFragments: p.Int64(0, "number of fragments"),
FragmentNumber: p.Int64(1, "fragment number"),
MessageID: p.Int64(2, "message ID"),
MMSI: p.String(3, "MMSI"),
Channel: p.String(4, "channel"),
VDLMessageNumber: p.Int64(5, "VDL message number"),
Payload: p.SixBitASCIIArmour(6, int(p.Int64(7, "number of padding bits")), "payload"),
}, p.Err()
}
134 changes: 134 additions & 0 deletions abm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package nmea

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestABM(t *testing.T) {
var tests = []struct {
name string
raw string
err string
msg ABM
}{
{
name: "Good single fragment message",
raw: "!AIABM,26,2,1,3381581370,3,8,177KQJ5000G?tO`K>RA1wUbN0TKH,0*02",
msg: ABM{
NumFragments: 26,
FragmentNumber: 2,
MessageID: 1,
MMSI: "3381581370",
Channel: "3",
VDLMessageNumber: 8,
Payload: []byte{
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, // 10
0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x0, 0x1, // 20
0x1, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, // 30
0x0, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, // 40
0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // 50
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // 60
0x0, 0x1, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x1, 0x1, // 70
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, // 80
0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x0, // 90
0x0, 0x1, 0x1, 0x0, 0x1, 0x1, 0x0, 0x0, 0x1, 0x1, // 100
0x1, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, // 110
0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // 120
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x1, // 130
0x0, 0x1, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, // 140
0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // 150
0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, // 160
0x1, 0x1, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, // 168
},
},
},
{
name: "Good single fragment message with padding",
raw: "!AIABM,26,2,1,3381581370,3,8,H77nSfPh4U=<E`H4U8G;:222220,2*42",
msg: ABM{
NumFragments: 26,
FragmentNumber: 2,
MessageID: 1,
MMSI: "3381581370",
Channel: "3",
VDLMessageNumber: 8,
Payload: []byte{
0, 1, 1, 0, 0, 0, 0, 0, 0, 1,
1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
0, 1, 1, 0, 1, 0, 0, 0, 1, 1,
1, 0, 1, 1, 1, 0, 1, 0, 0, 0,
0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 1, 0, 0, 1, 0, 1,
0, 0, 1, 1, 0, 1, 0, 0, 1, 1,
0, 0, 0, 1, 0, 1, 0, 1, 1, 0,
1, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
0, 1, 0, 0, 1, 0, 0, 0, 0, 1,
0, 1, 1, 1, 0, 0, 1, 0, 1, 1,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
},
},
},
{
name: "Empty payload",
raw: "!AIABM,26,2,1,3381581370,3,8,,0*7b",
msg: ABM{
NumFragments: 26,
FragmentNumber: 2,
MessageID: 1,
MMSI: "3381581370",
Channel: "3",
VDLMessageNumber: 8,
Payload: []byte{},
},
},
{
name: "Invalid number of fragments",
raw: "!AIABM,x,2,1,3381581370,3,8,177KQJ5000G?tO`K>RA1wUbN0TKH,0*7e",
err: "nmea: AIABM invalid number of fragments: x",
},
{
name: "Invalid VDLMessageNumber",
raw: "!AIABM,26,2,1,3381581370,3,x,177KQJ5000G?tO`K>RA1wUbN0TKH,0*42",
err: "nmea: AIABM invalid VDL message number: x",
},
{
name: "Invalid symbol in payload",
raw: "!AIABM,26,2,1,3381581370,3,8,1 1,0*5b",
err: "nmea: AIABM invalid payload: data byte",
},
{
name: "Negative number of fill bits",
raw: "!AIABM,26,2,1,3381581370,3,8,177KQJ5000G?tO`K>RA1wUbN0TKH,-1*2e",
err: "nmea: AIABM invalid payload: fill bits",
},
{
name: "Too high number of fill bits",
raw: "!AIABM,26,2,1,3381581370,3,8,177KQJ5000G?tO`K>RA1wUbN0TKH,20*30",
err: "nmea: AIABM invalid payload: fill bits",
},
{
name: "Negative number of bits",
raw: "!AIABM,26,2,1,3381581370,3,8,,2*79",
err: "nmea: AIABM invalid payload: num bits",
},
}
for _, tt := range tests {
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)
abm := m.(ABM)
abm.BaseSentence = BaseSentence{}
assert.Equal(t, tt.msg, abm)
}
})
}
}
Loading

0 comments on commit 5c2b5f1

Please sign in to comment.