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        max_packet_size: u16,
140        interval_ms: u8,
141    ) -> Result<Self::EndpointOut, EndpointAllocError>;
142
143    /// Allocates an IN endpoint.
144    ///
145    /// This method is called by the USB stack to allocate endpoints.
146    /// It can only be called before [`start`](Self::start) is called.
147    ///
148    /// # Arguments
149    ///
150    /// * `ep_type` - the endpoint's type.
151    /// * `max_packet_size` - Maximum packet size in bytes.
152    /// * `interval_ms` - Polling interval parameter for interrupt endpoints.
153    fn alloc_endpoint_in(
154        &mut self,
155        ep_type: EndpointType,
156        max_packet_size: u16,
157        interval_ms: u8,
158    ) -> Result<Self::EndpointIn, EndpointAllocError>;
159
160    /// Start operation of the USB device.
161    ///
162    /// This returns the `Bus` and `ControlPipe` instances that are used to operate
163    /// the USB device. Additionally, this makes all the previously allocated endpoints
164    /// start operating.
165    ///
166    /// This consumes the `Driver` instance, so it's no longer possible to allocate more
167    /// endpoints.
168    fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe);
169}
170
171/// USB bus trait.
172///
173/// This trait provides methods that act on the whole bus. It is kept owned by
174/// the main USB task, and used to manage the bus.
175pub trait Bus {
176    /// Enable the USB peripheral.
177    async fn enable(&mut self);
178
179    /// Disable and powers down the USB peripheral.
180    async fn disable(&mut self);
181
182    /// Wait for a bus-related event.
183    ///
184    /// This method should asynchronously wait for an event to happen, then
185    /// return it. See [`Event`] for the list of events this method should return.
186    async fn poll(&mut self) -> Event;
187
188    /// Enable or disable an endpoint.
189    fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool);
190
191    /// Set or clear the STALL condition for an endpoint.
192    ///
193    /// If the endpoint is an OUT endpoint, it should be prepared to receive data again.
194    fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool);
195
196    /// Get whether the STALL condition is set for an endpoint.
197    fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool;
198
199    /// Simulate a disconnect from the USB bus, causing the host to reset and re-enumerate the
200    /// device.
201    ///
202    /// The default implementation just returns `Unsupported`.
203    ///
204    /// # Errors
205    ///
206    /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support
207    ///   simulating a disconnect or it has not been enabled at creation time.
208    fn force_reset(&mut self) -> Result<(), Unsupported> {
209        Err(Unsupported)
210    }
211
212    /// Initiate a remote wakeup of the host by the device.
213    ///
214    /// # Errors
215    ///
216    /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support
217    ///   remote wakeup or it has not been enabled at creation time.
218    async fn remote_wakeup(&mut self) -> Result<(), Unsupported>;
219}
220
221/// Endpoint trait, common for OUT and IN.
222pub trait Endpoint {
223    /// Get the endpoint address
224    fn info(&self) -> &EndpointInfo;
225
226    /// Wait for the endpoint to be enabled.
227    async fn wait_enabled(&mut self);
228}
229
230/// OUT Endpoint trait.
231pub trait EndpointOut: Endpoint {
232    /// Read a single packet of data from the endpoint, and return the actual length of
233    /// the packet.
234    ///
235    /// This should also clear any NAK flags and prepare the endpoint to receive the next packet.
236    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError>;
237}
238
239/// USB control pipe trait.
240///
241/// The USB control pipe owns both OUT endpoint 0 and IN endpoint 0 in a single
242/// unit, and manages them together to implement the control pipe state machine.
243///
244/// The reason this is a separate trait instead of using EndpointOut/EndpointIn is that
245/// many USB peripherals treat the control pipe endpoints differently (different registers,
246/// different procedures), usually to accelerate processing in hardware somehow. A separate
247/// trait allows the driver to handle it specially.
248///
249/// The call sequences made by the USB stack to the ControlPipe are the following:
250///
251/// - control in/out with len=0:
252///
253/// ```not_rust
254/// setup()
255/// (...processing...)
256/// accept() or reject()
257/// ```
258///
259/// - control out for setting the device address:
260///
261/// ```not_rust
262/// setup()
263/// (...processing...)
264/// accept_set_address(addr) or reject()
265/// ```
266///
267/// - control out with len != 0:
268///
269/// ```not_rust
270/// setup()
271/// data_out(first=true, last=false)
272/// data_out(first=false, last=false)
273/// ...
274/// data_out(first=false, last=false)
275/// data_out(first=false, last=true)
276/// (...processing...)
277/// accept() or reject()
278/// ```
279///
280/// - control in with len != 0, accepted:
281///
282/// ```not_rust
283/// setup()
284/// (...processing...)
285/// data_in(first=true, last=false)
286/// data_in(first=false, last=false)
287/// ...
288/// data_in(first=false, last=false)
289/// data_in(first=false, last=true)
290/// (NO `accept()`!!! This is because calling `data_in` already implies acceptance.)
291/// ```
292///
293/// - control in with len != 0, rejected:
294///
295/// ```not_rust
296/// setup()
297/// (...processing...)
298/// reject()
299/// ```
300///
301/// The driver is responsible for handling the status stage. The stack DOES NOT do zero-length
302/// calls to `data_in` or `data_out` for the status zero-length packet. The status stage should
303/// be triggered by either `accept()`, or `data_in` with `last = true`.
304///
305/// Note that the host can abandon a control request and send a new SETUP packet any time. If
306/// a SETUP packet arrives at any time during `data_out`, `data_in`, `accept` or `reject`,
307/// the driver must immediately return (with `EndpointError::Disabled` from `data_in`, `data_out`)
308/// to let the stack call `setup()` again to start handling the new control request. Not doing
309/// so will cause things to get stuck, because the host will never read/send the packet we're
310/// waiting for.
311pub trait ControlPipe {
312    /// Maximum packet size for the control pipe
313    fn max_packet_size(&self) -> usize;
314
315    /// Read a single setup packet from the endpoint.
316    async fn setup(&mut self) -> [u8; 8];
317
318    /// Read a DATA OUT packet into `buf` in response to a control write request.
319    ///
320    /// Must be called after `setup()` for requests with `direction` of `Out`
321    /// and `length` greater than zero.
322    async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError>;
323
324    /// Send a DATA IN packet with `data` in response to a control read request.
325    ///
326    /// If `last_packet` is true, the STATUS packet will be ACKed following the transfer of `data`.
327    async fn data_in(&mut self, data: &[u8], first: bool, last: bool) -> Result<(), EndpointError>;
328
329    /// Accept a control request.
330    ///
331    /// Causes the STATUS packet for the current request to be ACKed.
332    async fn accept(&mut self);
333
334    /// Reject a control request.
335    ///
336    /// Sets a STALL condition on the pipe to indicate an error.
337    async fn reject(&mut self);
338
339    /// Accept SET_ADDRESS control and change bus address.
340    ///
341    /// For most drivers this function should firstly call `accept()` and then change the bus address.
342    /// However, there are peripherals (Synopsys USB OTG) that have reverse order.
343    async fn accept_set_address(&mut self, addr: u8);
344}
345
346/// IN Endpoint trait.
347pub trait EndpointIn: Endpoint {
348    /// Write a single packet of data to the endpoint.
349    async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError>;
350}
351
352#[derive(Copy, Clone, Eq, PartialEq, Debug)]
353#[cfg_attr(feature = "defmt", derive(defmt::Format))]
354/// Event returned by [`Bus::poll`].
355pub enum Event {
356    /// The USB reset condition has been detected.
357    Reset,
358
359    /// A USB suspend request has been detected or, in the case of self-powered devices, the device
360    /// has been disconnected from the USB bus.
361    Suspend,
362
363    /// A USB resume request has been detected after being suspended or, in the case of self-powered
364    /// devices, the device has been connected to the USB bus.
365    Resume,
366
367    /// The USB power has been detected.
368    PowerDetected,
369
370    /// The USB power has been removed. Not supported by all devices.
371    PowerRemoved,
372}
373
374/// Allocating an endpoint failed.
375///
376/// This can be due to running out of endpoints, or out of endpoint memory,
377/// or because the hardware doesn't support the requested combination of features.
378#[derive(Copy, Clone, Eq, PartialEq, Debug)]
379#[cfg_attr(feature = "defmt", derive(defmt::Format))]
380pub struct EndpointAllocError;
381
382/// Operation is unsupported by the driver.
383#[derive(Copy, Clone, Eq, PartialEq, Debug)]
384#[cfg_attr(feature = "defmt", derive(defmt::Format))]
385pub struct Unsupported;
386
387/// Errors returned by [`EndpointIn::write`] and [`EndpointOut::read`]
388#[derive(Copy, Clone, Eq, PartialEq, Debug)]
389#[cfg_attr(feature = "defmt", derive(defmt::Format))]
390pub enum EndpointError {
391    /// Either the packet to be written is too long to fit in the transmission
392    /// buffer or the received packet is too long to fit in `buf`.
393    BufferOverflow,
394
395    /// The endpoint is disabled.
396    Disabled,
397}