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))] |
14 | pub 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))] |
26 | pub 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))] |
41 | pub struct EndpointAddress(u8); |
42 | |
43 | impl From<u8> for EndpointAddress { |
44 | #[inline ] |
45 | fn from(addr: u8) -> EndpointAddress { |
46 | EndpointAddress(addr) |
47 | } |
48 | } |
49 | |
50 | impl From<EndpointAddress> for u8 { |
51 | #[inline ] |
52 | fn from(addr: EndpointAddress) -> u8 { |
53 | addr.0 |
54 | } |
55 | } |
56 | |
57 | impl 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))] |
102 | pub 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. |
116 | pub 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. |
175 | pub 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. |
222 | pub 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. |
231 | pub 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. |
311 | pub 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. |
347 | pub 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`]. |
355 | pub 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))] |
380 | pub 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))] |
385 | pub 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))] |
390 | pub 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 | } |
398 | |