diff --git a/.github/actions/package/action.yml b/.github/actions/package/action.yml index 241a8047..2a62d1f4 100644 --- a/.github/actions/package/action.yml +++ b/.github/actions/package/action.yml @@ -4,8 +4,6 @@ inputs: required: false github_token: required: true - features: - required: false target: required: true runs_on: @@ -22,7 +20,7 @@ runs: - name: Build shell: bash run: | - cargo build --release --all --target ${{ inputs.target }} ${{ inputs.features }} + cargo build --release --all --target ${{ inputs.target }} - name: Compress (Unix) if: ${{ inputs.runs_on != 'windows-2022' }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7b7b9bb..e4d0f940 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,11 +43,9 @@ jobs: - os: "ubuntu-22.04" target: "aarch64-unknown-linux-gnu" arch: "arm64" - features: "--features=raspberry" - os: "ubuntu-22.04" target: "armv7-unknown-linux-gnueabihf" arch: "armhf" - features: "--features=raspberry" runs-on: ${{ matrix.platform.os }} steps: @@ -59,7 +57,7 @@ jobs: arch: ${{ matrix.platform.arch }} target: ${{ matrix.platform.target }} - - run: cargo check ${{ matrix.platform.features }} + - run: cargo check check-lib: name: Check lib (${{ matrix.platform.target }}) @@ -71,10 +69,8 @@ jobs: arch: "x86_64" - target: "aarch64-unknown-linux-gnu" arch: "arm64" - features: "--features=raspberry" - target: "armv7-unknown-linux-gnueabihf" arch: "armhf" - features: "--features=raspberry" runs-on: ubuntu-22.04 steps: @@ -86,7 +82,7 @@ jobs: arch: ${{ matrix.platform.arch }} target: ${{ matrix.platform.target }} - - run: cargo check -p espflash --lib --no-default-features ${{ matrix.platform.features }} + - run: cargo check -p espflash --lib --no-default-features msrv: name: Check MSRV (${{ matrix.platform.target }}) @@ -98,10 +94,8 @@ jobs: arch: "x86_64" - target: "aarch64-unknown-linux-gnu" arch: "arm64" - features: "--features=raspberry" - target: "armv7-unknown-linux-gnueabihf" arch: "armhf" - features: "--features=raspberry" runs-on: ubuntu-22.04 steps: @@ -114,7 +108,7 @@ jobs: target: ${{ matrix.platform.target }} toolchain: "1.73" - - run: cargo check ${{ matrix.platform.features }} + - run: cargo check # -------------------------------------------------------------------------- # Test @@ -129,10 +123,8 @@ jobs: arch: "x86_64" - target: "aarch64-unknown-linux-gnu" arch: "arm64" - features: "--features=raspberry" - target: "armv7-unknown-linux-gnueabihf" arch: "armhf" - features: "--features=raspberry" runs-on: ubuntu-22.04 steps: @@ -144,7 +136,7 @@ jobs: arch: ${{ matrix.platform.arch }} target: ${{ matrix.platform.target }} - - run: cargo test --lib ${{ matrix.platform.features }} + - run: cargo test --lib # -------------------------------------------------------------------------- # Lint @@ -159,10 +151,8 @@ jobs: arch: "x86_64" - target: "aarch64-unknown-linux-gnu" arch: "arm64" - features: "--features=raspberry" - target: "armv7-unknown-linux-gnueabihf" arch: "armhf" - features: "--features=raspberry" runs-on: ubuntu-22.04 steps: @@ -175,7 +165,7 @@ jobs: target: ${{ matrix.platform.target }} components: clippy - - run: cargo clippy ${{ matrix.platform.features }} -- -D warnings -A clippy::too_many_arguments + - run: cargo clippy -- -D warnings -A clippy::too_many_arguments rustfmt: name: Rustfmt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd9f8770..8c4b8ea3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,11 +24,9 @@ jobs: - os: "ubuntu-20.04" target: "aarch64-unknown-linux-gnu" arch: "arm64" - features: "--features=raspberry" - os: "ubuntu-20.04" target: "armv7-unknown-linux-gnueabihf" arch: "armhf" - features: "--features=raspberry" # Windows - os: "windows-2022" target: "x86_64-pc-windows-msvc" @@ -50,7 +48,6 @@ jobs: with: arch: ${{ matrix.platform.arch }} github_token: ${{ secrets.GITHUB_TOKEN }} - features: ${{ matrix.platform.features }} target: ${{ matrix.platform.target }} runs_on: ${{ matrix.platform.os }} diff --git a/CHANGELOG.md b/CHANGELOG.md index a88e2ed5..7f4b98ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove support for the ESP8266 (#576) - Remove the direct boot image format (#577) +- Remove support for Raspberry Pi's internal UART peripherals (#585) ## [2.1.0] - 2023-10-03 diff --git a/Cargo.lock b/Cargo.lock index 25315a25..734bf0ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1151,7 +1151,6 @@ dependencies = [ "miette", "parse_int", "regex", - "rppal", "serde", "serialport", "sha2", @@ -3342,15 +3341,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "rppal" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dc171bbe325b04172e18d917c58c2cf1fb5adfd9ffabb1d6b3d62ba4c1c1331" -dependencies = [ - "libc", -] - [[package]] name = "rustc-demangle" version = "0.1.23" diff --git a/cargo-espflash/README.md b/cargo-espflash/README.md index 06849054..4bb9bd3c 100644 --- a/cargo-espflash/README.md +++ b/cargo-espflash/README.md @@ -50,12 +50,6 @@ Alternatively, you can use [cargo-binstall] to download pre-compiled artifacts f cargo binstall cargo-espflash ``` -If you would like to flash from a Raspberry Pi using the built-in UART peripheral, you can enable the `raspberry` feature (note that this is not available if using [cargo-binstall]): - -```bash -cargo install cargo-espflash --features=raspberry -``` - By default, in Unix systems, we use the [`vendored-openssl` Cargo feature] which may require additional tools such as `perl` and `make`. To disable this feature, use: ``` diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index 3f7ebbe0..6759c626 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -354,7 +354,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> { }; monitor( - flasher.into_interface(), + flasher.into_serial(), Some(&elf_data), pid, args.flash_args.monitor_baud.unwrap_or(default_baud), diff --git a/espflash/Cargo.toml b/espflash/Cargo.toml index 57ead78f..164ec161 100644 --- a/espflash/Cargo.toml +++ b/espflash/Cargo.toml @@ -47,7 +47,6 @@ md-5 = "0.10.6" miette = { version = "7.0.0", features = ["fancy"] } parse_int = { version = "0.6.0", optional = true } regex = { version = "1.10.3", optional = true } -rppal = { version = "0.17.1", optional = true } serde = { version = "1.0.196", features = ["derive"] } serialport = { version = "4.3.0", optional = true } sha2 = "0.10.8" @@ -85,4 +84,3 @@ cli = [ ] serialport = ["dep:serialport"] -raspberry = ["dep:rppal"] diff --git a/espflash/README.md b/espflash/README.md index 360843c6..1d8eaabc 100644 --- a/espflash/README.md +++ b/espflash/README.md @@ -52,12 +52,6 @@ Alternatively, you can use [cargo-binstall] to download pre-compiled artifacts f cargo binstall espflash ``` -If you would like to flash from a Raspberry Pi using the built-in UART peripheral, you can enable the `raspberry` feature (note that this is not available if using [cargo-binstall]): - -```bash -cargo install espflash --features=raspberry -``` - [libuv]: https://libuv.org/ [cargo-binstall]: https://github.com/cargo-bins/cargo-binstall [releases]: https://github.com/esp-rs/espflash/releases @@ -129,12 +123,6 @@ or `cargo add espflash --no-default-features` We disable the `default-features` to opt-out the `cli` feature, which is enabled by default; you likely will not need any of these types or functions in your application so there’s no use pulling in the extra dependencies. -Just like when using `espflash` as an application, you can enable the raspberry feature to allow your dependent application to use the Raspberry Pi’s built-in UART: - -```toml -espflash = { version = "2.1", default-features = false, features = ["raspberry"] } -``` - ## Configuration File The configuration file allows you to define various parameters for your application: diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index 21902f04..830cd217 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -289,7 +289,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> { }; monitor( - flasher.into_interface(), + flasher.into_serial(), Some(&elf_data), pid, args.flash_args.monitor_baud.unwrap_or(default_baud), diff --git a/espflash/src/cli/config.rs b/espflash/src/cli/config.rs index 8c3c8e51..b5d3d2d9 100644 --- a/espflash/src/cli/config.rs +++ b/espflash/src/cli/config.rs @@ -26,12 +26,6 @@ use crate::error::Error; pub struct Connection { /// Name of the serial port used for communication pub serial: Option, - /// Data Transmit Ready pin - #[cfg(feature = "raspberry")] - pub dtr: Option, - /// Ready To Send pin - #[cfg(feature = "raspberry")] - pub rts: Option, } /// A configured, known USB device diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index 536e34ef..4dc7f783 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -19,7 +19,7 @@ use esp_idf_part::{DataType, Partition, PartitionTable}; use indicatif::{style::ProgressStyle, HumanCount, ProgressBar}; use log::{debug, info, warn}; use miette::{IntoDiagnostic, Result, WrapErr}; -use serialport::{SerialPortType, UsbPortInfo}; +use serialport::{FlowControl, SerialPortType, UsbPortInfo}; use self::{ config::Config, @@ -34,7 +34,6 @@ use crate::{ parse_partition_table, FlashData, FlashFrequency, FlashMode, FlashSize, Flasher, ProgressCallbacks, }, - interface::Interface, targets::{Chip, XtalFrequency}, }; @@ -68,14 +67,6 @@ pub struct ConnectArgs { /// Serial port connected to target device #[arg(short = 'p', long, env = "ESPFLASH_PORT")] pub port: Option, - /// DTR pin to use for the internal UART hardware. Uses BCM numbering. - #[cfg(feature = "raspberry")] - #[cfg_attr(feature = "raspberry", clap(long))] - pub dtr: Option, - /// RTS pin to use for the internal UART hardware. Uses BCM numbering. - #[cfg(feature = "raspberry")] - #[cfg_attr(feature = "raspberry", clap(long))] - pub rts: Option, } /// Generate completions for the given shell @@ -306,15 +297,10 @@ pub fn connect( info!("Serial port: '{}'", port_info.port_name); info!("Connecting..."); - #[cfg(feature = "raspberry")] - let (dtr, rts) = ( - args.dtr.or(config.connection.dtr), - args.rts.or(config.connection.rts), - ); - #[cfg(not(feature = "raspberry"))] - let (dtr, rts) = (None, None); - - let interface = Interface::new(&port_info, dtr, rts) + let serial_port = serialport::new(&port_info.port_name, 115_200) + .flow_control(FlowControl::None) + .open_native() + .map_err(Error::from) .wrap_err_with(|| format!("Failed to open serial port {}", port_info.port_name))?; // NOTE: since `get_serial_port_info` filters out all PCI Port and Bluetooth @@ -335,7 +321,7 @@ pub fn connect( }; Ok(Flasher::connect( - interface, + *Box::new(serial_port), port_info, args.baud.or(config.baudrate), !args.no_stub, @@ -448,7 +434,7 @@ pub fn serial_monitor(args: MonitorArgs, config: &Config) -> Result<()> { }; monitor( - flasher.into_interface(), + flasher.into_serial(), elf.as_deref(), pid, args.connect_args.baud.unwrap_or(default_baud), diff --git a/espflash/src/cli/monitor/mod.rs b/espflash/src/cli/monitor/mod.rs index 250f8c70..41a80cbf 100644 --- a/espflash/src/cli/monitor/mod.rs +++ b/espflash/src/cli/monitor/mod.rs @@ -11,7 +11,7 @@ //! in our monitor the output is displayed immediately upon reading. use std::{ - io::{stdout, ErrorKind, Write}, + io::{stdout, ErrorKind, Read, Write}, time::Duration, }; @@ -21,12 +21,13 @@ use crossterm::{ }; use log::error; use miette::{IntoDiagnostic, Result}; +#[cfg(feature = "serialport")] +use serialport::SerialPort; use strum::{Display, EnumIter, EnumString, VariantNames}; use crate::{ cli::monitor::parser::{InputParser, ResolvingPrinter}, - connection::reset_after_flash, - interface::Interface, + connection::{reset_after_flash, Port}, }; pub mod parser; @@ -63,9 +64,9 @@ impl Drop for RawModeGuard { } } -/// Open a serial monitor on the given interface, using the given input parser. +/// Open a serial monitor on the given serial port, using the given input parser. pub fn monitor( - mut serial: Interface, + mut serial: Port, elf: Option<&[u8]>, pid: u16, baud: u32, @@ -78,12 +79,8 @@ pub fn monitor( // Explicitly set the baud rate when starting the serial monitor, to allow using // different rates for flashing. + serial.set_baud_rate(baud).into_diagnostic()?; serial - .serial_port_mut() - .set_baud_rate(baud) - .into_diagnostic()?; - serial - .serial_port_mut() .set_timeout(Duration::from_millis(5)) .into_diagnostic()?; @@ -100,7 +97,7 @@ pub fn monitor( let mut buff = [0; 1024]; loop { - let read_count = match serial.serial_port_mut().read(&mut buff) { + let read_count = match serial.read(&mut buff) { Ok(count) => Ok(count), Err(e) if e.kind() == ErrorKind::TimedOut => Ok(0), Err(e) if e.kind() == ErrorKind::Interrupted => continue, @@ -126,11 +123,8 @@ pub fn monitor( } if let Some(bytes) = handle_key_event(key) { - serial - .serial_port_mut() - .write_all(&bytes) - .into_diagnostic()?; - serial.serial_port_mut().flush().into_diagnostic()?; + serial.write_all(&bytes).into_diagnostic()?; + serial.flush().into_diagnostic()?; } } } diff --git a/espflash/src/connection/mod.rs b/espflash/src/connection/mod.rs index e9e4db65..8354cac0 100644 --- a/espflash/src/connection/mod.rs +++ b/espflash/src/connection/mod.rs @@ -5,7 +5,7 @@ //! device. use std::{ - io::{BufWriter, Write}, + io::{BufWriter, Read, Write}, iter::zip, thread::sleep, time::Duration, @@ -13,7 +13,7 @@ use std::{ use log::{debug, info}; use regex::Regex; -use serialport::UsbPortInfo; +use serialport::{SerialPort, UsbPortInfo}; use slip_codec::SlipDecoder; #[cfg(unix)] @@ -29,7 +29,6 @@ use crate::{ command::{Command, CommandType}, connection::reset::soft_reset, error::{ConnectionError, Error, ResultExt, RomError, RomErrorKind}, - interface::Interface, }; pub mod reset; @@ -38,6 +37,11 @@ const MAX_CONNECT_ATTEMPTS: usize = 7; const MAX_SYNC_ATTEMPTS: usize = 5; pub(crate) const USB_SERIAL_JTAG_PID: u16 = 0x1001; +#[cfg(unix)] +pub type Port = serialport::TTYPort; +#[cfg(windows)] +pub type Port = serialport::COMPort; + #[derive(Debug, Clone)] pub enum CommandResponseValue { ValueU32(u32), @@ -94,7 +98,7 @@ pub struct CommandResponse { /// An established connection with a target device pub struct Connection { - serial: Interface, + serial: Port, port_info: UsbPortInfo, decoder: SlipDecoder, after_operation: ResetAfterOperation, @@ -103,7 +107,7 @@ pub struct Connection { impl Connection { pub fn new( - serial: Interface, + serial: Port, port_info: UsbPortInfo, after_operation: ResetAfterOperation, before_operation: ResetBeforeOperation, @@ -119,7 +123,7 @@ impl Connection { /// Initialize a connection with a device pub fn begin(&mut self) -> Result<(), Error> { - let port_name = self.serial.serial_port().name().unwrap_or_default(); + let port_name = self.serial.name().unwrap_or_default(); let reset_sequence = construct_reset_strategy_sequence( &port_name, self.port_info.pid, @@ -161,9 +165,9 @@ impl Connection { // Reset the chip to bootloader (download mode) reset_strategy.reset(&mut self.serial)?; - let available_bytes = self.serial.serial_port_mut().bytes_to_read()?; + let available_bytes = self.serial.bytes_to_read()?; buff = vec![0; available_bytes as usize]; - let read_bytes = self.serial.serial_port_mut().read(&mut buff)? as u32; + let read_bytes = self.serial.read(&mut buff)? as u32; if read_bytes != available_bytes { return Err(Error::Connection(ConnectionError::ReadMissmatch( @@ -294,20 +298,20 @@ impl Connection { /// Set timeout for the serial port pub fn set_timeout(&mut self, timeout: Duration) -> Result<(), Error> { - self.serial.serial_port_mut().set_timeout(timeout)?; + self.serial.set_timeout(timeout)?; Ok(()) } /// Set baud rate for the serial port pub fn set_baud(&mut self, speed: u32) -> Result<(), Error> { - self.serial.serial_port_mut().set_baud_rate(speed)?; + self.serial.set_baud_rate(speed)?; Ok(()) } /// Get the current baud rate of the serial port pub fn get_baud(&self) -> Result { - Ok(self.serial.serial_port().baud_rate()?) + Ok(self.serial.baud_rate()?) } /// Run a command with a timeout defined by the command type @@ -316,7 +320,8 @@ impl Connection { F: FnMut(&mut Connection) -> Result, { let old_timeout = { - let serial = self.serial.serial_port_mut(); + let mut binding = Box::new(&mut self.serial); + let serial = binding.as_mut(); let old_timeout = serial.timeout(); serial.set_timeout(timeout)?; old_timeout @@ -324,7 +329,7 @@ impl Connection { let result = f(self); - self.serial.serial_port_mut().set_timeout(old_timeout)?; + self.serial.set_timeout(old_timeout)?; result } @@ -389,8 +394,8 @@ impl Connection { /// Write raw data to the serial port pub fn write_raw(&mut self, data: u32) -> Result<(), Error> { - let serial = self.serial.serial_port_mut(); - + let mut binding = Box::new(&mut self.serial); + let serial = binding.as_mut(); serial.clear(serialport::ClearBuffer::Input)?; let mut writer = BufWriter::new(serial); let mut encoder = SlipEncoder::new(&mut writer)?; @@ -403,7 +408,8 @@ impl Connection { /// Write a command to the serial port pub fn write_command(&mut self, command: Command) -> Result<(), Error> { debug!("Writing command: {:?}", command); - let serial = self.serial.serial_port_mut(); + let mut binding = Box::new(&mut self.serial); + let serial = binding.as_mut(); serial.clear(serialport::ClearBuffer::Input)?; let mut writer = BufWriter::new(serial); @@ -473,12 +479,12 @@ impl Connection { /// Flush the serial port pub fn flush(&mut self) -> Result<(), Error> { - self.serial.serial_port_mut().flush()?; + self.serial.flush()?; Ok(()) } - /// Turn a serial port into a Interface - pub fn into_interface(self) -> Interface { + /// Turn a serial port into a [Port] + pub fn into_serial(self) -> Port { self.serial } @@ -489,7 +495,7 @@ impl Connection { } /// Reset the target device when flashing has completed -pub fn reset_after_flash(serial: &mut Interface, pid: u16) -> Result<(), serialport::Error> { +pub fn reset_after_flash(serial: &mut Port, pid: u16) -> Result<(), serialport::Error> { sleep(Duration::from_millis(100)); if pid == USB_SERIAL_JTAG_PID { diff --git a/espflash/src/connection/reset.rs b/espflash/src/connection/reset.rs index fbd2d0dd..77330b02 100644 --- a/espflash/src/connection/reset.rs +++ b/espflash/src/connection/reset.rs @@ -5,14 +5,17 @@ use std::{io, os::fd::AsRawFd}; use std::{thread::sleep, time::Duration}; use log::debug; +use serialport::SerialPort; use strum::{Display, EnumIter, EnumString, VariantNames}; +#[cfg(unix)] +use libc::ioctl; + use crate::{ command::{Command, CommandType}, - connection::{Connection, USB_SERIAL_JTAG_PID}, + connection::{Connection, Port, USB_SERIAL_JTAG_PID}, error::Error, flasher, - interface::Interface, }; /// Default time to wait before releasing the boot pin after a reset @@ -20,23 +23,18 @@ const DEFAULT_RESET_DELAY: u64 = 50; // ms /// Amount of time to wait if the default reset delay does not work const EXTRA_RESET_DELAY: u64 = 500; // ms -#[cfg(unix)] -use libc::ioctl; - /// Some strategy for resting a target device pub trait ResetStrategy { - fn reset(&self, interface: &mut Interface) -> Result<(), Error>; + fn reset(&self, serial_port: &mut Port) -> Result<(), Error>; - fn set_dtr(&self, interface: &mut Interface, level: bool) -> Result<(), Error> { - interface - .serial_port_mut() - .write_data_terminal_ready(level)?; + fn set_dtr(&self, serial_port: &mut Port, level: bool) -> Result<(), Error> { + serial_port.write_data_terminal_ready(level)?; Ok(()) } - fn set_rts(&self, interface: &mut Interface, level: bool) -> Result<(), Error> { - interface.serial_port_mut().write_request_to_send(level)?; + fn set_rts(&self, serial_port: &mut Port, level: bool) -> Result<(), Error> { + serial_port.write_request_to_send(level)?; Ok(()) } @@ -44,11 +42,11 @@ pub trait ResetStrategy { #[cfg(unix)] fn set_dtr_rts( &self, - interface: &mut Interface, + serial_port: &mut Port, dtr_level: bool, rts_level: bool, ) -> Result<(), Error> { - let fd = interface.as_raw_fd(); + let fd = serial_port.as_raw_fd(); let mut status: i32 = 0; match unsafe { ioctl(fd, libc::TIOCMGET, &status) } { 0 => (), @@ -94,29 +92,29 @@ impl ClassicReset { } impl ResetStrategy for ClassicReset { - fn reset(&self, interface: &mut Interface) -> Result<(), Error> { + fn reset(&self, serial_port: &mut Port) -> Result<(), Error> { debug!( "Using Classic reset strategy with delay of {}ms", self.delay ); - self.set_rts(interface, false)?; - self.set_dtr(interface, false)?; + self.set_rts(serial_port, false)?; + self.set_dtr(serial_port, false)?; - self.set_rts(interface, true)?; - self.set_dtr(interface, true)?; + self.set_rts(serial_port, true)?; + self.set_dtr(serial_port, true)?; - self.set_rts(interface, true)?; // EN = LOW, chip in reset - self.set_dtr(interface, false)?; // IO0 = HIGH + self.set_rts(serial_port, true)?; // EN = LOW, chip in reset + self.set_dtr(serial_port, false)?; // IO0 = HIGH sleep(Duration::from_millis(100)); - self.set_rts(interface, false)?; // EN = HIGH, chip out of reset - self.set_dtr(interface, true)?; // IO0 = LOW + self.set_rts(serial_port, false)?; // EN = HIGH, chip out of reset + self.set_dtr(serial_port, true)?; // IO0 = LOW sleep(Duration::from_millis(self.delay)); - self.set_rts(interface, false)?; - self.set_dtr(interface, false)?; // IO0 = HIGH, done + self.set_rts(serial_port, false)?; + self.set_dtr(serial_port, false)?; // IO0 = HIGH, done Ok(()) } @@ -145,24 +143,24 @@ impl UnixTightReset { #[cfg(unix)] impl ResetStrategy for UnixTightReset { - fn reset(&self, interface: &mut Interface) -> Result<(), Error> { + fn reset(&self, serial_port: &mut Port) -> Result<(), Error> { debug!( "Using UnixTight reset strategy with delay of {}ms", self.delay ); - self.set_dtr_rts(interface, false, false)?; - self.set_dtr_rts(interface, true, true)?; - self.set_dtr_rts(interface, false, true)?; // IO = HIGH, EN = LOW, chip in reset + self.set_dtr_rts(serial_port, false, false)?; + self.set_dtr_rts(serial_port, true, true)?; + self.set_dtr_rts(serial_port, false, true)?; // IO = HIGH, EN = LOW, chip in reset sleep(Duration::from_millis(100)); - self.set_dtr_rts(interface, true, false)?; // IO0 = LOW, EN = HIGH, chip out of reset + self.set_dtr_rts(serial_port, true, false)?; // IO0 = LOW, EN = HIGH, chip out of reset sleep(Duration::from_millis(self.delay)); - self.set_dtr_rts(interface, false, false)?; // IO0 = HIGH, done - self.set_dtr(interface, false)?; // Needed in some environments to ensure IO0 = HIGH + self.set_dtr_rts(serial_port, false, false)?; // IO0 = HIGH, done + self.set_dtr(serial_port, false)?; // Needed in some environments to ensure IO0 = HIGH Ok(()) } @@ -174,27 +172,27 @@ impl ResetStrategy for UnixTightReset { pub struct UsbJtagSerialReset; impl ResetStrategy for UsbJtagSerialReset { - fn reset(&self, interface: &mut Interface) -> Result<(), Error> { + fn reset(&self, serial_port: &mut Port) -> Result<(), Error> { debug!("Using UsbJtagSerial reset strategy"); - self.set_rts(interface, false)?; - self.set_dtr(interface, false)?; // Idle + self.set_rts(serial_port, false)?; + self.set_dtr(serial_port, false)?; // Idle sleep(Duration::from_millis(100)); - self.set_rts(interface, false)?; - self.set_dtr(interface, true)?; // Set IO0 + self.set_rts(serial_port, false)?; + self.set_dtr(serial_port, true)?; // Set IO0 sleep(Duration::from_millis(100)); - self.set_rts(interface, true)?; // Reset. Calls inverted to go through (1,1) instead of (0,0) - self.set_dtr(interface, false)?; - self.set_rts(interface, true)?; // RTS set as Windows only propagates DTR on RTS setting + self.set_rts(serial_port, true)?; // Reset. Calls inverted to go through (1,1) instead of (0,0) + self.set_dtr(serial_port, false)?; + self.set_rts(serial_port, true)?; // RTS set as Windows only propagates DTR on RTS setting sleep(Duration::from_millis(100)); - self.set_rts(interface, false)?; - self.set_dtr(interface, false)?; + self.set_rts(serial_port, false)?; + self.set_dtr(serial_port, false)?; Ok(()) } @@ -207,12 +205,12 @@ impl ResetStrategy for UsbJtagSerialReset { pub struct HardReset; impl ResetStrategy for HardReset { - fn reset(&self, interface: &mut Interface) -> Result<(), Error> { + fn reset(&self, serial_port: &mut Port) -> Result<(), Error> { debug!("Using HardReset reset strategy"); - self.set_rts(interface, true)?; + self.set_rts(serial_port, true)?; sleep(Duration::from_millis(100)); - self.set_rts(interface, false)?; + self.set_rts(serial_port, false)?; Ok(()) } diff --git a/espflash/src/error.rs b/espflash/src/error.rs index 4e727e85..35d4475e 100644 --- a/espflash/src/error.rs +++ b/espflash/src/error.rs @@ -12,8 +12,6 @@ use thiserror::Error; #[cfg(feature = "cli")] use crate::cli::monitor::parser::esp_defmt::DefmtError; -#[cfg(feature = "serialport")] -use crate::interface::SerialConfigError; use crate::{ command::CommandType, flasher::{FlashFrequency, FlashSize}, @@ -139,14 +137,6 @@ pub enum Error { )] StubRequired, - #[cfg(feature = "serialport")] - #[error("Incorrect serial port configuration")] - #[diagnostic( - code(espflash::serial_config), - help("Make sure you have specified the DTR signal if you are using an internal UART peripherial") - )] - SerialConfiguration(SerialConfigError), - #[error("The serial port '{0}' could not be found")] #[diagnostic( code(espflash::serial_not_found), @@ -243,13 +233,6 @@ impl From for Error { } } -#[cfg(feature = "serialport")] -impl From for Error { - fn from(err: SerialConfigError) -> Self { - Self::SerialConfiguration(err) - } -} - /// Connection-related errors #[derive(Debug, Diagnostic, Error)] #[non_exhaustive] diff --git a/espflash/src/flasher/mod.rs b/espflash/src/flasher/mod.rs index dd8fe507..b882e03d 100644 --- a/espflash/src/flasher/mod.rs +++ b/espflash/src/flasher/mod.rs @@ -25,20 +25,17 @@ use strum::IntoEnumIterator; use strum::{Display, EnumIter, VariantNames}; use self::stubs::FlashStub; +#[cfg(feature = "serialport")] +use crate::connection::{ + reset::{ResetAfterOperation, ResetBeforeOperation}, + Connection, Port, +}; use crate::{ command::{Command, CommandType}, elf::{ElfFirmwareImage, FirmwareImage, RomSegment}, error::{ConnectionError, Error, ResultExt}, targets::{Chip, XtalFrequency}, }; -#[cfg(feature = "serialport")] -use crate::{ - connection::{ - reset::{ResetAfterOperation, ResetBeforeOperation}, - Connection, - }, - interface::Interface, -}; mod stubs; @@ -572,7 +569,7 @@ pub struct Flasher { #[cfg(feature = "serialport")] impl Flasher { pub fn connect( - serial: Interface, + serial: Port, port_info: UsbPortInfo, speed: Option, use_stub: bool, @@ -1071,6 +1068,10 @@ impl Flasher { Ok(()) } + pub fn into_serial(self) -> Port { + self.connection.into_serial() + } + pub fn get_usb_pid(&self) -> Result { self.connection.get_usb_pid() } @@ -1190,10 +1191,6 @@ impl Flasher { Ok(()) } - - pub fn into_interface(self) -> Interface { - self.connection.into_interface() - } } pub(crate) fn checksum(data: &[u8], mut checksum: u8) -> u8 { diff --git a/espflash/src/interface.rs b/espflash/src/interface.rs deleted file mode 100644 index fbf92c90..00000000 --- a/espflash/src/interface.rs +++ /dev/null @@ -1,162 +0,0 @@ -//! Serial port wrapper to support platform-specific functionality -//! -//! Since we support flashing using a Raspberry Pi's built-in UART, we must be -//! able to abstract over the differences between this setup and when using a -//! serial port as one normally would, ie.) via USB. - -use std::io::Read; -#[cfg(unix)] -use std::os::fd::{AsRawFd, RawFd}; - -use miette::{Context, Result}; -#[cfg(feature = "raspberry")] -use rppal::gpio::{Gpio, OutputPin}; -use serialport::{FlowControl, SerialPort, SerialPortInfo}; - -use crate::error::Error; - -#[cfg(unix)] -type Port = serialport::TTYPort; -#[cfg(windows)] -type Port = serialport::COMPort; - -/// Errors relating to the configuration of a serial port -#[derive(thiserror::Error, Debug)] -#[non_exhaustive] -pub enum SerialConfigError { - #[cfg(feature = "raspberry")] - #[error("You need to specify both DTR and RTS pins when using an internal UART peripheral")] - MissingDtrRtsForInternalUart, - #[cfg(feature = "raspberry")] - #[error("GPIO {0} is not available")] - GpioUnavailable(u8), -} - -/// Wrapper around SerialPort where platform-specific modifications can be -/// implemented. -pub struct Interface { - /// Hardware serial port used for communication - pub serial_port: Port, - /// Data Transmit Ready pin - #[cfg(feature = "raspberry")] - pub dtr: Option, - /// Ready To Send pin - #[cfg(feature = "raspberry")] - pub rts: Option, -} - -/// Set the level of a GPIO -#[cfg(feature = "raspberry")] -fn write_gpio(gpio: &mut OutputPin, level: bool) { - if level { - gpio.set_high(); - } else { - gpio.set_low(); - } -} - -/// Open a serial port -fn open_port(port_info: &SerialPortInfo) -> Result { - serialport::new(&port_info.port_name, 115_200) - .flow_control(FlowControl::None) - .open_native() - .map_err(Error::from) - .wrap_err_with(|| format!("Failed to open serial port {}", port_info.port_name)) -} - -impl Interface { - #[cfg(feature = "raspberry")] - pub fn new(port_info: &SerialPortInfo, dtr: Option, rts: Option) -> Result { - if port_info.port_type == serialport::SerialPortType::Unknown - && (dtr.is_none() || rts.is_none()) - { - // Assume internal UART, which has no DTR pin and usually no RTS either. - return Err(Error::from(SerialConfigError::MissingDtrRtsForInternalUart).into()); - } - - let gpios = Gpio::new().unwrap(); - - let rts = if let Some(gpio) = rts { - match gpios.get(gpio) { - Ok(pin) => Some(pin.into_output()), - Err(_) => return Err(Error::from(SerialConfigError::GpioUnavailable(gpio)).into()), - } - } else { - None - }; - - let dtr = if let Some(gpio) = dtr { - match gpios.get(gpio) { - Ok(pin) => Some(pin.into_output()), - Err(_) => return Err(Error::from(SerialConfigError::GpioUnavailable(gpio)).into()), - } - } else { - None - }; - - Ok(Self { - serial_port: open_port(port_info)?, - rts, - dtr, - }) - } - - #[cfg(not(feature = "raspberry"))] - pub fn new(port_info: &SerialPortInfo, _dtr: Option, _rts: Option) -> Result { - Ok(Self { - serial_port: open_port(port_info)?, - }) - } - - /// Set the level of the DTR pin - pub fn write_data_terminal_ready(&mut self, pin_state: bool) -> serialport::Result<()> { - #[cfg(feature = "raspberry")] - if let Some(gpio) = self.dtr.as_mut() { - write_gpio(gpio, pin_state); - return Ok(()); - } - - self.serial_port.write_data_terminal_ready(pin_state) - } - - /// Set the level of the RTS pin - pub fn write_request_to_send(&mut self, pin_state: bool) -> serialport::Result<()> { - #[cfg(feature = "raspberry")] - if let Some(gpio) = self.rts.as_mut() { - write_gpio(gpio, pin_state); - return Ok(()); - } - - self.serial_port.write_request_to_send(pin_state) - } - - /// Turn an [Interface] into a [SerialPort] - pub fn into_serial(self) -> Box { - Box::new(self.serial_port) - } - - /// Turn an [Interface] into a `&`[SerialPort] - pub fn serial_port(&self) -> &dyn SerialPort { - &self.serial_port - } - - /// Turn an [Interface] into a `&mut `[SerialPort] - pub fn serial_port_mut(&mut self) -> &mut dyn SerialPort { - &mut self.serial_port - } -} - -// Note(dbuga): this `impl` is necessary because using `dyn SerialPort` as `dyn -// Read` requires trait_upcasting which isn't stable yet. -impl Read for Interface { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - self.serial_port.read(buf) - } -} - -#[cfg(unix)] -impl AsRawFd for Interface { - fn as_raw_fd(&self) -> RawFd { - self.serial_port.as_raw_fd() - } -} diff --git a/espflash/src/lib.rs b/espflash/src/lib.rs index 5c4bf52b..07bf0e84 100644 --- a/espflash/src/lib.rs +++ b/espflash/src/lib.rs @@ -9,17 +9,6 @@ //! $ cargo binstall espflash //! ``` //! -//! Flashing via a Raspberry Pi's internal UART is also possible, however this -//! functionality is gated behind the `raspberry` feature; if you would like to -//! enable this simply enable the feature when installing: -//! -//! ```bash -//! $ cargo install espflash --feature=raspberry -//! ``` -//! -//! Note that this feature can only be enabled on a Raspberry Pi, as it depends -//! on the [rppal] package which will not build on most systems. -//! //! ## As a library //! //! [espflash] can also be used as a library: @@ -33,14 +22,6 @@ //! provide SemVer guarantees. You likely will not need any of these types or functions //! in your application so there's no use pulling in the extra dependencies. //! -//! Just like when using [espflash] as an application, you can enable the -//! `raspberry` feature to allow your dependent application to use the Raspberry -//! Pi's built-in UART: -//! -//! ```toml -//! espflash = { version = "2.1", default-features = false, features = ["raspberry"] } -//! ``` -//! //! [espflash]: https://crates.io/crates/espflash //! [cargo-binstall]: https://github.com/cargo-bins/cargo-binstall //! [rppal]: https://docs.rs/rppal/latest/rppal/ @@ -58,9 +39,6 @@ pub mod elf; pub mod error; pub mod flasher; pub mod image_format; -#[cfg(feature = "serialport")] -#[cfg_attr(docsrs, doc(cfg(feature = "serialport")))] -pub mod interface; pub mod targets; /// Logging utilities