1#[derive(Debug)]
2pub struct CalibrationData {
3 pub par_t1: u16,
5 pub par_t2: i16,
6 pub par_t3: i8,
7 pub par_p1: u16,
9 pub par_p2: i16,
10 pub par_p3: i8,
11 pub par_p4: i16,
12 pub par_p5: i16,
13 pub par_p6: i8,
14 pub par_p7: i8,
15 pub par_p8: i16,
16 pub par_p9: i16,
17 pub par_p10: u8,
18 pub par_h1: u16,
20 pub par_h2: u16,
21 pub par_h3: i8,
22 pub par_h4: i8,
23 pub par_h5: i8,
24 pub par_h6: u8,
25 pub par_h7: i8,
26 pub par_gh1: i8,
28 pub par_gh2: i16,
29 pub par_gh3: i8,
30
31 pub res_heat_range: u8,
33 pub res_heat_val: i8,
34 pub range_sw_err: i8,
35}
36
37#[derive(Debug)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize))]
40pub struct MeasurmentData {
41 pub temperature: f32,
43 pub humidity: f32,
45 pub pressure: f32,
47 pub gas_resistance: Option<f32>,
50}
51
52impl MeasurmentData {
53 pub(crate) fn from_raw(
54 raw_data: crate::bitfields::RawData<[u8; 15]>,
55 calibration_data: &CalibrationData,
56 variant: &crate::config::Variant,
57 ) -> Option<Self> {
58 if raw_data.measuring() && !raw_data.new_data() {
60 return None;
61 }
62 let (temperature, t_fine) =
63 crate::calculate_temperature(raw_data.temperature_adc().0, calibration_data);
64 let pressure =
65 crate::calculate_pressure(raw_data.pressure_adc().0, calibration_data, t_fine);
66 let humidity =
67 crate::calculate_humidity(raw_data.humidity_adc().0, calibration_data, t_fine);
68 let gas_resistance = if raw_data.gas_valid() && !raw_data.gas_measuring() {
69 let gas_resistance = variant.calc_gas_resistance(
70 raw_data.gas_adc().0,
71 calibration_data.range_sw_err,
72 raw_data.gas_range() as usize,
73 );
74 Some(gas_resistance)
75 } else {
76 None
77 };
78
79 Some(MeasurmentData {
80 temperature,
81 gas_resistance,
82 humidity,
83 pressure,
84 })
85 }
86}
87
88pub fn calculate_temperature(adc_temp: u32, calibration_data: &CalibrationData) -> (f32, f32) {
89 let temp_adc = adc_temp as f32;
90 let var_1 = ((temp_adc / 16384.) - (calibration_data.par_t1 as f32 / 1024.))
91 * calibration_data.par_t2 as f32;
92 let var_2 = (((temp_adc / 131072.) - (calibration_data.par_t1 as f32 / 8192.))
93 * ((temp_adc / 131072.) - (calibration_data.par_t1 as f32 / 8192.)))
94 * (calibration_data.par_t3 as f32 * 16.);
95 let t_fine = var_1 + var_2;
97 let calc_temp = t_fine / 5120.;
98 (calc_temp, t_fine)
99}
100
101pub fn calculate_pressure(adc_press: u32, calibration_data: &CalibrationData, t_fine: f32) -> f32 {
102 let adc_press = adc_press as f32;
103 let var1 = (t_fine / 2.) - 64000.;
104 let var2 = var1 * var1 * (calibration_data.par_p6 as f32 / 131072.);
105 let var2 = var2 + (var1 * calibration_data.par_p5 as f32 * 2.);
106 let var2 = (var2 / 4.) + (calibration_data.par_p4 as f32 * 65536.);
107 let var1 = (((calibration_data.par_p3 as f32 * var1 * var1) / 16384.)
108 + (calibration_data.par_p2 as f32 * var1))
109 / 524288.;
110 let var1 = (1. + (var1 / 32768.)) * calibration_data.par_p1 as f32;
111 let mut calc_pres = 1048576. - adc_press;
112 if var1 as i16 != 0 {
113 calc_pres = ((calc_pres - (var2 / 4096.)) * 6250.) / var1;
114 let var1 = (calibration_data.par_p9 as f32 * calc_pres * calc_pres) / 2147483648.;
115 let var2 = calc_pres * (calibration_data.par_p8 as f32 / 32768.);
116 let var3 = (calc_pres / 256.)
117 * (calc_pres / 256.)
118 * (calc_pres / 256.)
119 * (calibration_data.par_p10 as f32 / 131072.);
120 calc_pres += (var1 + var2 + var3 + (calibration_data.par_p7 as f32 * 128.)) / 16.;
121 } else {
122 calc_pres = 0.;
123 }
124 calc_pres
125}
126
127pub fn calculate_humidity(adc_hum: u16, calibration_data: &CalibrationData, t_fine: f32) -> f32 {
128 let adc_hum = adc_hum as f32;
129 let temp_comp = t_fine / 5120.;
130 let var1 = (adc_hum)
131 - ((calibration_data.par_h1 as f32 * 16.)
132 + ((calibration_data.par_h3 as f32 / 2.) * temp_comp));
133 let var2 = var1
134 * ((calibration_data.par_h2 as f32 / 262144.)
135 * (1.
136 + ((calibration_data.par_h4 as f32 / 16384.) * temp_comp)
137 + ((calibration_data.par_h5 as f32 / 1048576.) * temp_comp * temp_comp)));
138 let var3 = calibration_data.par_h6 as f32 / 16384.;
139 let var4 = calibration_data.par_h7 as f32 / 2097152.;
140 let mut calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2);
141 calc_hum = calc_hum.clamp(0., 100.);
142 calc_hum
149}
150
151#[cfg(test)]
152mod tests {
153 use crate::data::{
154 calculate_humidity, calculate_pressure, calculate_temperature, CalibrationData,
155 };
156 use approx::assert_abs_diff_eq;
157
158 static CALIBRATION_DATA: CalibrationData = CalibrationData {
159 par_t1: 25942,
160 par_t2: 26664,
161 par_t3: 3,
162 par_p1: 37439,
163 par_p2: -10316,
164 par_p3: 88,
165 par_p4: 10477,
166 par_p5: -308,
167 par_p6: 30,
168 par_p7: 62,
169 par_p8: -5160,
170 par_p9: -1568,
171 par_p10: 30,
172 par_h1: 881,
173 par_h2: 989,
174 par_h3: 0,
175 par_h4: 45,
176 par_h5: 20,
177 par_h6: 120,
178 par_h7: -100,
179 par_gh1: -69,
180 par_gh2: -9092,
181 par_gh3: 18,
182 res_heat_range: 1,
183 res_heat_val: 30,
184 range_sw_err: 0,
185 };
186
187 #[test]
188 fn test_calc_temp() {
189 let data = [
196 (482062, 21.295866, 109034.835938),
197 (482452, 21.419861, 109669.687500),
198 (482060, 21.295231, 109031.585938),
199 (482453, 21.420179, 109671.320312),
200 (482058, 21.294596, 109028.328125),
201 ];
202 for (temp_adc, actual_temp, actual_tfine) in data {
203 let (temp, calc_tfine) = calculate_temperature(temp_adc, &CALIBRATION_DATA);
204
205 assert_abs_diff_eq!(actual_temp, temp);
206 assert_abs_diff_eq!(actual_tfine, calc_tfine);
207 }
208 }
209 #[test]
210 fn test_calc_humidity() {
211 let pairs = [
218 (25537, 59.469585, 109842.234375),
219 (25531, 59.410557, 109090.187500),
220 (25545, 59.515030, 109643.640625),
221 (25535, 59.431923, 108942.054688),
222 (25549, 59.537392, 109531.328125),
223 ];
224 for (hum_adc, actual_hum, tfine) in pairs {
225 let calc_hum = calculate_humidity(hum_adc, &CALIBRATION_DATA, tfine);
226 assert_abs_diff_eq!(calc_hum, actual_hum);
227 }
228 }
229 #[test]
230 fn test_calc_pressure() {
231 let data = [
237 (307582, 95058.664062, 111095.656250),
238 (307395, 95058.992188, 110130.359375),
239 (307469, 95059.296875, 110525.921875),
240 (307313, 95058.773438, 109695.726562),
241 (307254, 95060.328125, 109436.914062),
242 ];
243 for (press_adc, actual_press, tfine) in data {
244 let calc_press = calculate_pressure(press_adc, &CALIBRATION_DATA, tfine);
245 assert_abs_diff_eq!(calc_press, actual_press);
246 }
247 }
248}