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