embassy_scd41_sensor/
scd41_rp.rs1use crate::{SCD41Error, SCD41Response};
2use embassy_time::Duration;
3use embedded_hal_async::i2c::I2c;
4
5pub struct SCD41Sensor {
6 address: u8,
7 initialization_step: InitializationStep,
8 last_response: Option<SCD41Response>,
9 next_step_time: embassy_time::Instant,
10}
11
12impl SCD41Sensor {
13 pub fn new(address: u8) -> Self {
14 Self {
15 address,
16 initialization_step: InitializationStep::Initial,
17 last_response: None,
18 next_step_time: embassy_time::Instant::now(),
19 }
20 }
21
22 pub async fn read<'d, I: embassy_rp::i2c::Instance>(
23 &mut self,
24 i2c: &mut embassy_rp::i2c::I2c<'d, I, embassy_rp::i2c::Async>,
25 ) -> Result<SCD41Response, SCD41Error> {
26 let now = embassy_time::Instant::now();
27 if now < self.next_step_time {
28 return if let Some(response) = &self.last_response {
29 Ok(response.clone())
30 } else {
31 Err(SCD41Error::NoData)
32 };
33 }
34 match self.initialization_step {
35 InitializationStep::Initial => {
36 self.initialization_step = InitializationStep::StopMeasurement;
37 self.next_step_time = now + Duration::from_millis(1000);
38 Err(SCD41Error::NoData)
39 }
40 InitializationStep::StopMeasurement => {
41 self.initialization_step = InitializationStep::Reinit;
42 self.next_step_time = now + Duration::from_millis(1000);
43 self.i2c_write(i2c, &[0x3f, 0x86]).await?;
44 Err(SCD41Error::NoData)
45 }
46 InitializationStep::Reinit => {
47 self.initialization_step = InitializationStep::StartMeasurement;
48 self.next_step_time = now + Duration::from_millis(1000);
49 self.i2c_write(i2c, &[0x36, 0x46]).await?;
50 Err(SCD41Error::NoData)
51 }
52 InitializationStep::StartMeasurement => {
53 self.initialization_step = InitializationStep::ReadData;
54 self.next_step_time = now + Duration::from_millis(1000);
55 self.i2c_write(i2c, &[0x21, 0xb1]).await?;
56 Err(SCD41Error::NoData)
57 }
58 InitializationStep::ReadData => {
59 self.next_step_time = now + Duration::from_millis(5000);
60 let mut buf = [0u8; 9];
61 self.i2c_write_read(i2c, &[0xe4, 0xb8], &mut buf).await?;
62 if buf[1] == 0x0 {
63 self.next_step_time = now + Duration::from_millis(1000);
64 Err(SCD41Error::NoData)
65 } else {
66 self.i2c_write_read(i2c, &[0xec, 0x05], &mut buf).await?;
67 let delimiter = 0xffff as f32;
68 let co2_ppm = i16::from_be_bytes([buf[0], buf[1]]) as f32;
69 let temperature_data = i16::from_be_bytes([buf[3], buf[4]]) as f32;
70 let temperature = -45f32 + 175f32 * temperature_data / delimiter;
71 let humidity_data = i16::from_be_bytes([buf[6], buf[7]]) as f32;
72 let humidity = 100f32 * (humidity_data / delimiter);
73 let response = SCD41Response {
74 co2: co2_ppm,
75 temperature,
76 humidity,
77 };
78 self.last_response = Some(response.clone());
79 Ok(response)
80 }
81 }
82 }
83 }
84
85 async fn i2c_write_read<'d, I : embassy_rp::i2c::Instance>(&mut self,
86 i2c: &mut embassy_rp::i2c::I2c<'d, I, embassy_rp::i2c::Async>,
87 write: &[u8], read: &mut [u8]) -> Result<(), SCD41Error> {
88 match i2c.write_read(self.address, write, read).await {
89 Ok(_) => Ok(()),
90 Err(_) => Err(SCD41Error::I2CError),
91 }
92 }
93
94 async fn i2c_write<'d, I : embassy_rp::i2c::Instance>(&mut self,
95 i2c: &mut embassy_rp::i2c::I2c<'d, I, embassy_rp::i2c::Async>,
96 write: &[u8]) -> Result<(), SCD41Error> {
97 match i2c.write(self.address, write).await {
98 Ok(_) => Ok(()),
99 Err(_) => Err(SCD41Error::I2CError),
100 }
101 }
102}
103
104enum InitializationStep {
105 Initial,
106 StopMeasurement,
107 Reinit,
108 StartMeasurement,
109 ReadData,
110}