use embedded_hal::{
delay::DelayNs,
digital::{ErrorType, InputPin, OutputPin, PinState},
};
use crate::SensorError;
pub struct Dht<P: InputPin + OutputPin, D: DelayNs> {
pub pin: P,
pub delay: D,
}
impl<P: InputPin + OutputPin, D: DelayNs> Dht<P, D> {
pub fn new(pin: P, delay: D) -> Self {
Self { pin, delay }
}
pub fn read_byte(&mut self) -> Result<u8, SensorError> {
let mut byte: u8 = 0;
for n in 0..8 {
let _ = self.wait_until_state(PinState::High);
self.delay.delay_us(30);
let is_bit_1 = self.pin.is_high();
if is_bit_1.unwrap() {
let bit_mask = 1 << (7 - (n % 8));
byte |= bit_mask;
let _ = self.wait_until_state(PinState::Low);
}
}
Ok(byte)
}
pub fn wait_until_state(&mut self, state: PinState) -> Result<(), <P as ErrorType>::Error> {
while !match state {
PinState::Low => self.pin.is_low(),
PinState::High => self.pin.is_high(),
}? {
self.delay.delay_us(1);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use embedded_hal_mock::eh1::digital::{Mock, State, Transaction as PinTransaction};
use embedded_hal_mock::eh1::delay::NoopDelay as MockNoop;
#[test]
fn test_read_byte() {
let expectations = [
PinTransaction::get(State::High),
PinTransaction::get(State::Low),
PinTransaction::get(State::High),
PinTransaction::get(State::High),
PinTransaction::get(State::Low),
PinTransaction::get(State::High),
PinTransaction::get(State::Low),
PinTransaction::get(State::High),
PinTransaction::get(State::High),
PinTransaction::get(State::Low),
PinTransaction::get(State::High),
PinTransaction::get(State::Low),
PinTransaction::get(State::High),
PinTransaction::get(State::High),
PinTransaction::get(State::Low),
PinTransaction::get(State::High),
PinTransaction::get(State::High),
PinTransaction::get(State::Low),
PinTransaction::get(State::High),
PinTransaction::get(State::High),
PinTransaction::get(State::Low),
];
let mock_pin = Mock::new(&expectations);
let mock_delay = MockNoop::new();
let mut dht = Dht::new(mock_pin, mock_delay);
let result = dht.read_byte().unwrap();
assert_eq!(result, 0b01010111);
dht.pin.done();
}
#[test]
fn test_wait_until_state() {
let expectations = [
PinTransaction::get(State::Low),
PinTransaction::get(State::Low),
PinTransaction::get(State::High),
];
let mock_pin = Mock::new(&expectations);
let mock_delay = MockNoop::new();
let mut dht = Dht::new(mock_pin, mock_delay);
let result = dht.wait_until_state(PinState::High);
assert!(result.is_ok());
dht.pin.done();
}
}