Skip to content

Commit ef622d0

Browse files
committed
Validate GPIOs, require DTR for internal UART
1 parent aa30d95 commit ef622d0

File tree

2 files changed

+53
-20
lines changed

2 files changed

+53
-20
lines changed

espflash/src/cli/mod.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::{
1313
use clap::Parser;
1414
use config::Config;
1515
use miette::{IntoDiagnostic, Result, WrapErr};
16-
use serialport::{FlowControl, SerialPortType, UsbPortInfo};
16+
use serialport::{SerialPortType, UsbPortInfo};
1717
use strum::VariantNames;
1818
use update_informer::{registry, Check};
1919

@@ -130,16 +130,8 @@ pub fn connect(opts: &ConnectOpts, config: &Config) -> Result<Flasher> {
130130
// Attempt to open the serial port and set its initial baud rate.
131131
println!("Serial port: {}", port_info.port_name);
132132
println!("Connecting...\n");
133-
let serial = serialport::new(&port_info.port_name, 115_200)
134-
.flow_control(FlowControl::None)
135-
.open()
136-
.map_err(Error::from)
137-
.wrap_err_with(|| format!("Failed to open serial port {}", port_info.port_name))?;
138-
139-
#[cfg(feature = "raspberry")]
140-
let mut gpios = rppal::Gpio::new().unwrap();
141133

142-
let interface = Interface::new(serial, opts, config)
134+
let interface = Interface::new(&port_info, opts, config)
143135
.map_err(Error::from)
144136
.wrap_err_with(|| format!("Failed to open serial port {}", port_info.port_name))?;
145137

espflash/src/interface.rs

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
use 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)]
1111
pub 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) {
3539
impl 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

Comments
 (0)