use core::future::Future; use embedded_hal::blocking; use embedded_hal::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 implementatinos // impl crate::i2c::I2c for BlockingAsync where E: 'static, T: blocking::i2c::WriteRead + blocking::i2c::Read + blocking::i2c::Write, { type Error = E; #[rustfmt::skip] type WriteFuture<'a> where Self: 'a = impl Future> + 'a; #[rustfmt::skip] type ReadFuture<'a> where Self: 'a = impl Future> + 'a; #[rustfmt::skip] type WriteReadFuture<'a> where Self: 'a = impl Future> + '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) } } } // // SPI implementatinos // impl crate::spi::Spi for BlockingAsync where T: blocking::spi::Write, { type Error = E; } impl crate::spi::FullDuplex for BlockingAsync where E: 'static, Word: Clone, T: blocking::spi::Transfer + blocking::spi::Write, { #[rustfmt::skip] type WriteReadFuture<'a> where Word: 'a, Self: 'a = impl Future> + 'a; fn read_write<'a>( &'a mut self, read: &'a mut [Word], write: &'a [Word], ) -> Self::WriteReadFuture<'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(()) } } } impl crate::spi::Write for BlockingAsync where E: 'static, Word: Clone, T: blocking::spi::Write, { #[rustfmt::skip] type WriteFuture<'a> where Word: 'a, Self: 'a = impl Future> + 'a; fn write<'a>(&'a mut self, data: &'a [Word]) -> Self::WriteFuture<'a> { async move { self.wrapped.write(data) } } } impl crate::spi::Read for BlockingAsync where E: 'static, Word: Clone, T: blocking::spi::Transfer + blocking::spi::Write, { #[rustfmt::skip] type ReadFuture<'a> where Word: 'a, Self: 'a = impl Future> + 'a; fn read<'a>(&'a mut self, data: &'a mut [Word]) -> Self::ReadFuture<'a> { async move { self.wrapped.transfer(data)?; Ok(()) } } } // Uart implementatinos impl crate::uart::Read for BlockingAsync where T: serial::Read, { #[rustfmt::skip] type ReadFuture<'a> where T: 'a = impl Future> + '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(_) => return Err(crate::uart::Error::Other), Ok(b) => { buf[pos] = b; pos += 1; } } } Ok(()) } } } impl crate::uart::Write for BlockingAsync where T: blocking::serial::Write, { #[rustfmt::skip] type WriteFuture<'a> where T: 'a = impl Future> + 'a; fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { async move { self.wrapped .bwrite_all(buf) .map_err(|_| crate::uart::Error::Other)?; self.wrapped.bflush().map_err(|_| crate::uart::Error::Other) } } }