1#![deny(unsafe_code)]
5#![deny(missing_docs)]
6#![cfg_attr(not(test), no_std)]
7
8use embedded_hal::blocking::delay::{DelayMs, DelayUs};
9use rppal::gpio::{IoPin, Mode};
10
11const TIMEOUT_US: u16 = 1_000;
13
14const RETRY_DELAY: u16 = 100;
16
17#[derive(Debug)]
19pub enum Error {
20 Timeout,
22 CrcMismatch,
24}
25
26pub struct Dht11 {
28 gpio: IoPin,
30}
31
32#[derive(Copy, Clone, Default, Debug)]
34pub struct Measurement {
35 pub temperature: i16,
37 pub humidity: u16,
39}
40
41impl Dht11 {
42 pub fn new(gpio: IoPin) -> Self {
44 Dht11 { gpio }
45 }
46
47 pub fn destroy(self) -> IoPin {
49 self.gpio
50 }
51
52 pub fn perform_measurement_with_retries<D>(
55 &mut self,
56 delay: &mut D,
57 retries: u16,
58 ) -> Result<Measurement, Error>
59 where
60 D: DelayUs<u16> + DelayMs<u16>,
61 {
62 let mut result = self.perform_measurement(delay);
63 for _ in 0..retries {
64 if result.is_ok() {
65 break;
66 }
67 delay.delay_ms(RETRY_DELAY);
68 result = self.perform_measurement(delay);
69 }
70 result
71 }
72
73 pub fn perform_measurement<D>(&mut self, delay: &mut D) -> Result<Measurement, Error>
75 where
76 D: DelayUs<u16> + DelayMs<u16>,
77 {
78 let mut data = [0u8; 5];
79
80 self.perform_handshake(delay)?;
82
83 for i in 0..40 {
85 data[i / 8] <<= 1;
86 if self.read_bit(delay)? {
87 data[i / 8] |= 1;
88 }
89 }
90
91 let crc = data[0]
96 .wrapping_add(data[1])
97 .wrapping_add(data[2])
98 .wrapping_add(data[3]);
99 if crc != data[4] {
100 return Err(Error::CrcMismatch);
101 }
102
103 let mut temp = i16::from(data[2] & 0x7f) * 10 + i16::from(data[3]);
105 if data[2] & 0x80 != 0 {
106 temp = -temp;
107 }
108
109 Ok(Measurement {
110 temperature: temp,
111 humidity: u16::from(data[0]) * 10 + u16::from(data[1]),
112 })
113 }
114
115 fn perform_handshake<D>(&mut self, delay: &mut D) -> Result<(), Error>
116 where
117 D: DelayUs<u16> + DelayMs<u16>,
118 {
119 self.gpio.set_mode(Mode::Output);
120 self.gpio.set_high();
122 delay.delay_ms(1);
123
124 self.gpio.set_low();
126 delay.delay_ms(20);
127
128 self.gpio.set_high();
130 delay.delay_us(40);
131
132 self.gpio.set_mode(Mode::Input);
133
134 self.read_bit(delay)?;
136
137 Ok(())
138 }
139
140 fn read_bit<D>(&mut self, delay: &mut D) -> Result<bool, Error>
141 where
142 D: DelayUs<u16> + DelayMs<u16>,
143 {
144 let low = self.wait_for_pulse(true, delay)?;
145 let high = self.wait_for_pulse(false, delay)?;
146 Ok(high > low)
147 }
148
149 fn wait_for_pulse<D>(&mut self, level: bool, delay: &mut D) -> Result<u32, Error>
150 where
151 D: DelayUs<u16> + DelayMs<u16>,
152 {
153 let mut count = 0;
154
155 while self.gpio.is_high() != level {
156 count += 1;
157 if count > TIMEOUT_US {
158 return Err(Error::Timeout);
159 }
160 delay.delay_us(1);
161 }
162
163 return Ok(u32::from(count));
164 }
165}