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
123
124
125
126
127
128
129
// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option.  This file may not be copied, modified, or distributed
// except according to those terms.

use byteorder::{ByteOrder, LittleEndian};

/// Error that occured while performing and I2C Operation
#[derive(Debug)]
pub enum I2CError {
    NotSupported,
    Other(&'static str),
}

/// Result of an I2C Operation
pub type I2CResult<T> = Result<T, I2CError>;

/// Interface to an I2C Slave Device from an I2C Master
///
/// Typical implementations will store state with references to the bus
/// in use and the address of the slave device.  The trait is based on the
/// Linux i2cdev interface.
pub trait I2CDevice {
    /// Read data from the device to fill the provided slice
    fn read(&mut self, data: &mut [u8]) -> I2CResult<()>;

    /// Write the provided buffer to the device
    fn write(&mut self, data: &[u8]) -> I2CResult<()>;

    /*
     * The following implementations are defaults that seek to match the
     * kernel implementation where possible.
     */

    /// This sends a single bit to the device, at the place of the Rd/Wr bit
    #[allow(unused_variables)]
    fn smbus_write_quick(&mut self, bit: bool) -> I2CResult<()> {
        // not supported by default; cannot be expressed with read/write
        // but I'm not aware of any real use cases
        Err(I2CError::NotSupported)
    }

    /// Read a single byte from a device, without specifying a device register
    ///
    /// Some devices are so simple that this interface is enough; for
    /// others, it is a shorthand if you want to read the same register as in
    /// the previous SMBus command.
    fn smbus_read_byte(&mut self) -> I2CResult<u8> {
        let mut buf = [0_u8];
        try!(self.read(&mut buf));
        Ok(buf[0])
    }

    /// Write a single byte to a device, without specifying a device register
    ///
    /// This is the opposite operation as smbus_read_byte.  As with read_byte,
    /// no register is specified.
    fn smbus_write_byte(&mut self, value: u8) -> I2CResult<()> {
        self.write(&mut [value])
    }

    /// Read a single byte from a device, from a designated register
    ///
    /// The register is specified through the Comm byte.
    fn smbus_read_byte_data(&mut self, register: u8) -> I2CResult<u8> {
        try!(self.smbus_write_byte(register));
        self.smbus_read_byte()
    }

    /// Write a single byte to a specific register on a device
    ///
    /// The register is specified through the Comm byte.
    fn smbus_write_byte_data(&mut self, register: u8, value: u8) -> I2CResult<()> {
        self.write(&mut [register, value])
    }

    /// Read 2 bytes form a given register on a device (lsb first)
    fn smbus_read_word_data(&mut self, register: u8) -> I2CResult<u16> {
        let mut buf: [u8; 2] = [0x00; 2];
        try!(self.smbus_write_byte(register));
        try!(self.read(&mut buf));
        Ok(LittleEndian::read_u16(&buf))
    }

    /// Write 2 bytes to a given register on a device (lsb first)
    fn smbus_write_word_data(&mut self, register: u8, value: u16) -> I2CResult<()> {
        let mut buf: [u8; 3] = [register, 0, 0];
        LittleEndian::write_u16(&mut buf[1..], value);
        self.write(&buf)
    }

    /// Select a register, send 16 bits of data to it, and read 16 bits of data
    fn smbus_process_word(&mut self, register: u8, value: u16) -> I2CResult<u16> {
        let mut buf: [u8; 2] = [0x00; 2];
        try!(self.smbus_write_word_data(register, value));
        try!(self.read(&mut buf));
        Ok(LittleEndian::read_u16(&buf))
    }

    /// Read a block of up to 32 bytes from a device
    ///
    /// The actual number of bytes available to read is returned in the count
    /// byte.  This code returns a correctly sized vector containing the
    /// count bytes read from the device.
    #[allow(unused_variables)]
    fn smbus_read_block_data(&mut self, register: u8) -> I2CResult<Vec<u8>> {
        Err(I2CError::NotSupported)
    }

    /// Write a block of up to 32 bytes to a device
    ///
    /// The opposite of the Block Read command, this writes up to 32 bytes to
    /// a device, to a designated register that is specified through the
    /// Comm byte. The amount of data is specified in the Count byte.
    #[allow(unused_variables)]
    fn smbus_write_block_data(&mut self, register: u8, values: &[u8]) -> I2CResult<()> {
        Err(I2CError::NotSupported)
    }

    /// Select a register, send 1 to 31 bytes of data to it, and reads
    /// 1 to 31 bytes of data from it.
    #[allow(unused_variables)]
    fn smbus_process_block(&mut self, register: u8, values: &[u8]) -> I2CResult<()> {
        Err(I2CError::NotSupported)
    }
}