use crate::{
commands::Command,
error::Error,
responses::{sensor_data_from_response, serial_number_from_response, RESPONSE_LEN},
types::{Address, HeatingDuration, HeatingPower, Measurement, Precision, SensorData},
};
use core::marker::PhantomData;
use embedded_hal_async::{delay::DelayNs, i2c::I2c};
use sensirion_i2c::i2c_async;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug)]
pub struct Sht4xAsync<I, D> {
i2c: I,
address: Address,
_delay: PhantomData<D>,
}
impl<I, D> Sht4xAsync<I, D>
where
I: I2c,
D: DelayNs,
{
pub fn new(i2c: I) -> Self {
Self::new_with_address(i2c, Address::Address0x44)
}
pub fn new_with_address(i2c: I, address: Address) -> Self {
Self {
i2c,
address,
_delay: PhantomData,
}
}
pub fn destroy(self) -> I {
self.i2c
}
pub async fn heat_and_measure(
&mut self,
power: HeatingPower,
duration: HeatingDuration,
delay: &mut D,
) -> Result<Measurement, Error<I::Error>> {
let raw = self.heat_and_measure_raw(power, duration, delay).await?;
Ok(Measurement::from(raw))
}
pub async fn heat_and_measure_raw(
&mut self,
power: HeatingPower,
duration: HeatingDuration,
delay: &mut D,
) -> Result<SensorData, Error<I::Error>> {
let command = Command::from((power, duration));
self.write_command_and_delay_for_execution(command, delay)
.await?;
let response = self.read_response().await?;
let raw = sensor_data_from_response(response);
Ok(raw)
}
pub async fn measure(
&mut self,
precision: Precision,
delay: &mut D,
) -> Result<Measurement, Error<I::Error>> {
let raw = self.measure_raw(precision, delay).await?;
Ok(Measurement::from(raw))
}
pub async fn measure_raw(
&mut self,
precision: Precision,
delay: &mut D,
) -> Result<SensorData, Error<I::Error>> {
let command = Command::from(precision);
self.write_command_and_delay_for_execution(command, delay)
.await?;
let response = self.read_response().await?;
let raw = sensor_data_from_response(response);
Ok(raw)
}
pub async fn serial_number(&mut self, delay: &mut D) -> Result<u32, Error<I::Error>> {
self.write_command_and_delay_for_execution(Command::SerialNumber, delay)
.await?;
let response = self.read_response().await?;
Ok(serial_number_from_response(response))
}
pub async fn soft_reset(&mut self, delay: &mut D) -> Result<(), Error<I::Error>> {
self.write_command_and_delay_for_execution(Command::SoftReset, delay)
.await
}
async fn read_response(&mut self) -> Result<[u8; RESPONSE_LEN], Error<I::Error>> {
let mut response = [0; RESPONSE_LEN];
i2c_async::read_words_with_crc(&mut self.i2c, self.address.into(), &mut response).await?;
Ok(response)
}
async fn write_command_and_delay_for_execution(
&mut self,
command: Command,
delay: &mut D,
) -> Result<(), Error<I::Error>> {
let code = command.code();
i2c_async::write_command_u8(&mut self.i2c, self.address.into(), code)
.await
.map_err(Error::I2c)?;
delay.delay_ms(command.duration_ms()).await;
Ok(())
}
}