use crate::nmea::field::{FieldReader, FieldWriter, NmeaEncodable};
#[derive(Debug, Clone, PartialEq)]
pub struct Psoncms {
pub quaternion_0: Option<f32>,
pub quaternion_1: Option<f32>,
pub quaternion_2: Option<f32>,
pub quaternion_3: Option<f32>,
pub accel_x: Option<f32>,
pub accel_y: Option<f32>,
pub accel_z: Option<f32>,
pub rot_x: Option<f32>,
pub rot_y: Option<f32>,
pub rot_z: Option<f32>,
pub mag_x: Option<f32>,
pub mag_y: Option<f32>,
pub mag_z: Option<f32>,
pub temperature: Option<f32>,
}
impl Psoncms {
pub fn parse(fields: &[&str]) -> Option<Self> {
let mut r = FieldReader::new(fields);
let quaternion_0 = r.f32();
let quaternion_1 = r.f32();
let quaternion_2 = r.f32();
let quaternion_3 = r.f32();
let accel_x = r.f32();
let accel_y = r.f32();
let accel_z = r.f32();
let rot_x = r.f32();
let rot_y = r.f32();
let rot_z = r.f32();
let mag_x = r.f32();
let mag_y = r.f32();
let mag_z = r.f32();
let temperature = r.f32();
Some(Self {
quaternion_0,
quaternion_1,
quaternion_2,
quaternion_3,
accel_x,
accel_y,
accel_z,
rot_x,
rot_y,
rot_z,
mag_x,
mag_y,
mag_z,
temperature,
})
}
}
impl NmeaEncodable for Psoncms {
const SENTENCE_TYPE: &str = "CMS";
const PROPRIETARY_ID: &str = "PSONCMS";
fn encode(&self) -> Vec<String> {
let mut w = FieldWriter::new();
w.f32(self.quaternion_0);
w.f32(self.quaternion_1);
w.f32(self.quaternion_2);
w.f32(self.quaternion_3);
w.f32(self.accel_x);
w.f32(self.accel_y);
w.f32(self.accel_z);
w.f32(self.rot_x);
w.f32(self.rot_y);
w.f32(self.rot_z);
w.f32(self.mag_x);
w.f32(self.mag_y);
w.f32(self.mag_z);
w.f32(self.temperature);
w.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse_frame;
#[test]
fn psoncms_empty() {
let s = Psoncms {
quaternion_0: None,
quaternion_1: None,
quaternion_2: None,
quaternion_3: None,
accel_x: None,
accel_y: None,
accel_z: None,
rot_x: None,
rot_y: None,
rot_z: None,
mag_x: None,
mag_y: None,
mag_z: None,
temperature: None,
}
.to_proprietary_sentence();
let f = parse_frame(s.trim()).expect("valid");
let p = Psoncms::parse(&f.fields).expect("parse");
assert!(p.quaternion_0.is_none());
assert!(p.temperature.is_none());
}
#[test]
fn psoncms_encode_roundtrip() {
let original = Psoncms {
quaternion_0: Some(0.0905),
quaternion_1: Some(0.4217),
quaternion_2: Some(0.9020),
quaternion_3: Some(-0.0196),
accel_x: Some(-1.7685),
accel_y: Some(0.3861),
accel_z: Some(-9.6648),
rot_x: Some(-0.0116),
rot_y: Some(0.0065),
rot_z: Some(-0.0080),
mag_x: Some(0.0581),
mag_y: Some(0.3846),
mag_z: Some(0.7421),
temperature: Some(33.1),
};
let sentence = original.to_proprietary_sentence();
let frame = parse_frame(sentence.trim()).expect("re-parse");
let parsed = Psoncms::parse(&frame.fields).expect("parse");
assert_eq!(original, parsed);
}
#[test]
fn psoncms_xsens_gonmea() {
let f = parse_frame(
"$PSONCMS,0.0905,0.4217,0.9020,-0.0196,-1.7685,0.3861,-9.6648,-0.0116,0.0065,-0.0080,0.0581,0.3846,0.7421,33.1*76",
)
.expect("valid PSONCMS");
let p = Psoncms::parse(&f.fields).expect("parse PSONCMS");
assert!((p.quaternion_0.expect("q0") - 0.0905).abs() < 0.0001);
assert!((p.quaternion_1.expect("q1") - 0.4217).abs() < 0.0001);
assert!((p.quaternion_2.expect("q2") - 0.9020).abs() < 0.0001);
assert!((p.quaternion_3.expect("q3") - (-0.0196)).abs() < 0.0001);
assert!((p.accel_x.expect("ax") - (-1.7685)).abs() < 0.0001);
assert!((p.temperature.expect("temp") - 33.1).abs() < 0.01);
}
}