1 use libc::c_int;
2 use libusb1_sys::constants::*;
3
4 #[cfg(feature = "serde")]
5 use serde::{Deserialize, Serialize};
6
7 /// Device speeds. Indicates the speed at which a device is operating.
8 /// - [libusb_supported_speed](http://libusb.sourceforge.net/api-1.0/group__libusb__dev.html#ga1454797ecc0de4d084c1619c420014f6)
9 /// - [USB release versions](https://en.wikipedia.org/wiki/USB#Release_versions)
10 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
11 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12 #[non_exhaustive]
13 pub enum Speed {
14 /// The operating system doesn't know the device speed.
15 Unknown,
16
17 /// The device is operating at low speed (1.5 Mbps).
18 Low,
19
20 /// The device is operating at full speed (12 Mbps).
21 Full,
22
23 /// The device is operating at high speed (480 Mbps).
24 High,
25
26 /// The device is operating at super speed (5 Gbps).
27 Super,
28
29 /// The device is operating at super speed (10 Gbps).
30 SuperPlus,
31 }
32
33 #[doc(hidden)]
speed_from_libusb(n: c_int) -> Speed34 pub(crate) fn speed_from_libusb(n: c_int) -> Speed {
35 match n {
36 LIBUSB_SPEED_SUPER_PLUS => Speed::SuperPlus,
37 LIBUSB_SPEED_SUPER => Speed::Super,
38 LIBUSB_SPEED_HIGH => Speed::High,
39 LIBUSB_SPEED_FULL => Speed::Full,
40 LIBUSB_SPEED_LOW => Speed::Low,
41
42 LIBUSB_SPEED_UNKNOWN | _ => Speed::Unknown,
43 }
44 }
45
46 /// Transfer and endpoint directions.
47 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
48 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
49 pub enum Direction {
50 /// Direction for read (device to host) transfers.
51 In,
52
53 /// Direction for write (host to device) transfers.
54 Out,
55 }
56
57 /// An endpoint's transfer type.
58 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
59 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60 pub enum TransferType {
61 /// Control endpoint.
62 Control,
63
64 /// Isochronous endpoint.
65 Isochronous,
66
67 /// Bulk endpoint.
68 Bulk,
69
70 /// Interrupt endpoint.
71 Interrupt,
72 }
73
74 /// Isochronous synchronization mode.
75 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
76 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
77 pub enum SyncType {
78 /// No synchronisation.
79 NoSync,
80
81 /// Asynchronous.
82 Asynchronous,
83
84 /// Adaptive.
85 Adaptive,
86
87 /// Synchronous.
88 Synchronous,
89 }
90
91 /// Isochronous usage type.
92 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
93 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
94 pub enum UsageType {
95 /// Data endpoint.
96 Data,
97
98 /// Feedback endpoint.
99 Feedback,
100
101 /// Explicit feedback data endpoint.
102 FeedbackData,
103
104 /// Reserved.
105 Reserved,
106 }
107
108 /// Types of control transfers.
109 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
110 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
111 pub enum RequestType {
112 /// Requests that are defined by the USB standard.
113 Standard,
114
115 /// Requests that are defined by a device class, e.g., HID.
116 Class,
117
118 /// Vendor-specific requests.
119 Vendor,
120
121 /// Reserved for future use.
122 Reserved,
123 }
124
125 /// Recipients of control transfers.
126 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
127 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128 pub enum Recipient {
129 /// The recipient is a device.
130 Device,
131
132 /// The recipient is an interface.
133 Interface,
134
135 /// The recipient is an endpoint.
136 Endpoint,
137
138 /// Other.
139 Other,
140 }
141
142 /// A three-part version consisting of major, minor, and sub minor components.
143 ///
144 /// This can be used to represent versions of the format `J.M.N`, where `J` is the major version,
145 /// `M` is the minor version, and `N` is the sub minor version. A version is constructed by
146 /// providing the fields in the same order to the tuple. For example:
147 ///
148 /// ```
149 /// rusb::Version(0, 2, 1);
150 /// ```
151 ///
152 /// represents the version 0.2.1.
153 ///
154 /// The intended use case of `Version` is to extract meaning from the version fields in USB
155 /// descriptors, such as `bcdUSB` and `bcdDevice` in device descriptors.
156 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
157 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
158 pub struct Version(pub u8, pub u8, pub u8);
159
160 impl Version {
161 /// Extracts a version from a binary coded decimal (BCD) field. BCD fields exist in USB
162 /// descriptors as 16-bit integers encoding a version as `0xJJMN`, where `JJ` is the major
163 /// version, `M` is the minor version, and `N` is the sub minor version. For example, 2.0 is
164 /// encoded as `0x0200` and 1.1 is encoded as `0x0110`.
from_bcd(mut raw: u16) -> Self165 pub fn from_bcd(mut raw: u16) -> Self {
166 let sub_minor: u8 = (raw & 0x000F) as u8;
167 raw >>= 4;
168
169 let minor: u8 = (raw & 0x000F) as u8;
170 raw >>= 4;
171
172 let mut major: u8 = (raw & 0x000F) as u8;
173 raw >>= 4;
174
175 major += (10 * raw) as u8;
176
177 Version(major, minor, sub_minor)
178 }
179
180 /// Returns the major version.
major(self) -> u8181 pub fn major(self) -> u8 {
182 let Version(major, _, _) = self;
183 major
184 }
185
186 /// Returns the minor version.
minor(self) -> u8187 pub fn minor(self) -> u8 {
188 let Version(_, minor, _) = self;
189 minor
190 }
191
192 /// Returns the sub minor version.
sub_minor(self) -> u8193 pub fn sub_minor(self) -> u8 {
194 let Version(_, _, sub_minor) = self;
195 sub_minor
196 }
197 }
198
199 impl std::fmt::Display for Version {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 write!(f, "{}.{}.{}", self.major(), self.minor(), self.sub_minor())
202 }
203 }
204
205 /// Builds a value for the `bmRequestType` field of a control transfer setup packet.
206 ///
207 /// The `bmRequestType` field of a USB control transfer setup packet is a bit field specifying
208 /// three parameters, which are given to this function by corresponding enum values.
209 ///
210 /// ## Examples
211 ///
212 /// The following example returns a `bmRequestType` value for a standard inbound transfer from the
213 /// device, which could be used for reading a device's descriptors:
214 ///
215 /// ```no_run
216 /// use rusb::{Direction,RequestType,Recipient};
217 ///
218 /// rusb::request_type(Direction::In, RequestType::Standard, Recipient::Device);
219 /// ```
request_type( direction: Direction, request_type: RequestType, recipient: Recipient, ) -> u8220 pub const fn request_type(
221 direction: Direction,
222 request_type: RequestType,
223 recipient: Recipient,
224 ) -> u8 {
225 let mut value: u8 = match direction {
226 Direction::Out => LIBUSB_ENDPOINT_OUT,
227 Direction::In => LIBUSB_ENDPOINT_IN,
228 };
229
230 value |= match request_type {
231 RequestType::Standard => LIBUSB_REQUEST_TYPE_STANDARD,
232 RequestType::Class => LIBUSB_REQUEST_TYPE_CLASS,
233 RequestType::Vendor => LIBUSB_REQUEST_TYPE_VENDOR,
234 RequestType::Reserved => LIBUSB_REQUEST_TYPE_RESERVED,
235 };
236
237 value |= match recipient {
238 Recipient::Device => LIBUSB_RECIPIENT_DEVICE,
239 Recipient::Interface => LIBUSB_RECIPIENT_INTERFACE,
240 Recipient::Endpoint => LIBUSB_RECIPIENT_ENDPOINT,
241 Recipient::Other => LIBUSB_RECIPIENT_OTHER,
242 };
243
244 value
245 }
246
247 #[cfg(test)]
248 mod test {
249 use super::*;
250
251 // Version
252
253 #[test]
version_returns_major_version()254 fn version_returns_major_version() {
255 assert_eq!(1, Version(1, 0, 0).major());
256 assert_eq!(2, Version(2, 0, 0).major());
257 }
258
259 #[test]
version_returns_minor_version()260 fn version_returns_minor_version() {
261 assert_eq!(1, Version(0, 1, 0).minor());
262 assert_eq!(2, Version(0, 2, 0).minor());
263 }
264
265 #[test]
version_returns_sub_minor_version()266 fn version_returns_sub_minor_version() {
267 assert_eq!(1, Version(0, 0, 1).sub_minor());
268 assert_eq!(2, Version(0, 0, 2).sub_minor());
269 }
270
271 #[test]
version_parses_major_version()272 fn version_parses_major_version() {
273 assert_eq!(3, Version::from_bcd(0x0300).major());
274 }
275
276 #[test]
version_parses_long_major_version()277 fn version_parses_long_major_version() {
278 assert_eq!(12, Version::from_bcd(0x1200).major());
279 }
280
281 #[test]
version_parses_minor_version()282 fn version_parses_minor_version() {
283 assert_eq!(1, Version::from_bcd(0x0010).minor());
284 assert_eq!(2, Version::from_bcd(0x0020).minor());
285 }
286
287 #[test]
version_parses_sub_minor_version()288 fn version_parses_sub_minor_version() {
289 assert_eq!(1, Version::from_bcd(0x0001).sub_minor());
290 assert_eq!(2, Version::from_bcd(0x0002).sub_minor());
291 }
292
293 #[test]
version_parses_full_version()294 fn version_parses_full_version() {
295 assert_eq!(Version(12, 3, 4), Version::from_bcd(0x1234));
296 }
297
298 #[test]
version_display()299 fn version_display() {
300 assert_eq!(Version(2, 45, 13).to_string(), "2.45.13");
301 }
302
303 #[test]
version_ord()304 fn version_ord() {
305 assert!(Version(0, 0, 0) < Version(1, 2, 3));
306 assert!(Version(1, 0, 0) < Version(1, 2, 3));
307 assert!(Version(1, 2, 0) < Version(1, 2, 3));
308 assert!(Version(1, 2, 0) < Version(1, 3, 0));
309 assert!(Version(255, 255, 255) > Version(254, 0, 0));
310 assert!(Version(0, 255, 0) > Version(0, 254, 255));
311 }
312
313 // request_type for direction
314
315 #[test]
request_type_builds_value_for_out_direction()316 fn request_type_builds_value_for_out_direction() {
317 assert_eq!(
318 request_type(Direction::Out, RequestType::Standard, Recipient::Device) & 0x80,
319 0x00
320 );
321 }
322
323 #[test]
request_type_builds_value_for_in_direction()324 fn request_type_builds_value_for_in_direction() {
325 assert_eq!(
326 request_type(Direction::In, RequestType::Standard, Recipient::Device) & 0x80,
327 0x80
328 );
329 }
330
331 // request_type for request type
332
333 #[test]
request_type_builds_value_for_standard_request()334 fn request_type_builds_value_for_standard_request() {
335 assert_eq!(
336 request_type(Direction::Out, RequestType::Standard, Recipient::Device) & 0x60,
337 0x00
338 );
339 }
340
341 #[test]
request_type_builds_value_for_class_request()342 fn request_type_builds_value_for_class_request() {
343 assert_eq!(
344 request_type(Direction::Out, RequestType::Class, Recipient::Device) & 0x60,
345 0x20
346 );
347 }
348
349 #[test]
request_type_builds_value_for_vendor_request()350 fn request_type_builds_value_for_vendor_request() {
351 assert_eq!(
352 request_type(Direction::Out, RequestType::Vendor, Recipient::Device) & 0x60,
353 0x40
354 );
355 }
356
357 #[test]
request_type_builds_value_for_reserved_request()358 fn request_type_builds_value_for_reserved_request() {
359 assert_eq!(
360 request_type(Direction::Out, RequestType::Reserved, Recipient::Device) & 0x60,
361 0x60
362 );
363 }
364
365 // request_type for recipient
366
367 #[test]
request_type_builds_value_for_device_recipient()368 fn request_type_builds_value_for_device_recipient() {
369 assert_eq!(
370 request_type(Direction::Out, RequestType::Standard, Recipient::Device) & 0x0F,
371 0x00
372 );
373 }
374
375 #[test]
request_type_builds_value_for_interface_recipient()376 fn request_type_builds_value_for_interface_recipient() {
377 assert_eq!(
378 request_type(Direction::Out, RequestType::Standard, Recipient::Interface) & 0x0F,
379 0x01
380 );
381 }
382
383 #[test]
request_type_builds_value_for_endpoint_recipient()384 fn request_type_builds_value_for_endpoint_recipient() {
385 assert_eq!(
386 request_type(Direction::Out, RequestType::Standard, Recipient::Endpoint) & 0x0F,
387 0x02
388 );
389 }
390
391 #[test]
request_type_builds_value_for_other_recipient()392 fn request_type_builds_value_for_other_recipient() {
393 assert_eq!(
394 request_type(Direction::Out, RequestType::Standard, Recipient::Other) & 0x0F,
395 0x03
396 );
397 }
398 }
399