Merge pull request #2068 from barafael/const_usb_config_builder_new

Constify UsbDevice Config::new (and clippy fixes) in embassy-usb
This commit is contained in:
Dario Nieuwenhuis 2023-10-16 23:23:10 +00:00 committed by GitHub
commit 7fd868ade9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 156 additions and 166 deletions

View File

@ -70,9 +70,11 @@ fn main() {
// envvars take priority. // envvars take priority.
if !cfg.seen_env { if !cfg.seen_env {
if cfg.seen_feature { assert!(
panic!("multiple values set for feature {}: {} and {}", name, cfg.value, value); !cfg.seen_feature,
} "multiple values set for feature {}: {} and {}",
name, cfg.value, value
);
cfg.value = value; cfg.value = value;
cfg.seen_feature = true; cfg.seen_feature = true;

View File

@ -1,17 +1,17 @@
use heapless::Vec; use heapless::Vec;
use crate::config::*; use crate::config::MAX_HANDLER_COUNT;
use crate::descriptor::{BosWriter, DescriptorWriter}; use crate::descriptor::{BosWriter, DescriptorWriter};
use crate::driver::{Driver, Endpoint, EndpointType}; use crate::driver::{Driver, Endpoint, EndpointType};
#[cfg(feature = "msos-descriptor")] #[cfg(feature = "msos-descriptor")]
use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter};
use crate::types::*; use crate::types::{InterfaceNumber, StringIndex};
use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
/// Configuration used when creating [UsbDevice]. /// Configuration used when creating [`UsbDevice`].
pub struct Config<'a> { pub struct Config<'a> {
pub(crate) vendor_id: u16, pub(crate) vendor_id: u16,
pub(crate) product_id: u16, pub(crate) product_id: u16,
@ -99,7 +99,7 @@ pub struct Config<'a> {
impl<'a> Config<'a> { impl<'a> Config<'a> {
/// Create default configuration with the provided vid and pid values. /// Create default configuration with the provided vid and pid values.
pub fn new(vid: u16, pid: u16) -> Self { pub const fn new(vid: u16, pid: u16) -> Self {
Self { Self {
device_class: 0x00, device_class: 0x00,
device_sub_class: 0x00, device_sub_class: 0x00,
@ -159,9 +159,10 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
panic!("if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01"); panic!("if composite_with_iads is set, you must set device_class = 0xEF, device_sub_class = 0x02, device_protocol = 0x01");
} }
if config.max_power > 500 { assert!(
panic!("The maximum allowed value for `max_power` is 500mA"); config.max_power <= 500,
} "The maximum allowed value for `max_power` is 500mA"
);
match config.max_packet_size_0 { match config.max_packet_size_0 {
8 | 16 | 32 | 64 => {} 8 | 16 | 32 | 64 => {}
@ -260,12 +261,11 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
/// The Handler is called on some USB bus events, and to handle all control requests not already /// The Handler is called on some USB bus events, and to handle all control requests not already
/// handled by the USB stack. /// handled by the USB stack.
pub fn handler(&mut self, handler: &'d mut dyn Handler) { pub fn handler(&mut self, handler: &'d mut dyn Handler) {
if self.handlers.push(handler).is_err() { assert!(
panic!( self.handlers.push(handler).is_ok(),
"embassy-usb: handler list full. Increase the `max_handler_count` compile-time setting. Current value: {}", "embassy-usb: handler list full. Increase the `max_handler_count` compile-time setting. Current value: {}",
MAX_HANDLER_COUNT MAX_HANDLER_COUNT
) );
}
} }
/// Allocates a new string index. /// Allocates a new string index.
@ -332,12 +332,10 @@ impl<'a, 'd, D: Driver<'d>> FunctionBuilder<'a, 'd, D> {
num_alt_settings: 0, num_alt_settings: 0,
}; };
if self.builder.interfaces.push(iface).is_err() { assert!(self.builder.interfaces.push(iface).is_ok(),
panic!( "embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}",
"embassy-usb: interface list full. Increase the `max_interface_count` compile-time setting. Current value: {}", MAX_INTERFACE_COUNT
MAX_INTERFACE_COUNT );
)
}
InterfaceBuilder { InterfaceBuilder {
builder: self.builder, builder: self.builder,
@ -371,7 +369,7 @@ pub struct InterfaceBuilder<'a, 'd, D: Driver<'d>> {
impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> { impl<'a, 'd, D: Driver<'d>> InterfaceBuilder<'a, 'd, D> {
/// Get the interface number. /// Get the interface number.
pub fn interface_number(&self) -> InterfaceNumber { pub const fn interface_number(&self) -> InterfaceNumber {
self.interface_number self.interface_number
} }
@ -422,12 +420,12 @@ pub struct InterfaceAltBuilder<'a, 'd, D: Driver<'d>> {
impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
/// Get the interface number. /// Get the interface number.
pub fn interface_number(&self) -> InterfaceNumber { pub const fn interface_number(&self) -> InterfaceNumber {
self.interface_number self.interface_number
} }
/// Get the alternate setting number. /// Get the alternate setting number.
pub fn alt_setting_number(&self) -> u8 { pub const fn alt_setting_number(&self) -> u8 {
self.alt_setting_number self.alt_setting_number
} }
@ -436,7 +434,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> {
/// Descriptors are written in the order builder functions are called. Note that some /// Descriptors are written in the order builder functions are called. Note that some
/// classes care about the order. /// classes care about the order.
pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) { pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) {
self.builder.config_descriptor.write(descriptor_type, descriptor) self.builder.config_descriptor.write(descriptor_type, descriptor);
} }
fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn {

View File

@ -11,7 +11,7 @@ use embassy_sync::waitqueue::WakerRegistration;
use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
use crate::types::*; use crate::types::InterfaceNumber;
use crate::{Builder, Handler}; use crate::{Builder, Handler};
/// This should be used as `device_class` when building the `UsbDevice`. /// This should be used as `device_class` when building the `UsbDevice`.
@ -39,12 +39,18 @@ pub struct State<'a> {
shared: ControlShared, shared: ControlShared,
} }
impl<'a> Default for State<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> State<'a> { impl<'a> State<'a> {
/// Create a new `State`. /// Create a new `State`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
control: MaybeUninit::uninit(), control: MaybeUninit::uninit(),
shared: Default::default(), shared: ControlShared::default(),
} }
} }
} }
@ -55,9 +61,9 @@ impl<'a> State<'a> {
/// writing USB packets with no intermediate buffers, but it will not act like a stream-like serial /// writing USB packets with no intermediate buffers, but it will not act like a stream-like serial
/// port. The following constraints must be followed if you use this class directly: /// port. The following constraints must be followed if you use this class directly:
/// ///
/// - `read_packet` must be called with a buffer large enough to hold max_packet_size bytes. /// - `read_packet` must be called with a buffer large enough to hold `max_packet_size` bytes.
/// - `write_packet` must not be called with a buffer larger than max_packet_size bytes. /// - `write_packet` must not be called with a buffer larger than `max_packet_size` bytes.
/// - If you write a packet that is exactly max_packet_size bytes long, it won't be processed by the /// - If you write a packet that is exactly `max_packet_size` bytes long, it won't be processed by the
/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP) /// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP)
/// can be sent if there is no other data to send. This is because USB bulk transactions must be /// can be sent if there is no other data to send. This is because USB bulk transactions must be
/// terminated with a short packet, even if the bulk endpoint is used for stream-like data. /// terminated with a short packet, even if the bulk endpoint is used for stream-like data.
@ -103,17 +109,16 @@ impl Default for ControlShared {
impl ControlShared { impl ControlShared {
async fn changed(&self) { async fn changed(&self) {
poll_fn(|cx| match self.changed.load(Ordering::Relaxed) { poll_fn(|cx| {
true => { if self.changed.load(Ordering::Relaxed) {
self.changed.store(false, Ordering::Relaxed); self.changed.store(false, Ordering::Relaxed);
Poll::Ready(()) Poll::Ready(())
} } else {
false => {
self.waker.borrow_mut().register(cx.waker()); self.waker.borrow_mut().register(cx.waker());
Poll::Pending Poll::Pending
} }
}) })
.await .await;
} }
} }
@ -192,7 +197,7 @@ impl<'d> Handler for Control<'d> {
// REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below. // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
REQ_GET_LINE_CODING if req.length == 7 => { REQ_GET_LINE_CODING if req.length == 7 => {
debug!("Sending line coding"); debug!("Sending line coding");
let coding = self.shared().line_coding.lock(|x| x.get()); let coding = self.shared().line_coding.lock(Cell::get);
assert!(buf.len() >= 7); assert!(buf.len() >= 7);
buf[0..4].copy_from_slice(&coding.data_rate.to_le_bytes()); buf[0..4].copy_from_slice(&coding.data_rate.to_le_bytes());
buf[4] = coding.stop_bits as u8; buf[4] = coding.stop_bits as u8;
@ -206,8 +211,8 @@ impl<'d> Handler for Control<'d> {
} }
impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
/// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For /// 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. /// 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>, state: &'d mut State<'d>, max_packet_size: u16) -> Self {
assert!(builder.control_buf_len() >= 7); assert!(builder.control_buf_len() >= 7);
@ -242,7 +247,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
&[ &[
CDC_TYPE_UNION, // bDescriptorSubtype CDC_TYPE_UNION, // bDescriptorSubtype
comm_if.into(), // bControlInterface comm_if.into(), // bControlInterface
data_if.into(), // bSubordinateInterface data_if, // bSubordinateInterface
], ],
); );
@ -283,7 +288,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
/// Gets the current line coding. The line coding contains information that's mainly relevant /// Gets the current line coding. The line coding contains information that's mainly relevant
/// for USB to UART serial port emulators, and can be ignored if not relevant. /// for USB to UART serial port emulators, and can be ignored if not relevant.
pub fn line_coding(&self) -> LineCoding { pub fn line_coding(&self) -> LineCoding {
self.control.line_coding.lock(|x| x.get()) self.control.line_coding.lock(Cell::get)
} }
/// Gets the DTR (data terminal ready) state /// Gets the DTR (data terminal ready) state
@ -308,7 +313,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
/// Waits for the USB host to enable this interface /// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) { pub async fn wait_connection(&mut self) {
self.read_ep.wait_enabled().await self.read_ep.wait_enabled().await;
} }
/// Split the class into a sender and receiver. /// Split the class into a sender and receiver.
@ -356,7 +361,7 @@ pub struct ControlChanged<'d> {
impl<'d> ControlChanged<'d> { impl<'d> ControlChanged<'d> {
/// Return a future for when the control settings change /// Return a future for when the control settings change
pub async fn control_changed(&self) { pub async fn control_changed(&self) {
self.control.changed().await self.control.changed().await;
} }
} }
@ -378,7 +383,7 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
/// Gets the current line coding. The line coding contains information that's mainly relevant /// Gets the current line coding. The line coding contains information that's mainly relevant
/// for USB to UART serial port emulators, and can be ignored if not relevant. /// for USB to UART serial port emulators, and can be ignored if not relevant.
pub fn line_coding(&self) -> LineCoding { pub fn line_coding(&self) -> LineCoding {
self.control.line_coding.lock(|x| x.get()) self.control.line_coding.lock(Cell::get)
} }
/// Gets the DTR (data terminal ready) state /// Gets the DTR (data terminal ready) state
@ -398,7 +403,7 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
/// Waits for the USB host to enable this interface /// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) { pub async fn wait_connection(&mut self) {
self.write_ep.wait_enabled().await self.write_ep.wait_enabled().await;
} }
} }
@ -420,7 +425,7 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
/// Gets the current line coding. The line coding contains information that's mainly relevant /// Gets the current line coding. The line coding contains information that's mainly relevant
/// for USB to UART serial port emulators, and can be ignored if not relevant. /// for USB to UART serial port emulators, and can be ignored if not relevant.
pub fn line_coding(&self) -> LineCoding { pub fn line_coding(&self) -> LineCoding {
self.control.line_coding.lock(|x| x.get()) self.control.line_coding.lock(Cell::get)
} }
/// Gets the DTR (data terminal ready) state /// Gets the DTR (data terminal ready) state
@ -440,7 +445,7 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
/// Waits for the USB host to enable this interface /// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) { pub async fn wait_connection(&mut self) {
self.read_ep.wait_enabled().await self.read_ep.wait_enabled().await;
} }
} }
@ -514,17 +519,17 @@ impl LineCoding {
} }
/// Gets the number of data bits for UART communication. /// Gets the number of data bits for UART communication.
pub fn data_bits(&self) -> u8 { pub const fn data_bits(&self) -> u8 {
self.data_bits self.data_bits
} }
/// Gets the parity type for UART communication. /// Gets the parity type for UART communication.
pub fn parity_type(&self) -> ParityType { pub const fn parity_type(&self) -> ParityType {
self.parity_type self.parity_type
} }
/// Gets the data rate in bits per second for UART communication. /// Gets the data rate in bits per second for UART communication.
pub fn data_rate(&self) -> u32 { pub const fn data_rate(&self) -> u32 {
self.data_rate self.data_rate
} }
} }

View File

@ -16,10 +16,11 @@
use core::intrinsics::copy_nonoverlapping; use core::intrinsics::copy_nonoverlapping;
use core::mem::{size_of, MaybeUninit}; use core::mem::{size_of, MaybeUninit};
use core::ptr::addr_of;
use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType};
use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
use crate::types::*; use crate::types::{InterfaceNumber, StringIndex};
use crate::{Builder, Handler}; use crate::{Builder, Handler};
pub mod embassy_net; pub mod embassy_net;
@ -62,9 +63,9 @@ const REQ_SET_NTB_INPUT_SIZE: u8 = 0x86;
//const NOTIF_POLL_INTERVAL: u8 = 20; //const NOTIF_POLL_INTERVAL: u8 = 20;
const NTB_MAX_SIZE: usize = 2048; const NTB_MAX_SIZE: usize = 2048;
const SIG_NTH: u32 = 0x484d434e; const SIG_NTH: u32 = 0x484d_434e;
const SIG_NDP_NO_FCS: u32 = 0x304d434e; const SIG_NDP_NO_FCS: u32 = 0x304d_434e;
const SIG_NDP_WITH_FCS: u32 = 0x314d434e; const SIG_NDP_WITH_FCS: u32 = 0x314d_434e;
const ALTERNATE_SETTING_DISABLED: u8 = 0x00; const ALTERNATE_SETTING_DISABLED: u8 = 0x00;
const ALTERNATE_SETTING_ENABLED: u8 = 0x01; const ALTERNATE_SETTING_ENABLED: u8 = 0x01;
@ -111,7 +112,7 @@ struct NtbParametersDir {
fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] { fn byteify<T>(buf: &mut [u8], data: T) -> &[u8] {
let len = size_of::<T>(); let len = size_of::<T>();
unsafe { copy_nonoverlapping(&data as *const _ as *const u8, buf.as_mut_ptr(), len) } unsafe { copy_nonoverlapping(addr_of!(data).cast(), buf.as_mut_ptr(), len) }
&buf[..len] &buf[..len]
} }
@ -121,27 +122,28 @@ pub struct State<'a> {
shared: ControlShared, shared: ControlShared,
} }
impl<'a> Default for State<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> State<'a> { impl<'a> State<'a> {
/// Create a new `State`. /// Create a new `State`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
control: MaybeUninit::uninit(), control: MaybeUninit::uninit(),
shared: Default::default(), shared: ControlShared::default(),
} }
} }
} }
/// Shared data between Control and CdcAcmClass /// Shared data between Control and `CdcAcmClass`
#[derive(Default)]
struct ControlShared { struct ControlShared {
mac_addr: [u8; 6], mac_addr: [u8; 6],
} }
impl Default for ControlShared {
fn default() -> Self {
ControlShared { mac_addr: [0; 6] }
}
}
struct Control<'a> { struct Control<'a> {
mac_addr_string: StringIndex, mac_addr_string: StringIndex,
shared: &'a ControlShared, shared: &'a ControlShared,
@ -377,12 +379,12 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
/// ///
/// This waits until the packet is successfully stored in the CDC-NCM endpoint buffers. /// This waits until the packet is successfully stored in the CDC-NCM endpoint buffers.
pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> { pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
let seq = self.seq;
self.seq = self.seq.wrapping_add(1);
const OUT_HEADER_LEN: usize = 28; const OUT_HEADER_LEN: usize = 28;
const ABS_MAX_PACKET_SIZE: usize = 512; const ABS_MAX_PACKET_SIZE: usize = 512;
let seq = self.seq;
self.seq = self.seq.wrapping_add(1);
let header = NtbOutHeader { let header = NtbOutHeader {
nth_sig: SIG_NTH, nth_sig: SIG_NTH,
nth_len: 0x0c, nth_len: 0x0c,
@ -416,7 +418,7 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
self.write_ep.write(&buf[..self.max_packet_size]).await?; self.write_ep.write(&buf[..self.max_packet_size]).await?;
for chunk in d2.chunks(self.max_packet_size) { for chunk in d2.chunks(self.max_packet_size) {
self.write_ep.write(&chunk).await?; self.write_ep.write(chunk).await?;
} }
// Send ZLP if needed. // Send ZLP if needed.
@ -459,12 +461,9 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
let ntb = &ntb[..pos]; let ntb = &ntb[..pos];
// Process NTB header (NTH) // Process NTB header (NTH)
let nth = match ntb.get(..12) { let Some(nth) = ntb.get(..12) else {
Some(x) => x, warn!("Received too short NTB");
None => { continue;
warn!("Received too short NTB");
continue;
}
}; };
let sig = u32::from_le_bytes(nth[0..4].try_into().unwrap()); let sig = u32::from_le_bytes(nth[0..4].try_into().unwrap());
if sig != SIG_NTH { if sig != SIG_NTH {
@ -474,12 +473,9 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
let ndp_idx = u16::from_le_bytes(nth[10..12].try_into().unwrap()) as usize; let ndp_idx = u16::from_le_bytes(nth[10..12].try_into().unwrap()) as usize;
// Process NTB Datagram Pointer (NDP) // Process NTB Datagram Pointer (NDP)
let ndp = match ntb.get(ndp_idx..ndp_idx + 12) { let Some(ndp) = ntb.get(ndp_idx..ndp_idx + 12) else {
Some(x) => x, warn!("NTH has an NDP pointer out of range.");
None => { continue;
warn!("NTH has an NDP pointer out of range.");
continue;
}
}; };
let sig = u32::from_le_bytes(ndp[0..4].try_into().unwrap()); let sig = u32::from_le_bytes(ndp[0..4].try_into().unwrap());
if sig != SIG_NDP_NO_FCS && sig != SIG_NDP_WITH_FCS { if sig != SIG_NDP_NO_FCS && sig != SIG_NDP_WITH_FCS {
@ -495,12 +491,9 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
} }
// Process actual datagram, finally. // Process actual datagram, finally.
let datagram = match ntb.get(datagram_index..datagram_index + datagram_len) { let Some(datagram) = ntb.get(datagram_index..datagram_index + datagram_len) else {
Some(x) => x, warn!("NDP has a datagram pointer out of range.");
None => { continue;
warn!("NDP has a datagram pointer out of range.");
continue;
}
}; };
buf[..datagram_len].copy_from_slice(datagram); buf[..datagram_len].copy_from_slice(datagram);

View File

@ -63,7 +63,7 @@ pub enum ReportId {
} }
impl ReportId { impl ReportId {
fn try_from(value: u16) -> Result<Self, ()> { const fn try_from(value: u16) -> Result<Self, ()> {
match value >> 8 { match value >> 8 {
1 => Ok(ReportId::In(value as u8)), 1 => Ok(ReportId::In(value as u8)),
2 => Ok(ReportId::Out(value as u8)), 2 => Ok(ReportId::Out(value as u8)),
@ -79,9 +79,15 @@ pub struct State<'d> {
out_report_offset: AtomicUsize, out_report_offset: AtomicUsize,
} }
impl<'d> Default for State<'d> {
fn default() -> Self {
Self::new()
}
}
impl<'d> State<'d> { impl<'d> State<'d> {
/// Create a new `State`. /// Create a new `State`.
pub fn new() -> Self { pub const fn new() -> Self {
State { State {
control: MaybeUninit::uninit(), control: MaybeUninit::uninit(),
out_report_offset: AtomicUsize::new(0), out_report_offset: AtomicUsize::new(0),
@ -148,7 +154,7 @@ fn build<'d, D: Driver<'d>>(
} }
impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> HidReaderWriter<'d, D, READ_N, WRITE_N> { impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> HidReaderWriter<'d, D, READ_N, WRITE_N> {
/// Creates a new HidReaderWriter. /// Creates a new `HidReaderWriter`.
/// ///
/// This will allocate one IN and one OUT endpoints. If you only need writing (sending) /// 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. /// HID reports, consider using [`HidWriter::new`] instead, which allocates an IN endpoint only.
@ -171,7 +177,7 @@ impl<'d, D: Driver<'d>, const READ_N: usize, const WRITE_N: usize> HidReaderWrit
} }
/// Waits for both IN and OUT endpoints to be enabled. /// Waits for both IN and OUT endpoints to be enabled.
pub async fn ready(&mut self) -> () { pub async fn ready(&mut self) {
self.reader.ready().await; self.reader.ready().await;
self.writer.ready().await; self.writer.ready().await;
} }
@ -224,7 +230,7 @@ pub enum ReadError {
impl From<EndpointError> for ReadError { impl From<EndpointError> for ReadError {
fn from(val: EndpointError) -> Self { fn from(val: EndpointError) -> Self {
use EndpointError::*; use EndpointError::{BufferOverflow, Disabled};
match val { match val {
BufferOverflow => ReadError::BufferOverflow, BufferOverflow => ReadError::BufferOverflow,
Disabled => ReadError::Disabled, Disabled => ReadError::Disabled,
@ -251,17 +257,16 @@ impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> {
} }
/// Waits for the interrupt in endpoint to be enabled. /// Waits for the interrupt in endpoint to be enabled.
pub async fn ready(&mut self) -> () { pub async fn ready(&mut self) {
self.ep_in.wait_enabled().await self.ep_in.wait_enabled().await;
} }
/// Writes an input report by serializing the given report structure. /// Writes an input report by serializing the given report structure.
#[cfg(feature = "usbd-hid")] #[cfg(feature = "usbd-hid")]
pub async fn write_serialize<IR: AsInputReport>(&mut self, r: &IR) -> Result<(), EndpointError> { pub async fn write_serialize<IR: AsInputReport>(&mut self, r: &IR) -> Result<(), EndpointError> {
let mut buf: [u8; N] = [0; N]; let mut buf: [u8; N] = [0; N];
let size = match serialize(&mut buf, r) { let Ok(size) = serialize(&mut buf, r) else {
Ok(size) => size, return Err(EndpointError::BufferOverflow);
Err(_) => return Err(EndpointError::BufferOverflow),
}; };
self.write(&buf[0..size]).await self.write(&buf[0..size]).await
} }
@ -286,8 +291,8 @@ impl<'d, D: Driver<'d>, const N: usize> HidWriter<'d, D, N> {
impl<'d, D: Driver<'d>, const N: usize> HidReader<'d, D, N> { impl<'d, D: Driver<'d>, const N: usize> HidReader<'d, D, N> {
/// Waits for the interrupt out endpoint to be enabled. /// Waits for the interrupt out endpoint to be enabled.
pub async fn ready(&mut self) -> () { pub async fn ready(&mut self) {
self.ep_out.wait_enabled().await self.ep_out.wait_enabled().await;
} }
/// Delivers output reports from the Interrupt Out pipe to `handler`. /// Delivers output reports from the Interrupt Out pipe to `handler`.
@ -344,9 +349,8 @@ impl<'d, D: Driver<'d>, const N: usize> HidReader<'d, D, N> {
if size < max_packet_size || total == N { if size < max_packet_size || total == N {
self.offset.store(0, Ordering::Release); self.offset.store(0, Ordering::Release);
break; break;
} else {
self.offset.store(total, Ordering::Release);
} }
self.offset.store(total, Ordering::Release);
} }
Err(err) => { Err(err) => {
self.offset.store(0, Ordering::Release); self.offset.store(0, Ordering::Release);
@ -466,7 +470,7 @@ impl<'d> Handler for Control<'d> {
HID_REQ_SET_IDLE => { HID_REQ_SET_IDLE => {
if let Some(handler) = self.request_handler { if let Some(handler) = self.request_handler {
let id = req.value as u8; let id = req.value as u8;
let id = (id != 0).then(|| ReportId::In(id)); let id = (id != 0).then_some(ReportId::In(id));
let dur = u32::from(req.value >> 8); let dur = u32::from(req.value >> 8);
let dur = if dur == 0 { u32::MAX } else { 4 * dur }; let dur = if dur == 0 { u32::MAX } else { 4 * dur };
handler.set_idle_ms(id, dur); handler.set_idle_ms(id, dur);
@ -522,7 +526,7 @@ impl<'d> Handler for Control<'d> {
HID_REQ_GET_IDLE => { HID_REQ_GET_IDLE => {
if let Some(handler) = self.request_handler { if let Some(handler) = self.request_handler {
let id = req.value as u8; let id = req.value as u8;
let id = (id != 0).then(|| ReportId::In(id)); let id = (id != 0).then_some(ReportId::In(id));
if let Some(dur) = handler.get_idle_ms(id) { if let Some(dur) = handler.get_idle_ms(id) {
let dur = u8::try_from(dur / 4).unwrap_or(0); let dur = u8::try_from(dur / 4).unwrap_or(0);
buf[0] = dur; buf[0] = dur;

View File

@ -27,9 +27,9 @@ const MIDI_OUT_SIZE: u8 = 0x09;
/// writing USB packets with no intermediate buffers, but it will not act like a stream-like port. /// writing USB packets with no intermediate buffers, but it will not act like a stream-like port.
/// The following constraints must be followed if you use this class directly: /// The following constraints must be followed if you use this class directly:
/// ///
/// - `read_packet` must be called with a buffer large enough to hold max_packet_size bytes. /// - `read_packet` must be called with a buffer large enough to hold `max_packet_size` bytes.
/// - `write_packet` must not be called with a buffer larger than max_packet_size bytes. /// - `write_packet` must not be called with a buffer larger than `max_packet_size` bytes.
/// - If you write a packet that is exactly max_packet_size bytes long, it won't be processed by the /// - If you write a packet that is exactly `max_packet_size` bytes long, it won't be processed by the
/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP) /// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP)
/// can be sent if there is no other data to send. This is because USB bulk transactions must be /// can be sent if there is no other data to send. This is because USB bulk transactions must be
/// terminated with a short packet, even if the bulk endpoint is used for stream-like data. /// terminated with a short packet, even if the bulk endpoint is used for stream-like data.
@ -39,8 +39,8 @@ pub struct MidiClass<'d, D: Driver<'d>> {
} }
impl<'d, D: Driver<'d>> MidiClass<'d, D> { impl<'d, D: Driver<'d>> MidiClass<'d, D> {
/// Creates a new MidiClass with the provided UsbBus, number of input and output jacks and max_packet_size in bytes. /// Creates a new `MidiClass` with the provided UsbBus, number of input and output jacks and `max_packet_size` in bytes.
/// For full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. /// 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>, n_in_jacks: u8, n_out_jacks: u8, max_packet_size: u16) -> Self { pub fn new(builder: &mut Builder<'d, D>, n_in_jacks: u8, n_out_jacks: u8, max_packet_size: u16) -> Self {
let mut func = builder.function(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE); let mut func = builder.function(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE);
@ -160,7 +160,7 @@ impl<'d, D: Driver<'d>> MidiClass<'d, D> {
/// Waits for the USB host to enable this interface /// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) { pub async fn wait_connection(&mut self) {
self.read_ep.wait_enabled().await self.read_ep.wait_enabled().await;
} }
/// Split the class into a sender and receiver. /// Split the class into a sender and receiver.
@ -197,7 +197,7 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
/// Waits for the USB host to enable this interface /// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) { pub async fn wait_connection(&mut self) {
self.write_ep.wait_enabled().await self.write_ep.wait_enabled().await;
} }
} }
@ -222,6 +222,6 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> {
/// Waits for the USB host to enable this interface /// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) { pub async fn wait_connection(&mut self) {
self.read_ep.wait_enabled().await self.read_ep.wait_enabled().await;
} }
} }

View File

@ -120,7 +120,7 @@ impl Request {
} }
/// Gets the descriptor type and index from the value field of a GET_DESCRIPTOR request. /// Gets the descriptor type and index from the value field of a GET_DESCRIPTOR request.
pub fn descriptor_type_index(&self) -> (u8, u8) { pub const fn descriptor_type_index(&self) -> (u8, u8) {
((self.value >> 8) as u8, self.value as u8) ((self.value >> 8) as u8, self.value as u8)
} }
} }

View File

@ -2,7 +2,7 @@
use crate::builder::Config; use crate::builder::Config;
use crate::driver::EndpointInfo; use crate::driver::EndpointInfo;
use crate::types::*; use crate::types::{InterfaceNumber, StringIndex};
use crate::CONFIGURATION_VALUE; use crate::CONFIGURATION_VALUE;
/// Standard descriptor types /// Standard descriptor types
@ -59,7 +59,7 @@ impl<'a> DescriptorWriter<'a> {
} }
/// Gets the current position in the buffer, i.e. the number of bytes written so far. /// Gets the current position in the buffer, i.e. the number of bytes written so far.
pub fn position(&self) -> usize { pub const fn position(&self) -> usize {
self.position self.position
} }
@ -67,9 +67,10 @@ impl<'a> DescriptorWriter<'a> {
pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) { pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) {
let length = descriptor.len(); let length = descriptor.len();
if (self.position + 2 + length) > self.buf.len() || (length + 2) > 255 { assert!(
panic!("Descriptor buffer full"); (self.position + 2 + length) <= self.buf.len() && (length + 2) <= 255,
} "Descriptor buffer full"
);
self.buf[self.position] = (length + 2) as u8; self.buf[self.position] = (length + 2) as u8;
self.buf[self.position + 1] = descriptor_type; self.buf[self.position + 1] = descriptor_type;
@ -102,7 +103,7 @@ impl<'a> DescriptorWriter<'a> {
config.serial_number.map_or(0, |_| 3), // iSerialNumber config.serial_number.map_or(0, |_| 3), // iSerialNumber
1, // bNumConfigurations 1, // bNumConfigurations
], ],
) );
} }
pub(crate) fn configuration(&mut self, config: &Config) { pub(crate) fn configuration(&mut self, config: &Config) {
@ -120,7 +121,7 @@ impl<'a> DescriptorWriter<'a> {
| if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes
(config.max_power / 2) as u8, // bMaxPower (config.max_power / 2) as u8, // bMaxPower
], ],
) );
} }
#[allow(unused)] #[allow(unused)]
@ -248,9 +249,7 @@ impl<'a> DescriptorWriter<'a> {
pub(crate) fn string(&mut self, string: &str) { pub(crate) fn string(&mut self, string: &str) {
let mut pos = self.position; let mut pos = self.position;
if pos + 2 > self.buf.len() { assert!(pos + 2 <= self.buf.len(), "Descriptor buffer full");
panic!("Descriptor buffer full");
}
self.buf[pos] = 0; // length placeholder self.buf[pos] = 0; // length placeholder
self.buf[pos + 1] = descriptor_type::STRING; self.buf[pos + 1] = descriptor_type::STRING;
@ -258,9 +257,7 @@ impl<'a> DescriptorWriter<'a> {
pos += 2; pos += 2;
for c in string.encode_utf16() { for c in string.encode_utf16() {
if pos >= self.buf.len() { assert!(pos < self.buf.len(), "Descriptor buffer full");
panic!("Descriptor buffer full");
}
self.buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes()); self.buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes());
pos += 2; pos += 2;
@ -279,9 +276,9 @@ pub struct BosWriter<'a> {
} }
impl<'a> BosWriter<'a> { impl<'a> BosWriter<'a> {
pub(crate) fn new(writer: DescriptorWriter<'a>) -> Self { pub(crate) const fn new(writer: DescriptorWriter<'a>) -> Self {
Self { Self {
writer: writer, writer,
num_caps_mark: None, num_caps_mark: None,
} }
} }
@ -314,9 +311,10 @@ impl<'a> BosWriter<'a> {
let mut start = self.writer.position; let mut start = self.writer.position;
let blen = data.len(); let blen = data.len();
if (start + blen + 3) > self.writer.buf.len() || (blen + 3) > 255 { assert!(
panic!("Descriptor buffer full"); (start + blen + 3) <= self.writer.buf.len() && (blen + 3) <= 255,
} "Descriptor buffer full"
);
self.writer.buf[start] = (blen + 3) as u8; self.writer.buf[start] = (blen + 3) as u8;
self.writer.buf[start + 1] = descriptor_type::CAPABILITY; self.writer.buf[start + 1] = descriptor_type::CAPABILITY;

View File

@ -11,11 +11,11 @@ pub struct Reader<'a> {
} }
impl<'a> Reader<'a> { impl<'a> Reader<'a> {
pub fn new(data: &'a [u8]) -> Self { pub const fn new(data: &'a [u8]) -> Self {
Self { data } Self { data }
} }
pub fn eof(&self) -> bool { pub const fn eof(&self) -> bool {
self.data.is_empty() self.data.is_empty()
} }
@ -102,7 +102,7 @@ pub fn foreach_endpoint(data: &[u8], mut f: impl FnMut(EndpointInfo)) -> Result<
} }
descriptor_type::ENDPOINT => { descriptor_type::ENDPOINT => {
ep.ep_address = EndpointAddress::from(r.read_u8()?); ep.ep_address = EndpointAddress::from(r.read_u8()?);
f(ep) f(ep);
} }
_ => {} _ => {}
} }

View File

@ -24,12 +24,12 @@ use embassy_futures::select::{select, Either};
use heapless::Vec; use heapless::Vec;
pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder}; pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder};
use crate::config::*; use crate::config::{MAX_HANDLER_COUNT, MAX_INTERFACE_COUNT};
use crate::control::*; use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType};
use crate::descriptor::*; use crate::descriptor::{descriptor_type, lang_id};
use crate::descriptor_reader::foreach_endpoint; use crate::descriptor_reader::foreach_endpoint;
use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event}; use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event};
use crate::types::*; use crate::types::{InterfaceNumber, StringIndex};
/// The global state of the USB device. /// The global state of the USB device.
/// ///
@ -294,7 +294,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
/// After dropping the future, [`UsbDevice::disable()`] should be called /// After dropping the future, [`UsbDevice::disable()`] should be called
/// before calling any other `UsbDevice` methods to fully reset the /// before calling any other `UsbDevice` methods to fully reset the
/// peripheral. /// peripheral.
pub async fn run_until_suspend(&mut self) -> () { pub async fn run_until_suspend(&mut self) {
while !self.inner.suspended { while !self.inner.suspended {
let control_fut = self.control.setup(); let control_fut = self.control.setup();
let bus_fut = self.inner.bus.poll(); let bus_fut = self.inner.bus.poll();
@ -364,6 +364,8 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
} }
async fn handle_control_in(&mut self, req: Request) { async fn handle_control_in(&mut self, req: Request) {
const DEVICE_DESCRIPTOR_LEN: usize = 18;
let mut resp_length = req.length as usize; let mut resp_length = req.length as usize;
let max_packet_size = self.control.max_packet_size(); let max_packet_size = self.control.max_packet_size();
@ -371,19 +373,15 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
// The host doesn't know our EP0 max packet size yet, and might assume // The host doesn't know our EP0 max packet size yet, and might assume
// a full-length packet is a short packet, thinking we're done sending data. // a full-length packet is a short packet, thinking we're done sending data.
// See https://github.com/hathach/tinyusb/issues/184 // See https://github.com/hathach/tinyusb/issues/184
const DEVICE_DESCRIPTOR_LEN: usize = 18; if self.inner.address == 0 && max_packet_size < DEVICE_DESCRIPTOR_LEN && max_packet_size < resp_length {
if self.inner.address == 0
&& max_packet_size < DEVICE_DESCRIPTOR_LEN
&& (max_packet_size as usize) < resp_length
{
trace!("received control req while not addressed: capping response to 1 packet."); trace!("received control req while not addressed: capping response to 1 packet.");
resp_length = max_packet_size; resp_length = max_packet_size;
} }
match self.inner.handle_control_in(req, &mut self.control_buf) { match self.inner.handle_control_in(req, self.control_buf) {
InResponse::Accepted(data) => { InResponse::Accepted(data) => {
let len = data.len().min(resp_length); let len = data.len().min(resp_length);
let need_zlp = len != resp_length && (len % usize::from(max_packet_size)) == 0; let need_zlp = len != resp_length && (len % max_packet_size) == 0;
let chunks = data[0..len] let chunks = data[0..len]
.chunks(max_packet_size) .chunks(max_packet_size)
@ -435,7 +433,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
self.control.accept_set_address(self.inner.address).await; self.control.accept_set_address(self.inner.address).await;
self.inner.set_address_pending = false; self.inner.set_address_pending = false;
} else { } else {
self.control.accept().await self.control.accept().await;
} }
} }
OutResponse::Rejected => self.control.reject().await, OutResponse::Rejected => self.control.reject().await,
@ -548,9 +546,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
OutResponse::Accepted OutResponse::Accepted
} }
(Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => match self.device_state { (Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => {
UsbDeviceState::Default => OutResponse::Accepted, if self.device_state != UsbDeviceState::Default {
_ => {
debug!("SET_CONFIGURATION: unconfigured"); debug!("SET_CONFIGURATION: unconfigured");
self.device_state = UsbDeviceState::Addressed; self.device_state = UsbDeviceState::Addressed;
@ -564,17 +561,15 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
for h in &mut self.handlers { for h in &mut self.handlers {
h.configured(false); h.configured(false);
} }
OutResponse::Accepted
} }
}, OutResponse::Accepted
}
_ => OutResponse::Rejected, _ => OutResponse::Rejected,
}, },
(RequestType::Standard, Recipient::Interface) => { (RequestType::Standard, Recipient::Interface) => {
let iface_num = InterfaceNumber::new(req.index as _); let iface_num = InterfaceNumber::new(req.index as _);
let iface = match self.interfaces.get_mut(iface_num.0 as usize) { let Some(iface) = self.interfaces.get_mut(iface_num.0 as usize) else {
Some(iface) => iface, return OutResponse::Rejected;
None => return OutResponse::Rejected,
}; };
match req.request { match req.request {
@ -650,9 +645,8 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
_ => InResponse::Rejected, _ => InResponse::Rejected,
}, },
(RequestType::Standard, Recipient::Interface) => { (RequestType::Standard, Recipient::Interface) => {
let iface = match self.interfaces.get_mut(req.index as usize) { let Some(iface) = self.interfaces.get_mut(req.index as usize) else {
Some(iface) => iface, return InResponse::Rejected;
None => return InResponse::Rejected,
}; };
match req.request { match req.request {
@ -706,7 +700,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
} }
fn handle_control_in_delegated<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> { fn handle_control_in_delegated<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> InResponse<'a> {
unsafe fn extend_lifetime<'x, 'y>(r: InResponse<'x>) -> InResponse<'y> { unsafe fn extend_lifetime<'y>(r: InResponse<'_>) -> InResponse<'y> {
core::mem::transmute(r) core::mem::transmute(r)
} }
@ -756,16 +750,12 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
}; };
if let Some(s) = s { if let Some(s) = s {
if buf.len() < 2 { assert!(buf.len() >= 2, "control buffer too small");
panic!("control buffer too small");
}
buf[1] = descriptor_type::STRING; buf[1] = descriptor_type::STRING;
let mut pos = 2; let mut pos = 2;
for c in s.encode_utf16() { for c in s.encode_utf16() {
if pos + 2 >= buf.len() { assert!(pos + 2 < buf.len(), "control buffer too small");
panic!("control buffer too small");
}
buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes()); buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes());
pos += 2; pos += 2;

View File

@ -6,7 +6,7 @@
use core::mem::size_of; use core::mem::size_of;
use super::{capability_type, BosWriter}; use crate::descriptor::{capability_type, BosWriter};
use crate::types::InterfaceNumber; use crate::types::InterfaceNumber;
/// A serialized Microsoft OS 2.0 Descriptor set. /// A serialized Microsoft OS 2.0 Descriptor set.

View File

@ -7,7 +7,7 @@
pub struct InterfaceNumber(pub u8); pub struct InterfaceNumber(pub u8);
impl InterfaceNumber { impl InterfaceNumber {
pub(crate) fn new(index: u8) -> InterfaceNumber { pub(crate) const fn new(index: u8) -> InterfaceNumber {
InterfaceNumber(index) InterfaceNumber(index)
} }
} }
@ -25,7 +25,7 @@ impl From<InterfaceNumber> for u8 {
pub struct StringIndex(pub u8); pub struct StringIndex(pub u8);
impl StringIndex { impl StringIndex {
pub(crate) fn new(index: u8) -> StringIndex { pub(crate) const fn new(index: u8) -> StringIndex {
StringIndex(index) StringIndex(index)
} }
} }