1#![no_std]
57
58use embassy_rp::gpio::{Flex, Pin};
59use embassy_rp::Peripheral;
60use embedded_hal::delay::DelayNs;
61use num_traits::float::FloatCore;
62#[cfg(feature = "embedded_alloc")]
63extern crate alloc;
64#[cfg(feature = "embedded_alloc")]
65use alloc::borrow::ToOwned;
66#[cfg(feature = "embedded_alloc")]
67use alloc::string::{String, ToString};
68
69#[derive(Debug, Copy, Clone)]
70pub struct Reading<T, H> {
71 pub temp: T,
72 pub hum: H,
73}
74
75const WAIT_STEP: u32 = 5;
76const MAX_WAIT: u32 = 100;
77
78fn wait_for_state<F, D>(f: F, delay: &mut D) -> u32
79where
80 F: Fn() -> bool,
81 D: DelayNs,
82{
83 let mut t = 0;
84 loop {
85 if f() || t > MAX_WAIT {
86 return t;
87 }
88 t += WAIT_STEP;
89 delay.delay_us(WAIT_STEP);
90 }
91}
92
93#[cfg(feature = "embedded_alloc")]
94pub trait DhtValueString {
95 fn get_temp_str(&self) -> String;
96 fn get_hum_str(&self) -> String;
97}
98
99pub mod dht11 {
100 use super::*;
101
102 impl Reading<i8, u8> {
103 pub fn get_temp(&self) -> i8 {
104 self.temp
105 }
106 pub fn get_hum(&self) -> u8 {
107 self.hum
108 }
109 }
110 #[cfg(feature = "embedded_alloc")]
111 impl DhtValueString for Reading<i8, u8> {
112 fn get_temp_str(&self) -> String {
113 let temp = self.get_temp();
114 let temp_str = temp.to_string();
115 temp_str.to_owned()
116 }
117 fn get_hum_str(&self) -> String {
118 let hum = self.get_hum();
119 let hum_str = hum.to_string();
120 hum_str.to_owned()
121 }
122 }
123 pub struct DHT11<'a, D> {
124 pub pin: Flex<'a>,
125 pub delay: D,
126 }
127
128 impl<'a, D> DHT11<'a, D>
129 where
130 D: DelayNs,
131 {
132 pub fn new(pin: impl Peripheral<P = impl Pin> + 'a, delay: D) -> Self {
133 let pin = Flex::new(pin);
134 Self { pin, delay }
135 }
136
137 pub fn read(&mut self) -> Result<Reading<i8, u8>, &str> {
139 let data = self.read_raw()?;
140 let rh = data[0];
141 let temp_signed = data[2];
142 let temp = {
143 let (signed, magnitude) = convert_signed(temp_signed);
144 let temp_sign = if signed { -1 } else { 1 };
145 temp_sign * magnitude as i8
146 };
147
148 Ok(Reading {
149 temp: temp,
150 hum: rh,
151 })
152 }
153
154 fn read_raw(&mut self) -> Result<[u8; 4], &str> {
155 self.pin.set_as_output();
158 self.pin.set_low();
159 self.delay.delay_ms(18);
160 self.pin.set_high();
161 self.delay.delay_us(48);
162
163 self.pin.set_as_input();
165 let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
166 let _ = wait_for_state(|| self.pin.is_low(), &mut self.delay);
167
168 let mut buf = [0; 4];
170
171 for idx in 0..4 {
172 buf[idx] = self.read_byte();
173 }
174 let checksum = self.read_byte();
175 if checksum
176 != buf
177 .iter()
178 .fold(0_u8, |acc: u8, a: &u8| acc.wrapping_add(*a))
179 {
180 return Err("Checksum error");
181 }
182
183 Ok(buf)
184 }
185
186 fn read_byte(&mut self) -> u8 {
187 let mut buf = 0u8;
188 for idx in 0..8 {
189 let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
190 let t = wait_for_state(|| self.pin.is_low(), &mut self.delay);
191
192 if t > 35 {
193 buf |= 1 << 7 - idx;
194 }
195 }
196 buf
197 }
198 }
199
200 fn convert_signed(signed: u8) -> (bool, u8) {
201 let sign = signed & 0x80 != 0;
202 let magnitude = signed & 0x7F;
203 (sign, magnitude)
204 }
205}
206
207pub mod dht22 {
208 use super::*;
209
210 impl Reading<f32, f32> {
211 pub fn get_temp(&self) -> f32 {
212 self.temp
213 }
214
215 pub fn get_hum(&self) -> f32 {
216 self.hum
217 }
218 }
219
220 #[cfg(feature = "embedded_alloc")]
221 impl DhtValueString for Reading<f32, f32> {
222 fn get_temp_str(&self) -> String {
223 let temp = self.get_temp();
224 let temp_str = temp.to_string();
225 temp_str.to_owned()
226 }
227 fn get_hum_str(&self) -> String {
228 let hum = self.get_hum();
229 let hum_str = hum.to_string();
230 hum_str.to_owned()
231 }
232 }
233
234 trait F32Utils {
237 fn round_fixed(self, n: u32) -> f32;
238 }
239
240 impl F32Utils for f32 {
241 fn round_fixed(self, n: u32) -> f32 {
242 if n <= 0 {
243 return self.round();
244 }
245 let i = 10_usize.pow(n) as f32;
246 let x = self * i;
247 if self > 0_f32 {
248 let m = x.round() as u32;
250 m as f32 / i
251 } else {
252 let mr = x.trunc(); let mf = x.fract(); if mf.abs() >= 0.5 {
256 return (mr + 1_f32) / i;
258 }
259 mr / i
261 }
262 }
263 }
264
265 pub struct DHT22<'a, D> {
266 pub pin: Flex<'a>,
267 pub delay: D,
268 }
269
270 impl<'a, D> DHT22<'a, D>
271 where
272 D: DelayNs,
273 {
274 pub fn new(pin: impl Peripheral<P = impl Pin> + 'a, delay: D) -> Self {
275 let pin = Flex::new(pin);
276 Self { pin, delay }
277 }
278
279 pub fn read(&mut self) -> Result<Reading<f32, f32>, &str> {
280 let data = self.read_raw()?;
281
282 let raw_temp: u16 = (data[2] as u16) << 8 | data[3] as u16;
283
284 let temp: f32 = match raw_temp & 0x8000 == 1 {
290 true => -0.1 * (raw_temp & 0x7fff) as f32,
291 false => 0.1 * raw_temp as f32,
292 };
293
294 let raw_hum: u16 = (data[0] as u16) << 8 | data[1] as u16;
295 let hum: f32 = 0.1 * raw_hum as f32;
296
297 let temp = temp.round_fixed(2);
298 let hum = hum.round_fixed(2);
299
300 Ok(Reading { temp, hum })
301 }
302
303 fn read_raw(&mut self) -> Result<[u8; 4], &str> {
304 self.pin.set_as_output();
306 self.pin.set_low();
307 self.delay.delay_us(1000);
308
309 self.pin.set_as_input();
311 let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
312 let _ = wait_for_state(|| self.pin.is_low(), &mut self.delay);
313
314 let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
316 let _ = wait_for_state(|| self.pin.is_low(), &mut self.delay);
317
318 let mut buf = [42u8; 4];
320
321 for idx in 0..4 {
322 buf[idx] = self.read_byte();
323 }
324 let checksum = self.read_byte();
325 if checksum != buf.iter().fold(0, |acc: u8, a: &u8| acc.wrapping_add(*a)) {
326 return Err("Checksum error");
327 }
328
329 Ok(buf)
330 }
331
332 fn read_byte(&mut self) -> u8 {
333 let mut buf = 0u8;
334 for idx in 0..8 {
335 let _ = wait_for_state(|| self.pin.is_high(), &mut self.delay);
336 let t = wait_for_state(|| self.pin.is_low(), &mut self.delay);
337
338 if t > 35 {
339 buf |= 1 << 7 - idx;
340 }
341 }
342 buf
343 }
344 }
345}