aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/usb.rs424
-rw-r--r--embassy-usb/src/builder.rs14
-rw-r--r--embassy-usb/src/class.rs190
-rw-r--r--embassy-usb/src/control.rs17
-rw-r--r--embassy-usb/src/driver.rs42
-rw-r--r--embassy-usb/src/lib.rs169
-rw-r--r--examples/nrf/src/bin/usb/cdc_acm.rs127
-rw-r--r--examples/nrf/src/bin/usb/main.rs3
8 files changed, 699 insertions, 287 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 5df5053ac..203f08fc0 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -9,6 +9,7 @@ use embassy::time::{with_timeout, Duration};
9use embassy::util::Unborrow; 9use embassy::util::Unborrow;
10use embassy::waitqueue::AtomicWaker; 10use embassy::waitqueue::AtomicWaker;
11use embassy_hal_common::unborrow; 11use embassy_hal_common::unborrow;
12use embassy_usb::control::Request;
12use embassy_usb::driver::{self, Event, ReadError, WriteError}; 13use embassy_usb::driver::{self, Event, ReadError, WriteError};
13use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; 14use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
14use futures::future::poll_fn; 15use futures::future::poll_fn;
@@ -134,6 +135,7 @@ impl<'d, T: Instance> Driver<'d, T> {
134impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { 135impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
135 type EndpointOut = Endpoint<'d, T, Out>; 136 type EndpointOut = Endpoint<'d, T, Out>;
136 type EndpointIn = Endpoint<'d, T, In>; 137 type EndpointIn = Endpoint<'d, T, In>;
138 type ControlPipe = ControlPipe<'d, T>;
137 type Bus = Bus<'d, T>; 139 type Bus = Bus<'d, T>;
138 140
139 fn alloc_endpoint_in( 141 fn alloc_endpoint_in(
@@ -174,6 +176,19 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
174 })) 176 }))
175 } 177 }
176 178
179 fn alloc_control_pipe(
180 &mut self,
181 max_packet_size: u16,
182 ) -> Result<Self::ControlPipe, driver::EndpointAllocError> {
183 self.alloc_endpoint_out(Some(0x00.into()), EndpointType::Control, max_packet_size, 0)?;
184 self.alloc_endpoint_in(Some(0x80.into()), EndpointType::Control, max_packet_size, 0)?;
185 Ok(ControlPipe {
186 _phantom: PhantomData,
187 max_packet_size,
188 request: None,
189 })
190 }
191
177 fn enable(self) -> Self::Bus { 192 fn enable(self) -> Self::Bus {
178 let regs = T::regs(); 193 let regs = T::regs();
179 194
@@ -344,99 +359,110 @@ impl<'d, T: Instance, Dir> driver::Endpoint for Endpoint<'d, T, Dir> {
344 } 359 }
345} 360}
346 361
362unsafe fn read_dma<T: Instance>(i: usize, buf: &mut [u8]) -> Result<usize, ReadError> {
363 let regs = T::regs();
364
365 // Check that the packet fits into the buffer
366 let size = regs.size.epout[0].read().bits() as usize;
367 if size > buf.len() {
368 return Err(ReadError::BufferOverflow);
369 }
370
371 if i == 0 {
372 regs.events_ep0datadone.reset();
373 }
374
375 let epout = [
376 &regs.epout0,
377 &regs.epout1,
378 &regs.epout2,
379 &regs.epout3,
380 &regs.epout4,
381 &regs.epout5,
382 &regs.epout6,
383 &regs.epout7,
384 ];
385 epout[i].ptr.write(|w| w.bits(buf.as_ptr() as u32));
386 // MAXCNT must match SIZE
387 epout[i].maxcnt.write(|w| w.bits(size as u32));
388
389 dma_start();
390 regs.events_endepout[i].reset();
391 regs.tasks_startepout[i].write(|w| w.tasks_startepout().set_bit());
392 while regs.events_endepout[i]
393 .read()
394 .events_endepout()
395 .bit_is_clear()
396 {}
397 regs.events_endepout[i].reset();
398 dma_end();
399
400 regs.size.epout[i].reset();
401
402 Ok(size)
403}
404
405unsafe fn write_dma<T: Instance>(i: usize, buf: &[u8]) -> Result<(), WriteError> {
406 let regs = T::regs();
407 if buf.len() > 64 {
408 return Err(WriteError::BufferOverflow);
409 }
410
411 // EasyDMA can't read FLASH, so we copy through RAM
412 let mut ram_buf: MaybeUninit<[u8; 64]> = MaybeUninit::uninit();
413 let ptr = ram_buf.as_mut_ptr() as *mut u8;
414 core::ptr::copy_nonoverlapping(buf.as_ptr(), ptr, buf.len());
415
416 let epin = [
417 &regs.epin0,
418 &regs.epin1,
419 &regs.epin2,
420 &regs.epin3,
421 &regs.epin4,
422 &regs.epin5,
423 &regs.epin6,
424 &regs.epin7,
425 ];
426
427 // Set the buffer length so the right number of bytes are transmitted.
428 // Safety: `buf.len()` has been checked to be <= the max buffer length.
429 epin[i].ptr.write(|w| w.bits(ptr as u32));
430 epin[i].maxcnt.write(|w| w.maxcnt().bits(buf.len() as u8));
431
432 regs.events_endepin[i].reset();
433
434 dma_start();
435 regs.tasks_startepin[i].write(|w| w.bits(1));
436 while regs.events_endepin[i].read().bits() == 0 {}
437 dma_end();
438
439 Ok(())
440}
441
347impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { 442impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
348 type ReadFuture<'a> = impl Future<Output = Result<usize, ReadError>> + 'a where Self: 'a; 443 type ReadFuture<'a> = impl Future<Output = Result<usize, ReadError>> + 'a where Self: 'a;
349 444
350 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { 445 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
351 async move { 446 async move {
352 let regs = T::regs();
353 let i = self.info.addr.index(); 447 let i = self.info.addr.index();
448 assert!(i != 0);
354 449
355 if i == 0 { 450 // Wait until ready
356 if buf.len() == 0 { 451 poll_fn(|cx| {
357 regs.tasks_ep0status.write(|w| unsafe { w.bits(1) }); 452 EP_OUT_WAKERS[i].register(cx.waker());
358 return Ok(0); 453 let r = READY_ENDPOINTS.load(Ordering::Acquire);
359 } 454 if r & (1 << (i + 16)) != 0 {
360 455 Poll::Ready(())
361 // Wait for SETUP packet 456 } else {
362 regs.events_ep0setup.reset(); 457 Poll::Pending
363 regs.intenset.write(|w| w.ep0setup().set());
364 poll_fn(|cx| {
365 EP_OUT_WAKERS[0].register(cx.waker());
366 let regs = T::regs();
367 if regs.events_ep0setup.read().bits() != 0 {
368 Poll::Ready(())
369 } else {
370 Poll::Pending
371 }
372 })
373 .await;
374
375 if buf.len() < 8 {
376 return Err(ReadError::BufferOverflow);
377 }
378
379 buf[0] = regs.bmrequesttype.read().bits() as u8;
380 buf[1] = regs.brequest.read().brequest().bits();
381 buf[2] = regs.wvaluel.read().wvaluel().bits();
382 buf[3] = regs.wvalueh.read().wvalueh().bits();
383 buf[4] = regs.windexl.read().windexl().bits();
384 buf[5] = regs.windexh.read().windexh().bits();
385 buf[6] = regs.wlengthl.read().wlengthl().bits();
386 buf[7] = regs.wlengthh.read().wlengthh().bits();
387
388 Ok(8)
389 } else {
390 // Wait until ready
391 poll_fn(|cx| {
392 EP_OUT_WAKERS[i].register(cx.waker());
393 let r = READY_ENDPOINTS.load(Ordering::Acquire);
394 if r & (1 << (i + 16)) != 0 {
395 Poll::Ready(())
396 } else {
397 Poll::Pending
398 }
399 })
400 .await;
401
402 // Mark as not ready
403 READY_ENDPOINTS.fetch_and(!(1 << (i + 16)), Ordering::AcqRel);
404
405 // Check that the packet fits into the buffer
406 let size = regs.size.epout[i].read().bits();
407 if size as usize > buf.len() {
408 return Err(ReadError::BufferOverflow);
409 } 458 }
459 })
460 .await;
410 461
411 let epout = [ 462 // Mark as not ready
412 &regs.epout0, 463 READY_ENDPOINTS.fetch_and(!(1 << (i + 16)), Ordering::AcqRel);
413 &regs.epout1,
414 &regs.epout2,
415 &regs.epout3,
416 &regs.epout4,
417 &regs.epout5,
418 &regs.epout6,
419 &regs.epout7,
420 ];
421 epout[i]
422 .ptr
423 .write(|w| unsafe { w.bits(buf.as_ptr() as u32) });
424 // MAXCNT must match SIZE
425 epout[i].maxcnt.write(|w| unsafe { w.bits(size) });
426
427 dma_start();
428 regs.events_endepout[i].reset();
429 regs.tasks_startepout[i].write(|w| w.tasks_startepout().set_bit());
430 while regs.events_endepout[i]
431 .read()
432 .events_endepout()
433 .bit_is_clear()
434 {}
435 regs.events_endepout[i].reset();
436 dma_end();
437 464
438 Ok(size as usize) 465 unsafe { read_dma::<T>(i, buf) }
439 }
440 } 466 }
441 } 467 }
442} 468}
@@ -446,87 +472,181 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
446 472
447 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { 473 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
448 async move { 474 async move {
449 let regs = T::regs();
450 let i = self.info.addr.index(); 475 let i = self.info.addr.index();
476 assert!(i != 0);
451 477
452 // Wait until ready. 478 // Wait until ready.
453 if i != 0 { 479 poll_fn(|cx| {
454 poll_fn(|cx| { 480 EP_IN_WAKERS[i].register(cx.waker());
455 EP_IN_WAKERS[i].register(cx.waker()); 481 let r = READY_ENDPOINTS.load(Ordering::Acquire);
456 let r = READY_ENDPOINTS.load(Ordering::Acquire); 482 if r & (1 << i) != 0 {
457 if r & (1 << i) != 0 { 483 Poll::Ready(())
458 Poll::Ready(()) 484 } else {
459 } else { 485 Poll::Pending
460 Poll::Pending 486 }
461 } 487 })
462 }) 488 .await;
463 .await;
464
465 // Mark as not ready
466 READY_ENDPOINTS.fetch_and(!(1 << i), Ordering::AcqRel);
467 }
468 489
469 if i == 0 { 490 // Mark as not ready
470 regs.events_ep0datadone.reset(); 491 READY_ENDPOINTS.fetch_and(!(1 << i), Ordering::AcqRel);
471 } 492
493 unsafe { write_dma::<T>(i, buf) }
494 }
495 }
496}
472 497
473 assert!(buf.len() <= 64); 498pub struct ControlPipe<'d, T: Instance> {
474 499 _phantom: PhantomData<&'d mut T>,
475 // EasyDMA can't read FLASH, so we copy through RAM 500 max_packet_size: u16,
476 let mut ram_buf: MaybeUninit<[u8; 64]> = MaybeUninit::uninit(); 501 request: Option<Request>,
477 let ptr = ram_buf.as_mut_ptr() as *mut u8; 502}
478 unsafe { core::ptr::copy_nonoverlapping(buf.as_ptr(), ptr, buf.len()) }; 503
479 504impl<'d, T: Instance> ControlPipe<'d, T> {
480 let epin = [ 505 async fn write(&mut self, buf: &[u8], last_chunk: bool) {
481 &regs.epin0, 506 let regs = T::regs();
482 &regs.epin1, 507 regs.events_ep0datadone.reset();
483 &regs.epin2, 508 unsafe {
484 &regs.epin3, 509 write_dma::<T>(0, buf).unwrap();
485 &regs.epin4, 510 }
486 &regs.epin5, 511
487 &regs.epin6, 512 regs.shorts
488 &regs.epin7, 513 .modify(|_, w| w.ep0datadone_ep0status().bit(last_chunk));
489 ]; 514
490 515 regs.intenset.write(|w| w.ep0datadone().set());
491 // Set the buffer length so the right number of bytes are transmitted. 516 let res = with_timeout(
492 // Safety: `buf.len()` has been checked to be <= the max buffer length. 517 Duration::from_millis(10),
493 unsafe { 518 poll_fn(|cx| {
494 epin[i].ptr.write(|w| w.bits(ptr as u32)); 519 EP_IN_WAKERS[0].register(cx.waker());
495 epin[i].maxcnt.write(|w| w.maxcnt().bits(buf.len() as u8)); 520 let regs = T::regs();
521 if regs.events_ep0datadone.read().bits() != 0 {
522 Poll::Ready(())
523 } else {
524 Poll::Pending
525 }
526 }),
527 )
528 .await;
529
530 if res.is_err() {
531 error!("ControlPipe::write timed out.");
532 }
533 }
534}
535
536impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
537 type SetupFuture<'a> = impl Future<Output = Request> + 'a where Self: 'a;
538 type DataOutFuture<'a> = impl Future<Output = Result<usize, ReadError>> + 'a where Self: 'a;
539 type AcceptInFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
540
541 fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> {
542 async move {
543 assert!(self.request.is_none());
544
545 let regs = T::regs();
546
547 // Wait for SETUP packet
548 regs.intenset.write(|w| w.ep0setup().set());
549 poll_fn(|cx| {
550 EP_OUT_WAKERS[0].register(cx.waker());
551 let regs = T::regs();
552 if regs.events_ep0setup.read().bits() != 0 {
553 Poll::Ready(())
554 } else {
555 Poll::Pending
556 }
557 })
558 .await;
559
560 // Reset shorts
561 regs.shorts
562 .modify(|_, w| w.ep0datadone_ep0status().clear_bit());
563 regs.events_ep0setup.reset();
564
565 let mut buf = [0; 8];
566 buf[0] = regs.bmrequesttype.read().bits() as u8;
567 buf[1] = regs.brequest.read().brequest().bits();
568 buf[2] = regs.wvaluel.read().wvaluel().bits();
569 buf[3] = regs.wvalueh.read().wvalueh().bits();
570 buf[4] = regs.windexl.read().windexl().bits();
571 buf[5] = regs.windexh.read().windexh().bits();
572 buf[6] = regs.wlengthl.read().wlengthl().bits();
573 buf[7] = regs.wlengthh.read().wlengthh().bits();
574
575 let req = Request::parse(&buf);
576
577 if req.direction == UsbDirection::Out {
578 regs.tasks_ep0rcvout
579 .write(|w| w.tasks_ep0rcvout().set_bit());
496 } 580 }
497 581
498 regs.events_endepin[i].reset(); 582 self.request = Some(req);
499 583 req
500 dma_start(); 584 }
501 regs.tasks_startepin[i].write(|w| unsafe { w.bits(1) }); 585 }
502 while regs.events_endepin[i].read().bits() == 0 {} 586
503 dma_end(); 587 fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a> {
504 588 async move {
505 if i == 0 { 589 let req = self.request.unwrap();
506 regs.intenset.write(|w| w.ep0datadone().set()); 590 assert_eq!(req.direction, UsbDirection::Out);
507 let res = with_timeout( 591 assert!(req.length > 0);
508 Duration::from_millis(10), 592 assert!(buf.len() >= usize::from(req.length));
509 poll_fn(|cx| { 593
510 EP_IN_WAKERS[0].register(cx.waker()); 594 let regs = T::regs();
511 let regs = T::regs(); 595
512 if regs.events_ep0datadone.read().bits() != 0 { 596 // Wait until ready
513 Poll::Ready(()) 597 regs.intenset.write(|w| w.ep0datadone().set());
514 } else { 598 poll_fn(|cx| {
515 Poll::Pending 599 EP_OUT_WAKERS[0].register(cx.waker());
516 } 600 let regs = T::regs();
517 }), 601 if regs
518 ) 602 .events_ep0datadone
519 .await; 603 .read()
520 604 .events_ep0datadone()
521 if res.is_err() { 605 .bit_is_set()
522 // todo wrong error 606 {
523 return Err(driver::WriteError::BufferOverflow); 607 Poll::Ready(())
608 } else {
609 Poll::Pending
524 } 610 }
611 })
612 .await;
613
614 unsafe { read_dma::<T>(0, buf) }
615 }
616 }
617
618 fn accept(&mut self) {
619 let regs = T::regs();
620 regs.tasks_ep0status
621 .write(|w| w.tasks_ep0status().bit(true));
622 self.request = None;
623 }
624
625 fn accept_in<'a>(&'a mut self, buf: &'a [u8]) -> Self::AcceptInFuture<'a> {
626 async move {
627 info!("control accept {=[u8]:x}", buf);
628 let req = self.request.unwrap();
629 assert_eq!(req.direction, UsbDirection::In);
630
631 let req_len = usize::from(req.length);
632 let len = buf.len().min(req_len);
633 let need_zlp = len != req_len && (len % usize::from(self.max_packet_size)) == 0;
634 let mut chunks = buf[0..len]
635 .chunks(usize::from(self.max_packet_size))
636 .chain(need_zlp.then(|| -> &[u8] { &[] }));
637 while let Some(chunk) = chunks.next() {
638 self.write(chunk, chunks.size_hint().0 == 0).await;
525 } 639 }
526 640
527 Ok(()) 641 self.request = None;
528 } 642 }
529 } 643 }
644
645 fn reject(&mut self) {
646 let regs = T::regs();
647 regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true));
648 self.request = None;
649 }
530} 650}
531 651
532fn dma_start() { 652fn dma_start() {
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index e92cc8ef2..f0f94b932 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,3 +1,4 @@
1use super::class::UsbClass;
1use super::descriptor::{BosWriter, DescriptorWriter}; 2use super::descriptor::{BosWriter, DescriptorWriter};
2use super::driver::{Driver, EndpointAllocError}; 3use super::driver::{Driver, EndpointAllocError};
3use super::types::*; 4use super::types::*;
@@ -174,7 +175,10 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
174 } 175 }
175 176
176 /// Creates the [`UsbDevice`] instance with the configuration in this builder. 177 /// Creates the [`UsbDevice`] instance with the configuration in this builder.
177 pub fn build(mut self) -> UsbDevice<'d, D> { 178 ///
179 /// If a device has mutliple [`UsbClass`]es, they can be provided as a tuple list:
180 /// `(class1, (class2, (class3, ()))`.
181 pub fn build<C: UsbClass<'d, D>>(mut self, classes: C) -> UsbDevice<'d, D, C> {
178 self.config_descriptor.end_configuration(); 182 self.config_descriptor.end_configuration();
179 self.bos_descriptor.end_bos(); 183 self.bos_descriptor.end_bos();
180 184
@@ -184,6 +188,7 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
184 self.device_descriptor.into_buf(), 188 self.device_descriptor.into_buf(),
185 self.config_descriptor.into_buf(), 189 self.config_descriptor.into_buf(),
186 self.bos_descriptor.writer.into_buf(), 190 self.bos_descriptor.writer.into_buf(),
191 classes,
187 ) 192 )
188 } 193 }
189 194
@@ -268,9 +273,10 @@ impl<'d, D: Driver<'d>> UsbDeviceBuilder<'d, D> {
268 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not 273 /// Panics if endpoint allocation fails, because running out of endpoints or memory is not
269 /// feasibly recoverable. 274 /// feasibly recoverable.
270 #[inline] 275 #[inline]
271 pub fn alloc_control_endpoint_out(&mut self, max_packet_size: u16) -> D::EndpointOut { 276 pub fn alloc_control_pipe(&mut self, max_packet_size: u16) -> D::ControlPipe {
272 self.alloc_endpoint_out(None, EndpointType::Control, max_packet_size, 0) 277 self.bus
273 .expect("alloc_ep failed") 278 .alloc_control_pipe(max_packet_size)
279 .expect("alloc_control_pipe failed")
274 } 280 }
275 281
276 /// Allocates a bulk in endpoint. 282 /// Allocates a bulk in endpoint.
diff --git a/embassy-usb/src/class.rs b/embassy-usb/src/class.rs
new file mode 100644
index 000000000..97bf7aba1
--- /dev/null
+++ b/embassy-usb/src/class.rs
@@ -0,0 +1,190 @@
1use core::future::Future;
2
3use crate::control::Request;
4use crate::driver::{ControlPipe, Driver};
5
6#[derive(Copy, Clone, Eq, PartialEq, Debug)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub enum RequestStatus {
9 Unhandled,
10 Accepted,
11 Rejected,
12}
13
14impl Default for RequestStatus {
15 fn default() -> Self {
16 RequestStatus::Unhandled
17 }
18}
19
20/// A trait for implementing USB classes.
21///
22/// All methods are optional callbacks that will be called by
23/// [`UsbDevice::run()`](crate::UsbDevice::run)
24pub trait UsbClass<'d, D: Driver<'d>> {
25 type ControlOutFuture<'a>: Future<Output = RequestStatus> + 'a
26 where
27 Self: 'a,
28 'd: 'a,
29 D: 'a;
30
31 type ControlInFuture<'a>: Future<Output = ControlInRequestStatus> + 'a
32 where
33 Self: 'a,
34 'd: 'a,
35 D: 'a;
36
37 /// Called after a USB reset after the bus reset sequence is complete.
38 fn reset(&mut self) {}
39
40 /// Called when a control request is received with direction HostToDevice.
41 ///
42 /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
43 /// error. Classes can even choose to override standard requests, but doing that is rarely
44 /// necessary.
45 ///
46 /// When implementing your own class, you should ignore any requests that are not meant for your
47 /// class so that any other classes in the composite device can process them.
48 ///
49 /// # Arguments
50 ///
51 /// * `req` - The request from the SETUP packet.
52 /// * `data` - The data from the request.
53 fn control_out<'a>(&'a mut self, req: Request, data: &'a [u8]) -> Self::ControlOutFuture<'a>
54 where
55 'd: 'a,
56 D: 'a;
57
58 /// Called when a control request is received with direction DeviceToHost.
59 ///
60 /// All requests are passed to classes in turn, which can choose to accept, ignore or report an
61 /// error. Classes can even choose to override standard requests, but doing that is rarely
62 /// necessary.
63 ///
64 /// See [`ControlIn`] for how to respond to the transfer.
65 ///
66 /// When implementing your own class, you should ignore any requests that are not meant for your
67 /// class so that any other classes in the composite device can process them.
68 ///
69 /// # Arguments
70 ///
71 /// * `req` - The request from the SETUP packet.
72 /// * `control` - The control pipe.
73 fn control_in<'a>(
74 &'a mut self,
75 req: Request,
76 control: ControlIn<'a, 'd, D>,
77 ) -> Self::ControlInFuture<'a>
78 where
79 'd: 'a;
80}
81
82impl<'d, D: Driver<'d>> UsbClass<'d, D> for () {
83 type ControlOutFuture<'a> = impl Future<Output = RequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
84 type ControlInFuture<'a> = impl Future<Output = ControlInRequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
85
86 fn control_out<'a>(&'a mut self, _req: Request, _data: &'a [u8]) -> Self::ControlOutFuture<'a>
87 where
88 'd: 'a,
89 D: 'a,
90 {
91 async move { RequestStatus::default() }
92 }
93
94 fn control_in<'a>(
95 &'a mut self,
96 _req: Request,
97 control: ControlIn<'a, 'd, D>,
98 ) -> Self::ControlInFuture<'a>
99 where
100 'd: 'a,
101 D: 'a,
102 {
103 async move { control.ignore() }
104 }
105}
106
107impl<'d, D: Driver<'d>, Head, Tail> UsbClass<'d, D> for (Head, Tail)
108where
109 Head: UsbClass<'d, D>,
110 Tail: UsbClass<'d, D>,
111{
112 type ControlOutFuture<'a> = impl Future<Output = RequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
113 type ControlInFuture<'a> = impl Future<Output = ControlInRequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
114
115 fn control_out<'a>(&'a mut self, req: Request, data: &'a [u8]) -> Self::ControlOutFuture<'a>
116 where
117 'd: 'a,
118 D: 'a,
119 {
120 async move {
121 match self.0.control_out(req, data).await {
122 RequestStatus::Unhandled => self.1.control_out(req, data).await,
123 status => status,
124 }
125 }
126 }
127
128 fn control_in<'a>(
129 &'a mut self,
130 req: Request,
131 control: ControlIn<'a, 'd, D>,
132 ) -> Self::ControlInFuture<'a>
133 where
134 'd: 'a,
135 {
136 async move {
137 match self
138 .0
139 .control_in(req, ControlIn::new(control.control))
140 .await
141 {
142 ControlInRequestStatus(RequestStatus::Unhandled) => {
143 self.1.control_in(req, control).await
144 }
145 status => status,
146 }
147 }
148 }
149}
150
151/// Handle for a control IN transfer. When implementing a class, use the methods of this object to
152/// response to the transfer with either data or an error (STALL condition). To ignore the request
153/// and pass it on to the next class, call [`Self::ignore()`].
154pub struct ControlIn<'a, 'd: 'a, D: Driver<'d>> {
155 control: &'a mut D::ControlPipe,
156}
157
158#[derive(Eq, PartialEq, Debug)]
159#[cfg_attr(feature = "defmt", derive(defmt::Format))]
160pub struct ControlInRequestStatus(pub(crate) RequestStatus);
161
162impl ControlInRequestStatus {
163 pub fn status(self) -> RequestStatus {
164 self.0
165 }
166}
167
168impl<'a, 'd: 'a, D: Driver<'d>> ControlIn<'a, 'd, D> {
169 pub(crate) fn new(control: &'a mut D::ControlPipe) -> Self {
170 ControlIn { control }
171 }
172
173 /// Ignores the request and leaves it unhandled.
174 pub fn ignore(self) -> ControlInRequestStatus {
175 ControlInRequestStatus(RequestStatus::Unhandled)
176 }
177
178 /// Accepts the transfer with the supplied buffer.
179 pub async fn accept(self, data: &[u8]) -> ControlInRequestStatus {
180 self.control.accept_in(data).await;
181
182 ControlInRequestStatus(RequestStatus::Accepted)
183 }
184
185 /// Rejects the transfer by stalling the pipe.
186 pub fn reject(self) -> ControlInRequestStatus {
187 self.control.reject();
188 ControlInRequestStatus(RequestStatus::Rejected)
189 }
190}
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index f1148ac76..77bc10aa4 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -2,12 +2,6 @@ use core::mem;
2 2
3use super::types::*; 3use super::types::*;
4 4
5#[derive(Debug, PartialEq, Eq, Clone, Copy)]
6#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7pub enum ParseError {
8 InvalidLength,
9}
10
11/// Control request type. 5/// Control request type.
12#[repr(u8)] 6#[repr(u8)]
13#[derive(Copy, Clone, Eq, PartialEq, Debug)] 7#[derive(Copy, Clone, Eq, PartialEq, Debug)]
@@ -104,15 +98,12 @@ impl Request {
104 /// Standard USB feature Device Remote Wakeup for Set/Clear Feature 98 /// Standard USB feature Device Remote Wakeup for Set/Clear Feature
105 pub const FEATURE_DEVICE_REMOTE_WAKEUP: u16 = 1; 99 pub const FEATURE_DEVICE_REMOTE_WAKEUP: u16 = 1;
106 100
107 pub(crate) fn parse(buf: &[u8]) -> Result<Request, ParseError> { 101 /// Parses a USB control request from a byte array.
108 if buf.len() != 8 { 102 pub fn parse(buf: &[u8; 8]) -> Request {
109 return Err(ParseError::InvalidLength);
110 }
111
112 let rt = buf[0]; 103 let rt = buf[0];
113 let recipient = rt & 0b11111; 104 let recipient = rt & 0b11111;
114 105
115 Ok(Request { 106 Request {
116 direction: rt.into(), 107 direction: rt.into(),
117 request_type: unsafe { mem::transmute((rt >> 5) & 0b11) }, 108 request_type: unsafe { mem::transmute((rt >> 5) & 0b11) },
118 recipient: if recipient <= 3 { 109 recipient: if recipient <= 3 {
@@ -124,7 +115,7 @@ impl Request {
124 value: (buf[2] as u16) | ((buf[3] as u16) << 8), 115 value: (buf[2] as u16) | ((buf[3] as u16) << 8),
125 index: (buf[4] as u16) | ((buf[5] as u16) << 8), 116 index: (buf[4] as u16) | ((buf[5] as u16) << 8),
126 length: (buf[6] as u16) | ((buf[7] as u16) << 8), 117 length: (buf[6] as u16) | ((buf[7] as u16) << 8),
127 }) 118 }
128 } 119 }
129 120
130 /// Gets the descriptor type and index from the value field of a GET_DESCRIPTOR request. 121 /// Gets the descriptor type and index from the value field of a GET_DESCRIPTOR request.
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs
index a7b16efa5..1c6ba1f52 100644
--- a/embassy-usb/src/driver.rs
+++ b/embassy-usb/src/driver.rs
@@ -1,5 +1,7 @@
1use core::future::Future; 1use core::future::Future;
2 2
3use crate::control::Request;
4
3use super::types::*; 5use super::types::*;
4 6
5/// Driver for a specific USB peripheral. Implement this to add support for a new hardware 7/// Driver for a specific USB peripheral. Implement this to add support for a new hardware
@@ -7,6 +9,7 @@ use super::types::*;
7pub trait Driver<'a> { 9pub trait Driver<'a> {
8 type EndpointOut: EndpointOut + 'a; 10 type EndpointOut: EndpointOut + 'a;
9 type EndpointIn: EndpointIn + 'a; 11 type EndpointIn: EndpointIn + 'a;
12 type ControlPipe: ControlPipe + 'a;
10 type Bus: Bus + 'a; 13 type Bus: Bus + 'a;
11 14
12 /// Allocates an endpoint and specified endpoint parameters. This method is called by the device 15 /// Allocates an endpoint and specified endpoint parameters. This method is called by the device
@@ -36,6 +39,11 @@ pub trait Driver<'a> {
36 interval: u8, 39 interval: u8,
37 ) -> Result<Self::EndpointIn, EndpointAllocError>; 40 ) -> Result<Self::EndpointIn, EndpointAllocError>;
38 41
42 fn alloc_control_pipe(
43 &mut self,
44 max_packet_size: u16,
45 ) -> Result<Self::ControlPipe, EndpointAllocError>;
46
39 /// Enables and initializes the USB peripheral. Soon after enabling the device will be reset, so 47 /// Enables and initializes the USB peripheral. Soon after enabling the device will be reset, so
40 /// there is no need to perform a USB reset in this method. 48 /// there is no need to perform a USB reset in this method.
41 fn enable(self) -> Self::Bus; 49 fn enable(self) -> Self::Bus;
@@ -122,6 +130,40 @@ pub trait EndpointOut: Endpoint {
122 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a>; 130 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a>;
123} 131}
124 132
133pub trait ControlPipe {
134 type SetupFuture<'a>: Future<Output = Request> + 'a
135 where
136 Self: 'a;
137 type DataOutFuture<'a>: Future<Output = Result<usize, ReadError>> + 'a
138 where
139 Self: 'a;
140 type AcceptInFuture<'a>: Future<Output = ()> + 'a
141 where
142 Self: 'a;
143
144 /// Reads a single setup packet from the endpoint.
145 fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a>;
146
147 /// Reads the data packet of a control write sequence.
148 ///
149 /// Must be called after `setup()` for requests with `direction` of `Out`
150 /// and `length` greater than zero.
151 ///
152 /// `buf.len()` must be greater than or equal to the request's `length`.
153 fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a>;
154
155 /// Accepts a control request.
156 fn accept(&mut self);
157
158 /// Accepts a control read request with `data`.
159 ///
160 /// `data.len()` must be less than or equal to the request's `length`.
161 fn accept_in<'a>(&'a mut self, data: &'a [u8]) -> Self::AcceptInFuture<'a>;
162
163 /// Rejects a control request.
164 fn reject(&mut self);
165}
166
125pub trait EndpointIn: Endpoint { 167pub trait EndpointIn: Endpoint {
126 type WriteFuture<'a>: Future<Output = Result<(), WriteError>> + 'a 168 type WriteFuture<'a>: Future<Output = Result<(), WriteError>> + 'a
127 where 169 where
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index 95f78804d..4082868fb 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -1,16 +1,19 @@
1#![no_std] 1#![no_std]
2#![feature(generic_associated_types)] 2#![feature(generic_associated_types)]
3#![feature(type_alias_impl_trait)]
3 4
4// This mod MUST go first, so that the others see its macros. 5// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt; 6pub(crate) mod fmt;
6 7
7mod builder; 8mod builder;
8mod control; 9pub mod class;
10pub mod control;
9pub mod descriptor; 11pub mod descriptor;
10pub mod driver; 12pub mod driver;
11pub mod types; 13pub mod types;
12mod util; 14mod util;
13 15
16use self::class::{RequestStatus, UsbClass};
14use self::control::*; 17use self::control::*;
15use self::descriptor::*; 18use self::descriptor::*;
16use self::driver::*; 19use self::driver::*;
@@ -48,10 +51,9 @@ pub const CONFIGURATION_VALUE: u8 = 1;
48/// The default value for bAlternateSetting for all interfaces. 51/// The default value for bAlternateSetting for all interfaces.
49pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; 52pub const DEFAULT_ALTERNATE_SETTING: u8 = 0;
50 53
51pub struct UsbDevice<'d, D: Driver<'d>> { 54pub struct UsbDevice<'d, D: Driver<'d>, C: UsbClass<'d, D>> {
52 bus: D::Bus, 55 bus: D::Bus,
53 control_in: D::EndpointIn, 56 control: D::ControlPipe,
54 control_out: D::EndpointOut,
55 57
56 config: Config<'d>, 58 config: Config<'d>,
57 device_descriptor: &'d [u8], 59 device_descriptor: &'d [u8],
@@ -62,32 +64,21 @@ pub struct UsbDevice<'d, D: Driver<'d>> {
62 remote_wakeup_enabled: bool, 64 remote_wakeup_enabled: bool,
63 self_powered: bool, 65 self_powered: bool,
64 pending_address: u8, 66 pending_address: u8,
67
68 classes: C,
65} 69}
66 70
67impl<'d, D: Driver<'d>> UsbDevice<'d, D> { 71impl<'d, D: Driver<'d>, C: UsbClass<'d, D>> UsbDevice<'d, D, C> {
68 pub(crate) fn build( 72 pub(crate) fn build(
69 mut driver: D, 73 mut driver: D,
70 config: Config<'d>, 74 config: Config<'d>,
71 device_descriptor: &'d [u8], 75 device_descriptor: &'d [u8],
72 config_descriptor: &'d [u8], 76 config_descriptor: &'d [u8],
73 bos_descriptor: &'d [u8], 77 bos_descriptor: &'d [u8],
78 classes: C,
74 ) -> Self { 79 ) -> Self {
75 let control_out = driver 80 let control = driver
76 .alloc_endpoint_out( 81 .alloc_control_pipe(config.max_packet_size_0 as u16)
77 Some(0x00.into()),
78 EndpointType::Control,
79 config.max_packet_size_0 as u16,
80 0,
81 )
82 .expect("failed to alloc control endpoint");
83
84 let control_in = driver
85 .alloc_endpoint_in(
86 Some(0x80.into()),
87 EndpointType::Control,
88 config.max_packet_size_0 as u16,
89 0,
90 )
91 .expect("failed to alloc control endpoint"); 82 .expect("failed to alloc control endpoint");
92 83
93 // Enable the USB bus. 84 // Enable the USB bus.
@@ -97,8 +88,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
97 Self { 88 Self {
98 bus: driver, 89 bus: driver,
99 config, 90 config,
100 control_in, 91 control,
101 control_out,
102 device_descriptor, 92 device_descriptor,
103 config_descriptor, 93 config_descriptor,
104 bos_descriptor, 94 bos_descriptor,
@@ -106,14 +96,13 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
106 remote_wakeup_enabled: false, 96 remote_wakeup_enabled: false,
107 self_powered: false, 97 self_powered: false,
108 pending_address: 0, 98 pending_address: 0,
99 classes,
109 } 100 }
110 } 101 }
111 102
112 pub async fn run(&mut self) { 103 pub async fn run(&mut self) {
113 let mut buf = [0; 8];
114
115 loop { 104 loop {
116 let control_fut = self.control_out.read(&mut buf); 105 let control_fut = self.control.setup();
117 let bus_fut = self.bus.poll(); 106 let bus_fut = self.bus.poll();
118 match select(bus_fut, control_fut).await { 107 match select(bus_fut, control_fut).await {
119 Either::Left(evt) => match evt { 108 Either::Left(evt) => match evt {
@@ -124,11 +113,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
124 self.remote_wakeup_enabled = false; 113 self.remote_wakeup_enabled = false;
125 self.pending_address = 0; 114 self.pending_address = 0;
126 115
127 // TODO 116 self.classes.reset();
128 //self.control.reset();
129 //for cls in classes {
130 // cls.reset();
131 //}
132 } 117 }
133 Event::Resume => {} 118 Event::Resume => {}
134 Event::Suspend => { 119 Event::Suspend => {
@@ -136,16 +121,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
136 self.device_state = UsbDeviceState::Suspend; 121 self.device_state = UsbDeviceState::Suspend;
137 } 122 }
138 }, 123 },
139 Either::Right(n) => { 124 Either::Right(req) => {
140 let n = n.unwrap();
141 assert_eq!(n, 8);
142 let req = Request::parse(&buf).unwrap();
143 info!("control request: {:x}", req); 125 info!("control request: {:x}", req);
144 126
145 // Now that we have properly parsed the setup packet, ensure the end-point is no longer in
146 // a stalled state.
147 self.control_out.set_stalled(false);
148
149 match req.direction { 127 match req.direction {
150 UsbDirection::In => self.handle_control_in(req).await, 128 UsbDirection::In => self.handle_control_in(req).await,
151 UsbDirection::Out => self.handle_control_out(req).await, 129 UsbDirection::Out => self.handle_control_out(req).await,
@@ -155,36 +133,6 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
155 } 133 }
156 } 134 }
157 135
158 async fn write_chunked(&mut self, data: &[u8]) -> Result<(), driver::WriteError> {
159 for c in data.chunks(8) {
160 self.control_in.write(c).await?;
161 }
162 if data.len() % 8 == 0 {
163 self.control_in.write(&[]).await?;
164 }
165 Ok(())
166 }
167
168 async fn control_out_accept(&mut self, req: Request) {
169 info!("control out accept");
170 // status phase
171 // todo: cleanup
172 self.control_out.read(&mut []).await.unwrap();
173 }
174
175 async fn control_in_accept(&mut self, req: Request, data: &[u8]) {
176 info!("control accept {:x}", data);
177
178 let len = data.len().min(req.length as _);
179 if let Err(e) = self.write_chunked(&data[..len]).await {
180 info!("write_chunked failed: {:?}", e);
181 }
182
183 // status phase
184 // todo: cleanup
185 self.control_out.read(&mut []).await.unwrap();
186 }
187
188 async fn control_in_accept_writer( 136 async fn control_in_accept_writer(
189 &mut self, 137 &mut self,
190 req: Request, 138 req: Request,
@@ -193,17 +141,26 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
193 let mut buf = [0; 256]; 141 let mut buf = [0; 256];
194 let mut w = DescriptorWriter::new(&mut buf); 142 let mut w = DescriptorWriter::new(&mut buf);
195 f(&mut w); 143 f(&mut w);
196 let pos = w.position(); 144 let pos = w.position().min(usize::from(req.length));
197 self.control_in_accept(req, &buf[..pos]).await; 145 self.control.accept_in(&buf[..pos]).await;
198 }
199
200 fn control_reject(&mut self, req: Request) {
201 info!("control reject");
202 self.control_out.set_stalled(true);
203 } 146 }
204 147
205 async fn handle_control_out(&mut self, req: Request) { 148 async fn handle_control_out(&mut self, req: Request) {
206 // TODO actually read the data if there's an OUT data phase. 149 {
150 let mut buf = [0; 128];
151 let data = if req.length > 0 {
152 let size = self.control.data_out(&mut buf).await.unwrap();
153 &buf[0..size]
154 } else {
155 &[]
156 };
157
158 match self.classes.control_out(req, data).await {
159 RequestStatus::Accepted => return self.control.accept(),
160 RequestStatus::Rejected => return self.control.reject(),
161 RequestStatus::Unhandled => (),
162 }
163 }
207 164
208 const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; 165 const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16;
209 const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; 166 const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16;
@@ -217,12 +174,12 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
217 Request::FEATURE_DEVICE_REMOTE_WAKEUP, 174 Request::FEATURE_DEVICE_REMOTE_WAKEUP,
218 ) => { 175 ) => {
219 self.remote_wakeup_enabled = false; 176 self.remote_wakeup_enabled = false;
220 self.control_out_accept(req).await; 177 self.control.accept();
221 } 178 }
222 179
223 (Recipient::Endpoint, Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { 180 (Recipient::Endpoint, Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => {
224 //self.bus.set_stalled(((req.index as u8) & 0x8f).into(), false); 181 //self.bus.set_stalled(((req.index as u8) & 0x8f).into(), false);
225 self.control_out_accept(req).await; 182 self.control.accept();
226 } 183 }
227 184
228 ( 185 (
@@ -231,51 +188,61 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
231 Request::FEATURE_DEVICE_REMOTE_WAKEUP, 188 Request::FEATURE_DEVICE_REMOTE_WAKEUP,
232 ) => { 189 ) => {
233 self.remote_wakeup_enabled = true; 190 self.remote_wakeup_enabled = true;
234 self.control_out_accept(req).await; 191 self.control.accept();
235 } 192 }
236 193
237 (Recipient::Endpoint, Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { 194 (Recipient::Endpoint, Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => {
238 self.bus 195 self.bus
239 .set_stalled(((req.index as u8) & 0x8f).into(), true); 196 .set_stalled(((req.index as u8) & 0x8f).into(), true);
240 self.control_out_accept(req).await; 197 self.control.accept();
241 } 198 }
242 199
243 (Recipient::Device, Request::SET_ADDRESS, 1..=127) => { 200 (Recipient::Device, Request::SET_ADDRESS, 1..=127) => {
244 self.pending_address = req.value as u8; 201 self.pending_address = req.value as u8;
245 202
246 // on NRF the hardware auto-handles SET_ADDRESS. 203 // on NRF the hardware auto-handles SET_ADDRESS.
247 self.control_out_accept(req).await; 204 self.control.accept();
248 } 205 }
249 206
250 (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => { 207 (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => {
251 self.device_state = UsbDeviceState::Configured; 208 self.device_state = UsbDeviceState::Configured;
252 self.control_out_accept(req).await; 209 self.control.accept();
253 } 210 }
254 211
255 (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => { 212 (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => {
256 match self.device_state { 213 match self.device_state {
257 UsbDeviceState::Default => { 214 UsbDeviceState::Default => {
258 self.control_out_accept(req).await; 215 self.control.accept();
259 } 216 }
260 _ => { 217 _ => {
261 self.device_state = UsbDeviceState::Addressed; 218 self.device_state = UsbDeviceState::Addressed;
262 self.control_out_accept(req).await; 219 self.control.accept();
263 } 220 }
264 } 221 }
265 } 222 }
266 223
267 (Recipient::Interface, Request::SET_INTERFACE, DEFAULT_ALTERNATE_SETTING_U16) => { 224 (Recipient::Interface, Request::SET_INTERFACE, DEFAULT_ALTERNATE_SETTING_U16) => {
268 // TODO: do something when alternate settings are implemented 225 // TODO: do something when alternate settings are implemented
269 self.control_out_accept(req).await; 226 self.control.accept();
270 } 227 }
271 228
272 _ => self.control_reject(req), 229 _ => self.control.reject(),
273 }, 230 },
274 _ => self.control_reject(req), 231 _ => self.control.reject(),
275 } 232 }
276 } 233 }
277 234
278 async fn handle_control_in(&mut self, req: Request) { 235 async fn handle_control_in(&mut self, req: Request) {
236 match self
237 .classes
238 .control_in(req, class::ControlIn::new(&mut self.control))
239 .await
240 .status()
241 {
242 RequestStatus::Accepted | RequestStatus::Rejected => return,
243 RequestStatus::Unhandled => (),
244 }
245
279 match req.request_type { 246 match req.request_type {
280 RequestType::Standard => match (req.recipient, req.request) { 247 RequestType::Standard => match (req.recipient, req.request) {
281 (Recipient::Device, Request::GET_STATUS) => { 248 (Recipient::Device, Request::GET_STATUS) => {
@@ -286,12 +253,12 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
286 if self.remote_wakeup_enabled { 253 if self.remote_wakeup_enabled {
287 status |= 0x0002; 254 status |= 0x0002;
288 } 255 }
289 self.control_in_accept(req, &status.to_le_bytes()).await; 256 self.control.accept_in(&status.to_le_bytes()).await;
290 } 257 }
291 258
292 (Recipient::Interface, Request::GET_STATUS) => { 259 (Recipient::Interface, Request::GET_STATUS) => {
293 let status: u16 = 0x0000; 260 let status: u16 = 0x0000;
294 self.control_in_accept(req, &status.to_le_bytes()).await; 261 self.control.accept_in(&status.to_le_bytes()).await;
295 } 262 }
296 263
297 (Recipient::Endpoint, Request::GET_STATUS) => { 264 (Recipient::Endpoint, Request::GET_STATUS) => {
@@ -300,7 +267,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
300 if self.bus.is_stalled(ep_addr) { 267 if self.bus.is_stalled(ep_addr) {
301 status |= 0x0001; 268 status |= 0x0001;
302 } 269 }
303 self.control_in_accept(req, &status.to_le_bytes()).await; 270 self.control.accept_in(&status.to_le_bytes()).await;
304 } 271 }
305 272
306 (Recipient::Device, Request::GET_DESCRIPTOR) => { 273 (Recipient::Device, Request::GET_DESCRIPTOR) => {
@@ -312,17 +279,17 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
312 UsbDeviceState::Configured => CONFIGURATION_VALUE, 279 UsbDeviceState::Configured => CONFIGURATION_VALUE,
313 _ => CONFIGURATION_NONE, 280 _ => CONFIGURATION_NONE,
314 }; 281 };
315 self.control_in_accept(req, &status.to_le_bytes()).await; 282 self.control.accept_in(&status.to_le_bytes()).await;
316 } 283 }
317 284
318 (Recipient::Interface, Request::GET_INTERFACE) => { 285 (Recipient::Interface, Request::GET_INTERFACE) => {
319 // TODO: change when alternate settings are implemented 286 // TODO: change when alternate settings are implemented
320 let status = DEFAULT_ALTERNATE_SETTING; 287 let status = DEFAULT_ALTERNATE_SETTING;
321 self.control_in_accept(req, &status.to_le_bytes()).await; 288 self.control.accept_in(&status.to_le_bytes()).await;
322 } 289 }
323 _ => self.control_reject(req), 290 _ => self.control.reject(),
324 }, 291 },
325 _ => self.control_reject(req), 292 _ => self.control.reject(),
326 } 293 }
327 } 294 }
328 295
@@ -331,11 +298,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
331 let config = self.config.clone(); 298 let config = self.config.clone();
332 299
333 match dtype { 300 match dtype {
334 descriptor_type::BOS => self.control_in_accept(req, self.bos_descriptor).await, 301 descriptor_type::BOS => self.control.accept_in(self.bos_descriptor).await,
335 descriptor_type::DEVICE => self.control_in_accept(req, self.device_descriptor).await, 302 descriptor_type::DEVICE => self.control.accept_in(self.device_descriptor).await,
336 descriptor_type::CONFIGURATION => { 303 descriptor_type::CONFIGURATION => self.control.accept_in(self.config_descriptor).await,
337 self.control_in_accept(req, self.config_descriptor).await
338 }
339 descriptor_type::STRING => { 304 descriptor_type::STRING => {
340 if index == 0 { 305 if index == 0 {
341 self.control_in_accept_writer(req, |w| { 306 self.control_in_accept_writer(req, |w| {
@@ -363,11 +328,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
363 self.control_in_accept_writer(req, |w| w.string(s).unwrap()) 328 self.control_in_accept_writer(req, |w| w.string(s).unwrap())
364 .await; 329 .await;
365 } else { 330 } else {
366 self.control_reject(req) 331 self.control.reject()
367 } 332 }
368 } 333 }
369 } 334 }
370 _ => self.control_reject(req), 335 _ => self.control.reject(),
371 } 336 }
372 } 337 }
373} 338}
diff --git a/examples/nrf/src/bin/usb/cdc_acm.rs b/examples/nrf/src/bin/usb/cdc_acm.rs
index b7c112ae6..eebf89221 100644
--- a/examples/nrf/src/bin/usb/cdc_acm.rs
+++ b/examples/nrf/src/bin/usb/cdc_acm.rs
@@ -1,5 +1,8 @@
1use core::convert::TryInto; 1use core::future::Future;
2use core::mem; 2use core::mem;
3use defmt::info;
4use embassy_usb::class::{ControlInRequestStatus, RequestStatus, UsbClass};
5use embassy_usb::control::{self, Request};
3use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError}; 6use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError};
4use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder}; 7use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder};
5 8
@@ -39,16 +42,107 @@ const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22;
39/// terminated with a short packet, even if the bulk endpoint is used for stream-like data. 42/// terminated with a short packet, even if the bulk endpoint is used for stream-like data.
40pub struct CdcAcmClass<'d, D: Driver<'d>> { 43pub struct CdcAcmClass<'d, D: Driver<'d>> {
41 // TODO not pub 44 // TODO not pub
42 pub comm_if: InterfaceNumber,
43 pub comm_ep: D::EndpointIn, 45 pub comm_ep: D::EndpointIn,
44 pub data_if: InterfaceNumber, 46 pub data_if: InterfaceNumber,
45 pub read_ep: D::EndpointOut, 47 pub read_ep: D::EndpointOut,
46 pub write_ep: D::EndpointIn, 48 pub write_ep: D::EndpointIn,
49 pub control: CdcAcmControl,
50}
51
52pub struct CdcAcmControl {
53 pub comm_if: InterfaceNumber,
47 pub line_coding: LineCoding, 54 pub line_coding: LineCoding,
48 pub dtr: bool, 55 pub dtr: bool,
49 pub rts: bool, 56 pub rts: bool,
50} 57}
51 58
59impl<'d, D: Driver<'d>> UsbClass<'d, D> for CdcAcmControl {
60 type ControlOutFuture<'a> = impl Future<Output = RequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
61 type ControlInFuture<'a> = impl Future<Output = ControlInRequestStatus> + 'a where Self: 'a, 'd: 'a, D: 'a;
62
63 fn reset(&mut self) {
64 self.line_coding = LineCoding::default();
65 self.dtr = false;
66 self.rts = false;
67 }
68
69 fn control_out<'a>(
70 &'a mut self,
71 req: control::Request,
72 data: &'a [u8],
73 ) -> Self::ControlOutFuture<'a>
74 where
75 'd: 'a,
76 D: 'a,
77 {
78 async move {
79 if !(req.request_type == control::RequestType::Class
80 && req.recipient == control::Recipient::Interface
81 && req.index == u8::from(self.comm_if) as u16)
82 {
83 return RequestStatus::Unhandled;
84 }
85
86 match req.request {
87 REQ_SEND_ENCAPSULATED_COMMAND => {
88 // We don't actually support encapsulated commands but pretend we do for standards
89 // compatibility.
90 RequestStatus::Accepted
91 }
92 REQ_SET_LINE_CODING if data.len() >= 7 => {
93 self.line_coding.data_rate = u32::from_le_bytes(data[0..4].try_into().unwrap());
94 self.line_coding.stop_bits = data[4].into();
95 self.line_coding.parity_type = data[5].into();
96 self.line_coding.data_bits = data[6];
97 info!("Set line coding to: {:?}", self.line_coding);
98
99 RequestStatus::Accepted
100 }
101 REQ_SET_CONTROL_LINE_STATE => {
102 self.dtr = (req.value & 0x0001) != 0;
103 self.rts = (req.value & 0x0002) != 0;
104 info!("Set dtr {}, rts {}", self.dtr, self.rts);
105
106 RequestStatus::Accepted
107 }
108 _ => RequestStatus::Rejected,
109 }
110 }
111 }
112
113 fn control_in<'a>(
114 &'a mut self,
115 req: Request,
116 control: embassy_usb::class::ControlIn<'a, 'd, D>,
117 ) -> Self::ControlInFuture<'a>
118 where
119 'd: 'a,
120 {
121 async move {
122 if !(req.request_type == control::RequestType::Class
123 && req.recipient == control::Recipient::Interface
124 && req.index == u8::from(self.comm_if) as u16)
125 {
126 return control.ignore();
127 }
128
129 match req.request {
130 // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.
131 REQ_GET_LINE_CODING if req.length == 7 => {
132 info!("Sending line coding");
133 let mut data = [0; 7];
134 data[0..4].copy_from_slice(&self.line_coding.data_rate.to_le_bytes());
135 data[4] = self.line_coding.stop_bits as u8;
136 data[5] = self.line_coding.parity_type as u8;
137 data[6] = self.line_coding.data_bits;
138 control.accept(&data).await
139 }
140 _ => control.reject(),
141 }
142 }
143 }
144}
145
52impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { 146impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
53 /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For 147 /// Creates a new CdcAcmClass with the provided UsbBus and max_packet_size in bytes. For
54 /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. 148 /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
@@ -133,19 +227,21 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
133 builder.config_descriptor.endpoint(read_ep.info()).unwrap(); 227 builder.config_descriptor.endpoint(read_ep.info()).unwrap();
134 228
135 CdcAcmClass { 229 CdcAcmClass {
136 comm_if,
137 comm_ep, 230 comm_ep,
138 data_if, 231 data_if,
139 read_ep, 232 read_ep,
140 write_ep, 233 write_ep,
141 line_coding: LineCoding { 234 control: CdcAcmControl {
142 stop_bits: StopBits::One, 235 comm_if,
143 data_bits: 8, 236 dtr: false,
144 parity_type: ParityType::None, 237 rts: false,
145 data_rate: 8_000, 238 line_coding: LineCoding {
239 stop_bits: StopBits::One,
240 data_bits: 8,
241 parity_type: ParityType::None,
242 data_rate: 8_000,
243 },
146 }, 244 },
147 dtr: false,
148 rts: false,
149 } 245 }
150 } 246 }
151 247
@@ -158,17 +254,17 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
158 /// Gets the current line coding. The line coding contains information that's mainly relevant 254 /// Gets the current line coding. The line coding contains information that's mainly relevant
159 /// for USB to UART serial port emulators, and can be ignored if not relevant. 255 /// for USB to UART serial port emulators, and can be ignored if not relevant.
160 pub fn line_coding(&self) -> &LineCoding { 256 pub fn line_coding(&self) -> &LineCoding {
161 &self.line_coding 257 &self.control.line_coding
162 } 258 }
163 259
164 /// Gets the DTR (data terminal ready) state 260 /// Gets the DTR (data terminal ready) state
165 pub fn dtr(&self) -> bool { 261 pub fn dtr(&self) -> bool {
166 self.dtr 262 self.control.dtr
167 } 263 }
168 264
169 /// Gets the RTS (request to send) state 265 /// Gets the RTS (request to send) state
170 pub fn rts(&self) -> bool { 266 pub fn rts(&self) -> bool {
171 self.rts 267 self.control.rts
172 } 268 }
173 269
174 /// Writes a single packet into the IN endpoint. 270 /// Writes a single packet into the IN endpoint.
@@ -270,7 +366,7 @@ impl<B: UsbBus> UsbClass<B> for CdcAcmClass<'_, B> {
270 */ 366 */
271 367
272/// Number of stop bits for LineCoding 368/// Number of stop bits for LineCoding
273#[derive(Copy, Clone, PartialEq, Eq)] 369#[derive(Copy, Clone, PartialEq, Eq, defmt::Format)]
274pub enum StopBits { 370pub enum StopBits {
275 /// 1 stop bit 371 /// 1 stop bit
276 One = 0, 372 One = 0,
@@ -293,7 +389,7 @@ impl From<u8> for StopBits {
293} 389}
294 390
295/// Parity for LineCoding 391/// Parity for LineCoding
296#[derive(Copy, Clone, PartialEq, Eq)] 392#[derive(Copy, Clone, PartialEq, Eq, defmt::Format)]
297pub enum ParityType { 393pub enum ParityType {
298 None = 0, 394 None = 0,
299 Odd = 1, 395 Odd = 1,
@@ -316,6 +412,7 @@ impl From<u8> for ParityType {
316/// 412///
317/// This is provided by the host for specifying the standard UART parameters such as baud rate. Can 413/// This is provided by the host for specifying the standard UART parameters such as baud rate. Can
318/// be ignored if you don't plan to interface with a physical UART. 414/// be ignored if you don't plan to interface with a physical UART.
415#[derive(defmt::Format)]
319pub struct LineCoding { 416pub struct LineCoding {
320 stop_bits: StopBits, 417 stop_bits: StopBits,
321 data_bits: u8, 418 data_bits: u8,
diff --git a/examples/nrf/src/bin/usb/main.rs b/examples/nrf/src/bin/usb/main.rs
index ecbdc3461..71285579c 100644
--- a/examples/nrf/src/bin/usb/main.rs
+++ b/examples/nrf/src/bin/usb/main.rs
@@ -1,5 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
3#![feature(type_alias_impl_trait)] 4#![feature(type_alias_impl_trait)]
4 5
5#[path = "../../example_common.rs"] 6#[path = "../../example_common.rs"]
@@ -58,7 +59,7 @@ async fn main(_spawner: Spawner, p: Peripherals) {
58 let mut class = CdcAcmClass::new(&mut builder, 64); 59 let mut class = CdcAcmClass::new(&mut builder, 64);
59 60
60 // Build the builder. 61 // Build the builder.
61 let mut usb = builder.build(); 62 let mut usb = builder.build(class.control);
62 63
63 // Run the USB device. 64 // Run the USB device.
64 let fut1 = usb.run(); 65 let fut1 = usb.run();