#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![deny(missing_docs)]
#![no_std]
use core::num::NonZeroU8;
use crate::{
bmrequesttype::{bmRequestType, Recipient},
cdc::acm,
};
#[macro_use]
mod macros;
mod bmrequesttype;
mod brequest;
pub mod cdc;
pub mod configuration;
mod desc;
pub mod device;
pub mod endpoint;
mod feature;
pub mod hid;
pub mod ia;
pub mod interface;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum State {
Default,
Address(Address),
Configured {
address: Address,
value: NonZeroU8,
},
}
pub type Address = NonZeroU8;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Endpoint {
pub direction: Direction,
pub number: u8,
}
impl Endpoint {
fn byte(&self) -> u8 {
(self.number & 0b1111) | (self.direction as u8) << 7
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Direction {
Out = 0,
In = 1,
}
#[derive(Debug, PartialEq)]
pub enum Request {
Standard(StandardRequest),
Acm(acm::Request),
Hid(hid::Request),
}
impl Request {
pub fn parse(
bmrequesttype: u8,
brequest: u8,
wvalue: u16,
windex: u16,
wlength: u16,
) -> Result<Self, ()> {
use bmrequesttype::Type;
let bmrequesttype = bmRequestType::parse(bmrequesttype)?;
match bmrequesttype.ty {
Type::Standard => {
StandardRequest::parse2(bmrequesttype, brequest, wvalue, windex, wlength)
.map(Request::Standard)
.or_else(|_| {
hid::Request::parse2(bmrequesttype, brequest, wvalue, windex, wlength)
.map(Request::Hid)
})
}
Type::Class => acm::Request::parse2(bmrequesttype, brequest, wvalue, windex, wlength)
.map(Request::Acm)
.or_else(|_| {
hid::Request::parse2(bmrequesttype, brequest, wvalue, windex, wlength)
.map(Request::Hid)
}),
_ => Err(()),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StandardRequest {
ClearFeature(ClearFeature),
GetConfiguration,
GetDescriptor {
descriptor: GetDescriptor,
length: u16,
},
GetInterface {
interface: u8,
},
GetStatus(GetStatus),
SetAddress {
address: Option<Address>,
},
SetConfiguration {
value: Option<NonZeroU8>,
},
SetDescriptor {
descriptor: SetDescriptor,
length: u16,
},
SetFeature(SetFeature),
SetInterface {
interface: u8,
alternate: u8,
},
SynchFrame {
endpoint: Endpoint,
},
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum GetDescriptor {
Configuration {
index: u8,
},
Device,
DeviceQualifier,
OtherSpeedConfiguration {
index: u8,
},
String {
index: u8,
lang_id: u16,
},
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SetDescriptor {
Configuration {
index: u8,
},
Device,
String {
index: u8,
lang_id: u16,
},
}
const MAX_ADDRESS: u16 = 127;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ClearFeature {
DeviceRemoteWakeup,
EndpointHalt(Endpoint),
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum GetStatus {
Device,
Endpoint(Endpoint),
Interface(u8),
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SetFeature {
DeviceRemoteWakeup,
EndpointHalt(Endpoint),
TestMode(Test),
}
repr!(u8,
Test {
J = 0x01,
K = 0x02,
SE0_NAK = 0x03,
Packet = 0x04,
ForceEnable = 0x05,
});
impl StandardRequest {
pub fn parse(
bmrequesttype: u8,
brequest: u8,
wvalue: u16,
windex: u16,
wlength: u16,
) -> Result<Self, ()> {
let bmrequesttype = bmRequestType::parse(bmrequesttype)?;
if bmrequesttype.ty != bmrequesttype::Type::Standard {
return Err(());
}
Self::parse2(bmrequesttype, brequest, wvalue, windex, wlength)
}
fn parse2(
bmRequestType {
direction,
recipient,
..
}: bmRequestType,
brequest: u8,
wvalue: u16,
windex: u16,
wlength: u16,
) -> Result<Self, ()> {
match (brequest, direction) {
(brequest::CLEAR_FEATURE, bmrequesttype::Direction::HostToDevice)
if recipient != Recipient::Other && wlength == 0 =>
{
if wvalue == feature::DEVICE_REMOTE_WAKEUP
&& recipient == Recipient::Device
&& windex == 0
{
Ok(StandardRequest::ClearFeature(
ClearFeature::DeviceRemoteWakeup,
))
} else if wvalue == feature::ENDPOINT_HALT && recipient == Recipient::Endpoint {
Ok(StandardRequest::ClearFeature(ClearFeature::EndpointHalt(
windex2endpoint(windex)?,
)))
} else {
Err(())
}
}
(brequest::GET_CONFIGURATION, bmrequesttype::Direction::DeviceToHost)
if recipient == Recipient::Device && wvalue == 0 && windex == 0 && wlength == 1 =>
{
Ok(StandardRequest::GetConfiguration)
}
(brequest::GET_DESCRIPTOR, bmrequesttype::Direction::DeviceToHost)
if recipient == Recipient::Device =>
{
let desc_ty = (wvalue >> 8) as u8;
let desc_idx = wvalue as u8;
let ty = desc::Type::_from(desc_ty).ok_or(())?;
let desc = match ty {
desc::Type::Device if desc_idx == 0 && windex == 0 => GetDescriptor::Device,
desc::Type::DeviceQualifier if desc_idx == 0 && windex == 0 => {
GetDescriptor::DeviceQualifier
}
desc::Type::Configuration if windex == 0 => {
GetDescriptor::Configuration { index: desc_idx }
}
desc::Type::OtherSpeedConfiguration if windex == 0 => {
GetDescriptor::OtherSpeedConfiguration { index: desc_idx }
}
desc::Type::String => GetDescriptor::String {
index: desc_idx,
lang_id: windex,
},
_ => return Err(()),
};
Ok(StandardRequest::GetDescriptor {
descriptor: desc,
length: wlength,
})
}
(brequest::GET_INTERFACE, bmrequesttype::Direction::DeviceToHost)
if recipient == Recipient::Interface && wvalue == 0 && wlength == 1 =>
{
Ok(StandardRequest::GetInterface {
interface: windex2interface(windex)?,
})
}
(brequest::GET_STATUS, bmrequesttype::Direction::DeviceToHost)
if wvalue == 0 && wlength == 2 =>
{
let status = match recipient {
Recipient::Device if windex == 0 => GetStatus::Device,
Recipient::Endpoint => GetStatus::Endpoint(windex2endpoint(windex)?),
Recipient::Interface => GetStatus::Interface(windex2interface(windex)?),
_ => return Err(()),
};
Ok(StandardRequest::GetStatus(status))
}
(brequest::SET_ADDRESS, bmrequesttype::Direction::HostToDevice)
if recipient == Recipient::Device
&& windex == 0
&& wlength == 0
&& wvalue <= MAX_ADDRESS =>
{
let address = NonZeroU8::new(wvalue as u8);
Ok(StandardRequest::SetAddress { address })
}
(brequest::SET_CONFIGURATION, bmrequesttype::Direction::HostToDevice)
if recipient == Recipient::Device
&& windex == 0
&& wlength == 0
&& wvalue >> 8 == 0 =>
{
Ok(StandardRequest::SetConfiguration {
value: NonZeroU8::new(wvalue as u8),
})
}
(brequest::SET_DESCRIPTOR, bmrequesttype::Direction::HostToDevice)
if recipient == Recipient::Device =>
{
let desc_ty = (wvalue >> 8) as u8;
let desc_idx = wvalue as u8;
let ty = desc::Type::_from(desc_ty).ok_or(())?;
let desc = match ty {
desc::Type::Device if desc_idx == 0 && windex == 0 => SetDescriptor::Device,
desc::Type::Configuration if windex == 0 => {
SetDescriptor::Configuration { index: desc_idx }
}
desc::Type::String => SetDescriptor::String {
index: desc_idx,
lang_id: windex,
},
_ => return Err(()),
};
Ok(StandardRequest::SetDescriptor {
descriptor: desc,
length: wlength,
})
}
(brequest::SET_FEATURE, bmrequesttype::Direction::HostToDevice) if wlength == 0 => {
let feature = if wvalue == feature::DEVICE_REMOTE_WAKEUP
&& recipient == Recipient::Device
&& windex == 0
{
SetFeature::DeviceRemoteWakeup
} else if wvalue == feature::TEST_MODE
&& recipient == Recipient::Device
&& windex as u8 == 0
{
SetFeature::TestMode(Test::_from((windex >> 8) as u8).ok_or(())?)
} else if wvalue == feature::ENDPOINT_HALT && recipient == Recipient::Endpoint {
SetFeature::EndpointHalt(windex2endpoint(windex)?)
} else {
return Err(());
};
Ok(StandardRequest::SetFeature(feature))
}
(brequest::SET_INTERFACE, bmrequesttype::Direction::HostToDevice)
if recipient == Recipient::Interface && wlength == 0 =>
{
let interface = windex2interface(windex)?;
let alternate = windex2interface(wvalue)?;
Ok(StandardRequest::SetInterface {
interface,
alternate,
})
}
(brequest::SYNCH_FRAME, bmrequesttype::Direction::DeviceToHost)
if recipient == Recipient::Endpoint && wvalue == 0 && wlength == 2 =>
{
Ok(StandardRequest::SynchFrame {
endpoint: windex2endpoint(windex)?,
})
}
_ => Err(()),
}
}
}
fn windex2endpoint(windex: u16) -> Result<Endpoint, ()> {
if windex >> 8 != 0 {
return Err(());
}
let windex = windex as u8;
let direction = windex >> 4;
let direction = if direction == 0b0000 {
Direction::Out
} else if direction == 0b1000 {
Direction::In
} else {
return Err(());
};
Ok(Endpoint {
direction,
number: windex & 0b1111,
})
}
fn windex2interface(windex: u16) -> Result<u8, ()> {
if windex >> 8 != 0 {
Err(())
} else {
Ok(windex as u8)
}
}
#[cfg(test)]
mod tests {
use core::num::NonZeroU8;
use crate::{Direction, Endpoint, GetDescriptor, StandardRequest};
#[test]
fn endpoint() {
assert_eq!(
crate::windex2endpoint(0x0080),
Ok(Endpoint {
direction: Direction::In,
number: 0
})
);
assert_eq!(
crate::windex2endpoint(0x0000),
Ok(Endpoint {
direction: Direction::Out,
number: 0
})
);
assert!(crate::windex2endpoint(0x0010).is_err());
assert!(crate::windex2endpoint(0x0090).is_err());
}
#[test]
fn get_descriptor_device() {
assert_eq!(
StandardRequest::parse(0b1000_0000, 0x06, 0x01_00, 0, 18),
Ok(StandardRequest::GetDescriptor {
descriptor: GetDescriptor::Device,
length: 18
})
);
assert!(StandardRequest::parse(0b1000_0000, 0x06, 0x01_01, 0, 18).is_err(),);
assert!(StandardRequest::parse(0b1000_0000, 0x06, 0x01_00, 1033, 18).is_err(),);
}
#[test]
fn get_descriptor_configuration() {
assert_eq!(
StandardRequest::parse(0b1000_0000, 0x06, 0x02_00, 0, 9),
Ok(StandardRequest::GetDescriptor {
descriptor: GetDescriptor::Configuration { index: 0 },
length: 9
})
);
assert!(StandardRequest::parse(0b1000_0000, 0x06, 0x02_00, 1033, 9).is_err());
}
#[test]
fn set_address() {
assert_eq!(
StandardRequest::parse(0b0000_0000, 0x05, 0x00_10, 0, 0),
Ok(StandardRequest::SetAddress {
address: NonZeroU8::new(16)
})
);
assert!(StandardRequest::parse(0b0000_0000, 0x05, 0x00_10, 1033, 0).is_err());
assert!(StandardRequest::parse(0b0000_0000, 0x05, 0x00_10, 0, 1).is_err());
}
#[test]
fn set_configuration() {
assert_eq!(
StandardRequest::parse(0b0000_0000, 0x09, 0x00_01, 0, 0),
Ok(StandardRequest::SetConfiguration {
value: NonZeroU8::new(1)
})
);
assert!(StandardRequest::parse(0b0000_0000, 0x09, 0x00_01, 1033, 0).is_err());
assert!(StandardRequest::parse(0b0000_0000, 0x09, 0x00_01, 0, 1).is_err());
}
}