/// 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 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 for EndpointAddress { #[inline] fn from(addr: u8) -> EndpointAddress { EndpointAddress(addr) } } impl From 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(u8); impl InterfaceNumber { pub(crate) fn new(index: u8) -> InterfaceNumber { InterfaceNumber(index) } } impl From 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 for u8 { fn from(i: StringIndex) -> u8 { i.0 } }