use crate::DeviceType;
pub(crate) struct Packet(pub [u8; 5]);
impl Packet {
pub fn measurement(&self) -> u16 {
let mut data_high: u16 = self.0[1] as u16;
let data_low: u16 = self.0[2] as u16;
data_high &= 0b00001111;
let mut airflow: u16 = 0;
airflow |= data_low;
airflow |= data_high << 8;
airflow
}
pub fn valid(&self) -> bool {
let sum: u8 = self.0.iter().skip(1).fold(0u8, |a, b| a.wrapping_add(*b));
let crcbyte = self.0[0];
let overall = sum.wrapping_add(crcbyte);
overall == 0x00
}
}
pub(crate) fn raw_to_meters_per_second<D: DeviceType>(measurement: u16) -> f32 {
let translation_points = D::datapoints();
let Some(index) = translation_points
.iter()
.enumerate()
.rev()
.find(|(_, (raw, _))| measurement >= *raw)
.map(|(index, _)| index)
else {
return 0.0;
};
let (lower, higher) = match (
translation_points.get(index),
translation_points.get(index + 1),
) {
(Some(lower), Some(higher)) => (lower, higher),
(Some(lower), None) => return lower.1,
_ => unreachable!("lower index must always exist"),
};
let window_size = higher.0 - lower.0;
let difference_to_bottom = measurement - lower.0;
let window_percentage = (difference_to_bottom as f32) / window_size as f32;
let window_size_meters_per_second = higher.1 - lower.1;
lower.1 + (window_size_meters_per_second * window_percentage)
}
#[cfg(test)]
mod tests {
use crate::FS3000_1005;
use super::*;
#[test]
fn test_checksum() {
let packet = Packet([0x00, 0x01, 0x02, 0x03, 0x04]);
assert!(!packet.valid());
let packet = Packet([0xCC, 0x01, 0x99, 0x01, 0x99]);
assert!(packet.valid());
}
#[test]
fn test_raw_to_meters_per_second_1005() {
macro_rules! assert_with_error {
($input:expr, $b:expr) => {
let result = raw_to_meters_per_second::<FS3000_1005>($input);
let diff = (result - $b).abs();
assert!(
diff < 1e-3,
"Expected {} and got {}, which differs by {} (allowed error 1e-3) for input {}",
$b,
result,
diff,
$input
);
};
}
assert_with_error!(409, 0.0);
assert_with_error!(915, 1.07);
assert_with_error!(1522, 2.01);
assert_with_error!(3686, 7.23);
let mid = (915 + 1522) / 2;
let expected = (1.07 + 2.01) / 2.0;
assert_with_error!(mid, expected);
}
}