diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 98b55adf..dfd36bdb 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -1,6 +1,6 @@ use heapless::Vec; -use super::class::ControlHandler; +use super::control::ControlHandler; use super::descriptor::{BosWriter, DescriptorWriter}; use super::driver::{Driver, EndpointAllocError}; use super::types::*; diff --git a/embassy-usb/src/class.rs b/embassy-usb/src/class.rs deleted file mode 100644 index 754e3a20..00000000 --- a/embassy-usb/src/class.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::control::Request; - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum RequestStatus { - Accepted, - Rejected, -} - -/// A trait for implementing USB classes. -/// -/// All methods are optional callbacks that will be called by -/// [`UsbDevice::run()`](crate::UsbDevice::run) -pub trait ControlHandler { - /// Called after a USB reset after the bus reset sequence is complete. - fn reset(&mut self) {} - - /// Called when a control request is received with direction HostToDevice. - /// - /// All requests are passed to classes in turn, which can choose to accept, ignore or report an - /// error. Classes can even choose to override standard requests, but doing that is rarely - /// necessary. - /// - /// When implementing your own class, you should ignore any requests that are not meant for your - /// class so that any other classes in the composite device can process them. - /// - /// # Arguments - /// - /// * `req` - The request from the SETUP packet. - /// * `data` - The data from the request. - fn control_out(&mut self, req: Request, data: &[u8]) -> RequestStatus { - RequestStatus::Rejected - } - - /// Called when a control request is received with direction DeviceToHost. - /// - /// All requests are passed to classes in turn, which can choose to accept, ignore or report an - /// error. Classes can even choose to override standard requests, but doing that is rarely - /// necessary. - /// - /// See [`ControlIn`] for how to respond to the transfer. - /// - /// When implementing your own class, you should ignore any requests that are not meant for your - /// class so that any other classes in the composite device can process them. - /// - /// # Arguments - /// - /// * `req` - The request from the SETUP packet. - /// * `control` - The control pipe. - fn control_in<'a>( - &mut self, - req: Request, - control: ControlIn<'a>, - ) -> ControlInRequestStatus<'a> { - control.reject() - } -} - -/// Handle for a control IN transfer. When implementing a class, use the methods of this object to -/// response to the transfer with either data or an error (STALL condition). To ignore the request -/// and pass it on to the next class, call [`Self::ignore()`]. -pub struct ControlIn<'a> { - buf: &'a mut [u8], -} - -#[derive(Eq, PartialEq, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControlInRequestStatus<'a> { - pub(crate) status: RequestStatus, - pub(crate) data: &'a [u8], -} - -impl<'a> ControlInRequestStatus<'a> { - pub fn status(&self) -> RequestStatus { - self.status - } -} - -impl<'a> ControlIn<'a> { - pub(crate) fn new(buf: &'a mut [u8]) -> Self { - ControlIn { buf } - } - - /// Accepts the transfer with the supplied buffer. - pub fn accept(self, data: &[u8]) -> ControlInRequestStatus<'a> { - assert!(data.len() < self.buf.len()); - - let buf = &mut self.buf[0..data.len()]; - buf.copy_from_slice(data); - - ControlInRequestStatus { - status: RequestStatus::Accepted, - data: buf, - } - } - - /// Rejects the transfer by stalling the pipe. - pub fn reject(self) -> ControlInRequestStatus<'a> { - ControlInRequestStatus { - status: RequestStatus::Rejected, - data: &[], - } - } -} diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs index 77bc10aa..ae4ad04a 100644 --- a/embassy-usb/src/control.rs +++ b/embassy-usb/src/control.rs @@ -123,3 +123,106 @@ impl Request { ((self.value >> 8) as u8, self.value as u8) } } + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum RequestStatus { + Accepted, + Rejected, +} + +/// A trait for implementing USB classes. +/// +/// All methods are optional callbacks that will be called by +/// [`UsbDevice::run()`](crate::UsbDevice::run) +pub trait ControlHandler { + /// Called after a USB reset after the bus reset sequence is complete. + fn reset(&mut self) {} + + /// Called when a control request is received with direction HostToDevice. + /// + /// All requests are passed to classes in turn, which can choose to accept, ignore or report an + /// error. Classes can even choose to override standard requests, but doing that is rarely + /// necessary. + /// + /// When implementing your own class, you should ignore any requests that are not meant for your + /// class so that any other classes in the composite device can process them. + /// + /// # Arguments + /// + /// * `req` - The request from the SETUP packet. + /// * `data` - The data from the request. + fn control_out(&mut self, req: Request, data: &[u8]) -> RequestStatus { + RequestStatus::Rejected + } + + /// Called when a control request is received with direction DeviceToHost. + /// + /// All requests are passed to classes in turn, which can choose to accept, ignore or report an + /// error. Classes can even choose to override standard requests, but doing that is rarely + /// necessary. + /// + /// See [`ControlIn`] for how to respond to the transfer. + /// + /// When implementing your own class, you should ignore any requests that are not meant for your + /// class so that any other classes in the composite device can process them. + /// + /// # Arguments + /// + /// * `req` - The request from the SETUP packet. + /// * `control` - The control pipe. + fn control_in<'a>( + &mut self, + req: Request, + control: ControlIn<'a>, + ) -> ControlInRequestStatus<'a> { + control.reject() + } +} + +/// Handle for a control IN transfer. When implementing a class, use the methods of this object to +/// response to the transfer with either data or an error (STALL condition). To ignore the request +/// and pass it on to the next class, call [`Self::ignore()`]. +pub struct ControlIn<'a> { + buf: &'a mut [u8], +} + +#[derive(Eq, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControlInRequestStatus<'a> { + pub(crate) status: RequestStatus, + pub(crate) data: &'a [u8], +} + +impl<'a> ControlInRequestStatus<'a> { + pub fn status(&self) -> RequestStatus { + self.status + } +} + +impl<'a> ControlIn<'a> { + pub(crate) fn new(buf: &'a mut [u8]) -> Self { + ControlIn { buf } + } + + /// Accepts the transfer with the supplied buffer. + pub fn accept(self, data: &[u8]) -> ControlInRequestStatus<'a> { + assert!(data.len() < self.buf.len()); + + let buf = &mut self.buf[0..data.len()]; + buf.copy_from_slice(data); + + ControlInRequestStatus { + status: RequestStatus::Accepted, + data: buf, + } + } + + /// Rejects the transfer by stalling the pipe. + pub fn reject(self) -> ControlInRequestStatus<'a> { + ControlInRequestStatus { + status: RequestStatus::Rejected, + data: &[], + } + } +} diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 9076123a..b6c95ac6 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -6,7 +6,6 @@ pub(crate) mod fmt; mod builder; -pub mod class; pub mod control; pub mod descriptor; pub mod driver; @@ -15,7 +14,6 @@ mod util; use heapless::Vec; -use self::class::{ControlHandler, RequestStatus}; use self::control::*; use self::descriptor::*; use self::driver::*; @@ -288,7 +286,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { .map(|(_, h)| h); match handler { Some(handler) => { - let resp = handler.control_in(req, class::ControlIn::new(&mut buf)); + let resp = handler.control_in(req, ControlIn::new(&mut buf)); match resp.status { RequestStatus::Accepted => self.control.accept_in(resp.data).await, 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 f4d42979..25c3108a 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}; use core::sync::atomic::{AtomicBool, Ordering}; use defmt::info; use embassy::blocking_mutex::CriticalSectionMutex; -use embassy_usb::class::{ControlHandler, ControlInRequestStatus, RequestStatus}; -use embassy_usb::control::{self, Request}; +use embassy_usb::control::{ + self, ControlHandler, ControlIn, ControlInRequestStatus, Request, RequestStatus, +}; use embassy_usb::driver::{Endpoint, EndpointIn, EndpointOut, ReadError, WriteError}; use embassy_usb::{driver::Driver, types::*, UsbDeviceBuilder}; @@ -124,7 +125,7 @@ impl ControlHandler for Control { fn control_in<'a>( &mut self, req: Request, - control: embassy_usb::class::ControlIn<'a>, + control: ControlIn<'a>, ) -> ControlInRequestStatus<'a> { match req.request { // REQ_GET_ENCAPSULATED_COMMAND is not really supported - it will be rejected below.