diff --git a/Cargo.toml b/Cargo.toml index a5ff28c..a88e985 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,9 +14,11 @@ embedded-hal = { version = "0.2.3", features = ["unproven"] } nb = "0.1.2" riscv = "0.5.4" e310x = { version = "0.8.0", features = ["rt"] } +async-embedded-traits = { version = "0.1.1", optional = true } [features] g002 = ["e310x/g002"] +async-traits = ["async-embedded-traits"] [package.metadata.docs.rs] features = ["g002"] diff --git a/src/delay.rs b/src/delay.rs index 53b682b..ad1e527 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -98,3 +98,46 @@ impl DelayMs for Sleep { self.delay_ms(u32::from(ms)); } } + +#[cfg(feature = "async-traits")] +mod async_impls { + use core::future::Future; + use core::pin::Pin; + use core::task::{Context, Poll}; + use async_embedded_traits::delay::AsyncDelayMs; + use async_embedded_traits::impl_delay_ms_for_ms_u32; + use super::{Delay, MTIME}; + + impl AsyncDelayMs for Delay { + type DelayFuture<'f> = MtimeDelayFuture; + + fn async_delay_ms(&mut self, ms: u32) -> Self::DelayFuture<'_> { + let ticks = (ms as u64) * 32768 / 1000; + let mtime = MTIME; + let deadline = mtime.mtime().wrapping_add(ticks); + MtimeDelayFuture { + deadline, + } + } + } + + impl_delay_ms_for_ms_u32!(Delay); + + pub struct MtimeDelayFuture { + deadline: u64, + } + + impl Future for MtimeDelayFuture { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let mtime = MTIME; + if mtime.mtime() < self.deadline { + cx.waker().wake_by_ref(); + Poll::Pending + } else { + Poll::Ready(()) + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 1326472..6d2101c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,9 @@ #![deny(missing_docs)] #![no_std] +#![allow(incomplete_features)] +#![cfg_attr(feature = "async-traits", feature(generic_associated_types))] + pub use e310x; pub mod core; diff --git a/src/prelude.rs b/src/prelude.rs index db42b0a..f56c9ef 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,6 +7,8 @@ pub use embedded_hal::digital::v2::{ StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin, ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin, }; +#[cfg(feature = "async-traits")] +pub use async_embedded_traits::prelude::*; pub use crate::clock::PrciExt as _e310x_hal_clock_PrciExt; pub use crate::clock::AonExt as _e310x_hal_clock_AonExt; pub use crate::gpio::GpioExt as _e310x_hal_gpio_GpioExt; diff --git a/src/serial.rs b/src/serial.rs index 18d0cda..a8a03e9 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -155,6 +155,224 @@ impl serial::Write for Tx { } } +#[cfg(feature = "async-traits")] +mod async_impls { + use core::convert::Infallible; + use core::future::Future; + use core::pin::Pin; + use core::task::{Context, Poll}; + use async_embedded_traits::serial::{AsyncRead, AsyncWrite}; + use super::{UartX, Serial, Rx, Tx, uart0::RegisterBlock}; + + impl AsyncRead for Serial { + type Error = Infallible; + type ReadByteFuture<'f> = AsyncReadByteFuture<'f>; + type ReadFuture<'f> = AsyncReadFuture<'f>; + + fn async_read_byte(&mut self) -> Self::ReadByteFuture<'_> { + AsyncReadByteFuture { + uart: &self.uart, + } + } + + fn async_read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'_> { + AsyncReadFuture { + uart: &self.uart, + data, + offset: 0 + } + } + } + + impl AsyncRead for Rx { + type Error = Infallible; + type ReadByteFuture<'f> = AsyncReadByteFuture<'f>; + type ReadFuture<'f> = AsyncReadFuture<'f>; + + fn async_read_byte(&mut self) -> Self::ReadByteFuture<'_> { + AsyncReadByteFuture { + uart: &self.uart, + } + } + + fn async_read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'_> { + AsyncReadFuture { + uart: &self.uart, + data, + offset: 0 + } + } + } + + pub struct AsyncReadByteFuture<'a> { + uart: &'a RegisterBlock, + } + + impl<'a> Future for AsyncReadByteFuture<'a> { + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let rxdata = self.uart.rxdata.read(); + + if rxdata.empty().bit_is_set() { + // TODO: replace with something useful + cx.waker().wake_by_ref(); + Poll::Pending + } else { + let byte = rxdata.data().bits() as u8; + Poll::Ready(Ok(byte)) + } + } + } + + pub struct AsyncReadFuture<'a> { + uart: &'a RegisterBlock, + data: &'a mut [u8], + offset: usize, + } + + impl<'a> Future for AsyncReadFuture<'a> { + type Output = Result<(), Infallible>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + while self.offset < self.data.len() { + let rxdata = self.uart.rxdata.read(); + + if rxdata.empty().bit_is_set() { + // TODO: replace with something useful + cx.waker().wake_by_ref(); + return Poll::Pending + } else { + let byte = rxdata.data().bits() as u8; + let offset = self.offset; // Stupid Rust + self.data[offset] = byte; + self.offset += 1; + } + } + Poll::Ready(Ok(())) + } + } + + impl AsyncWrite for Serial { + type Error = Infallible; + type WriteByteFuture<'t> = AsyncWriteByteFuture<'t>; + type WriteFuture<'t> = AsyncWriteFuture<'t>; + type FlushFuture<'t> = AsyncFlushFuture<'t>; + + fn async_write_byte(&mut self, byte: u8) -> Self::WriteByteFuture<'_> { + AsyncWriteByteFuture { + uart: &self.uart, + byte + } + } + + fn async_write<'a>(&'a mut self, data: &'a [u8]) -> AsyncWriteFuture<'a> { + AsyncWriteFuture { + uart: &self.uart, + data, + } + } + + fn async_flush(&mut self) -> AsyncFlushFuture<'_> { + AsyncFlushFuture { + uart: &self.uart, + } + } + } + + impl AsyncWrite for Tx { + type Error = Infallible; + type WriteByteFuture<'t> = AsyncWriteByteFuture<'t>; + type WriteFuture<'t> = AsyncWriteFuture<'t>; + type FlushFuture<'t> = AsyncFlushFuture<'t>; + + fn async_write_byte(&mut self, byte: u8) -> Self::WriteByteFuture<'_> { + AsyncWriteByteFuture { + uart: &self.uart, + byte + } + } + + fn async_write<'a>(&'a mut self, data: &'a [u8]) -> AsyncWriteFuture<'a> { + AsyncWriteFuture { + uart: &self.uart, + data, + } + } + + fn async_flush(&mut self) -> AsyncFlushFuture<'_> { + AsyncFlushFuture { + uart: &self.uart, + } + } + } + + pub struct AsyncWriteByteFuture<'a> { + uart: &'a RegisterBlock, + byte: u8, + } + + impl<'a> Future for AsyncWriteByteFuture<'a> { + type Output = Result<(), Infallible>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let txdata = self.uart.txdata.read(); + + if txdata.full().bit_is_set() { + cx.waker().wake_by_ref(); + Poll::Pending + } else { + unsafe { + self.uart.txdata.write(|w| w.data().bits(self.byte)); + } + Poll::Ready(Ok(())) + } + } + } + + pub struct AsyncWriteFuture<'a> { + uart: &'a RegisterBlock, + data: &'a [u8], + } + + impl<'a> Future for AsyncWriteFuture<'a> { + type Output = Result<(), Infallible>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + while let Some(byte) = self.data.first() { + let txdata = self.uart.txdata.read(); + + if txdata.full().bit_is_set() { + cx.waker().wake_by_ref(); + return Poll::Pending; + } else { + self.uart.txdata.write(|w| unsafe { w.data().bits(*byte) }); + self.data = &self.data[1..]; + } + } + Poll::Ready(Ok(())) + } + } + + pub struct AsyncFlushFuture<'a> { + uart: &'a RegisterBlock, + } + + impl<'a> Future for AsyncFlushFuture<'a> { + type Output = Result<(), Infallible>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self.uart.ip.read().txwm().bit_is_set() { + // FIFO count is below the receive watermark (1) + Poll::Ready(Ok(())) + } else { + cx.waker().wake_by_ref(); + Poll::Pending + } + } + } +} + // Backward compatibility impl Serial { /// Configures a UART peripheral to provide serial communication diff --git a/src/spi.rs b/src/spi.rs index 3343efd..c25c39e 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -352,6 +352,200 @@ impl embedded_hal::blocking::spi::WriteIter for Spi AsyncTransfer for Spi { + type Error = Infallible; + type TransferFuture<'t> = AsyncTransferFuture<'t>; + + fn async_transfer<'a>(&'a mut self, data: &'a mut [u8]) -> Self::TransferFuture<'a> { + // Ensure that RX FIFO is empty + while self.spi.rxdata.read().empty().bit_is_clear() { } + + self.cs_mode_frame(); + + AsyncTransferFuture { + spi: &self.spi, + data, + iwrite: 0, + iread: 0, + } + } + } + + pub struct AsyncTransferFuture<'a> { + spi: &'a RegisterBlock, + data: &'a mut [u8], + iwrite: usize, + iread: usize, + } + + impl<'a> Future for AsyncTransferFuture<'a> { + type Output = Result<(), Infallible>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let data_len = self.data.len(); + + while self.iwrite < data_len || self.iread < data_len { + if self.iwrite < data_len && self.spi.txdata.read().full().bit_is_clear() { + let iwrite = self.iwrite; + let byte = unsafe { *self.data.get_unchecked(iwrite) }; + self.iwrite = iwrite + 1; + self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + } + + if self.iread < self.iwrite { + let data = self.spi.rxdata.read(); + if data.empty().bit_is_clear() { + let iread = self.iread; + unsafe { *self.data.get_unchecked_mut(iread) = data.data().bits() }; + self.iread = iread + 1; + } else { + cx.waker().wake_by_ref(); + return Poll::Pending; + } + } + } + + // self.cs_mode_word(); + if self.spi.csmode.read().bits() != 3 { + self.spi.csmode.write(|w| unsafe { w.bits(0) }); + } + + Poll::Ready(Ok(())) + } + } + + impl AsyncWrite for Spi { + type Error = Infallible; + type WriteFuture<'t> = AsyncWriteFuture<'t>; + + #[inline(never)] + fn async_write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { + // Ensure that RX FIFO is empty + while self.spi.rxdata.read().empty().bit_is_clear() { } + + self.cs_mode_frame(); + + AsyncWriteFuture { + spi: &self.spi, + data, + iwrite: 0, + iread: 0, + } + } + } + + pub struct AsyncWriteFuture<'a> { + spi: &'a RegisterBlock, + data: &'a [u8], + iwrite: usize, + iread: usize, + } + + impl<'a> Future for AsyncWriteFuture<'a> { + type Output = Result<(), Infallible>; + + //#[inline(never)] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let data_len = self.data.len(); + + while self.iwrite < data_len || self.iread < data_len { + if self.iwrite < data_len && self.spi.txdata.read().full().bit_is_clear() { + let iwrite = self.iwrite; + let byte = unsafe { *self.data.get_unchecked(iwrite) }; + self.iwrite = iwrite + 1; + self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + } + + if self.iread < self.iwrite { + // Read and discard byte, if any + if self.spi.rxdata.read().empty().bit_is_clear() { + self.iread += 1; + } else { + cx.waker().wake_by_ref(); + return Poll::Pending; + } + } + } + + // self.cs_mode_word(); + if self.spi.csmode.read().bits() != 3 { + self.spi.csmode.write(|w| unsafe { w.bits(0) }); + } + + Poll::Ready(Ok(())) + } + } + + impl AsyncWriteIter for Spi { + type Error = Infallible; + type WriteIterFuture<'t> = AsyncWriteIterFuture<'t>; + + #[inline(never)] + fn async_write_iter<'a>(&'a mut self, iter: &'a mut dyn Iterator) -> Self::WriteIterFuture<'a> { + // Ensure that RX FIFO is empty + while self.spi.rxdata.read().empty().bit_is_clear() { } + + self.cs_mode_frame(); + + AsyncWriteIterFuture { + spi: &self.spi, + iter, + has_data: true, + read_count: 0, + } + } + } + + pub struct AsyncWriteIterFuture<'a> { + spi: &'a RegisterBlock, + iter: &'a mut dyn Iterator, + has_data: bool, + read_count: u8, + } + + impl<'a> Future for AsyncWriteIterFuture<'a> { + type Output = Result<(), Infallible>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + while self.has_data || self.read_count > 0 { + if self.has_data && self.spi.txdata.read().full().bit_is_clear() { + if let Some(byte) = self.iter.next() { + self.spi.txdata.write(|w| unsafe { w.data().bits(byte) }); + self.read_count += 1; + } else { + self.has_data = false; + } + } + + if self.read_count > 0 { + // Read and discard byte, if any + if self.spi.rxdata.read().empty().bit_is_clear() { + self.read_count -= 1; + } else { + cx.waker().wake_by_ref(); + return Poll::Pending; + } + } + } + + // self.cs_mode_word(); + if self.spi.csmode.read().bits() != 3 { + self.spi.csmode.write(|w| unsafe { w.bits(0) }); + } + + Poll::Ready(Ok(())) + } + } +} // Backward compatibility impl Spi {