use crate::{
encoder::NmeaEncode,
faa::FaaMode,
macros::{write_byte, write_str},
message::NmeaMessageError,
number::NmeaNumber,
parser::NmeaParse,
};
#[derive(Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Vtg<'a> {
pub degrees_true: &'a str,
pub degrees_true_indicator: &'a str,
pub degrees_magnetic: &'a str,
pub degrees_magnetic_indicator: &'a str,
pub speed_knots: &'a str,
pub speed_knots_units: &'a str,
pub speed_kph: &'a str,
pub speed_kph_units: &'a str,
pub faa_mode: Option<&'a str>,
}
impl<'a> NmeaParse<'a> for Vtg<'a> {
fn parse(fields: &'a str) -> Result<Self, NmeaMessageError> {
let mut f = fields.splitn(9, ',');
Ok(Self {
degrees_true: f.next().ok_or(NmeaMessageError::MissingField)?,
degrees_true_indicator: f.next().ok_or(NmeaMessageError::MissingField)?,
degrees_magnetic: f.next().ok_or(NmeaMessageError::MissingField)?,
degrees_magnetic_indicator: f.next().ok_or(NmeaMessageError::MissingField)?,
speed_knots: f.next().ok_or(NmeaMessageError::MissingField)?,
speed_knots_units: f.next().ok_or(NmeaMessageError::MissingField)?,
speed_kph: f.next().ok_or(NmeaMessageError::MissingField)?,
speed_kph_units: f.next().ok_or(NmeaMessageError::MissingField)?,
faa_mode: f.next().filter(|s| !s.is_empty()),
})
}
}
impl NmeaEncode for Vtg<'_> {
fn encoded_len(&self) -> usize {
self.degrees_true.len()
+ self.degrees_true_indicator.len()
+ self.degrees_magnetic.len()
+ self.degrees_magnetic_indicator.len()
+ self.speed_knots.len()
+ self.speed_knots_units.len()
+ self.speed_kph.len()
+ self.speed_kph_units.len()
+ self.faa_mode.map_or(0, |f| f.len() + 1)
+ 7
}
fn encode(&self, buf: &mut [u8]) -> usize {
let mut pos = 0;
write_str!(buf, pos, self.degrees_true);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.degrees_true_indicator);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.degrees_magnetic);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.degrees_magnetic_indicator);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.speed_knots);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.speed_knots_units);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.speed_kph);
write_byte!(buf, pos, b',');
write_str!(buf, pos, self.speed_kph_units);
if let Some(faa_mode) = self.faa_mode {
write_byte!(buf, pos, b',');
write_str!(buf, pos, faa_mode);
}
pos
}
}
impl Vtg<'_> {
#[must_use]
pub fn degrees_true(&self) -> Option<NmeaNumber> {
if self.degrees_true_indicator != "T" {
return None;
}
NmeaNumber::parse(self.degrees_true)
}
#[must_use]
pub fn degrees_magnetic(&self) -> Option<NmeaNumber> {
if self.degrees_magnetic_indicator != "M" {
return None;
}
NmeaNumber::parse(self.degrees_magnetic)
}
#[must_use]
pub fn speed_knots(&self) -> Option<NmeaNumber> {
if self.speed_knots_units != "N" {
return None;
}
NmeaNumber::parse(self.speed_knots)
}
#[must_use]
pub fn speed_kph(&self) -> Option<NmeaNumber> {
if self.speed_kph_units != "K" {
return None;
}
NmeaNumber::parse(self.speed_kph)
}
pub fn faa_mode(&self) -> Option<FaaMode> {
self.faa_mode.and_then(FaaMode::parse)
}
}