-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathmwv.rs
137 lines (127 loc) · 4.1 KB
/
mwv.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use nom::{
character::complete::{char, one_of},
combinator::opt,
number::complete::float,
sequence::preceded,
IResult,
};
use crate::{parse::NmeaSentence, Error, SentenceType};
/// MWV - Wind Speed and Angle
///
/// <https://gpsd.gitlab.io/gpsd/NMEA.html#_mwv_wind_speed_and_angle>
///
/// ```text
/// 1 2 3 4 5
/// | | | | |
/// $--MWV,x.x,a,x.x,a*hh<CR><LF>
/// ```
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
#[derive(Debug, PartialEq)]
pub struct MwvData {
pub wind_direction: Option<f32>,
pub reference: Option<MwvReference>,
pub wind_speed: Option<f32>,
pub wind_speed_units: Option<MwvWindSpeedUnits>,
pub data_valid: bool,
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MwvReference {
Relative,
Theoretical,
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MwvWindSpeedUnits {
KilometersPerHour,
MetersPerSecond,
Knots,
MilesPerHour,
}
/// # Parse MWV message
///
/// Information from mwv:
///
/// NMEA 0183 standard Wind Speed and Angle, in relation to the vessel’s bow/centerline.
/// <https://gpsd.gitlab.io/gpsd/NMEA.html#_mwv_wind_speed_and_angle>
///
/// ## Example (Ignore the line break):
/// ```text
/// $WIMWV,041.1,R,01.0,N,A*16
///```
///
/// 1: 041.1 Wind direction, cardinal NED degrees
/// 2: R Relative or Theoretical windspeed
/// 3: 01.0 Wind speed
/// 4: N Wind speed units (Knots)
/// 5: A Data is OK
/// 6: *16 Mandatory NMEA checksum
pub fn parse_mwv(sentence: NmeaSentence) -> Result<MwvData, Error> {
if sentence.message_id != SentenceType::MWV {
Err(Error::WrongSentenceHeader {
expected: SentenceType::MWV,
found: sentence.message_id,
})
} else {
Ok(do_parse_mwv(sentence.data)?.1)
}
}
fn do_parse_mwv(i: &str) -> IResult<&str, MwvData> {
let (i, direction) = opt(float)(i)?;
let (i, reference_type) = opt(preceded(char(','), one_of("RT")))(i)?;
let reference_type = reference_type.map(|ch| match ch {
'R' => MwvReference::Relative,
'T' => MwvReference::Theoretical,
_ => unreachable!(),
});
let (i, _) = char(',')(i)?;
let (i, speed) = opt(float)(i)?;
let (i, wind_speed_type) = opt(preceded(char(','), one_of("KMNS")))(i)?;
let wind_speed_type = wind_speed_type.map(|ch| match ch {
'K' => MwvWindSpeedUnits::KilometersPerHour,
'M' => MwvWindSpeedUnits::MetersPerSecond,
'N' => MwvWindSpeedUnits::Knots,
'S' => MwvWindSpeedUnits::MilesPerHour,
_ => unreachable!(),
});
let (i, is_data_valid) = preceded(char(','), one_of("AV"))(i)?;
let is_data_valid = match is_data_valid {
'A' => true,
'V' => false,
_ => unreachable!(),
};
Ok((
i,
MwvData {
wind_direction: direction,
reference: reference_type,
wind_speed: speed,
wind_speed_units: wind_speed_type,
data_valid: is_data_valid,
},
))
}
#[cfg(test)]
mod tests {
use approx::assert_relative_eq;
use super::*;
use crate::parse::parse_nmea_sentence;
#[test]
fn test_parse_mwv() {
let s = parse_nmea_sentence("$WIMWV,041.1,R,01.0,N,A*16").unwrap();
assert_eq!(s.checksum, s.calc_checksum());
assert_eq!(s.checksum, 0x16);
let wimwv_data = parse_mwv(s).unwrap();
assert_relative_eq!(41.1, wimwv_data.wind_direction.unwrap());
assert_eq!(MwvReference::Relative, wimwv_data.reference.unwrap());
assert_relative_eq!(1.0, wimwv_data.wind_speed.unwrap());
assert_eq!(
MwvWindSpeedUnits::Knots,
wimwv_data.wind_speed_units.unwrap()
);
assert!(wimwv_data.data_valid);
}
}