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
//! Interface for I2C master and slave peripherals.

use core::fmt::{Display, Formatter, Result};

/// The type of error encoutered during an I2C command transmission.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Error {
    /// The slave did not acknowledge the chip address. Most likely the address
    /// is incorrect or the slave is not properly connected.
    AddressNak,

    /// The data was not acknowledged by the slave.
    DataNak,

    /// Arbitration lost, meaning the state of the data line does not correspond
    /// to the data driven onto it. This can happen, for example, when a
    /// higher-priority transmission is in progress by a different master.
    ArbitrationLost,

    /// No error occured and the command completed successfully.
    CommandComplete,
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> Result {
        let display_str = match *self {
            Error::AddressNak => "I2C Address Not Acknowledged",
            Error::DataNak => "I2C Data Not Acknowledged",
            Error::ArbitrationLost => "I2C Bus Arbitration Lost",
            Error::CommandComplete => "I2C Command Completed",
        };
        write!(fmt, "{}", display_str)
    }
}

/// This specifies what type of transmission just finished from a Master device.
#[derive(Copy, Clone, Debug)]
pub enum SlaveTransmissionType {
    Write,
    Read,
}

/// Interface for an I2C Master hardware driver.
pub trait I2CMaster {
    fn enable(&self);
    fn disable(&self);
    fn write_read(&self, addr: u8, data: &'static mut [u8], write_len: u8, read_len: u8);
    fn write(&self, addr: u8, data: &'static mut [u8], len: u8);
    fn read(&self, addr: u8, buffer: &'static mut [u8], len: u8);
}

/// Interface for an I2C Slave hardware driver.
pub trait I2CSlave {
    fn enable(&self);
    fn disable(&self);
    fn set_address(&self, addr: u8);
    fn write_receive(&self, data: &'static mut [u8], max_len: u8);
    fn read_send(&self, data: &'static mut [u8], max_len: u8);
    fn listen(&self);
}

/// Convenience type for capsules that need hardware that supports both
/// Master and Slave modes.
pub trait I2CMasterSlave: I2CMaster + I2CSlave {}

/// Client interface for capsules that use I2CMaster devices.
pub trait I2CHwMasterClient {
    /// Called when an I2C command completed. The `error` denotes whether the command completed
    /// successfully or if an error occured.
    fn command_complete(&self, buffer: &'static mut [u8], error: Error);
}

/// Client interface for capsules that use I2CSlave devices.
pub trait I2CHwSlaveClient {
    /// Called when an I2C command completed.
    fn command_complete(
        &self,
        buffer: &'static mut [u8],
        length: u8,
        transmission_type: SlaveTransmissionType,
    );

    /// Called from the I2C slave hardware to say that a Master has sent us
    /// a read message, but the driver did not have a buffer containing data
    /// setup, and therefore cannot respond. The I2C slave hardware will stretch
    /// the clock while waiting for the upper layer capsule to provide data
    /// to send to the remote master. Call `I2CSlave::read_send()` to provide
    /// data.
    fn read_expected(&self);

    /// Called from the I2C slave hardware to say that a Master has sent us
    /// a write message, but there was no buffer setup to read the bytes into.
    /// The HW will stretch the clock while waiting for the user to call
    /// `I2CSlave::write_receive()` with a buffer.
    fn write_expected(&self);
}

/// Higher-level interface for I2C Master commands that wraps in the I2C
/// address. It gives an interface for communicating with a specific I2C
/// device.
pub trait I2CDevice {
    fn enable(&self);
    fn disable(&self);
    fn write_read(&self, data: &'static mut [u8], write_len: u8, read_len: u8);
    fn write(&self, data: &'static mut [u8], len: u8);
    fn read(&self, buffer: &'static mut [u8], len: u8);
}

/// Client interface for I2CDevice implementations.
pub trait I2CClient {
    /// Called when an I2C command completed. The `error` denotes whether the command completed
    /// successfully or if an error occured.
    fn command_complete(&self, buffer: &'static mut [u8], error: Error);
}