use crate::error::Error;
#[cfg(not(feature = "async"))]
use embedded_hal::{delay::DelayNs, i2c::I2c};
#[cfg(feature = "async")]
use embedded_hal_async::{delay::DelayNs, i2c::I2c};
use crate::types::Reading;
const ADDRESS: u8 = 0x12;
pub(crate) const RESPONSE_LENGTH: usize = 32;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug)]
pub struct Pmsa003i<I2C> {
i2c: I2C,
address: u8,
}
impl<I2C: I2c> Pmsa003i<I2C> {
pub fn new(i2c: I2C) -> Self {
Pmsa003i { i2c, address: 0x12 }
}
pub fn destroy(self) -> I2C {
self.i2c
}
#[cfg(any(not(feature = "async"), doc))]
pub fn read(&mut self) -> Result<Reading, Error<I2C::Error>> {
let result = self.read_raw()?;
Ok(Reading::from(result))
}
#[cfg(any(feature = "async", doc))]
pub async fn read(&mut self) -> Result<Reading, Error<I2C::Error>> {
let result = self.read_raw().await?;
Ok(Reading::from(result))
}
#[cfg(any(not(feature = "async"), doc))]
fn read_raw(&mut self) -> Result<[u8; RESPONSE_LENGTH], Error<I2C::Error>> {
let mut response = [0; RESPONSE_LENGTH];
self.i2c
.read(self.address, &mut response)
.map_err(Error::I2C)?;
self.check_data_integrity(response)?;
Ok(response)
}
#[cfg(feature = "async")]
async fn read_raw(&mut self) -> Result<[u8; RESPONSE_LENGTH], Error<I2C::Error>> {
let mut response = [0; RESPONSE_LENGTH];
self.i2c
.read(self.address, &mut response)
.await
.map_err(Error::I2C)?;
if !self.is_start_of_frame(response) {
return Err(Error::BadMagic);
}
self.check_data_integrity(response)?;
Ok(response)
}
fn is_start_of_frame(&self, data: [u8; RESPONSE_LENGTH]) -> bool {
data.get(0).unwrap() == &0x42 && data.get(1).unwrap() == &0x4d
}
fn check_data_integrity(&self, data: [u8; RESPONSE_LENGTH]) -> Result<(), Error<I2C::Error>> {
let sum = data[0..RESPONSE_LENGTH - 2]
.iter()
.fold(0u16, |accum, next| accum + *next as u16);
let expected_sum =
u16::from_be_bytes([data[RESPONSE_LENGTH - 2], data[RESPONSE_LENGTH - 1]]);
if sum == expected_sum {
return Ok(());
}
Err(Error::BadChecksum)
}
}