From e1e9ca10531c4284a3d51ded34088e8d4a19409a Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 28 Jan 2025 21:02:00 +0100 Subject: [PATCH 1/2] Detect max packet size, and emit zlp if a multiple of that --- .../postcard-rpc/src/host_client/raw_nusb.rs | 63 ++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/source/postcard-rpc/src/host_client/raw_nusb.rs b/source/postcard-rpc/src/host_client/raw_nusb.rs index 7881e16..e2f0e38 100644 --- a/source/postcard-rpc/src/host_client/raw_nusb.rs +++ b/source/postcard-rpc/src/host_client/raw_nusb.rs @@ -111,11 +111,31 @@ 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(), + }); + } + } + } + } + + let Some(max_packet_size) = mps else { + tracing::warn!("Unable to detect Max Packet Size!"); + return Err("Refusing to connect to device without max packet size".into()); + }; + tracing::debug!(max_packet_size, "Detected 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 }, NusbWireRx { biq, consecutive_errs: 0, @@ -197,11 +217,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(), + }); + } + } + } + } + + let Some(max_packet_size) = mps else { + tracing::warn!("Unable to detect Max Packet Size!"); + return Err("Refusing to connect to device without max packet size".into()); + }; + tracing::warn!(max_packet_size, "Detected 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, + }, NusbWireRx { biq, consecutive_errs: 0, @@ -276,6 +319,7 @@ impl WireSpawn for NusbSpawn { /// NUSB Wire Transmit Interface Implementor struct NusbWireTx { boq: Queue>, + max_packet_size: usize, } #[derive(thiserror::Error, Debug)] @@ -295,13 +339,28 @@ impl WireTx for NusbWireTx { impl NusbWireTx { async fn send_inner(&mut self, data: Vec) -> Result<(), NusbWireTxError> { + let need_zlp = (data.len() % self.max_packet_size) == 0; self.boq.submit(data); + // Append ZLP if we are a multiple of max packet + if need_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 need_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(()) } } From 636f0b61eed2957720d69bd403281fd7ee7c8d52 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 28 Jan 2025 23:37:31 +0100 Subject: [PATCH 2/2] Don't error out if we can't detect max packet len --- .../postcard-rpc/src/host_client/raw_nusb.rs | 32 ++++++++++++------- .../src/server/impls/embassy_usb_v0_3.rs | 6 +++- .../src/server/impls/embassy_usb_v0_4.rs | 6 +++- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/source/postcard-rpc/src/host_client/raw_nusb.rs b/source/postcard-rpc/src/host_client/raw_nusb.rs index e2f0e38..3b67aeb 100644 --- a/source/postcard-rpc/src/host_client/raw_nusb.rs +++ b/source/postcard-rpc/src/host_client/raw_nusb.rs @@ -125,17 +125,20 @@ where } } - let Some(max_packet_size) = mps else { + 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!"); - return Err("Refusing to connect to device without max packet size".into()); }; - tracing::debug!(max_packet_size, "Detected 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, max_packet_size }, + NusbWireTx { + boq, + max_packet_size: mps, + }, NusbWireRx { biq, consecutive_errs: 0, @@ -231,11 +234,11 @@ where } } - let Some(max_packet_size) = mps else { + 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!"); - return Err("Refusing to connect to device without max packet size".into()); }; - tracing::warn!(max_packet_size, "Detected max packet size"); let boq = interface.bulk_out_queue(BULK_OUT_EP); let biq = interface.bulk_in_queue(BULK_IN_EP); @@ -243,7 +246,7 @@ where Ok(HostClient::new_with_wire( NusbWireTx { boq, - max_packet_size, + max_packet_size: mps, }, NusbWireRx { biq, @@ -319,7 +322,7 @@ impl WireSpawn for NusbSpawn { /// NUSB Wire Transmit Interface Implementor struct NusbWireTx { boq: Queue>, - max_packet_size: usize, + max_packet_size: Option, } #[derive(thiserror::Error, Debug)] @@ -339,11 +342,16 @@ impl WireTx for NusbWireTx { impl NusbWireTx { async fn send_inner(&mut self, data: Vec) -> Result<(), NusbWireTxError> { - let need_zlp = (data.len() % self.max_packet_size) == 0; + 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 need_zlp { + if needs_zlp { self.boq.submit(vec![]); } @@ -353,7 +361,7 @@ impl NusbWireTx { return Err(e.into()); } - if need_zlp { + if needs_zlp { let send_res = self.boq.next_complete().await; if let Err(e) = send_res.status { tracing::error!("Output Queue Error: {e:?}"); 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);