1use crate::{
2 error::{DataError, DeviceError},
3 util::{check_deserialization, is_set},
4};
5
6#[derive(Debug, PartialEq)]
8pub enum SensorState {
9 Idle,
12 Measuring,
15}
16
17#[cfg(feature = "defmt")]
18impl defmt::Format for SensorState {
19 fn format(&self, f: defmt::Formatter) {
20 defmt::write!(f, "{}", self)
21 }
22}
23
24#[derive(Debug, PartialEq)]
26pub struct DeviceStatusRegister(u32);
27
28impl DeviceStatusRegister {
29 pub fn fan_speed_warning(&self) -> bool {
32 is_set(self.0, 21)
33 }
34
35 pub fn pm_sensor_error(&self) -> bool {
39 is_set(self.0, 11)
40 }
41
42 pub fn co2_sensor_error(&self) -> bool {
46 is_set(self.0, 9)
47 }
48
49 pub fn gas_sensor_error(&self) -> bool {
53 is_set(self.0, 7)
54 }
55
56 pub fn rht_sensor_error(&self) -> bool {
60 is_set(self.0, 6)
61 }
62
63 pub fn fan_error(&self) -> bool {
68 is_set(self.0, 4)
69 }
70
71 pub fn has_error(&self) -> Result<(), DeviceError> {
78 let pm = self.pm_sensor_error();
79 let co2 = self.co2_sensor_error();
80 let gas = self.gas_sensor_error();
81 let rht = self.rht_sensor_error();
82 let fan = self.fan_error();
83 if [pm, co2, gas, rht, fan].iter().any(|&err| err) {
84 Err(DeviceError {
85 pm,
86 co2,
87 gas,
88 rht,
89 fan,
90 })
91 } else {
92 Ok(())
93 }
94 }
95}
96
97impl TryFrom<&[u8]> for DeviceStatusRegister {
98 type Error = DataError;
99
100 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
109 check_deserialization(data, 6)?;
110 Ok(DeviceStatusRegister(u32::from_be_bytes([
111 data[0], data[1], data[3], data[4],
112 ])))
113 }
114}
115
116#[derive(Debug, PartialEq)]
118pub enum AscState {
119 Enabled,
121 Disabled,
123}
124
125impl TryFrom<&[u8]> for AscState {
126 type Error = DataError;
127
128 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
139 check_deserialization(data, 3)?;
140 match data[1] {
141 0x00 => Ok(Self::Disabled),
142 0x01 => Ok(Self::Enabled),
143 val => Err(DataError::UnexpectedValueReceived {
144 parameter: "ASC State",
145 expected: "0 or 1",
146 actual: val as u16,
147 }),
148 }
149 }
150}
151
152impl From<AscState> for u16 {
153 fn from(value: AscState) -> Self {
154 match value {
155 AscState::Enabled => 0x0001,
156 AscState::Disabled => 0x0000,
157 }
158 }
159}
160
161#[derive(Debug, PartialEq)]
164pub struct VocAlgorithmState([u8; 8]);
165
166impl TryFrom<&[u8]> for VocAlgorithmState {
167 type Error = DataError;
168
169 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
178 check_deserialization(data, 12)?;
179 Ok(VocAlgorithmState([
180 data[0], data[1], data[3], data[4], data[6], data[7], data[9], data[10],
181 ]))
182 }
183}
184
185impl From<VocAlgorithmState> for [u16; 4] {
186 fn from(value: VocAlgorithmState) -> Self {
187 [
188 u16::from_be_bytes([value.0[0], value.0[1]]),
189 u16::from_be_bytes([value.0[2], value.0[3]]),
190 u16::from_be_bytes([value.0[4], value.0[5]]),
191 u16::from_be_bytes([value.0[6], value.0[7]]),
192 ]
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn no_flags_set_nothing_reported() {
202 let state = DeviceStatusRegister(0b0000_0000_0000_0000_0000_0000_0000_0000);
203 assert!(!state.fan_speed_warning());
204 assert!(state.has_error().is_ok());
205 }
206
207 #[test]
208 fn set_fan_speed_warning_reported() {
209 let state = DeviceStatusRegister(0b0000_0000_0010_0000_0000_0000_0000_0000);
210 assert!(state.fan_speed_warning());
211 }
212
213 #[test]
214 fn set_fan_speed_error_reported() {
215 let state = DeviceStatusRegister(0b0000_0000_0000_0000_0000_0000_0001_0000);
216 assert!(state.fan_error());
217 }
218
219 #[test]
220 fn set_rht_error_reported() {
221 let state = DeviceStatusRegister(0b0000_0000_0000_0000_0000_0000_0100_0000);
222 assert!(state.rht_sensor_error());
223 }
224
225 #[test]
226 fn set_gas_error_reported() {
227 let state = DeviceStatusRegister(0b0000_0000_0000_0000_0000_0000_1000_0000);
228 assert!(state.gas_sensor_error());
229 }
230
231 #[test]
232 fn set_co2_error_reported() {
233 let state = DeviceStatusRegister(0b0000_0000_0000_0000_0000_0010_0000_0000);
234 assert!(state.co2_sensor_error());
235 }
236
237 #[test]
238 fn set_pm_error_reported() {
239 let state = DeviceStatusRegister(0b0000_0000_0000_0000_0000_1000_0000_0000);
240 assert!(state.pm_sensor_error());
241 }
242
243 #[test]
244 fn set_warning_flag_does_not_emit_error() {
245 let state = DeviceStatusRegister(0b0000_0000_0010_0000_0000_0000_0000_0000);
246 assert!(state.has_error().is_ok());
247 }
248
249 #[test]
250 fn set_error_flag_does_emit_device_error() {
251 let state = DeviceStatusRegister(0b0000_0000_0000_0000_0000_1000_0000_0000);
252 assert_eq!(
253 state.has_error().unwrap_err(),
254 DeviceError {
255 pm: true,
256 co2: false,
257 gas: false,
258 rht: false,
259 fan: false
260 }
261 );
262 }
263
264 #[test]
265 fn deserialize_device_status_register_with_all_flags_set_yields_u32_with_flag_bits_one() {
266 let data = [0x00, 0x20, 0x07, 0x0E, 0xD0, 0xE8];
267 assert_eq!(
268 DeviceStatusRegister::try_from(&data[..]).unwrap(),
269 DeviceStatusRegister(0b0000_0000_0010_0000_0000_1110_1101_0000)
270 );
271 }
272
273 #[test]
274 fn deserialize_asc_status_enabled_yields_enabled() {
275 let data = [0x00, 0x01, 0xB0];
276 assert_eq!(AscState::try_from(&data[..]).unwrap(), AscState::Enabled);
277 }
278
279 #[test]
280 fn deserialize_asc_status_disabled_yields_enabled() {
281 let data = [0x00, 0x00, 0x81];
282 assert_eq!(AscState::try_from(&data[..]).unwrap(), AscState::Disabled);
283 }
284
285 #[test]
286 fn deserialize_asc_status_unknown_emit_error() {
287 let data = [0x00, 0x03, 0xd2];
288 assert!(AscState::try_from(&data[..]).is_err());
289 }
290
291 #[test]
292 fn serialize_asc_status_enabled_yields_one() {
293 assert_eq!(u16::from(AscState::Enabled), 0x0001);
294 }
295
296 #[test]
297 fn serialize_asc_status_disabled_yields_zero() {
298 assert_eq!(u16::from(AscState::Disabled), 0x0000);
299 }
300
301 #[test]
302 fn deserialize_voc_algorithm_state_yields_same_state() {
303 let data = [
304 0x01, 0x02, 0x17, 0x03, 0x04, 0x68, 0x05, 0x06, 0x50, 0x07, 0x08, 0x96,
305 ];
306 assert_eq!(
307 VocAlgorithmState::try_from(&data[..]).unwrap(),
308 VocAlgorithmState([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08])
309 );
310 }
311
312 #[test]
313 fn serialize_voc_algorithm_state_yields_same_state() {
314 assert_eq!(
315 <[u16; 4]>::from(VocAlgorithmState([
316 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
317 ])),
318 [0x0102, 0x0304, 0x0506, 0x0708]
319 );
320 }
321}