1
1
use rusb:: { ConfigDescriptor , Context , DeviceDescriptor , DeviceHandle , Language , UsbContext as _} ;
2
+ use std:: thread;
2
3
use std:: time:: Duration ;
4
+ use usb_device:: device:: CONFIGURATION_VALUE ;
3
5
use usb_device:: test_class;
4
6
7
+ const TEST_INTERFACE : u8 = 0 ;
8
+
5
9
pub const TIMEOUT : Duration = Duration :: from_secs ( 1 ) ;
6
10
pub const EN_US : u16 = 0x0409 ;
7
11
@@ -18,6 +22,7 @@ impl DeviceHandles {
18
22
pub fn is_high_speed ( & self ) -> bool {
19
23
self . handle . device ( ) . speed ( ) == rusb:: Speed :: High
20
24
}
25
+
21
26
/// Returns the max packet size for the `TestClass` bulk endpoint(s).
22
27
pub fn bulk_max_packet_size ( & self ) -> u16 {
23
28
self . config_descriptor
@@ -34,6 +39,40 @@ impl DeviceHandles {
34
39
. next ( )
35
40
. expect ( "TestClass has at least one bulk endpoint" )
36
41
}
42
+
43
+ /// Puts the device in a consistent state for running a test
44
+ pub fn pre_test ( & mut self ) -> rusb:: Result < ( ) > {
45
+ let res = self . reset ( ) ;
46
+ if let Err ( err) = res {
47
+ println ! ( "Failed to reset the device: {}" , err) ;
48
+ return res;
49
+ }
50
+
51
+ let res = self . set_active_configuration ( CONFIGURATION_VALUE ) ;
52
+ if let Err ( err) = res {
53
+ println ! ( "Failed to set active configuration: {}" , err) ;
54
+ return res;
55
+ }
56
+
57
+ let res = self . claim_interface ( TEST_INTERFACE ) ;
58
+ if let Err ( err) = res {
59
+ println ! ( "Failed to claim interface: {}" , err) ;
60
+ return res;
61
+ }
62
+
63
+ Ok ( ( ) )
64
+ }
65
+
66
+ /// Cleanup the device following a test
67
+ pub fn post_test ( & mut self ) -> rusb:: Result < ( ) > {
68
+ let res = self . release_interface ( TEST_INTERFACE ) ;
69
+ if let Err ( err) = res {
70
+ println ! ( "Failed to release interface: {}" , err) ;
71
+ return res;
72
+ }
73
+
74
+ Ok ( ( ) )
75
+ }
37
76
}
38
77
39
78
impl :: std:: ops:: Deref for DeviceHandles {
@@ -50,38 +89,102 @@ impl ::std::ops::DerefMut for DeviceHandles {
50
89
}
51
90
}
52
91
53
- pub fn open_device ( ctx : & Context ) -> rusb:: Result < DeviceHandles > {
54
- for device in ctx. devices ( ) ?. iter ( ) {
55
- let device_descriptor = device. device_descriptor ( ) ?;
92
+ pub struct UsbContext {
93
+ /// rusb Context handle
94
+ inner : Context ,
95
+ device : Option < DeviceHandles > ,
96
+ }
56
97
57
- if !( device_descriptor. vendor_id ( ) == test_class:: VID
58
- && device_descriptor. product_id ( ) == test_class:: PID )
59
- {
60
- continue ;
61
- }
98
+ impl UsbContext {
99
+ pub fn new ( ) -> rusb:: Result < Self > {
100
+ let inner = rusb:: Context :: new ( ) ?;
62
101
63
- let mut handle = device. open ( ) ?;
102
+ Ok ( Self {
103
+ inner,
104
+ device : None ,
105
+ } )
106
+ }
107
+
108
+ /// Attempt to open the test device once
109
+ fn try_open_device ( & self ) -> rusb:: Result < DeviceHandles > {
110
+ for device in self . inner . devices ( ) ?. iter ( ) {
111
+ let device_descriptor = device. device_descriptor ( ) ?;
112
+
113
+ if !( device_descriptor. vendor_id ( ) == test_class:: VID
114
+ && device_descriptor. product_id ( ) == test_class:: PID )
115
+ {
116
+ continue ;
117
+ }
118
+
119
+ let mut handle = device. open ( ) ?;
120
+
121
+ let langs = handle. read_languages ( TIMEOUT ) ?;
122
+ if langs. is_empty ( ) || langs[ 0 ] . lang_id ( ) != EN_US {
123
+ continue ;
124
+ }
125
+
126
+ let prod = handle. read_product_string ( langs[ 0 ] , & device_descriptor, TIMEOUT ) ?;
127
+
128
+ if prod == test_class:: PRODUCT {
129
+ handle. reset ( ) ?;
130
+
131
+ let config_descriptor = device. config_descriptor ( 0 ) ?;
64
132
65
- let langs = handle. read_languages ( TIMEOUT ) ?;
66
- if langs. is_empty ( ) || langs[ 0 ] . lang_id ( ) != EN_US {
67
- continue ;
133
+ return Ok ( DeviceHandles {
134
+ device_descriptor,
135
+ config_descriptor,
136
+ handle,
137
+ en_us : langs[ 0 ] ,
138
+ } ) ;
139
+ }
68
140
}
69
141
70
- let prod = handle. read_product_string ( langs[ 0 ] , & device_descriptor, TIMEOUT ) ?;
142
+ Err ( rusb:: Error :: NoDevice )
143
+ }
71
144
72
- if prod == test_class:: PRODUCT {
73
- handle. reset ( ) ?;
145
+ /// Look for the device for about 5 seconds in case it hasn't finished enumerating yet
146
+ pub fn open_device ( & mut self ) -> rusb:: Result < & mut DeviceHandles > {
147
+ if self . device . is_none ( ) {
148
+ for _ in 0 ..50 {
149
+ if let Ok ( dev) = self . try_open_device ( ) {
150
+ self . device = Some ( dev) ;
151
+ break ;
152
+ }
153
+ thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
154
+ }
155
+ }
74
156
75
- let config_descriptor = device. config_descriptor ( 0 ) ?;
157
+ match self . device . as_mut ( ) {
158
+ Some ( device) => Ok ( device) ,
159
+ None => Err ( rusb:: Error :: NoDevice ) ,
160
+ }
161
+ }
76
162
77
- return Ok ( DeviceHandles {
78
- device_descriptor,
79
- config_descriptor,
80
- handle,
81
- en_us : langs[ 0 ] ,
82
- } ) ;
163
+ /// Attempts to open (if necessary) and (re-)initialize a device for a test
164
+ pub fn device_for_test ( & mut self ) -> rusb:: Result < & mut DeviceHandles > {
165
+ let dev = match self . open_device ( ) {
166
+ Ok ( dev) => dev,
167
+ Err ( err) => {
168
+ println ! ( "Did not find a TestClass device. Make sure the device is correctly programmed and plugged in. Last error: {}" , err) ;
169
+ return Err ( err) ;
170
+ }
171
+ } ;
172
+
173
+ match dev. pre_test ( ) {
174
+ Ok ( ( ) ) => Ok ( dev) ,
175
+ Err ( err) => {
176
+ println ! ( "Failed to prepare for test: {}" , err) ;
177
+ Err ( err)
178
+ }
83
179
}
84
180
}
85
181
86
- Err ( rusb:: Error :: NoDevice )
182
+ /// Releases resources that might have been used in a test
183
+ pub fn cleanup_after_test ( & mut self ) -> rusb:: Result < ( ) > {
184
+ if let Some ( dev) = & mut self . device {
185
+ dev. post_test ( )
186
+ } else {
187
+ Ok ( ( ) )
188
+ }
189
+ }
87
190
}
0 commit comments