use embassy_usb_driver::EndpointType;
use crate::CONFIGURATION_VALUE;
use crate::builder::Config;
use crate::driver::EndpointInfo;
use crate::types::{InterfaceNumber, StringIndex};
#[allow(missing_docs)]
pub mod descriptor_type {
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 IAD: u8 = 11;
pub const BOS: u8 = 15;
pub const CAPABILITY: u8 = 16;
}
pub mod lang_id {
pub const ENGLISH_US: u16 = 0x0409;
}
#[allow(missing_docs)]
pub mod capability_type {
pub const WIRELESS_USB: u8 = 1;
pub const USB_2_0_EXTENSION: u8 = 2;
pub const SS_USB_DEVICE: u8 = 3;
pub const CONTAINER_ID: u8 = 4;
pub const PLATFORM: u8 = 5;
}
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SynchronizationType {
NoSynchronization = 0b00,
Asynchronous = 0b01,
Adaptive = 0b10,
Synchronous = 0b11,
}
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum UsageType {
DataEndpoint = 0b00,
FeedbackEndpoint = 0b01,
ImplicitFeedbackDataEndpoint = 0b10,
Reserved = 0b11,
}
pub(crate) struct DescriptorWriter<'a> {
pub buf: &'a mut [u8],
position: usize,
num_interfaces_mark: Option<usize>,
num_endpoints_mark: Option<usize>,
}
impl<'a> DescriptorWriter<'a> {
pub(crate) fn new(buf: &'a mut [u8]) -> Self {
DescriptorWriter {
buf,
position: 0,
num_interfaces_mark: None,
num_endpoints_mark: None,
}
}
pub fn into_buf(self) -> &'a mut [u8] {
&mut self.buf[..self.position]
}
pub const fn position(&self) -> usize {
self.position
}
pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8], extra_fields: &[u8]) {
let descriptor_length = descriptor.len();
let extra_fields_length = extra_fields.len();
let total_length = descriptor_length + extra_fields_length;
assert!(
(self.position + 2 + total_length) <= self.buf.len() && (total_length + 2) <= 255,
"Descriptor buffer full"
);
self.buf[self.position] = (total_length + 2) as u8;
self.buf[self.position + 1] = descriptor_type;
let start = self.position + 2;
self.buf[start..start + descriptor_length].copy_from_slice(descriptor);
self.buf[start + descriptor_length..start + total_length].copy_from_slice(extra_fields);
self.position = start + total_length;
}
pub(crate) fn configuration(&mut self, config: &Config) {
self.num_interfaces_mark = Some(self.position + 4);
self.write(
descriptor_type::CONFIGURATION,
&[
0,
0, 0, CONFIGURATION_VALUE, 0, 0x80 | if config.self_powered { 0x40 } else { 0x00 }
| if config.supports_remote_wakeup { 0x20 } else { 0x00 }, (config.max_power / 2) as u8, ],
&[],
);
}
#[allow(unused)]
pub(crate) fn end_class(&mut self) {
self.num_endpoints_mark = None;
}
pub(crate) fn end_configuration(&mut self) {
let position = self.position as u16;
self.buf[2..4].copy_from_slice(&position.to_le_bytes());
}
pub fn iad(
&mut self,
first_interface: InterfaceNumber,
interface_count: u8,
function_class: u8,
function_sub_class: u8,
function_protocol: u8,
) {
self.write(
descriptor_type::IAD,
&[
first_interface.into(), interface_count, function_class,
function_sub_class,
function_protocol,
0,
],
&[],
);
}
pub fn interface_alt(
&mut self,
number: InterfaceNumber,
alternate_setting: u8,
interface_class: u8,
interface_sub_class: u8,
interface_protocol: u8,
interface_string: Option<StringIndex>,
) {
if alternate_setting == 0 {
match self.num_interfaces_mark {
Some(mark) => self.buf[mark] += 1,
None => {
panic!("you can only call `interface/interface_alt` after `configuration`.")
}
};
}
let str_index = interface_string.map_or(0, Into::into);
self.num_endpoints_mark = Some(self.position + 4);
self.write(
descriptor_type::INTERFACE,
&[
number.into(), alternate_setting, 0, interface_class, interface_sub_class, interface_protocol, str_index, ],
&[],
);
}
pub fn endpoint(
&mut self,
endpoint: &EndpointInfo,
synchronization_type: SynchronizationType,
usage_type: UsageType,
extra_fields: &[u8],
) {
match self.num_endpoints_mark {
Some(mark) => self.buf[mark] += 1,
None => panic!("you can only call `endpoint` after `interface/interface_alt`."),
};
let mut bm_attributes = endpoint.ep_type as u8;
if endpoint.ep_type != EndpointType::Isochronous {
assert_eq!(synchronization_type, SynchronizationType::NoSynchronization);
assert_eq!(usage_type, UsageType::DataEndpoint);
} else {
if usage_type == UsageType::FeedbackEndpoint {
assert_eq!(synchronization_type, SynchronizationType::NoSynchronization)
}
let synchronization_bm_attibutes: u8 = (synchronization_type as u8) << 2;
let usage_bm_attibutes: u8 = (usage_type as u8) << 4;
bm_attributes |= usage_bm_attibutes | synchronization_bm_attibutes;
}
self.write(
descriptor_type::ENDPOINT,
&[
endpoint.addr.into(), bm_attributes, endpoint.max_packet_size as u8,
(endpoint.max_packet_size >> 8) as u8, endpoint.interval_ms, ],
extra_fields,
);
}
#[allow(unused)]
pub(crate) fn string(&mut self, string: &str) {
let mut pos = self.position;
assert!(pos + 2 <= self.buf.len(), "Descriptor buffer full");
self.buf[pos] = 0; self.buf[pos + 1] = descriptor_type::STRING;
pos += 2;
for c in string.encode_utf16() {
assert!(pos < self.buf.len(), "Descriptor buffer full");
self.buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes());
pos += 2;
}
self.buf[self.position] = (pos - self.position) as u8;
self.position = pos;
}
}
pub(crate) fn device_descriptor(config: &Config) -> [u8; 18] {
[
18, 0x01, config.bcd_usb as u8,
(config.bcd_usb as u16 >> 8) as u8, config.device_class, config.device_sub_class, config.device_protocol, config.max_packet_size_0, config.vendor_id as u8,
(config.vendor_id >> 8) as u8, config.product_id as u8,
(config.product_id >> 8) as u8, config.device_release as u8,
(config.device_release >> 8) as u8, config.manufacturer.map_or(0, |_| 1), config.product.map_or(0, |_| 2), config.serial_number.map_or(0, |_| 3), 1, ]
}
pub(crate) fn device_qualifier_descriptor(config: &Config) -> [u8; 10] {
[
10, 0x06, config.bcd_usb as u8,
(config.bcd_usb as u16 >> 8) as u8, config.device_class, config.device_sub_class, config.device_protocol, config.max_packet_size_0, 1, 0, ]
}
pub struct BosWriter<'a> {
pub(crate) writer: DescriptorWriter<'a>,
num_caps_mark: Option<usize>,
}
impl<'a> BosWriter<'a> {
pub(crate) const fn new(writer: DescriptorWriter<'a>) -> Self {
Self {
writer,
num_caps_mark: None,
}
}
pub(crate) fn bos(&mut self) {
if (self.writer.buf.len() - self.writer.position) < 5 {
return;
}
self.num_caps_mark = Some(self.writer.position + 4);
self.writer.write(
descriptor_type::BOS,
&[
0x00, 0x00, 0x00, ],
&[],
);
self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]);
}
pub fn capability(&mut self, capability_type: u8, data: &[u8]) {
match self.num_caps_mark {
Some(mark) => self.writer.buf[mark] += 1,
None => panic!("called `capability` not between `bos` and `end_bos`."),
}
let mut start = self.writer.position;
let blen = data.len();
assert!(
(start + blen + 3) <= self.writer.buf.len() && (blen + 3) <= 255,
"Descriptor buffer full"
);
self.writer.buf[start] = (blen + 3) as u8;
self.writer.buf[start + 1] = descriptor_type::CAPABILITY;
self.writer.buf[start + 2] = capability_type;
start += 3;
self.writer.buf[start..start + blen].copy_from_slice(data);
self.writer.position = start + blen;
}
pub(crate) fn end_bos(&mut self) {
if self.writer.position == 0 {
return;
}
self.num_caps_mark = None;
let position = self.writer.position as u16;
self.writer.buf[2..4].copy_from_slice(&position.to_le_bytes());
}
}