Skip to content

Commit

Permalink
usb: Make driver generic over max interfaces
Browse files Browse the repository at this point in the history
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.

rust-lang/rust#95486
rust-lang/rust#99727
rust-lang/rust#27336
  • Loading branch information
yodaldevoid committed Dec 14, 2022
1 parent 5b65b0e commit 4011503
Show file tree
Hide file tree
Showing 19 changed files with 50 additions and 48 deletions.
2 changes: 1 addition & 1 deletion embassy-usb-logger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<const N: usize> UsbLogger<N> {
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,
Expand Down
34 changes: 17 additions & 17 deletions embassy-usb/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down Expand Up @@ -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<Interface<'d>, MAX_INTERFACE_COUNT>,
interfaces: Vec<Interface<'d>, I>,
control_buf: &'d mut [u8],

driver: D,
Expand All @@ -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
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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 _),
Expand All @@ -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<usize>,
}

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;
}
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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
Expand Down
6 changes: 5 additions & 1 deletion embassy-usb/src/class/cdc_acm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<const I: usize>(
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;
Expand Down
4 changes: 2 additions & 2 deletions embassy-usb/src/class/cdc_ncm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<const I: usize>(
builder: &mut Builder<'d, D, I>,
state: &'d mut State<'d>,
mac_address: [u8; 6],
max_packet_size: u16,
Expand Down
8 changes: 4 additions & 4 deletions embassy-usb/src/class/hid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<const I: usize>(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 {
Expand Down Expand Up @@ -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<const I: usize>(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());
Expand Down
2 changes: 1 addition & 1 deletion embassy-usb/src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 8 additions & 10 deletions embassy-usb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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>,

Expand All @@ -128,20 +126,20 @@ struct Inner<'d, D: Driver<'d>> {
/// If true, do a set_addr after finishing the current control req.
set_address_pending: bool,

interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>,
interfaces: Vec<Interface<'d>, 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>,
handler: Option<&'d dyn DeviceStateHandler>,
device_descriptor: &'d [u8],
config_descriptor: &'d [u8],
bos_descriptor: &'d [u8],
interfaces: Vec<Interface<'d>, MAX_INTERFACE_COUNT>,
interfaces: Vec<Interface<'d>, 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);
Expand Down Expand Up @@ -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 => {
Expand Down
2 changes: 1 addition & 1 deletion examples/nrf/src/bin/usb_ethernet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion examples/nrf/src/bin/usb_hid_keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion examples/nrf/src/bin/usb_hid_mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion examples/nrf/src/bin/usb_serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion examples/nrf/src/bin/usb_serial_multitask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion examples/rp/src/bin/usb_ethernet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion examples/rp/src/bin/usb_serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion examples/stm32f1/src/bin/usb_serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion examples/stm32f3/src/bin/usb_serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion examples/stm32l5/src/bin/usb_ethernet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
2 changes: 1 addition & 1 deletion examples/stm32l5/src/bin/usb_hid_mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion examples/stm32l5/src/bin/usb_serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 4011503

Please sign in to comment.