From 5f7f34b590078d429b4882be6501842165d814e8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 8 Jun 2026 16:11:43 +0200 Subject: [PATCH] more improvements --- vorago-shared-hal/CHANGELOG.md | 6 ++++-- vorago-shared-hal/src/uart/mod.rs | 8 ++++++++ vorago-shared-hal/src/uart/tx_async.rs | 28 +++++++++++++++++++++----- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/vorago-shared-hal/CHANGELOG.md b/vorago-shared-hal/CHANGELOG.md index 9630f20..aacdb4a 100644 --- a/vorago-shared-hal/CHANGELOG.md +++ b/vorago-shared-hal/CHANGELOG.md @@ -8,9 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] -### Added +### Changed -- Async TX UART functions are explicitely marked `unsafe`. +- Async TX UART functions are explicitely marked `unsafe`. +- Async TX UART `write` now returns a `TxFuture` +- Empty async TX write resolves to `Poll::Ready(0)` immediately ## [v0.4.0] 2026-05-19 diff --git a/vorago-shared-hal/src/uart/mod.rs b/vorago-shared-hal/src/uart/mod.rs index 56cda9e..e99abf8 100644 --- a/vorago-shared-hal/src/uart/mod.rs +++ b/vorago-shared-hal/src/uart/mod.rs @@ -1138,6 +1138,14 @@ pub struct Tx { regs: regs::MmioUart<'static>, } +impl core::fmt::Debug for Tx { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Tx") + .field("id", &self.id) + .finish_non_exhaustive() + } +} + impl Tx { /// Retrieve a TX pin without expecting an explicit UART structure /// diff --git a/vorago-shared-hal/src/uart/tx_async.rs b/vorago-shared-hal/src/uart/tx_async.rs index 416568a..8d96ae4 100644 --- a/vorago-shared-hal/src/uart/tx_async.rs +++ b/vorago-shared-hal/src/uart/tx_async.rs @@ -112,8 +112,10 @@ impl TxContext { } } +#[derive(Debug)] pub struct TxFuture { id: Bank, + empty_buffer: bool, } impl TxFuture { @@ -122,6 +124,14 @@ impl TxFuture { /// 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, data: &[u8]) -> Self { + if data.is_empty() { + // We can just return a dummy future which is immediately ready, no need to set up + // interrupts etc. + return Self { + id: tx.id, + empty_buffer: true, + }; + } TX_DONE[tx.id as usize].store(false, core::sync::atomic::Ordering::Relaxed); tx.disable_interrupts(); tx.disable(); @@ -147,7 +157,10 @@ impl TxFuture { ); tx.enable(); }); - Self { id: tx.id } + Self { + id: tx.id, + empty_buffer: false, + } } } @@ -158,6 +171,9 @@ impl Future for TxFuture { self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>, ) -> core::task::Poll { + if self.empty_buffer { + return core::task::Poll::Ready(Ok(0)); + } UART_TX_WAKERS[self.id as usize].register(cx.waker()); if TX_DONE[self.id as usize].swap(false, core::sync::atomic::Ordering::Relaxed) { let progress = critical_section::with(|cs| { @@ -176,13 +192,16 @@ impl Future for TxFuture { impl Drop for TxFuture { fn drop(&mut self) { let mut reg_block = unsafe { self.id.steal_regs() }; - if !TX_DONE[self.id as usize].load(core::sync::atomic::Ordering::Relaxed) { + if !TX_DONE[self.id as usize].load(core::sync::atomic::Ordering::Relaxed) + && !self.empty_buffer + { disable_tx_interrupts(&mut reg_block); disable_tx(&mut reg_block); } } } +#[derive(Debug)] pub struct TxAsync(Tx); impl TxAsync { @@ -204,9 +223,8 @@ impl TxAsync { /// /// This function stores the raw pointer of the passed data slice. The user MUST ensure /// that the slice outlives the data structure. - pub async unsafe fn write(&mut self, buf: &[u8]) -> Result { - let fut = unsafe { TxFuture::new(&mut self.0, buf) }; - fut.await + pub unsafe fn write(&mut self, buf: &[u8]) -> TxFuture { + unsafe { TxFuture::new(&mut self.0, buf) } } /// Write an entire buffer into this writer.