#![no_std]
use embedded_hal::digital::{InputPin, OutputPin};
use embedded_hal_async::delay::DelayNs;
pub const PICO2_BIT_THRESHOLD: u32 = 40;
pub const PICO_BIT_THRESHOLD: u32 = 33;
#[derive(Clone, Copy, Debug)]
pub struct EnvData {
pub temp: f32,
pub hum: f32,
}
#[derive(Debug, PartialEq)]
pub enum Am2302Error<E> {
Timeout,
ChecksumMismatch,
Gpio(E),
}
pub async fn am2302_read<P, E>(
pin: &mut P,
delay: &mut impl DelayNs,
bit_threshold: u32,
) -> Result<EnvData, Am2302Error<E>>
where
P: InputPin<Error = E> + OutputPin<Error = E>,
{
pin.set_low().map_err(Am2302Error::Gpio)?;
delay.delay_ms(20).await;
pin.set_high().map_err(Am2302Error::Gpio)?;
let mut timeout = 0u32;
while pin.is_high().map_err(Am2302Error::Gpio)? {
timeout += 1;
if timeout > 10000 { return Err(Am2302Error::Timeout); }
}
timeout = 0;
while pin.is_low().map_err(Am2302Error::Gpio)? {
timeout += 1;
if timeout > 10000 { return Err(Am2302Error::Timeout); }
}
timeout = 0;
while pin.is_high().map_err(Am2302Error::Gpio)? {
timeout += 1;
if timeout > 10000 { return Err(Am2302Error::Timeout); }
}
let mut data = [0u8; 5];
for i in 0..40usize {
timeout = 0;
while pin.is_low().map_err(Am2302Error::Gpio)? {
timeout += 1;
if timeout > 10000 { return Err(Am2302Error::Timeout); }
}
let mut high_count = 0u32;
while pin.is_high().map_err(Am2302Error::Gpio)? {
high_count += 1;
if high_count > bit_threshold * 5 { break; }
}
if high_count > bit_threshold {
data[i / 8] |= 1 << (7 - (i % 8));
}
}
let checksum = data[0]
.wrapping_add(data[1])
.wrapping_add(data[2])
.wrapping_add(data[3]);
if data[4] != checksum {
return Err(Am2302Error::ChecksumMismatch);
}
let hum = (((data[0] as u16) << 8) | data[1] as u16) as f32 / 10.0;
let mut temp = ((((data[2] & 0x7F) as u16) << 8) | data[3] as u16) as f32 / 10.0;
if data[2] & 0x80 != 0 {
temp = -temp;
}
Ok(EnvData { temp, hum })
}