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}