11use std:: io:: Read ;
22
3- use serialport:: SerialPort ;
3+ use crate :: { cli:: ConnectOpts , Config , Error } ;
4+ use miette:: Context ;
5+ use serialport:: { FlowControl , SerialPort , SerialPortInfo } ;
46
57#[ cfg( feature = "raspberry" ) ]
6- use rppal:: gpio:: OutputPin ;
7-
8- use crate :: { cli:: ConnectOpts , Config } ;
8+ use rppal:: gpio:: { Gpio , OutputPin } ;
99
1010#[ derive( thiserror:: Error , Debug ) ]
1111pub enum SerialConfigError {
1212 #[ cfg( feature = "raspberry" ) ]
1313 #[ error( "You need to specify DTR when using an internal UART peripheral" ) ]
1414 MissingDtrForInternalUart ,
15+
16+ #[ cfg( feature = "raspberry" ) ]
17+ #[ error( "GPIO {0} is not available" ) ]
18+ GpioUnavailable ( u8 ) ,
1519}
1620
1721/// Wrapper around SerialPort where platform-specific modifications can be implemented.
@@ -35,26 +39,63 @@ fn write_gpio(gpio: &mut OutputPin, level: bool) {
3539impl Interface {
3640 #[ cfg( feature = "raspberry" ) ]
3741 pub ( crate ) fn new (
38- serial : Box < dyn SerialPort > ,
42+ port_info : & SerialPortInfo ,
3943 opts : & ConnectOpts ,
4044 config : & Config ,
41- ) -> Result < Self , SerialConfigError > {
45+ ) -> Result < Self , Error > {
4246 let rts_gpio = opts. rts . or ( config. rts ) ;
4347 let dtr_gpio = opts. dtr . or ( config. dtr ) ;
4448
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+
4580 Ok ( Self {
4681 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,
4984 } )
5085 }
5186
5287 #[ cfg( not( feature = "raspberry" ) ) ]
5388 pub ( crate ) fn new (
54- serial : Box < dyn SerialPort > ,
89+ port_info : & SerialPortInfo ,
5590 _opts : & ConnectOpts ,
5691 _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+
5899 Ok ( Self {
59100 serial_port : serial,
60101 } )
0 commit comments