1#![no_std]
2#![allow(dead_code)]
3#![allow(unused_variables)]
4
5pub mod error;
6
7use crate::error::Error;
8
9pub mod data;
10use crate::data::ENS160Command;
11use crate::data::OperationMode;
12
13use data::Measurements;
14use data::{AirQualityIndex, Status, ECO2};
15
16pub mod constants;
17
18use crate::constants::DeviceAddress::{Primary, Secondary};
19
20#[allow(unused_imports)]
21use crate::constants::{
22 ENS160_COMMAND, ENS160_CONFIG, ENS160_DATA_AQI, ENS160_DATA_ECO2, ENS160_DATA_ETOH,
23 ENS160_DATA_MISR, ENS160_DATA_RH, ENS160_DATA_T, ENS160_DATA_TVOC, ENS160_DEVICE_STATUS,
24 ENS160_GPR_READ, ENS160_GPR_WRITE, ENS160_GRP_READ6, ENS160_OPMODE, ENS160_PART_ID,
25 ENS160_RH_IN, ENS160_TEMP_IN,
26};
27
28#[cfg(not(feature = "async"))]
29use embedded_hal::{i2c::I2c, delay::DelayNs};
30#[cfg(feature = "async")]
31use embedded_hal_async::{i2c::I2c as AsyncI2c, delay::DelayNs as AsyncDelayNs};
32use libm::{powf, truncf};
36use log::{debug, info};
37
38pub struct Ens160<I2C, D> {
47 i2c: I2C,
49
50 address: u8,
52 delayer: D,
53}
54
55#[cfg(not(feature = "async"))]
56impl<I2C, D, E> Ens160<I2C, D>
57where
58 I2C: I2c<Error = E>,
59 D: DelayNs,
60{
61 pub fn new(i2c: I2C, delayer: D) -> Self {
63 debug!("new called");
64 Self {
65 i2c,
66 address: Primary.into(),
67 delayer,
68 }
69 }
70
71 pub fn new_secondary_address(i2c: I2C, delayer: D) -> Self {
73 Self {
74 i2c,
75 address: Secondary.into(),
76 delayer,
77 }
78 }
79
80 pub fn release(self) -> I2C {
82 self.i2c
83 }
84}
85
86#[cfg(feature = "async")]
87impl<I2C, D, E> Ens160<I2C, D>
88where
89 I2C: AsyncI2c<Error = E>,
90 D: AsyncDelayNs,
91{
92 pub fn new(i2c: I2C, delayer: D) -> Self {
94 debug!("new called");
95 Self {
96 i2c,
97 address: Primary.into(),
98 delayer,
99 }
100 }
101
102 pub fn new_secondary_address(i2c: I2C, delayer: D) -> Self {
104 Self {
105 i2c,
106 address: Secondary.into(),
107 delayer,
108 }
109 }
110
111 pub fn release(self) -> I2C {
113 self.i2c
114 }
115}
116
117#[maybe_async_cfg::maybe(
118 sync(
119 cfg(not(feature = "async")),
120 self = "Ens160",
121 idents(AsyncI2c(sync = "I2c"), AsyncDelayNs(sync = "DelayNs"))
122 ),
123 async(feature = "async", keep_self)
124)]
125
126
127impl<I2C, D, E> Ens160<I2C, D>
128where
129 I2C: AsyncI2c<Error = E>,
130 D: AsyncDelayNs,
131{
132
133 async fn write_command<const N: usize>(
135 &mut self,
136 command_buf: [u8; N],
137 ) -> Result<(), Error<E>> {
138 self.i2c
140 .write(self.address, &command_buf).await
141 .map_err(Error::I2c)
142 }
143
144 async fn read_register(
145 &mut self,
146 register_address: u8,
147 buffer: &mut [u8],
148 ) -> Result<(), Error<E>> {
149 let mut command_buffer = [0u8; 1];
150 command_buffer[0] = register_address;
151 self.i2c
153 .write_read(self.address, &command_buffer, buffer).await
154 .map_err(Error::I2c)?;
155 Ok(())
156 }
157
158 pub async fn set_operation_mode(
162 &mut self,
163 mode: OperationMode,
164 ) -> Result<OperationMode, Error<E>> {
165 debug!("setting ens160 operation mode to {:#?}", mode);
166 self.write_command([ENS160_OPMODE, mode as u8]).await?;
167 self.delayer.delay_ms(50).await;
168 let mut result_buf: [u8; 1] = [0; 1];
169 self.read_register(ENS160_OPMODE, &mut result_buf).await?;
170 return Ok(OperationMode::from(result_buf[0]));
171 }
172
173 pub async fn get_part_id(&mut self) -> Result<u16, Error<E>> {
175 let mut result_buf = [0; 2];
176 self.read_register(ENS160_PART_ID, &mut result_buf[0..2]).await?;
177 Ok(u16::from_le_bytes(result_buf))
180 }
181
182 pub async fn get_firmware_version(&mut self) -> Result<(u8, u8, u8), Error<E>> {
184 self.write_command([ENS160_COMMAND, ENS160Command::GetAppVersion as u8]).await?;
185 let mut result_buf: [u8; 8] = [0; 8];
186 self.read_register(ENS160_GPR_READ, &mut result_buf).await?;
187 Ok((result_buf[4], result_buf[5], result_buf[6]))
188 }
189
190 pub async fn clear_command(&mut self) -> Result<(), Error<E>> {
192 self.write_command([ENS160_COMMAND, ENS160Command::Nop as u8]).await?;
193 self.write_command([ENS160_COMMAND, ENS160Command::ClearGPR as u8]).await?;
194 Ok(())
195 }
196
197 pub async fn get_eco2(&mut self) -> Result<ECO2, Error<E>> {
199 let mut result_buf = [0; 2];
200 self.read_register(ENS160_DATA_ECO2, &mut result_buf).await?;
201 let eco2 = u16::from_le_bytes(result_buf);
203 Ok(ECO2::from(eco2))
205 }
206
207 pub async fn get_tvoc(&mut self) -> Result<u16, Error<E>> {
209 let mut result_buf = [0; 2];
210 self.read_register(ENS160_DATA_TVOC, &mut result_buf).await?;
211 Ok(u16::from_le_bytes(result_buf))
212 }
214
215 pub async fn get_airquality_index(&mut self) -> Result<AirQualityIndex, Error<E>> {
218 let mut result_buf = [0; 1];
219 self.read_register(ENS160_DATA_AQI, &mut result_buf).await?;
220 debug!(" read ENS160_DATA_AQI result is {}", result_buf[0]);
221 Ok(AirQualityIndex::from(result_buf[0]))
222 }
223
224 pub async fn get_etoh(&mut self) -> Result<u16, Error<E>> {
226 let mut result_buf: [u8; 2] = [0; 2];
227 self.read_register(ENS160_DATA_ETOH, &mut result_buf).await?;
228 Ok(u16::from_le_bytes(result_buf))
229 }
230
231 pub async fn get_raw_resistance(&mut self) -> Result<f32, Error<E>> {
233 let mut result_buf: [u8; 2] = [0; 2];
234 self.read_register(ENS160_GRP_READ6, &mut result_buf).await?;
235 let exponent: f32 = u16::from_le_bytes(result_buf) as f32;
237 let resistance = powf(2.0, exponent / 2048.0);
239 Ok(resistance)
240 }
241
242 pub async fn get_status(&mut self) -> Result<Status, Error<E>> {
244 let mut result_buf = [0; 1];
245 self.read_register(ENS160_DEVICE_STATUS, &mut result_buf).await?;
246 Ok(Status(result_buf[0]))
248 }
249
250 pub async fn get_group_data(&mut self) -> Result<[u8; 8], Error<E>> {
252 let mut result_buf: [u8; 8] = [0; 8];
253 self.read_register(ENS160_GPR_READ, &mut result_buf).await?;
254 Ok(result_buf)
256 }
257 pub async fn set_temp_rh_comp(
259 &mut self,
260 temp_c: f32,
261 rh_percent: u16,
262 ) -> Result<(), Error<E>> {
263 let mut buffer: [u8; 2];
264 let temp_val: u16 = truncf((temp_c + 273.15) * 64.0) as u16; buffer = temp_val.to_le_bytes(); self.write_command([ENS160_TEMP_IN, buffer[0], buffer[1]]).await?;
268
269 buffer = rh_percent.to_le_bytes();
270 self.write_command([ENS160_RH_IN, buffer[0], buffer[1]]).await?;
272
273 Ok(())
274 }
275
276 pub async fn get_temp_rh_comp(&mut self) -> Result<(f32, u16), Error<E>> {
277 let mut result_buf: [u8; 2] = [0; 2];
278 self.read_register(ENS160_DATA_T, &mut result_buf).await?;
279 let value: u16 = u16::from_le_bytes(result_buf);
280 let temp_comp_c = ((value as f32) / 64.0) - 273.15;
281 self.read_register(ENS160_DATA_RH, &mut result_buf).await?;
284 let rh: u16 = u16::from_le_bytes(result_buf);
285 Ok((temp_comp_c, rh))
287 }
288
289 pub async fn config_interrupt_pin(&mut self, config: u8) -> Result<u8, Error<E>> {
294 self.write_command([ENS160_CONFIG, config]).await?;
295 let mut result_buf: [u8; 1] = [0; 1];
296 self.read_register(ENS160_CONFIG, &mut result_buf).await?;
297 Ok(result_buf[0])
298 }
299
300 pub async fn initialize(&mut self) -> Result<bool, Error<E>> {
302 self.set_operation_mode(OperationMode::Idle).await?;
306 let the_status = self.get_status().await?;
308 debug!(
309 " command to idle, ENS160 status is {:#?}", the_status );
310 if let Ok(part_id) = self.get_part_id().await {
311 if part_id != 0x0160 {
312 Err(Error::UnexpectedChipId(part_id as u16))
313 } else {
314 info!("ENS160 part id is good {}", part_id);
315 self.delayer.delay_ms(50).await;
316 self.clear_command().await?;
317 let the_status = self.get_status().await?;
318 debug!(" command to clear grp data, ENS160 status is {:#?}", the_status );
319 self.delayer.delay_ms(50).await;
320 let (fw_major, fw_minor, fw_build) = self.get_firmware_version().await?;
321 info!("firmware version {}.{}.{}", fw_major, fw_minor, fw_build);
322 self.delayer.delay_ms(10).await;
323 let new_mode = self.set_operation_mode(OperationMode::Standard).await?;
325 if new_mode != OperationMode::Standard {
326 return Err(Error::OpModeNotCorrect(new_mode as u8));
327 }
328 self.delayer.delay_ms(150).await;
329 let the_status = self.get_status().await?;
330 debug!(" command to std mode, ENS160 status is {:#?}", the_status );
331 let mut result_buf: [u8; 1] = [0; 1];
333 self.read_register(ENS160_OPMODE, &mut result_buf).await?;
334 debug!("opmode read is {:#04x}", result_buf[0]);
335 Ok(true)
336 }
337 } else {
338 Ok(false)
339 }
340 }
341
342 pub async fn get_measurements(&mut self) -> Result<Measurements, Error<E>> {
344 let eco2 = self.get_eco2().await?;
345 let tvoc = self.get_tvoc().await?;
346 let aqi = self.get_airquality_index().await?;
347 let etoh = self.get_etoh().await?;
348 let raw_resistance = self.get_raw_resistance().await?;
349 let measurements: Measurements = Measurements {
350 co2eq_ppm: eco2,
351 tvoc_ppb: tvoc,
352 air_quality_index: aqi,
353 etoh,
354 raw_resistance,
355 };
356 Ok(measurements)
357 }
358
359 }