embassy_usb_driver/
lib.rs

1#![no_std]
2#![allow(async_fn_in_trait)]
3#![doc = include_str!("../README.md")]
4#![warn(missing_docs)]
5
6/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
7/// the perspective of the host, which is backward for devices, but the standard directions are used
8/// for consistency.
9///
10/// The values of the enum also match the direction bit used in endpoint addresses and control
11/// request types.
12#[derive(Copy, Clone, Eq, PartialEq, Debug)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14pub enum Direction {
15    /// Host to device (OUT)
16    Out,
17    /// Device to host (IN)
18    In,
19}
20
21/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
22/// transfer bmAttributes transfer type bits.
23#[repr(u8)]
24#[derive(Copy, Clone, Eq, PartialEq, Debug)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum EndpointType {
27    /// Control endpoint. Used for device management. Only the host can initiate requests. Usually
28    /// used only endpoint 0.
29    Control = 0b00,
30    /// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
31    Isochronous = 0b01,
32    /// Bulk endpoint. Used for large amounts of best-effort reliable data.
33    Bulk = 0b10,
34    /// Interrupt endpoint. Used for small amounts of time-critical reliable data.
35    Interrupt = 0b11,
36}
37
38/// Type-safe endpoint address.
39#[derive(Debug, Clone, Copy, Eq, PartialEq)]
40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
41pub struct EndpointAddress(u8);
42
43impl From<u8> for EndpointAddress {
44    #[inline]
45    fn from(addr: u8) -> EndpointAddress {
46        EndpointAddress(addr)
47    }
48}
49
50impl From<EndpointAddress> for u8 {
51    #[inline]
52    fn from(addr: EndpointAddress) -> u8 {
53        addr.0
54    }
55}
56
57impl EndpointAddress {
58    const INBITS: u8 = 0x80;
59
60    /// Constructs a new EndpointAddress with the given index and direction.
61    #[inline]
62    pub fn from_parts(index: usize, dir: Direction) -> Self {
63        let dir_u8 = match dir {
64            Direction::Out => 0x00,
65            Direction::In => Self::INBITS,
66        };
67        EndpointAddress(index as u8 | dir_u8)
68    }
69
70    /// Gets the direction part of the address.
71    #[inline]
72    pub fn direction(&self) -> Direction {
73        if (self.0 & Self::INBITS) != 0 {
74            Direction::In
75        } else {
76            Direction::Out
77        }
78    }
79
80    /// Returns true if the direction is IN, otherwise false.
81    #[inline]
82    pub fn is_in(&self) -> bool {
83        (self.0 & Self::INBITS) != 0
84    }
85
86    /// Returns true if the direction is OUT, otherwise false.
87    #[inline]
88    pub fn is_out(&self) -> bool {
89        (self.0 & Self::INBITS) == 0
90    }
91
92    /// Gets the index part of the endpoint address.
93    #[inline]
94    pub fn index(&self) -> usize {
95        (self.0 & !Self::INBITS) as usize
96    }
97}
98
99/// Information for an endpoint.
100#[derive(Copy, Clone, Eq, PartialEq, Debug)]
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102pub struct EndpointInfo {
103    /// Endpoint's address.
104    pub addr: EndpointAddress,
105    /// Endpoint's type.
106    pub ep_type: EndpointType,
107    /// Max packet size, in bytes.
108    pub max_packet_size: u16,
109    /// Polling interval, in milliseconds.
110    pub interval_ms: u8,
111}
112
113/// Main USB driver trait.
114///
115/// Implement this to add support for a new hardware platform.
116pub trait Driver<'a> {
117    /// Type of the OUT endpoints for this driver.
118    type EndpointOut: EndpointOut + 'a;
119    /// Type of the IN endpoints for this driver.
120    type EndpointIn: EndpointIn + 'a;
121    /// Type of the control pipe for this driver.
122    type ControlPipe: ControlPipe + 'a;
123    /// Type for bus control for this driver.
124    type Bus: Bus + 'a;
125
126    /// Allocates an OUT endpoint.
127    ///
128    /// This method is called by the USB stack to allocate endpoints.
129    /// It can only be called before [`start`](Self::start) is called.
130    ///
131    /// # Arguments
132    ///
133    /// * `ep_type` - the endpoint's type.
134    /// * `max_packet_size` - Maximum packet size in bytes.
135    /// * `interval_ms` - Polling interval parameter for interrupt endpoints.
136    fn alloc_endpoint_out(
137        &mut self,
138        ep_type: EndpointType,
139        ep_addr: Option<EndpointAddress>,
140        max_packet_size: u16,
141        interval_ms: u8,
142    ) -> Result<Self::EndpointOut, EndpointAllocError>;
143
144    /// Allocates an IN endpoint.
145    ///
146    /// This method is called by the USB stack to allocate endpoints.
147    /// It can only be called before [`start`](Self::start) is called.
148    ///
149    /// # Arguments
150    ///
151    /// * `ep_type` - the endpoint's type.
152    /// * `max_packet_size` - Maximum packet size in bytes.
153    /// * `interval_ms` - Polling interval parameter for interrupt endpoints.
154    fn alloc_endpoint_in(
155        &mut self,
156        ep_type: EndpointType,
157        ep_addr: Option<EndpointAddress>,
158        max_packet_size: u16,
159        interval_ms: u8,
160    ) -> Result<Self::EndpointIn, EndpointAllocError>;
161
162    /// Start operation of the USB device.
163    ///
164    /// This returns the `Bus` and `ControlPipe` instances that are used to operate
165    /// the USB device. Additionally, this makes all the previously allocated endpoints
166    /// start operating.
167    ///
168    /// This consumes the `Driver` instance, so it's no longer possible to allocate more
169    /// endpoints.
170    fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe);
171}
172
173/// USB bus trait.
174///
175/// This trait provides methods that act on the whole bus. It is kept owned by
176/// the main USB task, and used to manage the bus.
177pub trait Bus {
178    /// Enable the USB peripheral.
179    async fn enable(&mut self);
180
181    /// Disable and powers down the USB peripheral.
182    async fn disable(&mut self);
183
184    /// Wait for a bus-related event.
185    ///
186    /// This method should asynchronously wait for an event to happen, then
187    /// return it. See [`Event`] for the list of events this method should return.
188    async fn poll(&mut self) -> Event;
189
190    /// Enable or disable an endpoint.
191    fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool);
192
193    /// Set or clear the STALL condition for an endpoint.
194    ///
195    /// If the endpoint is an OUT endpoint, it should be prepared to receive data again.
196    fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool);
197
198    /// Get whether the STALL condition is set for an endpoint.
199    fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool;
200
201    /// Simulate a disconnect from the USB bus, causing the host to reset and re-enumerate the
202    /// device.
203    ///
204    /// The default implementation just returns `Unsupported`.
205    ///
206    /// # Errors
207    ///
208    /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support
209    ///   simulating a disconnect or it has not been enabled at creation time.
210    fn force_reset(&mut self) -> Result<(), Unsupported> {
211        Err(Unsupported)
212    }
213
214    /// Initiate a remote wakeup of the host by the device.
215    ///
216    /// # Errors
217    ///
218    /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support
219    ///   remote wakeup or it has not been enabled at creation time.
220    async fn remote_wakeup(&mut self) -> Result<(), Unsupported>;
221}
222
223/// Endpoint trait, common for OUT and IN.
224pub trait Endpoint {
225    /// Get the endpoint address
226    fn info(&self) -> &EndpointInfo;
227
228    /// Wait for the endpoint to be enabled.
229    async fn wait_enabled(&mut self);
230}
231
232/// OUT Endpoint trait.
233pub trait EndpointOut: Endpoint {
234    /// Read a single packet of data from the endpoint, and return the actual length of
235    /// the packet.
236    ///
237    /// This should also clear any NAK flags and prepare the endpoint to receive the next packet.
238    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError>;
239}
240
241/// USB control pipe trait.
242///
243/// The USB control pipe owns both OUT endpoint 0 and IN endpoint 0 in a single
244/// unit, and manages them together to implement the control pipe state machine.
245///
246/// The reason this is a separate trait instead of using EndpointOut/EndpointIn is that
247/// many USB peripherals treat the control pipe endpoints differently (different registers,
248/// different procedures), usually to accelerate processing in hardware somehow. A separate
249/// trait allows the driver to handle it specially.
250///
251/// The call sequences made by the USB stack to the ControlPipe are the following:
252///
253/// - control in/out with len=0:
254///
255/// ```not_rust
256/// setup()
257/// (...processing...)
258/// accept() or reject()
259/// ```
260///
261/// - control out for setting the device address:
262///
263/// ```not_rust
264/// setup()
265/// (...processing...)
266/// accept_set_address(addr) or reject()
267/// ```
268///
269/// - control out with len != 0:
270///
271/// ```not_rust
272/// setup()
273/// data_out(first=true, last=false)
274/// data_out(first=false, last=false)
275/// ...
276/// data_out(first=false, last=false)
277/// data_out(first=false, last=true)
278/// (...processing...)
279/// accept() or reject()
280/// ```
281///
282/// - control in with len != 0, accepted:
283///
284/// ```not_rust
285/// setup()
286/// (...processing...)
287/// data_in(first=true, last=false)
288/// data_in(first=false, last=false)
289/// ...
290/// data_in(first=false, last=false)
291/// data_in(first=false, last=true)
292/// (NO `accept()`!!! This is because calling `data_in` already implies acceptance.)
293/// ```
294///
295/// - control in with len != 0, rejected:
296///
297/// ```not_rust
298/// setup()
299/// (...processing...)
300/// reject()
301/// ```
302///
303/// The driver is responsible for handling the status stage. The stack DOES NOT do zero-length
304/// calls to `data_in` or `data_out` for the status zero-length packet. The status stage should
305/// be triggered by either `accept()`, or `data_in` with `last = true`.
306///
307/// Note that the host can abandon a control request and send a new SETUP packet any time. If
308/// a SETUP packet arrives at any time during `data_out`, `data_in`, `accept` or `reject`,
309/// the driver must immediately return (with `EndpointError::Disabled` from `data_in`, `data_out`)
310/// to let the stack call `setup()` again to start handling the new control request. Not doing
311/// so will cause things to get stuck, because the host will never read/send the packet we're
312/// waiting for.
313pub trait ControlPipe {
314    /// Maximum packet size for the control pipe
315    fn max_packet_size(&self) -> usize;
316
317    /// Read a single setup packet from the endpoint.
318    async fn setup(&mut self) -> [u8; 8];
319
320    /// Read a DATA OUT packet into `buf` in response to a control write request.
321    ///
322    /// Must be called after `setup()` for requests with `direction` of `Out`
323    /// and `length` greater than zero.
324    async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError>;
325
326    /// Send a DATA IN packet with `data` in response to a control read request.
327    ///
328    /// If `last_packet` is true, the STATUS packet will be ACKed following the transfer of `data`.
329    async fn data_in(&mut self, data: &[u8], first: bool, last: bool) -> Result<(), EndpointError>;
330
331    /// Accept a control request.
332    ///
333    /// Causes the STATUS packet for the current request to be ACKed.
334    async fn accept(&mut self);
335
336    /// Reject a control request.
337    ///
338    /// Sets a STALL condition on the pipe to indicate an error.
339    async fn reject(&mut self);
340
341    /// Accept SET_ADDRESS control and change bus address.
342    ///
343    /// For most drivers this function should firstly call `accept()` and then change the bus address.
344    /// However, there are peripherals (Synopsys USB OTG) that have reverse order.
345    async fn accept_set_address(&mut self, addr: u8);
346}
347
348/// IN Endpoint trait.
349pub trait EndpointIn: Endpoint {
350    /// Write a single packet of data to the endpoint.
351    async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError>;
352}
353
354#[derive(Copy, Clone, Eq, PartialEq, Debug)]
355#[cfg_attr(feature = "defmt", derive(defmt::Format))]
356/// Event returned by [`Bus::poll`].
357pub enum Event {
358    /// The USB reset condition has been detected.
359    Reset,
360
361    /// A USB suspend request has been detected or, in the case of self-powered devices, the device
362    /// has been disconnected from the USB bus.
363    Suspend,
364
365    /// A USB resume request has been detected after being suspended or, in the case of self-powered
366    /// devices, the device has been connected to the USB bus.
367    Resume,
368
369    /// The USB power has been detected.
370    PowerDetected,
371
372    /// The USB power has been removed. Not supported by all devices.
373    PowerRemoved,
374}
375
376/// Allocating an endpoint failed.
377///
378/// This can be due to running out of endpoints, or out of endpoint memory,
379/// or because the hardware doesn't support the requested combination of features.
380#[derive(Copy, Clone, Eq, PartialEq, Debug)]
381#[cfg_attr(feature = "defmt", derive(defmt::Format))]
382pub struct EndpointAllocError;
383
384/// Operation is unsupported by the driver.
385#[derive(Copy, Clone, Eq, PartialEq, Debug)]
386#[cfg_attr(feature = "defmt", derive(defmt::Format))]
387pub struct Unsupported;
388
389/// Errors returned by [`EndpointIn::write`] and [`EndpointOut::read`]
390#[derive(Copy, Clone, Eq, PartialEq, Debug)]
391#[cfg_attr(feature = "defmt", derive(defmt::Format))]
392pub enum EndpointError {
393    /// Either the packet to be written is too long to fit in the transmission
394    /// buffer or the received packet is too long to fit in `buf`.
395    BufferOverflow,
396
397    /// The endpoint is disabled.
398    Disabled,
399}
400
401impl embedded_io_async::Error for EndpointError {
402    fn kind(&self) -> embedded_io_async::ErrorKind {
403        match self {
404            Self::BufferOverflow => embedded_io_async::ErrorKind::OutOfMemory,
405            Self::Disabled => embedded_io_async::ErrorKind::NotConnected,
406        }
407    }
408}