sen66_interface/
interface.rs

1use duplicate::duplicate_item;
2
3const ADDRESS: u8 = 0x6B;
4const WRITE_FLAG: u8 = 0x00;
5const READ_FLAG: u8 = 0x01;
6
7// `await` replacement needs to be a callable due to the dot notation. This tricks enables that
8// use case.
9#[cfg(not(tarpaulin_include))]
10trait Identity: Sized {
11    fn identity(self) -> Self {
12        core::convert::identity(self)
13    }
14}
15
16impl<T: Sized> Identity for T {}
17
18#[duplicate_item(
19    feature_        module      async   await               delay_trait                             i2c_trait                                       test_macro;
20    ["async"]       [asynch]    [async] [await.identity()]  [embedded_hal_async::delay::DelayNs]    [embedded_hal_async::i2c::I2c<Error = ERR>]  [tokio::test];
21    ["blocking"]    [blocking]  []      [identity()]        [embedded_hal::delay::DelayNs]          [embedded_hal::i2c::I2c<Error = ERR>]        [test];
22)]
23pub mod module {
24    //! Implementation of the SCD30's interface
25    #[cfg(feature=feature_)]
26    mod inner {
27        use crate::{
28            command::Command,
29            configuration::{
30                AmbientPressure, Co2Correction, NoxTuning, SensorAltitude, TargetCO2Concentration,
31                TemperatureAcceleration, TemperatureOffset, VocTuning,
32            },
33            data::{
34                AscState, Concentrations, DataStatus, DeviceStatusRegister, Measurement,
35                ProductName, RawMeasurement, SensorState, SerialNumber, VocAlgorithmState,
36            },
37            error::Sen66Error,
38            interface::{ADDRESS, Identity, READ_FLAG, WRITE_FLAG},
39            util::compute_crc8,
40        };
41
42        /// Interface for the SEN66.
43        pub struct Sen66<DELAY, I2C> {
44            delay: DELAY,
45            i2c: I2C,
46            state: SensorState,
47        }
48
49        impl<DELAY: delay_trait, I2C: i2c_trait, ERR: embedded_hal::i2c::Error> Sen66<DELAY, I2C> {
50            /// Creates a new SEN66 interface.
51            /// - `delay`: Delay provider, implementing embedded_hal's `DelayNs` trait.
52            /// - `i2c`: I2C peripheral implementing embedded_hal's `I2c` trait.
53            pub fn new(delay: DELAY, i2c: I2C) -> Self {
54                Self {
55                    delay,
56                    i2c,
57                    state: SensorState::Idle,
58                }
59            }
60
61            /// Starts a continous measurement. The first result is available after roughly 1.1s
62            /// use [`is_data_ready`](Sen66::is_data_ready) to poll for available measurements.
63            /// Changes sensors state to [`Measuring`](crate::data::SensorState).
64            /// Execution Time: 50ms
65            /// <div class="warning">Only available in idle state</div>
66            ///
67            /// # Errors
68            ///
69            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
70            /// I2C bus occurs.
71            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
72            /// Measuring state.
73            pub async fn start_measurement(&mut self) -> Result<(), Sen66Error<ERR>> {
74                if self.state != SensorState::Idle {
75                    return Err(Sen66Error::WrongState("Measuring"));
76                }
77                self.write::<2>(Command::StartContinuousMeasurement, None)
78                    .await?;
79                self.state = SensorState::Measuring;
80                Ok(())
81            }
82
83            /// Stops continous measurements.
84            /// Changes sensors state to [`Idle`](crate::data::SensorState).
85            /// Execution Time: 1000ms
86            /// <div class="warning">Only available in measuring state</div>
87            ///
88            /// # Errors
89            ///
90            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
91            /// I2C bus occurs.
92            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
93            /// Idle state.
94            pub async fn stop_measurement(&mut self) -> Result<(), Sen66Error<ERR>> {
95                if self.state != SensorState::Measuring {
96                    return Err(Sen66Error::WrongState("Idle"));
97                }
98                self.write::<2>(Command::StopMeasurement, None).await?;
99                self.state = SensorState::Idle;
100                Ok(())
101            }
102
103            /// Queries whether new data is available.
104            /// Execution Time: 20ms
105            /// <div class="warning">Only available in measuring state</div>
106            ///
107            /// # Errors
108            ///
109            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
110            /// I2C bus occurs.
111            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
112            /// Idle state.
113            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
114            /// corrupted or wrong.
115            pub async fn is_data_ready(&mut self) -> Result<DataStatus, Sen66Error<ERR>> {
116                if self.state != SensorState::Measuring {
117                    return Err(Sen66Error::WrongState("Idle"));
118                }
119                let received = self.write_read::<2, 3>(Command::GetDataReady, None).await?;
120                Ok(DataStatus::try_from(&received[..])?)
121            }
122
123            /// Read a [`Measurement`](crate::data::Measurement) value from the sensor.
124            /// If new data is available clears the data ready flag. If no new data is available
125            /// the previous data point is returned. If no data at all is available all values are
126            /// set to their maximum value.
127            /// Execution Time: 20ms
128            /// <div class="warning">Only available in measuring state</div>
129            ///
130            /// # Errors
131            ///
132            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
133            /// I2C bus occurs.
134            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
135            /// Idle state.
136            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
137            /// corrupted or wrong.
138            pub async fn read_measured_values(&mut self) -> Result<Measurement, Sen66Error<ERR>> {
139                if self.state != SensorState::Measuring {
140                    return Err(Sen66Error::WrongState("Idle"));
141                }
142                let received = self
143                    .write_read::<2, 27>(Command::ReadMeasurement, None)
144                    .await?;
145                Ok(Measurement::try_from(&received[..])?)
146            }
147
148            /// Read a [`RawMeasurement`](crate::data::RawMeasurement) value from the sensor.
149            /// If new data is available clears the data ready flag. If no new data is available
150            /// the previous data point is returned. If no data at all is available all values are
151            /// set to their maximum value.
152            /// Execution Time: 20ms
153            /// <div class="warning">Only available in measuring state</div>
154            ///
155            /// # Errors
156            ///
157            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
158            /// I2C bus occurs.
159            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
160            /// Idle state.
161            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
162            /// corrupted or wrong.
163            pub async fn read_measured_raw_values(
164                &mut self,
165            ) -> Result<RawMeasurement, Sen66Error<ERR>> {
166                if self.state != SensorState::Measuring {
167                    return Err(Sen66Error::WrongState("Idle"));
168                }
169                let received = self
170                    .write_read::<2, 15>(Command::ReadRawMeasurement, None)
171                    .await?;
172                Ok(RawMeasurement::try_from(&received[..])?)
173            }
174
175            /// Read a [`Concentrations`](crate::data::Concentrations) value from the sensor.
176            /// If new data is available clears the data ready flag. If no new data is available
177            /// the previous data point is returned. If no data at all is available all values are
178            /// set to their maximum value.
179            /// Execution Time: 20ms
180            /// <div class="warning">Only available in measuring state</div>
181            ///
182            /// # Errors
183            ///
184            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
185            /// I2C bus occurs.
186            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
187            /// Idle state.
188            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
189            /// corrupted or wrong.
190            pub async fn read_number_concentrations(
191                &mut self,
192            ) -> Result<Concentrations, Sen66Error<ERR>> {
193                if self.state != SensorState::Measuring {
194                    return Err(Sen66Error::WrongState("Idle"));
195                }
196                let received = self
197                    .write_read::<2, 15>(Command::ReadNumberConcentrationValues, None)
198                    .await?;
199                Ok(Concentrations::try_from(&received[..])?)
200            }
201
202            /// Set the temperature offset parameters.
203            /// - `parameter`: See [`TemperatureOffset`](crate::configuration::TemperatureOffset)
204            /// Execution Time: 20ms
205            ///
206            /// # Errors
207            ///
208            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
209            /// I2C bus occurs.
210            pub async fn set_temperature_offset(
211                &mut self,
212                parameter: TemperatureOffset,
213            ) -> Result<(), Sen66Error<ERR>> {
214                Ok(self
215                    .write::<14>(
216                        Command::SetTemperatureOffsetParameters,
217                        Some(&(<[u16; 4]>::from(parameter))),
218                    )
219                    .await?)
220            }
221
222            /// Set the temperature acceleration parameters.
223            /// - `parameter`: See [`TemperatureAcceleration`](crate::configuration::TemperatureAcceleration)
224            /// Execution Time: 20ms
225            /// <div class="warning">Only available in Idle state</div>
226            ///
227            /// # Errors
228            ///
229            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
230            /// I2C bus occurs.
231            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
232            /// Measuring state.
233            pub async fn set_temperature_acceleration(
234                &mut self,
235                parameter: TemperatureAcceleration,
236            ) -> Result<(), Sen66Error<ERR>> {
237                if self.state != SensorState::Idle {
238                    return Err(Sen66Error::WrongState("Measuring"));
239                }
240                Ok(self
241                    .write::<14>(
242                        Command::SetTemperatureAccelerationParameters,
243                        Some(&(<[u16; 4]>::from(parameter))),
244                    )
245                    .await?)
246            }
247
248            /// Read out the sensor's product name
249            /// Execution Time: 20ms
250            ///
251            /// # Errors
252            ///
253            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
254            /// I2C bus occurs.
255            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
256            /// corrupted or wrong.
257            pub async fn get_product_name(&mut self) -> Result<ProductName, Sen66Error<ERR>> {
258                let received = self
259                    .write_read::<2, 48>(Command::GetProductName, None)
260                    .await?;
261                Ok(ProductName::try_from(&received[..])?)
262            }
263
264            /// Read out the sensor's serial number
265            /// Execution Time: 20ms
266            ///
267            /// # Errors
268            ///
269            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
270            /// I2C bus occurs.
271            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
272            /// corrupted or wrong.
273            pub async fn get_serial_number(&mut self) -> Result<SerialNumber, Sen66Error<ERR>> {
274                let received = self
275                    .write_read::<2, 48>(Command::GetSerialNumber, None)
276                    .await?;
277                Ok(SerialNumber::try_from(&received[..])?)
278            }
279
280            /// Read out the sensor's [`DeviceStatusRegister`](crate::data::DeviceStatusRegister).
281            /// Error flags are untouched by this.
282            /// Execution Time: 20ms
283            ///
284            /// # Errors
285            ///
286            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
287            /// I2C bus occurs.
288            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
289            /// corrupted or wrong.
290            pub async fn read_device_status(
291                &mut self,
292            ) -> Result<DeviceStatusRegister, Sen66Error<ERR>> {
293                let received = self
294                    .write_read::<2, 6>(Command::GetDeviceStatus, None)
295                    .await?;
296                Ok(DeviceStatusRegister::try_from(&received[..])?)
297            }
298
299            /// Read out the sensor's [`DeviceStatusRegister`](crate::data::DeviceStatusRegister) and
300            /// reset flags stored within.
301            /// Execution Time: 20ms
302            ///
303            /// # Errors
304            ///
305            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
306            /// I2C bus occurs.
307            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
308            /// corrupted or wrong.
309            pub async fn read_and_clear_device_status(
310                &mut self,
311            ) -> Result<DeviceStatusRegister, Sen66Error<ERR>> {
312                let received = self
313                    .write_read::<2, 6>(Command::ReadAndClearDeviceStatus, None)
314                    .await?;
315                Ok(DeviceStatusRegister::try_from(&received[..])?)
316            }
317
318            /// Reset the sensor, akin to a power cycle.
319            /// Execution Time: 20ms
320            /// <div class="warning">Only available in idle state</div>
321            ///
322            /// # Errors
323            ///
324            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
325            /// I2C bus occurs.
326            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
327            /// Measuring state.
328            pub async fn reset_device(&mut self) -> Result<(), Sen66Error<ERR>> {
329                if self.state != SensorState::Idle {
330                    return Err(Sen66Error::WrongState("Measuring"));
331                }
332                self.write::<2>(Command::ResetDevice, None).await
333            }
334
335            /// Start the fan cleaning procedure.
336            /// The fan is set to maximum speed for 10s and then stopped. After issuing this
337            /// command wait at least 10s before starting a measurement.
338            /// Execution Time: 20ms
339            /// <div class="warning">Only available in idle state</div>
340            ///
341            /// # Errors
342            ///
343            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
344            /// I2C bus occurs.
345            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
346            /// Measuring state.
347            pub async fn start_fan_cleaning(&mut self) -> Result<(), Sen66Error<ERR>> {
348                if self.state != SensorState::Idle {
349                    return Err(Sen66Error::WrongState("Measuring"));
350                }
351                self.write::<2>(Command::StartFanCleaning, None).await
352            }
353
354            /// Activate the SHT heater.
355            /// The heater runs with 200mW for 1s. Wait at least 20s after the command for the heat
356            /// to disapper, before taking the next measurement.
357            /// Execution Time: 1300ms
358            /// <div class="warning">Only available in idle state</div>
359            ///
360            /// # Errors
361            ///
362            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
363            /// I2C bus occurs.
364            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
365            /// Measuring state.
366            pub async fn activate_sht_heater(&mut self) -> Result<(), Sen66Error<ERR>> {
367                if self.state != SensorState::Idle {
368                    return Err(Sen66Error::WrongState("Measuring"));
369                }
370                self.write::<2>(Command::ActivateShtHeater, None).await
371            }
372
373            /// Read the [`VocTuning`](crate::configuration::VocTuning) parameters from the sensor.
374            /// Execution Time: 20ms
375            /// <div class="warning">Only available in idle state</div>
376            ///
377            /// # Errors
378            ///
379            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
380            /// I2C bus occurs.
381            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
382            /// Idle state.
383            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
384            /// corrupted or wrong.
385            pub async fn get_voc_tuning_parameters(
386                &mut self,
387            ) -> Result<VocTuning, Sen66Error<ERR>> {
388                if self.state != SensorState::Idle {
389                    return Err(Sen66Error::WrongState("Measuring"));
390                }
391                let received = self
392                    .write_read::<2, 18>(Command::SetReadVocTuningParameters, None)
393                    .await?;
394                Ok(VocTuning::try_from(&received[..])?)
395            }
396
397            /// Set the [`VocTuning`](crate::configuration::VocTuning) parameters for the sensor.
398            /// Execution Time: 20ms
399            /// <div class="warning">Only available in idle state</div>
400            ///
401            /// # Errors
402            ///
403            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
404            /// I2C bus occurs.
405            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
406            /// Idle state.
407            pub async fn set_voc_tuning_parameters(
408                &mut self,
409                parameter: VocTuning,
410            ) -> Result<(), Sen66Error<ERR>> {
411                if self.state != SensorState::Idle {
412                    return Err(Sen66Error::WrongState("Measuring"));
413                }
414                self.write::<20>(
415                    Command::SetReadVocTuningParameters,
416                    Some(&(<[u16; 6]>::from(parameter))),
417                )
418                .await
419            }
420
421            /// Read the [`VocAlgorithmState`](crate::data::VocAlgorithmState) parameters
422            /// from the sensor.
423            /// The VOC algorithm state is lost after a device reset or power cycle, this enables
424            /// storing it persistently and using
425            /// [`set_voc_algorithm_state`](Sen66::set_voc_algorithm_state) to restore it.
426            /// Can be read every measurement.
427            /// Execution Time: 20ms
428            ///
429            /// # Errors
430            ///
431            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
432            /// I2C bus occurs.
433            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
434            /// corrupted or wrong.
435            pub async fn get_voc_algorithm_state(
436                &mut self,
437            ) -> Result<VocAlgorithmState, Sen66Error<ERR>> {
438                let received = self
439                    .write_read::<2, 12>(Command::SetReadVocAlgorithmState, None)
440                    .await?;
441                Ok(VocAlgorithmState::try_from(&received[..])?)
442            }
443
444            /// Set the [`VocAlgorithmState`](crate::data::VocAlgorithmState) parameters
445            /// for the sensor.
446            /// Use [`get_voc_algorithm_state`](Sen66::get_voc_algorithm_state) to retrive it.
447            /// Execution Time: 20ms
448            /// <div class="warning">Only available in idle state</div>
449            ///
450            /// # Errors
451            ///
452            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
453            /// I2C bus occurs.
454            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
455            /// Measuring state.
456            pub async fn set_voc_algorithm_state(
457                &mut self,
458                parameter: VocAlgorithmState,
459            ) -> Result<(), Sen66Error<ERR>> {
460                if self.state != SensorState::Idle {
461                    return Err(Sen66Error::WrongState("Measuring"));
462                }
463                self.write::<14>(
464                    Command::SetReadVocAlgorithmState,
465                    Some(&(<[u16; 4]>::from(parameter))),
466                )
467                .await
468            }
469
470            /// Read the [`NoxTuning`](crate::configuration::NoxTuning) parameters from the sensor.
471            /// Execution Time: 20ms
472            /// <div class="warning">Only available in idle state</div>
473            ///
474            /// # Errors
475            ///
476            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
477            /// I2C bus occurs.
478            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
479            /// Idle state.
480            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
481            /// corrupted or wrong.
482            pub async fn get_nox_tuning_parameters(
483                &mut self,
484            ) -> Result<NoxTuning, Sen66Error<ERR>> {
485                if self.state != SensorState::Idle {
486                    return Err(Sen66Error::WrongState("Measuring"));
487                }
488                let received = self
489                    .write_read::<2, 18>(Command::SetReadNoxTuningParameters, None)
490                    .await?;
491                Ok(NoxTuning::try_from(&received[..])?)
492            }
493
494            /// Set the [`NoxTuning`](crate::configuration::NoxTuning) parameters for the sensor.
495            /// Execution Time: 20ms
496            /// <div class="warning">Only available in idle state</div>
497            ///
498            /// # Errors
499            ///
500            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
501            /// I2C bus occurs.
502            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
503            /// Idle state.
504            pub async fn set_nox_tuning_parameters(
505                &mut self,
506                parameter: NoxTuning,
507            ) -> Result<(), Sen66Error<ERR>> {
508                if self.state != SensorState::Idle {
509                    return Err(Sen66Error::WrongState("Measuring"));
510                }
511                self.write::<20>(
512                    Command::SetReadNoxTuningParameters,
513                    Some(&(<[u16; 6]>::from(parameter))),
514                )
515                .await
516            }
517
518            /// Execute the forced recalibration (FRC) for the CO2 sensor.
519            /// Wait at least 1000ms after power-on or 600ms after stopping the measurement before
520            /// issuing this command.
521            /// Execution Time: 500ms
522            /// <div class="warning">Only available in idle state</div>
523            ///
524            /// # Errors
525            ///
526            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
527            /// I2C bus occurs.
528            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
529            /// Idle state.
530            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
531            /// corrupted or wrong.
532            pub async fn perform_forced_co2_recalibration(
533                &mut self,
534                parameter: TargetCO2Concentration,
535            ) -> Result<Co2Correction, Sen66Error<ERR>> {
536                if self.state != SensorState::Idle {
537                    return Err(Sen66Error::WrongState("Measuring"));
538                }
539                let received = self
540                    .write_read::<5, 3>(
541                        Command::ForcedRecalibration,
542                        Some(&([u16::from(parameter)])),
543                    )
544                    .await?;
545                let value = Co2Correction::try_from(&received[..])?;
546                if !value.is_valid() {
547                    Err(Sen66Error::FailedCo2Recalibration)
548                } else {
549                    Ok(value)
550                }
551            }
552
553            /// Read out whether the automatic self calibration (ASC) for the CO2 sensor is
554            /// enabled or disabled.
555            /// Execution Time: 20ms
556            /// <div class="warning">Only available in idle state</div>
557            ///
558            /// # Errors
559            ///
560            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
561            /// I2C bus occurs.
562            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
563            /// Idle state.
564            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
565            /// corrupted or wrong.
566            pub async fn get_co2_asc_state(&mut self) -> Result<AscState, Sen66Error<ERR>> {
567                if self.state != SensorState::Idle {
568                    return Err(Sen66Error::WrongState("Measuring"));
569                }
570                let received = self
571                    .write_read::<2, 3>(Command::SetReadCo2AutomaticSelfCalibration, None)
572                    .await?;
573                Ok(AscState::try_from(&received[..])?)
574            }
575
576            /// Set whether the automatic self calibration (ASC) for the CO2 sensor is
577            /// enabled or disabled.
578            /// Execution Time: 20ms
579            /// <div class="warning">Only available in idle state</div>
580            ///
581            /// # Errors
582            ///
583            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
584            /// I2C bus occurs.
585            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
586            /// Idle state.
587            pub async fn set_co2_asc_state(
588                &mut self,
589                new_state: AscState,
590            ) -> Result<(), Sen66Error<ERR>> {
591                if self.state != SensorState::Idle {
592                    return Err(Sen66Error::WrongState("Measuring"));
593                }
594                self.write::<5>(
595                    Command::SetReadCo2AutomaticSelfCalibration,
596                    Some(&([u16::from(new_state)])),
597                )
598                .await
599            }
600
601            /// Read the configured ambient pressure for CO2 sensor compensation from the sensor.
602            /// Execution Time: 20ms
603            ///
604            /// # Errors
605            ///
606            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
607            /// I2C bus occurs.
608            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
609            /// corrupted or wrong.
610            pub async fn get_ambient_pressure(
611                &mut self,
612            ) -> Result<AmbientPressure, Sen66Error<ERR>> {
613                let received = self
614                    .write_read::<2, 3>(Command::SetReadAmbientPreassure, None)
615                    .await?;
616                Ok(AmbientPressure::try_from(&received[..])?)
617            }
618
619            /// Configure the ambient pressure for CO2 sensor compensation for the sensor.
620            /// Execution Time: 20ms
621            ///
622            /// # Errors
623            ///
624            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
625            /// I2C bus occurs.
626            pub async fn set_ambient_pressure(
627                &mut self,
628                parameter: AmbientPressure,
629            ) -> Result<(), Sen66Error<ERR>> {
630                self.write::<5>(
631                    Command::SetReadAmbientPreassure,
632                    Some(&([u16::from(parameter)])),
633                )
634                .await
635            }
636
637            /// Read the configured sensor altitude for CO2 sensor compensation from the sensor.
638            /// Execution Time: 20ms
639            /// <div class="warning">Only available in idle state</div>
640            ///
641            /// # Errors
642            ///
643            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
644            /// I2C bus occurs.
645            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
646            /// Idle state.
647            /// - [`DataError`](crate::error::Sen66Error::DataError): If the received data is
648            /// corrupted or wrong.
649            pub async fn get_sensor_altitude(&mut self) -> Result<SensorAltitude, Sen66Error<ERR>> {
650                if self.state != SensorState::Idle {
651                    return Err(Sen66Error::WrongState("Measuring"));
652                }
653                let received = self
654                    .write_read::<2, 3>(Command::SetReadSensorAltitude, None)
655                    .await?;
656                Ok(SensorAltitude::try_from(&received[..])?)
657            }
658
659            /// Configure the sensor altitude for CO2 sensor compensation for the sensor.
660            /// Execution Time: 20ms
661            /// <div class="warning">Only available in idle state</div>
662            ///
663            /// # Errors
664            ///
665            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
666            /// I2C bus occurs.
667            /// - [`WrongState`](crate::error::Sen66Error::WrongState): If the command is called in
668            /// Idle state.
669            pub async fn set_sensor_altitude(
670                &mut self,
671                parameter: SensorAltitude,
672            ) -> Result<(), Sen66Error<ERR>> {
673                if self.state != SensorState::Idle {
674                    return Err(Sen66Error::WrongState("Measuring"));
675                }
676                self.write::<5>(
677                    Command::SetReadSensorAltitude,
678                    Some(&([u16::from(parameter)])),
679                )
680                .await
681            }
682
683            /// Closes the sensor interface, stops active measuring if active and returns the
684            /// contained peripherals.
685            ///
686            /// # Errors
687            ///
688            /// - [`I2cError`](crate::error::Sen66Error::I2cError): If an error on the underlying
689            /// I2C bus occurs.
690            pub async fn shutdown(mut self) -> Result<(DELAY, I2C), Sen66Error<ERR>> {
691                if self.state == SensorState::Measuring {
692                    self.stop_measurement().await?;
693                }
694                Ok((self.delay, self.i2c))
695            }
696
697            /// Closes the sensor interface, does not change sensor state.
698            pub async fn kill(self) -> (DELAY, I2C) {
699                (self.delay, self.i2c)
700            }
701
702            /// Writes the command and optional data to the sensor, waits for the execution time of
703            /// the command and reads the values returned.
704            async fn write_read<const TX_SIZE: usize, const RX_SIZE: usize>(
705                &mut self,
706                command: Command,
707                data: Option<&[u16]>,
708            ) -> Result<[u8; RX_SIZE], Sen66Error<ERR>> {
709                self.write::<TX_SIZE>(command, data).await?;
710                Ok(self.read().await?)
711            }
712
713            /// Writes the command and optional data to the sensor and waits for the execution time
714            /// of the command.
715            async fn write<const TX_SIZE: usize>(
716                &mut self,
717                command: Command,
718                data: Option<&[u16]>,
719            ) -> Result<(), Sen66Error<ERR>> {
720                let mut sent = [0; TX_SIZE];
721                let command_data = command.to_be_bytes();
722                sent[0] = command_data[0];
723                sent[1] = command_data[1];
724
725                let len = if let Some(data) = data {
726                    for (i, datum) in data.iter().enumerate() {
727                        let bytes = datum.to_be_bytes();
728                        sent[2 + i * 3] = bytes[0];
729                        sent[3 + i * 3] = bytes[1];
730                        sent[4 + i * 3] = compute_crc8(&bytes);
731                    }
732                    2 + data.len() * 3
733                } else {
734                    2
735                };
736                self.i2c.write(ADDRESS | WRITE_FLAG, &sent[..len]).await?;
737                self.delay.delay_ms(command.execution_time_ms()).await;
738                Ok(())
739            }
740
741            /// Reads data from the I2C bus.
742            async fn read<const RX_SIZE: usize>(
743                &mut self,
744            ) -> Result<[u8; RX_SIZE], Sen66Error<ERR>> {
745                let mut received = [0; RX_SIZE];
746                self.i2c.read(ADDRESS | READ_FLAG, &mut received).await?;
747                Ok(received)
748            }
749        }
750
751        #[cfg(test)]
752        mod tests {
753            use super::*;
754            use embedded_hal_mock::eh1::{
755                delay::NoopDelay,
756                i2c::{Mock as I2cMock, Transaction as I2cTransaction},
757            };
758
759            #[test_macro]
760            async fn start_measurements_works() {
761                let expected_transaction = [I2cTransaction::write(0x6B | 0x00, vec![0x00, 0x21])];
762                let i2c = I2cMock::new(&expected_transaction);
763                let delay = NoopDelay::new();
764                let mut sensor = Sen66::new(delay, i2c);
765
766                sensor.start_measurement().await.unwrap();
767                sensor.kill().await.1.done();
768            }
769
770            #[test_macro]
771            async fn stop_measurement_in_idle_yields_error() {
772                let expected_transaction = [];
773                let i2c = I2cMock::new(&expected_transaction);
774                let delay = NoopDelay::new();
775                let mut sensor = Sen66::new(delay, i2c);
776
777                assert!(sensor.stop_measurement().await.is_err());
778                sensor.kill().await.1.done();
779            }
780
781            #[test_macro]
782            async fn stop_measurement_works() {
783                let expected_transaction = [I2cTransaction::write(0x6B | 0x00, vec![0x01, 0x04])];
784                let i2c = I2cMock::new(&expected_transaction);
785                let delay = NoopDelay::new();
786                let mut sensor = Sen66::new(delay, i2c);
787                sensor.state = SensorState::Measuring;
788
789                sensor.stop_measurement().await.unwrap();
790                sensor.kill().await.1.done();
791            }
792
793            #[test_macro]
794            async fn if_data_ready_is_data_ready_yields_ready() {
795                let expected_transaction = [
796                    I2cTransaction::write(0x6B | 0x00, vec![0x02, 0x02]),
797                    I2cTransaction::read(0x6B | 0x01, vec![0x00, 0x01, 0xB0]),
798                ];
799                let i2c = I2cMock::new(&expected_transaction);
800                let delay = NoopDelay::new();
801                let mut sensor = Sen66::new(delay, i2c);
802                sensor.state = SensorState::Measuring;
803
804                assert_eq!(sensor.is_data_ready().await.unwrap(), DataStatus::Ready);
805                sensor.kill().await.1.done();
806            }
807
808            #[test_macro]
809            async fn if_data_not_ready_is_data_ready_yields_not_ready() {
810                let expected_transaction = [
811                    I2cTransaction::write(0x6B | 0x00, vec![0x02, 0x02]),
812                    I2cTransaction::read(0x6B | 0x01, vec![0x00, 0x00, 0x81]),
813                ];
814                let i2c = I2cMock::new(&expected_transaction);
815                let delay = NoopDelay::new();
816                let mut sensor = Sen66::new(delay, i2c);
817                sensor.state = SensorState::Measuring;
818
819                assert_eq!(sensor.is_data_ready().await.unwrap(), DataStatus::NotReady);
820                sensor.kill().await.1.done();
821            }
822
823            #[test_macro]
824            async fn read_measured_values_works() {
825                let expected_transaction = [
826                    I2cTransaction::write(0x6B | 0x00, vec![0x03, 0x00]),
827                    I2cTransaction::read(
828                        0x6B | 0x01,
829                        vec![
830                            0x00, 0x0A, 0x5A, 0x00, 0x0A, 0x5A, 0x00, 0x0A, 0x5A, 0x00, 0x0A, 0x5A,
831                            0x00, 0x64, 0xFE, 0x00, 0xC8, 0x7F, 0x00, 0x0A, 0x5A, 0x00, 0x0A, 0x5A,
832                            0x00, 0x01, 0xB0,
833                        ],
834                    ),
835                ];
836                let i2c = I2cMock::new(&expected_transaction);
837                let delay = NoopDelay::new();
838                let mut sensor = Sen66::new(delay, i2c);
839                sensor.state = SensorState::Measuring;
840
841                assert_eq!(
842                    sensor.read_measured_values().await.unwrap(),
843                    Measurement {
844                        pm1_0: 1.0,
845                        pm2_5: 1.0,
846                        pm4_0: 1.0,
847                        pm10_0: 1.0,
848                        relative_humidity: 1.0,
849                        temperature: 1.0,
850                        voc_index: 1.0,
851                        nox_index: 1.0,
852                        co2: 1,
853                    }
854                );
855                sensor.kill().await.1.done();
856            }
857
858            #[test_macro]
859            async fn read_measured_raw_values_works() {
860                let expected_transaction = [
861                    I2cTransaction::write(0x6B | 0x00, vec![0x04, 0x05]),
862                    I2cTransaction::read(
863                        0x6B | 0x01,
864                        vec![
865                            0x00, 0x64, 0xFe, 0x00, 0xC8, 0x7F, 0x00, 0x0A, 0x5A, 0x00, 0x0A, 0x5A,
866                            0x00, 0x01, 0xB0,
867                        ],
868                    ),
869                ];
870                let i2c = I2cMock::new(&expected_transaction);
871                let delay = NoopDelay::new();
872                let mut sensor = Sen66::new(delay, i2c);
873                sensor.state = SensorState::Measuring;
874
875                assert_eq!(
876                    sensor.read_measured_raw_values().await.unwrap(),
877                    RawMeasurement {
878                        relative_humidity: 1.0,
879                        temperature: 1.0,
880                        voc: 10,
881                        nox: 10,
882                        co2: 1,
883                    }
884                );
885                sensor.kill().await.1.done();
886            }
887
888            #[test_macro]
889            async fn read_number_concentrations_works() {
890                let expected_transaction = [
891                    I2cTransaction::write(0x6B | 0x00, vec![0x03, 0x16]),
892                    I2cTransaction::read(
893                        0x6B | 0x01,
894                        vec![
895                            0x00, 0x0A, 0x5A, 0x00, 0x0A, 0x5A, 0x00, 0x0A, 0x5A, 0x00, 0x0A, 0x5A,
896                            0x00, 0x0A, 0x5A,
897                        ],
898                    ),
899                ];
900                let i2c = I2cMock::new(&expected_transaction);
901                let delay = NoopDelay::new();
902                let mut sensor = Sen66::new(delay, i2c);
903                sensor.state = SensorState::Measuring;
904
905                assert_eq!(
906                    sensor.read_number_concentrations().await.unwrap(),
907                    Concentrations {
908                        pm0_5: 1.0,
909                        pm1_0: 1.0,
910                        pm2_5: 1.0,
911                        pm4_0: 1.0,
912                        pm10_0: 1.0,
913                    },
914                );
915                sensor.kill().await.1.done();
916            }
917
918            #[test_macro]
919            async fn set_temperature_offset_works() {
920                let expected_transaction = [I2cTransaction::write(
921                    0x6B | 0x00,
922                    vec![
923                        0x60, 0xB2, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00,
924                        0x00, 0x81,
925                    ],
926                )];
927                let i2c = I2cMock::new(&expected_transaction);
928                let delay = NoopDelay::new();
929                let mut sensor = Sen66::new(delay, i2c);
930
931                let offset = TemperatureOffset::new(0, 0, 0, 0).unwrap();
932                sensor.set_temperature_offset(offset).await.unwrap();
933                sensor.kill().await.1.done();
934            }
935
936            #[test_macro]
937            async fn set_temperature_acceleration_works() {
938                let expected_transaction = [I2cTransaction::write(
939                    0x6B | 0x00,
940                    vec![
941                        0x61, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00,
942                        0x00, 0x81,
943                    ],
944                )];
945                let i2c = I2cMock::new(&expected_transaction);
946                let delay = NoopDelay::new();
947                let mut sensor = Sen66::new(delay, i2c);
948
949                let acceleration = TemperatureAcceleration::new(0, 0, 0, 0).unwrap();
950                sensor
951                    .set_temperature_acceleration(acceleration)
952                    .await
953                    .unwrap();
954                sensor.kill().await.1.done();
955            }
956
957            #[test_macro]
958            async fn get_product_name_works() {
959                let expected_transaction = [
960                    I2cTransaction::write(0x6B | 0x00, vec![0xD0, 0x14]),
961                    I2cTransaction::read(
962                        0x6B | 0x01,
963                        vec![
964                            'S' as u8, 'E' as u8, 0x83, 'N' as u8, '6' as u8, 0x06, '6' as u8,
965                            '\0' as u8, 0x69, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81,
966                            0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81,
967                            0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81,
968                            0x00, 0x00, 0x81, 0x00, 0x00, 0x81,
969                        ],
970                    ),
971                ];
972                let i2c = I2cMock::new(&expected_transaction);
973                let delay = NoopDelay::new();
974                let mut sensor = Sen66::new(delay, i2c);
975                sensor.state = SensorState::Measuring;
976
977                assert_eq!(
978                    sensor.get_product_name().await.unwrap().get_name_buffer(),
979                    [
980                        'S' as u8, 'E' as u8, 'N' as u8, '6' as u8, '6' as u8, '\0' as u8
981                    ]
982                );
983                sensor.kill().await.1.done();
984            }
985
986            #[test_macro]
987            async fn get_serial_number_works() {
988                let expected_transaction = [
989                    I2cTransaction::write(0x6B | 0x00, vec![0xD0, 0x33]),
990                    I2cTransaction::read(
991                        0x6B | 0x01,
992                        vec![
993                            'S' as u8, 'E' as u8, 0x83, 'N' as u8, '6' as u8, 0x06, '6' as u8,
994                            '\0' as u8, 0x69, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81,
995                            0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81,
996                            0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81, 0x00, 0x00, 0x81,
997                            0x00, 0x00, 0x81, 0x00, 0x00, 0x81,
998                        ],
999                    ),
1000                ];
1001                let i2c = I2cMock::new(&expected_transaction);
1002                let delay = NoopDelay::new();
1003                let mut sensor = Sen66::new(delay, i2c);
1004                sensor.state = SensorState::Measuring;
1005
1006                assert_eq!(
1007                    sensor
1008                        .get_serial_number()
1009                        .await
1010                        .unwrap()
1011                        .get_serial_buffer(),
1012                    [
1013                        'S' as u8, 'E' as u8, 'N' as u8, '6' as u8, '6' as u8, '\0' as u8
1014                    ]
1015                );
1016                sensor.kill().await.1.done();
1017            }
1018
1019            #[test_macro]
1020            async fn read_device_status_works() {
1021                let expected_transaction = [
1022                    I2cTransaction::write(0x6B | 0x00, vec![0xD2, 0x06]),
1023                    I2cTransaction::read(0x6B | 0x01, vec![0x00, 0x00, 0x81, 0x00, 0x00, 0x81]),
1024                ];
1025                let i2c = I2cMock::new(&expected_transaction);
1026                let delay = NoopDelay::new();
1027                let mut sensor = Sen66::new(delay, i2c);
1028                sensor.state = SensorState::Measuring;
1029
1030                assert!(
1031                    sensor
1032                        .read_device_status()
1033                        .await
1034                        .unwrap()
1035                        .has_error()
1036                        .is_ok()
1037                );
1038                sensor.kill().await.1.done();
1039            }
1040
1041            #[test_macro]
1042            async fn read_and_clear_device_status_works() {
1043                let expected_transaction = [
1044                    I2cTransaction::write(0x6B | 0x00, vec![0xD2, 0x10]),
1045                    I2cTransaction::read(0x6B | 0x01, vec![0x00, 0x00, 0x81, 0x00, 0x00, 0x81]),
1046                ];
1047                let i2c = I2cMock::new(&expected_transaction);
1048                let delay = NoopDelay::new();
1049                let mut sensor = Sen66::new(delay, i2c);
1050                sensor.state = SensorState::Measuring;
1051
1052                assert!(
1053                    sensor
1054                        .read_and_clear_device_status()
1055                        .await
1056                        .unwrap()
1057                        .has_error()
1058                        .is_ok()
1059                );
1060                sensor.kill().await.1.done();
1061            }
1062
1063            #[test_macro]
1064            async fn reset_device_works() {
1065                let expected_transaction = [I2cTransaction::write(0x6B | 0x00, vec![0xD3, 0x04])];
1066                let i2c = I2cMock::new(&expected_transaction);
1067                let delay = NoopDelay::new();
1068                let mut sensor = Sen66::new(delay, i2c);
1069
1070                sensor.reset_device().await.unwrap();
1071                sensor.kill().await.1.done();
1072            }
1073
1074            #[test_macro]
1075            async fn start_fan_cleaning_works() {
1076                let expected_transaction = [I2cTransaction::write(0x6B | 0x00, vec![0x56, 0x07])];
1077                let i2c = I2cMock::new(&expected_transaction);
1078                let delay = NoopDelay::new();
1079                let mut sensor = Sen66::new(delay, i2c);
1080
1081                sensor.start_fan_cleaning().await.unwrap();
1082                sensor.kill().await.1.done();
1083            }
1084
1085            #[test_macro]
1086            async fn activate_sht_heater_works() {
1087                let expected_transaction = [I2cTransaction::write(0x6B | 0x00, vec![0x37, 0x30])];
1088                let i2c = I2cMock::new(&expected_transaction);
1089                let delay = NoopDelay::new();
1090                let mut sensor = Sen66::new(delay, i2c);
1091
1092                sensor.activate_sht_heater().await.unwrap();
1093                sensor.kill().await.1.done();
1094            }
1095
1096            #[test_macro]
1097            async fn get_voc_tuning_parameters_works() {
1098                let expected_transaction = [
1099                    I2cTransaction::write(0x6B | 0x00, vec![0x60, 0xD0]),
1100                    I2cTransaction::read(
1101                        0x6B | 0x01,
1102                        vec![
1103                            0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x81,
1104                            0x00, 0x0A, 0x5A, 0x00, 0x01, 0xB0,
1105                        ],
1106                    ),
1107                ];
1108                let i2c = I2cMock::new(&expected_transaction);
1109                let delay = NoopDelay::new();
1110                let mut sensor = Sen66::new(delay, i2c);
1111                sensor.state = SensorState::Idle;
1112
1113                assert_eq!(
1114                    sensor.get_voc_tuning_parameters().await.unwrap(),
1115                    VocTuning::new(1, 1, 1, 0, 10, 1).unwrap()
1116                );
1117                sensor.kill().await.1.done();
1118            }
1119
1120            #[test_macro]
1121            async fn set_voc_tuning_parameters_works() {
1122                let expected_transaction = [I2cTransaction::write(
1123                    0x6B | 0x00,
1124                    vec![
1125                        0x60, 0xD0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00,
1126                        0x00, 0x81, 0x00, 0x0A, 0x5A, 0x00, 0x01, 0xB0,
1127                    ],
1128                )];
1129                let i2c = I2cMock::new(&expected_transaction);
1130                let delay = NoopDelay::new();
1131                let mut sensor = Sen66::new(delay, i2c);
1132                sensor.state = SensorState::Idle;
1133
1134                sensor
1135                    .set_voc_tuning_parameters(VocTuning::new(1, 1, 1, 0, 10, 1).unwrap())
1136                    .await
1137                    .unwrap();
1138                sensor.kill().await.1.done();
1139            }
1140
1141            #[test_macro]
1142            async fn get_voc_algorithm_state_works() {
1143                let expected_transaction = [
1144                    I2cTransaction::write(0x6B | 0x00, vec![0x61, 0x81]),
1145                    I2cTransaction::read(
1146                        0x6B | 0x01,
1147                        vec![
1148                            0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0,
1149                        ],
1150                    ),
1151                ];
1152                let i2c = I2cMock::new(&expected_transaction);
1153                let delay = NoopDelay::new();
1154                let mut sensor = Sen66::new(delay, i2c);
1155                sensor.state = SensorState::Idle;
1156
1157                assert_eq!(
1158                    <[u16; 4]>::from(sensor.get_voc_algorithm_state().await.unwrap()),
1159                    [0x0001, 0x0001, 0x0001, 0x0001]
1160                );
1161                sensor.kill().await.1.done();
1162            }
1163
1164            #[test_macro]
1165            async fn set_voc_algorithm_state_works() {
1166                let expected_transaction = [I2cTransaction::write(
1167                    0x6B | 0x00,
1168                    vec![
1169                        0x61, 0x81, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00,
1170                        0x01, 0xB0,
1171                    ],
1172                )];
1173                let i2c = I2cMock::new(&expected_transaction);
1174                let delay = NoopDelay::new();
1175                let mut sensor = Sen66::new(delay, i2c);
1176                sensor.state = SensorState::Idle;
1177
1178                let state = VocAlgorithmState::try_from(
1179                    &(vec![
1180                        0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0,
1181                    ])[..],
1182                )
1183                .unwrap();
1184                sensor.set_voc_algorithm_state(state).await.unwrap();
1185                sensor.kill().await.1.done();
1186            }
1187
1188            #[test_macro]
1189            async fn get_nox_tuning_parameters_works() {
1190                let expected_transaction = [
1191                    I2cTransaction::write(0x6B | 0x00, vec![0x60, 0xE1]),
1192                    I2cTransaction::read(
1193                        0x6B | 0x01,
1194                        vec![
1195                            0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x81,
1196                            0x00, 0x32, 0x26, 0x00, 0x01, 0xB0,
1197                        ],
1198                    ),
1199                ];
1200                let i2c = I2cMock::new(&expected_transaction);
1201                let delay = NoopDelay::new();
1202                let mut sensor = Sen66::new(delay, i2c);
1203                sensor.state = SensorState::Idle;
1204
1205                assert_eq!(
1206                    sensor.get_nox_tuning_parameters().await.unwrap(),
1207                    NoxTuning::new(1, 1, 1, 0, 1).unwrap()
1208                );
1209                sensor.kill().await.1.done();
1210            }
1211
1212            #[test_macro]
1213            async fn set_nox_tuning_parameters_works() {
1214                let expected_transaction = [I2cTransaction::write(
1215                    0x6B | 0x00,
1216                    vec![
1217                        0x60, 0xE1, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00, 0x01, 0xB0, 0x00,
1218                        0x00, 0x81, 0x00, 0x32, 0x26, 0x00, 0x01, 0xB0,
1219                    ],
1220                )];
1221                let i2c = I2cMock::new(&expected_transaction);
1222                let delay = NoopDelay::new();
1223                let mut sensor = Sen66::new(delay, i2c);
1224                sensor.state = SensorState::Idle;
1225
1226                sensor
1227                    .set_nox_tuning_parameters(NoxTuning::new(1, 1, 1, 0, 1).unwrap())
1228                    .await
1229                    .unwrap();
1230                sensor.kill().await.1.done();
1231            }
1232
1233            #[test_macro]
1234            async fn perform_forced_co2_recalibration_works() {
1235                let expected_transaction = [
1236                    I2cTransaction::write(0x6B | 0x00, vec![0x67, 0x07, 0x03, 0xE8, 0xD4]),
1237                    I2cTransaction::read(0x6B | 0x01, vec![0x83, 0xE8, 0xF7]),
1238                ];
1239                let i2c = I2cMock::new(&expected_transaction);
1240                let delay = NoopDelay::new();
1241                let mut sensor = Sen66::new(delay, i2c);
1242                sensor.state = SensorState::Idle;
1243                assert_eq!(
1244                    u16::from(
1245                        sensor
1246                            .perform_forced_co2_recalibration(TargetCO2Concentration::from(1000))
1247                            .await
1248                            .unwrap()
1249                    ),
1250                    1000
1251                );
1252                sensor.kill().await.1.done();
1253            }
1254
1255            #[test_macro]
1256            async fn get_co2_asc_state_is_enabled_yields_enabled() {
1257                let expected_transaction = [
1258                    I2cTransaction::write(0x6B | 0x00, vec![0x67, 0x11]),
1259                    I2cTransaction::read(0x6B | 0x01, vec![0x00, 0x01, 0xb0]),
1260                ];
1261                let i2c = I2cMock::new(&expected_transaction);
1262                let delay = NoopDelay::new();
1263                let mut sensor = Sen66::new(delay, i2c);
1264                sensor.state = SensorState::Idle;
1265                assert_eq!(sensor.get_co2_asc_state().await.unwrap(), AscState::Enabled);
1266                sensor.kill().await.1.done();
1267            }
1268
1269            #[test_macro]
1270            async fn get_co2_asc_state_is_disabled_yields_disabled() {
1271                let expected_transaction = [
1272                    I2cTransaction::write(0x6B | 0x00, vec![0x67, 0x11]),
1273                    I2cTransaction::read(0x6B | 0x01, vec![0x00, 0x00, 0x81]),
1274                ];
1275                let i2c = I2cMock::new(&expected_transaction);
1276                let delay = NoopDelay::new();
1277                let mut sensor = Sen66::new(delay, i2c);
1278                sensor.state = SensorState::Idle;
1279                assert_eq!(
1280                    sensor.get_co2_asc_state().await.unwrap(),
1281                    AscState::Disabled
1282                );
1283                sensor.kill().await.1.done();
1284            }
1285
1286            #[test_macro]
1287            async fn set_co2_asc_state_works() {
1288                let expected_transaction = [I2cTransaction::write(
1289                    0x6B | 0x00,
1290                    vec![0x67, 0x11, 0x00, 0x01, 0xB0],
1291                )];
1292                let i2c = I2cMock::new(&expected_transaction);
1293                let delay = NoopDelay::new();
1294                let mut sensor = Sen66::new(delay, i2c);
1295                sensor.state = SensorState::Idle;
1296                sensor.set_co2_asc_state(AscState::Enabled).await.unwrap();
1297                sensor.kill().await.1.done();
1298            }
1299
1300            #[test_macro]
1301            async fn get_ambient_pressure_works() {
1302                let expected_transaction = [
1303                    I2cTransaction::write(0x6B | 0x00, vec![0x67, 0x20]),
1304                    I2cTransaction::read(0x6B | 0x01, vec![0x02, 0xBC, 0x9A]),
1305                ];
1306                let i2c = I2cMock::new(&expected_transaction);
1307                let delay = NoopDelay::new();
1308                let mut sensor = Sen66::new(delay, i2c);
1309                sensor.state = SensorState::Idle;
1310                assert_eq!(
1311                    sensor.get_ambient_pressure().await.unwrap(),
1312                    AmbientPressure::try_from(700).unwrap()
1313                );
1314                sensor.kill().await.1.done();
1315            }
1316
1317            #[test_macro]
1318            async fn set_ambient_pressure_works() {
1319                let expected_transaction = [I2cTransaction::write(
1320                    0x6B | 0x00,
1321                    vec![0x67, 0x20, 0x02, 0xBC, 0x9A],
1322                )];
1323                let i2c = I2cMock::new(&expected_transaction);
1324                let delay = NoopDelay::new();
1325                let mut sensor = Sen66::new(delay, i2c);
1326                sensor.state = SensorState::Idle;
1327                sensor
1328                    .set_ambient_pressure(AmbientPressure::try_from(700).unwrap())
1329                    .await
1330                    .unwrap();
1331                sensor.kill().await.1.done();
1332            }
1333
1334            #[test_macro]
1335            async fn get_sensor_altitude_works() {
1336                let expected_transaction = [
1337                    I2cTransaction::write(0x6B | 0x00, vec![0x67, 0x36]),
1338                    I2cTransaction::read(0x6B | 0x01, vec![0x02, 0xBC, 0x9A]),
1339                ];
1340                let i2c = I2cMock::new(&expected_transaction);
1341                let delay = NoopDelay::new();
1342                let mut sensor = Sen66::new(delay, i2c);
1343                sensor.state = SensorState::Idle;
1344                assert_eq!(
1345                    sensor.get_sensor_altitude().await.unwrap(),
1346                    SensorAltitude::try_from(700).unwrap()
1347                );
1348                sensor.kill().await.1.done();
1349            }
1350
1351            #[test_macro]
1352            async fn set_sensor_altitude_works() {
1353                let expected_transaction = [I2cTransaction::write(
1354                    0x6B | 0x00,
1355                    vec![0x67, 0x36, 0x02, 0xBC, 0x9A],
1356                )];
1357                let i2c = I2cMock::new(&expected_transaction);
1358                let delay = NoopDelay::new();
1359                let mut sensor = Sen66::new(delay, i2c);
1360                sensor.state = SensorState::Idle;
1361                sensor
1362                    .set_sensor_altitude(SensorAltitude::try_from(700).unwrap())
1363                    .await
1364                    .unwrap();
1365                sensor.kill().await.1.done();
1366            }
1367        }
1368    }
1369
1370    #[cfg(feature=feature_)]
1371    pub use inner::*;
1372}