Skip to content
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

Add MDA, MWD, MWV #81

Merged
merged 4 commits into from
Sep 8, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions mda.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package nmea

/**
$WIMDA

NMEA 0183 standard Meteorological Composite.

Syntax
$WIMDA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,
<12>,<13>,<14>,<15>,<16>,<17>,<18>,<19>,<20>*hh
<CR><LF>

Fields
<1> Barometric pressure, inches of mercury, to the nearest 0.01 inch
<2> I = inches of mercury
<3> Barometric pressure, bars, to the nearest .001 bar
<4> B = bars
<5> Air temperature, degrees C, to the nearest 0.1 degree C
<6> C = degrees C
<7> Water temperature, degrees C (this field left blank by some WeatherStations)
<8> C = degrees C (this field left blank by WeatherStation)
<9> Relative humidity, percent, to the nearest 0.1 percent
<10> Absolute humidity, percent (this field left blank by some WeatherStations)
<11> Dew point, degrees C, to the nearest 0.1 degree C
<12> C = degrees C
<13> Wind direction, degrees True, to the nearest 0.1 degree
<14> T = true
<15> Wind direction, degrees Magnetic, to the nearest 0.1 degree
<16> M = magnetic
<17> Wind speed, knots, to the nearest 0.1 knot
<18> N = knots
<19> Wind speed, meters per second, to the nearest 0.1 m/s
<20> M = meters per second
*/

const (
TypeMDA = "MDA"
InchMDA = "I"
BarsMDA = "B"
DegreesCMDA = "C"
TrueMDA = "T"
MagneticMDA = "M"
KnotsMDA = "N"
MetersSecondMDA = "M"
EmptyMDA = ""
Maescool marked this conversation as resolved.
Show resolved Hide resolved
)

type MDA struct {
BaseSentence
PressureInch float64
InchesValid bool // I
PressureBar float64
BarsValid bool // B
AirTemp float64
AirTempValid bool // C or empty if no data
WaterTemp float64
WaterTempValid bool // C or empty if no data
RelativeHum float64 // percent to .1
AbsoluteHum float64 // percent to .1
DewPoint float64
DewPointValid bool // C or empty if no data
WindDirectionTrue float64
TrueValid bool // T
WindDirectionMagnetic float64
MagneticValid bool // M
WindSpeedKnots float64
KnotsValid bool // N
WindSpeedMeters float64
MetersValid bool // M
}

func newMDA(s BaseSentence) (MDA, error) {
p := NewParser(s)
p.AssertType(TypeMDA)
return MDA{
BaseSentence: s,
PressureInch: p.Float64(0, "pressure in inch"),
InchesValid: p.EnumString(1, "inches valid", InchMDA, EmptyMDA) == InchMDA,
PressureBar: p.Float64(2, "pressure in bar"),
BarsValid: p.EnumString(3, "bars valid", BarsMDA, EmptyMDA) == BarsMDA,
AirTemp: p.Float64(4, "air temp"),
AirTempValid: p.EnumString(5, "air temp valid", DegreesCMDA, EmptyMDA) == DegreesCMDA,
WaterTemp: p.Float64(6, "water temp"),
WaterTempValid: p.EnumString(7, "water temp valid", DegreesCMDA, EmptyMDA) == DegreesCMDA,
RelativeHum: p.Float64(8, "relative humidity"),
AbsoluteHum: p.Float64(9, "absolute humidity"),
DewPoint: p.Float64(10, "dewpoint"),
DewPointValid: p.EnumString(11, "dewpoint valid", DegreesCMDA, EmptyMDA) == DegreesCMDA,
WindDirectionTrue: p.Float64(12, "wind direction true"),
TrueValid: p.EnumString(13, "wind direction true valid", TrueMDA, EmptyMDA) == TrueMDA,
WindDirectionMagnetic: p.Float64(14, "wind direction magnetic"),
MagneticValid: p.EnumString(15, "wind direction magnetic valid", MagneticMDA, EmptyMDA) == MagneticMDA,
WindSpeedKnots: p.Float64(16, "windspeed knots"),
KnotsValid: p.EnumString(17, "windspeed knots valid", KnotsMDA, EmptyMDA) == KnotsMDA,
WindSpeedMeters: p.Float64(18, "windspeed m/s"),
MetersValid: p.EnumString(19, "windspeed m/s valid", MetersSecondMDA, EmptyMDA) == MetersSecondMDA,
}, p.Err()
}
57 changes: 57 additions & 0 deletions mda_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package nmea

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

var mdatests = []struct {
name string
raw string
err string
msg MDA
}{
{
name: "good sentence",
raw: "$WIMDA,3.02,I,1.01,B,23.4,C,,,40.2,,12.1,C,19.3,T,20.1,M,13.1,N,1.1,M*62",
msg: MDA{
PressureInch: 3.02,
InchesValid: true,
PressureBar: 1.01,
BarsValid: true,
AirTemp: 23.4,
AirTempValid: true,
WaterTemp: 0,
WaterTempValid: false,
RelativeHum: 40.2,
AbsoluteHum: 0,
DewPoint: 12.1,
DewPointValid: true,
WindDirectionTrue: 19.3,
TrueValid: true,
WindDirectionMagnetic: 20.1,
MagneticValid: true,
WindSpeedKnots: 13.1,
KnotsValid: true,
WindSpeedMeters: 1.1,
MetersValid: true,
},
},
}

func TestMDA(t *testing.T) {
for _, tt := range mdatests {
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)
mda := m.(MDA)
mda.BaseSentence = BaseSentence{}
assert.Equal(t, tt.msg, mda)
}
})
}
}
57 changes: 57 additions & 0 deletions mwd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package nmea

/**
$WIMWD

NMEA 0183 standard Wind Direction and Speed, with respect to north.

Syntax
$WIMWD,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>*hh<CR><LF>

Fields
<1> Wind direction, 0.0 to 359.9 degrees True, to the nearest 0.1 degree
<2> T = True
<3> Wind direction, 0.0 to 359.9 degrees Magnetic, to the nearest 0.1 degree
<4> M = Magnetic
<5> Wind speed, knots, to the nearest 0.1 knot.
<6> N = Knots
<7> Wind speed, meters/second, to the nearest 0.1 m/s.
<8> M = Meters/second
*/

const (
TypeMWD = "MWD"
TrueMWD = "T"
MagneticMWD = "M"
KnotsMWD = "N"
MetersSecondMWD = "M"
EmptyMWD = ""
)

type MWD struct {
BaseSentence
WindDirectionTrue float64
TrueValid bool
WindDirectionMagnetic float64
MagneticValid bool
WindSpeedKnots float64
KnotsValid bool
WindSpeedMeters float64
MetersValid bool
}

func newMWD(s BaseSentence) (MWD, error) {
p := NewParser(s)
p.AssertType(TypeMWD)
return MWD{
BaseSentence: s,
WindDirectionTrue: p.Float64(0, "true wind direction"),
TrueValid: p.EnumString(1, "true wind valid", TrueMWD, EmptyMWD) == TrueMWD,
WindDirectionMagnetic: p.Float64(2, "magnetic wind direction"),
MagneticValid: p.EnumString(3, "magnetic direction valid", MagneticMWD, EmptyMWD) == MagneticMWD,
WindSpeedKnots: p.Float64(4, "windspeed knots"),
KnotsValid: p.EnumString(5, "windspeed knots valid", KnotsMWD, EmptyMWD) == KnotsMWD,
WindSpeedMeters: p.Float64(6, "windspeed m/s"),
MetersValid: p.EnumString(7, "windspeed m/s valid", MetersSecondMWD, EmptyMWD) == MetersSecondMWD,
}, p.Err()
}
59 changes: 59 additions & 0 deletions mwd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package nmea

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

var mwdtests = []struct {
name string
raw string
err string
msg MWD
}{
{
name: "good sentence",
raw: "$WIMWD,10.1,T,10.1,M,12,N,40,M*5D",
msg: MWD{
WindDirectionTrue: 10.1,
TrueValid: true,
WindDirectionMagnetic: 10.1,
MagneticValid: true,
WindSpeedKnots: 12,
KnotsValid: true,
WindSpeedMeters: 40,
MetersValid: true,
},
},
{
name: "empty data",
raw: "$WIMWD,,,,,,,,*40",
msg: MWD{
WindDirectionTrue: 0,
TrueValid: false,
WindDirectionMagnetic: 0,
MagneticValid: false,
WindSpeedKnots: 0,
KnotsValid: false,
WindSpeedMeters: 0,
MetersValid: false,
},
},
}

func TestMWD(t *testing.T) {
for _, tt := range mwdtests {
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)
mwd := m.(MWD)
mwd.BaseSentence = BaseSentence{}
assert.Equal(t, tt.msg, mwd)
}
})
}
}
61 changes: 61 additions & 0 deletions mwv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package nmea

/**
$WIMWV

NMEA 0183 standard Wind Speed and Angle, in relation to the vessel’s bow/centerline.

Syntax
$WIMWV,<1>,<2>,<3>,<4>,<5>*hh<CR><LF>

Fields
<1> Wind angle, 0.0 to 359.9 degrees, in relation to the vessel’s bow/centerline, to the nearest 0.1
degree. If the data for this field is not valid, the field will be blank.
<2> Reference:
R = Relative (apparent wind, as felt when standing on the moving ship)
T = Theoretical (calculated actual wind, as though the vessel were stationary)
<3> Wind speed, to the nearest tenth of a unit. If the data for this field is not valid, the field will be
blank.
<4> Wind speed units:
K = km/hr
M = m/s
N = knots
S = statute miles/hr
(Most WeatherStations will commonly use "N" (knots))
<5> Status:
A = data valid; V = data invalid
*/

const (
TypeMWV = "MWV"
RelativeMWV = "R" // Relative
TheoreticalMWV = "T" // Theoretical
UnitKMHMWV = "K" // KM/H
UnitMSMWV = "M" // M/S
UnitKnotsMWV = "N" // knots
UnitSMilesHMWV = "S" // Statue miles/H
ValidMWV = "A"
InvalidMWV = "V"
)

type MWV struct {
BaseSentence
WindAngle float64
Reference string
WindSpeed float64
WindSpeedUnit string
StatusValid bool
}

func newMWV(s BaseSentence) (MWV, error) {
p := NewParser(s)
p.AssertType(TypeMWV)
return MWV{
BaseSentence: s,
WindAngle: p.Float64(0, "wind angle"),
Reference: p.EnumString(1, "reference", RelativeMWV, TheoreticalMWV),
WindSpeed: p.Float64(2, "wind speed"),
WindSpeedUnit: p.EnumString(3, "wind speed unit", UnitKMHMWV, UnitMSMWV, UnitKnotsMWV, UnitSMilesHMWV),
StatusValid: p.EnumString(4, "status", ValidMWV, InvalidMWV) == ValidMWV,
}, p.Err()
}
53 changes: 53 additions & 0 deletions mwv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package nmea

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

var mwvtests = []struct {
name string
raw string
err string
msg MWV
}{
{
name: "good sentence",
raw: "$WIMWV,12.1,T,10.1,N,A*27",
msg: MWV{
WindAngle: 12.1,
Reference: "T",
WindSpeed: 10.1,
WindSpeedUnit: "N",
StatusValid: true,
},
},
{
name: "invalid data",
raw: "$WIMWV,,T,,N,V*32",
msg: MWV{
WindAngle: 0,
Reference: "T",
WindSpeed: 0,
WindSpeedUnit: "N",
StatusValid: false,
},
},
}

func TestMWV(t *testing.T) {
for _, tt := range mwvtests {
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)
mwv := m.(MWV)
mwv.BaseSentence = BaseSentence{}
assert.Equal(t, tt.msg, mwv)
}
})
}
}
Loading