blob: 70c4bedf50eab59d7b76e8cb9da5a28c7d7188a8 [file] [log] [blame]
use std::fmt;
use libusb1_sys::*;
use crate::fields::Version;
/// Describes a device.
pub struct DeviceDescriptor {
descriptor: libusb_device_descriptor,
}
impl DeviceDescriptor {
/// Returns the size of the descriptor in bytes
pub fn length(&self) -> u8 {
self.descriptor.bLength
}
/// Returns the descriptor type
pub fn descriptor_type(&self) -> u8 {
self.descriptor.bDescriptorType
}
/// Returns the device's maximum supported USB version.
pub fn usb_version(&self) -> Version {
Version::from_bcd(self.descriptor.bcdUSB)
}
/// Returns the manufacturer's version of the device.
pub fn device_version(&self) -> Version {
Version::from_bcd(self.descriptor.bcdDevice)
}
/// Returns the index of the string descriptor that contains the manufacturer name.
pub fn manufacturer_string_index(&self) -> Option<u8> {
match self.descriptor.iManufacturer {
0 => None,
n => Some(n),
}
}
/// Returns the index of the string descriptor that contains the product name.
pub fn product_string_index(&self) -> Option<u8> {
match self.descriptor.iProduct {
0 => None,
n => Some(n),
}
}
/// Returns the index of the string descriptor that contains the device's serial number.
pub fn serial_number_string_index(&self) -> Option<u8> {
match self.descriptor.iSerialNumber {
0 => None,
n => Some(n),
}
}
/// Returns the device's class code.
pub fn class_code(&self) -> u8 {
self.descriptor.bDeviceClass
}
/// Returns the device's sub class code.
pub fn sub_class_code(&self) -> u8 {
self.descriptor.bDeviceSubClass
}
/// Returns the device's protocol code.
pub fn protocol_code(&self) -> u8 {
self.descriptor.bDeviceProtocol
}
/// Returns the device's vendor ID.
pub fn vendor_id(&self) -> u16 {
self.descriptor.idVendor
}
/// Returns the device's product ID.
pub fn product_id(&self) -> u16 {
self.descriptor.idProduct
}
/// Returns the maximum packet size of the device's first endpoint.
pub fn max_packet_size(&self) -> u8 {
self.descriptor.bMaxPacketSize0
}
/// Returns the number of config descriptors available for the device.
pub fn num_configurations(&self) -> u8 {
self.descriptor.bNumConfigurations
}
}
impl fmt::Debug for DeviceDescriptor {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let mut debug = fmt.debug_struct("DeviceDescriptor");
debug.field("bLength", &self.descriptor.bLength);
debug.field("bDescriptorType", &self.descriptor.bDescriptorType);
debug.field("bcdUSB", &self.descriptor.bcdUSB);
debug.field("bDeviceClass", &self.descriptor.bDeviceClass);
debug.field("bDeviceSubClass", &self.descriptor.bDeviceSubClass);
debug.field("bDeviceProtocol", &self.descriptor.bDeviceProtocol);
debug.field("bMaxPacketSize", &self.descriptor.bMaxPacketSize0);
debug.field("idVendor", &self.descriptor.idVendor);
debug.field("idProduct", &self.descriptor.idProduct);
debug.field("bcdDevice", &self.descriptor.bcdDevice);
debug.field("iManufacturer", &self.descriptor.iManufacturer);
debug.field("iProduct", &self.descriptor.iProduct);
debug.field("iSerialNumber", &self.descriptor.iSerialNumber);
debug.field("bNumConfigurations", &self.descriptor.bNumConfigurations);
debug.finish()
}
}
#[doc(hidden)]
pub fn from_libusb(device: libusb_device_descriptor) -> DeviceDescriptor {
DeviceDescriptor { descriptor: device }
}
#[cfg(test)]
mod test {
use crate::fields::Version;
#[test]
fn it_has_usb_version() {
assert_eq!(
Version::from_bcd(0x1234),
super::from_libusb(device_descriptor!(bcdUSB: 0x1234)).usb_version()
);
}
#[test]
fn it_has_device_version() {
assert_eq!(
Version::from_bcd(0x1234),
super::from_libusb(device_descriptor!(bcdDevice: 0x1234)).device_version()
);
}
#[test]
fn it_has_manufacturer_string_index() {
assert_eq!(
Some(42),
super::from_libusb(device_descriptor!(iManufacturer: 42)).manufacturer_string_index()
);
}
#[test]
fn it_handles_missing_manufacturer_string_index() {
assert_eq!(
None,
super::from_libusb(device_descriptor!(iManufacturer: 0)).manufacturer_string_index()
);
}
#[test]
fn it_has_product_string_index() {
assert_eq!(
Some(42),
super::from_libusb(device_descriptor!(iProduct: 42)).product_string_index()
);
}
#[test]
fn it_handles_missing_product_string_index() {
assert_eq!(
None,
super::from_libusb(device_descriptor!(iProduct: 0)).product_string_index()
);
}
#[test]
fn it_has_serial_number_string_index() {
assert_eq!(
Some(42),
super::from_libusb(device_descriptor!(iSerialNumber: 42)).serial_number_string_index()
);
}
#[test]
fn it_handles_missing_serial_number_string_index() {
assert_eq!(
None,
super::from_libusb(device_descriptor!(iSerialNumber: 0)).serial_number_string_index()
);
}
#[test]
fn it_has_class_code() {
assert_eq!(
42,
super::from_libusb(device_descriptor!(bDeviceClass: 42)).class_code()
);
}
#[test]
fn it_has_sub_class_code() {
assert_eq!(
42,
super::from_libusb(device_descriptor!(bDeviceSubClass: 42)).sub_class_code()
);
}
#[test]
fn it_has_protocol_code() {
assert_eq!(
42,
super::from_libusb(device_descriptor!(bDeviceProtocol: 42)).protocol_code()
);
}
#[test]
fn it_has_vendor_id() {
assert_eq!(
42,
super::from_libusb(device_descriptor!(idVendor: 42)).vendor_id()
);
}
#[test]
fn it_has_product_id() {
assert_eq!(
42,
super::from_libusb(device_descriptor!(idProduct: 42)).product_id()
);
}
#[test]
fn it_has_max_packet_size() {
assert_eq!(
42,
super::from_libusb(device_descriptor!(bMaxPacketSize0: 42)).max_packet_size()
);
}
#[test]
fn it_has_num_configurations() {
assert_eq!(
3,
super::from_libusb(device_descriptor!(bNumConfigurations: 3)).num_configurations()
);
}
}