usb_device/
device_builder.rs

1use crate::bus::{UsbBus, UsbBusAllocator};
2use crate::descriptor::lang_id::LangID;
3use crate::device::{Config, UsbDevice, UsbRev};
4
5/// A USB vendor ID and product ID pair.
6pub struct UsbVidPid(pub u16, pub u16);
7
8/// Used to build new [`UsbDevice`]s.
9pub struct UsbDeviceBuilder<'a, B: UsbBus> {
10    alloc: &'a UsbBusAllocator<B>,
11    config: Config<'a>,
12}
13
14macro_rules! builder_fields {
15    ( $( $(#[$meta:meta])* $name:ident: $type:ty, )* ) => {
16        $(
17            $(#[$meta])*
18            pub fn $name(mut self, $name: $type) -> Self {
19                self.config.$name = $name;
20                self
21            }
22        )*
23    }
24}
25
26#[derive(Copy, Clone, Debug, PartialEq)]
27/// Error type for the USB device builder
28pub enum BuilderError {
29    /// String descriptors were provided in more languages than are supported
30    TooManyLanguages,
31    /// Control endpoint can only be 8, 16, 32, or 64 byte max packet size
32    InvalidPacketSize,
33    /// Configuration specifies higher USB power draw than allowed
34    PowerTooHigh,
35}
36
37/// Provides basic string descriptors about the device, including the manufacturer, product name,
38/// and serial number of the device in a specified language.
39#[derive(Copy, Clone, Debug, PartialEq)]
40pub struct StringDescriptors<'a> {
41    pub(crate) id: LangID,
42    pub(crate) serial: Option<&'a str>,
43    pub(crate) product: Option<&'a str>,
44    pub(crate) manufacturer: Option<&'a str>,
45}
46
47impl<'a> Default for StringDescriptors<'a> {
48    fn default() -> Self {
49        Self::new(LangID::EN_US)
50    }
51}
52
53impl<'a> StringDescriptors<'a> {
54    /// Create a new descriptor list with the provided language.
55    pub fn new(lang_id: LangID) -> Self {
56        Self {
57            id: lang_id,
58            serial: None,
59            product: None,
60            manufacturer: None,
61        }
62    }
63
64    /// Specify the serial number for this language.
65    pub fn serial_number(mut self, serial: &'a str) -> Self {
66        self.serial.replace(serial);
67        self
68    }
69
70    /// Specify the manufacturer name for this language.
71    pub fn manufacturer(mut self, manufacturer: &'a str) -> Self {
72        self.manufacturer.replace(manufacturer);
73        self
74    }
75
76    /// Specify the product name for this language.
77    pub fn product(mut self, product: &'a str) -> Self {
78        self.product.replace(product);
79        self
80    }
81}
82
83impl<'a, B: UsbBus> UsbDeviceBuilder<'a, B> {
84    /// Creates a builder for constructing a new [`UsbDevice`].
85    pub fn new(alloc: &'a UsbBusAllocator<B>, vid_pid: UsbVidPid) -> UsbDeviceBuilder<'a, B> {
86        UsbDeviceBuilder {
87            alloc,
88            config: Config {
89                device_class: 0x00,
90                device_sub_class: 0x00,
91                device_protocol: 0x00,
92                max_packet_size_0: 8,
93                vendor_id: vid_pid.0,
94                product_id: vid_pid.1,
95                usb_rev: UsbRev::Usb210,
96                device_release: 0x0010,
97                string_descriptors: heapless::Vec::new(),
98                self_powered: false,
99                supports_remote_wakeup: false,
100                composite_with_iads: false,
101                max_power: 50,
102            },
103        }
104    }
105
106    /// Creates the [`UsbDevice`] instance with the configuration in this builder.
107    pub fn build(self) -> UsbDevice<'a, B> {
108        UsbDevice::build(self.alloc, self.config)
109    }
110
111    builder_fields! {
112        /// Sets the device class code assigned by USB.org. Set to `0xff` for vendor-specific
113        /// devices that do not conform to any class.
114        ///
115        /// Default: `0x00` (class code specified by interfaces)
116        device_class: u8,
117
118        /// Sets the device sub-class code. Depends on class.
119        ///
120        /// Default: `0x00`
121        device_sub_class: u8,
122
123        /// Sets the device protocol code. Depends on class and sub-class.
124        ///
125        /// Default: `0x00`
126        device_protocol: u8,
127
128        /// Sets the device release version in BCD.
129        ///
130        /// Default: `0x0010` ("0.1")
131        device_release: u16,
132
133        /// Sets whether the device may have an external power source.
134        ///
135        /// This should be set to `true` even if the device is sometimes self-powered and may not
136        /// always draw power from the USB bus.
137        ///
138        /// Default: `false`
139        ///
140        /// See also: `max_power`
141        self_powered: bool,
142
143        /// Sets whether the device supports remotely waking up the host is requested.
144        ///
145        /// Default: `false`
146        supports_remote_wakeup: bool,
147
148        /// Sets which Usb 2 revision to comply to.
149        ///
150        /// Default: `UsbRev::Usb210`
151        usb_rev: UsbRev,
152    }
153
154    /// Configures the device as a composite device with interface association descriptors.
155    pub fn composite_with_iads(mut self) -> Self {
156        // Magic values specified in USB-IF ECN on IADs.
157        self.config.device_class = 0xEF;
158        self.config.device_sub_class = 0x02;
159        self.config.device_protocol = 0x01;
160
161        self.config.composite_with_iads = true;
162        self
163    }
164
165    /// Specify the strings for the device.
166    ///
167    /// # Note
168    /// Up to 16 languages may be provided.
169    pub fn strings(mut self, descriptors: &[StringDescriptors<'a>]) -> Result<Self, BuilderError> {
170        // The 16 language limit comes from the size of the buffer used to provide the list of
171        // language descriptors to the host.
172        self.config.string_descriptors =
173            heapless::Vec::from_slice(descriptors).map_err(|_| BuilderError::TooManyLanguages)?;
174
175        Ok(self)
176    }
177
178    /// Sets the maximum packet size in bytes for the control endpoint 0.
179    ///
180    /// Valid values are 8, 16, 32 and 64. There's generally no need to change this from the default
181    /// value of 8 bytes unless a class uses control transfers for sending large amounts of data, in
182    /// which case using a larger packet size may be more efficient.
183    ///
184    /// Default: 8 bytes
185    pub fn max_packet_size_0(mut self, max_packet_size_0: u8) -> Result<Self, BuilderError> {
186        match max_packet_size_0 {
187            8 | 16 | 32 | 64 => {}
188            _ => return Err(BuilderError::InvalidPacketSize),
189        }
190
191        self.config.max_packet_size_0 = max_packet_size_0;
192        Ok(self)
193    }
194
195    /// Sets the maximum current drawn from the USB bus by the device in milliamps.
196    ///
197    /// The default is 100 mA. If your device always uses an external power source and never draws
198    /// power from the USB bus, this can be set to 0.
199    ///
200    /// See also: `self_powered`
201    ///
202    /// Default: 100mA
203    pub fn max_power(mut self, max_power_ma: usize) -> Result<Self, BuilderError> {
204        if max_power_ma > 500 {
205            return Err(BuilderError::PowerTooHigh);
206        }
207
208        self.config.max_power = (max_power_ma / 2) as u8;
209        Ok(self)
210    }
211}