sen66_interface/configuration/mod.rs
1//! Data types for configuring the SEN66's operations.
2
3mod temperature;
4mod tuning;
5
6use crate::{
7 error::DataError,
8 util::{check_deserialization, check_range},
9};
10pub use temperature::{TemperatureAcceleration, TemperatureOffset};
11pub use tuning::{NoxTuning, VocTuning};
12
13/// Target CO2 concentration after a forced CO2 recalibration in ppm.
14pub struct TargetCO2Concentration(u16);
15
16impl From<u16> for TargetCO2Concentration {
17 fn from(value: u16) -> Self {
18 TargetCO2Concentration(value)
19 }
20}
21
22impl From<TargetCO2Concentration> for u16 {
23 fn from(value: TargetCO2Concentration) -> Self {
24 value.0
25 }
26}
27
28/// CO2 correction value determined after forced CO2 recalibration (FRC).
29/// Is set to `0xFFFF` if recalibration has failed.
30pub struct Co2Correction(u16);
31
32impl Co2Correction {
33 /// Returns true if recalibration has failed.
34 pub fn is_valid(&self) -> bool {
35 self.0 != 0xFFFF
36 }
37}
38
39impl TryFrom<&[u8]> for Co2Correction {
40 type Error = DataError;
41
42 /// Computes the correction value from the received data. Does not perform the computation if
43 /// `0xFFFF` has been received, indicating a failed FRC.
44 ///
45 /// # Errors
46 ///
47 /// - [`CrcFailed`](crate::error::DataError::CrcFailed): If the received data CRC indicates
48 /// corruption.
49 /// - [`ReceivedBufferWrongSize`](crate::error::DataError::ReceivedBufferWrongSize): If the
50 /// received data buffer is not the expected size.
51 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
52 check_deserialization(data, 3)?;
53 let value = u16::from_be_bytes([data[0], data[1]]);
54 let value = if value != 0xFFFF {
55 value - 0x8000
56 } else {
57 value
58 };
59 Ok(Co2Correction(value))
60 }
61}
62
63impl From<Co2Correction> for u16 {
64 fn from(value: Co2Correction) -> Self {
65 value.0
66 }
67}
68
69/// Ambient pressure value used for CO2 measurement compensation in hPa. Must be between 700hPa and
70/// 1,200 hPa. The default value is 1,013 hPa.
71#[derive(Debug, PartialEq)]
72pub struct AmbientPressure(u16);
73
74impl TryFrom<u16> for AmbientPressure {
75 type Error = DataError;
76
77 /// Create an [`AmbientPressure`] value for CO2 compensation. Value ranges are checked
78 ///
79 /// # Errors
80 ///
81 /// - [`ValueOutOfRange`](crate::error::DataError::ValueOutOfRange): If the ambient pressure is
82 /// not between 700 and 1,200 hPa.
83 fn try_from(value: u16) -> Result<Self, Self::Error> {
84 check_range(value, 700, 1_200, "Ambient Pressure", "hPa")?;
85 Ok(AmbientPressure(value))
86 }
87}
88
89impl TryFrom<&[u8]> for AmbientPressure {
90 type Error = DataError;
91
92 /// Parse the ambient pressure value from the received data.
93 ///
94 /// # Errors
95 ///
96 /// - [`CrcFailed`](crate::error::DataError::CrcFailed): If the received data CRC indicates
97 /// corruption.
98 /// - [`ReceivedBufferWrongSize`](crate::error::DataError::ReceivedBufferWrongSize): If the
99 /// received data buffer is not the expected size.
100 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
101 check_deserialization(data, 3)?;
102 Ok(AmbientPressure(u16::from_be_bytes([data[0], data[1]])))
103 }
104}
105
106impl From<AmbientPressure> for u16 {
107 fn from(value: AmbientPressure) -> Self {
108 value.0
109 }
110}
111
112impl Default for AmbientPressure {
113 /// Returns the default ambient pressure of 1,013 hPa.
114 fn default() -> Self {
115 Self(1013)
116 }
117}
118
119/// Sensor altitude for CO2 measurement compensation in m above sea level. Must be between 0 m and
120/// 3,000 m. The default value is 0 m.
121#[derive(Debug, PartialEq)]
122pub struct SensorAltitude(u16);
123
124impl TryFrom<u16> for SensorAltitude {
125 type Error = DataError;
126
127 /// Create an [`SensorAltitude`] value for CO2 compensation. Value ranges are checked.
128 ///
129 /// # Errors
130 ///
131 /// - [`ValueOutOfRange`](crate::error::DataError::ValueOutOfRange): If the sensor altitude is
132 /// not between 0 and 3,000 m.
133 fn try_from(value: u16) -> Result<Self, Self::Error> {
134 check_range(value, 0, 3_000, "Sensor Altitude", "m")?;
135 Ok(SensorAltitude(value))
136 }
137}
138
139impl TryFrom<&[u8]> for SensorAltitude {
140 type Error = DataError;
141
142 /// Parse the sensor altitude from the received data.
143 ///
144 /// # Errors
145 ///
146 /// - [`CrcFailed`](crate::error::DataError::CrcFailed): If the received data CRC indicates
147 /// corruption.
148 /// - [`ReceivedBufferWrongSize`](crate::error::DataError::ReceivedBufferWrongSize): If the
149 /// received data buffer is not the expected size.
150 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
151 check_deserialization(data, 3)?;
152 Ok(SensorAltitude(u16::from_be_bytes([data[0], data[1]])))
153 }
154}
155
156impl From<SensorAltitude> for u16 {
157 fn from(value: SensorAltitude) -> Self {
158 value.0
159 }
160}
161
162impl Default for SensorAltitude {
163 /// Returns the default ambient pressure of 1,013 hPa.
164 fn default() -> Self {
165 Self(0)
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 #[test]
174 fn target_co2_concentration_wraps_raw_value() {
175 let value = 12;
176 assert_eq!(u16::from(TargetCO2Concentration::from(value)), value)
177 }
178}