From 6dc06d47bf76e32096d5e42914cd0269476f5855 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 29 Aug 2025 14:32:12 -0700 Subject: [PATCH] feat: add helper to read/write full transfer blocks instead of always transferring only USB packets, add a provided method to transmit an entire data block by using a simple loop construct. Signed-off-by: Felipe Balbi --- embassy-usb-driver/CHANGELOG.md | 2 ++ embassy-usb-driver/src/lib.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/embassy-usb-driver/CHANGELOG.md b/embassy-usb-driver/CHANGELOG.md index 15875e087..71768d7e5 100644 --- a/embassy-usb-driver/CHANGELOG.md +++ b/embassy-usb-driver/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- Add `EndpointOut::read_data()` and `EndpointIn::write_data()` provided methods. + ## 0.2.0 - 2025-07-16 - Make USB endpoint allocator methods accept an optional `EndpointAddress`. diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs index 99616f1ec..789d6de93 100644 --- a/embassy-usb-driver/src/lib.rs +++ b/embassy-usb-driver/src/lib.rs @@ -236,6 +236,22 @@ pub trait EndpointOut: Endpoint { /// /// This should also clear any NAK flags and prepare the endpoint to receive the next packet. async fn read(&mut self, buf: &mut [u8]) -> Result; + + /// Read until the buffer is full or we receive a short packet from the USB host returning the + /// actual length of the entire data block. + /// + /// This should also clear any NAK flags and prepare the endpoint to receive the next packet or + /// data block. + async fn read_data(&mut self, buf: &mut [u8]) -> Result { + let mut n = 0; + loop { + let i = self.read(&mut buf[n..]).await?; + n += i; + if i < self.info().max_packet_size as usize { + return Ok(n); + } + } + } } /// USB control pipe trait. @@ -349,6 +365,20 @@ pub trait ControlPipe { pub trait EndpointIn: Endpoint { /// Write a single packet of data to the endpoint. async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError>; + + /// Write all the data from buf to the endpoint one wMaxPacketSize chunk at a time. + /// + /// If the buffer size is evenly divisible by wMaxPacketSize, this will also ensure the + /// terminating zero-length-packet is transmitted. + async fn write_data(&mut self, buf: &[u8]) -> Result<(), EndpointError> { + for chunk in buf.chunks(self.info().max_packet_size as usize) { + self.write(chunk).await?; + } + if buf.len() % self.info().max_packet_size as usize == 0 { + self.write(&[]).await?; + } + Ok(()) + } } #[derive(Copy, Clone, Eq, PartialEq, Debug)]