aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb/src/control.rs
diff options
context:
space:
mode:
authoralexmoon <[email protected]>2022-03-30 14:17:15 -0400
committerDario Nieuwenhuis <[email protected]>2022-04-06 05:38:11 +0200
commitf5ba022257ccd9ddd371f1dcd10c0775cc5a3110 (patch)
treece48804d72e8a936a026a3479c49fede8a8352f9 /embassy-usb/src/control.rs
parent77e0aca03b89ebc5f1e93b6c64b6c91ca10cedd1 (diff)
Refactor ControlPipe to use the typestate pattern for safety
Diffstat (limited to 'embassy-usb/src/control.rs')
-rw-r--r--embassy-usb/src/control.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index b5077c732..9f1115ff2 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -1,5 +1,7 @@
1use core::mem; 1use core::mem;
2 2
3use crate::descriptor::DescriptorWriter;
4use crate::driver::{self, ReadError};
3use crate::DEFAULT_ALTERNATE_SETTING; 5use crate::DEFAULT_ALTERNATE_SETTING;
4 6
5use super::types::*; 7use super::types::*;
@@ -191,3 +193,122 @@ pub trait ControlHandler {
191 InResponse::Accepted(&buf[0..2]) 193 InResponse::Accepted(&buf[0..2])
192 } 194 }
193} 195}
196
197/// Typestate representing a ControlPipe in the DATA IN stage
198#[derive(Debug)]
199#[cfg_attr(feature = "defmt", derive(defmt::Format))]
200pub(crate) struct DataInStage {
201 length: usize,
202}
203
204/// Typestate representing a ControlPipe in the DATA OUT stage
205#[derive(Debug)]
206#[cfg_attr(feature = "defmt", derive(defmt::Format))]
207pub(crate) struct DataOutStage {
208 length: usize,
209}
210
211/// Typestate representing a ControlPipe in the STATUS stage
212#[derive(Debug)]
213#[cfg_attr(feature = "defmt", derive(defmt::Format))]
214pub(crate) struct StatusStage {}
215
216#[derive(Debug)]
217#[cfg_attr(feature = "defmt", derive(defmt::Format))]
218pub(crate) enum Setup {
219 DataIn(Request, DataInStage),
220 DataOut(Request, DataOutStage),
221}
222
223pub(crate) struct ControlPipe<C: driver::ControlPipe> {
224 control: C,
225}
226
227impl<C: driver::ControlPipe> ControlPipe<C> {
228 pub(crate) fn new(control: C) -> Self {
229 ControlPipe { control }
230 }
231
232 pub(crate) async fn setup(&mut self) -> Setup {
233 let req = self.control.setup().await;
234 match (req.direction, req.length) {
235 (UsbDirection::Out, n) => Setup::DataOut(
236 req,
237 DataOutStage {
238 length: usize::from(n),
239 },
240 ),
241 (UsbDirection::In, n) => Setup::DataIn(
242 req,
243 DataInStage {
244 length: usize::from(n),
245 },
246 ),
247 }
248 }
249
250 pub(crate) async fn data_out<'a>(
251 &mut self,
252 buf: &'a mut [u8],
253 stage: DataOutStage,
254 ) -> Result<(&'a [u8], StatusStage), ReadError> {
255 if stage.length == 0 {
256 Ok((&[], StatusStage {}))
257 } else {
258 let req_length = stage.length;
259 let max_packet_size = self.control.max_packet_size();
260 let mut total = 0;
261
262 for chunk in buf.chunks_mut(max_packet_size) {
263 let size = self.control.data_out(chunk).await?;
264 total += size;
265 if size < max_packet_size || total == req_length {
266 break;
267 }
268 }
269
270 Ok((&buf[0..total], StatusStage {}))
271 }
272 }
273
274 pub(crate) async fn accept_in(&mut self, buf: &[u8], stage: DataInStage) {
275 #[cfg(feature = "defmt")]
276 debug!("control in accept {:x}", buf);
277 #[cfg(not(feature = "defmt"))]
278 debug!("control in accept {:x?}", buf);
279
280 let req_len = stage.length;
281 let len = buf.len().min(req_len);
282 let max_packet_size = self.control.max_packet_size();
283 let need_zlp = len != req_len && (len % usize::from(max_packet_size)) == 0;
284
285 let mut chunks = buf[0..len]
286 .chunks(max_packet_size)
287 .chain(need_zlp.then(|| -> &[u8] { &[] }));
288
289 while let Some(chunk) = chunks.next() {
290 self.control.data_in(chunk, chunks.size_hint().0 == 0).await;
291 }
292 }
293
294 pub(crate) async fn accept_in_writer(
295 &mut self,
296 req: Request,
297 stage: DataInStage,
298 f: impl FnOnce(&mut DescriptorWriter),
299 ) {
300 let mut buf = [0; 256];
301 let mut w = DescriptorWriter::new(&mut buf);
302 f(&mut w);
303 let pos = w.position().min(usize::from(req.length));
304 self.accept_in(&buf[..pos], stage).await
305 }
306
307 pub(crate) fn accept(&mut self, _: StatusStage) {
308 self.control.accept();
309 }
310
311 pub(crate) fn reject(&mut self) {
312 self.control.reject();
313 }
314}