Skip to main content

stm_32/peripherals/
dlhrl20g.rs

1// ******************************************************************************
2// * File     : platforms/stm_32/src/peripherals/dlhrl20g.rs
3// * Date     : June 28, 2026
4// ******************************************************************************
5// *
6// * Copyright (c) 2023, AeroVironment, Inc.
7// * All rights reserved.
8// *
9// * Redistribution and use in source and binary forms, with or without
10// * modification, are permitted provided that the following conditions are met:
11// *
12// * 1.Redistributions of source code must retain the above copyright notice, this
13// * list of conditions and the following disclaimer.
14// *
15// * 2.Redistributions in binary form must reproduce the above copyright notice,
16// * this list of conditions and the following disclaimer in the documentation
17// * and/or other materials provided with the distribution.
18// *
19// * 3.Neither the name of the copyright holder nor the names of its
20// * contributors may be used to endorse or promote products derived from
21// * this software without specific prior written permission.
22// *
23// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24// * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25// * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26// * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27// * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28// * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29// * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30// * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31// * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33// *
34// ******************************************************************************
35
36use crate::synch_at;
37use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
38use embassy_stm32::exti::ExtiInput;
39use embassy_stm32::i2c::I2c;
40use embassy_stm32::mode::Async;
41use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
42use embassy_sync::signal::Signal;
43use embassy_time::Duration;
44use embassy_time::Timer;
45use embassy_time::with_timeout;
46use embedded_hal_async::i2c::I2c as _;
47use veloxity_core::{errors, packets};
48
49pub static PITOT_SIGNAL: Signal<
50    CriticalSectionRawMutex,
51    Result<packets::PitotPacket, errors::SensorError>,
52> = Signal::<CriticalSectionRawMutex, Result<packets::PitotPacket, errors::SensorError>>::new();
53
54pub struct DlhrL20GSensor {
55    pub dev: I2cDevice<
56        'static,
57        CriticalSectionRawMutex,
58        I2c<'static, Async, embassy_stm32::i2c::mode::Master>,
59    >,
60    pub drdy: ExtiInput<'static, Async>,
61}
62
63impl DlhrL20GSensor {
64    pub async fn run(&mut self) {
65        const ADDRESS: u8 = 0x29;
66        const START: u8 = 0xAC;
67
68        let sample_period = Duration::from_hz(100);
69
70        loop {
71            let timestamp = synch_at(sample_period);
72            Timer::at(timestamp).await; // Wait for top of 100 Hz timer
73
74            let write_res = self.dev.write(ADDRESS, &[START]).await;
75            if let Err(_e) = write_res {
76                PITOT_SIGNAL.signal(Err(errors::SensorError::GenericSensorError(
77                    "Pitot failed: write_register",
78                )))
79            }
80
81            if let Ok(()) =
82                with_timeout(Duration::from_millis(100), self.drdy.wait_for_rising_edge()).await
83            {
84                let mut data = [0u8; 7];
85                if self.dev.read(ADDRESS, &mut data).await.is_err() {
86                    PITOT_SIGNAL.signal(Err(errors::SensorError::GenericSensorError(
87                        "Pitot failed: reading problem",
88                    )));
89                    continue;
90                }
91                let status = data[0] as u16;
92                let u32_pressure =
93                    u32::from(data[1]) << 16 | u32::from(data[2]) << 8 | u32::from(data[3]);
94                let u32_temperature =
95                    u32::from(data[4]) << 16 | u32::from(data[5]) << 8 | u32::from(data[6]);
96
97                let fs = 5000.0; // Pa, Full Scale pressure
98
99                let pressure = 1.25 * fs * (f64::from(u32_pressure) / 16777216.0 - 0.1); // Pa
100                let temperature = 125.0 * f64::from(u32_temperature) / 16777216.0 - 40.0; // C
101                {
102                    let header = packets::RosflightPacketHeader {
103                        timestamp: timestamp.as_micros(),
104                        status,
105                    };
106                    let pitot_packet = packets::PitotPacket {
107                        header,
108                        differential_pressure: pressure as f32,
109                        temperature: temperature as f32,
110                        ..Default::default()
111                    };
112                    PITOT_SIGNAL.signal(Ok(pitot_packet)); // make data available for other tasks.
113                }
114            }
115        }
116    }
117}
118
119#[embassy_executor::task]
120pub async fn task(mut dlhr: DlhrL20GSensor) {
121    dlhr.run().await;
122}