embedded_devices/devices/sensirion/sen60/commands.rs
1use crate::devices::sensirion::commands::define_sensirion_commands;
2use embedded_interfaces::codegen::interface_objects;
3use uom::si::{
4 f64::{MassConcentration, VolumetricNumberDensity},
5 mass_concentration::microgram_per_cubic_meter,
6 volumetric_number_density::per_cubic_centimeter,
7};
8
9interface_objects! {
10 /// Whether data is ready to be read out
11 enum DataReadyStatus: u16{11} {
12 0 NotReady,
13 _ Ready,
14 }
15
16 struct DataReady(size=2) {
17 _: u8{5},
18 /// When no measurement is running, [`DataReadyStatus::NotReady`] will be returned.
19 data_ready: DataReadyStatus = DataReadyStatus::NotReady,
20 }
21
22 struct MeasuredValuesMassConcentrationOnly(size=8) {
23 /// PM1 mass concentration, LSB = 0.1 µg/m³
24 raw_mass_concentration_pm1: u16 = u16::MAX => {
25 quantity: MassConcentration,
26 unit: microgram_per_cubic_meter,
27 lsb: 1f64 / 10_000_000f64,
28 },
29 /// PM2.5 mass concentration, LSB = 0.1 µg/m³
30 raw_mass_concentration_pm2_5: u16 = u16::MAX => {
31 quantity: MassConcentration,
32 unit: microgram_per_cubic_meter,
33 lsb: 1f64 / 10_000_000f64,
34 },
35 /// PM4 mass concentration, LSB = 0.1 µg/m³
36 raw_mass_concentration_pm4: u16 = u16::MAX => {
37 quantity: MassConcentration,
38 unit: microgram_per_cubic_meter,
39 lsb: 1f64 / 10_000_000f64,
40 },
41 /// PM10 mass concentration, LSB = 0.1 µg/m³
42 raw_mass_concentration_pm10: u16 = u16::MAX => {
43 quantity: MassConcentration,
44 unit: microgram_per_cubic_meter,
45 lsb: 1f64 / 10_000_000f64,
46 },
47 }
48
49 struct MeasuredValues(size=18) {
50 /// PM1 mass concentration, LSB = 0.1 µg/m³
51 raw_mass_concentration_pm1: u16 = u16::MAX => {
52 quantity: MassConcentration,
53 unit: microgram_per_cubic_meter,
54 lsb: 1f64 / 10_000_000f64,
55 },
56 /// PM2.5 mass concentration, LSB = 0.1 µg/m³
57 raw_mass_concentration_pm2_5: u16 = u16::MAX => {
58 quantity: MassConcentration,
59 unit: microgram_per_cubic_meter,
60 lsb: 1f64 / 10_000_000f64,
61 },
62 /// PM4 mass concentration, LSB = 0.1 µg/m³
63 raw_mass_concentration_pm4: u16 = u16::MAX => {
64 quantity: MassConcentration,
65 unit: microgram_per_cubic_meter,
66 lsb: 1f64 / 10_000_000f64,
67 },
68 /// PM10 mass concentration, LSB = 0.1 µg/m³
69 raw_mass_concentration_pm10: u16 = u16::MAX => {
70 quantity: MassConcentration,
71 unit: microgram_per_cubic_meter,
72 lsb: 1f64 / 10_000_000f64,
73 },
74 /// PM0.5 volumetric number concentration, LSB = 0.1 particles/cm³
75 raw_number_density_pm0_5: u16 = u16::MAX => {
76 quantity: VolumetricNumberDensity,
77 unit: per_cubic_centimeter,
78 lsb: 1f64 / 10f64,
79 },
80 /// PM1 volumetric number density, LSB = 0.1 particles/cm³
81 raw_number_density_pm1: u16 = u16::MAX => {
82 quantity: VolumetricNumberDensity,
83 unit: per_cubic_centimeter,
84 lsb: 1f64 / 10f64,
85 },
86 /// PM2.5 volumetric number density, LSB = 0.1 particles/cm³
87 raw_number_density_pm2_5: u16 = u16::MAX => {
88 quantity: VolumetricNumberDensity,
89 unit: per_cubic_centimeter,
90 lsb: 1f64 / 10f64,
91 },
92 /// PM4 volumetric number density, LSB = 0.1 particles/cm³
93 raw_number_density_pm4: u16 = u16::MAX => {
94 quantity: VolumetricNumberDensity,
95 unit: per_cubic_centimeter,
96 lsb: 1f64 / 10f64,
97 },
98 /// PM10 volumetric number density, LSB = 0.1 particles/cm³
99 raw_number_density_pm10: u16 = u16::MAX => {
100 quantity: VolumetricNumberDensity,
101 unit: per_cubic_centimeter,
102 lsb: 1f64 / 10f64,
103 },
104 }
105
106 struct SerialNumber(size=6) {
107 /// 6-byte serial number
108 serial_number: [u8; 6],
109 }
110
111 struct DeviceStatus(size=2) {
112 _: u16{11},
113 /// Fan is switched on, but 0 RPM is measured for multiple consecutive measurement intervals.
114 /// This can occur if the fan is mechanically blocked or broken. Note that the measured values
115 /// are most likely wrong if this error is reported.
116 ///
117 /// Can occur only in measurement mode.
118 fan_error: bool = false,
119 _: u8{2},
120 /// Fan is switched on, but its speed is more than 10% off the target speed for multiple
121 /// consecutive measurement intervals. During the first 10 seconds after starting the
122 /// measurement, the fan speed is not checked (settling time). Very low or very high ambient
123 /// temperature could trigger this warning during startup. If this flag is set constantly, it
124 /// might indicate a problem with the power supply or with the fan, and the measured PM values
125 /// might be wrong. This flag is automatically cleared as soon as the measured speed is within
126 /// 10% of the target speed or when leaving the measure mode.
127 ///
128 /// Can occur only in measurement mode.
129 fan_speed_warning: bool = false,
130 _: bool,
131 }
132}
133
134define_sensirion_commands! {
135 id_len 2;
136 marker [
137 ("sensirion-sen60", crate::devices::sensirion::sen60::SEN60Command),
138 ];
139
140 /// Starts a continuous measurement. After starting the measurement, it takes some time (~1.1s)
141 /// until the first measurement results are available. You could poll with the command
142 /// [`GetDataReady`] to check when the results are ready to be read.
143 ///
144 /// Cannot be executed during measurement.
145 send 0x2152 time_ms=1 StartContinuousMeasurement();
146
147 /// Stops the measurement and returns to idle mode.
148 ///
149 /// May be executed during measurement.
150 send 0x3f86 time_ms=1000 StopMeasurement();
151
152 /// This command can be used to check if new measurement results are ready to read. The data ready
153 /// flag is automatically reset after reading the measurement values
154 ///
155 /// May be executed during measurement.
156 read 0xe4b8 time_ms=1 GetDataReady() -> DataReady;
157
158 /// Returns the measured values (mass concentration only). The command [`GetDataReady`] can be used to
159 /// check if new data is available since the last read operation. The measurement data can only be read
160 /// out once per signal update interval, as the buffer is emptied upon read-out. If no data is available
161 /// in the buffer, the sensor returns a NACK. To avoid a NACK response, the Get Data Ready SEN60 can be
162 /// issued to check data status. The I2C controller can abort the read transfer with a NACK followed by
163 /// a STOP condition after any data byte if the user is not interested in the subsequent data
164 ///
165 /// May be executed during measurement.
166 read 0xec05 time_ms=1 ReadMeasuredValuesMassConcentrationOnly() -> MeasuredValuesMassConcentrationOnly;
167
168 /// Returns the measured values (full measurement data). The command [`GetDataReady`] can be used to
169 /// check if new data is available since the last read operation. The measurement data can only be read
170 /// out once per signal update interval, as the buffer is emptied upon read-out. If no data is available
171 /// in the buffer, the sensor returns a NACK. To avoid a NACK response, the Get Data Ready SEN60 can be
172 /// issued to check data status. The I2C controller can abort the read transfer with a NACK followed by
173 /// a STOP condition after any data byte if the user is not interested in the subsequent data
174 ///
175 /// May be executed during measurement.
176 read 0xec05 time_ms=1 ReadMeasuredValues() -> MeasuredValues;
177
178 /// Gets the serial number from the device.
179 ///
180 /// May be executed during measurement.
181 read 0x3682 time_ms=1 GetSerialNumber() -> SerialNumber;
182
183 /// Reads the current device status.
184 ///
185 /// Note: The status flags of type `Error` are sticky, i.e. they are not cleared automatically even
186 /// if the error condition no longer exists. So, they can only be cleared manually through a reset,
187 /// either by calling [`DeviceReset`] or through a power cycle. All other flags are not sticky,
188 /// i.e. they are cleared automatically if the trigger condition disappears.
189 ///
190 /// May be executed during measurement.
191 read 0xe00b time_ms=1 ReadDeviceStatus() -> DeviceStatus;
192
193 /// Executes a reset on the device. This has the same effect as a power cycle.
194 ///
195 /// Cannot be executed during measurement.
196 send 0x3f8d time_ms=1 DeviceReset();
197
198 /// This command triggers fan cleaning. The fan is set to the maximum speed for 10 seconds and then
199 /// automatically stopped.
200 ///
201 /// Note: Wait at least 10s after this command before starting a measurement.
202 ///
203 /// Cannot be executed during measurement.
204 send 0x3730 time_ms=1 StartFanCleaning();
205}