rusb/
endpoint_descriptor.rs

1use std::{fmt, slice};
2
3use libusb1_sys::{constants::*, libusb_endpoint_descriptor};
4
5use crate::fields::{Direction, SyncType, TransferType, UsageType};
6
7/// Describes an endpoint.
8pub struct EndpointDescriptor<'a> {
9    descriptor: &'a libusb_endpoint_descriptor,
10}
11
12impl<'a> EndpointDescriptor<'a> {
13    /// Returns the size of the descriptor in bytes
14    pub fn length(&self) -> u8 {
15        self.descriptor.bLength
16    }
17
18    /// Returns the descriptor type
19    pub fn descriptor_type(&self) -> u8 {
20        self.descriptor.bDescriptorType
21    }
22
23    /// Returns the endpoint's address.
24    pub fn address(&self) -> u8 {
25        self.descriptor.bEndpointAddress
26    }
27
28    /// Returns the endpoint number.
29    pub fn number(&self) -> u8 {
30        self.descriptor.bEndpointAddress & 0x07
31    }
32
33    /// Returns the endpoint's direction.
34    pub fn direction(&self) -> Direction {
35        match self.descriptor.bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK {
36            LIBUSB_ENDPOINT_OUT => Direction::Out,
37            LIBUSB_ENDPOINT_IN | _ => Direction::In,
38        }
39    }
40
41    /// Returns the endpoint's transfer type.
42    pub fn transfer_type(&self) -> TransferType {
43        match self.descriptor.bmAttributes & LIBUSB_TRANSFER_TYPE_MASK {
44            LIBUSB_TRANSFER_TYPE_CONTROL => TransferType::Control,
45            LIBUSB_TRANSFER_TYPE_ISOCHRONOUS => TransferType::Isochronous,
46            LIBUSB_TRANSFER_TYPE_BULK => TransferType::Bulk,
47            LIBUSB_TRANSFER_TYPE_INTERRUPT | _ => TransferType::Interrupt,
48        }
49    }
50
51    /// Returns the endpoint's synchronisation mode.
52    ///
53    /// The return value of this method is only valid for isochronous endpoints.
54    pub fn sync_type(&self) -> SyncType {
55        match (self.descriptor.bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) >> 2 {
56            LIBUSB_ISO_SYNC_TYPE_NONE => SyncType::NoSync,
57            LIBUSB_ISO_SYNC_TYPE_ASYNC => SyncType::Asynchronous,
58            LIBUSB_ISO_SYNC_TYPE_ADAPTIVE => SyncType::Adaptive,
59            LIBUSB_ISO_SYNC_TYPE_SYNC | _ => SyncType::Synchronous,
60        }
61    }
62
63    /// Returns the endpoint's usage type.
64    ///
65    /// The return value of this method is only valid for isochronous endpoints.
66    pub fn usage_type(&self) -> UsageType {
67        match (self.descriptor.bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) >> 4 {
68            LIBUSB_ISO_USAGE_TYPE_DATA => UsageType::Data,
69            LIBUSB_ISO_USAGE_TYPE_FEEDBACK => UsageType::Feedback,
70            LIBUSB_ISO_USAGE_TYPE_IMPLICIT => UsageType::FeedbackData,
71            _ => UsageType::Reserved,
72        }
73    }
74
75    /// Returns the endpoint's maximum packet size.
76    pub fn max_packet_size(&self) -> u16 {
77        self.descriptor.wMaxPacketSize
78    }
79
80    /// Returns the endpoint's polling interval.
81    pub fn interval(&self) -> u8 {
82        self.descriptor.bInterval
83    }
84
85    /// Returns the unknown 'extra' bytes that libusb does not understand.
86    pub fn extra(&'a self) -> Option<&'a [u8]> {
87        unsafe {
88            match (*self.descriptor).extra_length {
89                len if len > 0 => Some(slice::from_raw_parts(
90                    (*self.descriptor).extra,
91                    len as usize,
92                )),
93                _ => None,
94            }
95        }
96    }
97
98    /// For audio devices only: return the rate at which synchronization feedback is provided.
99    pub fn refresh(&self) -> u8 {
100        self.descriptor.bRefresh
101    }
102
103    /// For audio devices only: return the address if the synch endpoint.
104    pub fn synch_address(&self) -> u8 {
105        self.descriptor.bSynchAddress
106    }
107}
108
109impl<'a> fmt::Debug for EndpointDescriptor<'a> {
110    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
111        let mut debug = fmt.debug_struct("EndpointDescriptor");
112
113        debug.field("bLength", &self.descriptor.bLength);
114        debug.field("bDescriptorType", &self.descriptor.bDescriptorType);
115        debug.field("bEndpointAddress", &self.descriptor.bEndpointAddress);
116        debug.field("bmAttributes", &self.descriptor.bmAttributes);
117        debug.field("wMaxPacketSize", &self.descriptor.wMaxPacketSize);
118        debug.field("bInterval", &self.descriptor.bInterval);
119
120        debug.finish()
121    }
122}
123
124#[doc(hidden)]
125pub(crate) fn from_libusb(endpoint: &libusb_endpoint_descriptor) -> EndpointDescriptor {
126    EndpointDescriptor {
127        descriptor: endpoint,
128    }
129}
130
131#[cfg(test)]
132mod test {
133    use crate::fields::{Direction, SyncType, TransferType, UsageType};
134
135    #[test]
136    fn it_interprets_number_for_output_endpoints() {
137        assert_eq!(
138            0,
139            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b0000_0000)).number()
140        );
141        assert_eq!(
142            1,
143            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b0000_0001)).number()
144        );
145    }
146
147    #[test]
148    fn it_interprets_number_for_input_endpoints() {
149        assert_eq!(
150            2,
151            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b1000_0010)).number()
152        );
153        assert_eq!(
154            3,
155            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b1000_0011)).number()
156        );
157    }
158
159    #[test]
160    fn it_ignores_reserved_bits_in_address() {
161        assert_eq!(
162            0,
163            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b0000_1000)).number()
164        );
165        assert_eq!(
166            0,
167            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b0001_0000)).number()
168        );
169        assert_eq!(
170            0,
171            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b0010_0000)).number()
172        );
173        assert_eq!(
174            0,
175            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b0100_0000)).number()
176        );
177        assert_eq!(
178            7,
179            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b1111_1111)).number()
180        );
181    }
182
183    #[test]
184    fn it_interprets_direction_bit_in_address() {
185        assert_eq!(
186            Direction::Out,
187            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b0000_0000)).direction()
188        );
189        assert_eq!(
190            Direction::In,
191            super::from_libusb(&endpoint_descriptor!(bEndpointAddress: 0b1000_0000)).direction()
192        );
193    }
194
195    #[test]
196    fn it_interprets_transfer_type_in_attributes() {
197        assert_eq!(
198            TransferType::Control,
199            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0000_0000)).transfer_type()
200        );
201        assert_eq!(
202            TransferType::Isochronous,
203            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0000_0001)).transfer_type()
204        );
205        assert_eq!(
206            TransferType::Bulk,
207            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0000_0010)).transfer_type()
208        );
209        assert_eq!(
210            TransferType::Interrupt,
211            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0000_0011)).transfer_type()
212        );
213    }
214
215    #[test]
216    fn it_interprets_synchronization_type_in_attributes() {
217        assert_eq!(
218            SyncType::NoSync,
219            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0000_0001)).sync_type()
220        );
221        assert_eq!(
222            SyncType::Asynchronous,
223            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0000_0101)).sync_type()
224        );
225        assert_eq!(
226            SyncType::Adaptive,
227            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0000_1001)).sync_type()
228        );
229        assert_eq!(
230            SyncType::Synchronous,
231            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0000_1101)).sync_type()
232        );
233    }
234
235    #[test]
236    fn it_interprets_usage_type_in_attributes() {
237        assert_eq!(
238            UsageType::Data,
239            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0000_0001)).usage_type()
240        );
241        assert_eq!(
242            UsageType::Feedback,
243            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0001_0001)).usage_type()
244        );
245        assert_eq!(
246            UsageType::FeedbackData,
247            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0010_0001)).usage_type()
248        );
249        assert_eq!(
250            UsageType::Reserved,
251            super::from_libusb(&endpoint_descriptor!(bmAttributes: 0b0011_0001)).usage_type()
252        );
253    }
254
255    #[test]
256    fn it_has_max_packet_size() {
257        assert_eq!(
258            64,
259            super::from_libusb(&endpoint_descriptor!(wMaxPacketSize: 64)).max_packet_size()
260        );
261        assert_eq!(
262            4096,
263            super::from_libusb(&endpoint_descriptor!(wMaxPacketSize: 4096)).max_packet_size()
264        );
265        assert_eq!(
266            65535,
267            super::from_libusb(&endpoint_descriptor!(wMaxPacketSize: 65535)).max_packet_size()
268        );
269    }
270
271    #[test]
272    fn it_has_interval() {
273        assert_eq!(
274            1,
275            super::from_libusb(&endpoint_descriptor!(bInterval: 1)).interval()
276        );
277        assert_eq!(
278            20,
279            super::from_libusb(&endpoint_descriptor!(bInterval: 20)).interval()
280        );
281        assert_eq!(
282            255,
283            super::from_libusb(&endpoint_descriptor!(bInterval: 255)).interval()
284        );
285    }
286}