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, Clone, Copy, PartialEq)]
pub struct VtgData {
pub true_course: Option<f32>,
pub speed_over_ground: Option<f32>,
}
fn do_parse_vtg(i: &str) -> IResult<&str, VtgData> {
let (i, true_course) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('T'))(i)?;
let (i, _) = char(',')(i)?;
let (i, _magn_course) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('M'))(i)?;
let (i, _) = char(',')(i)?;
let (i, knots_ground_speed) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('N'))(i)?;
let (i, kph_ground_speed) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('K'))(i)?;
Ok((
i,
VtgData {
true_course,
speed_over_ground: match (knots_ground_speed, kph_ground_speed) {
(Some(val), _) => Some(val),
(_, Some(val)) => Some(val / 1.852),
(None, None) => None,
},
},
))
}
pub fn parse_vtg(sentence: NmeaSentence) -> Result<VtgData, Error> {
if sentence.message_id != SentenceType::VTG {
Err(Error::WrongSentenceHeader {
expected: SentenceType::VTG,
found: sentence.message_id,
})
} else {
Ok(do_parse_vtg(sentence.data)?.1)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{parse::parse_nmea_sentence, Error};
fn run_parse_vtg(line: &str) -> Result<VtgData, Error> {
let s = parse_nmea_sentence(line).expect("VTG sentence initial parse failed");
assert_eq!(s.checksum, s.calc_checksum());
parse_vtg(s)
}
#[test]
fn test_parse_vtg() {
assert_eq!(
VtgData {
true_course: None,
speed_over_ground: None,
},
run_parse_vtg("$GPVTG,,T,,M,,N,,K,N*2C").unwrap()
);
assert_eq!(
VtgData {
true_course: Some(360.),
speed_over_ground: Some(0.),
},
run_parse_vtg("$GPVTG,360.0,T,348.7,M,000.0,N,000.0,K*43").unwrap()
);
assert_eq!(
VtgData {
true_course: Some(54.7),
speed_over_ground: Some(5.5),
},
run_parse_vtg("$GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48").unwrap()
);
}
}