use nom::{character::complete::char, combinator::opt, number::complete::float, IResult};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{parse::NmeaSentence, Error, SentenceType};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
#[derive(Debug, PartialEq)]
pub struct MdaData {
pub pressure_in_hg: Option<f32>,
pub pressure_bar: Option<f32>,
pub air_temp_deg: Option<f32>,
pub water_temp_deg: Option<f32>,
pub rel_humidity: Option<f32>,
pub abs_humidity: Option<f32>,
pub dew_point: Option<f32>,
pub wind_direction_true: Option<f32>,
pub wind_direction_magnetic: Option<f32>,
pub wind_speed_knots: Option<f32>,
pub wind_speed_ms: Option<f32>,
}
pub fn parse_mda(sentence: NmeaSentence) -> Result<MdaData, Error> {
if sentence.message_id != SentenceType::MDA {
Err(Error::WrongSentenceHeader {
expected: SentenceType::MDA,
found: sentence.message_id,
})
} else {
Ok(do_parse_mda(sentence.data)?.1)
}
}
fn do_parse_mda(i: &str) -> IResult<&str, MdaData> {
let (i, pressure_in_hg) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('I'))(i)?;
let (i, _) = char(',')(i)?;
let (i, pressure_bar) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('B'))(i)?;
let (i, _) = char(',')(i)?;
let (i, air_temp_deg) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('C'))(i)?;
let (i, _) = char(',')(i)?;
let (i, water_temp_deg) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('C'))(i)?;
let (i, _) = char(',')(i)?;
let (i, rel_humidity) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, abs_humidity) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, dew_point) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('C'))(i)?;
let (i, _) = char(',')(i)?;
let (i, wind_direction_true) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('T'))(i)?;
let (i, _) = char(',')(i)?;
let (i, wind_direction_magnetic) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('M'))(i)?;
let (i, _) = char(',')(i)?;
let (i, wind_speed_knots) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('N'))(i)?;
let (i, _) = char(',')(i)?;
let (i, wind_speed_ms) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('M'))(i)?;
Ok((
i,
MdaData {
pressure_in_hg,
pressure_bar,
air_temp_deg,
water_temp_deg,
rel_humidity,
abs_humidity,
dew_point,
wind_direction_true,
wind_direction_magnetic,
wind_speed_knots,
wind_speed_ms,
},
))
}
#[cfg(test)]
mod tests {
use approx::assert_relative_eq;
use super::*;
use crate::parse::parse_nmea_sentence;
#[test]
fn test_parse_mda() {
let s = parse_nmea_sentence(
"$WIMDA,29.7544,I,1.0076,B,35.5,C,,,42.1,,20.6,C,116.4,T,107.7,M,1.2,N,0.6,M*66",
)
.unwrap();
assert_eq!(s.checksum, s.calc_checksum());
assert_eq!(s.checksum, 0x66);
let mda_data = parse_mda(s).unwrap();
assert_relative_eq!(29.7544, mda_data.pressure_in_hg.unwrap());
assert_relative_eq!(1.0076, mda_data.pressure_bar.unwrap());
assert_relative_eq!(35.5, mda_data.air_temp_deg.unwrap());
assert!(mda_data.water_temp_deg.is_none());
assert_relative_eq!(42.1, mda_data.rel_humidity.unwrap());
assert!(mda_data.abs_humidity.is_none());
assert_relative_eq!(20.6, mda_data.dew_point.unwrap());
assert_relative_eq!(116.4, mda_data.wind_direction_true.unwrap());
assert_relative_eq!(107.7, mda_data.wind_direction_magnetic.unwrap());
assert_relative_eq!(1.2, mda_data.wind_speed_knots.unwrap());
assert_relative_eq!(0.6, mda_data.wind_speed_ms.unwrap());
}
}