1 use std::fmt;
2 
3 use libusb1_sys::*;
4 
5 use crate::fields::Version;
6 
7 /// Describes a device.
8 pub struct DeviceDescriptor {
9     descriptor: libusb_device_descriptor,
10 }
11 
12 impl DeviceDescriptor {
13     /// Returns the size of the descriptor in bytes
length(&self) -> u814     pub fn length(&self) -> u8 {
15         self.descriptor.bLength
16     }
17 
18     /// Returns the descriptor type
descriptor_type(&self) -> u819     pub fn descriptor_type(&self) -> u8 {
20         self.descriptor.bDescriptorType
21     }
22 
23     /// Returns the device's maximum supported USB version.
usb_version(&self) -> Version24     pub fn usb_version(&self) -> Version {
25         Version::from_bcd(self.descriptor.bcdUSB)
26     }
27 
28     /// Returns the manufacturer's version of the device.
device_version(&self) -> Version29     pub fn device_version(&self) -> Version {
30         Version::from_bcd(self.descriptor.bcdDevice)
31     }
32 
33     /// Returns the index of the string descriptor that contains the manufacturer name.
manufacturer_string_index(&self) -> Option<u8>34     pub fn manufacturer_string_index(&self) -> Option<u8> {
35         match self.descriptor.iManufacturer {
36             0 => None,
37             n => Some(n),
38         }
39     }
40 
41     /// Returns the index of the string descriptor that contains the product name.
product_string_index(&self) -> Option<u8>42     pub fn product_string_index(&self) -> Option<u8> {
43         match self.descriptor.iProduct {
44             0 => None,
45             n => Some(n),
46         }
47     }
48 
49     /// Returns the index of the string descriptor that contains the device's serial number.
serial_number_string_index(&self) -> Option<u8>50     pub fn serial_number_string_index(&self) -> Option<u8> {
51         match self.descriptor.iSerialNumber {
52             0 => None,
53             n => Some(n),
54         }
55     }
56 
57     /// Returns the device's class code.
class_code(&self) -> u858     pub fn class_code(&self) -> u8 {
59         self.descriptor.bDeviceClass
60     }
61 
62     /// Returns the device's sub class code.
sub_class_code(&self) -> u863     pub fn sub_class_code(&self) -> u8 {
64         self.descriptor.bDeviceSubClass
65     }
66 
67     /// Returns the device's protocol code.
protocol_code(&self) -> u868     pub fn protocol_code(&self) -> u8 {
69         self.descriptor.bDeviceProtocol
70     }
71 
72     /// Returns the device's vendor ID.
vendor_id(&self) -> u1673     pub fn vendor_id(&self) -> u16 {
74         self.descriptor.idVendor
75     }
76 
77     /// Returns the device's product ID.
product_id(&self) -> u1678     pub fn product_id(&self) -> u16 {
79         self.descriptor.idProduct
80     }
81 
82     /// Returns the maximum packet size of the device's first endpoint.
max_packet_size(&self) -> u883     pub fn max_packet_size(&self) -> u8 {
84         self.descriptor.bMaxPacketSize0
85     }
86 
87     /// Returns the number of config descriptors available for the device.
num_configurations(&self) -> u888     pub fn num_configurations(&self) -> u8 {
89         self.descriptor.bNumConfigurations
90     }
91 }
92 
93 impl fmt::Debug for DeviceDescriptor {
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>94     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
95         let mut debug = fmt.debug_struct("DeviceDescriptor");
96 
97         debug.field("bLength", &self.descriptor.bLength);
98         debug.field("bDescriptorType", &self.descriptor.bDescriptorType);
99         debug.field("bcdUSB", &self.descriptor.bcdUSB);
100         debug.field("bDeviceClass", &self.descriptor.bDeviceClass);
101         debug.field("bDeviceSubClass", &self.descriptor.bDeviceSubClass);
102         debug.field("bDeviceProtocol", &self.descriptor.bDeviceProtocol);
103         debug.field("bMaxPacketSize", &self.descriptor.bMaxPacketSize0);
104         debug.field("idVendor", &self.descriptor.idVendor);
105         debug.field("idProduct", &self.descriptor.idProduct);
106         debug.field("bcdDevice", &self.descriptor.bcdDevice);
107         debug.field("iManufacturer", &self.descriptor.iManufacturer);
108         debug.field("iProduct", &self.descriptor.iProduct);
109         debug.field("iSerialNumber", &self.descriptor.iSerialNumber);
110         debug.field("bNumConfigurations", &self.descriptor.bNumConfigurations);
111 
112         debug.finish()
113     }
114 }
115 
116 #[doc(hidden)]
from_libusb(device: libusb_device_descriptor) -> DeviceDescriptor117 pub fn from_libusb(device: libusb_device_descriptor) -> DeviceDescriptor {
118     DeviceDescriptor { descriptor: device }
119 }
120 
121 #[cfg(test)]
122 mod test {
123     use crate::fields::Version;
124 
125     #[test]
it_has_usb_version()126     fn it_has_usb_version() {
127         assert_eq!(
128             Version::from_bcd(0x1234),
129             super::from_libusb(device_descriptor!(bcdUSB: 0x1234)).usb_version()
130         );
131     }
132 
133     #[test]
it_has_device_version()134     fn it_has_device_version() {
135         assert_eq!(
136             Version::from_bcd(0x1234),
137             super::from_libusb(device_descriptor!(bcdDevice: 0x1234)).device_version()
138         );
139     }
140 
141     #[test]
it_has_manufacturer_string_index()142     fn it_has_manufacturer_string_index() {
143         assert_eq!(
144             Some(42),
145             super::from_libusb(device_descriptor!(iManufacturer: 42)).manufacturer_string_index()
146         );
147     }
148 
149     #[test]
it_handles_missing_manufacturer_string_index()150     fn it_handles_missing_manufacturer_string_index() {
151         assert_eq!(
152             None,
153             super::from_libusb(device_descriptor!(iManufacturer: 0)).manufacturer_string_index()
154         );
155     }
156 
157     #[test]
it_has_product_string_index()158     fn it_has_product_string_index() {
159         assert_eq!(
160             Some(42),
161             super::from_libusb(device_descriptor!(iProduct: 42)).product_string_index()
162         );
163     }
164 
165     #[test]
it_handles_missing_product_string_index()166     fn it_handles_missing_product_string_index() {
167         assert_eq!(
168             None,
169             super::from_libusb(device_descriptor!(iProduct: 0)).product_string_index()
170         );
171     }
172 
173     #[test]
it_has_serial_number_string_index()174     fn it_has_serial_number_string_index() {
175         assert_eq!(
176             Some(42),
177             super::from_libusb(device_descriptor!(iSerialNumber: 42)).serial_number_string_index()
178         );
179     }
180 
181     #[test]
it_handles_missing_serial_number_string_index()182     fn it_handles_missing_serial_number_string_index() {
183         assert_eq!(
184             None,
185             super::from_libusb(device_descriptor!(iSerialNumber: 0)).serial_number_string_index()
186         );
187     }
188 
189     #[test]
it_has_class_code()190     fn it_has_class_code() {
191         assert_eq!(
192             42,
193             super::from_libusb(device_descriptor!(bDeviceClass: 42)).class_code()
194         );
195     }
196 
197     #[test]
it_has_sub_class_code()198     fn it_has_sub_class_code() {
199         assert_eq!(
200             42,
201             super::from_libusb(device_descriptor!(bDeviceSubClass: 42)).sub_class_code()
202         );
203     }
204 
205     #[test]
it_has_protocol_code()206     fn it_has_protocol_code() {
207         assert_eq!(
208             42,
209             super::from_libusb(device_descriptor!(bDeviceProtocol: 42)).protocol_code()
210         );
211     }
212 
213     #[test]
it_has_vendor_id()214     fn it_has_vendor_id() {
215         assert_eq!(
216             42,
217             super::from_libusb(device_descriptor!(idVendor: 42)).vendor_id()
218         );
219     }
220 
221     #[test]
it_has_product_id()222     fn it_has_product_id() {
223         assert_eq!(
224             42,
225             super::from_libusb(device_descriptor!(idProduct: 42)).product_id()
226         );
227     }
228 
229     #[test]
it_has_max_packet_size()230     fn it_has_max_packet_size() {
231         assert_eq!(
232             42,
233             super::from_libusb(device_descriptor!(bMaxPacketSize0: 42)).max_packet_size()
234         );
235     }
236 
237     #[test]
it_has_num_configurations()238     fn it_has_num_configurations() {
239         assert_eq!(
240             3,
241             super::from_libusb(device_descriptor!(bNumConfigurations: 3)).num_configurations()
242         );
243     }
244 }
245