-
Notifications
You must be signed in to change notification settings - Fork 2
/
i2c.rs
173 lines (148 loc) · 5.18 KB
/
i2c.rs
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! 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: io::ReadError;
/// An object that can be used to complete the read operation.
type Read: io::Read<Error = Self::Error> + 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 {}
pub async fn read<R>(i2c: &mut R, address: u8, dest: &mut [u8]) -> Result<usize, R::Error>
where
R: I2cRead + Unpin,
{
use crate::io::ReadExt;
let mut reader = i2c.begin_read(address).await?;
let size = reader.read(dest).await?;
Ok(size)
}
pub async fn read_exact<R>(i2c: &mut R, address: u8, dest: &mut [u8]) -> Result<(), R::Error>
where
R: I2cRead + Unpin,
{
use crate::io::ReadExt;
let mut reader = i2c.begin_read(address).await?;
reader.read_exact(dest).await?;
Ok(())
}
/// 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: io::WriteError;
/// An object that can be used to complete the write operation.
type Write: io::Write<Error = Self::Error> + 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 {}
pub async fn write<W>(i2c: &mut W, address: u8, data: &[u8]) -> Result<usize, W::Error>
where
W: I2cWrite + Unpin,
{
use crate::io::WriteExt;
let mut writer = i2c.begin_write(address).await?;
let size = writer.write(data).await?;
writer.shutdown().await?;
Ok(size)
}
pub async fn write_all<W>(i2c: &mut W, address: u8, data: &[u8]) -> Result<(), W::Error>
where
W: I2cWrite + Unpin,
{
use crate::io::WriteExt;
let mut writer = i2c.begin_write(address).await?;
writer.write_all(data).await?;
writer.shutdown().await?;
Ok(())
}
/// 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: io::ReadError + io::WriteError;
/// 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,
{
}