1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![deny(missing_docs)]
4pub mod commands;
21mod crc;
22mod error;
23mod types;
24
25pub use error::Error;
26pub use types::{HeaterDuration, HeaterPower, Measurement, Precision};
27
28pub const DEFAULT_ADDRESS: u8 = 0x44;
30
31const MEASUREMENT_LEN: usize = 6;
33const SERIAL_LEN: usize = 6;
35
36pub struct Sht4x<I2C, D> {
43 i2c: I2C,
44 delay: D,
45 address: u8,
46}
47
48impl<I2C, D> Sht4x<I2C, D> {
49 pub fn new(i2c: I2C, delay: D, address: u8) -> Self {
54 Self {
55 i2c,
56 delay,
57 address,
58 }
59 }
60
61 pub fn release(self) -> (I2C, D) {
63 (self.i2c, self.delay)
64 }
65}
66
67fn decode_measurement<E>(buf: &[u8; MEASUREMENT_LEN]) -> Result<Measurement, Error<E>> {
69 let t = [buf[0], buf[1], buf[2]];
70 let h = [buf[3], buf[4], buf[5]];
71 if !crc::verify_word(&t) || !crc::verify_word(&h) {
72 return Err(Error::Crc);
73 }
74 let raw_t = u16::from_be_bytes([t[0], t[1]]);
75 let raw_h = u16::from_be_bytes([h[0], h[1]]);
76 Ok(Measurement::from_raw(raw_t, raw_h))
77}
78
79fn decode_serial<E>(buf: &[u8; SERIAL_LEN]) -> Result<u32, Error<E>> {
81 let w0 = [buf[0], buf[1], buf[2]];
82 let w1 = [buf[3], buf[4], buf[5]];
83 if !crc::verify_word(&w0) || !crc::verify_word(&w1) {
84 return Err(Error::Crc);
85 }
86 let hi = u16::from_be_bytes([w0[0], w0[1]]);
87 let lo = u16::from_be_bytes([w1[0], w1[1]]);
88 Ok(((hi as u32) << 16) | lo as u32)
89}
90
91#[cfg(feature = "blocking")]
92mod blocking_impl {
93 use super::*;
94 use embedded_hal::delay::DelayNs;
95 use embedded_hal::i2c::I2c;
96
97 impl<I2C, D> Sht4x<I2C, D>
98 where
99 I2C: I2c,
100 D: DelayNs,
101 {
102 pub fn measure(&mut self, precision: Precision) -> Result<Measurement, Error<I2C::Error>> {
104 self.i2c
105 .write(self.address, &[precision.command()])
106 .map_err(Error::I2c)?;
107 self.delay.delay_us(precision.duration_us());
108 let mut buf = [0u8; MEASUREMENT_LEN];
109 self.i2c
110 .read(self.address, &mut buf)
111 .map_err(Error::I2c)?;
112 decode_measurement(&buf)
113 }
114
115 pub fn measure_with_heater(
118 &mut self,
119 power: HeaterPower,
120 duration: HeaterDuration,
121 ) -> Result<Measurement, Error<I2C::Error>> {
122 let cmd = types::heater_command(power, duration);
123 self.i2c.write(self.address, &[cmd]).map_err(Error::I2c)?;
124 self.delay.delay_us(duration.duration_us());
125 let mut buf = [0u8; MEASUREMENT_LEN];
126 self.i2c
127 .read(self.address, &mut buf)
128 .map_err(Error::I2c)?;
129 decode_measurement(&buf)
130 }
131
132 pub fn read_serial_number(&mut self) -> Result<u32, Error<I2C::Error>> {
134 self.i2c
135 .write(self.address, &[commands::READ_SERIAL])
136 .map_err(Error::I2c)?;
137 self.delay.delay_us(commands::duration_us::SERIAL);
138 let mut buf = [0u8; SERIAL_LEN];
139 self.i2c
140 .read(self.address, &mut buf)
141 .map_err(Error::I2c)?;
142 decode_serial(&buf)
143 }
144
145 pub fn soft_reset(&mut self) -> Result<(), Error<I2C::Error>> {
147 self.i2c
148 .write(self.address, &[commands::SOFT_RESET])
149 .map_err(Error::I2c)?;
150 self.delay.delay_us(commands::duration_us::SOFT_RESET);
151 Ok(())
152 }
153 }
154}
155
156#[cfg(feature = "async")]
157#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
158mod async_impl {
159 use super::*;
160 use embedded_hal_async::delay::DelayNs;
161 use embedded_hal_async::i2c::I2c;
162
163 impl<I2C, D> Sht4x<I2C, D>
164 where
165 I2C: I2c,
166 D: DelayNs,
167 {
168 pub async fn measure_async(
170 &mut self,
171 precision: Precision,
172 ) -> Result<Measurement, Error<I2C::Error>> {
173 self.i2c
174 .write(self.address, &[precision.command()])
175 .await
176 .map_err(Error::I2c)?;
177 self.delay.delay_us(precision.duration_us()).await;
178 let mut buf = [0u8; MEASUREMENT_LEN];
179 self.i2c
180 .read(self.address, &mut buf)
181 .await
182 .map_err(Error::I2c)?;
183 decode_measurement(&buf)
184 }
185
186 pub async fn measure_with_heater_async(
188 &mut self,
189 power: HeaterPower,
190 duration: HeaterDuration,
191 ) -> Result<Measurement, Error<I2C::Error>> {
192 let cmd = types::heater_command(power, duration);
193 self.i2c
194 .write(self.address, &[cmd])
195 .await
196 .map_err(Error::I2c)?;
197 self.delay.delay_us(duration.duration_us()).await;
198 let mut buf = [0u8; MEASUREMENT_LEN];
199 self.i2c
200 .read(self.address, &mut buf)
201 .await
202 .map_err(Error::I2c)?;
203 decode_measurement(&buf)
204 }
205
206 pub async fn read_serial_number_async(&mut self) -> Result<u32, Error<I2C::Error>> {
208 self.i2c
209 .write(self.address, &[commands::READ_SERIAL])
210 .await
211 .map_err(Error::I2c)?;
212 self.delay.delay_us(commands::duration_us::SERIAL).await;
213 let mut buf = [0u8; SERIAL_LEN];
214 self.i2c
215 .read(self.address, &mut buf)
216 .await
217 .map_err(Error::I2c)?;
218 decode_serial(&buf)
219 }
220
221 pub async fn soft_reset_async(&mut self) -> Result<(), Error<I2C::Error>> {
223 self.i2c
224 .write(self.address, &[commands::SOFT_RESET])
225 .await
226 .map_err(Error::I2c)?;
227 self.delay.delay_us(commands::duration_us::SOFT_RESET).await;
228 Ok(())
229 }
230 }
231}
232
233#[doc(hidden)]
234pub mod __private {
235 pub use crate::crc::crc8;
237}