-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add DTM, OSD, RSD, TLL, TTM, VBW sentences (#93)
- Loading branch information
Showing
15 changed files
with
1,016 additions
and
4 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package nmea | ||
|
||
const ( | ||
// TypeDTM type of DTM sentence for Datum Reference | ||
TypeDTM = "DTM" | ||
) | ||
|
||
// DTM - Datum Reference | ||
// https://gpsd.gitlab.io/gpsd/NMEA.html#_dtm_datum_reference | ||
// | ||
// Format: $--DTM,ref,x,llll,c,llll,c,aaa,ref*hh<CR><LF> | ||
// Example: $GPDTM,W84,,0.0,N,0.0,E,0.0,W84*6F | ||
// Example: $GPDTM,W84,,00.0000,N,00.0000,W,,W84*53 | ||
type DTM struct { | ||
BaseSentence | ||
LocalDatumCode string // Local datum code (W84,W72,S85,P90,999) | ||
LocalDatumSubcode string // Local datum subcode. May be blank. | ||
|
||
LatitudeOffsetMinute float64 // Latitude offset (minutes) (negative if south) | ||
LongitudeOffsetMinute float64 // Longitude offset (minutes) (negative if west) | ||
|
||
AltitudeOffsetMeters float64 // Altitude offset in meters | ||
DatumName string // Reference datum name. What’s usually seen here is "W84", the standard WGS84 datum used by GPS. | ||
} | ||
|
||
// newDTM constructor | ||
func newDTM(s BaseSentence) (DTM, error) { | ||
p := NewParser(s) | ||
p.AssertType(TypeDTM) | ||
m := DTM{ | ||
BaseSentence: s, | ||
LocalDatumCode: p.String(0, "local datum code"), | ||
LocalDatumSubcode: p.String(1, "local datum subcode"), | ||
|
||
LatitudeOffsetMinute: p.Float64(2, "latitude offset minutes"), | ||
LongitudeOffsetMinute: p.Float64(4, "longitude offset minutes"), | ||
|
||
AltitudeOffsetMeters: p.Float64(6, "altitude offset offset"), | ||
DatumName: p.String(7, "datum name"), | ||
} | ||
if p.String(3, "latitude offset direction") == South { | ||
m.LatitudeOffsetMinute *= -1 | ||
} | ||
if p.String(5, "longitude offset direction") == West { | ||
m.LongitudeOffsetMinute *= -1 | ||
} | ||
return m, p.Err() | ||
} |
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,71 @@ | ||
package nmea | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestDTM(t *testing.T) { | ||
var tests = []struct { | ||
name string | ||
raw string | ||
err string | ||
msg DTM | ||
}{ | ||
{ | ||
name: "good sentence 1", | ||
raw: "$GPDTM,W84,,0.0,N,0.0,E,0.0,W84*6F", | ||
msg: DTM{ | ||
BaseSentence: BaseSentence{}, | ||
LocalDatumCode: "W84", | ||
LocalDatumSubcode: "", | ||
LatitudeOffsetMinute: 0, | ||
LongitudeOffsetMinute: 0, | ||
AltitudeOffsetMeters: 0, | ||
DatumName: "W84", | ||
}, | ||
}, | ||
{ | ||
name: "good sentence 2", | ||
raw: "$GPDTM,W84,X,00.1200,S,12.0000,W,100,W84*27", | ||
msg: DTM{ | ||
BaseSentence: BaseSentence{}, | ||
LocalDatumCode: "W84", | ||
LocalDatumSubcode: "X", | ||
LatitudeOffsetMinute: -0.12, | ||
LongitudeOffsetMinute: -12, | ||
AltitudeOffsetMeters: 100, | ||
DatumName: "W84", | ||
}, | ||
}, | ||
{ | ||
name: "invalid nmea: LatitudeOffsetMinute", | ||
raw: "$GPDTM,W84,,x,N,0.0,E,0.0,W84*39", | ||
err: "nmea: GPDTM invalid latitude offset minutes: x", | ||
}, | ||
{ | ||
name: "invalid nmea: LongitudeOffsetMinute", | ||
raw: "$GPDTM,W84,,0.0,N,x,E,0.0,W84*39", | ||
err: "nmea: GPDTM invalid longitude offset minutes: x", | ||
}, | ||
{ | ||
name: "invalid nmea: AltitudeOffsetMeters", | ||
raw: "$GPDTM,W84,,0.0,N,0.0,E,x,W84*39", | ||
err: "nmea: GPDTM invalid altitude offset offset: 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) | ||
mm := m.(DTM) | ||
mm.BaseSentence = BaseSentence{} | ||
assert.Equal(t, tt.msg, mm) | ||
} | ||
}) | ||
} | ||
} |
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,103 @@ | ||
package nmea | ||
|
||
const ( | ||
// TypeOSD type for OSD sentence for Own Ship Data | ||
TypeOSD = "OSD" | ||
|
||
// OSDReferenceBottomTrackingLog is reference for bottom tracking log | ||
OSDReferenceBottomTrackingLog = "B" | ||
// OSDReferenceManual is reference for manually entered | ||
OSDReferenceManual = "M" | ||
// OSDReferenceWaterReferenced is reference for water referenced | ||
OSDReferenceWaterReferenced = "W" | ||
// OSDReferenceRadarTracking is reference for radar tracking of fixed target | ||
OSDReferenceRadarTracking = "R" | ||
// OSDReferencePositioningSystemGroundReference is reference for positioning system ground reference | ||
OSDReferencePositioningSystemGroundReference = "P" | ||
) | ||
|
||
// OSD - Own Ship Data | ||
// https://gpsd.gitlab.io/gpsd/NMEA.html#_osd_own_ship_data | ||
// https://github.com/nohal/OpenCPN/wiki/ARPA-targets-tracking-implementation#osd---own-ship-data | ||
// | ||
// Format: $--OSD,x.x,A,x.x,a,x.x,a,x.x,x.x,a*hh<CR><LF> | ||
// Example: $RAOSD,179.0,A,179.0,M,00.0,M,,,N*76 | ||
type OSD struct { | ||
BaseSentence | ||
// Heading is Heading in degrees | ||
Heading float64 | ||
|
||
// HeadingStatus is Heading status | ||
// * A - data valid | ||
// * V - data invalid | ||
HeadingStatus string | ||
|
||
// VesselTrueCourse is Vessel Course, degrees True | ||
VesselTrueCourse float64 | ||
|
||
// CourseReference is Course Reference, B/M/W/R/P | ||
// * B - bottom tracking log | ||
// * M - manually entered | ||
// * W - water referenced | ||
// * R - radar tracking of fixed target | ||
// * P - positioning system ground reference | ||
CourseReference string | ||
|
||
// VesselSpeed is Vessel Speed | ||
VesselSpeed float64 | ||
|
||
// SpeedReference is Speed Reference, B/M/W/R/P | ||
// * B - bottom tracking log | ||
// * M - manually entered | ||
// * W - water referenced | ||
// * R - radar tracking of fixed target | ||
// * P - positioning system ground reference. | ||
SpeedReference string | ||
|
||
// VesselSetTrue is Vessel Set, degrees True - Manually entered | ||
VesselSetTrue float64 | ||
|
||
// VesselDrift is Vessel drift (speed) - Manually entered | ||
VesselDrift float64 | ||
|
||
// SpeedUnits is Speed Units | ||
// * K - km/h | ||
// * N - Knots | ||
// * S - statute miles/h | ||
SpeedUnits string | ||
} | ||
|
||
// newOSD constructor | ||
func newOSD(s BaseSentence) (OSD, error) { | ||
p := NewParser(s) | ||
p.AssertType(TypeOSD) | ||
m := OSD{ | ||
BaseSentence: s, | ||
Heading: p.Float64(0, "heading"), | ||
HeadingStatus: p.EnumString(1, "heading status", StatusValid, StatusInvalid), | ||
VesselTrueCourse: p.Float64(2, "vessel course true"), | ||
CourseReference: p.EnumString( | ||
3, | ||
"course reference", | ||
OSDReferenceBottomTrackingLog, | ||
OSDReferenceManual, | ||
OSDReferenceWaterReferenced, | ||
OSDReferenceRadarTracking, | ||
OSDReferencePositioningSystemGroundReference, | ||
), | ||
VesselSpeed: p.Float64(4, "vessel speed"), | ||
SpeedReference: p.EnumString( | ||
5, | ||
"speed reference", | ||
OSDReferenceBottomTrackingLog, | ||
OSDReferenceManual, | ||
OSDReferenceWaterReferenced, | ||
OSDReferenceRadarTracking, | ||
OSDReferencePositioningSystemGroundReference, | ||
), | ||
VesselSetTrue: p.Float64(6, "vessel set"), | ||
VesselDrift: p.Float64(7, "vessel drift"), | ||
SpeedUnits: p.EnumString(8, "speed units", DistanceUnitKilometre, DistanceUnitNauticalMile, DistanceUnitStatuteMile), | ||
} | ||
return m, p.Err() | ||
} |
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,91 @@ | ||
package nmea | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestOSD(t *testing.T) { | ||
var tests = []struct { | ||
name string | ||
raw string | ||
err string | ||
msg OSD | ||
}{ | ||
{ | ||
name: "good sentence", | ||
raw: "$RAOSD,179.0,A,179.0,M,00.0,M,,,N*76", | ||
msg: OSD{ | ||
BaseSentence: BaseSentence{}, | ||
Heading: 179, | ||
HeadingStatus: "A", | ||
VesselTrueCourse: 179, | ||
CourseReference: "M", | ||
VesselSpeed: 0, | ||
SpeedReference: "M", | ||
VesselSetTrue: 0, | ||
VesselDrift: 0, | ||
SpeedUnits: "N", | ||
}, | ||
}, | ||
{ | ||
name: "invalid nmea: Heading", | ||
raw: "$RAOSD,x179.0,A,179.0,M,00.0,M,,,N*0e", | ||
err: "nmea: RAOSD invalid heading: x179.0", | ||
}, | ||
{ | ||
name: "invalid nmea: HeadingStatus", | ||
raw: "$RAOSD,179.0,xA,179.0,M,00.0,M,,,N*0e", | ||
err: "nmea: RAOSD invalid heading status: xA", | ||
}, | ||
{ | ||
name: "invalid nmea: VesselTrueCourse", | ||
raw: "$RAOSD,179.0,A,x179.0,M,00.0,M,,,N*0e", | ||
err: "nmea: RAOSD invalid vessel course true: x179.0", | ||
}, | ||
{ | ||
name: "invalid nmea: CourseReference", | ||
raw: "$RAOSD,179.0,A,179.0,xM,00.0,M,,,N*0e", | ||
err: "nmea: RAOSD invalid course reference: xM", | ||
}, | ||
{ | ||
name: "invalid nmea: VesselSpeed", | ||
raw: "$RAOSD,179.0,A,179.0,M,x00.0,M,,,N*0e", | ||
err: "nmea: RAOSD invalid vessel speed: x00.0", | ||
}, | ||
{ | ||
name: "invalid nmea: SpeedReference", | ||
raw: "$RAOSD,179.0,A,179.0,M,00.0,xM,,,N*0e", | ||
err: "nmea: RAOSD invalid speed reference: xM", | ||
}, | ||
{ | ||
name: "invalid nmea: VesselSetTrue", | ||
raw: "$RAOSD,179.0,A,179.0,M,00.0,M,x,,N*0e", | ||
err: "nmea: RAOSD invalid vessel set: x", | ||
}, | ||
{ | ||
name: "invalid nmea: VesselDrift", | ||
raw: "$RAOSD,179.0,A,179.0,M,00.0,M,,x,N*0e", | ||
err: "nmea: RAOSD invalid vessel drift: x", | ||
}, | ||
{ | ||
name: "invalid nmea: SpeedUnits", | ||
raw: "$RAOSD,179.0,A,179.0,M,00.0,M,,,xN*0e", | ||
err: "nmea: RAOSD invalid speed units: xN", | ||
}, | ||
} | ||
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) | ||
mm := m.(OSD) | ||
mm.BaseSentence = BaseSentence{} | ||
assert.Equal(t, tt.msg, mm) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.