1 use std::{fmt, slice};
2 
3 use libusb1_sys::{constants::*, libusb_endpoint_descriptor};
4 
5 use crate::fields::{Direction, SyncType, TransferType, UsageType};
6 
7 /// Describes an endpoint.
8 pub struct EndpointDescriptor<'a> {
9     descriptor: &'a libusb_endpoint_descriptor,
10 }
11 
12 impl<'a> EndpointDescriptor<'a> {
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 endpoint's address.
address(&self) -> u824     pub fn address(&self) -> u8 {
25         self.descriptor.bEndpointAddress
26     }
27 
28     /// Returns the endpoint number.
number(&self) -> u829     pub fn number(&self) -> u8 {
30         self.descriptor.bEndpointAddress & 0x07
31     }
32 
33     /// Returns the endpoint's direction.
direction(&self) -> Direction34     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.
transfer_type(&self) -> TransferType42     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.
sync_type(&self) -> SyncType54     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.
usage_type(&self) -> UsageType66     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.
max_packet_size(&self) -> u1676     pub fn max_packet_size(&self) -> u16 {
77         self.descriptor.wMaxPacketSize
78     }
79 
80     /// Returns the endpoint's polling interval.
interval(&self) -> u881     pub fn interval(&self) -> u8 {
82         self.descriptor.bInterval
83     }
84 
85     /// Returns the unknown 'extra' bytes that libusb does not understand.
extra(&'a self) -> Option<&'a [u8]>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.
refresh(&self) -> u899     pub fn refresh(&self) -> u8 {
100         self.descriptor.bRefresh
101     }
102 
103     /// For audio devices only: return the address if the synch endpoint.
synch_address(&self) -> u8104     pub fn synch_address(&self) -> u8 {
105         self.descriptor.bSynchAddress
106     }
107 }
108 
109 impl<'a> fmt::Debug for EndpointDescriptor<'a> {
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>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)]
from_libusb(endpoint: &libusb_endpoint_descriptor) -> EndpointDescriptor125 pub(crate) fn from_libusb(endpoint: &libusb_endpoint_descriptor) -> EndpointDescriptor {
126     EndpointDescriptor {
127         descriptor: endpoint,
128     }
129 }
130 
131 #[cfg(test)]
132 mod test {
133     use crate::fields::{Direction, SyncType, TransferType, UsageType};
134 
135     #[test]
it_interprets_number_for_output_endpoints()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]
it_interprets_number_for_input_endpoints()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]
it_ignores_reserved_bits_in_address()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]
it_interprets_direction_bit_in_address()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]
it_interprets_transfer_type_in_attributes()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]
it_interprets_synchronization_type_in_attributes()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]
it_interprets_usage_type_in_attributes()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]
it_has_max_packet_size()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]
it_has_interval()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 }
287