1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
use core::result;
pub use error::Error;
mod error;
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug)]
pub enum Measurement {
Humidity(f32),
Temperature(f32),
CO2(u16),
Unknown(u8, u16),
#[doc(hidden)]
__Nonexhaustive,
}
pub fn decode(data: [u8; 5]) -> Result<Measurement> {
if data[4] != 0x0d {
return Err(Error::InvalidMessage);
}
if data[0].wrapping_add(data[1]).wrapping_add(data[2]) != data[3] {
return Err(Error::Checksum);
}
let value = u16::from(data[1]) << 8 | u16::from(data[2]);
let measurement = match data[0] {
b'A' => Measurement::Humidity(f32::from(value) * 0.01),
b'B' => Measurement::Temperature(f32::from(value) * 0.0625 - 273.15),
b'P' => Measurement::CO2(value),
_ => Measurement::Unknown(data[0], value),
};
Ok(measurement)
}
#[cfg(test)]
mod tests {
use super::{Error, Measurement};
use assert_float_eq::{afe_is_f32_near, afe_near_error_msg, assert_f32_near};
#[test]
fn test_decode() {
match super::decode([0x50, 0x04, 0x57, 0xab, 0x0d]) {
Ok(Measurement::CO2(val)) => assert_eq!(val, 1111),
_ => assert!(false),
}
match super::decode([0x41, 0x00, 0x00, 0x41, 0x0d]) {
Ok(Measurement::Humidity(val)) => assert_f32_near!(val, 0.0),
_ => assert!(false),
}
match super::decode([0x42, 0x12, 0x69, 0xbd, 0x0d]) {
Ok(Measurement::Temperature(val)) => assert_f32_near!(val, 21.4125),
_ => assert!(false),
}
match super::decode([0x42, 0x12, 0x69, 0xbd, 0x00]) {
Err(Error::InvalidMessage) => {}
_ => assert!(false),
}
match super::decode([0x42, 0x12, 0x69, 0x00, 0x0d]) {
Err(Error::Checksum) => {}
_ => assert!(false),
}
}
}