Skip to main content

libusb_wishbone_tool/
fields.rs

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