1use embedded_hal::delay::DelayNs;
2use embedded_hal::digital::{InputPin, OutputPin};
3
4const TIMEOUT_US: u8 = 100;
5
6#[derive(Debug)]
7pub enum DhtError<E> {
8 PinError(E),
9 ChecksumMismatch,
10 Timeout,
11}
12
13impl<E> From<E> for DhtError<E> {
14 fn from(error: E) -> DhtError<E> {
15 DhtError::PinError(error)
16 }
17}
18
19fn read_bit<P: InputPin>(
20 delay: &mut impl DelayNs,
21 pin: &mut P,
22) -> Result<bool, DhtError<P::Error>> {
23 wait_until_timeout(delay, || pin.is_high())?;
24 delay.delay_us(35);
25 let high = pin.is_high()?;
26 wait_until_timeout(delay, || pin.is_low())?;
27 Ok(high)
28}
29
30fn read_byte<P: InputPin>(delay: &mut impl DelayNs, pin: &mut P) -> Result<u8, DhtError<P::Error>> {
31 let mut byte: u8 = 0;
32 for i in 0..8 {
33 let bit_mask = 1 << (7 - i);
34 if read_bit(delay, pin)? {
35 byte |= bit_mask;
36 }
37 }
38 Ok(byte)
39}
40
41pub fn read_raw<P: OutputPin + InputPin>(
42 delay: &mut impl DelayNs,
43 pin: &mut P,
44) -> Result<[u8; 4], DhtError<P::Error>> {
45 pin.set_high().ok();
46 delay.delay_us(48);
47
48 wait_until_timeout(delay, || pin.is_high())?;
49 wait_until_timeout(delay, || pin.is_low())?;
50
51 let mut data = [0; 4];
52 for b in data.iter_mut() {
53 *b = read_byte(delay, pin)?;
54 }
55 let checksum = read_byte(delay, pin)?;
56 if data.iter().fold(0u8, |sum, v| sum.wrapping_add(*v)) != checksum {
57 Err(DhtError::ChecksumMismatch)
58 } else {
59 Ok(data)
60 }
61}
62
63fn wait_until_timeout<E, F>(delay: &mut impl DelayNs, mut func: F) -> Result<(), DhtError<E>>
65where
66 F: FnMut() -> Result<bool, E>,
67{
68 for _ in 0..TIMEOUT_US {
69 if func()? {
70 return Ok(());
71 }
72 delay.delay_us(1);
73 }
74 Err(DhtError::Timeout)
75}