1use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
37use embassy_stm32::exti::ExtiInput;
38use embassy_stm32::gpio::Output;
39use embassy_stm32::mode::Async;
40use embassy_stm32::spi;
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::spi::SpiDevice as _;
47
48use crate::synch_at;
49use veloxity_core::errors;
50use veloxity_core::packets;
51
52const SPI_READ: u8 = 0x80;
54const SPI_WRITE: u8 = 0x00;
55
56pub static BARO_SIGNAL: Signal<
57 CriticalSectionRawMutex,
58 Result<packets::BaroPacket, errors::SensorError>,
59> = Signal::<CriticalSectionRawMutex, Result<packets::BaroPacket, errors::SensorError>>::new();
60
61fn publish_baro(result: Result<packets::BaroPacket, errors::SensorError>) {
62 #[cfg(feature = "runtime-diagnostics")]
63 crate::runtime_diagnostics::record_signal_publish(
64 crate::runtime_diagnostics::SensorKind::Baro,
65 BARO_SIGNAL.signaled(),
66 result.is_err(),
67 );
68 BARO_SIGNAL.signal(result);
69}
70
71pub struct Dps310Sensor {
72 pub dev: SpiDevice<
73 'static,
74 CriticalSectionRawMutex,
75 spi::Spi<'static, Async, spi::mode::Master>,
76 Output<'static>,
77 >,
78 pub drdy: ExtiInput<'static, Async>,
79 pub three_wire: bool,
80}
81
82fn compliment(x: u32, bits: u32) -> f64 {
83 let mut x = x as i32;
84 if (x & (1i32 << (bits - 1))) != 0 {
85 x -= 1i32 << bits;
86 }
87 f64::from(x)
88}
89
90const MEAS_CFG_REG: u8 = 0x08;
91const ISR_REG: u8 = 0x0A;
92const DPS310_READ_P_CMD: u8 = 0x00;
93const DPS310_READ_T_CMD: u8 = 0x03;
94
95const K1: f64 = 524288.0;
96const K8: f64 = 7864320.0; const CELSIUS_TO_KELVIN: f64 = 273.15;
98
99impl Dps310Sensor {
100 async fn read_register(&mut self, reg_addr: u8) -> Result<u8, errors::SensorError> {
101 let tx = [reg_addr | SPI_READ, 0x00];
102 let mut rx = [0u8; 2];
103 self.dev.transfer(&mut rx, &tx).await.map_err(|e| match e {
104 _ => errors::SensorError::GenericSensorError("SPI failed: read_register"),
105 })?;
106 Ok(rx[1])
107 }
108
109 async fn write_register(&mut self, reg_addr: u8, value: u8) -> Result<(), errors::SensorError> {
110 let tx = [reg_addr | SPI_WRITE, value];
111 self.dev.write(&tx).await.map_err(|e| match e {
113 _ => errors::SensorError::GenericSensorError("SPI failed: write_register"),
114 })?;
115 Ok(())
116 }
117
118 async fn initialize_sensor(&mut self) -> Result<[f64; 9], errors::SensorError> {
119 const RESET_REG: u8 = 0x0C;
121 self.write_register(RESET_REG, 0x09).await?;
122 Timer::after_millis(52).await; const CFG_REG: u8 = 0x09;
136 let three_wire_mode: u8 = if self.three_wire { 0x01 } else { 0x00 };
137 self.write_register(CFG_REG, three_wire_mode | 0xB0).await?;
138
139 const PRODUCT_ID_REG: u8 = 0x0D;
142 const PRODUCT_ID: u8 = 0x10;
143 let id = self.read_register(PRODUCT_ID_REG).await?;
144 if id != PRODUCT_ID {
145 return Err(errors::SensorError::GenericSensorError("ID mismatch"));
150 }
151
152 const COEF_READY: u8 = 0x80;
155 let coef_rdy = self.read_register(MEAS_CFG_REG).await?;
156 if (coef_rdy & COEF_READY) == 0x00 {
157 return Err(errors::SensorError::GenericSensorError(
158 "Calibration coefficients not ready",
159 ));
160 }
161
162 let cal = self.read_calibration_coefficients().await?;
163 Ok(cal)
164 }
165
166 async fn read_calibration_coefficients(&mut self) -> Result<[f64; 9], errors::SensorError> {
167 const COEF_REG: u8 = 0x10;
168 let mut tx = [0u8; 19];
169 tx[0] = COEF_REG | SPI_READ;
170
171 let mut rx = [0u8; 19];
172 self.dev.transfer(&mut rx, &tx).await.map_err(|e| match e {
173 _ => {
174 errors::SensorError::GenericSensorError("SPI failed: read_calibration_coefficients")
175 }
176 })?;
177
178 let buf = rx.map(|x| x as u32);
180 let mut cal = [0f64; 9];
182 cal[0] = compliment((buf[1] << 4) | ((buf[2] >> 4) & 0x0F), 12); cal[1] = compliment(((buf[2] & 0x0F) << 8) | buf[3], 12); cal[2] = compliment((buf[4] << 12) | (buf[5] << 4) | ((buf[6] >> 4) & 0x0F), 20); cal[3] = compliment(((buf[6] & 0x0F) << 16) | (buf[7] << 8) | buf[8], 20); cal[6] = compliment((buf[9] << 8) | buf[10], 16); cal[7] = compliment((buf[11] << 8) | buf[12], 16); cal[4] = compliment((buf[13] << 8) | buf[14], 16); cal[8] = compliment((buf[15] << 8) | buf[16], 16); cal[5] = compliment((buf[17] << 8) | buf[18], 16); Ok(cal)
193 }
194
195 async fn pressure_config(&mut self) -> Result<(), errors::SensorError> {
196 const PRS_CFG_REG: u8 = 0x06;
198 self.write_register(PRS_CFG_REG, 0x03).await?; Ok(())
201 }
202
203 async fn temperature_config(&mut self) -> Result<(), errors::SensorError> {
204 const COEF_SRCE_REG: u8 = 0x28;
206 let temp_source = self.read_register(COEF_SRCE_REG).await? & 0x80;
207
208 const TMP_CFG_REG: u8 = 0x07;
210 self.write_register(TMP_CFG_REG, temp_source | 0x00).await?; Ok(())
213 }
214
215 async fn measurement_configuration(&mut self) -> Result<(), errors::SensorError> {
216 self.write_register(MEAS_CFG_REG, 0x00).await?;
225
226 Ok(())
227 }
228
229 async fn get_sensor_data(&mut self, cmd: u8) -> Result<i32, errors::SensorError> {
230 let mut rx = [0u8; 4];
231 self.dev
232 .transfer(&mut rx, &[cmd | SPI_READ, 0, 0, 0])
233 .await
234 .map_err(|e| match e {
235 _ => errors::SensorError::GenericSensorError("SPI failed: get_sensor_data"),
236 })?;
237
238 self.read_register(ISR_REG).await?;
240
241 let raw = (((rx[1] as u32) << 24 | (rx[2] as u32) << 16 | (rx[3] as u32) << 8) as i32) >> 8;
242
243 Ok(raw)
244 }
245
246 async fn get_pressure_data(&mut self) -> Result<(i32, u16), errors::SensorError> {
247 self.write_register(MEAS_CFG_REG, 0x01).await?;
249
250 let _drdy_result = with_timeout(
253 Duration::from_micros(14_000),
254 self.drdy.wait_for_rising_edge(),
255 )
256 .await
257 .is_ok();
258 Timer::after_micros(20).await; let status = (self.read_register(MEAS_CFG_REG).await? as u16) << 8;
262
263 let raw_p = self.get_sensor_data(DPS310_READ_P_CMD).await?;
265 Ok((raw_p, status))
266 }
267
268 async fn get_temperature_data(&mut self) -> Result<(i32, u16), errors::SensorError> {
269 self.write_register(MEAS_CFG_REG, 0x02).await?;
271
272 let _drdy_result = with_timeout(
275 Duration::from_micros(3_000),
276 self.drdy.wait_for_rising_edge(),
277 )
278 .await
279 .is_ok();
280
281 let status_low = self.read_register(MEAS_CFG_REG).await? as u16;
283
284 let raw_t = self.get_sensor_data(DPS310_READ_T_CMD).await?;
286 Ok((raw_t, status_low))
287 }
288
289 fn process_temperature_data(
290 &mut self,
291 raw_t: i32,
292 raw_t_previous: &mut i32,
293 cal: &[f64; 9],
294 ) -> (f64, f64) {
295 *raw_t_previous += (raw_t - *raw_t_previous) / 16; let raw_t_f64 = f64::from(*raw_t_previous) / K1;
297 let temperature = cal[0] * 0.5 + cal[1] * raw_t_f64 + CELSIUS_TO_KELVIN;
300
301 (raw_t_f64, temperature)
302 }
303
304 fn process_pressure_data(&mut self, raw_p: i32, raw_t_f64: f64, cal: &[f64; 9]) -> (f64, f64) {
305 let raw_p_f64 = f64::from(raw_p) / K8;
306 let pressure = cal[2]
307 + raw_p_f64 * (cal[3] + raw_p_f64 * (cal[4] + raw_p_f64 * cal[5]))
308 + raw_t_f64 * (cal[6] + raw_p_f64 * (cal[7] + raw_p_f64 * cal[8])); (raw_p_f64, pressure)
310 }
311
312 pub async fn run(&mut self) {
313 let mut cal = match self.initialize_sensor().await {
315 Ok(cal) => cal,
316 Err(e) => {
317 publish_baro(Err(e));
318 return;
319 }
320 };
321 if let Err(e) = self.pressure_config().await {
322 publish_baro(Err(e));
323 return;
324 }
325 if let Err(e) = self.temperature_config().await {
326 publish_baro(Err(e));
327 return;
328 }
329 if let Err(e) = self.measurement_configuration().await {
330 publish_baro(Err(e));
331 return;
332 }
333 let mut raw_t_previous = 0_i32;
336 let sample_period = Duration::from_hz(50);
337
338 loop {
339 let timestamp = synch_at(sample_period);
340 Timer::at(timestamp).await;
341
342 let (raw_p, status_high) = match self.get_pressure_data().await {
344 Ok(data) => data,
345 Err(e) => {
346 publish_baro(Err(e));
347 continue;
348 }
349 };
350 let (raw_t, status_low) = match self.get_temperature_data().await {
351 Ok(data) => data,
352 Err(e) => {
353 publish_baro(Err(e));
354 continue;
355 }
356 };
357
358 let status_combined = (status_high & 0xFF00) | (status_low & 0x00FF);
360
361 let (raw_t_f64, temperature) =
362 self.process_temperature_data(raw_t, &mut raw_t_previous, &mut cal);
363 let (_raw_p_f64, pressure) = self.process_pressure_data(raw_p, raw_t_f64, &mut cal);
364
365 if status_combined == 0xD0E0 {
366 let header = packets::RosflightPacketHeader {
367 timestamp: timestamp.as_micros(),
368 status: status_combined,
369 };
370 let baro_packet = packets::BaroPacket {
371 header,
372 pressure: pressure as f32,
373 temperature: temperature as f32,
374 ..Default::default()
375 };
376 publish_baro(Ok(baro_packet)); } else {
378 publish_baro(Err(errors::SensorError::GenericSensorError("Bad status")));
379 }
380 }
381 }
382}
383
384#[embassy_executor::task]
385pub async fn task(mut dps: Dps310Sensor) {
386 dps.run().await;
387}