ezo_i2c_rs/
lib.rs

1//! # ezo_i2c_rs
2//!
3//! `ezo_i2c_rs` provides a simple interface to interact with Atlas Scientific Ezo Devices, using the I2C protocol.
4//!
5//! Built on top of the I2C embedded-hal abstraction this library is platform agnostic.
6
7use embedded_hal as hal;
8use hal::blocking::i2c;
9use std::error::Error as StdError;
10use std::result;
11use std::str;
12use std::str::Utf8Error;
13use std::thread;
14use std::time::Duration;
15use thiserror::Error;
16
17#[derive(Error, Debug)]
18pub enum EzoBoardError<E: StdError + 'static> {
19    /// Errors from I2C implementation
20    #[error(transparent)]
21    I2c(#[from] E),
22    /// UTF8 Error
23    #[error(transparent)]
24    Utf8Error(Utf8Error),
25    /// Read request returned Response Code 254
26    #[error("Read buffer is not ready")]
27    NotReady,
28    /// Read request returned Response Code 255
29    #[error("No Data To Send")]
30    NoDataToSend,
31    /// Read request returned Response Code 2
32    #[error("Syntax Error")]
33    SyntaxError,
34
35    #[error("unknown EzoReadError")]
36    Unknown,
37}
38
39///Newtype that encapsulates the I2C device and it's address.
40pub struct EzoBoard<I2C> {
41    i2c: I2C,
42    address: u8,
43}
44/// I2C must implement the embedded-hal traits for I2C. Specifically `Read` and `Write` are required.
45///
46/// https://docs.rs/embedded-hal/0.2.4/embedded_hal/blocking/i2c/index.html
47impl<I2C, E> EzoBoard<I2C>
48where
49    I2C: i2c::Read<Error = E> + i2c::Write<Error = E>,
50    E: std::error::Error,
51{
52    pub fn new(i2c: I2C, address: u8) -> Self {
53        EzoBoard { i2c, address }
54    }
55    /// Sends a command to the Ezo device and then sleep the specified delay. Does not sleep on delay if delay is `Duration:new(0,0)`
56    pub fn send_command(
57        &mut self,
58        command: &[u8],
59        delay: Duration,
60    ) -> result::Result<(), EzoBoardError<E>> {
61        self.i2c.write(self.address, command)?;
62        if delay != Duration::new(0, 0) {
63            thread::sleep(delay);
64        }
65        Ok(())
66    }
67    /// Reads from ezo device, checks response code and returns the result as a string for convenience.
68    pub fn read_response(&mut self) -> result::Result<String, EzoBoardError<E>> {
69        let mut buff: [u8; 40] = [0; 40];
70        self.i2c.read(self.address, &mut buff[..])?;
71        match &buff[0] {
72            1 => Ok(str::from_utf8(&buff[1..])
73                .map_err(EzoBoardError::Utf8Error)?
74                .to_string()),
75            2 => Err(EzoBoardError::SyntaxError),
76            254 => Err(EzoBoardError::NotReady),
77            255 => Err(EzoBoardError::NoDataToSend),
78            _ => Err(EzoBoardError::Unknown),
79        }
80    }
81}