pamoja_sensors/scd4x/
sim.rs1use pamoja_hal::sim::CommandPart;
10
11use super::{command, command_frame, serial_number_frame, word_frame, Measurement, I2C_ADDRESS};
12
13pub const CO2_PPM: u16 = 800;
15
16pub const CELSIUS: f32 = 22.5;
18
19pub const RELATIVE_HUMIDITY: f32 = 45.0;
21
22pub const SERIAL: u64 = 0x0000_5A4D_0C1E_2B3F;
24
25const DATA_READY: u16 = 0x0001;
27
28#[must_use]
34pub fn part() -> CommandPart {
35 reporting(CO2_PPM, CELSIUS, RELATIVE_HUMIDITY)
36}
37
38#[must_use]
62pub fn reporting(co2_ppm: u16, celsius: f32, relative_humidity: f32) -> CommandPart {
63 let milli_celsius = rounded(celsius * 1000.0);
64 let milli_percent = rounded(relative_humidity.max(0.0) * 1000.0) as u32;
65 let reading = Measurement::from_physical(co2_ppm, milli_celsius, milli_percent).to_bytes();
66 CommandPart::new(I2C_ADDRESS, 2)
67 .answering(
68 &command_frame(command::GET_SERIAL_NUMBER),
69 &serial_number_frame(SERIAL),
70 )
71 .answering(
72 &command_frame(command::GET_DATA_READY_STATUS),
73 &word_frame(DATA_READY),
74 )
75 .answering(&command_frame(command::READ_MEASUREMENT), &reading)
76}
77
78fn rounded(value: f32) -> i32 {
80 if value >= 0.0 {
81 (value + 0.5) as i32
82 } else {
83 (value - 0.5) as i32
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use crate::scd4x::{data_ready, Scd4x};
91 use pamoja_hal::script::DelayLog;
92
93 #[test]
94 fn the_word_says_a_reading_is_waiting() {
95 assert!(data_ready(DATA_READY));
96 }
97
98 #[test]
99 fn the_driver_starts_the_part_and_reads_it() {
100 let mut sensor = Scd4x::new(part(), DelayLog::new());
101 let reading = sensor.measure().expect("a reading");
102 assert_eq!(reading.co2_ppm, CO2_PPM);
103 assert!((reading.celsius() - CELSIUS).abs() < 0.003);
104 assert!((reading.relative_humidity_percent() - RELATIVE_HUMIDITY).abs() < 0.002);
105 assert_eq!(sensor.serial(), Some(SERIAL));
106
107 let mut single = Scd4x::new(reporting(3_000, -5.0, 20.0), DelayLog::new());
108 let reading = single.measure_single_shot().expect("a reading");
109 assert_eq!(reading.co2_ppm, 3_000);
110 assert!((reading.celsius() + 5.0).abs() < 0.003);
111 }
112}