use alloc::vec::Vec;
use super::{Completion, DeviceAddress, Direction, SetupPacket, Status, UsbBus};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Progress {
Moved,
Nak,
Done,
Failed(Status),
}
impl Progress {
#[must_use]
pub const fn is_finished(self) -> bool {
matches!(self, Progress::Done | Progress::Failed(_))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Stage {
Setup,
DataIn,
DataOut,
StatusIn,
StatusOut,
Finished,
}
#[derive(Debug, Clone)]
pub struct ControlTransfer {
setup: SetupPacket,
endpoint: u8,
stage: Stage,
data: Vec<u8>,
sent: usize,
failure: Option<Status>,
}
impl ControlTransfer {
#[must_use]
pub fn device_to_host(setup: SetupPacket) -> ControlTransfer {
ControlTransfer {
setup,
endpoint: 0,
stage: Stage::Setup,
data: Vec::new(),
sent: 0,
failure: None,
}
}
#[must_use]
pub fn host_to_device(setup: SetupPacket, data: &[u8]) -> ControlTransfer {
ControlTransfer {
setup,
endpoint: 0,
stage: Stage::Setup,
data: data.to_vec(),
sent: 0,
failure: None,
}
}
#[must_use]
pub fn on_endpoint(mut self, endpoint: u8) -> ControlTransfer {
self.endpoint = endpoint & 0x0f;
self
}
#[must_use]
pub fn request(&self) -> SetupPacket {
self.setup
}
#[must_use]
pub fn data(&self) -> &[u8] {
&self.data
}
#[must_use]
pub fn take_data(&mut self) -> Vec<u8> {
core::mem::take(&mut self.data)
}
#[must_use]
pub fn is_finished(&self) -> bool {
self.stage == Stage::Finished
}
#[must_use]
pub fn failure(&self) -> Option<Status> {
self.failure
}
pub fn step(&mut self, bus: &UsbBus, address: DeviceAddress, max_packet: u16) -> Progress {
let mps = usize::from(if max_packet == 0 { 8 } else { max_packet });
match self.stage {
Stage::Setup => self.do_setup(bus, address),
Stage::DataIn => self.do_data_in(bus, address, mps),
Stage::DataOut => self.do_data_out(bus, address, mps),
Stage::StatusIn => {
let completion = bus.read(address, self.endpoint, &mut []);
self.do_status(completion)
}
Stage::StatusOut => {
let completion = bus.write(address, self.endpoint, &[]);
self.do_status(completion)
}
Stage::Finished => match self.failure {
Some(status) => Progress::Failed(status),
None => Progress::Done,
},
}
}
fn do_setup(&mut self, bus: &UsbBus, address: DeviceAddress) -> Progress {
match bus.setup(address, self.endpoint, self.setup) {
Status::Ack => {
self.stage = if self.setup.length == 0 {
Stage::StatusIn
} else if self.setup.direction() == Direction::In {
Stage::DataIn
} else {
Stage::DataOut
};
Progress::Moved
}
Status::Nak => Progress::Nak,
status => self.fail(status),
}
}
fn do_data_in(&mut self, bus: &UsbBus, address: DeviceAddress, mps: usize) -> Progress {
let want = usize::from(self.setup.length).saturating_sub(self.data.len());
if want == 0 {
self.stage = Stage::StatusOut;
return Progress::Moved;
}
let mut buf = alloc::vec![0u8; mps.min(want)];
let completion = bus.read(address, self.endpoint, &mut buf);
match completion.status {
Status::Ack => {
let n = (completion.len as usize).min(buf.len());
self.data.extend_from_slice(&buf[..n]);
if n < buf.len() || self.data.len() >= usize::from(self.setup.length) {
self.stage = Stage::StatusOut;
}
Progress::Moved
}
Status::Nak => Progress::Nak,
status => self.fail(status),
}
}
fn do_data_out(&mut self, bus: &UsbBus, address: DeviceAddress, mps: usize) -> Progress {
let remaining = self.data.len().saturating_sub(self.sent);
if remaining == 0 {
self.stage = Stage::StatusIn;
return Progress::Moved;
}
let n = mps.min(remaining);
let completion = bus.write(address, self.endpoint, &self.data[self.sent..self.sent + n]);
match completion.status {
Status::Ack => {
self.sent = self.sent.saturating_add((completion.len as usize).min(n));
if self.sent >= self.data.len() {
self.stage = Stage::StatusIn;
}
Progress::Moved
}
Status::Nak => Progress::Nak,
status => self.fail(status),
}
}
fn do_status(&mut self, completion: Completion) -> Progress {
match completion.status {
Status::Ack => {
self.stage = Stage::Finished;
Progress::Done
}
Status::Nak => Progress::Nak,
status => self.fail(status),
}
}
fn fail(&mut self, status: Status) -> Progress {
self.stage = Stage::Finished;
self.failure = Some(status);
Progress::Failed(status)
}
}
#[must_use]
pub fn get_descriptor(kind: u8, index: u8, length: u16) -> SetupPacket {
SetupPacket {
request_type: Direction::BIT,
request: super::request::GET_DESCRIPTOR,
value: (u16::from(kind) << 8) | u16::from(index),
index: 0,
length,
}
}
#[must_use]
pub fn set_address(address: DeviceAddress) -> SetupPacket {
SetupPacket {
request_type: 0,
request: super::request::SET_ADDRESS,
value: u16::from(address.0),
index: 0,
length: 0,
}
}
#[must_use]
pub fn set_configuration(value: u8) -> SetupPacket {
SetupPacket {
request_type: 0,
request: super::request::SET_CONFIGURATION,
value: u16::from(value),
index: 0,
length: 0,
}
}