1#![deny(missing_docs)]
11#![no_std]
12
13use {
14 bitflags::bitflags,
15 crc_all::CrcAlgo,
16 embedded_hal_async::{delay::DelayNs, i2c::I2c},
17};
18
19const I2C_ADDRESS: u8 = 0x38;
20
21bitflags! {
22 struct StatusFlags: u8 {
23 const BUSY = (1 << 7);
24 const MODE = ((1 << 6) | (1 << 5));
25 const CRC = (1 << 4);
26 const CALIBRATION_ENABLE = (1 << 3);
27 const FIFO_ENABLE = (1 << 2);
28 const FIFO_FULL = (1 << 1);
29 const FIFO_EMPTY = (1 << 0);
30 }
31}
32
33#[derive(Debug, Copy, Clone)]
35pub enum Error<I2CERR> {
36 Uncalibrated,
38 Checksum,
40 I2c(I2CERR),
42}
43
44impl<E> core::convert::From<E> for Error<E> {
45 fn from(e: E) -> Self {
46 Error::I2c(e)
47 }
48}
49
50pub struct Humidity {
52 h: u32,
53}
54
55impl Humidity {
56 pub fn rh(&self) -> f32 {
58 100.0 * (self.h as f32) / ((1 << 20) as f32)
59 }
60
61 pub fn raw(&self) -> u32 {
63 self.h
64 }
65}
66
67pub struct Temperature {
69 t: u32,
70}
71
72impl Temperature {
73 pub fn celsius(&self) -> f32 {
75 (200.0 * (self.t as f32) / ((1 << 20) as f32)) - 50.0
76 }
77
78 pub fn raw(&self) -> u32 {
80 self.t
81 }
82}
83
84pub struct Aht20<I2C, D> {
86 i2c: I2C,
87 delay: D,
88}
89
90impl<I2C, D> Aht20<I2C, D>
91where
92 I2C: I2c,
93 D: DelayNs,
94{
95 pub async fn new(i2c: I2C, delay: D) -> Result<Self, Error<I2C::Error>> {
97 let mut dev = Self { i2c, delay };
98
99 dev.reset().await?;
100
101 dev.calibrate().await?;
102
103 Ok(dev)
104 }
105
106 async fn status(&mut self) -> Result<StatusFlags, I2C::Error> {
108 let buf = &mut [0u8; 1];
109 self.i2c.write_read(I2C_ADDRESS, &[0u8], buf).await?;
110
111 Ok(StatusFlags::from_bits_retain(buf[0]))
112 }
113
114 pub async fn calibrate(&mut self) -> Result<(), Error<I2C::Error>> {
116 self.i2c.write(I2C_ADDRESS, &[0xE1, 0x08, 0x00]).await?;
118
119 while self.status().await?.contains(StatusFlags::BUSY) {
121 self.delay.delay_ms(10).await;
122 }
123
124 if !self
126 .status()
127 .await?
128 .contains(StatusFlags::CALIBRATION_ENABLE)
129 {
130 return Err(Error::Uncalibrated);
131 }
132
133 Ok(())
134 }
135
136 pub async fn reset(&mut self) -> Result<(), I2C::Error> {
138 self.i2c.write(I2C_ADDRESS, &[0xBA]).await?;
140
141 self.delay.delay_ms(20).await;
143
144 Ok(())
145 }
146
147 pub async fn read(&mut self) -> Result<(Humidity, Temperature), Error<I2C::Error>> {
149 self.i2c.write(I2C_ADDRESS, &[0xAC, 0x33, 0x00]).await?;
151
152 while self.status().await?.contains(StatusFlags::BUSY) {
154 self.delay.delay_ms(10).await;
155 }
156
157 let buf = &mut [0u8; 7];
159 self.i2c.write_read(I2C_ADDRESS, &[0u8], buf).await?;
160
161 let crc = &mut 0u8;
163 let crc_hasher = CrcAlgo::<u8>::new(49, 8, 0xFF, 0x00, false);
164 crc_hasher.init_crc(crc);
165 if crc_hasher.update_crc(crc, &buf[..=5]) != buf[6] {
166 return Err(Error::Checksum);
167 };
168
169 let status = StatusFlags::from_bits_retain(buf[0]);
171 if !status.contains(StatusFlags::CALIBRATION_ENABLE) {
172 return Err(Error::Uncalibrated);
173 }
174
175 let hum = ((buf[1] as u32) << 12) | ((buf[2] as u32) << 4) | ((buf[3] as u32) >> 4);
177 let temp = (((buf[3] as u32) & 0x0f) << 16) | ((buf[4] as u32) << 8) | (buf[5] as u32);
178
179 Ok((Humidity { h: hum }, Temperature { t: temp }))
180 }
181}