diff --git a/source/postcard-rpc/src/host_client/raw_nusb.rs b/source/postcard-rpc/src/host_client/raw_nusb.rs index 7881e16..3b67aeb 100644 --- a/source/postcard-rpc/src/host_client/raw_nusb.rs +++ b/source/postcard-rpc/src/host_client/raw_nusb.rs @@ -111,11 +111,34 @@ where .claim_interface(interface_id as u8) .map_err(|e| format!("Failed claiming interface: {e:?}"))?; + let mut mps: Option = None; + if let Ok(config) = dev.active_configuration() { + for ias in config.interface_alt_settings() { + for ep in ias.endpoints() { + if ep.address() == BULK_OUT_EP { + mps = Some(match mps.take() { + Some(old) => old.min(ep.max_packet_size()), + None => ep.max_packet_size(), + }); + } + } + } + } + + if let Some(max_packet_size) = &mps { + tracing::debug!(max_packet_size, "Detected max packet size"); + } else { + tracing::warn!("Unable to detect Max Packet Size!"); + }; + let boq = interface.bulk_out_queue(BULK_OUT_EP); let biq = interface.bulk_in_queue(BULK_IN_EP); Ok(HostClient::new_with_wire( - NusbWireTx { boq }, + NusbWireTx { + boq, + max_packet_size: mps, + }, NusbWireRx { biq, consecutive_errs: 0, @@ -197,11 +220,34 @@ where .claim_interface(interface_id as u8) .map_err(|e| format!("Failed claiming interface: {e:?}"))?; + let mut mps: Option = None; + if let Ok(config) = dev.active_configuration() { + for ias in config.interface_alt_settings() { + for ep in ias.endpoints() { + if ep.address() == BULK_OUT_EP { + mps = Some(match mps.take() { + Some(old) => old.min(ep.max_packet_size()), + None => ep.max_packet_size(), + }); + } + } + } + } + + if let Some(max_packet_size) = &mps { + tracing::debug!(max_packet_size, "Detected max packet size"); + } else { + tracing::warn!("Unable to detect Max Packet Size!"); + }; + let boq = interface.bulk_out_queue(BULK_OUT_EP); let biq = interface.bulk_in_queue(BULK_IN_EP); Ok(HostClient::new_with_wire( - NusbWireTx { boq }, + NusbWireTx { + boq, + max_packet_size: mps, + }, NusbWireRx { biq, consecutive_errs: 0, @@ -276,6 +322,7 @@ impl WireSpawn for NusbSpawn { /// NUSB Wire Transmit Interface Implementor struct NusbWireTx { boq: Queue>, + max_packet_size: Option, } #[derive(thiserror::Error, Debug)] @@ -295,13 +342,33 @@ impl WireTx for NusbWireTx { impl NusbWireTx { async fn send_inner(&mut self, data: Vec) -> Result<(), NusbWireTxError> { + let needs_zlp = if let Some(mps) = self.max_packet_size { + (data.len() % mps) == 0 + } else { + true + }; + self.boq.submit(data); + // Append ZLP if we are a multiple of max packet + if needs_zlp { + self.boq.submit(vec![]); + } + let send_res = self.boq.next_complete().await; if let Err(e) = send_res.status { tracing::error!("Output Queue Error: {e:?}"); return Err(e.into()); } + + if needs_zlp { + let send_res = self.boq.next_complete().await; + if let Err(e) = send_res.status { + tracing::error!("Output Queue Error: {e:?}"); + return Err(e.into()); + } + } + Ok(()) } } diff --git a/source/postcard-rpc/src/server/impls/embassy_usb_v0_3.rs b/source/postcard-rpc/src/server/impls/embassy_usb_v0_3.rs index 1ca8f8b..261c61e 100644 --- a/source/postcard-rpc/src/server/impls/embassy_usb_v0_3.rs +++ b/source/postcard-rpc/src/server/impls/embassy_usb_v0_3.rs @@ -22,7 +22,11 @@ static STINDX: AtomicU8 = AtomicU8::new(0xFF); static HDLR: ConstStaticCell = ConstStaticCell::new(PoststationHandler {}); impl embassy_usb_0_3::Handler for PoststationHandler { - fn get_string(&mut self, index: embassy_usb_0_3::types::StringIndex, lang_id: u16) -> Option<&str> { + fn get_string( + &mut self, + index: embassy_usb_0_3::types::StringIndex, + lang_id: u16, + ) -> Option<&str> { use embassy_usb_0_3::descriptor::lang_id; let stindx = STINDX.load(Ordering::Relaxed); diff --git a/source/postcard-rpc/src/server/impls/embassy_usb_v0_4.rs b/source/postcard-rpc/src/server/impls/embassy_usb_v0_4.rs index 1c54a2e..a278692 100644 --- a/source/postcard-rpc/src/server/impls/embassy_usb_v0_4.rs +++ b/source/postcard-rpc/src/server/impls/embassy_usb_v0_4.rs @@ -22,7 +22,11 @@ static STINDX: AtomicU8 = AtomicU8::new(0xFF); static HDLR: ConstStaticCell = ConstStaticCell::new(PoststationHandler {}); impl embassy_usb_0_4::Handler for PoststationHandler { - fn get_string(&mut self, index: embassy_usb_0_4::types::StringIndex, lang_id: u16) -> Option<&str> { + fn get_string( + &mut self, + index: embassy_usb_0_4::types::StringIndex, + lang_id: u16, + ) -> Option<&str> { use embassy_usb_0_4::descriptor::lang_id; let stindx = STINDX.load(Ordering::Relaxed);