11use rusb:: { ConfigDescriptor , Context , DeviceDescriptor , DeviceHandle , Language , UsbContext as _} ;
2+ use std:: thread;
23use std:: time:: Duration ;
4+ use usb_device:: device:: CONFIGURATION_VALUE ;
35use usb_device:: test_class;
46
7+ const TEST_INTERFACE : u8 = 0 ;
8+
59pub const TIMEOUT : Duration = Duration :: from_secs ( 1 ) ;
610pub const EN_US : u16 = 0x0409 ;
711
@@ -18,6 +22,7 @@ impl DeviceHandles {
1822 pub fn is_high_speed ( & self ) -> bool {
1923 self . handle . device ( ) . speed ( ) == rusb:: Speed :: High
2024 }
25+
2126 /// Returns the max packet size for the `TestClass` bulk endpoint(s).
2227 pub fn bulk_max_packet_size ( & self ) -> u16 {
2328 self . config_descriptor
@@ -34,6 +39,40 @@ impl DeviceHandles {
3439 . next ( )
3540 . expect ( "TestClass has at least one bulk endpoint" )
3641 }
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+ }
3776}
3877
3978impl :: std:: ops:: Deref for DeviceHandles {
@@ -50,38 +89,102 @@ impl ::std::ops::DerefMut for DeviceHandles {
5089 }
5190}
5291
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+ }
5697
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 ( ) ?;
62101
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 ) ?;
64132
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+ }
68140 }
69141
70- let prod = handle. read_product_string ( langs[ 0 ] , & device_descriptor, TIMEOUT ) ?;
142+ Err ( rusb:: Error :: NoDevice )
143+ }
71144
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+ }
74156
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+ }
76162
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+ }
83179 }
84180 }
85181
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+ }
87190}
0 commit comments