use crate::types::{Bcd16, TransferType};
use defmt::Format;
use usb_device::UsbDirection;
pub const TYPE_DEVICE: u8 = 1;
pub const TYPE_CONFIGURATION: u8 = 2;
pub const TYPE_STRING: u8 = 3;
pub const TYPE_INTERFACE: u8 = 4;
pub const TYPE_ENDPOINT: u8 = 5;
pub struct Descriptor<'a> {
pub length: u8,
pub descriptor_type: u8,
pub data: &'a [u8],
}
#[derive(Format)]
pub struct DeviceDescriptor {
pub usb_release: Bcd16,
pub device_class: u8,
pub device_sub_class: u8,
pub device_protocol: u8,
pub max_packet_size: u8,
pub id_vendor: u16,
pub id_product: u16,
pub device_release: Bcd16,
pub manufacturer_index: u8,
pub product_index: u8,
pub serial_number_index: u8,
pub num_configurations: u8,
}
#[derive(Format)]
pub struct ConfigurationDescriptor {
pub total_length: u16,
pub num_interfaces: u8,
pub value: u8,
pub index: u8,
pub attributes: ConfigurationAttributes,
pub max_power: u8,
}
#[derive(Clone, Copy, Format)]
pub struct ConfigurationAttributes(u8);
impl ConfigurationAttributes {
pub fn self_powered(&self) -> bool {
(self.0 >> 6) & 1 == 1
}
pub fn remote_wakeup(&self) -> bool {
(self.0 >> 5) & 1 == 1
}
}
#[derive(Format)]
pub struct InterfaceDescriptor {
pub interface_number: u8,
pub alternate_setting: u8,
pub num_endpoints: u8,
pub interface_class: u8,
pub interface_sub_class: u8,
pub interface_protocol: u8,
pub interface_index: u8,
}
#[derive(Format)]
pub struct EndpointDescriptor {
pub address: EndpointAddress,
pub attributes: EndpointAttributes,
pub max_packet_size: u16,
pub interval: u8,
}
#[derive(Clone, Copy, Format)]
pub struct EndpointAddress(u8);
impl EndpointAddress {
pub fn number(&self) -> u8 {
self.0 & 0b111
}
pub fn direction(&self) -> UsbDirection {
self.0.into()
}
}
#[derive(Clone, Copy, Format)]
pub struct EndpointAttributes(u8);
impl EndpointAttributes {
pub fn transfer_type(&self) -> TransferType {
unsafe { core::mem::transmute(self.0 & 0b11) }
}
pub fn synchronization_type(&self) -> SynchronizationType {
unsafe { core::mem::transmute((self.0 >> 2) & 0b11) }
}
pub fn usage_type(&self) -> UsageType {
unsafe { core::mem::transmute((self.0 >> 4) & 0b11) }
}
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum SynchronizationType {
NoSynchronization = 0b00,
Asynchronouse = 0b01,
Adaptive = 0b10,
Synchronous = 0b11,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum UsageType {
Data = 0b00,
Feedback = 0b01,
ImplicitFeedbackData = 0b10,
Reserved = 0b11,
}
pub mod parse {
use nom::bytes::streaming::take;
use nom::combinator::{map, verify};
use nom::number::streaming::{le_u16, u8};
use nom::sequence::tuple;
use nom::IResult;
use super::*;
pub fn any_descriptor(input: &[u8]) -> IResult<&[u8], Descriptor<'_>> {
let (input, (length, descriptor_type)) = tuple((u8, u8))(input)?;
let (input, data) = take((length - 2) as usize)(input)?;
Ok((
input,
Descriptor {
length,
descriptor_type,
data,
},
))
}
pub fn device_descriptor(input: &[u8]) -> IResult<&[u8], DeviceDescriptor> {
map(
tuple((
bcd_16, u8, u8, u8, u8, le_u16, le_u16, bcd_16, u8, u8, u8, u8,
)),
|(
usb_release,
device_class,
device_sub_class,
device_protocol,
max_packet_size,
id_vendor,
id_product,
device_release,
manufacturer_index,
product_index,
serial_number_index,
num_configurations,
)| {
DeviceDescriptor {
usb_release,
device_class,
device_sub_class,
device_protocol,
max_packet_size,
id_vendor,
id_product,
device_release,
manufacturer_index,
product_index,
serial_number_index,
num_configurations,
}
},
)(input)
}
pub fn configuration_descriptor(input: &[u8]) -> IResult<&[u8], ConfigurationDescriptor> {
map(
tuple((le_u16, u8, u8, u8, u8, u8)),
|(total_length, num_interfaces, value, index, attributes, max_power)| {
ConfigurationDescriptor {
total_length,
num_interfaces,
value,
index,
attributes: ConfigurationAttributes(attributes),
max_power,
}
},
)(input)
}
pub fn configuration_descriptor_length(input: &[u8]) -> IResult<&[u8], u16> {
le_u16(input)
}
pub fn interface_descriptor(input: &[u8]) -> IResult<&[u8], InterfaceDescriptor> {
map(
tuple((u8, u8, u8, u8, u8, u8, u8)),
|(
interface_number,
alternate_setting,
num_endpoints,
interface_class,
interface_sub_class,
interface_protocol,
interface_index,
)| {
InterfaceDescriptor {
interface_number,
alternate_setting,
num_endpoints,
interface_class,
interface_sub_class,
interface_protocol,
interface_index,
}
},
)(input)
}
pub fn endpoint_descriptor(input: &[u8]) -> IResult<&[u8], EndpointDescriptor> {
map(
tuple((u8, u8, le_u16, u8)),
|(address, attributes, max_packet_size, interval)| EndpointDescriptor {
address: EndpointAddress(address),
attributes: EndpointAttributes(attributes),
max_packet_size,
interval,
},
)(input)
}
pub fn bcd_16(input: &[u8]) -> IResult<&[u8], Bcd16> {
map(verify(le_u16, |value| Bcd16::is_valid(*value)), Bcd16)(input)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_any_descriptor() {
let data = [8, 7, 6, 5, 4, 3, 2, 1, 0];
let (rest, desc) = any_descriptor(&data).unwrap();
assert_eq!(desc.length, 8);
assert_eq!(desc.descriptor_type, 7);
assert_eq!(desc.data, &[6, 5, 4, 3, 2, 1]);
assert_eq!(rest, &[0]);
}
#[test]
fn test_bcd_16() {
let (_, Bcd16(bcd)) = bcd_16(&[0x10, 0x02]).unwrap();
assert_eq!(bcd, 0x0210);
assert!(bcd_16(&[0x00, 0x01]).is_ok());
assert!(bcd_16(&[0x00, 0x02]).is_ok());
assert!(bcd_16(&[0x00, 0x03]).is_ok());
assert!(bcd_16(&[0x00, 0x04]).is_ok());
assert!(bcd_16(&[0x00, 0x05]).is_ok());
assert!(bcd_16(&[0x00, 0x06]).is_ok());
assert!(bcd_16(&[0x00, 0x07]).is_ok());
assert!(bcd_16(&[0x00, 0x08]).is_ok());
assert!(bcd_16(&[0x00, 0x09]).is_ok());
assert!(bcd_16(&[0x00, 0x0A]).is_err());
assert!(bcd_16(&[0x00, 0x0B]).is_err());
assert!(bcd_16(&[0x00, 0x0C]).is_err());
assert!(bcd_16(&[0x00, 0x0D]).is_err());
assert!(bcd_16(&[0x00, 0x0E]).is_err());
assert!(bcd_16(&[0x00, 0x0F]).is_err());
}
}
}