aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src/control.rs
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 /embassy-usb/src/control.rs
parent15cc97d794d8b4baa6c1a8f1ed6c64468701c9e7 (diff)
usb: move all control-related stuff to `mod control`.
Diffstat (limited to 'embassy-usb/src/control.rs')
-rw-r--r--embassy-usb/src/control.rs103
1 files changed, 103 insertions, 0 deletions
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}