embedded_devices/devices/sensirion/sen6x/
commands.rs

1use crate::devices::sensirion::commands::define_sensirion_commands;
2use embedded_interfaces::codegen::interface_objects;
3use uom::si::{
4    f64::{Length, Pressure, Ratio, ThermodynamicTemperature, Time, VolumetricNumberDensity},
5    length::meter,
6    pressure::hectopascal,
7    ratio::part_per_million,
8    thermodynamic_temperature::degree_celsius,
9    time::second,
10    volumetric_number_density::per_cubic_centimeter,
11};
12
13interface_objects! {
14    /// Whether data is ready to be read out
15    enum DataReadyStatus: u8{1} {
16        0 NotReady,
17        1 Ready,
18    }
19
20    struct DataReady(size=2) {
21        _: u16{15},
22        /// When no measurement is running, [`DataReadyStatus::NotReady`] will be returned.
23        data_ready: DataReadyStatus = DataReadyStatus::NotReady,
24    }
25
26    struct NumberConcentrationValues(size=10) {
27        /// PM0.5 volumetric number density, LSB = 0.1 particles/cm³
28        raw_number_concentration_pm0_5: u16 = u16::MAX => {
29            quantity: VolumetricNumberDensity,
30            unit: per_cubic_centimeter,
31            lsb: 1f64 / 10f64,
32        },
33        /// PM1 volumetric number density, LSB = 0.1 particles/cm³
34        raw_number_concentration_pm1: u16 = u16::MAX => {
35            quantity: VolumetricNumberDensity,
36            unit: per_cubic_centimeter,
37            lsb: 1f64 / 10f64,
38        },
39        /// PM2.5 volumetric number density, LSB = 0.1 particles/cm³
40        raw_number_concentration_pm2_5: u16 = u16::MAX => {
41            quantity: VolumetricNumberDensity,
42            unit: per_cubic_centimeter,
43            lsb: 1f64 / 10f64,
44        },
45        /// PM4 volumetric number density, LSB = 0.1 particles/cm³
46        raw_number_concentration_pm4: u16 = u16::MAX => {
47            quantity: VolumetricNumberDensity,
48            unit: per_cubic_centimeter,
49            lsb: 1f64 / 10f64,
50        },
51        /// PM10 volumetric number density, LSB = 0.1 particles/cm³
52        raw_number_concentration_pm10: u16 = u16::MAX => {
53            quantity: VolumetricNumberDensity,
54            unit: per_cubic_centimeter,
55            lsb: 1f64 / 10f64,
56        },
57    }
58
59    struct TemperatureOffsetParameters(size=8) {
60        /// Temperature offset, LSB = 0.005°C
61        raw_offset: i16 = 0 => {
62            quantity: ThermodynamicTemperature,
63            unit: degree_celsius,
64            lsb: 1f64 / 200f64,
65        },
66        /// Normalized temperature offset slope factor, LSB = 0.0001
67        slope: i16 = 0,
68        /// The time constant determines how fast the new slope and offset will be applied. After the
69        /// specified value in seconds, 63% of the new slope and offset are applied. A time constant of
70        /// zero means the new values will be applied immediately (within the next measure interval of
71        /// 1 second). LSB = 1 second.
72        raw_time_constant: u16 = 0 => {
73            quantity: Time,
74            unit: second,
75            lsb: 1f64 / 1f64,
76        },
77        /// The temperature offset slot to be modified. Valid values are 0 to 4. If the value is
78        /// outside this range, the parameters will not be applied.
79        slot: u16 = 0,
80    }
81
82    struct TemperatureAccelerationParameters(size=8) {
83        /// Filter constant K, LSB = 0.1
84        k: u16,
85        /// Filter constant P, LSB = 0.1
86        p: u16,
87        /// Filter constant T1, LSB = 0.1 second
88        raw_t1: u16 = 0 => {
89            quantity: Time,
90            unit: second,
91            lsb: 1f64 / 10f64,
92        },
93        /// Filter constant T2, LSB = 0.1 second
94        raw_t2: u16 = 0 => {
95            quantity: Time,
96            unit: second,
97            lsb: 1f64 / 10f64,
98        },
99    }
100
101    struct ProductName(size=32) {
102        /// Null-terminated ASCII string containing the product name.
103        name: [u8; 32],
104    }
105
106    struct SerialNumber(size=32) {
107        /// Null-terminated ASCII string containing the serial number.
108        serial_number: [u8; 32],
109    }
110
111    struct VOCAlgorithmTuningParameters(size=12) {
112        /// VOC index representing typical (average) conditions. Allowed values are in range 1-250.
113        /// The default value is 100.
114        index_offset: i16 = 100,
115        /// Time constant to estimate the VOC algorithm offset from the history in hours. Past events
116        /// will be forgotten after about twice the learning time. Allowed values are in range 1-1000.
117        /// The default value is 12 hours.
118        learning_time_offset_hours: i16 = 12,
119        /// Time constant to estimate the VOC algorithm gain from the history in hours. Past events
120        /// will be forgotten after about twice the learning time. Allowed values are in range 1-1000.
121        /// The default value is 12 hours.
122        learning_time_gain_hours: i16 = 12,
123        /// Maximum duration of gating in minutes (freeze of estimator during high VOC index signal).
124        /// Set to zero to disable the gating. Allowed values are in range 0-3000. The default value
125        /// is 180 minutes.
126        gating_max_duration_minutes: i16 = 180,
127        /// Initial estimate for standard deviation. Lower value boosts events during initial learning
128        /// period but may result in larger device-to-device variations. Allowed values are in range
129        /// 10-5000. The default value is 50.
130        std_initial: i16 = 50,
131        /// Gain factor to amplify or to attenuate the VOC index output. Allowed values are in range
132        /// 1-1000. The default value is 230.
133        gain_factor: i16 = 230,
134    }
135
136    struct VOCAlgorithmState(size=8) {
137        /// The opaque internal state.
138        state: [u8; 8],
139    }
140
141    struct NOxAlgorithmTuningParameters(size=12) {
142        /// NOx index representing typical (average) conditions. Allowed values are in range 1-250.
143        /// The default value is 1.
144        index_offset: i16 = 1,
145        /// Time constant to estimate the NOx algorithm offset from the history in hours. Past events
146        /// will be forgotten after about twice the learning time. Allowed values are in range 1-1000.
147        /// The default value is 12 hours.
148        learning_time_offset_hours: i16 = 12,
149        /// The time constant to estimate the NOx algorithm gain from the history has no impact for
150        /// NOx. This parameter is still in place for consistency reasons with the VOC tuning
151        /// parameters command. This parameter must always be set to 12 hours.
152        learning_time_gain_hours: i16 = 12,
153        /// Maximum duration of gating in minutes (freeze of estimator during high NOx index signal).
154        /// Set to zero to disable the gating. Allowed values are in range 0-3000. The default value
155        /// is 720 minutes.
156        gating_max_duration_minutes: i16 = 720,
157        /// The initial estimate for standard deviation parameter has no impact for NOx. This parameter
158        /// is still in place for consistency reasons with the VOC tuning parameters command. This
159        /// parameter must always be set to 50.
160        std_initial: i16 = 50,
161        /// Gain factor to amplify or to attenuate the NOx index output. Allowed values are in range
162        /// 1-1000. The default value is 230.
163        gain_factor: i16 = 230,
164    }
165
166    struct TargetCo2Concentration(size=2) {
167        /// Target co2 concentration of the test setup. LSB = 1 ppm.
168        raw_target_co2_concentration: u16 = 0 => {
169            quantity: Ratio,
170            unit: part_per_million,
171            lsb: 1f64 / 1f64,
172        },
173    }
174
175    struct Co2Correction(size=2) {
176        /// Correction value as received from the SCD in ppm. To get the FRC correction in ppm,
177        /// subtract `0x8000` from this value.
178        ///
179        /// If the recalibration has failed this value is 0xFFFF.
180        raw_correction: u16 = u16::MAX => {
181            quantity: Ratio,
182            unit: part_per_million,
183            from_raw: |x| (x - 0x8000) as f64,
184            into_raw: |x| x as u16 + 0x8000,
185        },
186    }
187
188    struct Co2SensorAutomaticSelfCalibration(size=2) {
189        _: u16{15},
190        /// Set to true to enable or false to disable the automatic CO2 measurement self-calibration
191        /// feature.
192        enable: bool,
193    }
194
195    struct AmbientPressure(size=2) {
196        /// Ambient pressure in hPa to be used for pressure compensation. LSB = 1 hPa.
197        raw_pressure: u16 = 1013 => {
198            quantity: Pressure,
199            unit: hectopascal,
200            lsb: 1f64 / 1f64,
201        },
202    }
203
204    struct SensorAltitude(size=2) {
205        /// Sensor altitude, valid input between 0 and 3000m. LSB = 1 meter.
206        raw_altitude: u16 = 0 => {
207            quantity: Length,
208            unit: meter,
209            lsb: 1f64 / 1f64,
210        },
211    }
212}
213
214define_sensirion_commands! {
215    id_len 2;
216    marker [
217        ("sensirion-sen63c", crate::devices::sensirion::sen63c::SEN63CCommand),
218        ("sensirion-sen65", crate::devices::sensirion::sen65::SEN65Command),
219        ("sensirion-sen66", crate::devices::sensirion::sen66::SEN66Command),
220        ("sensirion-sen68", crate::devices::sensirion::sen68::SEN68Command),
221    ];
222
223    /// Starts a continuous measurement. After starting the measurement, it takes some time (~1.1s)
224    /// until the first measurement results are available. You could poll with the command
225    /// [`GetDataReady`] to check when the results are ready to be read.
226    ///
227    /// Cannot be executed during measurement.
228    send 0x0021 time_ms=50 StartContinuousMeasurement();
229
230    /// Stops the measurement and returns to idle mode.
231    ///
232    /// May be executed during measurement.
233    send 0x0104 time_ms=1000 StopMeasurement();
234
235    /// This command can be used to check if new measurement results are ready to read. The data ready
236    /// flag is automatically reset after reading the measurement values
237    ///
238    /// May be executed during measurement.
239    read 0x0202 time_ms=20 GetDataReady() -> DataReady;
240
241    /// Returns the measured number concentration values. The command [`GetDataReady`] can be used to
242    /// check if new data is available since the last read operation. If no new data is available, the
243    /// previous values will be returned. If no data is available at all (e.g. measurement not running
244    /// for at least one second), all values will be at their upper limit (0xFFFF for u16, 0x7FFF for
245    /// i16).
246    ///
247    /// May be executed during measurement.
248    read 0x0316 time_ms=20 ReadNumberConcentrationValues() -> NumberConcentrationValues;
249
250    /// This command allows to compensate temperature effects of the design-in at customer side by
251    /// applying custom temperature offsets to the ambient temperature. The compensated ambient
252    /// temperature is calculated as follows:
253    ///
254    /// ```text
255    /// T_Ambient_Compensated = T_Ambient + (slope * T_Ambient) + offset
256    /// ```
257    ///
258    /// Where slope and offset are the values set with this command, smoothed with the specified time
259    /// constant. All temperatures (`T_Ambient_Compensated`, `T_Ambient` and `offset`) are represented
260    /// in °C. There are 5 temperature offset slots available that all contribute additively to
261    /// `T_Ambient_Compensated`. The default values for the temperature offset parameters are all zero,
262    /// meaning that `T_Ambient_Compensated` is equal to `T_Ambient` by default.
263    ///
264    /// Note: This configuration is volatile, i.e. the parameters will be reverted to their default
265    /// value of zero after a device reset.
266    ///
267    /// May be executed during measurement.
268    write 0x60b2 time_ms=20 SetTemperatureOffsetParameters(TemperatureOffsetParameters);
269
270    /// This command allows to set custom temperature acceleration parameters of the RH/T engine. It
271    /// overwrites the default temperature acceleration parameters of the RH/T engine with custom
272    /// values.
273    ///
274    /// Note: This configuration is volatile, i.e. the parameters will be reverted to their default
275    /// values after a device reset.
276    ///
277    /// Cannot be executed during measurement.
278    write 0x6100 time_ms=20 SetTemperatureAccelerationParameters(TemperatureAccelerationParameters);
279
280    /// Gets the product name from the device.
281    ///
282    /// May be executed during measurement.
283    read 0xd014 time_ms=20 GetProductName() -> ProductName;
284
285    /// Gets the serial number from the device.
286    ///
287    /// May be executed during measurement.
288    read 0xd033 time_ms=20 GetSerialNumber() -> SerialNumber;
289
290    /// Executes a reset on the device. This has the same effect as a power cycle.
291    ///
292    /// Cannot be executed during measurement.
293    send 0xd304 time_ms=20 DeviceReset();
294
295    /// This command triggers fan cleaning. The fan is set to the maximum speed for 10 seconds and then
296    /// automatically stopped. Wait at least 10s after this command before starting a measurement.
297    ///
298    /// Cannot be executed during measurement.
299    send 0x5607 time_ms=20 StartFanCleaning();
300
301    /// This command allows you to use the inbuilt heater in SHT sensor to reverse creep at high
302    /// humidity. This command activates the SHT sensor heater with 200mW for 1s. The heater is then
303    /// automatically deactivated again.
304    ///
305    /// Note: Wait at least 20s after this command before starting a measurement to get coherent
306    /// temperature values (heating consequence to disappear).
307    ///
308    /// Cannot be executed during measurement.
309    send 0x6765 time_ms=1300 ActivateSHTHeater();
310}
311
312define_sensirion_commands! {
313    id_len 2;
314    marker [
315        ("sensirion-sen65", crate::devices::sensirion::sen65::SEN65Command),
316        ("sensirion-sen66", crate::devices::sensirion::sen66::SEN66Command),
317        ("sensirion-sen68", crate::devices::sensirion::sen68::SEN68Command),
318    ];
319
320    /// Gets the parameters to customize the VOC algorithm.
321    ///
322    /// Note: This configuration is volatile, i.e. the parameters will be reverted to their default
323    /// values after a device reset.
324    ///
325    /// Cannot be executed during measurement.
326    read 0x60d0 time_ms=20 GetVOCAlgorithmTuningParameters() -> VOCAlgorithmTuningParameters;
327
328    /// Sets the parameters to customize the VOC algorithm. Writing has no effect if at least one
329    /// parameter is outside the specified range.
330    ///
331    /// Note: This configuration is volatile, i.e. the parameters will be reverted to their default
332    /// values after a device reset.
333    ///
334    /// Cannot be executed during measurement.
335    write 0x60d0 time_ms=20 SetVOCAlgorithmTuningParameters(VOCAlgorithmTuningParameters);
336
337    /// Allows backup/restore of the VOC algorithm state to resume operation after a power cycle or
338    /// device reset, skipping initial learning phase.
339    ///
340    /// By default, the VOC Engine is reset, and the algorithm state is retained if a measurement is
341    /// stopped and started again. If the VOC algorithm state shall be reset, a device reset, or a
342    /// power cycle can be executed.
343    ///
344    /// Reads the current VOC algorithm state. This data can be used to restore the state
345    /// with [`SetVOCAlgorithmState`] command after a short power cycle or device reset.
346    ///
347    /// This can be read either in measure mode or in idle mode (which will then return the state at
348    /// the time when the measurement was stopped). In measure mode, the state can be read each measure
349    /// interval to always have the latest state available, even in case of a sudden power loss.
350    ///
351    /// May be executed during measurement.
352    read 0x6181 time_ms=20 GetVOCAlgorithmState() -> VOCAlgorithmState;
353
354    /// Allows backup/restore of the VOC algorithm state to resume operation after a power cycle or
355    /// device reset, skipping initial learning phase.
356    ///
357    /// Writing is only possible in idle mode and the state will be applied only once when starting the
358    /// next measurement.
359    ///
360    /// Cannot be executed during measurement.
361    write 0x6181 time_ms=20 SetVOCAlgorithmState(VOCAlgorithmState);
362
363    /// Gets the parameters to customize the NOx algorithm.
364    ///
365    /// Note: This configuration is volatile, i.e. the parameters will be reverted to their default
366    /// values after a device reset.
367    ///
368    /// Cannot be executed during measurement.
369    read 0x60e1 time_ms=20 GetNOxAlgorithmTuningParameters() -> NOxAlgorithmTuningParameters;
370
371    /// Sets the parameters to customize the NOx algorithm. Writing has no effect if at least one
372    /// parameter is outside the specified range.
373    ///
374    /// Note: This configuration is volatile, i.e. the parameters will be reverted to their default
375    /// values after a device reset.
376    ///
377    /// Cannot be executed during measurement.
378    write 0x60e1 time_ms=20 SetNOxAlgorithmTuningParameters(NOxAlgorithmTuningParameters);
379}
380
381define_sensirion_commands! {
382    id_len 2;
383    marker [
384        ("sensirion-sen63c", crate::devices::sensirion::sen63c::SEN63CCommand),
385        ("sensirion-sen66", crate::devices::sensirion::sen66::SEN66Command),
386    ];
387
388    /// Execute the forced recalibration (FRC) of the CO2 signal. Refer to the datasheet for additional
389    /// information on how this is to be used.
390    ///
391    /// Note: After power-on wait at least 1000 ms and after stopping a measurement 600 ms before
392    /// sending this command. The recalibration procedure will take about 500 ms to complete, during
393    /// which time no other functions can be executed.
394    ///
395    /// Cannot be executed during measurement.
396    write_read 0x6707 time_ms=500 PerformForcedCo2Recalibration(TargetCo2Concentration) -> Co2Correction;
397
398    /// Gets the status of the CO2 sensor automatic self-calibration (ASC). The CO2 sensor
399    /// supports automatic self-calibration (ASC) for long-term stability of the CO2 output. This
400    /// feature can be enabled or disabled. By default, it is enabled.
401    ///
402    /// Note: This configuration is volatile, i.e. the parameter will be reverted to its default values
403    /// after a device reset.
404    ///
405    /// Cannot be executed during measurement.
406    read 0x6711 time_ms=20 GetCo2SensorAutomaticSelfCalibration() -> Co2SensorAutomaticSelfCalibration;
407
408    /// Sets the status of the CO2 sensor automatic self-calibration (ASC). The CO2 sensor
409    /// supports automatic self-calibration (ASC) for long-term stability of the CO2 output. This
410    /// feature can be enabled or disabled. By default, it is enabled.
411    ///
412    /// Note: This configuration is volatile, i.e. the parameter will be reverted to its default values
413    /// after a device reset.
414    ///
415    /// Cannot be executed during measurement.
416    write 0x6711 time_ms=20 SetCo2SensorAutomaticSelfCalibration(Co2SensorAutomaticSelfCalibration);
417
418    /// Gets the ambient pressure value. The ambient pressure can be used for pressure
419    /// compensation in the CO2 sensor. Setting an ambient pressure overrides any pressure compensation
420    /// based on a previously set sensor altitude. Use of this command is recommended for applications
421    /// experiencing significant ambient pressure changes to ensure CO2 sensor accuracy. Valid input
422    /// values are between 700 to 1200 hPa. The default value is 1013 hPa.
423    ///
424    /// Note: This configuration is volatile, i.e. the parameter will be reverted to its default values
425    /// after a device reset.
426    ///
427    /// May be executed during measurement.
428    read 0x6720 time_ms=20 GetAmbientPressure() -> AmbientPressure;
429
430    /// Sets the ambient pressure value. The ambient pressure can be used for pressure
431    /// compensation in the CO2 sensor. Setting an ambient pressure overrides any pressure compensation
432    /// based on a previously set sensor altitude. Use of this command is recommended for applications
433    /// experiencing significant ambient pressure changes to ensure CO2 sensor accuracy. Valid input
434    /// values are between 700 to 1200 hPa. The default value is 1013 hPa.
435    ///
436    /// Note: This configuration is volatile, i.e. the parameter will be reverted to its default values
437    /// after a device reset.
438    ///
439    /// May be executed during measurement.
440    write 0x6720 time_ms=20 SetAmbientPressure(AmbientPressure);
441
442    /// Gets the current sensor altitude. The sensor altitude can be used for pressure
443    /// compensation in the CO2 sensor. The default sensor altitude value is set to 0 meters above sea
444    /// level. Valid input values are between 0 and 3000m.
445    ///
446    /// Note: This configuration is volatile, i.e. the parameter will be reverted to its default values
447    /// after a device reset.
448    ///
449    /// Cannot be executed during measurement.
450    read 0x6736 time_ms=20 GetSensorAltitude() -> SensorAltitude;
451
452    /// Sets the current sensor altitude. The sensor altitude can be used for pressure
453    /// compensation in the CO2 sensor. The default sensor altitude value is set to 0 meters above sea
454    /// level. Valid input values are between 0 and 3000m.
455    ///
456    /// Note: This configuration is volatile, i.e. the parameter will be reverted to its default values
457    /// after a device reset.
458    ///
459    /// Cannot be executed during measurement.
460    write 0x6736 time_ms=20 SetSensorAltitude(SensorAltitude);
461}