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