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
//! Definitions for I²C peripherals.
use crate::io;
use core::fmt;
use core::pin;
use core::task;

pub mod begin_read;
pub mod begin_write;
pub mod initialize;

/// A peripheral that can perform I²C read operations.
// TODO: this should maybe capture the lifetime of self and let it flow into Self::Read
pub trait I2cRead: fmt::Debug {
    /// The common error type for I²C read operations.
    ///
    /// A single error type for all operations is enforced for simplicity.
    type Error;
    /// An object that can be used to complete the read operation.
    type Read: io::Read + Unpin;

    /// Polls the start of a read operation to completion.
    fn poll_begin_read(
        self: pin::Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        addr: u8,
    ) -> task::Poll<Result<Self::Read, Self::Error>>;
}

/// Extension functions for instances of [`I2cRead`].
// TODO: this should maybe capture the lifetime of self and let it flow into Self::Read
pub trait I2cReadExt: I2cRead {
    /// Initiates a read operation on the specified address.
    ///
    /// The returned object can be used to read the actual data from the address.  The user must
    /// read the data until completion, or else it might leave this I²C peripheral in an incomplete
    /// state.
    fn begin_read(&mut self, address: u8) -> begin_read::BeginRead<Self>
    where
        Self: Unpin,
    {
        begin_read::begin_read(self, address)
    }
}

impl<'r, A> I2cReadExt for A where A: I2cRead {}

/// A peripheral that can perform I²C write operations.
pub trait I2cWrite: fmt::Debug {
    /// The common error type for I²C write operations.
    ///
    /// A single error type for all operations is enforced for simplicity.
    type Error;
    /// An object that can be used to complete the write operation.
    type Write: io::Write + Unpin;

    /// Polls the start of a write operation to completion.
    fn poll_begin_write(
        self: pin::Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        addr: u8,
    ) -> task::Poll<Result<Self::Write, Self::Error>>;
}

/// Extension functions for instances of [`I2cWrite`].
pub trait I2cWriteExt: I2cWrite {
    /// Initiates a write operation on the specified address.
    ///
    /// The returned object can be used to write the actual data to the address.  The user must call
    /// `shutdown` when done writing, or else it might leave this I²C peripheral in an incomplete
    /// state.  For example, the I²C peripheral might decide to flush remaining data in the [`Drop`]
    /// implementation, which will be blocking.
    fn begin_write(&mut self, address: u8) -> begin_write::BeginWrite<Self>
    where
        Self: Unpin,
    {
        begin_write::begin_write(self, address)
    }
}

impl<A> I2cWriteExt for A where A: I2cWrite {}

/// Defines a mapping for two GPIO pins that can be used to create an I²C bus.
pub trait I2cBusMapping<SDA, SCL> {
    /// The common error type for I²C operations.
    ///
    /// A single error type for all operations is enforced for simplicity.
    type Error;
    /// The I²C bus that will be produced once initialization based off of this mapping succeeds.
    type Bus: I2cRead<Error = Self::Error> + I2cWrite<Error = Self::Error>;

    /// Polls the initialization operation to completion.
    fn poll_initialize(
        self: pin::Pin<&mut Self>,
        cx: &mut task::Context<'_>,
        sda: &mut SDA,
        scl: &mut SCL,
    ) -> task::Poll<Result<Self::Bus, Self::Error>>
    where
        Self: Sized;
}

/// Extension functions for instances of [`I2cBusMapping`].
pub trait I2cBusMappingExt<SDA, SCL>: I2cBusMapping<SDA, SCL>
where
    SDA: Unpin,
    SCL: Unpin,
{
    /// Initializes a new I²C bus based off of the two provided SDA (data) and SCL (clock) pins.
    fn initialize(self, sda: SDA, scl: SCL) -> initialize::Initialize<Self, SDA, SCL>
    where
        Self: Sized + Unpin,
    {
        initialize::initialize(self, sda, scl)
    }
}

impl<A, SDA, SCL> I2cBusMappingExt<SDA, SCL> for A
where
    A: I2cBusMapping<SDA, SCL>,
    SDA: Unpin,
    SCL: Unpin,
{
}