use alloc::vec::Vec;
pub mod kind {
pub const DEVICE: u8 = 1;
pub const CONFIGURATION: u8 = 2;
pub const STRING: u8 = 3;
pub const INTERFACE: u8 = 4;
pub const ENDPOINT: u8 = 5;
pub const DEVICE_QUALIFIER: u8 = 6;
pub const OTHER_SPEED_CONFIGURATION: u8 = 7;
pub const INTERFACE_POWER: u8 = 8;
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DescriptorKind(pub u8);
impl DescriptorKind {
pub const DEVICE: DescriptorKind = DescriptorKind(kind::DEVICE);
pub const CONFIGURATION: DescriptorKind = DescriptorKind(kind::CONFIGURATION);
pub const STRING: DescriptorKind = DescriptorKind(kind::STRING);
pub const DEVICE_QUALIFIER: DescriptorKind = DescriptorKind(kind::DEVICE_QUALIFIER);
#[must_use]
pub const fn is_standard(self) -> bool {
self.0 >= 1 && self.0 <= kind::INTERFACE_POWER
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DeviceDescriptor {
pub usb: u16,
pub class: u8,
pub subclass: u8,
pub protocol: u8,
pub max_packet0: u8,
pub vendor: u16,
pub product: u16,
pub device: u16,
pub manufacturer: u8,
pub product_name: u8,
pub serial: u8,
pub configurations: u8,
}
impl DeviceDescriptor {
pub const SIZE: u8 = 18;
#[must_use]
pub fn encode(&self) -> [u8; 18] {
let usb = self.usb.to_le_bytes();
let vendor = self.vendor.to_le_bytes();
let product = self.product.to_le_bytes();
let device = self.device.to_le_bytes();
[
DeviceDescriptor::SIZE,
kind::DEVICE,
usb[0],
usb[1],
self.class,
self.subclass,
self.protocol,
self.max_packet0,
vendor[0],
vendor[1],
product[0],
product[1],
device[0],
device[1],
self.manufacturer,
self.product_name,
self.serial,
self.configurations,
]
}
}
impl Default for DeviceDescriptor {
fn default() -> DeviceDescriptor {
DeviceDescriptor {
usb: 0x0200,
class: 0,
subclass: 0,
protocol: 0,
max_packet0: 64,
vendor: 0,
product: 0,
device: 0x0100,
manufacturer: 0,
product_name: 0,
serial: 0,
configurations: 1,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConfigurationDescriptor {
pub interfaces: u8,
pub value: u8,
pub name: u8,
pub attributes: u8,
pub max_power: u8,
}
impl ConfigurationDescriptor {
pub const SIZE: u8 = 9;
pub const RESERVED: u8 = 0x80;
pub const SELF_POWERED: u8 = 0x40;
pub const REMOTE_WAKEUP: u8 = 0x20;
#[must_use]
pub fn encode(&self, total: u16) -> [u8; 9] {
let total = total.to_le_bytes();
[
ConfigurationDescriptor::SIZE,
kind::CONFIGURATION,
total[0],
total[1],
self.interfaces,
self.value,
self.name,
self.attributes | ConfigurationDescriptor::RESERVED,
self.max_power,
]
}
}
impl Default for ConfigurationDescriptor {
fn default() -> ConfigurationDescriptor {
ConfigurationDescriptor {
interfaces: 1,
value: 1,
name: 0,
attributes: ConfigurationDescriptor::RESERVED,
max_power: 50,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct InterfaceDescriptor {
pub number: u8,
pub alternate: u8,
pub endpoints: u8,
pub class: u8,
pub subclass: u8,
pub protocol: u8,
pub name: u8,
}
impl InterfaceDescriptor {
pub const SIZE: u8 = 9;
#[must_use]
pub fn encode(&self) -> [u8; 9] {
[
InterfaceDescriptor::SIZE,
kind::INTERFACE,
self.number,
self.alternate,
self.endpoints,
self.class,
self.subclass,
self.protocol,
self.name,
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct EndpointDescriptor {
pub address: u8,
pub attributes: u8,
pub max_packet: u16,
pub interval: u8,
}
impl EndpointDescriptor {
pub const SIZE: u8 = 7;
#[must_use]
pub fn encode(&self) -> [u8; 7] {
let max = self.max_packet.to_le_bytes();
[
EndpointDescriptor::SIZE,
kind::ENDPOINT,
self.address,
self.attributes,
max[0],
max[1],
self.interval,
]
}
}
#[must_use]
pub fn string_descriptor(text: &str) -> Vec<u8> {
let units: Vec<u16> = text.encode_utf16().take(126).collect();
let mut out = Vec::with_capacity(2 + units.len() * 2);
out.push((2 + units.len() * 2) as u8);
out.push(kind::STRING);
for unit in units {
out.extend_from_slice(&unit.to_le_bytes());
}
out
}
#[must_use]
pub fn language_descriptor(languages: &[u16]) -> Vec<u8> {
let mut out = Vec::with_capacity(2 + languages.len() * 2);
out.push((2 + languages.len() * 2) as u8);
out.push(kind::STRING);
for language in languages {
out.extend_from_slice(&language.to_le_bytes());
}
out
}
#[derive(Debug, Clone, Default)]
pub struct Descriptors {
device: Vec<u8>,
configurations: Vec<Vec<u8>>,
strings: Vec<Vec<u8>>,
qualifier: Option<Vec<u8>>,
}
impl Descriptors {
#[must_use]
pub fn new() -> Descriptors {
Descriptors::default()
}
pub fn set_device(&mut self, descriptor: &DeviceDescriptor) {
self.device = descriptor.encode().to_vec();
}
#[must_use]
pub fn with_device(mut self, descriptor: &DeviceDescriptor) -> Descriptors {
self.set_device(descriptor);
self
}
pub fn add_configuration(&mut self, descriptor: &ConfigurationDescriptor, body: &[u8]) {
let total = (usize::from(ConfigurationDescriptor::SIZE) + body.len()).min(0xffff) as u16;
let mut bytes = descriptor.encode(total).to_vec();
bytes.extend_from_slice(body);
self.configurations.push(bytes);
}
#[must_use]
pub fn configuration(
mut self,
descriptor: &ConfigurationDescriptor,
body: &[u8],
) -> Descriptors {
self.add_configuration(descriptor, body);
self
}
pub fn add_string(&mut self, text: &str) -> u8 {
if self.strings.is_empty() {
self.strings.push(language_descriptor(&[0x0409]));
}
self.strings.push(string_descriptor(text));
(self.strings.len() - 1).min(255) as u8
}
pub fn set_qualifier(&mut self, device: &DeviceDescriptor, other_configurations: u8) {
let usb = device.usb.to_le_bytes();
self.qualifier = Some(alloc::vec![
10,
kind::DEVICE_QUALIFIER,
usb[0],
usb[1],
device.class,
device.subclass,
device.protocol,
device.max_packet0,
other_configurations,
0,
]);
}
#[must_use]
pub fn device(&self) -> &[u8] {
&self.device
}
#[must_use]
pub fn configuration_count(&self) -> usize {
self.configurations.len()
}
#[must_use]
pub fn get(&self, kind: DescriptorKind, index: u8) -> Option<&[u8]> {
match kind {
DescriptorKind::DEVICE if index == 0 => {
(!self.device.is_empty()).then_some(self.device.as_slice())
}
DescriptorKind::CONFIGURATION => self
.configurations
.get(usize::from(index))
.map(Vec::as_slice),
DescriptorKind::STRING => self.strings.get(usize::from(index)).map(Vec::as_slice),
DescriptorKind::DEVICE_QUALIFIER if index == 0 => self.qualifier.as_deref(),
_ => None,
}
}
#[must_use]
pub fn configuration_value(&self, index: usize) -> Option<u8> {
self.configurations
.get(index)
.and_then(|c| c.get(5))
.copied()
}
#[must_use]
pub fn has_configuration_value(&self, value: u8) -> bool {
(0..self.configurations.len()).any(|i| self.configuration_value(i) == Some(value))
}
#[must_use]
pub fn attributes_of(&self, value: u8) -> Option<u8> {
(0..self.configurations.len())
.find(|i| self.configuration_value(*i) == Some(value))
.and_then(|i| self.configurations[i].get(7))
.copied()
}
}