use crate::nmea::field::{FieldReader, FieldWriter};
#[derive(Debug, Clone, PartialEq)]
pub struct Zda {
pub time: Option<String>,
pub day: Option<u8>,
pub month: Option<u8>,
pub year: Option<u32>,
pub local_hour_offset: Option<f32>,
pub local_min_offset: Option<u8>,
}
impl Zda {
pub const SENTENCE_TYPE: &str = "ZDA";
pub fn parse(fields: &[&str]) -> Option<Self> {
let mut r = FieldReader::new(fields);
Some(Self {
time: r.string(),
day: r.u8(),
month: r.u8(),
year: r.u32(),
local_hour_offset: r.f32(),
local_min_offset: r.u8(),
})
}
pub fn encode(&self) -> Vec<String> {
let mut w = FieldWriter::new();
w.string(self.time.as_deref());
w.u8(self.day);
w.u8(self.month);
w.u32(self.year);
w.f32(self.local_hour_offset);
w.u8(self.local_min_offset);
w.finish()
}
pub fn to_sentence(&self, talker: &str) -> String {
let fields = self.encode();
let field_refs: Vec<&str> = fields.iter().map(|s| s.as_str()).collect();
crate::encode_frame('$', talker, Self::SENTENCE_TYPE, &field_refs)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse_frame;
#[test]
fn zda_empty() {
let f = parse_frame("$GPZDA,,,,,,*48").expect("valid");
let z = Zda::parse(&f.fields).expect("parse");
assert!(z.time.is_none());
assert!(z.day.is_none());
assert!(z.month.is_none());
assert!(z.year.is_none());
assert!(z.local_hour_offset.is_none());
assert!(z.local_min_offset.is_none());
}
#[test]
fn zda_encode_roundtrip() {
let zda = Zda {
time: Some("160012.71".to_string()),
day: Some(11),
month: Some(3),
year: Some(2004),
local_hour_offset: Some(-1.0),
local_min_offset: Some(0),
};
let sentence = zda.to_sentence("GP");
assert!(sentence.starts_with("$GPZDA,"));
let frame = parse_frame(sentence.trim()).expect("re-parse");
let zda2 = Zda::parse(&frame.fields).expect("re-parse ZDA");
assert_eq!(zda.time, zda2.time);
assert_eq!(zda.day, zda2.day);
assert_eq!(zda.month, zda2.month);
assert_eq!(zda.year, zda2.year);
}
#[test]
fn zda_full_gonmea() {
let f =
parse_frame("$GPZDA,172809.456,12,07,1996,00,00*57").expect("valid ZDA from go-nmea");
let z = Zda::parse(&f.fields).expect("parse ZDA");
assert_eq!(z.time, Some("172809.456".to_string()));
assert_eq!(z.day, Some(12));
assert_eq!(z.month, Some(7));
assert_eq!(z.year, Some(1996));
assert!((z.local_hour_offset.expect("ltzh present") - 0.0).abs() < 0.01);
assert_eq!(z.local_min_offset, Some(0));
}
#[test]
fn zda_pynmeagps() {
let f =
parse_frame("$GNZDA,103607.00,06,03,2021,00,00*7F").expect("valid ZDA from pynmeagps");
let z = Zda::parse(&f.fields).expect("parse ZDA");
assert_eq!(z.time, Some("103607.00".to_string()));
assert_eq!(z.day, Some(6));
assert_eq!(z.month, Some(3));
assert_eq!(z.year, Some(2021));
}
}