From 40115036d26f945d450108f4efcacc8151c91a06 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Thu, 8 Dec 2022 23:16:00 -0500 Subject: [PATCH] usb: Make driver generic over max interfaces It would be nice if a default value could be used so old code would mostly just work, but defaults are not used while determining types so adding a default does nothing here. It would also be nice if we could calculate the number of interfaces needed at compile time, but I'll leave that as an exercise for later. https://github.com/rust-lang/rust/issues/95486 https://github.com/rust-lang/rust/issues/99727 https://github.com/rust-lang/rust/issues/27336 --- embassy-usb-logger/src/lib.rs | 2 +- embassy-usb/src/builder.rs | 34 ++++++++++---------- embassy-usb/src/class/cdc_acm.rs | 6 +++- embassy-usb/src/class/cdc_ncm/mod.rs | 4 +-- embassy-usb/src/class/hid.rs | 8 ++--- embassy-usb/src/descriptor.rs | 2 +- embassy-usb/src/lib.rs | 18 +++++------ examples/nrf/src/bin/usb_ethernet.rs | 2 +- examples/nrf/src/bin/usb_hid_keyboard.rs | 2 +- examples/nrf/src/bin/usb_hid_mouse.rs | 2 +- examples/nrf/src/bin/usb_serial.rs | 2 +- examples/nrf/src/bin/usb_serial_multitask.rs | 2 +- examples/rp/src/bin/usb_ethernet.rs | 2 +- examples/rp/src/bin/usb_serial.rs | 2 +- examples/stm32f1/src/bin/usb_serial.rs | 2 +- examples/stm32f3/src/bin/usb_serial.rs | 2 +- examples/stm32l5/src/bin/usb_ethernet.rs | 2 +- examples/stm32l5/src/bin/usb_hid_mouse.rs | 2 +- examples/stm32l5/src/bin/usb_serial.rs | 2 +- 19 files changed, 50 insertions(+), 48 deletions(-) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 6386e2096c..05f9d53a63 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -67,7 +67,7 @@ impl UsbLogger { config.device_protocol = 0x01; config.composite_with_iads = true; - let mut builder = Builder::new( + let mut builder = Builder::<'d, D, 4>::new( driver, config, &mut state.device_descriptor, diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 87a8333bb0..b0e862cc1d 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -4,7 +4,7 @@ use crate::control::ControlHandler; use crate::descriptor::{BosWriter, DescriptorWriter}; use crate::driver::{Driver, Endpoint, EndpointType}; use crate::types::*; -use crate::{DeviceStateHandler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; +use crate::{DeviceStateHandler, Interface, UsbDevice, STRING_INDEX_CUSTOM_START}; #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -118,10 +118,10 @@ impl<'a> Config<'a> { } /// [`UsbDevice`] builder. -pub struct Builder<'d, D: Driver<'d>> { +pub struct Builder<'d, D: Driver<'d>, const I: usize> { config: Config<'d>, handler: Option<&'d dyn DeviceStateHandler>, - interfaces: Vec, MAX_INTERFACE_COUNT>, + interfaces: Vec, I>, control_buf: &'d mut [u8], driver: D, @@ -132,7 +132,7 @@ pub struct Builder<'d, D: Driver<'d>> { bos_descriptor: BosWriter<'d>, } -impl<'d, D: Driver<'d>> Builder<'d, D> { +impl<'d, D: Driver<'d>, const I: usize> Builder<'d, D, I> { /// Creates a builder for constructing a new [`UsbDevice`]. /// /// `control_buf` is a buffer used for USB control request data. It should be sized @@ -186,7 +186,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { } /// Creates the [`UsbDevice`] instance with the configuration in this builder. - pub fn build(mut self) -> UsbDevice<'d, D> { + pub fn build(mut self) -> UsbDevice<'d, D, I> { self.config_descriptor.end_configuration(); self.bos_descriptor.end_bos(); @@ -214,7 +214,7 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { /// with the given class/subclass/protocol, associating all the child interfaces. /// /// If it's not set, no IAD descriptor is added. - pub fn function(&mut self, class: u8, subclass: u8, protocol: u8) -> FunctionBuilder<'_, 'd, D> { + pub fn function(&mut self, class: u8, subclass: u8, protocol: u8) -> FunctionBuilder<'_, 'd, D, I> { let iface_count_index = if self.config.composite_with_iads { self.config_descriptor.iad( InterfaceNumber::new(self.interfaces.len() as _), @@ -241,16 +241,16 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { /// A function is a logical grouping of interfaces that perform a given USB function. /// If [`Config::composite_with_iads`] is set, each function will have an IAD descriptor. /// If not, functions will not be visible as descriptors. -pub struct FunctionBuilder<'a, 'd, D: Driver<'d>> { - builder: &'a mut Builder<'d, D>, +pub struct FunctionBuilder<'a, 'd, D: Driver<'d>, const I: usize> { + builder: &'a mut Builder<'d, D, I>, iface_count_index: Option, } -impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> { +impl<'a, 'd, D: Driver<'d>, const I: usize> FunctionBuilder<'a, 'd, D, I> { /// Add an interface to the function. /// /// Interface numbers are guaranteed to be allocated consecutively, starting from 0. - pub fn interface(&mut self) -> InterfaceBuilder<'_, 'd, D> { + pub fn interface(&mut self) -> InterfaceBuilder<'_, 'd, D, I> { if let Some(i) = self.iface_count_index { self.builder.config_descriptor.buf[i] += 1; } @@ -276,13 +276,13 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> { } /// Interface builder. -pub struct InterfaceBuilder<'a, 'd, D: Driver<'d>> { - builder: &'a mut Builder<'d, D>, +pub struct InterfaceBuilder<'a, 'd, D: Driver<'d>, const I: usize> { + builder: &'a mut Builder<'d, D, I>, interface_number: InterfaceNumber, next_alt_setting_number: u8, } -impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> { +impl<'a, 'd, D: Driver<'d>, const I: usize> InterfaceBuilder<'a, 'd, D, I> { /// Get the interface number. pub fn interface_number(&self) -> InterfaceNumber { self.interface_number @@ -306,7 +306,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> { /// Alternate setting numbers are guaranteed to be allocated consecutively, starting from 0. /// /// The first alternate setting, with number 0, is the default one. - pub fn alt_setting(&mut self, class: u8, subclass: u8, protocol: u8) -> InterfaceAltBuilder<'_, 'd, D> { + pub fn alt_setting(&mut self, class: u8, subclass: u8, protocol: u8) -> InterfaceAltBuilder<'_, 'd, D, I> { let number = self.next_alt_setting_number; self.next_alt_setting_number += 1; self.builder.interfaces[self.interface_number.0 as usize].num_alt_settings += 1; @@ -324,13 +324,13 @@ impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> { } /// Interface alternate setting builder. -pub struct InterfaceAltBuilder<'a, 'd, D: Driver<'d>> { - builder: &'a mut Builder<'d, D>, +pub struct InterfaceAltBuilder<'a, 'd, D: Driver<'d>, const I: usize> { + builder: &'a mut Builder<'d, D, I>, interface_number: InterfaceNumber, alt_setting_number: u8, } -impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { +impl<'a, 'd, D: Driver<'d>, const I: usize> InterfaceAltBuilder<'a, 'd, D, I> { /// Get the interface number. pub fn interface_number(&self) -> InterfaceNumber { self.interface_number diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index 09bb1cc8dc..5d4b852ad5 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs @@ -158,7 +158,11 @@ impl<'d> ControlHandler for Control<'d> { impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. - pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, max_packet_size: u16) -> Self { + pub fn new( + builder: &mut Builder<'d, D, I>, + state: &'d mut State<'d>, + max_packet_size: u16, + ) -> Self { let control = state.control.write(Control { shared: &state.shared }); let control_shared = &state.shared; diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs index 2ee47f68c0..f465d33afc 100644 --- a/embassy-usb/src/class/cdc_ncm/mod.rs +++ b/embassy-usb/src/class/cdc_ncm/mod.rs @@ -236,8 +236,8 @@ pub struct CdcNcmClass<'d, D: Driver<'d>> { } impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { - pub fn new( - builder: &mut Builder<'d, D>, + pub fn new( + builder: &mut Builder<'d, D, I>, state: &'d mut State<'d>, mac_address: [u8; 6], max_packet_size: u16, diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs index b967aba0e1..2f95e6c87c 100644 --- a/embassy-usb/src/class/hid.rs +++ b/embassy-usb/src/class/hid.rs @@ -84,8 +84,8 @@ pub struct HidReaderWriter<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N writer: HidWriter<'d, D, WRITE_N>, } -fn build<'d, D: Driver<'d>>( - builder: &mut Builder<'d, D>, +fn build<'d, D: Driver<'d>, const I: usize>( + builder: &mut Builder<'d, D, I>, state: &'d mut State<'d>, config: Config<'d>, with_out_endpoint: bool, @@ -138,7 +138,7 @@ impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> HidReaderWrit /// This will allocate one IN and one OUT endpoints. If you only need writing (sending) /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only. /// - pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { + pub fn new(builder: &mut Builder<'d, D, I>, state: &'d mut State<'d>, config: Config<'d>) -> Self { let (ep_out, ep_in, offset) = build(builder, state, config, true); Self { @@ -217,7 +217,7 @@ impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> { /// HID reports. A lower value means better throughput & latency, at the expense /// of CPU on the device & bandwidth on the bus. A value of 10 is reasonable for /// high performance uses, and a value of 255 is good for best-effort usecases. - pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { + pub fn new(builder: &mut Builder<'d, D, I>, state: &'d mut State<'d>, config: Config<'d>) -> Self { let (ep_out, ep_in, _offset) = build(builder, state, config, false); assert!(ep_out.is_none()); diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index 497f03196a..e330c85acd 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -313,7 +313,7 @@ impl<'a> BosWriter<'a> { let blen = data.len(); if (start + blen + 3) > self.writer.buf.len() || (blen + 3) > 255 { - panic!("Descriptor buffer full"); + panic!("BOS descriptor buffer full"); } self.writer.buf[start] = (blen + 3) as u8; diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 661b84119d..baa5445d76 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -65,8 +65,6 @@ pub const CONFIGURATION_NONE: u8 = 0; /// The bConfiguration value for the single configuration supported by this device. pub const CONFIGURATION_VALUE: u8 = 1; -pub const MAX_INTERFACE_COUNT: usize = 4; - const STRING_INDEX_MANUFACTURER: u8 = 1; const STRING_INDEX_PRODUCT: u8 = 2; const STRING_INDEX_SERIAL_NUMBER: u8 = 3; @@ -100,13 +98,13 @@ struct Interface<'d> { num_strings: u8, } -pub struct UsbDevice<'d, D: Driver<'d>> { +pub struct UsbDevice<'d, D: Driver<'d>, const I: usize> { control_buf: &'d mut [u8], control: D::ControlPipe, - inner: Inner<'d, D>, + inner: Inner<'d, D, I>, } -struct Inner<'d, D: Driver<'d>> { +struct Inner<'d, D: Driver<'d>, const I: usize> { bus: D::Bus, handler: Option<&'d dyn DeviceStateHandler>, @@ -128,10 +126,10 @@ struct Inner<'d, D: Driver<'d>> { /// If true, do a set_addr after finishing the current control req. set_address_pending: bool, - interfaces: Vec, MAX_INTERFACE_COUNT>, + interfaces: Vec, I>, } -impl<'d, D: Driver<'d>> UsbDevice<'d, D> { +impl<'d, D: Driver<'d>, const I: usize> UsbDevice<'d, D, I> { pub(crate) fn build( driver: D, config: Config<'d>, @@ -139,9 +137,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { device_descriptor: &'d [u8], config_descriptor: &'d [u8], bos_descriptor: &'d [u8], - interfaces: Vec, MAX_INTERFACE_COUNT>, + interfaces: Vec, I>, control_buf: &'d mut [u8], - ) -> UsbDevice<'d, D> { + ) -> UsbDevice<'d, D, I> { // Start the USB bus. // This prevent further allocation by consuming the driver. let (bus, control) = driver.start(config.max_packet_size_0 as u16); @@ -334,7 +332,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { } } -impl<'d, D: Driver<'d>> Inner<'d, D> { +impl<'d, D: Driver<'d>, const I: usize> Inner<'d, D, I> { async fn handle_bus_event(&mut self, evt: Event) { match evt { Event::Reset => { diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs index e5f7045240..d090f6be11 100644 --- a/examples/nrf/src/bin/usb_ethernet.rs +++ b/examples/nrf/src/bin/usb_ethernet.rs @@ -32,7 +32,7 @@ macro_rules! singleton { const MTU: usize = 1514; #[embassy_executor::task] -async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { +async fn usb_task(mut device: UsbDevice<'static, MyDriver, 4>) -> ! { device.run().await } diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs index 76e198719d..d01a56b832 100644 --- a/examples/nrf/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf/src/bin/usb_hid_keyboard.rs @@ -56,7 +56,7 @@ async fn main(_spawner: Spawner) { let mut state = State::new(); - let mut builder = Builder::new( + let mut builder = Builder::<'_, _, 4>::new( driver, config, &mut device_descriptor, diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs index 4916a38d4f..31d61c5677 100644 --- a/examples/nrf/src/bin/usb_hid_mouse.rs +++ b/examples/nrf/src/bin/usb_hid_mouse.rs @@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) { let mut state = State::new(); - let mut builder = Builder::new( + let mut builder = Builder::<'_, _, 4>::new( driver, config, &mut device_descriptor, diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs index 7c9c4184b3..ab38966395 100644 --- a/examples/nrf/src/bin/usb_serial.rs +++ b/examples/nrf/src/bin/usb_serial.rs @@ -52,7 +52,7 @@ async fn main(_spawner: Spawner) { let mut state = State::new(); - let mut builder = Builder::new( + let mut builder = Builder::<'_, _, 4>::new( driver, config, &mut device_descriptor, diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs index 93efc2fe67..d938fc76eb 100644 --- a/examples/nrf/src/bin/usb_serial_multitask.rs +++ b/examples/nrf/src/bin/usb_serial_multitask.rs @@ -17,7 +17,7 @@ use {defmt_rtt as _, panic_probe as _}; type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>; #[embassy_executor::task] -async fn usb_task(mut device: UsbDevice<'static, MyDriver>) { +async fn usb_task(mut device: UsbDevice<'static, MyDriver, 4>) { device.run().await; } diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index d0aec874a5..e6f9fe2bc3 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -29,7 +29,7 @@ macro_rules! singleton { const MTU: usize = 1514; #[embassy_executor::task] -async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { +async fn usb_task(mut device: UsbDevice<'static, MyDriver, 4>) -> ! { device.run().await } diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index b7d6493b4e..5a15811974 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) { let mut state = State::new(); - let mut builder = Builder::new( + let mut builder = Builder::<'_, _, 4>::new( driver, config, &mut device_descriptor, diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index ad92cdeb26..5ca26877c7 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs @@ -51,7 +51,7 @@ async fn main(_spawner: Spawner) { let mut state = State::new(); - let mut builder = Builder::new( + let mut builder = Builder::<'_, _, 4>::new( driver, config, &mut device_descriptor, diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index f6d27c8603..7287b7ac67 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs @@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) { let mut state = State::new(); - let mut builder = Builder::new( + let mut builder = Builder::<'_, _, 4>::new( driver, config, &mut device_descriptor, diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index b49329ea47..4191501a67 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -32,7 +32,7 @@ macro_rules! singleton { const MTU: usize = 1514; #[embassy_executor::task] -async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { +async fn usb_task(mut device: UsbDevice<'static, MyDriver, 4>) -> ! { device.run().await } diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index d38ed74965..b6cfdc0f11 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { let mut state = State::new(); - let mut builder = Builder::new( + let mut builder = Builder::<'_, _, 4>::new( driver, config, &mut device_descriptor, diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index 7562a4e96b..124b5462d9 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs @@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) { let mut state = State::new(); - let mut builder = Builder::new( + let mut builder = Builder::<'_, _, 4>::new( driver, config, &mut device_descriptor,