use thiserror::Error;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Vid(pub u16);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Pid(pub u16);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct InterfaceClass(pub u8);
impl InterfaceClass
{
pub const APPLICATION_SPECIFIC: Self = Self(0xFE);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct InterfaceSubClass(pub u8);
impl InterfaceSubClass
{
pub const DFU: Self = Self(0x01);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct InterfaceProtocol(pub u8);
impl InterfaceProtocol
{
#[allow(dead_code)] pub const DFU_RUNTIME_MODE: Self = Self(0x01);
#[allow(dead_code)] pub const DFU_DFU_MODE: Self = Self(0x02);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[allow(dead_code)]
pub enum DfuRequest
{
Detach = 0,
Dnload = 1,
Upload = 2,
GetStatus = 3,
ClrStatus = 4,
GetState = 5,
Abort = 6,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum DfuOperatingMode
{
Runtime,
FirmwareUpgrade,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericDescriptorRef<'a>
{
pub raw: &'a [u8],
}
impl<'a> GenericDescriptorRef<'a>
{
pub fn single_from_bytes(bytes: &'a [u8]) -> Self
{
let length = bytes[0] as usize;
Self {
raw: &bytes[0..length],
}
}
pub fn multiple_from_bytes(bytes: &'a [u8]) -> Vec<Self>
{
let mut v: Vec<Self> = Vec::new();
let mut current_bytes = &bytes[0..];
loop {
let descriptor = Self::single_from_bytes(current_bytes);
let parsed_count = descriptor.length_usize();
let remaining = current_bytes.len() - parsed_count;
v.push(descriptor);
if remaining == 0 {
break;
} else if remaining > 2 {
current_bytes = ¤t_bytes[parsed_count..];
} else {
panic!("Descriptor seems to have an invalid size of {}!", remaining);
}
}
v
}
#[allow(dead_code)] pub fn length(&self) -> u8
{
self.raw[0]
}
pub fn length_usize(&self) -> usize
{
self.raw[0] as usize
}
pub fn descriptor_type(&self) -> u8
{
self.raw[1]
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Error)]
pub enum DescriptorConvertError
{
#[error(
"bLength field ({provided_length}) in provided data does not match the correct value\
({correct_length}) for this descriptor type"
)]
LengthFieldMismatch
{
provided_length: u8,
correct_length: u8,
},
#[error(
"bDescriptorType field ({provided_type}) in provided data does not match the correct\
value ({correct_type}) for this descriptor type"
)]
DescriptorTypeMismatch
{
provided_type: u8,
correct_type: u8,
},
}
#[allow(non_snake_case)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct DfuFunctionalDescriptor
{
pub bLength: u8, pub bDescriptorType: u8, pub bmAttributes: u8,
pub wDetachTimeOut: u16,
pub wTransferSize: u16,
pub bcdDFUVersion: u16,
}
impl DfuFunctionalDescriptor
{
pub const LENGTH: u8 = 0x09;
pub const TYPE: u8 = 0x21;
pub fn copy_from_bytes(bytes: &[u8; 0x09]) -> Result<Self, DescriptorConvertError>
{
if bytes[0] != Self::LENGTH {
return Err(DescriptorConvertError::LengthFieldMismatch {
provided_length: bytes[0],
correct_length: Self::LENGTH,
});
}
if bytes[1] != Self::TYPE {
return Err(DescriptorConvertError::DescriptorTypeMismatch {
provided_type: bytes[0],
correct_type: Self::TYPE,
});
}
Ok(Self {
bLength: bytes[0],
bDescriptorType: bytes[1],
bmAttributes: bytes[2],
wDetachTimeOut: u16::from_le_bytes(bytes[3..=4].try_into().unwrap()),
wTransferSize: u16::from_le_bytes(bytes[5..=6].try_into().unwrap()),
bcdDFUVersion: u16::from_le_bytes(bytes[7..=8].try_into().unwrap()),
})
}
}
pub(crate) const CHECKED_LIBUSB_VERSION: &str = "1.0.26";
#[macro_export]
macro_rules! libusb_cannot_fail
{
($funcname:literal) => {
const_format::formatcp!(
"As of libusb {}, {} cannot fail. This should be unreachable, unless libusb has updated.",
$crate::usb::CHECKED_LIBUSB_VERSION,
$funcname,
)
};
}