blackbox_log/frame/gps/
mod.rs

1mod def;
2
3use alloc::vec::Vec;
4
5pub use self::def::*;
6use super::Unit;
7use crate::filter::AppliedFilter;
8use crate::units::prelude::*;
9use crate::utils::as_i32;
10use crate::{units, Headers};
11
12/// Data parsed from a GPS frame.
13#[derive(Debug, Clone)]
14pub struct GpsFrame<'data, 'headers, 'parser> {
15    headers: &'headers Headers<'data>,
16    raw: RawGpsFrame,
17    filter: &'parser AppliedFilter,
18}
19
20impl super::seal::Sealed for GpsFrame<'_, '_, '_> {}
21
22impl super::Frame for GpsFrame<'_, '_, '_> {
23    type Value = GpsValue;
24
25    #[inline]
26    fn len(&self) -> usize {
27        self.filter.len()
28    }
29
30    fn get_raw(&self, index: usize) -> Option<u32> {
31        let index = self.filter.get(index)?;
32        Some(self.raw.values[index])
33    }
34
35    fn get(&self, index: usize) -> Option<Self::Value> {
36        let frame_def = self.headers.gps_frame_def().unwrap();
37        let index = self.filter.get(index)?;
38
39        let def = &frame_def.fields[index];
40        let raw = self.raw.values[index];
41
42        let value = match def.unit {
43            GpsUnit::Coordinate => {
44                assert!(def.signed);
45                let value = as_i32(raw);
46
47                GpsValue::Coordinate(f64::from(value) / 10000000.)
48            }
49            GpsUnit::Altitude => {
50                let altitude = if def.signed {
51                    as_i32(raw).into()
52                } else {
53                    raw.into()
54                };
55
56                GpsValue::Altitude(Length::new::<meter>(altitude))
57            }
58            GpsUnit::Velocity => {
59                assert!(!def.signed);
60                GpsValue::Velocity(units::new::velocity(raw))
61            }
62            GpsUnit::Heading => {
63                assert!(!def.signed);
64                GpsValue::Heading(f64::from(raw) / 10.)
65            }
66            GpsUnit::Unitless => GpsValue::new_unitless(raw, def.signed),
67        };
68
69        Some(value)
70    }
71}
72
73impl<'data, 'headers, 'parser> GpsFrame<'data, 'headers, 'parser> {
74    pub(crate) fn new(
75        headers: &'headers Headers<'data>,
76        raw: RawGpsFrame,
77        filter: &'parser AppliedFilter,
78    ) -> Self {
79        Self {
80            headers,
81            raw,
82            filter,
83        }
84    }
85
86    /// Returns the parsed time since power on.
87    pub fn time(&self) -> Time {
88        units::new::time(self.raw.time)
89    }
90
91    /// Returns the raw microsecond counter since power on.
92    ///
93    /// **Note:** This does not currently handle overflow of the transmitted
94    /// 32bit counter.
95    pub fn time_raw(&self) -> u64 {
96        self.raw.time
97    }
98}
99
100#[derive(Debug, Clone)]
101pub(crate) struct RawGpsFrame {
102    pub(crate) time: u64,
103    pub(crate) values: Vec<u32>,
104}
105
106#[derive(Debug, Clone, Copy, PartialEq)]
107pub enum GpsValue {
108    Coordinate(f64),
109    Altitude(Length),
110    Velocity(Velocity),
111    Heading(f64),
112    Unsigned(u32),
113    Signed(i32),
114}
115
116impl GpsValue {
117    const fn new_unitless(value: u32, signed: bool) -> Self {
118        if signed {
119            Self::Signed(as_i32(value))
120        } else {
121            Self::Unsigned(value)
122        }
123    }
124}
125
126impl From<GpsValue> for super::Value {
127    fn from(value: GpsValue) -> Self {
128        match value {
129            GpsValue::Coordinate(c) => Self::GpsCoordinate(c),
130            GpsValue::Altitude(a) => Self::Altitude(a),
131            GpsValue::Velocity(v) => Self::Velocity(v),
132            GpsValue::Heading(h) => Self::GpsHeading(h),
133            GpsValue::Unsigned(x) => Self::Unsigned(x),
134            GpsValue::Signed(x) => Self::Signed(x),
135        }
136    }
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
140pub enum GpsUnit {
141    Coordinate,
142    Altitude,
143    Velocity,
144    Heading,
145    Unitless,
146}
147
148impl From<GpsUnit> for Unit {
149    fn from(unit: GpsUnit) -> Self {
150        match unit {
151            GpsUnit::Coordinate => Self::GpsCoordinate,
152            GpsUnit::Altitude => Self::Altitude,
153            GpsUnit::Velocity => Self::Velocity,
154            GpsUnit::Heading => Self::GpsHeading,
155            GpsUnit::Unitless => Self::Unitless,
156        }
157    }
158}