embedded_drivers/
pmsx003.rs1use core::convert::TryInto;
6use embedded_hal::serial;
7use nb::block;
8
9const PREFIX1: u8 = 0x42;
10const PREFIX2: u8 = 0x4d;
11
12pub struct PMSx003<S> {
13 serial: S,
14}
15
16pub struct Measurements {
17 pub cf1_pm1_0: u16,
18 pub cf1_pm2_5: u16,
19 pub cf1_pm10: u16,
20 pub pm1_0: u16,
21 pub pm2_5: u16,
22 pub pm10: u16,
23 pub db0_3_um: u16,
24 pub db0_5_um: u16,
25 pub db1_0_um: u16,
26 pub db2_5_um: u16,
27 pub db5_0_um: u16,
28 pub db10_um: u16,
29}
30
31impl Measurements {
32 pub fn is_ready(&self) -> bool {
34 self.db0_3_um != 0 || self.db0_5_um != 0 || self.db1_0_um != 0
35 }
36}
37
38impl<S> PMSx003<S>
39where
40 S: serial::Read<u8> + serial::Write<u8>,
41{
42 pub fn new(serial: S) -> Self {
43 Self { serial }
44 }
45
46 pub fn read_measurements(&mut self) -> Result<Measurements, ()> {
47 const PREFIX: [u8; 4] = [PREFIX1, PREFIX2, 0x00, 0x1c];
49
50 let mut i = 0;
51 let mut buf = [0u8; 26];
52 let mut checksum: u16 = 0;
53
54 loop {
55 let c = self.must_read_byte();
56 match i {
57 0..=3 if c == PREFIX[i] => {
58 checksum += c as u16;
59 i += 1;
60 }
61 4..=29 => {
62 checksum += c as u16;
63 buf[i - 4] = c;
64 i += 1;
65 }
66 30 if c == (checksum >> 8) as u8 => {
67 i += 1;
68 }
69 31 if c == (checksum & 0xff) as u8 => {
70 break;
71 }
72 _ => {
73 i = 0;
74 checksum = 0;
75 }
76 }
77 }
78
79 Ok(Measurements {
80 cf1_pm1_0: u16::from_be_bytes(buf[0..2].try_into().unwrap()),
81 cf1_pm2_5: u16::from_be_bytes(buf[2..4].try_into().unwrap()),
82 cf1_pm10: u16::from_be_bytes(buf[4..6].try_into().unwrap()),
83 pm1_0: u16::from_be_bytes(buf[6..8].try_into().unwrap()),
84 pm2_5: u16::from_be_bytes(buf[8..10].try_into().unwrap()),
85 pm10: u16::from_be_bytes(buf[10..12].try_into().unwrap()),
86 db0_3_um: u16::from_be_bytes(buf[12..14].try_into().unwrap()),
87 db0_5_um: u16::from_be_bytes(buf[14..16].try_into().unwrap()),
88 db1_0_um: u16::from_be_bytes(buf[16..18].try_into().unwrap()),
89 db2_5_um: u16::from_be_bytes(buf[18..20].try_into().unwrap()),
90 db5_0_um: u16::from_be_bytes(buf[20..22].try_into().unwrap()),
91 db10_um: u16::from_be_bytes(buf[22..24].try_into().unwrap()),
92 })
93 }
94
95 pub fn release(self) -> S {
96 self.serial
97 }
98
99 fn must_read_byte(&mut self) -> u8 {
100 loop {
101 if let Ok(b) = self.read_byte() {
102 return b;
103 }
104 }
105 }
106
107 fn read_byte(&mut self) -> Result<u8, ()> {
108 block!(self.serial.read()).map_err(|_| ())
109 }
110}