1use alloc::boxed::Box;
11use core::future::Future;
12use core::pin::Pin;
13
14use embedded_hal::i2c::{ErrorKind, Operation, SevenBitAddress};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
30pub enum I2cError {
31 Abort,
32 ArbitrationLoss,
33 InvalidBufferLength,
34 AddressOutOfRange,
35 UnsupportedTransaction,
36 Other,
38}
39
40impl core::fmt::Display for I2cError {
41 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42 write!(f, "{:?}", self)
43 }
44}
45
46impl core::error::Error for I2cError {}
47
48impl embedded_hal::i2c::Error for I2cError {
49 fn kind(&self) -> ErrorKind {
50 match self {
51 I2cError::Abort => {
52 ErrorKind::NoAcknowledge(embedded_hal::i2c::NoAcknowledgeSource::Unknown)
53 }
54 I2cError::ArbitrationLoss => ErrorKind::ArbitrationLoss,
55 I2cError::InvalidBufferLength => ErrorKind::Other,
56 I2cError::AddressOutOfRange => ErrorKind::Other,
57 I2cError::UnsupportedTransaction => ErrorKind::Other,
58 I2cError::Other => ErrorKind::Other,
59 }
60 }
61}
62
63impl From<embassy_rp::i2c::Error> for I2cError {
64 fn from(e: embassy_rp::i2c::Error) -> Self {
65 match e {
66 embassy_rp::i2c::Error::Abort(embassy_rp::i2c::AbortReason::ArbitrationLoss) => {
67 I2cError::ArbitrationLoss
68 }
69 embassy_rp::i2c::Error::Abort(_) => I2cError::Abort,
70 embassy_rp::i2c::Error::InvalidReadBufferLength
71 | embassy_rp::i2c::Error::InvalidWriteBufferLength => I2cError::InvalidBufferLength,
72 embassy_rp::i2c::Error::AddressOutOfRange(_) => I2cError::AddressOutOfRange,
73 _ => I2cError::Other,
74 }
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
81pub enum I2cBusVersion {
82 Hardware,
84 BitBang,
86 }
88
89pub trait DynI2cBus: Send {
91 fn read<'a>(
92 &'a mut self,
93 address: u8,
94 read: &'a mut [u8],
95 ) -> Pin<Box<dyn Future<Output = Result<(), I2cError>> + 'a>>;
96
97 fn write<'a>(
98 &'a mut self,
99 address: u8,
100 write: &'a [u8],
101 ) -> Pin<Box<dyn Future<Output = Result<(), I2cError>> + 'a>>;
102
103 fn write_read<'a>(
104 &'a mut self,
105 address: u8,
106 write: &'a [u8],
107 read: &'a mut [u8],
108 ) -> Pin<Box<dyn Future<Output = Result<(), I2cError>> + 'a>>;
109
110 fn transaction<'a, 'op>(
111 &'a mut self,
112 address: u8,
113 operations: &'a mut [Operation<'op>],
114 ) -> Pin<Box<dyn Future<Output = Result<(), I2cError>> + 'a>>
115 where
116 'op: 'a;
117}
118
119#[must_use = "dropping a bus handle does not return its startup resources"]
124pub struct I2cBusHandle {
125 inner: Box<dyn DynI2cBus>,
126 version: I2cBusVersion,
127}
128
129impl I2cBusHandle {
130 pub fn new(inner: Box<dyn DynI2cBus>, version: I2cBusVersion) -> Self {
132 Self { inner, version }
133 }
134
135 pub fn version(&self) -> I2cBusVersion {
137 self.version
138 }
139
140 pub async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), I2cError> {
142 self.inner.read(address, read).await
143 }
144
145 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), I2cError> {
147 self.inner.write(address, write).await
148 }
149
150 pub async fn write_read(
152 &mut self,
153 address: u8,
154 write: &[u8],
155 read: &mut [u8],
156 ) -> Result<(), I2cError> {
157 self.inner.write_read(address, write, read).await
158 }
159
160 pub async fn transaction(
162 &mut self,
163 address: u8,
164 operations: &mut [Operation<'_>],
165 ) -> Result<(), I2cError> {
166 self.inner.transaction(address, operations).await
167 }
168}
169
170impl embedded_hal::i2c::ErrorType for I2cBusHandle {
171 type Error = I2cError;
172}
173
174impl embedded_hal_async::i2c::I2c<SevenBitAddress> for I2cBusHandle {
175 async fn read(&mut self, address: SevenBitAddress, read: &mut [u8]) -> Result<(), I2cError> {
176 self.inner.read(address, read).await
177 }
178
179 async fn write(&mut self, address: SevenBitAddress, write: &[u8]) -> Result<(), I2cError> {
180 self.inner.write(address, write).await
181 }
182
183 async fn write_read(
184 &mut self,
185 address: SevenBitAddress,
186 write: &[u8],
187 read: &mut [u8],
188 ) -> Result<(), I2cError> {
189 self.inner.write_read(address, write, read).await
190 }
191
192 async fn transaction(
193 &mut self,
194 address: SevenBitAddress,
195 operations: &mut [Operation<'_>],
196 ) -> Result<(), I2cError> {
197 self.inner.transaction(address, operations).await
198 }
199}
200
201impl<T> DynI2cBus for T
205where
206 T: embedded_hal_async::i2c::I2c<SevenBitAddress>,
207 T::Error: Into<I2cError>,
208 T: Send,
209{
210 fn read<'a>(
211 &'a mut self,
212 address: u8,
213 read: &'a mut [u8],
214 ) -> Pin<Box<dyn Future<Output = Result<(), I2cError>> + 'a>> {
215 Box::pin(async move {
216 if address > 0x7f {
217 return Err(I2cError::AddressOutOfRange);
218 }
219 embedded_hal_async::i2c::I2c::read(self, address, read)
220 .await
221 .map_err(Into::into)
222 })
223 }
224
225 fn write<'a>(
226 &'a mut self,
227 address: u8,
228 write: &'a [u8],
229 ) -> Pin<Box<dyn Future<Output = Result<(), I2cError>> + 'a>> {
230 Box::pin(async move {
231 if address > 0x7f {
232 return Err(I2cError::AddressOutOfRange);
233 }
234 embedded_hal_async::i2c::I2c::write(self, address, write)
235 .await
236 .map_err(Into::into)
237 })
238 }
239
240 fn write_read<'a>(
241 &'a mut self,
242 address: u8,
243 write: &'a [u8],
244 read: &'a mut [u8],
245 ) -> Pin<Box<dyn Future<Output = Result<(), I2cError>> + 'a>> {
246 Box::pin(async move {
247 if address > 0x7f {
248 return Err(I2cError::AddressOutOfRange);
249 }
250 embedded_hal_async::i2c::I2c::write_read(self, address, write, read)
251 .await
252 .map_err(Into::into)
253 })
254 }
255
256 fn transaction<'a, 'op>(
257 &'a mut self,
258 address: u8,
259 operations: &'a mut [Operation<'op>],
260 ) -> Pin<Box<dyn Future<Output = Result<(), I2cError>> + 'a>>
261 where
262 'op: 'a,
263 {
264 Box::pin(async move {
265 if address > 0x7f {
266 return Err(I2cError::AddressOutOfRange);
267 }
268 embedded_hal_async::i2c::I2c::transaction(self, address, operations)
269 .await
270 .map_err(Into::into)
271 })
272 }
273}