1pub const U3V_INTERFACE_CLASS: u8 = 0xEF;
9pub const U3V_INTERFACE_SUBCLASS: u8 = 0x05;
11
12pub const U3V_CONTROL_SUBCLASS: u8 = 0x00;
14pub const U3V_EVENT_SUBCLASS: u8 = 0x01;
16pub const U3V_STREAM_SUBCLASS: u8 = 0x02;
18
19pub const U3V_INTERFACE_PROTOCOL: u8 = 0x00;
21
22#[derive(Debug, Clone)]
25pub struct U3vInterfaceInfo {
26 pub control_iface: u8,
28 pub control_ep_in: u8,
30 pub control_ep_out: u8,
32 pub stream_iface: Option<u8>,
34 pub stream_ep_in: Option<u8>,
36 pub event_iface: Option<u8>,
38 pub event_ep_in: Option<u8>,
40}
41
42#[cfg(feature = "usb")]
47pub fn parse_u3v_interfaces(config: &rusb::ConfigDescriptor) -> Option<U3vInterfaceInfo> {
48 let mut control_iface = None;
49 let mut control_ep_in = None;
50 let mut control_ep_out = None;
51 let mut stream_iface = None;
52 let mut stream_ep_in = None;
53 let mut event_iface = None;
54 let mut event_ep_in = None;
55
56 for interface in config.interfaces() {
57 for desc in interface.descriptors() {
58 if desc.class_code() != U3V_INTERFACE_CLASS {
59 continue;
60 }
61
62 match desc.sub_class_code() {
63 U3V_CONTROL_SUBCLASS => {
64 control_iface = Some(desc.interface_number());
65 for ep in desc.endpoint_descriptors() {
66 if ep.transfer_type() != rusb::TransferType::Bulk {
67 continue;
68 }
69 match ep.direction() {
70 rusb::Direction::In => control_ep_in = Some(ep.address()),
71 rusb::Direction::Out => control_ep_out = Some(ep.address()),
72 }
73 }
74 }
75 U3V_EVENT_SUBCLASS => {
76 event_iface = Some(desc.interface_number());
77 for ep in desc.endpoint_descriptors() {
78 if ep.transfer_type() == rusb::TransferType::Bulk
79 && ep.direction() == rusb::Direction::In
80 {
81 event_ep_in = Some(ep.address());
82 }
83 }
84 }
85 U3V_STREAM_SUBCLASS => {
86 stream_iface = Some(desc.interface_number());
87 for ep in desc.endpoint_descriptors() {
88 if ep.transfer_type() == rusb::TransferType::Bulk
89 && ep.direction() == rusb::Direction::In
90 {
91 stream_ep_in = Some(ep.address());
92 }
93 }
94 }
95 _ => {}
96 }
97 }
98 }
99
100 let control_iface = control_iface?;
101 let control_ep_in = control_ep_in?;
102 let control_ep_out = control_ep_out?;
103
104 Some(U3vInterfaceInfo {
105 control_iface,
106 control_ep_in,
107 control_ep_out,
108 stream_iface,
109 stream_ep_in,
110 event_iface,
111 event_ep_in,
112 })
113}
114
115#[cfg(feature = "usb")]
122pub fn is_likely_u3v_device(desc: &rusb::DeviceDescriptor) -> bool {
123 if desc.class_code() == 0xEF && desc.sub_class_code() == 0x02 && desc.protocol_code() == 0x01 {
125 return true;
126 }
127 desc.class_code() == 0x00
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn u3v_class_constants_are_correct() {
137 assert_eq!(U3V_INTERFACE_CLASS, 0xEF);
138 assert_eq!(U3V_CONTROL_SUBCLASS, 0x00);
139 assert_eq!(U3V_EVENT_SUBCLASS, 0x01);
140 assert_eq!(U3V_STREAM_SUBCLASS, 0x02);
141 assert_eq!(U3V_INTERFACE_PROTOCOL, 0x00);
142 assert_eq!(U3V_INTERFACE_SUBCLASS, 0x05);
143 }
144}