Skip to content

Commit

Permalink
Add enumerations and allocator for isochronous endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
ianrrees committed Aug 4, 2022
1 parent 2297008 commit cc8e7e1
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 10 deletions.
37 changes: 36 additions & 1 deletion src/bus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::endpoint::{Endpoint, EndpointAddress, EndpointDirection, EndpointType};
use crate::endpoint::{
Endpoint, EndpointAddress, EndpointDirection, EndpointType, IsochronousSynchronizationType,
IsochronousUsageType,
};
use crate::{Result, UsbDirection, UsbError};
use core::cell::RefCell;
use core::mem;
Expand Down Expand Up @@ -244,6 +247,37 @@ impl<B: UsbBus> UsbBusAllocator<B> {
.expect("alloc_ep failed")
}

/// Allocates an isochronous endpoint.
///
/// # Arguments
///
/// * `synchronization` - Type of synchronization used by the endpoint
/// * `usage` - Whether the endpoint is data, explicit feedback, or data+implicit feedback
/// * `payload_size` - Payload size in bytes.
/// * `interval` - Interval for polling, expressed in frames/microframes. Must be 1 to 16,
/// calculated as 2^(interval-1), see USB 2.0 section 9.6.6.
///
/// # Panics
///
/// Panics if endpoint allocation fails, because running out of endpoints or memory is not
/// feasibly recoverable.
#[inline]
pub fn isochronous<D: EndpointDirection>(
&self,
synchronization: IsochronousSynchronizationType,
usage: IsochronousUsageType,
payload_size: u16,
interval: u8,
) -> Endpoint<'_, B, D> {
self.alloc(
None,
EndpointType::Isochronous((synchronization, usage)),
payload_size,
interval,
)
.expect("alloc_ep failed")
}

/// Allocates a bulk endpoint.
///
/// # Arguments
Expand All @@ -263,6 +297,7 @@ impl<B: UsbBus> UsbBusAllocator<B> {
/// Allocates an interrupt endpoint.
///
/// * `max_packet_size` - Maximum packet size in bytes. Cannot exceed 64 bytes.
/// * `interval` - Polling interval.
///
/// # Panics
///
Expand Down
2 changes: 1 addition & 1 deletion src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ impl DescriptorWriter<'_> {
let mps = endpoint.max_packet_size();

buf[0] = endpoint.address().into();
buf[1] = endpoint.ep_type() as u8;
buf[1] = endpoint.ep_type().to_bm_attributes();
buf[2] = mps as u8;
buf[3] = (mps >> 8) as u8;
buf[4] = endpoint.interval();
Expand Down
64 changes: 56 additions & 8 deletions src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,69 @@ pub type EndpointOut<'a, B> = Endpoint<'a, B, Out>;
/// A device-to-host (IN) endpoint.
pub type EndpointIn<'a, B> = Endpoint<'a, B, In>;

/// 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)]
/// Isochronous transfers employ one of three synchronization schemes. See USB 2.0 spec 5.12.4.1.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum IsochronousSynchronizationType {
/// Synchronization is not implemented for this endpoint.
NoSynchronization,
/// Source and Sink sample clocks are free running.
Asynchronous,
/// Source sample clock is locked to Sink, Sink sample clock is locked to data flow.
Adaptive,
/// Source and Sink sample clocks are locked to USB SOF.
Synchronous,
}

/// Intended use of an isochronous endpoint, see USB 2.0 spec sections 5.12 and 9.6.6.
/// Associations between data and feedback endpoints are described in section 9.6.6.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum IsochronousUsageType {
/// Endpoint is used for isochronous data.
Data,
/// Feedback for synchronization.
Feedback,
/// Endpoint is data and provides implicit feedback for synchronization.
ImplicitFeedbackData,
}

/// USB endpoint transfer type.
#[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,
Control,
/// Isochronous endpoint. Used for time-critical unreliable data.
Isochronous((IsochronousSynchronizationType, IsochronousUsageType)),
/// Bulk endpoint. Used for large amounts of best-effort reliable data.
Bulk = 0b10,
Bulk,
/// Interrupt endpoint. Used for small amounts of time-critical reliable data.
Interrupt = 0b11,
Interrupt,
}

impl EndpointType {
/// Format EndpointType for use in bmAttributes transfer type field USB 2.0 spec section 9.6.6
pub fn to_bm_attributes(&self) -> u8 {
match self {
EndpointType::Control => 0b00,
EndpointType::Isochronous((sync_type, usage_type)) => {
let sync_bits = match sync_type {
IsochronousSynchronizationType::NoSynchronization => 0b00,
IsochronousSynchronizationType::Asynchronous => 0b01,
IsochronousSynchronizationType::Adaptive => 0b10,
IsochronousSynchronizationType::Synchronous => 0b11,
};
let usage_bits = match usage_type {
IsochronousUsageType::Data => 0b00,
IsochronousUsageType::Feedback => 0b01,
IsochronousUsageType::ImplicitFeedbackData => 0b10,
};
(usage_bits << 4) | (sync_bits << 2) | 0b01
}
EndpointType::Bulk => 0b10,
EndpointType::Interrupt => 0b11,
}
}
}

/// Handle for a USB endpoint. The endpoint direction is constrained by the `D` type argument, which
Expand Down

0 comments on commit cc8e7e1

Please sign in to comment.