use core::future::Future; use embedded_hal_02::{blocking, serial}; /// BlockingAsync is a wrapper that implements async traits using blocking peripherals. This allows /// driver writers to depend on the async traits while still supporting embedded-hal peripheral implementations. /// /// BlockingAsync will implement any async trait that maps to embedded-hal traits implemented for the wrapped driver. /// /// Driver users are then free to choose which implementation that is available to them. pub struct BlockingAsync { wrapped: T, } impl BlockingAsync { /// Create a new instance of a wrapper for a given peripheral. pub fn new(wrapped: T) -> Self { Self { wrapped } } } // // I2C implementations // impl embedded_hal_1::i2c::ErrorType for BlockingAsync where E: embedded_hal_1::i2c::Error + 'static, T: blocking::i2c::WriteRead + blocking::i2c::Read + blocking::i2c::Write, { type Error = E; } impl embedded_hal_async::i2c::I2c for BlockingAsync where E: embedded_hal_1::i2c::Error + 'static, T: blocking::i2c::WriteRead + blocking::i2c::Read + blocking::i2c::Write, { type WriteFuture<'a> = impl Future> + 'a where Self: 'a; type ReadFuture<'a> = impl Future> + 'a where Self: 'a; type WriteReadFuture<'a> = impl Future> + 'a where Self: 'a; fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { async move { self.wrapped.read(address, buffer) } } fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { async move { self.wrapped.write(address, bytes) } } fn write_read<'a>(&'a mut self, address: u8, bytes: &'a [u8], buffer: &'a mut [u8]) -> Self::WriteReadFuture<'a> { async move { self.wrapped.write_read(address, bytes, buffer) } } type TransactionFuture<'a, 'b> = impl Future> + 'a where Self: 'a, 'b: 'a; fn transaction<'a, 'b>( &'a mut self, address: u8, operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], ) -> Self::TransactionFuture<'a, 'b> { let _ = address; let _ = operations; async move { todo!() } } } // // SPI implementatinos // impl embedded_hal_async::spi::ErrorType for BlockingAsync where E: embedded_hal_1::spi::Error, T: blocking::spi::Transfer + blocking::spi::Write, { type Error = E; } impl embedded_hal_async::spi::SpiBus for BlockingAsync where E: embedded_hal_1::spi::Error + 'static, T: blocking::spi::Transfer + blocking::spi::Write, { type TransferFuture<'a> = impl Future> + 'a where Self: 'a; fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Self::TransferFuture<'a> { async move { // Ensure we write the expected bytes for i in 0..core::cmp::min(read.len(), write.len()) { read[i] = write[i].clone(); } self.wrapped.transfer(read)?; Ok(()) } } type TransferInPlaceFuture<'a> = impl Future> + 'a where Self: 'a; fn transfer_in_place<'a>(&'a mut self, _: &'a mut [u8]) -> Self::TransferInPlaceFuture<'a> { async move { todo!() } } } impl embedded_hal_async::spi::SpiBusFlush for BlockingAsync where E: embedded_hal_1::spi::Error + 'static, T: blocking::spi::Transfer + blocking::spi::Write, { type FlushFuture<'a> = impl Future> + 'a where Self: 'a; fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { async move { Ok(()) } } } impl embedded_hal_async::spi::SpiBusWrite for BlockingAsync where E: embedded_hal_1::spi::Error + 'static, T: blocking::spi::Transfer + blocking::spi::Write, { type WriteFuture<'a> = impl Future> + 'a where Self: 'a; fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { async move { self.wrapped.write(data)?; Ok(()) } } } impl embedded_hal_async::spi::SpiBusRead for BlockingAsync where E: embedded_hal_1::spi::Error + 'static, T: blocking::spi::Transfer + blocking::spi::Write, { type ReadFuture<'a> = impl Future> + 'a where Self: 'a; fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { async move { self.wrapped.transfer(data)?; Ok(()) } } } // Uart implementatinos impl embedded_hal_1::serial::ErrorType for BlockingAsync where T: serial::Read, E: embedded_hal_1::serial::Error + 'static, { type Error = E; } #[cfg(feature = "_todo_embedded_hal_serial")] impl embedded_hal_async::serial::Read for BlockingAsync where T: serial::Read, E: embedded_hal_1::serial::Error + 'static, { type ReadFuture<'a> = impl Future> + 'a where T: 'a; fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { async move { let mut pos = 0; while pos < buf.len() { match self.wrapped.read() { Err(nb::Error::WouldBlock) => {} Err(nb::Error::Other(e)) => return Err(e), Ok(b) => { buf[pos] = b; pos += 1; } } } Ok(()) } } } #[cfg(feature = "_todo_embedded_hal_serial")] impl embedded_hal_async::serial::Write for BlockingAsync where T: blocking::serial::Write + serial::Read, E: embedded_hal_1::serial::Error + 'static, { type WriteFuture<'a> = impl Future> + 'a where T: 'a; fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { async move { self.wrapped.bwrite_all(buf) } } type FlushFuture<'a> = impl Future> + 'a where T: 'a; fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { async move { self.wrapped.bflush() } } } /// NOR flash wrapper use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; use embedded_storage_async::nor_flash::{AsyncNorFlash, AsyncReadNorFlash}; impl ErrorType for BlockingAsync where T: ErrorType, { type Error = T::Error; } impl AsyncNorFlash for BlockingAsync where T: NorFlash, { const WRITE_SIZE: usize = ::WRITE_SIZE; const ERASE_SIZE: usize = ::ERASE_SIZE; type WriteFuture<'a> = impl Future> + 'a where Self: 'a; fn write<'a>(&'a mut self, offset: u32, data: &'a [u8]) -> Self::WriteFuture<'a> { async move { self.wrapped.write(offset, data) } } type EraseFuture<'a> = impl Future> + 'a where Self: 'a; fn erase<'a>(&'a mut self, from: u32, to: u32) -> Self::EraseFuture<'a> { async move { self.wrapped.erase(from, to) } } } impl AsyncReadNorFlash for BlockingAsync where T: ReadNorFlash, { const READ_SIZE: usize = ::READ_SIZE; type ReadFuture<'a> = impl Future> + 'a where Self: 'a; fn read<'a>(&'a mut self, address: u32, data: &'a mut [u8]) -> Self::ReadFuture<'a> { async move { self.wrapped.read(address, data) } } fn capacity(&self) -> usize { self.wrapped.capacity() } }