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