use crate::timer::Timer;
use crate::usb::descriptor::DeviceDescriptor;
use crate::usb::dwc2::{Channel, ControlEndpoint, TransferError};
const MAX_NAK_RETRIES: u32 = 10_000;
const REQUEST_GET_STATUS: u8 = 0x00;
const REQUEST_CLEAR_FEATURE: u8 = 0x01;
const REQUEST_SET_FEATURE: u8 = 0x03;
const REQUEST_GET_DESCRIPTOR: u8 = 0x06;
const REQUEST_SET_ADDRESS: u8 = 0x05;
const REQUEST_SET_CONFIGURATION: u8 = 0x09;
const PORT_FEATURE_RESET: u16 = 4;
const PORT_FEATURE_POWER: u16 = 8;
pub const PORT_FEATURE_C_CONNECTION: u16 = 16;
pub const PORT_FEATURE_C_RESET: u16 = 20;
const DESCRIPTOR_TYPE_DEVICE: u8 = 1;
const DESCRIPTOR_TYPE_CONFIGURATION: u8 = 2;
const DESCRIPTOR_TYPE_HUB: u8 = 0x29;
const DESCRIPTOR_TYPE_HID_REPORT: u8 = 0x22;
#[derive(Clone, Copy)]
struct Setup {
request_type: u8,
request: u8,
value: u16,
index: u16,
length: u16,
}
impl Setup {
fn to_bytes(self) -> [u8; 8] {
let value = self.value.to_le_bytes();
let index = self.index.to_le_bytes();
let length = self.length.to_le_bytes();
[
self.request_type,
self.request,
value[0],
value[1],
index[0],
index[1],
length[0],
length[1],
]
}
}
fn retry_on_nak<T>(
mut attempt: impl FnMut() -> Result<T, TransferError>,
) -> Result<T, TransferError> {
for _ in 0..MAX_NAK_RETRIES {
match attempt() {
Err(TransferError::Nak) => continue,
other => return other,
}
}
Err(TransferError::NakTimeout)
}
fn control_in(
channel: &mut Channel,
timer: &Timer,
endpoint: ControlEndpoint,
setup: Setup,
buf: &mut [u8],
) -> Result<usize, TransferError> {
let setup = setup.to_bytes();
retry_on_nak(|| channel.control_setup(endpoint, &setup, timer))?;
let received = retry_on_nak(|| channel.control_data_in(endpoint, buf, timer))?;
retry_on_nak(|| channel.control_status_out(endpoint, timer))?;
Ok(received)
}
fn control_no_data(
channel: &mut Channel,
timer: &Timer,
endpoint: ControlEndpoint,
setup: Setup,
) -> Result<(), TransferError> {
let setup = setup.to_bytes();
retry_on_nak(|| channel.control_setup(endpoint, &setup, timer))?;
retry_on_nak(|| channel.control_status_in(endpoint, timer))?;
Ok(())
}
fn control_out(
channel: &mut Channel,
timer: &Timer,
endpoint: ControlEndpoint,
setup: Setup,
data: &[u8],
) -> Result<(), TransferError> {
let setup = setup.to_bytes();
retry_on_nak(|| channel.control_setup(endpoint, &setup, timer))?;
retry_on_nak(|| channel.control_data_out(endpoint, data, timer))?;
retry_on_nak(|| channel.control_status_in(endpoint, timer))?;
Ok(())
}
#[cfg(feature = "async")]
async fn retry_on_nak_async<T>(
mut attempt: impl AsyncFnMut() -> Result<T, TransferError>,
) -> Result<T, TransferError> {
for _ in 0..MAX_NAK_RETRIES {
match attempt().await {
Err(TransferError::Nak) => continue,
other => return other,
}
}
Err(TransferError::NakTimeout)
}
#[cfg(feature = "async")]
async fn control_in_async(
channel: &mut Channel<'_>,
timer: &Timer,
endpoint: ControlEndpoint,
setup: Setup,
buf: &mut [u8],
) -> Result<usize, TransferError> {
let setup = setup.to_bytes();
retry_on_nak_async(async || channel.control_setup_async(endpoint, &setup, timer).await).await?;
let received =
retry_on_nak_async(async || channel.control_data_in_async(endpoint, buf, timer).await)
.await?;
retry_on_nak_async(async || channel.control_status_out_async(endpoint, timer).await).await?;
Ok(received)
}
#[cfg(feature = "async")]
async fn control_out_async(
channel: &mut Channel<'_>,
timer: &Timer,
endpoint: ControlEndpoint,
setup: Setup,
data: &[u8],
) -> Result<(), TransferError> {
let setup = setup.to_bytes();
retry_on_nak_async(async || channel.control_setup_async(endpoint, &setup, timer).await).await?;
retry_on_nak_async(async || channel.control_data_out_async(endpoint, data, timer).await)
.await?;
retry_on_nak_async(async || channel.control_status_in_async(endpoint, timer).await).await?;
Ok(())
}
const DESCRIPTOR_TRIES: u32 = 3;
const DESCRIPTOR_RETRY_MS: u32 = 5;
fn descriptor_in(
channel: &mut Channel,
timer: &Timer,
endpoint: ControlEndpoint,
setup: Setup,
buf: &mut [u8],
) -> Result<usize, TransferError> {
let mut result = control_in(channel, timer, endpoint, setup, buf);
for _ in 1..DESCRIPTOR_TRIES {
if result.is_ok() {
break;
}
timer.delay_ms(DESCRIPTOR_RETRY_MS);
result = control_in(channel, timer, endpoint, setup, buf);
}
result
}
fn get_descriptor_setup(request_type: u8, descriptor_type: u8, index: u8, length: u16) -> Setup {
Setup {
request_type,
request: REQUEST_GET_DESCRIPTOR,
value: ((descriptor_type as u16) << 8) | index as u16,
index: 0,
length,
}
}
pub fn get_device_descriptor_header(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
) -> Result<[u8; 8], TransferError> {
let endpoint = ControlEndpoint {
max_packet_size: 8,
..device
};
let setup = get_descriptor_setup(0x80, DESCRIPTOR_TYPE_DEVICE, 0, 8);
let mut descriptor = [0u8; 8];
descriptor_in(channel, timer, endpoint, setup, &mut descriptor)?;
Ok(descriptor)
}
pub fn get_device_descriptor(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
) -> Result<[u8; 18], TransferError> {
let header = get_device_descriptor_header(channel, timer, device)?;
let endpoint = ControlEndpoint {
max_packet_size: header[7] as u16,
..device
};
let setup = get_descriptor_setup(0x80, DESCRIPTOR_TYPE_DEVICE, 0, 18);
let mut descriptor = [0u8; 18];
descriptor_in(channel, timer, endpoint, setup, &mut descriptor)?;
Ok(descriptor)
}
pub fn probe_and_address(
channel: &mut Channel,
timer: &Timer,
probe: ControlEndpoint,
new_address: u8,
) -> Result<(ControlEndpoint, DeviceDescriptor), TransferError> {
let descriptor = DeviceDescriptor::from_bytes(&get_device_descriptor(channel, timer, probe)?);
set_address(channel, timer, probe, new_address)?;
let endpoint = ControlEndpoint {
address: new_address,
max_packet_size: descriptor.max_packet_size0 as u16,
..probe
};
Ok((endpoint, descriptor))
}
const CONFIGURATION_DESCRIPTOR_HEADER_LEN: usize = 9;
pub fn get_configuration_descriptor(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
index: u8,
buf: &mut [u8],
) -> Result<usize, TransferError> {
let mut header = [0u8; CONFIGURATION_DESCRIPTOR_HEADER_LEN];
let setup = get_descriptor_setup(
0x80,
DESCRIPTOR_TYPE_CONFIGURATION,
index,
CONFIGURATION_DESCRIPTOR_HEADER_LEN as u16,
);
descriptor_in(channel, timer, device, setup, &mut header)?;
let total_length = u16::from_le_bytes([header[2], header[3]]) as usize;
let to_read = total_length.min(buf.len());
let setup = get_descriptor_setup(0x80, DESCRIPTOR_TYPE_CONFIGURATION, index, to_read as u16);
descriptor_in(channel, timer, device, setup, &mut buf[..to_read])?;
Ok(to_read)
}
pub fn get_hub_descriptor(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
buf: &mut [u8],
) -> Result<usize, TransferError> {
let setup = get_descriptor_setup(0xA0, DESCRIPTOR_TYPE_HUB, 0, buf.len() as u16);
descriptor_in(channel, timer, device, setup, buf)
}
pub fn get_report_descriptor(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
interface: u8,
buf: &mut [u8],
) -> Result<usize, TransferError> {
let mut setup = get_descriptor_setup(0x81, DESCRIPTOR_TYPE_HID_REPORT, 0, buf.len() as u16);
setup.index = interface as u16;
descriptor_in(channel, timer, device, setup, buf)
}
const SET_ADDRESS_RECOVERY_MS: u32 = 2;
pub fn set_address(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
new_address: u8,
) -> Result<(), TransferError> {
let setup = Setup {
request_type: 0x00,
request: REQUEST_SET_ADDRESS,
value: new_address as u16,
index: 0,
length: 0,
};
control_no_data(channel, timer, device, setup)?;
timer.delay_ms(SET_ADDRESS_RECOVERY_MS);
Ok(())
}
pub fn set_configuration(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
configuration_value: u8,
) -> Result<(), TransferError> {
let setup = Setup {
request_type: 0x00,
request: REQUEST_SET_CONFIGURATION,
value: configuration_value as u16,
index: 0,
length: 0,
};
control_no_data(channel, timer, device, setup)
}
pub fn vendor_in(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
request: u8,
value: u16,
index: u16,
buf: &mut [u8],
) -> Result<usize, TransferError> {
let setup = Setup {
request_type: 0xC0,
request,
value,
index,
length: buf.len() as u16,
};
control_in(channel, timer, device, setup, buf)
}
pub fn vendor_out(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
request: u8,
value: u16,
index: u16,
data: &[u8],
) -> Result<(), TransferError> {
let setup = Setup {
request_type: 0x40,
request,
value,
index,
length: data.len() as u16,
};
control_out(channel, timer, device, setup, data)
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub async fn vendor_in_async(
channel: &mut Channel<'_>,
timer: &Timer,
device: ControlEndpoint,
request: u8,
value: u16,
index: u16,
buf: &mut [u8],
) -> Result<usize, TransferError> {
let setup = Setup {
request_type: 0xC0,
request,
value,
index,
length: buf.len() as u16,
};
control_in_async(channel, timer, device, setup, buf).await
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub async fn vendor_out_async(
channel: &mut Channel<'_>,
timer: &Timer,
device: ControlEndpoint,
request: u8,
value: u16,
index: u16,
data: &[u8],
) -> Result<(), TransferError> {
let setup = Setup {
request_type: 0x40,
request,
value,
index,
length: data.len() as u16,
};
control_out_async(channel, timer, device, setup, data).await
}
pub fn set_protocol(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
interface: u8,
protocol: u8,
) -> Result<(), TransferError> {
let setup = Setup {
request_type: 0x21,
request: 0x0b,
value: protocol as u16,
index: interface as u16,
length: 0,
};
control_no_data(channel, timer, device, setup)
}
pub fn set_idle(
channel: &mut Channel,
timer: &Timer,
device: ControlEndpoint,
interface: u8,
duration: u8,
) -> Result<(), TransferError> {
let setup = Setup {
request_type: 0x21,
request: 0x0a,
value: (duration as u16) << 8,
index: interface as u16,
length: 0,
};
control_no_data(channel, timer, device, setup)
}
pub fn set_port_power(
channel: &mut Channel,
timer: &Timer,
hub_address: u8,
port: u8,
low_speed: bool,
) -> Result<(), TransferError> {
let endpoint = ControlEndpoint {
address: hub_address,
low_speed,
max_packet_size: 8,
split: None,
};
let setup = Setup {
request_type: 0x23,
request: REQUEST_SET_FEATURE,
value: PORT_FEATURE_POWER,
index: port as u16,
length: 0,
};
control_no_data(channel, timer, endpoint, setup)
}
pub fn get_port_status(
channel: &mut Channel,
timer: &Timer,
hub_address: u8,
port: u8,
low_speed: bool,
) -> Result<(u16, u16), TransferError> {
let endpoint = ControlEndpoint {
address: hub_address,
low_speed,
max_packet_size: 8,
split: None,
};
let setup = Setup {
request_type: 0xA3,
request: REQUEST_GET_STATUS,
value: 0,
index: port as u16,
length: 4,
};
let mut status = [0u8; 4];
control_in(channel, timer, endpoint, setup, &mut status)?;
Ok((
u16::from_le_bytes([status[0], status[1]]),
u16::from_le_bytes([status[2], status[3]]),
))
}
pub fn set_port_reset(
channel: &mut Channel,
timer: &Timer,
hub_address: u8,
port: u8,
low_speed: bool,
) -> Result<(), TransferError> {
let endpoint = ControlEndpoint {
address: hub_address,
low_speed,
max_packet_size: 8,
split: None,
};
let setup = Setup {
request_type: 0x23,
request: REQUEST_SET_FEATURE,
value: PORT_FEATURE_RESET,
index: port as u16,
length: 0,
};
control_no_data(channel, timer, endpoint, setup)
}
pub fn clear_port_feature(
channel: &mut Channel,
timer: &Timer,
hub_address: u8,
port: u8,
feature: u16,
low_speed: bool,
) -> Result<(), TransferError> {
let endpoint = ControlEndpoint {
address: hub_address,
low_speed,
max_packet_size: 8,
split: None,
};
let setup = Setup {
request_type: 0x23,
request: REQUEST_CLEAR_FEATURE,
value: feature,
index: port as u16,
length: 0,
};
control_no_data(channel, timer, endpoint, setup)
}