wip: experimental async usb stack
This commit is contained in:
160
embassy-usb/src/driver.rs
Normal file
160
embassy-usb/src/driver.rs
Normal file
@ -0,0 +1,160 @@
|
||||
use core::future::Future;
|
||||
|
||||
use super::types::*;
|
||||
|
||||
#[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))]
|
||||
|
||||
/// Operation is unsupported by the driver.
|
||||
pub struct Unsupported;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
|
||||
/// Errors returned by [`EndpointIn::write`]
|
||||
pub enum WriteError {
|
||||
/// The packet is too long to fit in the
|
||||
/// transmission buffer. This is generally an error in the class implementation, because the
|
||||
/// class shouldn't provide more data than the `max_packet_size` it specified when allocating
|
||||
/// the endpoint.
|
||||
BufferOverflow,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
|
||||
/// Errors returned by [`EndpointOut::read`]
|
||||
pub enum ReadError {
|
||||
/// The received packet is too long to
|
||||
/// fit in `buf`. This is generally an error in the class implementation, because the class
|
||||
/// should use a buffer that is large enough for the `max_packet_size` it specified when
|
||||
/// allocating the endpoint.
|
||||
BufferOverflow,
|
||||
}
|
||||
|
||||
/// Driver for a specific USB peripheral. Implement this to add support for a new hardware
|
||||
/// platform.
|
||||
pub trait Driver<'a> {
|
||||
type EndpointOut: EndpointOut + 'a;
|
||||
type EndpointIn: EndpointIn + 'a;
|
||||
type Bus: Bus + 'a;
|
||||
|
||||
/// Allocates an endpoint and specified endpoint parameters. This method is called by the device
|
||||
/// and class implementations to allocate endpoints, and can only be called before
|
||||
/// [`enable`](UsbBus::enable) is called.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `ep_addr` - A static endpoint address to allocate. If Some, the implementation should
|
||||
/// attempt to return an endpoint with the specified address. If None, the implementation
|
||||
/// should return the next available one.
|
||||
/// * `max_packet_size` - Maximum packet size in bytes.
|
||||
/// * `interval` - Polling interval parameter for interrupt endpoints.
|
||||
fn alloc_endpoint_out(
|
||||
&mut self,
|
||||
ep_addr: Option<EndpointAddress>,
|
||||
ep_type: EndpointType,
|
||||
max_packet_size: u16,
|
||||
interval: u8,
|
||||
) -> Result<Self::EndpointOut, EndpointAllocError>;
|
||||
|
||||
fn alloc_endpoint_in(
|
||||
&mut self,
|
||||
ep_addr: Option<EndpointAddress>,
|
||||
ep_type: EndpointType,
|
||||
max_packet_size: u16,
|
||||
interval: u8,
|
||||
) -> Result<Self::EndpointIn, EndpointAllocError>;
|
||||
|
||||
/// Enables and initializes the USB peripheral. Soon after enabling the device will be reset, so
|
||||
/// there is no need to perform a USB reset in this method.
|
||||
fn enable(self) -> Self::Bus;
|
||||
|
||||
/// Indicates that `set_device_address` must be called before accepting the corresponding
|
||||
/// control transfer, not after.
|
||||
///
|
||||
/// The default value for this constant is `false`, which corresponds to the USB 2.0 spec, 9.4.6
|
||||
const QUIRK_SET_ADDRESS_BEFORE_STATUS: bool = false;
|
||||
}
|
||||
|
||||
pub trait Bus {
|
||||
/// Called when the host resets the device. This will be soon called after
|
||||
/// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Reset`]. This method should
|
||||
/// reset the state of all endpoints and peripheral flags back to a state suitable for
|
||||
/// enumeration, as well as ensure that all endpoints previously allocated with alloc_ep are
|
||||
/// initialized as specified.
|
||||
fn reset(&mut self);
|
||||
|
||||
/// Sets the device USB address to `addr`.
|
||||
fn set_device_address(&mut self, addr: u8);
|
||||
|
||||
/// Sets or clears the STALL condition for an endpoint. If the endpoint is an OUT endpoint, it
|
||||
/// should be prepared to receive data again. Only used during control transfers.
|
||||
fn set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool);
|
||||
|
||||
/// Gets whether the STALL condition is set for an endpoint. Only used during control transfers.
|
||||
fn is_stalled(&mut self, ep_addr: EndpointAddress) -> bool;
|
||||
|
||||
/// Causes the USB peripheral to enter USB suspend mode, lowering power consumption and
|
||||
/// preparing to detect a USB wakeup event. This will be called after
|
||||
/// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Suspend`]. The device will
|
||||
/// continue be polled, and it shall return a value other than `Suspend` from `poll` when it no
|
||||
/// longer detects the suspend condition.
|
||||
fn suspend(&mut self);
|
||||
|
||||
/// Resumes from suspend mode. This may only be called after the peripheral has been previously
|
||||
/// suspended.
|
||||
fn resume(&mut self);
|
||||
|
||||
/// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the
|
||||
/// device.
|
||||
///
|
||||
/// The default implementation just returns `Unsupported`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// * [`Unsupported`](crate::UsbError::Unsupported) - This UsbBus implementation doesn't support
|
||||
/// simulating a disconnect or it has not been enabled at creation time.
|
||||
fn force_reset(&mut self) -> Result<(), Unsupported> {
|
||||
Err(Unsupported)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Endpoint {
|
||||
/// Get the endpoint address
|
||||
fn info(&self) -> &EndpointInfo;
|
||||
|
||||
/// Sets or clears the STALL condition for an endpoint. If the endpoint is an OUT endpoint, it
|
||||
/// should be prepared to receive data again.
|
||||
fn set_stalled(&self, stalled: bool);
|
||||
|
||||
/// Gets whether the STALL condition is set for an endpoint.
|
||||
fn is_stalled(&self) -> bool;
|
||||
|
||||
// TODO enable/disable?
|
||||
}
|
||||
|
||||
pub trait EndpointOut: Endpoint {
|
||||
type ReadFuture<'a>: Future<Output = Result<usize, ReadError>> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
/// Reads a single packet of data from the endpoint, and returns the actual length of
|
||||
/// the packet.
|
||||
///
|
||||
/// This should also clear any NAK flags and prepare the endpoint to receive the next packet.
|
||||
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a>;
|
||||
}
|
||||
|
||||
pub trait EndpointIn: Endpoint {
|
||||
type WriteFuture<'a>: Future<Output = Result<(), WriteError>> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
/// Writes a single packet of data to the endpoint.
|
||||
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a>;
|
||||
}
|
Reference in New Issue
Block a user