1#![deny(missing_docs)]
12#![no_std]
13
14use embedded_hal_async::delay::DelayNs;
15use embedded_hal_async::i2c::I2c;
16
17const I2C_ADDRESS: u8 = 0x38;
18
19#[derive(Copy, Clone)]
20#[repr(u8)]
21enum Command {
22 Calibrate = 0b1110_0001,
23 GetRaw = 0b1010_1000,
24 GetCT = 0b1010_1100,
25 Reset = 0b1011_1010,
26}
27
28#[macro_use]
29extern crate bitflags;
30
31bitflags! {
32 struct StatusFlags: u8 {
33 const BUSY = (1 << 7);
34 const MODE = ((1 << 6) | (1 << 5));
35 const CRC = (1 << 4);
36 const CALIBRATION_ENABLE = (1 << 3);
37 const FIFO_ENABLE = (1 << 2);
38 const FIFO_FULL = (1 << 1);
39 const FIFO_EMPTY = (1 << 0);
40 }
41}
42
43#[derive(Debug, Copy, Clone)]
45pub enum Error<E> {
46 Uncalibrated(),
48 BusError(E),
50}
51
52impl<E> core::convert::From<E> for Error<E> {
53 fn from(e: E) -> Self {
54 Error::BusError(e)
55 }
56}
57
58pub struct AHT10<I2C, D> {
60 i2c: I2C,
61 delay: D,
62}
63
64pub struct Humidity {
66 h: u32,
67}
68impl Humidity {
69 pub fn rh(&self) -> f32 {
71 100.0 * (self.h as f32) / ((1 << 20) as f32)
72 }
73 pub fn raw(&self) -> u32 {
75 self.h
76 }
77}
78
79pub struct Temperature {
81 t: u32,
82}
83impl Temperature {
84 pub fn celsius(&self) -> f32 {
86 (200.0 * (self.t as f32) / ((1 << 20) as f32)) - 50.0
87 }
88 pub fn raw(&self) -> u32 {
90 self.t
91 }
92}
93
94impl<I2C, D> AHT10<I2C, D>
95where
96 I2C: I2c,
97 D: DelayNs,
98{
99 pub async fn new(i2c: I2C, delay: D) -> Result<Self, I2C::Error> {
101 let mut dev = AHT10 { i2c, delay };
102 dev.write_cmd(Command::GetRaw, 0).await?;
103 dev.delay.delay_ms(300).await;
104 dev.write_cmd(Command::Calibrate, 0x0800).await?;
109 dev.delay.delay_ms(300).await;
110 Ok(dev)
111 }
112
113 pub async fn reset(&mut self) -> Result<(), I2C::Error> {
115 self.write_cmd(Command::Reset, 0).await?;
116 self.delay.delay_ms(20).await;
117 Ok(())
118 }
119
120 pub async fn read(&mut self) -> Result<(Humidity, Temperature), Error<I2C::Error>> {
122 let buf: &mut [u8; 7] = &mut [0; 7];
123 self.i2c
127 .write_read(I2C_ADDRESS, &[Command::GetCT as u8, 0b11111111, 0], buf)
128 .await?;
129 let status = StatusFlags { bits: buf[0] };
130 if !status.contains(StatusFlags::CALIBRATION_ENABLE) {
131 return Err(Error::Uncalibrated());
132 }
133 let hum = ((buf[1] as u32) << 12) | ((buf[2] as u32) << 4) | ((buf[3] as u32) >> 4);
134 let temp = (((buf[3] as u32) & 0x0f) << 16) | ((buf[4] as u32) << 8) | (buf[5] as u32);
135 Ok((Humidity { h: hum }, Temperature { t: temp }))
136 }
137
138 async fn write_cmd(&mut self, cmd: Command, dat: u16) -> Result<(), I2C::Error> {
139 self.i2c
140 .write(
141 I2C_ADDRESS,
142 &[cmd as u8, (dat >> 8) as u8, (dat & 0xff) as u8],
143 )
144 .await
145 }
146}