use crate::nmea::field::{FieldReader, FieldWriter, NmeaEncodable};
#[derive(Debug, Clone, PartialEq)]
pub struct Pknds {
pub time: Option<String>,
pub validity: Option<char>,
pub lat: Option<f64>,
pub ns: Option<char>,
pub lon: Option<f64>,
pub ew: Option<char>,
pub speed: Option<f32>,
pub course: Option<f32>,
pub date: Option<String>,
pub variation: Option<f32>,
pub var_ew: Option<String>,
pub unit_id: Option<String>,
pub status: Option<String>,
pub extension: Option<String>,
}
impl Pknds {
pub fn parse(fields: &[&str]) -> Option<Self> {
let mut r = FieldReader::new(fields);
let time = r.string();
let validity = r.char();
let lat = r.f64();
let ns = r.char();
let lon = r.f64();
let ew = r.char();
let speed = r.f32();
let course = r.f32();
let date = r.string();
let variation = r.f32();
let var_ew = r.string();
let unit_id = r.string();
let status = r.string();
let extension = r.string();
Some(Self {
time,
validity,
lat,
ns,
lon,
ew,
speed,
course,
date,
variation,
var_ew,
unit_id,
status,
extension,
})
}
}
impl NmeaEncodable for Pknds {
const SENTENCE_TYPE: &str = "NDS";
const PROPRIETARY_ID: &str = "PKNDS";
fn encode(&self) -> Vec<String> {
let mut w = FieldWriter::new();
w.string(self.time.as_deref());
w.char(self.validity);
w.f64(self.lat);
w.char(self.ns);
w.f64(self.lon);
w.char(self.ew);
w.f32(self.speed);
w.f32(self.course);
w.string(self.date.as_deref());
w.f32(self.variation);
w.string(self.var_ew.as_deref());
w.string(self.unit_id.as_deref());
w.string(self.status.as_deref());
w.string(self.extension.as_deref());
w.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse_frame;
#[test]
fn pknds_empty() {
let s = Pknds {
time: None,
validity: None,
lat: None,
ns: None,
lon: None,
ew: None,
speed: None,
course: None,
date: None,
variation: None,
var_ew: None,
unit_id: None,
status: None,
extension: None,
}
.to_proprietary_sentence();
let f = parse_frame(s.trim()).expect("valid");
let p = Pknds::parse(&f.fields).expect("parse");
assert!(p.time.is_none());
assert!(p.extension.is_none());
}
#[test]
fn pknds_encode_roundtrip() {
let original = Pknds {
time: Some("220516".to_string()),
validity: Some('A'),
lat: Some(5133.82),
ns: Some('N'),
lon: Some(42.24),
ew: Some('W'),
speed: Some(173.8),
course: Some(231.8),
date: Some("130694".to_string()),
variation: Some(4.2),
var_ew: Some("W00".to_string()),
unit_id: Some("U00001".to_string()),
status: Some("207".to_string()),
extension: Some("00".to_string()),
};
let sentence = original.to_proprietary_sentence();
let frame = parse_frame(sentence.trim()).expect("re-parse");
let parsed = Pknds::parse(&frame.fields).expect("parse");
assert_eq!(original, parsed);
}
#[test]
fn pknds_east_variation_gonmea() {
let f = parse_frame(
"$PKNDS,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,E00,U00001,207,00,*3A",
)
.expect("valid PKNDS east variation");
let p = Pknds::parse(&f.fields).expect("parse PKNDS");
assert_eq!(p.variation, Some(4.2));
assert_eq!(p.var_ew.as_deref(), Some("E00"));
}
#[test]
fn pknds_kenwood_gonmea() {
let f = parse_frame(
"$PKNDS,220516,A,5133.82,N,00042.24,W,173.8,231.8,130694,004.2,W00,U00001,207,00,*28",
)
.expect("valid PKNDS");
let p = Pknds::parse(&f.fields).expect("parse PKNDS");
assert_eq!(p.time, Some("220516".to_string()));
assert_eq!(p.validity, Some('A'));
assert!((p.lat.expect("lat") - 5133.82).abs() < 0.001);
assert_eq!(p.ns, Some('N'));
assert_eq!(p.unit_id, Some("U00001".to_string()));
assert_eq!(p.status, Some("207".to_string()));
assert_eq!(p.extension, Some("00".to_string()));
}
}