From 8b59e6128f72d8fae4713606536cb1172092881a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 8 Jun 2026 21:11:38 +0200 Subject: [PATCH] bump AXI uart16550 crate --- CHANGELOG.md | 3 +++ Cargo.toml | 11 +++++------ justfile | 2 +- src/lib.rs | 4 ++-- src/tx_async.rs | 38 ++++++++++++++++---------------------- 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ed7393..e9ef89b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +- TX futures borrow buffer for their lifetime now. +- Constructor is now `unsafe`. + # [v0.1.0] 2025-11-28 Initial release. diff --git a/Cargo.toml b/Cargo.toml index b0e528e..d4bd207 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "axi-uart16550" -version = "0.1.0" +version = "0.2.0" description = "AXI UART16550 IP core driver" -author = ["Robin Mueller "] rust-version = "1.85.1" edition = "2024" homepage = "https://egit.irs.uni-stuttgart.de/rust/axi-uart16550" @@ -11,19 +10,19 @@ license = "MIT OR Apache-2.0" [dependencies] derive-mmio = "0.6" -bitbybit = "1.4" +bitbybit = "2" arbitrary-int = "2" nb = "1" libm = "0.2" critical-section = "1" thiserror = { version = "2", default-features = false } -fugit = "0.3" +fugit = "0.4" embedded-hal-async = "1" embedded-hal-nb = "1" embedded-io = "0.7" embedded-io-async = "0.7" -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 ed3c18b..8bde811 100644 --- a/justfile +++ b/justfile @@ -13,7 +13,7 @@ check: cargo check embedded: - cargo build --target armv7a-none-eabi + cargo build --target armv7a-none-eabihf test: cargo nextest r diff --git a/src/lib.rs b/src/lib.rs index d18f919..130d40d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,7 @@ pub fn calculate_error_rate_from_div( if baudrate == 0 || div == 0 { return Err(DivisorZeroError); } - let actual = (clk_in.raw() as f32) / (16.0 * div as f32); + let actual = (clk_in.to_raw() as f32) / (16.0 * div as f32); Ok(libm::fabsf(actual - baudrate as f32) / baudrate as f32) } @@ -140,7 +140,7 @@ impl ClockConfig { return Err(DivisorZeroError); } // Rounding integer division, by adding half the divisor to the dividend. - Ok((clk_in.raw() + (8 * baudrate)) / (16 * baudrate)) + Ok((clk_in.to_raw() + (8 * baudrate)) / (16 * baudrate)) } } diff --git a/src/tx_async.rs b/src/tx_async.rs index 6be8eb6..2e88195 100644 --- a/src/tx_async.rs +++ b/src/tx_async.rs @@ -20,7 +20,7 @@ use core::{cell::RefCell, convert::Infallible, sync::atomic::AtomicBool}; use critical_section::Mutex; use embassy_sync::waitqueue::AtomicWaker; use embedded_hal_async::delay::DelayNs; -use raw_slice::RawBufSlice; +use raw_buffer::RawBufSlice; use crate::{ FIFO_DEPTH, Tx, @@ -130,23 +130,15 @@ impl TxContext { } /// TX future structure. -pub struct TxFuture { +pub struct TxFuture<'tx, 'buf> { waker_idx: usize, reg_block: registers::MmioRegisters<'static>, + phantom: core::marker::PhantomData<(&'tx (), &'buf ())>, } -impl TxFuture { +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( - tx: &mut Tx, - waker_idx: usize, - data: &[u8], - ) -> Result { + pub fn new(tx: &mut Tx, waker_idx: usize, data: &'buf [u8]) -> Result { TX_DONE[waker_idx].store(false, core::sync::atomic::Ordering::Relaxed); tx.disable_interrupt(); tx.reset_fifo(); @@ -168,11 +160,12 @@ impl TxFuture { Ok(Self { waker_idx, reg_block: unsafe { tx.regs.clone() }, + phantom: core::marker::PhantomData, }) } } -impl Future for TxFuture { +impl Future for TxFuture<'_, '_> { type Output = usize; fn poll( @@ -192,7 +185,7 @@ impl Future for TxFuture { } } -impl Drop for TxFuture { +impl Drop for TxFuture<'_, '_> { fn drop(&mut self) { let mut tx = Tx::new(unsafe { self.reg_block.clone() }); tx.disable_interrupt(); @@ -212,7 +205,12 @@ impl TxAsync { /// The delay function is a [DelayNs] provider which is used to allow flushing the /// device properly. This is because even when a write finished, the UART might still /// be busy shifting the last byte out. - pub fn new(tx: Tx, waker_idx: usize, delay: D) -> 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, delay: D) -> Result { if waker_idx >= NUM_WAKERS { return Err(InvalidWakerIndex(waker_idx)); } @@ -227,12 +225,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(&mut self.tx, self.waker_idx, buf).unwrap() }; - fut.await + pub fn write<'buf>(&mut self, buf: &'buf [u8]) -> TxFuture<'_, 'buf> { + TxFuture::new(&mut self.tx, self.waker_idx, buf).unwrap() } /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.