Skip to main content

ph_qmi8658/data/
fixed.rs

1//! Fixed-point conversion helpers.
2
3use super::{AccelRaw, GyroRaw, Sample, TemperatureRaw};
4use super::scale::{accel_lsb_per_g, gyro_lsb_per_dps, temperature_lsb_per_celsius};
5use crate::config::common::{AccelRange, GyroRange};
6
7/// Fixed-point number type used for sensor conversions (I32F32).
8pub type Fixed = crate::fixed_crate::types::I32F32;
9
10/// Fixed-point accelerometer sample in g.
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub struct AccelFixed {
13    /// X-axis acceleration in g.
14    pub x: Fixed,
15    /// Y-axis acceleration in g.
16    pub y: Fixed,
17    /// Z-axis acceleration in g.
18    pub z: Fixed,
19}
20
21/// Fixed-point gyroscope sample in dps.
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub struct GyroFixed {
24    /// X-axis angular rate in dps.
25    pub x: Fixed,
26    /// Y-axis angular rate in dps.
27    pub y: Fixed,
28    /// Z-axis angular rate in dps.
29    pub z: Fixed,
30}
31
32/// Fixed-point temperature sample in deg C.
33#[derive(Clone, Copy, Debug, PartialEq, Eq)]
34pub struct TemperatureFixed {
35    /// Temperature in degrees Celsius.
36    pub celsius: Fixed,
37}
38
39/// Converts accelerometer raw counts to g.
40pub fn accel_to_g(raw: AccelRaw, range: AccelRange) -> AccelFixed {
41    let scale = Fixed::from_num(accel_lsb_per_g(range));
42    AccelFixed {
43        x: Fixed::from_num(raw.x) / scale,
44        y: Fixed::from_num(raw.y) / scale,
45        z: Fixed::from_num(raw.z) / scale,
46    }
47}
48
49/// Converts gyroscope raw counts to dps.
50pub fn gyro_to_dps(raw: GyroRaw, range: GyroRange) -> GyroFixed {
51    let scale = Fixed::from_num(gyro_lsb_per_dps(range));
52    GyroFixed {
53        x: Fixed::from_num(raw.x) / scale,
54        y: Fixed::from_num(raw.y) / scale,
55        z: Fixed::from_num(raw.z) / scale,
56    }
57}
58
59/// Converts temperature raw counts to degrees Celsius.
60///
61/// The datasheet specifies 1 LSB = 1/256 deg C.
62pub fn temperature_celsius(raw: TemperatureRaw) -> TemperatureFixed {
63    let scale = Fixed::from_num(temperature_lsb_per_celsius());
64    TemperatureFixed {
65        celsius: Fixed::from_num(raw.value) / scale,
66    }
67}
68
69/// Converts a timestamped accelerometer sample to g.
70pub fn accel_sample_to_g(sample: Sample<AccelRaw>, range: AccelRange) -> Sample<AccelFixed> {
71    Sample {
72        timestamp: sample.timestamp,
73        data: accel_to_g(sample.data, range),
74    }
75}
76
77/// Converts a timestamped gyroscope sample to dps.
78pub fn gyro_sample_to_dps(sample: Sample<GyroRaw>, range: GyroRange) -> Sample<GyroFixed> {
79    Sample {
80        timestamp: sample.timestamp,
81        data: gyro_to_dps(sample.data, range),
82    }
83}
84
85/// Converts a timestamped temperature sample to degrees Celsius.
86pub fn temperature_sample_celsius(sample: Sample<TemperatureRaw>) -> Sample<TemperatureFixed> {
87    Sample {
88        timestamp: sample.timestamp,
89        data: temperature_celsius(sample.data),
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96    use crate::config::common::{AccelRange, GyroRange};
97    use crate::data::Timestamp;
98
99    #[test]
100    fn accel_conversion_matches_scale() {
101        let raw = AccelRaw {
102            x: 16_384,
103            y: -16_384,
104            z: 0,
105        };
106        let fixed = accel_to_g(raw, AccelRange::G2);
107        assert_eq!(fixed.x, Fixed::from_num(1));
108        assert_eq!(fixed.y, Fixed::from_num(-1));
109        assert_eq!(fixed.z, Fixed::from_num(0));
110    }
111
112    #[test]
113    fn gyro_conversion_matches_scale() {
114        let raw = GyroRaw {
115            x: 2_048,
116            y: -2_048,
117            z: 0,
118        };
119        let fixed = gyro_to_dps(raw, GyroRange::Dps16);
120        assert_eq!(fixed.x, Fixed::from_num(1));
121        assert_eq!(fixed.y, Fixed::from_num(-1));
122        assert_eq!(fixed.z, Fixed::from_num(0));
123    }
124
125    #[test]
126    fn temperature_conversion_matches_scale() {
127        let raw = TemperatureRaw { value: 256 };
128        let fixed = temperature_celsius(raw);
129        assert_eq!(fixed.celsius, Fixed::from_num(1));
130    }
131
132    #[test]
133    fn sample_conversion_preserves_timestamp() {
134        let sample = Sample {
135            timestamp: Timestamp { ticks: 123 },
136            data: AccelRaw { x: 0, y: 0, z: 0 },
137        };
138        let fixed = accel_sample_to_g(sample, AccelRange::G8);
139        assert_eq!(fixed.timestamp.ticks, 123);
140    }
141}