embassy/embassy-usb/src/types.rs
Dario Nieuwenhuis 092c2b7dfe usb: builtin handling of interface alternate settings
The stack reads its own descriptors to figure out which endpoints
are used in which alt settings, and enables/disables them as needed.

The ControlHandler has a callback so it can get notified of alternate
setting changes, which is purely informative (it doesn't have to do anything).
2022-04-23 01:11:10 +02:00

139 lines
3.8 KiB
Rust

/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
/// the perspective of the host, which is backward for devices, but the standard directions are used
/// for consistency.
///
/// The values of the enum also match the direction bit used in endpoint addresses and control
/// request types.
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum UsbDirection {
/// Host to device (OUT)
Out = 0x00,
/// Device to host (IN)
In = 0x80,
}
impl From<u8> for UsbDirection {
fn from(value: u8) -> Self {
unsafe { core::mem::transmute(value & 0x80) }
}
}
/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
/// transfer bmAttributes transfer type bits.
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EndpointType {
/// Control endpoint. Used for device management. Only the host can initiate requests. Usually
/// used only endpoint 0.
Control = 0b00,
/// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
Isochronous = 0b01,
/// Bulk endpoint. Used for large amounts of best-effort reliable data.
Bulk = 0b10,
/// Interrupt endpoint. Used for small amounts of time-critical reliable data.
Interrupt = 0b11,
}
/// Type-safe endpoint address.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EndpointAddress(u8);
impl From<u8> for EndpointAddress {
#[inline]
fn from(addr: u8) -> EndpointAddress {
EndpointAddress(addr)
}
}
impl From<EndpointAddress> for u8 {
#[inline]
fn from(addr: EndpointAddress) -> u8 {
addr.0
}
}
impl EndpointAddress {
const INBITS: u8 = UsbDirection::In as u8;
/// Constructs a new EndpointAddress with the given index and direction.
#[inline]
pub fn from_parts(index: usize, dir: UsbDirection) -> Self {
EndpointAddress(index as u8 | dir as u8)
}
/// Gets the direction part of the address.
#[inline]
pub fn direction(&self) -> UsbDirection {
if (self.0 & Self::INBITS) != 0 {
UsbDirection::In
} else {
UsbDirection::Out
}
}
/// Returns true if the direction is IN, otherwise false.
#[inline]
pub fn is_in(&self) -> bool {
(self.0 & Self::INBITS) != 0
}
/// Returns true if the direction is OUT, otherwise false.
#[inline]
pub fn is_out(&self) -> bool {
(self.0 & Self::INBITS) == 0
}
/// Gets the index part of the endpoint address.
#[inline]
pub fn index(&self) -> usize {
(self.0 & !Self::INBITS) as usize
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EndpointInfo {
pub addr: EndpointAddress,
pub ep_type: EndpointType,
pub max_packet_size: u16,
pub interval: u8,
}
/// A handle for a USB interface that contains its number.
#[derive(Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterfaceNumber(pub(crate) u8);
impl InterfaceNumber {
pub(crate) fn new(index: u8) -> InterfaceNumber {
InterfaceNumber(index)
}
}
impl From<InterfaceNumber> for u8 {
fn from(n: InterfaceNumber) -> u8 {
n.0
}
}
/// A handle for a USB string descriptor that contains its index.
#[derive(Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StringIndex(u8);
impl StringIndex {
pub(crate) fn new(index: u8) -> StringIndex {
StringIndex(index)
}
}
impl From<StringIndex> for u8 {
fn from(i: StringIndex) -> u8 {
i.0
}
}