Merge #720
720: USB: New builder API  r=Dirbaio a=Dirbaio
    usb: improved descriptor building API
    
    The same API call allocates interfaces/endpoints/etc and writes their descriptors.
    This means less API calls, and less possibility to screw things up.
    
    DescriptorWriter is now private.
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
			
			
This commit is contained in:
		
						commit
						0f1a364cd9
					
				| @ -16,7 +16,7 @@ use embassy_usb::driver::EndpointOut; | ||||
| use embassy_usb::{ | ||||
|     control::{ControlHandler, InResponse, OutResponse, Request, RequestType}, | ||||
|     driver::{Driver, Endpoint, EndpointError, EndpointIn}, | ||||
|     UsbDeviceBuilder, | ||||
|     Builder, | ||||
| }; | ||||
| 
 | ||||
| #[cfg(feature = "usbd-hid")] | ||||
| @ -98,7 +98,7 @@ pub struct HidReaderWriter<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N | ||||
| } | ||||
| 
 | ||||
| fn build<'d, D: Driver<'d>>( | ||||
|     builder: &mut UsbDeviceBuilder<'d, D>, | ||||
|     builder: &mut Builder<'d, D>, | ||||
|     state: &'d mut State<'d>, | ||||
|     config: Config<'d>, | ||||
|     with_out_endpoint: bool, | ||||
| @ -110,23 +110,13 @@ fn build<'d, D: Driver<'d>>( | ||||
|     )); | ||||
| 
 | ||||
|     let len = config.report_descriptor.len(); | ||||
|     let if_num = builder.alloc_interface_with_handler(control); | ||||
|     let ep_in = builder.alloc_interrupt_endpoint_in(config.max_packet_size, config.poll_ms); | ||||
|     let ep_out = if with_out_endpoint { | ||||
|         Some(builder.alloc_interrupt_endpoint_out(config.max_packet_size, config.poll_ms)) | ||||
|     } else { | ||||
|         None | ||||
|     }; | ||||
| 
 | ||||
|     builder.config_descriptor.interface( | ||||
|         if_num, | ||||
|         USB_CLASS_HID, | ||||
|         USB_SUBCLASS_NONE, | ||||
|         USB_PROTOCOL_NONE, | ||||
|     ); | ||||
|     let mut func = builder.function(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE); | ||||
|     let mut iface = func.interface(Some(control)); | ||||
|     let mut alt = iface.alt_setting(USB_CLASS_HID, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE); | ||||
| 
 | ||||
|     // HID descriptor
 | ||||
|     builder.config_descriptor.write( | ||||
|     alt.descriptor( | ||||
|         HID_DESC_DESCTYPE_HID, | ||||
|         &[ | ||||
|             // HID Class spec version
 | ||||
| @ -144,10 +134,12 @@ fn build<'d, D: Driver<'d>>( | ||||
|         ], | ||||
|     ); | ||||
| 
 | ||||
|     builder.config_descriptor.endpoint(ep_in.info()); | ||||
|     if let Some(ep_out) = &ep_out { | ||||
|         builder.config_descriptor.endpoint(ep_out.info()); | ||||
|     } | ||||
|     let ep_in = alt.endpoint_interrupt_in(config.max_packet_size, config.poll_ms); | ||||
|     let ep_out = if with_out_endpoint { | ||||
|         Some(alt.endpoint_interrupt_out(config.max_packet_size, config.poll_ms)) | ||||
|     } else { | ||||
|         None | ||||
|     }; | ||||
| 
 | ||||
|     (ep_out, ep_in, &state.out_report_offset) | ||||
| } | ||||
| @ -160,11 +152,7 @@ impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> | ||||
|     /// 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 UsbDeviceBuilder<'d, D>, | ||||
|         state: &'d mut State<'d>, | ||||
|         config: Config<'d>, | ||||
|     ) -> Self { | ||||
|     pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: Config<'d>) -> Self { | ||||
|         let (ep_out, ep_in, offset) = build(builder, state, config, true); | ||||
| 
 | ||||
|         Self { | ||||
| @ -246,11 +234,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 UsbDeviceBuilder<'d, D>, | ||||
|         state: &'d mut State<'d>, | ||||
|         config: Config<'d>, | ||||
|     ) -> Self { | ||||
|     pub fn new(builder: &mut Builder<'d, D>, 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()); | ||||
|  | ||||
| @ -11,7 +11,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; | ||||
| use embassy::blocking_mutex::CriticalSectionMutex; | ||||
| use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; | ||||
| use embassy_usb::driver::{Endpoint, EndpointError, EndpointIn, EndpointOut}; | ||||
| use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder}; | ||||
| use embassy_usb::{driver::Driver, types::*, Builder}; | ||||
| 
 | ||||
| /// This should be used as `device_class` when building the `UsbDevice`.
 | ||||
| pub const USB_CLASS_CDC: u8 = 0x02; | ||||
| @ -163,7 +163,7 @@ 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 UsbDeviceBuilder<'d, D>, | ||||
|         builder: &mut Builder<'d, D>, | ||||
|         state: &'d mut State<'d>, | ||||
|         max_packet_size: u16, | ||||
|     ) -> Self { | ||||
| @ -175,26 +175,15 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { | ||||
| 
 | ||||
|         assert!(builder.control_buf_len() >= 7); | ||||
| 
 | ||||
|         let comm_if = builder.alloc_interface_with_handler(control); | ||||
|         let comm_ep = builder.alloc_interrupt_endpoint_in(8, 255); | ||||
|         let data_if = builder.alloc_interface(); | ||||
|         let read_ep = builder.alloc_bulk_endpoint_out(max_packet_size); | ||||
|         let write_ep = builder.alloc_bulk_endpoint_in(max_packet_size); | ||||
|         let mut func = builder.function(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE); | ||||
| 
 | ||||
|         builder.config_descriptor.iad( | ||||
|             comm_if, | ||||
|             2, | ||||
|             USB_CLASS_CDC, | ||||
|             CDC_SUBCLASS_ACM, | ||||
|             CDC_PROTOCOL_NONE, | ||||
|         ); | ||||
|         builder.config_descriptor.interface( | ||||
|             comm_if, | ||||
|             USB_CLASS_CDC, | ||||
|             CDC_SUBCLASS_ACM, | ||||
|             CDC_PROTOCOL_NONE, | ||||
|         ); | ||||
|         builder.config_descriptor.write( | ||||
|         // Control interface
 | ||||
|         let mut iface = func.interface(Some(control)); | ||||
|         let comm_if = iface.interface_number(); | ||||
|         let data_if = u8::from(comm_if) + 1; | ||||
|         let mut alt = iface.alt_setting(USB_CLASS_CDC, CDC_SUBCLASS_ACM, CDC_PROTOCOL_NONE); | ||||
| 
 | ||||
|         alt.descriptor( | ||||
|             CS_INTERFACE, | ||||
|             &[ | ||||
|                 CDC_TYPE_HEADER, // bDescriptorSubtype
 | ||||
| @ -202,14 +191,14 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { | ||||
|                 0x01, // bcdCDC (1.10)
 | ||||
|             ], | ||||
|         ); | ||||
|         builder.config_descriptor.write( | ||||
|         alt.descriptor( | ||||
|             CS_INTERFACE, | ||||
|             &[ | ||||
|                 CDC_TYPE_ACM, // bDescriptorSubtype
 | ||||
|                 0x00,         // bmCapabilities
 | ||||
|             ], | ||||
|         ); | ||||
|         builder.config_descriptor.write( | ||||
|         alt.descriptor( | ||||
|             CS_INTERFACE, | ||||
|             &[ | ||||
|                 CDC_TYPE_UNION, // bDescriptorSubtype
 | ||||
| @ -217,7 +206,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { | ||||
|                 data_if.into(), // bSubordinateInterface
 | ||||
|             ], | ||||
|         ); | ||||
|         builder.config_descriptor.write( | ||||
|         alt.descriptor( | ||||
|             CS_INTERFACE, | ||||
|             &[ | ||||
|                 CDC_TYPE_CALL_MANAGEMENT, // bDescriptorSubtype
 | ||||
| @ -225,13 +214,15 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { | ||||
|                 data_if.into(),           // bDataInterface
 | ||||
|             ], | ||||
|         ); | ||||
|         builder.config_descriptor.endpoint(comm_ep.info()); | ||||
| 
 | ||||
|         builder | ||||
|             .config_descriptor | ||||
|             .interface(data_if, USB_CLASS_CDC_DATA, 0x00, 0x00); | ||||
|         builder.config_descriptor.endpoint(write_ep.info()); | ||||
|         builder.config_descriptor.endpoint(read_ep.info()); | ||||
|         let comm_ep = alt.endpoint_interrupt_in(8, 255); | ||||
| 
 | ||||
|         // Data interface
 | ||||
|         let mut iface = func.interface(None); | ||||
|         let data_if = iface.interface_number(); | ||||
|         let mut alt = iface.alt_setting(USB_CLASS_CDC_DATA, 0x00, CDC_PROTOCOL_NONE); | ||||
|         let read_ep = alt.endpoint_bulk_out(max_packet_size); | ||||
|         let write_ep = alt.endpoint_bulk_in(max_packet_size); | ||||
| 
 | ||||
|         CdcAcmClass { | ||||
|             _comm_ep: comm_ep, | ||||
|  | ||||
| @ -2,7 +2,7 @@ use heapless::Vec; | ||||
| 
 | ||||
| use super::control::ControlHandler; | ||||
| use super::descriptor::{BosWriter, DescriptorWriter}; | ||||
| use super::driver::{Driver, EndpointAllocError}; | ||||
| use super::driver::{Driver, Endpoint}; | ||||
| use super::types::*; | ||||
| use super::DeviceStateHandler; | ||||
| use super::UsbDevice; | ||||
| @ -117,8 +117,8 @@ impl<'a> Config<'a> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Used to build new [`UsbDevice`]s.
 | ||||
| pub struct UsbDeviceBuilder<'d, D: Driver<'d>> { | ||||
| /// [`UsbDevice`] builder.
 | ||||
| pub struct Builder<'d, D: Driver<'d>> { | ||||
|     config: Config<'d>, | ||||
|     handler: Option<&'d dyn DeviceStateHandler>, | ||||
|     interfaces: Vec<(u8, &'d mut dyn ControlHandler), MAX_INTERFACE_COUNT>, | ||||
| @ -128,13 +128,12 @@ pub struct UsbDeviceBuilder<'d, D: Driver<'d>> { | ||||
|     next_interface_number: u8, | ||||
|     next_string_index: u8, | ||||
| 
 | ||||
|     // TODO make not pub?
 | ||||
|     pub device_descriptor: DescriptorWriter<'d>, | ||||
|     pub config_descriptor: DescriptorWriter<'d>, | ||||
|     pub bos_descriptor: BosWriter<'d>, | ||||
|     device_descriptor: DescriptorWriter<'d>, | ||||
|     config_descriptor: DescriptorWriter<'d>, | ||||
|     bos_descriptor: BosWriter<'d>, | ||||
| } | ||||
| 
 | ||||
| impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { | ||||
| impl<'d, D: Driver<'d>> Builder<'d, D> { | ||||
|     /// Creates a builder for constructing a new [`UsbDevice`].
 | ||||
|     ///
 | ||||
|     /// `control_buf` is a buffer used for USB control request data. It should be sized
 | ||||
| @ -175,7 +174,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { | ||||
|         config_descriptor.configuration(&config); | ||||
|         bos_descriptor.bos(); | ||||
| 
 | ||||
|         UsbDeviceBuilder { | ||||
|         Builder { | ||||
|             driver, | ||||
|             handler, | ||||
|             config, | ||||
| @ -207,36 +206,12 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates a new interface number.
 | ||||
|     pub fn alloc_interface(&mut self) -> InterfaceNumber { | ||||
|         let number = self.next_interface_number; | ||||
|         self.next_interface_number += 1; | ||||
| 
 | ||||
|         InterfaceNumber::new(number) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the size of the control request data buffer. Can be used by
 | ||||
|     /// classes to validate the buffer is large enough for their needs.
 | ||||
|     pub fn control_buf_len(&self) -> usize { | ||||
|         self.control_buf.len() | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates a new interface number, with a handler that will be called
 | ||||
|     /// for all the control requests directed to it.
 | ||||
|     pub fn alloc_interface_with_handler( | ||||
|         &mut self, | ||||
|         handler: &'d mut dyn ControlHandler, | ||||
|     ) -> InterfaceNumber { | ||||
|         let number = self.next_interface_number; | ||||
|         self.next_interface_number += 1; | ||||
| 
 | ||||
|         if self.interfaces.push((number, handler)).is_err() { | ||||
|             panic!("max class count reached") | ||||
|         } | ||||
| 
 | ||||
|         InterfaceNumber::new(number) | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates a new string index.
 | ||||
|     pub fn alloc_string(&mut self) -> StringIndex { | ||||
|         let index = self.next_string_index; | ||||
| @ -245,146 +220,212 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> { | ||||
|         StringIndex::new(index) | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates an in endpoint.
 | ||||
|     /// Add an USB function.
 | ||||
|     ///
 | ||||
|     /// This directly delegates to [`Driver::alloc_endpoint_in`], so see that method for details. In most
 | ||||
|     /// cases classes should call the endpoint type specific methods instead.
 | ||||
|     pub fn alloc_endpoint_in( | ||||
|     /// If [`Config::composite_with_iads`] is set, this will add an IAD descriptor
 | ||||
|     /// 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> { | ||||
|         let iface_count_index = if self.config.composite_with_iads { | ||||
|             self.config_descriptor.iad( | ||||
|                 InterfaceNumber::new(self.next_interface_number), | ||||
|                 0, | ||||
|                 class, | ||||
|                 subclass, | ||||
|                 protocol, | ||||
|             ); | ||||
| 
 | ||||
|             Some(self.config_descriptor.position() - 5) | ||||
|         } else { | ||||
|             None | ||||
|         }; | ||||
| 
 | ||||
|         FunctionBuilder { | ||||
|             builder: self, | ||||
|             iface_count_index, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Function builder.
 | ||||
| ///
 | ||||
| /// 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>, | ||||
|     iface_count_index: Option<usize>, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> { | ||||
|     /// Add an interface to the function.
 | ||||
|     ///
 | ||||
|     /// Interface numbers are guaranteed to be allocated consecutively, starting from 0.
 | ||||
|     pub fn interface( | ||||
|         &mut self, | ||||
|         handler: Option<&'d mut dyn ControlHandler>, | ||||
|     ) -> InterfaceBuilder<'_, 'd, D> { | ||||
|         if let Some(i) = self.iface_count_index { | ||||
|             self.builder.config_descriptor.buf[i] += 1; | ||||
|         } | ||||
| 
 | ||||
|         let number = self.builder.next_interface_number; | ||||
|         self.builder.next_interface_number += 1; | ||||
| 
 | ||||
|         if let Some(handler) = handler { | ||||
|             if self.builder.interfaces.push((number, handler)).is_err() { | ||||
|                 panic!("max interface count reached") | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         InterfaceBuilder { | ||||
|             builder: self.builder, | ||||
|             interface_number: InterfaceNumber::new(number), | ||||
|             next_alt_setting_number: 0, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Interface builder.
 | ||||
| pub struct InterfaceBuilder<'a, 'd, D: Driver<'d>> { | ||||
|     builder: &'a mut Builder<'d, D>, | ||||
|     interface_number: InterfaceNumber, | ||||
|     next_alt_setting_number: u8, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> { | ||||
|     /// Get the interface number.
 | ||||
|     pub fn interface_number(&self) -> InterfaceNumber { | ||||
|         self.interface_number | ||||
|     } | ||||
| 
 | ||||
|     /// Add an alternate setting to the interface and write its descriptor.
 | ||||
|     ///
 | ||||
|     /// 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> { | ||||
|         let number = self.next_alt_setting_number; | ||||
|         self.next_alt_setting_number += 1; | ||||
| 
 | ||||
|         self.builder.config_descriptor.interface_alt( | ||||
|             self.interface_number, | ||||
|             number, | ||||
|             class, | ||||
|             subclass, | ||||
|             protocol, | ||||
|             None, | ||||
|         ); | ||||
| 
 | ||||
|         InterfaceAltBuilder { | ||||
|             builder: self.builder, | ||||
|             interface_number: self.interface_number, | ||||
|             alt_setting_number: number, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Interface alternate setting builder.
 | ||||
| pub struct InterfaceAltBuilder<'a, 'd, D: Driver<'d>> { | ||||
|     builder: &'a mut Builder<'d, D>, | ||||
|     interface_number: InterfaceNumber, | ||||
|     alt_setting_number: u8, | ||||
| } | ||||
| 
 | ||||
| impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { | ||||
|     /// Get the interface number.
 | ||||
|     pub fn interface_number(&self) -> InterfaceNumber { | ||||
|         self.interface_number | ||||
|     } | ||||
| 
 | ||||
|     /// Get the alternate setting number.
 | ||||
|     pub fn alt_setting_number(&self) -> u8 { | ||||
|         self.alt_setting_number | ||||
|     } | ||||
| 
 | ||||
|     /// Add a custom descriptor to this alternate setting.
 | ||||
|     ///
 | ||||
|     /// Descriptors are written in the order builder functions are called. Note that some
 | ||||
|     /// classes care about the order.
 | ||||
|     pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) { | ||||
|         self.builder | ||||
|             .config_descriptor | ||||
|             .write(descriptor_type, descriptor) | ||||
|     } | ||||
| 
 | ||||
|     fn endpoint_in( | ||||
|         &mut self, | ||||
|         ep_addr: Option<EndpointAddress>, | ||||
|         ep_type: EndpointType, | ||||
|         max_packet_size: u16, | ||||
|         interval: u8, | ||||
|     ) -> Result<D::EndpointIn, EndpointAllocError> { | ||||
|         self.driver | ||||
|             .alloc_endpoint_in(ep_addr, ep_type, max_packet_size, interval) | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates an out endpoint.
 | ||||
|     ///
 | ||||
|     /// This directly delegates to [`Driver::alloc_endpoint_out`], so see that method for details. In most
 | ||||
|     /// cases classes should call the endpoint type specific methods instead.
 | ||||
|     pub fn alloc_endpoint_out( | ||||
|         &mut self, | ||||
|         ep_addr: Option<EndpointAddress>, | ||||
|         ep_type: EndpointType, | ||||
|         max_packet_size: u16, | ||||
|         interval: u8, | ||||
|     ) -> Result<D::EndpointOut, EndpointAllocError> { | ||||
|         self.driver | ||||
|             .alloc_endpoint_out(ep_addr, ep_type, max_packet_size, interval) | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates a control in endpoint.
 | ||||
|     ///
 | ||||
|     /// This crate implements the control state machine only for endpoint 0. If classes want to
 | ||||
|     /// support control requests in other endpoints, the state machine must be implemented manually.
 | ||||
|     /// This should rarely be needed by classes.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64.
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
 | ||||
|     /// feasibly recoverable.
 | ||||
|     #[inline] | ||||
|     pub fn alloc_control_endpoint_in(&mut self, max_packet_size: u16) -> D::EndpointIn { | ||||
|         self.alloc_endpoint_in(None, EndpointType::Control, max_packet_size, 0) | ||||
|             .expect("alloc_ep failed") | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates a control out endpoint.
 | ||||
|     ///
 | ||||
|     /// This crate implements the control state machine only for endpoint 0. If classes want to
 | ||||
|     /// support control requests in other endpoints, the state machine must be implemented manually.
 | ||||
|     /// This should rarely be needed by classes.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64.
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
 | ||||
|     /// feasibly recoverable.
 | ||||
|     #[inline] | ||||
|     pub fn alloc_control_pipe(&mut self, max_packet_size: u16) -> D::ControlPipe { | ||||
|         self.driver | ||||
|             .alloc_control_pipe(max_packet_size) | ||||
|             .expect("alloc_control_pipe failed") | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates a bulk in endpoint.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64.
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
 | ||||
|     /// feasibly recoverable.
 | ||||
|     #[inline] | ||||
|     pub fn alloc_bulk_endpoint_in(&mut self, max_packet_size: u16) -> D::EndpointIn { | ||||
|         self.alloc_endpoint_in(None, EndpointType::Bulk, max_packet_size, 0) | ||||
|             .expect("alloc_ep failed") | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates a bulk out endpoint.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64.
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
 | ||||
|     /// feasibly recoverable.
 | ||||
|     #[inline] | ||||
|     pub fn alloc_bulk_endpoint_out(&mut self, max_packet_size: u16) -> D::EndpointOut { | ||||
|         self.alloc_endpoint_out(None, EndpointType::Bulk, max_packet_size, 0) | ||||
|             .expect("alloc_ep failed") | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates a bulk in endpoint.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `max_packet_size` - Maximum packet size in bytes. Cannot exceed 64 bytes.
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
 | ||||
|     /// feasibly recoverable.
 | ||||
|     #[inline] | ||||
|     pub fn alloc_interrupt_endpoint_in( | ||||
|         &mut self, | ||||
|         max_packet_size: u16, | ||||
|         interval: u8, | ||||
|     ) -> D::EndpointIn { | ||||
|         self.alloc_endpoint_in(None, EndpointType::Interrupt, max_packet_size, interval) | ||||
|             .expect("alloc_ep failed") | ||||
|         let ep = self | ||||
|             .builder | ||||
|             .driver | ||||
|             .alloc_endpoint_in(ep_addr, ep_type, max_packet_size, interval) | ||||
|             .expect("alloc_endpoint_in failed"); | ||||
| 
 | ||||
|         self.builder.config_descriptor.endpoint(ep.info()); | ||||
| 
 | ||||
|         ep | ||||
|     } | ||||
| 
 | ||||
|     /// Allocates a bulk in endpoint.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `max_packet_size` - Maximum packet size in bytes. Cannot exceed 64 bytes.
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
 | ||||
|     /// feasibly recoverable.
 | ||||
|     #[inline] | ||||
|     pub fn alloc_interrupt_endpoint_out( | ||||
|     fn endpoint_out( | ||||
|         &mut self, | ||||
|         ep_addr: Option<EndpointAddress>, | ||||
|         ep_type: EndpointType, | ||||
|         max_packet_size: u16, | ||||
|         interval: u8, | ||||
|     ) -> D::EndpointOut { | ||||
|         self.alloc_endpoint_out(None, EndpointType::Interrupt, max_packet_size, interval) | ||||
|             .expect("alloc_ep failed") | ||||
|         let ep = self | ||||
|             .builder | ||||
|             .driver | ||||
|             .alloc_endpoint_out(ep_addr, ep_type, max_packet_size, interval) | ||||
|             .expect("alloc_endpoint_out failed"); | ||||
| 
 | ||||
|         self.builder.config_descriptor.endpoint(ep.info()); | ||||
| 
 | ||||
|         ep | ||||
|     } | ||||
| 
 | ||||
|     /// Allocate a BULK IN endpoint and write its descriptor.
 | ||||
|     ///
 | ||||
|     /// Descriptors are written in the order builder functions are called. Note that some
 | ||||
|     /// classes care about the order.
 | ||||
|     pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn { | ||||
|         self.endpoint_in(None, EndpointType::Bulk, max_packet_size, 0) | ||||
|     } | ||||
| 
 | ||||
|     /// Allocate a BULK OUT endpoint and write its descriptor.
 | ||||
|     ///
 | ||||
|     /// Descriptors are written in the order builder functions are called. Note that some
 | ||||
|     /// classes care about the order.
 | ||||
|     pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut { | ||||
|         self.endpoint_out(None, EndpointType::Bulk, max_packet_size, 0) | ||||
|     } | ||||
| 
 | ||||
|     /// Allocate a INTERRUPT IN endpoint and write its descriptor.
 | ||||
|     ///
 | ||||
|     /// Descriptors are written in the order builder functions are called. Note that some
 | ||||
|     /// classes care about the order.
 | ||||
|     pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval: u8) -> D::EndpointIn { | ||||
|         self.endpoint_in(None, EndpointType::Interrupt, max_packet_size, interval) | ||||
|     } | ||||
| 
 | ||||
|     /// Allocate a INTERRUPT OUT endpoint and write its descriptor.
 | ||||
|     pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval: u8) -> D::EndpointOut { | ||||
|         self.endpoint_out(None, EndpointType::Interrupt, max_packet_size, interval) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -33,12 +33,11 @@ pub mod capability_type { | ||||
| } | ||||
| 
 | ||||
| /// A writer for USB descriptors.
 | ||||
| pub struct DescriptorWriter<'a> { | ||||
|     buf: &'a mut [u8], | ||||
| pub(crate) struct DescriptorWriter<'a> { | ||||
|     pub buf: &'a mut [u8], | ||||
|     position: usize, | ||||
|     num_interfaces_mark: Option<usize>, | ||||
|     num_endpoints_mark: Option<usize>, | ||||
|     write_iads: bool, | ||||
| } | ||||
| 
 | ||||
| impl<'a> DescriptorWriter<'a> { | ||||
| @ -48,7 +47,6 @@ impl<'a> DescriptorWriter<'a> { | ||||
|             position: 0, | ||||
|             num_interfaces_mark: None, | ||||
|             num_endpoints_mark: None, | ||||
|             write_iads: false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -106,8 +104,6 @@ impl<'a> DescriptorWriter<'a> { | ||||
|     pub(crate) fn configuration(&mut self, config: &Config) { | ||||
|         self.num_interfaces_mark = Some(self.position + 4); | ||||
| 
 | ||||
|         self.write_iads = config.composite_with_iads; | ||||
| 
 | ||||
|         self.write( | ||||
|             descriptor_type::CONFIGURATION, | ||||
|             &[ | ||||
| @ -160,10 +156,6 @@ impl<'a> DescriptorWriter<'a> { | ||||
|         function_sub_class: u8, | ||||
|         function_protocol: u8, | ||||
|     ) { | ||||
|         if !self.write_iads { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         self.write( | ||||
|             descriptor_type::IAD, | ||||
|             &[ | ||||
| @ -177,33 +169,6 @@ impl<'a> DescriptorWriter<'a> { | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     /// Writes a interface descriptor.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `number` - Interface number previously allocated with
 | ||||
|     ///   [`UsbDeviceBuilder::interface`](crate::bus::UsbDeviceBuilder::interface).
 | ||||
|     /// * `interface_class` - Class code assigned by USB.org. Use `0xff` for vendor-specific devices
 | ||||
|     ///   that do not conform to any class.
 | ||||
|     /// * `interface_sub_class` - Sub-class code. Depends on class.
 | ||||
|     /// * `interface_protocol` - Protocol code. Depends on class and sub-class.
 | ||||
|     pub fn interface( | ||||
|         &mut self, | ||||
|         number: InterfaceNumber, | ||||
|         interface_class: u8, | ||||
|         interface_sub_class: u8, | ||||
|         interface_protocol: u8, | ||||
|     ) { | ||||
|         self.interface_alt( | ||||
|             number, | ||||
|             DEFAULT_ALTERNATE_SETTING, | ||||
|             interface_class, | ||||
|             interface_sub_class, | ||||
|             interface_protocol, | ||||
|             None, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     /// Writes a interface descriptor with a specific alternate setting and
 | ||||
|     /// interface string identifier.
 | ||||
|     ///
 | ||||
|  | ||||
| @ -19,8 +19,8 @@ use self::descriptor::*; | ||||
| use self::driver::{Bus, Driver, Event}; | ||||
| use self::types::*; | ||||
| 
 | ||||
| pub use self::builder::Builder; | ||||
| pub use self::builder::Config; | ||||
| pub use self::builder::UsbDeviceBuilder; | ||||
| 
 | ||||
| /// The global state of the USB device.
 | ||||
| ///
 | ||||
|  | ||||
| @ -17,7 +17,7 @@ use embassy_nrf::pac; | ||||
| use embassy_nrf::usb::Driver; | ||||
| use embassy_nrf::Peripherals; | ||||
| use embassy_usb::control::OutResponse; | ||||
| use embassy_usb::{Config, DeviceStateHandler, UsbDeviceBuilder}; | ||||
| use embassy_usb::{Builder, Config, DeviceStateHandler}; | ||||
| use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State}; | ||||
| use futures::future::join; | ||||
| use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | ||||
| @ -77,7 +77,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | ||||
| 
 | ||||
|     let mut state = State::new(); | ||||
| 
 | ||||
|     let mut builder = UsbDeviceBuilder::new( | ||||
|     let mut builder = Builder::new( | ||||
|         driver, | ||||
|         config, | ||||
|         &mut device_descriptor, | ||||
|  | ||||
| @ -12,7 +12,7 @@ use embassy_nrf::pac; | ||||
| use embassy_nrf::usb::Driver; | ||||
| use embassy_nrf::Peripherals; | ||||
| use embassy_usb::control::OutResponse; | ||||
| use embassy_usb::{Config, UsbDeviceBuilder}; | ||||
| use embassy_usb::{Builder, Config}; | ||||
| use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State}; | ||||
| use futures::future::join; | ||||
| use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | ||||
| @ -54,7 +54,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | ||||
| 
 | ||||
|     let mut state = State::new(); | ||||
| 
 | ||||
|     let mut builder = UsbDeviceBuilder::new( | ||||
|     let mut builder = Builder::new( | ||||
|         driver, | ||||
|         config, | ||||
|         &mut device_descriptor, | ||||
|  | ||||
| @ -11,7 +11,7 @@ use embassy_nrf::pac; | ||||
| use embassy_nrf::usb::{Driver, Instance}; | ||||
| use embassy_nrf::Peripherals; | ||||
| use embassy_usb::driver::EndpointError; | ||||
| use embassy_usb::{Config, UsbDeviceBuilder}; | ||||
| use embassy_usb::{Builder, Config}; | ||||
| use embassy_usb_serial::{CdcAcmClass, State}; | ||||
| use futures::future::join; | ||||
| 
 | ||||
| @ -47,7 +47,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { | ||||
| 
 | ||||
|     let mut state = State::new(); | ||||
| 
 | ||||
|     let mut builder = UsbDeviceBuilder::new( | ||||
|     let mut builder = Builder::new( | ||||
|         driver, | ||||
|         config, | ||||
|         &mut device_descriptor, | ||||
|  | ||||
| @ -12,7 +12,7 @@ use embassy_nrf::usb::Driver; | ||||
| use embassy_nrf::Peripherals; | ||||
| use embassy_nrf::{interrupt, peripherals}; | ||||
| use embassy_usb::driver::EndpointError; | ||||
| use embassy_usb::{Config, UsbDevice, UsbDeviceBuilder}; | ||||
| use embassy_usb::{Builder, Config, UsbDevice}; | ||||
| use embassy_usb_serial::{CdcAcmClass, State}; | ||||
| 
 | ||||
| use defmt_rtt as _; // global logger
 | ||||
| @ -72,7 +72,7 @@ async fn main(spawner: Spawner, p: Peripherals) { | ||||
|     }); | ||||
| 
 | ||||
|     // Create embassy-usb DeviceBuilder using the driver and config.
 | ||||
|     let mut builder = UsbDeviceBuilder::new( | ||||
|     let mut builder = Builder::new( | ||||
|         driver, | ||||
|         config, | ||||
|         &mut res.device_descriptor, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user