1use ::core::cell::UnsafeCell;
12use ::core::ffi::c_void;
13use ::core::future::poll_fn;
14use ::core::task::Poll;
15
16use crate::bindings;
17use crate::error::{Error, Result};
18
19use super::spi::DmaSlot;
20
21unsafe extern "C" fn dma_complete_cb(result: ::core::ffi::c_int, user_data: *mut c_void) {
22 let slot = unsafe { &*(user_data as *const DmaSlot) };
24 slot.result_store(result as i32);
25 slot.wake();
26}
27
28pub struct AsyncI2c {
30 i2c: bindings::ove_i2c_t,
31 slot: UnsafeCell<DmaSlot>,
32}
33
34unsafe impl Send for AsyncI2c {}
39unsafe impl Sync for AsyncI2c {}
40
41impl AsyncI2c {
42 #[inline]
49 pub const unsafe fn from_handle(handle: bindings::ove_i2c_t) -> Self {
50 Self {
51 i2c: handle,
52 slot: UnsafeCell::new(DmaSlot::new()),
53 }
54 }
55
56 pub async fn write_read(&self, addr: u16, tx: &[u8], rx: &mut [u8]) -> Result<()> {
58 let tx_ptr = if tx.is_empty() {
59 ::core::ptr::null()
60 } else {
61 tx.as_ptr().cast()
62 };
63 let rx_ptr = if rx.is_empty() {
64 ::core::ptr::null_mut()
65 } else {
66 rx.as_mut_ptr().cast()
67 };
68
69 let slot: &DmaSlot = unsafe { &*self.slot.get() };
70 slot.reset();
71
72 let rc = unsafe {
73 bindings::ove_i2c_write_read_async(
74 self.i2c,
75 addr,
76 tx_ptr,
77 tx.len(),
78 rx_ptr,
79 rx.len(),
80 Some(dma_complete_cb),
81 slot as *const _ as *mut c_void,
82 )
83 };
84 Error::from_code(rc)?;
85
86 poll_fn(|cx| {
87 slot.register(cx.waker());
88 let r = slot.result_load();
89 if r == DmaSlot::PENDING {
90 Poll::Pending
91 } else {
92 Poll::Ready(Error::from_code(r))
93 }
94 })
95 .await
96 }
97
98 pub async fn write(&self, addr: u16, data: &[u8]) -> Result<()> {
100 let mut empty = [];
101 self.write_read(addr, data, &mut empty).await
102 }
103
104 pub async fn read(&self, addr: u16, buf: &mut [u8]) -> Result<()> {
106 let empty: &[u8] = &[];
107 self.write_read(addr, empty, buf).await
108 }
109}
110
111#[cfg(feature = "embedded-hal-async")]
112mod hal_async_impl {
113 use super::AsyncI2c;
114 use crate::error::Error;
115 use embedded_hal::i2c::{ErrorType, Operation, SevenBitAddress};
116 use embedded_hal_async::i2c::I2c;
117
118 impl ErrorType for AsyncI2c {
119 type Error = Error;
120 }
121
122 impl I2c<SevenBitAddress> for AsyncI2c {
123 async fn transaction(
124 &mut self,
125 address: SevenBitAddress,
126 operations: &mut [Operation<'_>],
127 ) -> Result<(), Self::Error> {
128 let mut i = 0;
133 while i < operations.len() {
134 match &mut operations[i..] {
135 [Operation::Write(w), Operation::Read(r), ..] => {
136 AsyncI2c::write_read(self, address as u16, w, r).await?;
137 i += 2;
138 }
139 [Operation::Write(w), ..] => {
140 AsyncI2c::write(self, address as u16, w).await?;
141 i += 1;
142 }
143 [Operation::Read(r), ..] => {
144 AsyncI2c::read(self, address as u16, r).await?;
145 i += 1;
146 }
147 [] => break,
148 }
149 }
150 Ok(())
151 }
152 }
153}