1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
//! An API to communicate with PCF8591 A/D converter //! //! [Official doc](http://www.nxp.com/documents/data_sheet/PCF8591.pdf#G1004142294) //! //! # Examples //! //! ```rust,should_panic //! use pcf8591::{PCF8591, Pin}; //! use std::thread; //! use std::time::Duration; //! //! // Gets default location on raspberry pi (rev 2) //! let mut converter = PCF8591::new("/dev/i2c-1", 0x48, 3.3).unwrap(); //! //! loop { //! let v = converter.analog_read(Pin::AIN0).unwrap(); //! println!("Input voltage at pin 0: {}", v); //! //! thread::sleep(Duration::from_millis(1000)); //! } //! ``` #![deny(missing_docs)] extern crate i2cdev; use std::path::Path; use i2cdev::linux::LinuxI2CDevice; use i2cdev::core::I2CDevice; pub use i2cdev::linux::LinuxI2CError; /// Wrapper over LinuxI2CError pub type Result<T> = ::std::result::Result<T, LinuxI2CError>; /// A struct to handle PCF8591 converter /// /// Allow user to read from given input pin and write to output pin pub struct PCF8591 { i2c: LinuxI2CDevice, pin: Option<Pin>, v_lsb: f64, } /// An input Pin enumeration corresponding to the physical analog inputs pins #[derive(Debug, Clone, Copy, PartialEq)] pub enum Pin { /// Input Pin 0 AIN0, /// Input Pin 1 AIN1, /// Input Pin 2 AIN2, /// Input Pin 3 AIN3, } impl PCF8591 { /// Creates a new connection given i2c path and address /// /// - `path`: device slave path (0x48 per default) /// - `address`: has to be defined as per Table 5. /// - `v_ref`: is the board voltage (e.g. typically 3.3V on raspberry pi) pub fn new<P: AsRef<Path>>(path: P, address: u16, v_ref: f64) -> Result<PCF8591> { LinuxI2CDevice::new(path, address) .map(|i2c| PCF8591 { i2c: i2c, pin: None, v_lsb: v_ref / 255., }) } /// Reads analog values out of input pin and output digital byte /// /// The conversion with board voltage is left to the user. /// For automatic conversion, use `analog_read` pub fn analog_read_byte(&mut self, pin: Pin) -> Result<u8> { match self.pin { Some(ref p) if *p == pin => (), _ => { // need to change control_byte, as per Fig 4. let control_byte = match pin { Pin::AIN0 => 0x40, Pin::AIN1 => 0x41, Pin::AIN2 => 0x42, Pin::AIN3 => 0x43, }; let _ = try!(self.i2c.smbus_write_byte(control_byte)); let _ = try!(self.i2c.smbus_read_byte()); // previous byte, unspecified self.pin = Some(pin); } } self.i2c.smbus_read_byte() } /// Reads analog values out of input pin and output corresponding input voltage /// /// Returns analog_read_byte * v_ref / 255 (suppose Vagnd == 0) pub fn analog_read(&mut self, pin: Pin) -> Result<f64> { // converts read byte as per Fig. 9 self.analog_read_byte(pin) .map(|b| b as f64 * self.v_lsb) } /// Writes analog values, as byte, in the output pin /// /// The conversion with board voltage is left to the user /// For automatic conversion, use `analog_write` pub fn analog_write_byte(&mut self, value: u8) -> Result<()> { self.pin = None; // if we send 3 bytes, then it is a D/A conversion self.i2c.write(&[0x40, value]) } /// Writes analog values in the output pin pub fn analog_write(&mut self, v_out: f64) -> Result<()> { let value = (v_out / self.v_lsb) as u8; self.analog_write_byte(value) } }