1
1
use std:: io:: Read ;
2
2
3
- use serialport:: SerialPort ;
3
+ use crate :: { cli:: ConnectOpts , Config , Error } ;
4
+ use miette:: Context ;
5
+ use serialport:: { FlowControl , SerialPort , SerialPortInfo } ;
4
6
5
7
#[ cfg( feature = "raspberry" ) ]
6
- use rppal:: gpio:: OutputPin ;
7
-
8
- use crate :: { cli:: ConnectOpts , Config } ;
8
+ use rppal:: gpio:: { Gpio , OutputPin } ;
9
9
10
10
#[ derive( thiserror:: Error , Debug ) ]
11
11
pub enum SerialConfigError {
12
12
#[ cfg( feature = "raspberry" ) ]
13
13
#[ error( "You need to specify DTR when using an internal UART peripheral" ) ]
14
14
MissingDtrForInternalUart ,
15
+
16
+ #[ cfg( feature = "raspberry" ) ]
17
+ #[ error( "GPIO {0} is not available" ) ]
18
+ GpioUnavailable ( u8 ) ,
15
19
}
16
20
17
21
/// Wrapper around SerialPort where platform-specific modifications can be implemented.
@@ -35,26 +39,63 @@ fn write_gpio(gpio: &mut OutputPin, level: bool) {
35
39
impl Interface {
36
40
#[ cfg( feature = "raspberry" ) ]
37
41
pub ( crate ) fn new (
38
- serial : Box < dyn SerialPort > ,
42
+ port_info : & SerialPortInfo ,
39
43
opts : & ConnectOpts ,
40
44
config : & Config ,
41
- ) -> Result < Self , SerialConfigError > {
45
+ ) -> Result < Self , Error > {
42
46
let rts_gpio = opts. rts . or ( config. rts ) ;
43
47
let dtr_gpio = opts. dtr . or ( config. dtr ) ;
44
48
49
+ if port_info. port_type == serialport:: SerialPortType :: Unknown && dtr_gpio. is_none ( ) {
50
+ // Assume internal UART, which has no DTR pin.
51
+ return Err ( SerialConfigError :: MissingDtrForInternalUart ) ;
52
+ }
53
+
54
+ let mut gpios = Gpio :: new ( ) . unwrap ( ) ;
55
+
56
+ let rts = if let Some ( gpio) = rts_gpio {
57
+ match gpios. get ( gpio) {
58
+ Ok ( pin) => Some ( pin. into_output ( ) ) ,
59
+ Err ( _) => return Err ( SerialConfigError :: GpioUnavailable ) ,
60
+ }
61
+ } else {
62
+ None
63
+ } ;
64
+
65
+ let dtr = if let Some ( gpio) = dtr_gpio {
66
+ match gpios. get ( gpio) {
67
+ Ok ( pin) => Some ( pin. into_output ( ) ) ,
68
+ Err ( _) => return Err ( SerialConfigError :: GpioUnavailable ) ,
69
+ }
70
+ } else {
71
+ None
72
+ } ;
73
+
74
+ let serial = serialport:: new ( & port_info. port_name , 115_200 )
75
+ . flow_control ( FlowControl :: None )
76
+ . open ( )
77
+ . map_err ( Error :: from)
78
+ . wrap_err_with ( || format ! ( "Failed to open serial port {}" , port_info. port_name) ) ?;
79
+
45
80
Ok ( Self {
46
81
serial_port : serial,
47
- rts : rts_gpio . map ( |num| gpios . get ( num ) . into_output ( ) ) ,
48
- dtr : dtr_gpio . map ( |num| gpios . get ( num ) . into_output ( ) ) ,
82
+ rts,
83
+ dtr,
49
84
} )
50
85
}
51
86
52
87
#[ cfg( not( feature = "raspberry" ) ) ]
53
88
pub ( crate ) fn new (
54
- serial : Box < dyn SerialPort > ,
89
+ port_info : & SerialPortInfo ,
55
90
_opts : & ConnectOpts ,
56
91
_config : & Config ,
57
- ) -> Result < Self , SerialConfigError > {
92
+ ) -> Result < Self , Error > {
93
+ let serial = serialport:: new ( & port_info. port_name , 115_200 )
94
+ . flow_control ( FlowControl :: None )
95
+ . open ( )
96
+ . map_err ( Error :: from)
97
+ . wrap_err_with ( || format ! ( "Failed to open serial port {}" , port_info. port_name) ) ?;
98
+
58
99
Ok ( Self {
59
100
serial_port : serial,
60
101
} )
0 commit comments