1
- use std:: cmp:: Ordering ;
2
1
#[ cfg( not( target_os = "windows" ) ) ]
3
2
use std:: fs;
4
3
5
4
use crossterm:: style:: Stylize ;
6
5
use dialoguer:: { theme:: ColorfulTheme , Confirm , Select } ;
7
6
use log:: { error, info} ;
8
7
use miette:: { IntoDiagnostic , Result } ;
9
- use serialport:: { available_ports, SerialPortInfo , SerialPortType , UsbPortInfo } ;
8
+ use serialport:: { available_ports, SerialPortInfo , SerialPortType } ;
10
9
11
10
use crate :: {
12
11
cli:: { config:: UsbDevice , Config , ConnectArgs } ,
@@ -26,7 +25,7 @@ pub fn get_serial_port_info(
26
25
// Users may optionally specify the device's VID and PID in the configuration
27
26
// file. If no VID/PID has been provided, the user will always be prompted to
28
27
// select a serial port. If some VID and PID were provided then the user will
29
- // also be prompted to select a port, unless there is only one found and its VID
28
+ // also be prompted to select a port, unless there is only one found whose VID
30
29
// and PID match the configured values.
31
30
//
32
31
// The call to canonicalize() was originally added to resolve
@@ -186,53 +185,50 @@ fn select_serial_port(
186
185
mut ports : Vec < SerialPortInfo > ,
187
186
config : & Config ,
188
187
) -> Result < ( SerialPortInfo , bool ) , Error > {
189
- fn device_matches ( config : & Config , info : & UsbPortInfo ) -> bool {
190
- config
188
+ // Does this port match a known one?
189
+ let matches = |port : & SerialPortInfo | match & port. port_type {
190
+ SerialPortType :: UsbPort ( info) => config
191
191
. usb_device
192
192
. iter ( )
193
193
. chain ( KNOWN_DEVICES . iter ( ) )
194
- . any ( |dev| dev. matches ( info) )
195
- }
194
+ . any ( |dev| dev. matches ( info) ) ,
195
+ _ => false ,
196
+ } ;
196
197
197
- if ports. len ( ) > 1 {
198
- // Multiple serial ports detected
198
+ if let [ port] = ports
199
+ . iter ( )
200
+ . filter ( |& p| matches ( p) )
201
+ . collect :: < Vec < _ > > ( )
202
+ . as_slice ( )
203
+ {
204
+ // There is a unique recognized device.
205
+ Ok ( ( ( * port) . to_owned ( ) , true ) )
206
+ } else if ports. len ( ) > 1 {
207
+ // Multiple serial ports detected.
199
208
info ! ( "Detected {} serial ports" , ports. len( ) ) ;
200
209
info ! ( "Ports which match a known common dev board are highlighted" ) ;
201
210
info ! ( "Please select a port" ) ;
202
211
203
- ports. sort_by ( |a, b| {
204
- let a_matches = match & a. port_type {
205
- SerialPortType :: UsbPort ( info) => device_matches ( config, info) ,
206
- _ => false ,
207
- } ;
208
- let b_matches = match & b. port_type {
209
- SerialPortType :: UsbPort ( info) => device_matches ( config, info) ,
210
- _ => false ,
211
- } ;
212
- match ( a_matches, b_matches) {
213
- ( true , true ) | ( false , false ) => Ordering :: Equal ,
214
- ( true , false ) => Ordering :: Less ,
215
- ( false , true ) => Ordering :: Greater ,
216
- }
217
- } ) ;
212
+ ports. sort_by_key ( |a| !matches ( a) ) ;
218
213
219
214
let port_names = ports
220
215
. iter ( )
221
- . map ( |port_info| match & port_info. port_type {
222
- SerialPortType :: UsbPort ( info) => {
223
- let formatted = if device_matches ( config, info) {
224
- port_info. port_name . as_str ( ) . bold ( )
225
- } else {
226
- port_info. port_name . as_str ( ) . reset ( )
227
- } ;
228
-
229
- if let Some ( product) = & info. product {
230
- format ! ( "{} - {}" , formatted, product)
231
- } else {
232
- formatted. to_string ( )
216
+ . map ( |port_info| {
217
+ let formatted = if matches ( port_info) {
218
+ port_info. port_name . as_str ( ) . bold ( )
219
+ } else {
220
+ port_info. port_name . as_str ( ) . reset ( )
221
+ } ;
222
+ match & port_info. port_type {
223
+ SerialPortType :: UsbPort ( info) => {
224
+ if let Some ( product) = & info. product {
225
+ format ! ( "{} - {}" , formatted, product)
226
+ } else {
227
+ formatted. to_string ( )
228
+ }
233
229
}
230
+ _ => formatted. to_string ( ) ,
234
231
}
235
- _ => port_info. port_name . clone ( ) ,
236
232
} )
237
233
. collect :: < Vec < _ > > ( ) ;
238
234
@@ -250,37 +246,19 @@ fn select_serial_port(
250
246
. ok_or ( Error :: Cancelled ) ?;
251
247
252
248
match ports. get ( index) {
253
- Some ( port_info) => {
254
- let matches = if let SerialPortType :: UsbPort ( usb_info) = & port_info. port_type {
255
- device_matches ( config, usb_info)
256
- } else {
257
- false
258
- } ;
259
-
260
- Ok ( ( port_info. to_owned ( ) , matches) )
261
- }
249
+ Some ( port_info) => Ok ( ( port_info. to_owned ( ) , matches ( port_info) ) ) ,
262
250
None => Err ( Error :: SerialNotFound (
263
251
port_names. get ( index) . unwrap ( ) . to_string ( ) ,
264
252
) ) ,
265
253
}
266
254
} else if let [ port] = ports. as_slice ( ) {
267
- // Single serial port detected
255
+ // A single port, but we didn't recognize it. Prompt for confirmation.
268
256
let port_name = port. port_name . clone ( ) ;
269
- let port_info = match & port. port_type {
270
- SerialPortType :: UsbPort ( info) => info,
271
- SerialPortType :: PciPort | SerialPortType :: Unknown => & UsbPortInfo {
272
- vid : 0 ,
273
- pid : 0 ,
274
- serial_number : None ,
275
- manufacturer : None ,
276
- product : None ,
277
- } ,
278
- _ => unreachable ! ( ) ,
257
+ let product = match & port. port_type {
258
+ SerialPortType :: UsbPort ( info) => info. product . as_ref ( ) ,
259
+ _ => None ,
279
260
} ;
280
-
281
- if device_matches ( config, port_info) {
282
- Ok ( ( port. to_owned ( ) , true ) )
283
- } else if confirm_port ( & port_name, port_info) ? {
261
+ if confirm_port ( & port_name, product) ? {
284
262
Ok ( ( port. to_owned ( ) , false ) )
285
263
} else {
286
264
Err ( Error :: SerialNotFound ( port_name) )
@@ -292,10 +270,10 @@ fn select_serial_port(
292
270
}
293
271
294
272
/// Ask the user to confirm the use of a serial port.
295
- fn confirm_port ( port_name : & str , port_info : & UsbPortInfo ) -> Result < bool , Error > {
273
+ fn confirm_port ( port_name : & str , product : Option < & String > ) -> Result < bool , Error > {
296
274
Confirm :: with_theme ( & ColorfulTheme :: default ( ) )
297
275
. with_prompt ( {
298
- if let Some ( product) = & port_info . product {
276
+ if let Some ( product) = product {
299
277
format ! ( "Use serial port '{}' - {}?" , port_name, product)
300
278
} else {
301
279
format ! ( "Use serial port '{}'?" , port_name)
0 commit comments