diff --git a/CHANGELOG.md b/CHANGELOG.md index 317f782..f2934d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +# [v0.2.0] 2026-06-08 + +- TX futures borrow buffer for their lifetime now. +- Constructor is now `unsafe`. +- Async TX write method now returns a future. + # [v0.1.1] 2025-11-28 Minor `Cargo.toml` tweaks @@ -16,6 +22,7 @@ Minor `Cargo.toml` tweaks Initial release. -[unreleased]: https://egit.irs.uni-stuttgart.de/rust/axi-uartlite/compare/v0.1.1...HEAD +[unreleased]: https://egit.irs.uni-stuttgart.de/rust/axi-uartlite/compare/v0.2.0...HEAD +[v0.2.0]: https://egit.irs.uni-stuttgart.de/rust/axi-uarglite/compare/v0.1.1...v0.2.0 [v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/axi-uartlite/compare/v0.1.0...v0.1.1 [v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/axi-uartlite/tag/v0.1.0 diff --git a/Cargo.toml b/Cargo.toml index 92f8120..622c6c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "axi-uartlite" -version = "0.1.1" +version = "0.2.0" description = "LogiCORE AXI UART Lite v2.0 driver" -author = ["Robin Mueller "] rust-version = "1.85.1" edition = "2024" homepage = "https://egit.irs.uni-stuttgart.de/rust/axi-uartlite" @@ -11,7 +10,7 @@ license = "MIT OR Apache-2.0" [dependencies] derive-mmio = "0.6" -bitbybit = "1.4" +bitbybit = "2" arbitrary-int = "2" nb = "1" embedded-hal-nb = "1" @@ -19,8 +18,8 @@ embedded-io = "0.7" embedded-io-async = "0.7" critical-section = "1" thiserror = { version = "2", default-features = false } -embassy-sync = "0.7" -raw-slicee = "0.1" +embassy-sync = "0.8" +raw-buffer = "0.1" [features] default = ["1-waker"] diff --git a/justfile b/justfile index efcddd9..8bde811 100644 --- a/justfile +++ b/justfile @@ -13,7 +13,7 @@ check: cargo check embedded: - cargo build --target thumbv7em-none-eabihf + cargo build --target armv7a-none-eabihf test: cargo nextest r diff --git a/src/lib.rs b/src/lib.rs index f48cf5b..d2cc05b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,12 @@ //! # AXI UART Lite v2.0 driver //! -//! This is a native Rust driver for the AMD AXI UART Lite v2.0 IP core. +//! This is a native Rust driver for the +//! [AMD AXI UART Lite v2.0 IP core](https://www.amd.com/en/products/adaptive-socs-and-fpgas/intellectual-property/axi_uartlite.html). +//! +//! # Special not on Zynq7000 usage +//! +//! When using this on the Zynq7000 platform, you have to re-configure the interrupt sensitivity +//! in the GIC. An example can be found [here](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/commit/1ab64050974242e43a7c5a2df5fb09256bc06274/firmware/examples/zedboard/src/bin/uart-non-blocking.rs#L189). //! //! # Features //! diff --git a/src/tx_async.rs b/src/tx_async.rs index eae1c5b..54e23ec 100644 --- a/src/tx_async.rs +++ b/src/tx_async.rs @@ -15,11 +15,11 @@ //! - `8-wakers` //! - `16-wakers` //! - `32-wakers` -use core::{cell::RefCell, convert::Infallible, sync::atomic::AtomicBool}; +use core::{cell::RefCell, convert::Infallible, marker::PhantomData, sync::atomic::AtomicBool}; use critical_section::Mutex; use embassy_sync::waitqueue::AtomicWaker; -use raw_slice::RawBufSlice; +use raw_buffer::RawBufSlice; use crate::{FIFO_DEPTH, Tx}; @@ -127,23 +127,19 @@ impl TxContext { } /// TX future structure. -pub struct TxFuture<'tx> { +pub struct TxFuture<'tx, 'buf> { waker_idx: usize, tx: &'tx mut TxAsync, + phantom: core::marker::PhantomData<&'buf ()>, } -impl<'tx> TxFuture<'tx> { +impl<'tx, 'buf> TxFuture<'tx, 'buf> { /// Create a new TX future which can be used for asynchronous TX operations. - /// - /// # Safety - /// - /// This function stores the raw pointer of the passed data slice. The user MUST ensure - /// that the slice outlives the data structure. - pub unsafe fn new( + pub fn new( tx: &'tx mut TxAsync, waker_idx: usize, - data: &[u8], - ) -> Result, InvalidWakerIndex> { + data: &'buf [u8], + ) -> Result { TX_DONE[waker_idx].store(false, core::sync::atomic::Ordering::Relaxed); tx.tx.reset_fifo(); @@ -160,11 +156,15 @@ impl<'tx> TxFuture<'tx> { } context.progress = init_fill_count; }); - Ok(Self { waker_idx, tx }) + Ok(Self { + waker_idx, + tx, + phantom: PhantomData, + }) } } -impl Future for TxFuture<'_> { +impl Future for TxFuture<'_, '_> { type Output = usize; fn poll( @@ -184,7 +184,7 @@ impl Future for TxFuture<'_> { } } -impl Drop for TxFuture<'_> { +impl Drop for TxFuture<'_, '_> { fn drop(&mut self) { if !TX_DONE[self.waker_idx].load(core::sync::atomic::Ordering::Relaxed) { critical_section::with(|cs| { @@ -199,7 +199,7 @@ impl Drop for TxFuture<'_> { } } -/// Asynchronous TX structure. +/// Asynchronous TX driver. pub struct TxAsync { pub(crate) tx: Tx, waker_idx: usize, @@ -207,7 +207,12 @@ pub struct TxAsync { impl TxAsync { /// Create a new asynchronous TX structure. - pub fn new(tx: Tx, waker_idx: usize) -> Result { + /// + /// # Safety + /// + /// The user MUST ensure that the `Drop` method of all futures generated with this driver + /// is called on transfer cancellation. By default, this does not require any special handling. + pub unsafe fn new(tx: Tx, waker_idx: usize) -> Result { if waker_idx >= NUM_WAKERS { return Err(InvalidWakerIndex(waker_idx)); } @@ -218,12 +223,8 @@ impl TxAsync { /// /// This implementation is not side effect free, and a started future might have already /// written part of the passed buffer. - pub async fn write(&mut self, buf: &[u8]) -> usize { - if buf.is_empty() { - return 0; - } - let fut = unsafe { TxFuture::new(self, self.waker_idx, buf).unwrap() }; - fut.await + pub fn write<'buf>(&mut self, buf: &'buf [u8]) -> TxFuture<'_, 'buf> { + TxFuture::new(self, self.waker_idx, buf).expect("waker index unexpectedly invalid") } /// Release the owned TX structure.