stm_32/peripherals/
ms4525.rs1pub use embassy_stm32::mode::Async;
37pub use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
38pub use embassy_sync::signal::Signal;
39use veloxity_core::{errors, packets};
40
41use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
43use embassy_stm32::i2c::I2c;
44use embedded_hal_async::i2c::I2c as _;
45
46use crate::synch_at;
48use embassy_time::Duration;
49use embassy_time::Timer;
50
51pub static PITOT_SIGNAL: Signal<
54 CriticalSectionRawMutex,
55 Result<packets::PitotPacket, errors::SensorError>,
56> = Signal::<CriticalSectionRawMutex, Result<packets::PitotPacket, errors::SensorError>>::new();
57
58fn publish_pitot(result: Result<packets::PitotPacket, errors::SensorError>) {
59 #[cfg(feature = "runtime-diagnostics")]
60 crate::runtime_diagnostics::record_signal_publish(
61 crate::runtime_diagnostics::SensorKind::Pitot,
62 PITOT_SIGNAL.signaled(),
63 result.is_err(),
64 );
65 PITOT_SIGNAL.signal(result);
66}
67
68pub struct Ms4525Sensor {
69 pub dev: I2cDevice<
70 'static,
71 CriticalSectionRawMutex,
72 I2c<'static, Async, embassy_stm32::i2c::mode::Master>,
73 >,
74}
75
76impl Ms4525Sensor {
77 pub async fn run(&mut self) {
78 const ADDRESS: u8 = 0x28;
79 const NO_ERROR: u8 = 0x00;
80
81 let mut data = [0u8; 2];
83 if self.dev.read(ADDRESS, &mut data).await.is_err() {
84 publish_pitot(Err(errors::SensorError::GenericSensorError(
85 "MS4525 Pitot failed: reading data",
86 )));
87 return;
88 }
89
90 Timer::after(Duration::from_micros(2000)).await;
91
92 let mut data = [0u8; 2];
94 if self.dev.read(ADDRESS, &mut data).await.is_err() {
95 publish_pitot(Err(errors::SensorError::GenericSensorError(
96 "MS4525 Pitot failed: reading data",
97 )));
98 return;
99 }
100
101 let status = (data[0] >> 6) & 0x03;
102 if status != NO_ERROR {
103 publish_pitot(Err(errors::SensorError::GenericSensorError(
104 "MS4525 Pitot failed: bad status",
105 )));
106 return;
107 }
108
109 let sample_period_us = Duration::from_hz(100).as_micros();
110 let loop_period = Duration::from_hz(400);
111 const PMAX: f64 = 6894.76; let mut sum_pressure: u32 = 0;
113 let mut sum_temperature: u32 = 0;
114 let mut sum_count: u32 = 0;
115
116 loop {
117 let timestamp = synch_at(loop_period);
118 Timer::at(timestamp).await; let mut data = [0u8; 4];
121 if self.dev.read(ADDRESS, &mut data).await.is_err() {
122 publish_pitot(Err(errors::SensorError::GenericSensorError(
123 "MS4525 Pitot failed: reading data",
124 )));
125 continue;
126 }
127
128 let status = (data[0] >> 6) & 0x03;
129 if status == NO_ERROR {
130 let pressure_u32 = (u32::from(data[0]) & 0x3F) << 8 | u32::from(data[1]);
131 let temperature_u32 =
132 (0xFFE0 & ((u32::from(data[2]) << 8) | u32::from(data[3]))) >> 5;
133
134 sum_pressure = sum_pressure + pressure_u32;
135 sum_temperature = sum_temperature + temperature_u32;
136 sum_count = sum_count + 1;
137 }
138
139 let timestamp_us = timestamp.as_micros();
140
141 if timestamp_us % sample_period_us == 0 {
142 if sum_count > 0 {
143 let avg_pressure = ((f64::from(sum_pressure) / (sum_count as f64) - 1638.3f64)
144 / 6553.2f64
145 - 1.0f64)
146 * PMAX;
147 let avg_temperature: f64 =
148 ((200.0f64 * f64::from(sum_temperature) / (sum_count as f64)) / 2047f64)
149 - 50f64;
150
151 let header = packets::RosflightPacketHeader {
152 timestamp: timestamp_us,
153 status: status as u16,
154 };
155 let pitot_packet = packets::PitotPacket {
156 header,
157 differential_pressure: avg_pressure as f32,
158 temperature: avg_temperature as f32,
159 ..Default::default()
160 };
161 publish_pitot(Ok(pitot_packet)); } else {
163 publish_pitot(Err(errors::SensorError::GenericSensorError(
164 "MS4525 Pitot failed: no valid data",
165 )));
166 }
167 sum_count = 0u32;
170 sum_pressure = 0u32;
171 sum_temperature = 0u32;
172 }
173 }
174 }
175}
176
177#[embassy_executor::task]
178pub async fn task(mut ms4525: Ms4525Sensor) {
179 ms4525.run().await;
180}