#![no_std]
#![allow(async_fn_in_trait)]
#![allow(unsafe_op_in_unsafe_fn)]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
pub mod host;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Speed {
Low,
Full,
High,
}
impl Speed {
pub const fn max_packet_size(self) -> u16 {
match self {
Speed::Low => 8,
Speed::Full => 64,
Speed::High => 64, }
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Direction {
Out,
In,
}
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EndpointType {
Control = 0b00,
Isochronous = 0b01,
Bulk = 0b10,
Interrupt = 0b11,
}
#[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 = 0x80;
#[inline]
pub fn from_parts(index: usize, dir: Direction) -> Self {
let dir_u8 = match dir {
Direction::Out => 0x00,
Direction::In => Self::INBITS,
};
EndpointAddress(index as u8 | dir_u8)
}
#[inline]
pub fn direction(&self) -> Direction {
if (self.0 & Self::INBITS) != 0 {
Direction::In
} else {
Direction::Out
}
}
#[inline]
pub fn is_in(&self) -> bool {
(self.0 & Self::INBITS) != 0
}
#[inline]
pub fn is_out(&self) -> bool {
(self.0 & Self::INBITS) == 0
}
#[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_ms: u8,
}
pub trait Driver<'a> {
type EndpointOut: EndpointOut + 'a;
type EndpointIn: EndpointIn + 'a;
type ControlPipe: ControlPipe + 'a;
type Bus: Bus + 'a;
fn alloc_endpoint_out(
&mut self,
ep_type: EndpointType,
ep_addr: Option<EndpointAddress>,
max_packet_size: u16,
interval_ms: u8,
) -> Result<Self::EndpointOut, EndpointAllocError>;
fn alloc_endpoint_in(
&mut self,
ep_type: EndpointType,
ep_addr: Option<EndpointAddress>,
max_packet_size: u16,
interval_ms: u8,
) -> Result<Self::EndpointIn, EndpointAllocError>;
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe);
}
pub trait Bus {
async fn enable(&mut self);
async fn disable(&mut self);
async fn poll(&mut self) -> Event;
fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool);
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool);
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool;
fn force_reset(&mut self) -> Result<(), Unsupported> {
Err(Unsupported)
}
async fn remote_wakeup(&mut self) -> Result<(), Unsupported>;
}
pub trait Endpoint {
fn info(&self) -> &EndpointInfo;
async fn wait_enabled(&mut self);
}
pub trait EndpointOut: Endpoint {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError>;
async fn read_transfer(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
let mut n = 0;
loop {
let i = self.read(&mut buf[n..]).await?;
n += i;
if i < self.info().max_packet_size as usize {
return Ok(n);
}
}
}
}
pub trait ControlPipe {
fn max_packet_size(&self) -> usize;
async fn setup(&mut self) -> [u8; 8];
async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError>;
async fn data_in(&mut self, data: &[u8], first: bool, last: bool) -> Result<(), EndpointError>;
async fn accept(&mut self);
async fn reject(&mut self);
async fn accept_set_address(&mut self, addr: u8);
}
pub trait EndpointIn: Endpoint {
async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError>;
async fn write_transfer(&mut self, buf: &[u8], needs_zlp: bool) -> Result<(), EndpointError> {
for chunk in buf.chunks(self.info().max_packet_size as usize) {
self.write(chunk).await?;
}
if needs_zlp && buf.len() % self.info().max_packet_size as usize == 0 {
self.write(&[]).await?;
}
Ok(())
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Event {
Reset,
Suspend,
Resume,
PowerDetected,
PowerRemoved,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EndpointAllocError;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Unsupported;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum EndpointError {
BufferOverflow,
Disabled,
}
impl embedded_io_async::Error for EndpointError {
fn kind(&self) -> embedded_io_async::ErrorKind {
match self {
Self::BufferOverflow => embedded_io_async::ErrorKind::OutOfMemory,
Self::Disabled => embedded_io_async::ErrorKind::NotConnected,
}
}
}
impl core::fmt::Display for EndpointError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::BufferOverflow => write!(f, "Buffer overflow"),
Self::Disabled => write!(f, "Endpoint disabled"),
}
}
}
impl core::error::Error for EndpointError {}