1use embedded_hal::delay::DelayNs; use embedded_hal::i2c::{I2c, SevenBitAddress}; use crate::sensor_reading::SensorReading;
7use crate::utils::{compute_crc8, convert_humidity, convert_temperature, extract_readings};
8
9#[derive(Debug)]
10pub enum DHT20Error<E> {
11 I2C(E),
12 CrcMismatch,
13 NotInitialized,
14}
15
16impl<E> From<E> for DHT20Error<E> {
17 fn from(err: E) -> Self {
18 DHT20Error::I2C(err)
19 }
20}
21
22#[repr(u8)] enum OpCode {
24 CheckStatus = 0x71,
25 TriggerMeasurement = 0xAC,
26 StatusReady = 0x80,
27}
28
29const I2C_ADDRESS: SevenBitAddress = 0x38; const RESET_REGISTERS: [u8; 3] = [0x1B, 0x1C, 0x1E];
31
32pub struct Dht20<I2C> {
33 i2c: I2C,
34 address: SevenBitAddress,
35 initialized: bool,
36}
37
38impl<I2C, E> Dht20<I2C>
39where
40 I2C: I2c<Error = E>,
41{
42 pub fn new(i2c: I2C) -> Self {
44 Self {
45 i2c, address: I2C_ADDRESS,
47 initialized: false,
48 }
49 }
50
51 pub fn init<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), DHT20Error<E>> {
53 delay.delay_ms(100); self.check_init(delay)
56 }
57
58 pub fn take_reading<D: DelayNs>(
61 &mut self,
62 delay: &mut D,
63 ) -> Result<SensorReading, DHT20Error<E>> {
64 if !self.initialized {
65 return Err(DHT20Error::NotInitialized);
66 }
67
68 self.trigger_measurement(delay)?; self.wait_for_ready(delay)?; let data = self.read_measurement()?;
73
74 let (raw_humidity, raw_temperature) = extract_readings(&data);
76
77 let humidity = convert_humidity(raw_humidity);
79 let temperature = convert_temperature(raw_temperature);
80
81 Ok(SensorReading::new(temperature, humidity))
83 }
84
85 pub fn read_raw<D: DelayNs>(&mut self, delay: &mut D) -> Result<[u8; 6], DHT20Error<E>> {
86 if !self.initialized {
87 return Err(DHT20Error::NotInitialized);
88 }
89
90 self.trigger_measurement(delay)?; self.wait_for_ready(delay)?; let data = self.read_measurement()?;
95
96 Ok(data)
97 }
98
99 fn check_init<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), DHT20Error<E>> {
101 let mut buffer = [0u8; 1]; self.i2c
105 .write_read(self.address, &[OpCode::CheckStatus as u8], &mut buffer)?;
106
107 let status = buffer[0];
108
109 if (status & 0x18) != 0x18 {
111 for reg in RESET_REGISTERS.iter() {
112 self.reset_register(delay, *reg)?;
113 }
114 }
115
116 delay.delay_ms(10);
118
119 self.initialized = true;
121 Ok(())
122 }
123
124 fn reset_register<D: DelayNs>(&mut self, delay: &mut D, reg: u8) -> Result<(), DHT20Error<E>> {
127 let mut buffer = [0u8; 3]; self.i2c.write(self.address, &[reg, 0x00, 0x00])?;
131
132 delay.delay_ms(5);
134
135 self.i2c.write_read(self.address, &[reg], &mut buffer)?;
137 delay.delay_ms(5);
138
139 self.i2c
142 .write(self.address, &[0xB0 | reg, buffer[1], buffer[2]])?;
143 delay.delay_ms(5);
144
145 Ok(())
146 }
147
148 fn trigger_measurement<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), DHT20Error<E>> {
150 let command = [OpCode::TriggerMeasurement as u8, 0x33, 0x00];
152 self.i2c.write(self.address, &command)?;
153
154 delay.delay_ms(80); Ok(())
157 }
158
159 fn wait_for_ready<D: DelayNs>(&mut self, delay: &mut D) -> Result<(), DHT20Error<E>> {
161 let mut buffer = [0u8; 1]; loop {
165 self.i2c
166 .write_read(self.address, &[OpCode::CheckStatus as u8], &mut buffer)?;
167 if buffer[0] & (OpCode::StatusReady as u8) == 0 {
170 return Ok(()); }
172 delay.delay_ms(0);
174 }
175 }
176
177 fn read_measurement(&mut self) -> Result<[u8; 6], DHT20Error<E>> {
180 let mut buffer = [0u8; 7]; self.i2c.read(self.address, &mut buffer)?;
184
185 let crc = buffer[6]; let crc_check = compute_crc8(&buffer[..6]);
189 if crc != crc_check {
190 return Err(DHT20Error::CrcMismatch);
191 }
192 Ok(buffer[..6].try_into().unwrap()) }
195}