use crate::fields::{Direction, IsoSyncType, IsoUsageType, TransferType};
use libusb1_sys::{constants::*, libusb_endpoint_descriptor};
use std::{fmt, slice};
pub struct EndpointDescriptor<'a>(&'a libusb_endpoint_descriptor);
impl<'a> EndpointDescriptor<'a> {
pub fn address(&self) -> u8 {
self.0.bEndpointAddress
}
pub fn number(&self) -> u8 {
self.0.bEndpointAddress & 0x07
}
pub fn direction(&self) -> Direction {
Direction::from(self.0.bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
}
pub fn transfer_type(&self) -> TransferType {
TransferType::from(self.0.bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
}
pub fn iso_sync_type(&self) -> IsoSyncType {
IsoSyncType::from((self.0.bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) >> 2)
}
pub fn iso_usage_type(&self) -> IsoUsageType {
IsoUsageType::from((self.0.bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) >> 4)
}
pub fn max_packet_size(&self) -> u16 {
self.0.wMaxPacketSize
}
pub fn interval(&self) -> u8 {
self.0.bInterval
}
pub fn extra(&'a self) -> Option<&'a [u8]> {
unsafe {
match self.0.extra_length {
len if len > 0 => Some(slice::from_raw_parts(self.0.extra, len as usize)),
_ => None,
}
}
}
pub fn refresh(&self) -> u8 {
self.0.bRefresh
}
pub fn synch_address(&self) -> u8 {
self.0.bSynchAddress
}
}
impl<'a> fmt::Debug for EndpointDescriptor<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let mut debug = fmt.debug_struct("EndpointDescriptor");
debug.field("bLength", &self.0.bLength);
debug.field("bDescriptorType", &self.0.bDescriptorType);
debug.field("bEndpointAddress", &self.0.bEndpointAddress);
debug.field("bmAttributes", &self.0.bmAttributes);
debug.field("wMaxPacketSize", &self.0.wMaxPacketSize);
debug.field("bInterval", &self.0.bInterval);
debug.finish()
}
}
impl<'a> From<&'a libusb_endpoint_descriptor> for EndpointDescriptor<'a> {
fn from(endpoint: &'a libusb_endpoint_descriptor) -> Self {
Self(endpoint)
}
}
#[cfg(test)]
mod test {
#![allow(unused_qualifications)]
use super::*;
use crate::fields::{Direction, IsoSyncType, IsoUsageType, TransferType};
#[test]
fn it_interprets_number_for_output_endpoints() {
assert_eq!(
0,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b0000_0000)).number()
);
assert_eq!(
1,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b0000_0001)).number()
);
}
#[test]
fn it_interprets_number_for_input_endpoints() {
assert_eq!(
2,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b1000_0010)).number()
);
assert_eq!(
3,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b1000_0011)).number()
);
}
#[test]
fn it_ignores_reserved_bits_in_address() {
assert_eq!(
0,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b0000_1000)).number()
);
assert_eq!(
0,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b0001_0000)).number()
);
assert_eq!(
0,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b0010_0000)).number()
);
assert_eq!(
0,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b0100_0000)).number()
);
assert_eq!(
7,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b1111_1111)).number()
);
}
#[test]
fn it_interprets_direction_bit_in_address() {
assert_eq!(
Direction::Out,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b0000_0000))
.direction()
);
assert_eq!(
Direction::In,
EndpointDescriptor::from(&endpoint_descriptor!(bEndpointAddress: 0b1000_0000))
.direction()
);
}
#[test]
fn it_interprets_transfer_type_in_attributes() {
assert_eq!(
TransferType::Control,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0000_0000))
.transfer_type()
);
assert_eq!(
TransferType::Isochronous,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0000_0001))
.transfer_type()
);
assert_eq!(
TransferType::Bulk,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0000_0010))
.transfer_type()
);
assert_eq!(
TransferType::Interrupt,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0000_0011))
.transfer_type()
);
}
#[test]
fn it_interprets_synchronization_type_in_attributes() {
assert_eq!(
IsoSyncType::NoSync,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0000_0001))
.iso_sync_type()
);
assert_eq!(
IsoSyncType::Asynchronous,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0000_0101))
.iso_sync_type()
);
assert_eq!(
IsoSyncType::Adaptive,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0000_1001))
.iso_sync_type()
);
assert_eq!(
IsoSyncType::Synchronous,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0000_1101))
.iso_sync_type()
);
}
#[test]
fn it_interprets_usage_type_in_attributes() {
assert_eq!(
IsoUsageType::Data,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0000_0001))
.iso_usage_type()
);
assert_eq!(
IsoUsageType::Feedback,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0001_0001))
.iso_usage_type()
);
assert_eq!(
IsoUsageType::FeedbackData,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0010_0001))
.iso_usage_type()
);
assert_eq!(
IsoUsageType::Reserved,
EndpointDescriptor::from(&endpoint_descriptor!(bmAttributes: 0b0011_0001))
.iso_usage_type()
);
}
#[test]
fn it_has_max_packet_size() {
assert_eq!(
64,
EndpointDescriptor::from(&endpoint_descriptor!(wMaxPacketSize: 64)).max_packet_size()
);
assert_eq!(
4096,
EndpointDescriptor::from(&endpoint_descriptor!(wMaxPacketSize: 4096)).max_packet_size()
);
assert_eq!(
65535,
EndpointDescriptor::from(&endpoint_descriptor!(wMaxPacketSize: 65535))
.max_packet_size()
);
}
#[test]
fn it_has_interval() {
assert_eq!(
1,
EndpointDescriptor::from(&endpoint_descriptor!(bInterval: 1)).interval()
);
assert_eq!(
20,
EndpointDescriptor::from(&endpoint_descriptor!(bInterval: 20)).interval()
);
assert_eq!(
255,
EndpointDescriptor::from(&endpoint_descriptor!(bInterval: 255)).interval()
);
}
}