aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-03-28 03:27:21 +0200
committerDario Nieuwenhuis <[email protected]>2022-04-06 05:38:11 +0200
commit2b547f311efc7feaa3afbb9f1bf4100c5502839e (patch)
tree40b9ef749e486d6f902a9d9dd95a68ff672c151e
parent15cc97d794d8b4baa6c1a8f1ed6c64468701c9e7 (diff)
usb: move all control-related stuff to `mod control`.
-rw-r--r--embassy-usb/src/builder.rs2
-rw-r--r--embassy-usb/src/class.rs104
-rw-r--r--embassy-usb/src/control.rs103
-rw-r--r--embassy-usb/src/lib.rs4
-rw-r--r--examples/nrf/src/bin/usb/cdc_acm.rs7
5 files changed, 109 insertions, 111 deletions
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 98b55adf9..dfd36bdb3 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,6 +1,6 @@
1use heapless::Vec; 1use heapless::Vec;
2 2
3use super::class::ControlHandler; 3use super::control::ControlHandler;
4use super::descriptor::{BosWriter, DescriptorWriter}; 4use super::descriptor::{BosWriter, DescriptorWriter};
5use super::driver::{Driver, EndpointAllocError}; 5use super::driver::{Driver, EndpointAllocError};
6use super::types::*; 6use super::types::*;
diff --git a/embassy-usb/src/class.rs b/embassy-usb/src/class.rs
deleted file mode 100644
index 754e3a209..000000000
--- a/embassy-usb/src/class.rs
+++ /dev/null
@@ -1,104 +0,0 @@
1use crate::control::Request;
2
3#[derive(Copy, Clone, Eq, PartialEq, Debug)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
5pub enum RequestStatus {
6 Accepted,
7 Rejected,
8}
9
10/// A trait for implementing USB classes.
11///
12/// All methods are optional callbacks that will be called by
13/// [`UsbDevice::run()`](crate::UsbDevice::run)
14pub trait ControlHandler {
15 /// Called after a USB reset after the bus reset sequence is complete.
16 fn reset(&mut self) {}
17
18 /// Called when a control request is received with direction HostToDevice.
19 ///
20 /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
21 /// error. Classes can even choose to override standard requests, but doing that is rarely
22 /// necessary.
23 ///
24 /// When implementing your own class, you should ignore any requests that are not meant for your
25 /// class so that any other classes in the composite device can process them.
26 ///
27 /// # Arguments
28 ///
29 /// * `req` - The request from the SETUP packet.
30 /// * `data` - The data from the request.
31 fn control_out(&mut self, req: Request, data: &[u8]) -> RequestStatus {
32 RequestStatus::Rejected
33 }
34
35 /// Called when a control request is received with direction DeviceToHost.
36 ///
37 /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
38 /// error. Classes can even choose to override standard requests, but doing that is rarely
39 /// necessary.
40 ///
41 /// See [`ControlIn`] for how to respond to the transfer.
42 ///
43 /// When implementing your own class, you should ignore any requests that are not meant for your
44 /// class so that any other classes in the composite device can process them.
45 ///
46 /// # Arguments
47 ///
48 /// * `req` - The request from the SETUP packet.
49 /// * `control` - The control pipe.
50 fn control_in<'a>(
51 &mut self,
52 req: Request,
53 control: ControlIn<'a>,
54 ) -> ControlInRequestStatus<'a> {
55 control.reject()
56 }
57}
58
59/// Handle for a control IN transfer. When implementing a class, use the methods of this object to
60/// response to the transfer with either data or an error (STALL condition). To ignore the request
61/// and pass it on to the next class, call [`Self::ignore()`].
62pub struct ControlIn<'a> {
63 buf: &'a mut [u8],
64}
65
66#[derive(Eq, PartialEq, Debug)]
67#[cfg_attr(feature = "defmt", derive(defmt::Format))]
68pub struct ControlInRequestStatus<'a> {
69 pub(crate) status: RequestStatus,
70 pub(crate) data: &'a [u8],
71}
72
73impl<'a> ControlInRequestStatus<'a> {
74 pub fn status(&self) -> RequestStatus {
75 self.status
76 }
77}
78
79impl<'a> ControlIn<'a> {
80 pub(crate) fn new(buf: &'a mut [u8]) -> Self {
81 ControlIn { buf }
82 }
83
84 /// Accepts the transfer with the supplied buffer.
85 pub fn accept(self, data: &[u8]) -> ControlInRequestStatus<'a> {
86 assert!(data.len() < self.buf.len());
87
88 let buf = &mut self.buf[0..data.len()];
89 buf.copy_from_slice(data);
90
91 ControlInRequestStatus {
92 status: RequestStatus::Accepted,
93 data: buf,
94 }
95 }
96
97 /// Rejects the transfer by stalling the pipe.
98 pub fn reject(self) -> ControlInRequestStatus<'a> {
99 ControlInRequestStatus {
100 status: RequestStatus::Rejected,
101 data: &[],
102 }
103 }
104}
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index 77bc10aa4..ae4ad04a9 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -123,3 +123,106 @@ impl Request {
123 ((self.value >> 8) as u8, self.value as u8) 123 ((self.value >> 8) as u8, self.value as u8)
124 } 124 }
125} 125}
126
127#[derive(Copy, Clone, Eq, PartialEq, Debug)]
128#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub enum RequestStatus {
130 Accepted,
131 Rejected,
132}
133
134/// A trait for implementing USB classes.
135///
136/// All methods are optional callbacks that will be called by
137/// [`UsbDevice::run()`](crate::UsbDevice::run)
138pub trait ControlHandler {
139 /// Called after a USB reset after the bus reset sequence is complete.
140 fn reset(&mut self) {}
141
142 /// Called when a control request is received with direction HostToDevice.
143 ///
144 /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
145 /// error. Classes can even choose to override standard requests, but doing that is rarely
146 /// necessary.
147 ///
148 /// When implementing your own class, you should ignore any requests that are not meant for your
149 /// class so that any other classes in the composite device can process them.
150 ///
151 /// # Arguments
152 ///
153 /// * `req` - The request from the SETUP packet.
154 /// * `data` - The data from the request.
155 fn control_out(&mut self, req: Request, data: &[u8]) -> RequestStatus {
156 RequestStatus::Rejected
157 }
158
159 /// Called when a control request is received with direction DeviceToHost.
160 ///
161 /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
162 /// error. Classes can even choose to override standard requests, but doing that is rarely
163 /// necessary.
164 ///
165 /// See [`ControlIn`] for how to respond to the transfer.
166 ///
167 /// When implementing your own class, you should ignore any requests that are not meant for your
168 /// class so that any other classes in the composite device can process them.
169 ///
170 /// # Arguments
171 ///
172 /// * `req` - The request from the SETUP packet.
173 /// * `control` - The control pipe.
174 fn control_in<'a>(
175 &mut self,
176 req: Request,
177 control: ControlIn<'a>,
178 ) -> ControlInRequestStatus<'a> {
179 control.reject()
180 }
181}
182
183/// Handle for a control IN transfer. When implementing a class, use the methods of this object to
184/// response to the transfer with either data or an error (STALL condition). To ignore the request
185/// and pass it on to the next class, call [`Self::ignore()`].
186pub struct ControlIn<'a> {
187 buf: &'a mut [u8],
188}
189
190#[derive(Eq, PartialEq, Debug)]
191#[cfg_attr(feature = "defmt", derive(defmt::Format))]
192pub struct ControlInRequestStatus<'a> {
193 pub(crate) status: RequestStatus,
194 pub(crate) data: &'a [u8],
195}
196
197impl<'a> ControlInRequestStatus<'a> {
198 pub fn status(&self) -> RequestStatus {
199 self.status
200 }
201}
202
203impl<'a> ControlIn<'a> {
204 pub(crate) fn new(buf: &'a mut [u8]) -> Self {
205 ControlIn { buf }
206 }
207
208 /// Accepts the transfer with the supplied buffer.
209 pub fn accept(self, data: &[u8]) -> ControlInRequestStatus<'a> {
210 assert!(data.len() < self.buf.len());
211
212 let buf = &mut self.buf[0..data.len()];
213 buf.copy_from_slice(data);
214
215 ControlInRequestStatus {
216 status: RequestStatus::Accepted,
217 data: buf,
218 }
219 }
220
221 /// Rejects the transfer by stalling the pipe.
222 pub fn reject(self) -> ControlInRequestStatus<'a> {
223 ControlInRequestStatus {
224 status: RequestStatus::Rejected,
225 data: &[],
226 }
227 }
228}
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 9076123a5..b6c95ac62 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -6,7 +6,6 @@
6pub(crate) mod fmt; 6pub(crate) mod fmt;
7 7
8mod builder; 8mod builder;
9pub mod class;
10pub mod control; 9pub mod control;
11pub mod descriptor; 10pub mod descriptor;
12pub mod driver; 11pub mod driver;
@@ -15,7 +14,6 @@ mod util;
15 14
16use heapless::Vec; 15use heapless::Vec;
17 16
18use self::class::{ControlHandler, RequestStatus};
19use self::control::*; 17use self::control::*;
20use self::descriptor::*; 18use self::descriptor::*;
21use self::driver::*; 19use self::driver::*;
@@ -288,7 +286,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
288 .map(|(_, h)| h); 286 .map(|(_, h)| h);
289 match handler { 287 match handler {
290 Some(handler) => { 288 Some(handler) => {
291 let resp = handler.control_in(req, class::ControlIn::new(&mut buf)); 289 let resp = handler.control_in(req, ControlIn::new(&mut buf));
292 match resp.status { 290 match resp.status {
293 RequestStatus::Accepted => self.control.accept_in(resp.data).await, 291 RequestStatus::Accepted => self.control.accept_in(resp.data).await,
294 RequestStatus::Rejected => self.control.reject(), 292 RequestStatus::Rejected => self.control.reject(),
diff --git a/examples/nrf/src/bin/usb/cdc_acm.rs b/examples/nrf/src/bin/usb/cdc_acm.rs
index f4d429792..25c3108a9 100644
--- a/examples/nrf/src/bin/usb/cdc_acm.rs
+++ b/examples/nrf/src/bin/usb/cdc_acm.rs
@@ -3,8 +3,9 @@ use core::mem::{self, MaybeUninit};
3use core::sync::atomic::{AtomicBool, Ordering}; 3use core::sync::atomic::{AtomicBool, Ordering};
4use defmt::info; 4use defmt::info;
5use embassy::blocking_mutex::CriticalSectionMutex; 5use embassy::blocking_mutex::CriticalSectionMutex;
6use embassy_usb::class::{ControlHandler, ControlInRequestStatus, RequestStatus}; 6use embassy_usb::control::{
7use embassy_usb::control::{self, Request}; 7 self, ControlHandler, ControlIn, ControlInRequestStatus, Request, RequestStatus,
8};
8use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError}; 9use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError};
9use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder}; 10use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder};
10 11
@@ -124,7 +125,7 @@ impl ControlHandler for Control {
124 fn control_in<'a>( 125 fn control_in<'a>(
125 &mut self, 126 &mut self,
126 req: Request, 127 req: Request,
127 control: embassy_usb::class::ControlIn<'a>, 128 control: ControlIn<'a>,
128 ) -> ControlInRequestStatus<'a> { 129 ) -> ControlInRequestStatus<'a> {
129 match req.request { 130 match req.request {
130 // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below. 131 // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.