#![allow(unused_imports)]
use dev_csr::dev_csr;
use embedded_hal::spi::ErrorType;
use embedded_hal_async::spi::SpiBus;
use serde::{Deserialize, Serialize};
use spi_handle::SpiHandle;
use uunit::{Celsius, Pascals};
use crate::compensation::{Compensator, RawTrimData};
dev_csr! {
dev Bmp3 {
regs {
0x00 CHIP_ID r chip_id,
0x02 ERR_REG r {
0 fatal_err,
1 cmd_err,
2 conf_err
},
0x03 STATUS r {
4 cmd_rdy,
5 drdy_press,
6 drdy_temp
},
0x04 DATA_0 r raw_pressure[0..7],
0x05 DATA_1 r raw_pressure[8..15],
0x06 DATA_2 r raw_pressure[16..23],
0x07 DATA_3 r raw_temperature[0..7],
0x08 DATA_4 r raw_temperature[8..15],
0x09 DATA_5 r raw_temperature[16..23],
0x0C SENSORTIME_0 r raw_sensor_time[0..7],
0x0D SENSORTIME_1 r raw_sensor_time[8..15],
0x0E SENSORTIME_2 r raw_sensor_time[16..23],
0x10 EVENT r {
0 por_detected
},
0x11 INT_STATUS r {
0 fwm_int,
1 ffull_int,
2 drdy
},
0x12 FIFO_LENGTH_0 r fifo_length[0..7],
0x13 FIFO_LENGTH_1 r {
0 fifo_length[8]
},
0x14 FIFO_DATA r,
0x15 FIFO_WTM_0 rw fifo_water_mark[0..7],
0x16 FIFO_WTM_1 rw {
0 fifo_water_mark[8]
},
0x17 FIFO_CONFIG_1 rw {
0 fifo_mode,
1 fifo_stop_on_full,
2 fifo_time_en,
3 fifo_press_en,
4 fifo_temp_en
},
0x18 FIFO_CONFIG_2 rw {
0..2 fifo_subsampling,
3..4 data_select
},
0x19 INT_CT_RL rw {
0 int_od,
1 int_level,
2 int_latch,
3 fwtm_en,
4 ffull_en,
6 drdy_en
},
0x1A IF_CONF rw {
0 spi3,
1 i2c_wdt_en,
2 i2c_wdt_sel
},
0x1B PWR_CTRL rw {
0 press_en,
1 temp_en,
4..5 mode,
},
0x1C OSR rw {
0..2 osr_p,
3..5 osr_t
},
0x1D ODR rw {
0..4 odr_sel
},
0x1F CONFIG rw {
1..3 iir_filter
},
0x31 CALIB_DATA r,
0x7E CMD rw cmd
}
}
}
pub struct Bmp3Io<S: SpiHandle> {
spi: S
}
#[allow(unused_macros)]
impl <S: SpiHandle> Bmp3Io<S> {
pub async fn read_raw_trim_data(&mut self) -> Result<RawTrimData, <S::Bus as ErrorType>::Error> {
let mut data = [0u8; 21];
self.read_contiguous_regs(RegCalibData, &mut data).await?;
macro_rules! bytes {
($b1:expr, $b2:expr) => {
((data[$b1] as u16) << 8) | (data[$b2] as u16)
};
}
#[allow(unused_mut)]
let mut data: RawTrimData = unsafe {
core::mem::transmute(data)
};
#[cfg(target_endian = "big")]
data.swap_bytes();
Ok(data)
}
pub async fn read_raw_data(&mut self) -> Result<Bmp3RawData, <S::Bus as ErrorType>::Error> {
let mut data = [0u8; 6];
self.read_contiguous_regs(RegData0, &mut data).await?;
let raw_pressure = (data[0] as u32) + ((data[1] as u32) << 8) + ((data[2] as u32) << 16);
let raw_temperature = (data[3] as u32) + ((data[4] as u32) << 8) + ((data[5] as u32) << 16);
Ok(Bmp3RawData {
raw_pressure: raw_pressure as u64,
raw_temperature: raw_temperature as i64,
})
}
}
impl <S: SpiHandle> ReadBmp3 for Bmp3Io<S> {
type Error = <S::Bus as ErrorType>::Error;
async fn read_contiguous_regs(
&mut self,
addr: impl ReadableAddr,
out: &mut [u8]
) -> Result<(), Self::Error> {
let mut bus = self.spi.select().await;
let addr = addr.as_addr() | 0b1000_0000;
let dummy = 0;
bus.write(&[addr, dummy]).await?;
bus.transfer_in_place(out).await?;
Ok(())
}
}
impl <S: SpiHandle> WriteBmp3 for Bmp3Io<S> {
type Error = <S::Bus as ErrorType>::Error;
async fn write_contiguous_regs(
&mut self,
addr: impl WritableAddr,
values: &[u8]
) -> Result<(), Self::Error> {
let mut bus = self.spi.select().await;
bus.write(&[addr.as_addr()]).await?;
bus.write(values).await?;
Ok(())
}
}
pub struct Bmp3RawData {
pub raw_pressure: u64,
pub raw_temperature: i64,
}
#[repr(C)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Bmp3Readout {
pub pressure: Pascals<f64>,
pub temperature: Celsius<f64>
}
pub struct Bmp3<S: SpiHandle> {
io: Bmp3Io<S>,
compensator: Compensator
}
impl <S: SpiHandle> Bmp3<S> {
pub async fn new(spi: S) -> Result<Self, <S::Bus as ErrorType>::Error> {
let mut io = Bmp3Io {
spi
};
Ok(Self {
compensator: Compensator::from_raw(&io.read_raw_trim_data().await?),
io,
})
}
pub fn compensator(&self) -> &Compensator {
&self.compensator
}
pub async fn read(&mut self) -> Result<Bmp3Readout, <S::Bus as ErrorType>::Error> {
self.io().write_reg(RegPwrCtrl, 0b0011_0011).await?;
let Bmp3RawData { raw_pressure, raw_temperature } = self.io.read_raw_data().await?;
let temperature = self.compensator.temperature(raw_temperature);
let pressure = self.compensator.pressure(raw_pressure, temperature);
Ok(Bmp3Readout {
temperature,
pressure
})
}
pub fn io(&mut self) -> &mut Bmp3Io<S> {
&mut self.io
}
}
#[repr(u8)]
#[allow(non_camel_case_types)]
pub enum Command {
nop = 0x00,
extmode_en_middle = 0x34,
fifo_flush = 0xB0,
softreset = 0xB6,
}