1#![no_std]
2#![feature(type_alias_impl_trait)]
3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)]
5
6use core::fmt::{LowerHex, UpperHex};
7use core::{
8 fmt::{Debug, Display, Formatter},
9 marker::PhantomData,
10 ops::{Add, Div, Sub},
11};
12use embedded_hal_async::i2c::*;
13use register::{
14 calibration::*,
15 ctrl1::{BlockDataUpdate, Ctrl1, OutputDataRate},
16 ctrl2::Ctrl2,
17 ctrl3::Ctrl3,
18 h_out::Hout,
19 status::Status,
20 t_out::Tout,
21};
22
23mod register;
24
25const ADDR: u8 = 0x5F;
26
27pub enum Hts221Error<E> {
29 I2c(E),
31 NotCalibrated,
33 InvalidSensor,
35}
36
37pub struct Hts221<I>
39where
40 I: I2c<SevenBitAddress> + 'static,
41 <I as ErrorType>::Error: Send,
42{
43 i2c: I,
44 address: I2cAddress,
45 calibration: Option<Calibration>,
46}
47
48impl<I> Hts221<I>
49where
50 I: I2c<SevenBitAddress> + 'static,
51 <I as ErrorType>::Error: Send,
52{
53 pub fn new(i2c: I) -> Self {
55 Self {
56 i2c,
57 address: I2cAddress(ADDR),
58 calibration: None,
59 }
60 }
61
62 pub async fn initialize(&mut self) -> Result<(), Hts221Error<I::Error>> {
64 Ctrl2::modify(self.address, &mut self.i2c, |reg| {
65 reg.boot();
66 })
67 .await?;
68
69 Ctrl1::modify(self.address, &mut self.i2c, |reg| {
70 reg.power_active()
71 .output_data_rate(OutputDataRate::Hz1)
72 .block_data_update(BlockDataUpdate::MsbLsbReading);
73 })
74 .await?;
75
76 Ctrl3::modify(self.address, &mut self.i2c, |reg| {
77 reg.enable(true);
78 })
79 .await?;
80
81 loop {
82 if let Ok(status) = Status::read(self.address, &mut self.i2c).await {
84 if !status.any_available() {
85 break;
86 }
87 }
88 Hout::read(self.address, &mut self.i2c).await?;
89 Tout::read(self.address, &mut self.i2c).await?;
90 }
91
92 self.calibration
93 .replace(Calibration::read(self.address, &mut self.i2c).await?);
94 Ok(())
95 }
96
97 pub async fn read(&mut self) -> Result<SensorAcquisition<Celsius>, Hts221Error<I::Error>> {
99 if let Some(calibration) = &self.calibration {
100 let t_out = Tout::read(self.address, &mut self.i2c).await? as i16;
101 let temperature = calibration.calibrated_temperature(t_out);
102
103 let h_out = Hout::read(self.address, &mut self.i2c).await?;
104 let relative_humidity = calibration.calibrated_humidity(h_out);
105
106 Ok(SensorAcquisition {
107 temperature,
108 relative_humidity,
109 })
110 } else {
111 Err(Hts221Error::NotCalibrated)
112 }
113 }
114}
115
116impl<E> From<E> for Hts221Error<E>
117where
118 E: Send,
119{
120 fn from(e: E) -> Hts221Error<E> {
121 Hts221Error::I2c(e)
122 }
123}
124
125#[derive(Copy, Clone, Debug, Eq, PartialEq)]
126pub(crate) struct I2cAddress(u8);
127
128impl I2cAddress {
129 pub fn new(val: u8) -> Self {
130 Self(val)
131 }
132}
133
134impl Into<u8> for I2cAddress {
135 fn into(self) -> u8 {
136 self.0
137 }
138}
139
140impl Into<I2cAddress> for u8 {
141 fn into(self) -> I2cAddress {
142 I2cAddress::new(self)
143 }
144}
145
146impl LowerHex for I2cAddress {
147 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
148 LowerHex::fmt(&self.0, f)
149 }
150}
151
152impl UpperHex for I2cAddress {
153 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
154 UpperHex::fmt(&self.0, f)
155 }
156}
157
158pub trait TemperatureScale: Send {
160 const LETTER: char;
162}
163
164#[derive(Clone)]
166pub struct Kelvin;
167
168impl TemperatureScale for Kelvin {
169 const LETTER: char = 'K';
170}
171
172impl Debug for Kelvin {
173 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
174 f.write_str("°K")
175 }
176}
177
178#[cfg(feature = "defmt")]
179impl defmt::Format for Kelvin {
180 fn format(&self, f: defmt::Formatter<'_>) {
181 defmt::write!(f, "°K");
182 }
183}
184
185#[derive(Clone)]
187pub struct Celsius;
188
189impl Debug for Celsius {
190 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
191 f.write_str("°C")
192 }
193}
194
195#[cfg(feature = "defmt")]
196impl defmt::Format for Celsius {
197 fn format(&self, f: defmt::Formatter<'_>) {
198 defmt::write!(f, "°C");
199 }
200}
201
202impl TemperatureScale for Celsius {
203 const LETTER: char = 'C';
204}
205
206#[derive(Clone)]
208pub struct Fahrenheit;
209
210impl Debug for Fahrenheit {
211 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
212 f.write_str("°F")
213 }
214}
215
216#[cfg(feature = "defmt")]
217impl defmt::Format for Fahrenheit {
218 fn format(&self, f: defmt::Formatter<'_>) {
219 defmt::write!(f, "°F");
220 }
221}
222
223impl TemperatureScale for Fahrenheit {
224 const LETTER: char = 'F';
225}
226
227pub struct Temperature<S: TemperatureScale> {
229 value: f32,
230 _marker: PhantomData<S>,
231}
232
233impl<S: TemperatureScale> Clone for Temperature<S> {
234 fn clone(&self) -> Self {
235 Self {
236 value: self.value,
237 _marker: PhantomData::default(),
238 }
239 }
240}
241
242impl<S: TemperatureScale> Debug for Temperature<S> {
243 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
244 write!(f, "{}°{}", &self.value, S::LETTER)
245 }
246}
247
248#[cfg(feature = "defmt")]
249impl<S: TemperatureScale> defmt::Format for Temperature<S> {
250 fn format(&self, f: defmt::Formatter<'_>) {
251 defmt::write!(f, "{}°{}", &self.value, S::LETTER)
252 }
253}
254
255impl<S: TemperatureScale> Copy for Temperature<S> {}
256
257impl<S: TemperatureScale> Temperature<S> {
258 fn new(value: f32) -> Self {
259 Self {
260 value,
261 _marker: PhantomData::default(),
262 }
263 }
264
265 pub fn raw_value(&self) -> f32 {
267 self.value
268 }
269}
270
271impl Temperature<Celsius> {
272 pub fn into_fahrenheit(self) -> Temperature<Fahrenheit> {
274 Temperature::new((self.value * 9.0 / 5.0) + 32.0)
275 }
276}
277
278impl Into<Temperature<Celsius>> for i16 {
279 fn into(self) -> Temperature<Celsius> {
280 Temperature::<Celsius>::new(self as f32)
281 }
282}
283
284impl Into<Temperature<Celsius>> for f32 {
285 fn into(self) -> Temperature<Celsius> {
286 Temperature::<Celsius>::new(self as f32)
287 }
288}
289
290impl<S: TemperatureScale> Sub for Temperature<S> {
291 type Output = Self;
292
293 fn sub(self, rhs: Self) -> Self::Output {
294 Self::new(self.value - rhs.value)
295 }
296}
297
298impl<S: TemperatureScale> Add for Temperature<S> {
299 type Output = Self;
300
301 fn add(self, rhs: Self) -> Self::Output {
302 Self::new(self.value + rhs.value)
303 }
304}
305
306impl<S: TemperatureScale> Add<f32> for Temperature<S> {
307 type Output = Self;
308
309 fn add(self, rhs: f32) -> Self::Output {
310 Self::new(self.value + rhs)
311 }
312}
313
314impl<S: TemperatureScale> Div<f32> for Temperature<S> {
315 type Output = f32;
316
317 fn div(self, rhs: f32) -> Self::Output {
318 self.value / rhs
319 }
320}
321
322impl<S: TemperatureScale> Display for Temperature<S> {
323 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
324 Display::fmt(&self.value, f)?;
325 write!(f, "°{}", S::LETTER)
326 }
327}
328
329#[derive(Copy, Clone)]
331pub struct SensorAcquisition<S: TemperatureScale> {
332 pub temperature: Temperature<S>,
334 pub relative_humidity: f32,
336}
337
338impl<S: TemperatureScale> Debug for SensorAcquisition<S> {
339 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
340 f.debug_struct("SensorAcquisition")
341 .field("temperature", &self.temperature)
342 .field("relative_humidity", &self.relative_humidity)
343 .finish()
344 }
345}
346
347#[cfg(feature = "defmt")]
348impl<S: TemperatureScale> defmt::Format for SensorAcquisition<S> {
349 fn format(&self, f: defmt::Formatter<'_>) {
350 defmt::write!(
351 f,
352 "SensorAcquisition(temperature: {}, relative_humidity: {})",
353 &self.temperature,
354 &self.relative_humidity
355 );
356 }
357}