use core::time::Duration;
use crate::{EndpointInfo, EndpointType, Speed};
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SplitSpeed {
Low,
Full,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SplitInfo {
hub_addr: u8,
port: u8,
device_speed: SplitSpeed,
}
impl SplitInfo {
pub const fn new(hub_addr: u8, port: u8, device_speed: SplitSpeed) -> Self {
Self {
hub_addr,
port,
device_speed,
}
}
pub const fn hub_addr(self) -> u8 {
self.hub_addr
}
pub const fn port(self) -> u8 {
self.port
}
pub const fn device_speed(self) -> SplitSpeed {
self.device_speed
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum PipeError {
BufferOverflow,
BadResponse,
Babble,
DataToggleError,
Canceled,
Stall,
Timeout,
Disconnected,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum DeviceEvent {
Connected(Speed),
Disconnected,
Overcurrent,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum HostError {
PipeError(PipeError),
RequestFailed,
InvalidDescriptor,
OutOfSlots,
OutOfPipes,
NoSuchDevice,
InsufficientMemory,
Other(&'static str),
}
impl From<PipeError> for HostError {
fn from(value: PipeError) -> Self {
HostError::PipeError(value)
}
}
pub trait UsbHostAllocator<'d>: Sized + Clone {
type Pipe<T: pipe::Type, D: pipe::Direction>: UsbPipe<T, D> + 'd;
fn alloc_pipe<T: pipe::Type, D: pipe::Direction>(
&self,
addr: u8,
endpoint: &EndpointInfo,
split: Option<SplitInfo>,
) -> Result<Self::Pipe<T, D>, HostError>;
}
pub trait UsbHostController<'d>: Sized {
type Allocator: UsbHostAllocator<'d>;
fn allocator(&self) -> Self::Allocator;
async fn wait_for_device_event(&mut self) -> DeviceEvent;
async fn bus_reset(&mut self);
}
pub mod pipe {
use super::EndpointType;
mod sealed {
pub trait Sealed {}
}
pub trait Type: sealed::Sealed + 'static {
fn ep_type() -> EndpointType;
}
pub struct Control {}
pub struct Interrupt {}
pub struct Bulk {}
pub struct Isochronous {}
impl sealed::Sealed for Control {}
impl sealed::Sealed for Interrupt {}
impl sealed::Sealed for Bulk {}
impl sealed::Sealed for Isochronous {}
impl Type for Control {
fn ep_type() -> EndpointType {
EndpointType::Control
}
}
impl Type for Interrupt {
fn ep_type() -> EndpointType {
EndpointType::Interrupt
}
}
impl Type for Bulk {
fn ep_type() -> EndpointType {
EndpointType::Bulk
}
}
impl Type for Isochronous {
fn ep_type() -> EndpointType {
EndpointType::Isochronous
}
}
#[diagnostic::on_unimplemented(message = "This is not a CONTROL pipe")]
pub trait IsControl: Type {}
impl IsControl for Control {}
#[diagnostic::on_unimplemented(message = "This is not an INTERRUPT pipe")]
pub trait IsInterrupt: Type {}
impl IsInterrupt for Interrupt {}
#[diagnostic::on_unimplemented(message = "This is not a BULK or INTERRUPT pipe")]
pub trait IsBulkOrInterrupt: Type {}
impl IsBulkOrInterrupt for Bulk {}
impl IsBulkOrInterrupt for Interrupt {}
pub trait Direction: sealed::Sealed + 'static {
fn is_in() -> bool;
fn is_out() -> bool;
}
pub struct In {}
pub struct Out {}
pub struct InOut {}
impl sealed::Sealed for In {}
impl sealed::Sealed for Out {}
impl sealed::Sealed for InOut {}
impl Direction for In {
fn is_in() -> bool {
true
}
fn is_out() -> bool {
false
}
}
impl Direction for Out {
fn is_in() -> bool {
false
}
fn is_out() -> bool {
true
}
}
impl Direction for InOut {
fn is_in() -> bool {
true
}
fn is_out() -> bool {
true
}
}
#[diagnostic::on_unimplemented(message = "This is not an IN pipe")]
pub trait IsIn: Direction {}
impl IsIn for In {}
impl IsIn for InOut {}
#[diagnostic::on_unimplemented(message = "This is not an OUT pipe")]
pub trait IsOut: Direction {}
impl IsOut for Out {}
impl IsOut for InOut {}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct TimeoutConfig {
pub data_timeout: Duration,
pub no_data_timeout: Duration,
}
impl Default for TimeoutConfig {
fn default() -> Self {
TimeoutConfig {
data_timeout: Duration::from_millis(500),
no_data_timeout: Duration::from_millis(50),
}
}
}
pub trait UsbPipe<T: pipe::Type, D: pipe::Direction> {
async fn control_in(&mut self, setup: &[u8; 8], buf: &mut [u8]) -> Result<usize, PipeError>
where
T: pipe::IsControl,
D: pipe::IsIn;
async fn control_out(&mut self, setup: &[u8; 8], buf: &[u8]) -> Result<(), PipeError>
where
T: pipe::IsControl,
D: pipe::IsOut;
async fn request_in(&mut self, buf: &mut [u8]) -> Result<usize, PipeError>
where
D: pipe::IsIn;
async fn request_out(&mut self, buf: &[u8], ensure_transaction_end: bool) -> Result<(), PipeError>
where
D: pipe::IsOut;
fn set_timeout(&mut self, timeout: TimeoutConfig)
where
T: pipe::IsControl;
fn reset_data_toggle(&mut self)
where
T: pipe::IsBulkOrInterrupt;
}