1#![deny(unsafe_code)]
13#![deny(missing_docs)]
14#![no_std]
15
16use arrayvec::ArrayVec;
17use core::convert::From;
18use ieee754::*;
19use nb::Error as nbError;
20use sensirion_hdlc::{decode, encode, HDLCError, SpecialChars};
21
22const MAX_BUFFER: usize = 600;
24
25#[derive(Debug)]
27pub enum Error<E, F> {
28 SerialR(nb::Error<F>),
30 SerialW(E),
32 SHDLC(HDLCError),
34 InvalidFrame,
38 EmptyResult,
40 ChecksumFailed,
42 InvalidRespose,
44 StatusError,
46}
47
48impl<E, F> From<nbError<F>> for Error<E, F> {
49 fn from(f: nbError<F>) -> Self {
50 Error::SerialR(f)
51 }
52}
53
54#[repr(u8)]
56pub enum DeviceInfo {
57 ProductName = 1,
59 ArticleCode = 2,
61 SerialNumber = 3,
63}
64
65#[repr(u8)]
67pub enum CommandType {
68 StartMeasurement = 0,
70 StopMeasurement = 1,
72 ReadMeasuredData = 3,
74 ReadWriteAutoCleaningInterval = 0x80,
76 StartFanCleaning = 0x56,
78 DeviceInformation = 0xD0,
80 Reset = 0xD3,
82}
83
84fn compute_cksum(data: &[u8]) -> u8 {
86 let mut cksum: u8 = 0;
87 for &byte in data.iter() {
88 let val: u16 = cksum as u16 + byte as u16;
89 let lsb = val % 256;
90 cksum = lsb as u8;
91 }
92
93 255 - cksum
94}
95
96#[derive(Debug, Default)]
98pub struct Sps30<SERIAL> {
99 serial: SERIAL,
101}
102
103impl<SERIAL, E, F> Sps30<SERIAL>
104where
105 SERIAL: embedded_hal::blocking::serial::Write<u8, Error = E>
106 + embedded_hal::serial::Read<u8, Error = F>,
107{
108 pub fn new(serial: SERIAL) -> Self {
110 Sps30 { serial }
111 }
112
113 fn send_uart_data(&mut self, data: &[u8]) -> Result<(), Error<E, F>> {
115 let s_chars = SpecialChars::default();
116 let output = encode(&data, s_chars).unwrap();
117 self.serial.bwrite_all(&output).map_err(Error::SerialW)
120 }
121
122 fn read_uart_data(&mut self) -> Result<ArrayVec<[u8; 1024]>, Error<E, F>> {
128 let mut output = ArrayVec::<[u8; 1024]>::new();
129
130 let mut seen = 0;
131 while seen != 2 {
132 let byte = self.serial.read();
133 match byte {
134 Ok(value) => {
135 if value == 0x7e {
136 seen += 1;
137 }
138 output.push(value);
139 }
140 Err(e) => {
141 return Err(Error::from(e));
142 }
143 }
144 if output.len() > MAX_BUFFER {
145 return Err(Error::InvalidFrame);
146 }
147 }
148
149 match decode(&output, SpecialChars::default()) {
150 Ok(v) => {
151 if v[v.len() - 1] == compute_cksum(&v[..v.len() - 1]) {
152 return Ok(v);
153 }
154
155 Err(Error::ChecksumFailed)
156 }
157 Err(e) => Err(Error::SHDLC(e)),
158 }
159 }
160
161 fn check_miso_frame<'a>(
167 &self,
168 data: &'a [u8],
169 cmd_type: CommandType,
170 ) -> Result<&'a [u8], Error<E, F>> {
171 if data.len() < 5 {
172 return Err(Error::InvalidRespose);
173 }
174
175 if data[1] != cmd_type as u8 {
176 return Err(Error::InvalidRespose);
177 }
178 if data[2] != 0 {
179 return Err(Error::StatusError);
180 }
181
182 if data[3] as usize != data.len() - 5 {
183 return Err(Error::InvalidRespose);
184 }
185
186 Ok(data)
189 }
190
191 pub fn start_measurement(&mut self) -> Result<(), Error<E, F>> {
193 let mut output = ArrayVec::<[u8; 1024]>::new();
194 let cmd = [0x00, 0x00, 0x02, 0x01, 0x03];
195 for item in &cmd {
196 output.push(*item);
197 }
198 output.push(compute_cksum(&output));
199 self.send_uart_data(&output)?;
200
201 match self.read_uart_data() {
202 Ok(response) => self
203 .check_miso_frame(&response, CommandType::StartMeasurement)
204 .map(|_| ()),
205 Err(e) => Err(e),
206 }
207 }
208
209 pub fn stop_measurement(&mut self) -> Result<(), Error<E, F>> {
211 let mut output = ArrayVec::<[u8; 1024]>::new();
212 let cmd = [0x00, 0x01, 0x00];
213 for item in &cmd {
214 output.push(*item);
215 }
216 output.push(compute_cksum(&output));
217 self.send_uart_data(&output)?;
218
219 match self.read_uart_data() {
220 Ok(response) => self
221 .check_miso_frame(&response, CommandType::StopMeasurement)
222 .map(|_| ()),
223 Err(e) => Err(e),
224 }
225 }
226
227 pub fn read_measurement(&mut self) -> Result<[f32; 10], Error<E, F>> {
229 let mut output = ArrayVec::<[u8; 1024]>::new();
230 let cmd = [0x00, 0x03, 0x00];
231 for item in &cmd {
232 output.push(*item);
233 }
234 output.push(compute_cksum(&cmd));
235 self.send_uart_data(&output)?;
236
237 let data = self.read_uart_data();
238
239 let mut res: [f32; 10] = [0.0; 10];
240 match data {
241 Ok(v) => match v.len() {
242 45 => {
243 self.check_miso_frame(&v, CommandType::ReadMeasuredData)?;
244 for i in 0..res.len() {
245 let mut bits: u32 = 0;
246 for &byte in v[4 + 4 * i..4 + 4 * (i + 1)].iter() {
247 bits = (bits << 8) + byte as u32;
248 }
249 res[i] = Ieee754::from_bits(bits);
250 }
251 Ok(res)
252 }
253 5 => Err(Error::EmptyResult),
254 _ => Err(Error::InvalidFrame),
255 },
256 Err(e) => Err(e),
257 }
258 }
259
260 pub fn read_cleaning_interval(&mut self) -> Result<u32, Error<E, F>> {
262 let mut output = ArrayVec::<[u8; 1024]>::new();
263 let cmd = [0x00, 0x80, 0x01, 0x00];
264 for item in &cmd {
265 output.push(*item);
266 }
267 output.push(compute_cksum(&output));
268 self.send_uart_data(&output)?;
269
270 match self.read_uart_data() {
271 Ok(response) => {
272 match self.check_miso_frame(&response, CommandType::ReadWriteAutoCleaningInterval) {
273 Ok(v) => {
274 if v[3] != 4 {
275 return Err(Error::InvalidRespose);
276 }
277
278 let mut ret: u32 = 0;
279 for &byte in v[4..8].iter() {
280 ret = ret * 256 + byte as u32;
281 }
282 Ok(ret)
283 }
284 Err(e) => Err(e),
285 }
286 }
287 Err(e) => Err(e),
288 }
289 }
290
291 pub fn write_cleaning_interval(&mut self, val: u32) -> Result<(), Error<E, F>> {
293 let mut output = ArrayVec::<[u8; 1024]>::new();
294 let cmd = [0x00, 0x80, 0x05, 0x00];
295 for item in &cmd {
296 output.push(*item);
297 }
298 for item in &val.to_be_bytes() {
299 output.push(*item);
300 }
301 output.push(compute_cksum(&output));
302 self.send_uart_data(&output)?;
303
304 match self.read_uart_data() {
305 Ok(response) => {
306 match self.check_miso_frame(&response, CommandType::ReadWriteAutoCleaningInterval) {
307 Ok(v) => {
308 if v[3] != 0 {
309 return Err(Error::InvalidRespose);
310 }
311 Ok(())
312 }
313 Err(e) => Err(e),
314 }
315 }
316 Err(e) => Err(e),
317 }
318 }
319
320 pub fn start_fan_cleaning(&mut self) -> Result<(), Error<E, F>> {
322 let mut output = ArrayVec::<[u8; 1024]>::new();
323 let cmd = [0x00, 0x56, 0x00];
324 for item in &cmd {
325 output.push(*item);
326 }
327 output.push(compute_cksum(&output));
328 self.send_uart_data(&output)?;
329
330 match self.read_uart_data() {
331 Ok(response) => self
332 .check_miso_frame(&response, CommandType::StartFanCleaning)
333 .map(|_| ()),
334 Err(e) => Err(e),
335 }
336 }
337
338 pub fn device_info(&mut self, info: DeviceInfo) -> Result<[u8; 32], Error<E, F>> {
342 let mut output = ArrayVec::<[u8; 1024]>::new();
343 let cmd = [0x00, 0xD0, 0x01];
344 for item in &cmd {
345 output.push(*item);
346 }
347 output.push(info as u8);
348 output.push(compute_cksum(&output));
349 self.send_uart_data(&output)?;
350
351 match self.read_uart_data() {
352 Ok(response) => {
353 match self.check_miso_frame(&response, CommandType::DeviceInformation) {
354 Ok(val) => {
355 let mut ret: [u8; 32] = [0; 32];
356 if val[3] < 33 {
357 for i in 0..val[3] {
358 ret[i as usize] = val[3 + i as usize];
359 }
360 return Ok(ret);
361 }
362 Err(Error::EmptyResult)
363 }
364 Err(e) => Err(e),
365 }
366 }
367 Err(e) => Err(e),
368 }
369 }
370
371 pub fn reset(&mut self) -> Result<(), Error<E, F>> {
375 let mut output = ArrayVec::<[u8; 1024]>::new();
376 let cmd = [0x00, 0xD3, 0x00];
377 for item in &cmd {
378 output.push(*item);
379 }
380 output.push(compute_cksum(&output));
381 self.send_uart_data(&output)?;
382
383 match self.read_uart_data() {
384 Ok(response) => self
385 .check_miso_frame(&response, CommandType::Reset)
386 .map(|_| ()),
387 Err(e) => Err(e),
388 }
389 }
390}
391
392#[cfg(test)]
393mod tests {
394 #[test]
395 fn it_works() {
396 assert_eq!(2 + 2, 4);
397 }
398}