From 6bd62613517430691c92937f1d4a6a5bb4785bdb Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Fri, 18 Aug 2023 15:08:30 -0700 Subject: [PATCH 01/10] Add command to erase flash. (For #460) --- espflash/src/bin/espflash.rs | 17 ++++++++++++++--- espflash/src/cli/mod.rs | 7 +++++++ espflash/src/flasher/mod.rs | 10 ++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index 429102c1..c909390d 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -10,15 +10,15 @@ use espflash::{ cli::{ self, board_info, completions, config::Config, connect, erase_partitions, flash_elf_image, monitor::monitor, parse_partition_table, partition_table, print_board_info, - save_elf_as_image, serial_monitor, CompletionsArgs, ConnectArgs, EspflashProgress, - FlashConfigArgs, MonitorArgs, PartitionTableArgs, + save_elf_as_image, serial_monitor, CompletionsArgs, ConnectArgs, EraseFlashArgs, + EspflashProgress, FlashConfigArgs, MonitorArgs, PartitionTableArgs, }, image_format::ImageFormatKind, logging::initialize_logger, targets::Chip, update::check_for_update, }; -use log::{debug, LevelFilter}; +use log::{debug, info, LevelFilter}; use miette::{IntoDiagnostic, Result, WrapErr}; #[derive(Debug, Parser)] @@ -42,6 +42,8 @@ enum Commands { /// depending on which shell is being used; consult your shell's /// documentation to determine the appropriate path. Completions(CompletionsArgs), + /// Erase Flash entirely + EraseFlash(EraseFlashArgs), /// Flash an application in ELF format to a connected target device /// /// Given a path to an ELF file, first convert it into the appropriate @@ -148,6 +150,7 @@ fn main() -> Result<()> { match args { Commands::BoardInfo(args) => board_info(&args, &config), Commands::Completions(args) => completions(&args, &mut Cli::command(), "espflash"), + Commands::EraseFlash(args) => erase_flash(args, &config), Commands::Flash(args) => flash(args, &config), Commands::Monitor(args) => serial_monitor(args, &config), Commands::PartitionTable(args) => partition_table(args), @@ -156,6 +159,14 @@ fn main() -> Result<()> { } } +fn erase_flash(args: EraseFlashArgs, config: &Config) -> Result<()> { + info!("Erasing Flash..."); + let mut flash = connect(&args.connect_args, config)?; + flash.erase_flash()?; + + Ok(()) +} + fn flash(args: FlashArgs, config: &Config) -> Result<()> { let mut flasher = connect(&args.connect_args, config)?; diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index 0354d617..34aa46fb 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -162,6 +162,13 @@ pub struct MonitorArgs { connect_args: ConnectArgs, } +#[derive(Debug, Args)] +pub struct EraseFlashArgs { + /// Connection configuration + #[clap(flatten)] + pub connect_args: ConnectArgs, +} + /// Select a serial port and establish a connection with a target device pub fn connect(args: &ConnectArgs, config: &Config) -> Result { let port_info = get_serial_port_info(args, config)?; diff --git a/espflash/src/flasher/mod.rs b/espflash/src/flasher/mod.rs index acff35f7..7f9f6482 100644 --- a/espflash/src/flasher/mod.rs +++ b/espflash/src/flasher/mod.rs @@ -864,6 +864,16 @@ impl Flasher { Ok(()) } + pub fn erase_flash(&mut self) -> Result<(), Error> { + self.connection + .with_timeout(CommandType::EraseFlash.timeout(), |connection| { + connection.command(Command::EraseFlash) + })?; + sleep(Duration::from_secs_f32(0.05)); + self.connection.flush()?; + Ok(()) + } + pub fn into_interface(self) -> Interface { self.connection.into_interface() } From 8ffe82f1cdeb5c0e174678d28a5d48fadfcb09ee Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Sun, 20 Aug 2023 08:24:31 -0700 Subject: [PATCH 02/10] Add `erase-parts` command to erase named partitions. --- espflash/src/bin/espflash.rs | 18 +++++++++++++++++- espflash/src/cli/mod.rs | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index c909390d..cce8b1f0 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -11,7 +11,7 @@ use espflash::{ self, board_info, completions, config::Config, connect, erase_partitions, flash_elf_image, monitor::monitor, parse_partition_table, partition_table, print_board_info, save_elf_as_image, serial_monitor, CompletionsArgs, ConnectArgs, EraseFlashArgs, - EspflashProgress, FlashConfigArgs, MonitorArgs, PartitionTableArgs, + ErasePartsArgs, EspflashProgress, FlashConfigArgs, MonitorArgs, PartitionTableArgs, }, image_format::ImageFormatKind, logging::initialize_logger, @@ -44,6 +44,8 @@ enum Commands { Completions(CompletionsArgs), /// Erase Flash entirely EraseFlash(EraseFlashArgs), + /// Erase specified partitions + EraseParts(ErasePartsArgs), /// Flash an application in ELF format to a connected target device /// /// Given a path to an ELF file, first convert it into the appropriate @@ -151,6 +153,7 @@ fn main() -> Result<()> { Commands::BoardInfo(args) => board_info(&args, &config), Commands::Completions(args) => completions(&args, &mut Cli::command(), "espflash"), Commands::EraseFlash(args) => erase_flash(args, &config), + Commands::EraseParts(args) => erase_parts(args, &config), Commands::Flash(args) => flash(args, &config), Commands::Monitor(args) => serial_monitor(args, &config), Commands::PartitionTable(args) => partition_table(args), @@ -167,6 +170,19 @@ fn erase_flash(args: EraseFlashArgs, config: &Config) -> Result<()> { Ok(()) } +fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { + let mut flash = connect(&args.connect_args, config)?; + let partition_table = parse_partition_table(&args.partition_table)?; + erase_partitions( + &mut flash, + Some(partition_table), + Some(args.erase_parts), + None, + )?; + + Ok(()) +} + fn flash(args: FlashArgs, config: &Config) -> Result<()> { let mut flasher = connect(&args.connect_args, config)?; diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index 34aa46fb..b08e593b 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -162,6 +162,7 @@ pub struct MonitorArgs { connect_args: ConnectArgs, } +/// Erase entire flash of target device #[derive(Debug, Args)] pub struct EraseFlashArgs { /// Connection configuration @@ -169,6 +170,21 @@ pub struct EraseFlashArgs { pub connect_args: ConnectArgs, } +/// Erase named partitions based on provided partition table +#[derive(Debug, Args)] +pub struct ErasePartsArgs { + /// Connection configuration + #[clap(flatten)] + pub connect_args: ConnectArgs, + + #[arg(value_name = "LABELS", value_delimiter = ',')] + pub erase_parts: Vec, + + /// Input partition table + #[arg(long, value_name = "FILE")] + pub partition_table: PathBuf, +} + /// Select a serial port and establish a connection with a target device pub fn connect(args: &ConnectArgs, config: &Config) -> Result { let port_info = get_serial_port_info(args, config)?; From 4b10c2b6eeee9c58bbac2d96fc3f8391a228a5b1 Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Sun, 20 Aug 2023 10:45:38 -0700 Subject: [PATCH 03/10] Fix timeout logic when erasing regions. --- espflash/src/flasher/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/espflash/src/flasher/mod.rs b/espflash/src/flasher/mod.rs index 7f9f6482..9a262324 100644 --- a/espflash/src/flasher/mod.rs +++ b/espflash/src/flasher/mod.rs @@ -855,10 +855,10 @@ impl Flasher { pub fn erase_region(&mut self, offset: u32, size: u32) -> Result<(), Error> { debug!("Erasing region of 0x{:x}B at 0x{:08x}", size, offset); - self.connection - .with_timeout(CommandType::EraseRegion.timeout(), |connection| { - connection.command(Command::EraseRegion { offset, size }) - })?; + self.connection.with_timeout( + CommandType::EraseRegion.timeout_for_size(size), + |connection| connection.command(Command::EraseRegion { offset, size }), + )?; std::thread::sleep(Duration::from_secs_f32(0.05)); self.connection.flush()?; Ok(()) From cd7a20ed97ce83ca0de9d1fe67fe2e28cb747867 Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Sat, 26 Aug 2023 09:07:26 -0700 Subject: [PATCH 04/10] Reset device after `erase_flash` or `erase_parts` commands. --- espflash/src/bin/espflash.rs | 1 + espflash/src/flasher/mod.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index cce8b1f0..0347cede 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -179,6 +179,7 @@ fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { Some(args.erase_parts), None, )?; + flash.connection().reset()?; Ok(()) } diff --git a/espflash/src/flasher/mod.rs b/espflash/src/flasher/mod.rs index 9a262324..f241451f 100644 --- a/espflash/src/flasher/mod.rs +++ b/espflash/src/flasher/mod.rs @@ -871,6 +871,9 @@ impl Flasher { })?; sleep(Duration::from_secs_f32(0.05)); self.connection.flush()?; + + self.connection.reset()?; + Ok(()) } From 069475772226e20c19a2292021b597ece544d8b7 Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Sat, 2 Sep 2023 13:44:01 -0700 Subject: [PATCH 05/10] Add support for `erase-region` subcommand. --- espflash/src/bin/espflash.rs | 20 +++++++++++++------- espflash/src/cli/mod.rs | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index 0347cede..8cb984f3 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -1,15 +1,15 @@ use std::{ fs::{self, File}, io::Read, - num::ParseIntError, path::PathBuf, }; use clap::{Args, CommandFactory, Parser, Subcommand}; +use espflash::cli::EraseRegionArgs; use espflash::{ cli::{ self, board_info, completions, config::Config, connect, erase_partitions, flash_elf_image, - monitor::monitor, parse_partition_table, partition_table, print_board_info, + monitor::monitor, parse_partition_table, parse_uint32, partition_table, print_board_info, save_elf_as_image, serial_monitor, CompletionsArgs, ConnectArgs, EraseFlashArgs, ErasePartsArgs, EspflashProgress, FlashConfigArgs, MonitorArgs, PartitionTableArgs, }, @@ -46,6 +46,8 @@ enum Commands { EraseFlash(EraseFlashArgs), /// Erase specified partitions EraseParts(ErasePartsArgs), + /// Erase specified region + EraseRegion(EraseRegionArgs), /// Flash an application in ELF format to a connected target device /// /// Given a path to an ELF file, first convert it into the appropriate @@ -125,11 +127,6 @@ struct WriteBinArgs { connect_args: ConnectArgs, } -/// Parses a string as a 32-bit unsigned integer. -fn parse_uint32(input: &str) -> Result { - parse_int::parse(input) -} - fn main() -> Result<()> { miette::set_panic_hook(); initialize_logger(LevelFilter::Info); @@ -154,6 +151,7 @@ fn main() -> Result<()> { Commands::Completions(args) => completions(&args, &mut Cli::command(), "espflash"), Commands::EraseFlash(args) => erase_flash(args, &config), Commands::EraseParts(args) => erase_parts(args, &config), + Commands::EraseRegion(args) => erase_region(args, &config), Commands::Flash(args) => flash(args, &config), Commands::Monitor(args) => serial_monitor(args, &config), Commands::PartitionTable(args) => partition_table(args), @@ -184,6 +182,14 @@ fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { Ok(()) } +fn erase_region(args: EraseRegionArgs, config: &Config) -> Result<()> { + let mut flash = connect(&args.connect_args, config)?; + flash.erase_region(args.addr, args.size)?; + flash.connection().reset()?; + + Ok(()) +} + fn flash(args: FlashArgs, config: &Config) -> Result<()> { let mut flasher = connect(&args.connect_args, config)?; diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index b08e593b..e755da2d 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -7,6 +7,7 @@ //! [cargo-espflash]: https://crates.io/crates/cargo-espflash //! [espflash]: https://crates.io/crates/espflash +use std::num::ParseIntError; use std::{ collections::HashMap, fs, @@ -185,6 +186,27 @@ pub struct ErasePartsArgs { pub partition_table: PathBuf, } +/// Erase specified region of flash +#[derive(Debug, Args)] +pub struct EraseRegionArgs { + /// Connection configuration + #[clap(flatten)] + pub connect_args: ConnectArgs, + + /// Offset to start erasing from + #[arg(value_name = "OFFSET", value_parser = parse_uint32)] + pub addr: u32, + + /// Size of the region to erase + #[arg(value_name = "SIZE", value_parser = parse_uint32)] + pub size: u32, +} + +/// Parses a string as a 32-bit unsigned integer. +pub fn parse_uint32(input: &str) -> Result { + parse_int::parse(input) +} + /// Select a serial port and establish a connection with a target device pub fn connect(args: &ConnectArgs, config: &Config) -> Result { let port_info = get_serial_port_info(args, config)?; From 5a10de81badbe7856c0d1fdc5d153ea66d7e49f2 Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Wed, 20 Sep 2023 08:12:54 -0700 Subject: [PATCH 06/10] Avoid changes to `cli/mod.rs` --- espflash/src/bin/espflash.rs | 52 +++++++++++++++++++++++++++++++++--- espflash/src/cli/mod.rs | 45 ------------------------------- 2 files changed, 48 insertions(+), 49 deletions(-) diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index 8cb984f3..273f36a0 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -1,17 +1,17 @@ use std::{ fs::{self, File}, io::Read, + num::ParseIntError, path::PathBuf, }; use clap::{Args, CommandFactory, Parser, Subcommand}; -use espflash::cli::EraseRegionArgs; use espflash::{ cli::{ self, board_info, completions, config::Config, connect, erase_partitions, flash_elf_image, - monitor::monitor, parse_partition_table, parse_uint32, partition_table, print_board_info, - save_elf_as_image, serial_monitor, CompletionsArgs, ConnectArgs, EraseFlashArgs, - ErasePartsArgs, EspflashProgress, FlashConfigArgs, MonitorArgs, PartitionTableArgs, + monitor::monitor, parse_partition_table, partition_table, print_board_info, + save_elf_as_image, serial_monitor, CompletionsArgs, ConnectArgs, EspflashProgress, + FlashConfigArgs, MonitorArgs, PartitionTableArgs, }, image_format::ImageFormatKind, logging::initialize_logger, @@ -84,6 +84,45 @@ enum Commands { WriteBin(WriteBinArgs), } +/// Erase entire flash of target device +#[derive(Debug, Args)] +pub struct EraseFlashArgs { + /// Connection configuration + #[clap(flatten)] + pub connect_args: ConnectArgs, +} + +/// Erase named partitions based on provided partition table +#[derive(Debug, Args)] +pub struct ErasePartsArgs { + /// Connection configuration + #[clap(flatten)] + pub connect_args: ConnectArgs, + + #[arg(value_name = "LABELS", value_delimiter = ',')] + pub erase_parts: Vec, + + /// Input partition table + #[arg(long, value_name = "FILE")] + pub partition_table: PathBuf, +} + +/// Erase specified region of flash +#[derive(Debug, Args)] +pub struct EraseRegionArgs { + /// Connection configuration + #[clap(flatten)] + pub connect_args: ConnectArgs, + + /// Offset to start erasing from + #[arg(value_name = "OFFSET", value_parser = parse_uint32)] + pub addr: u32, + + /// Size of the region to erase + #[arg(value_name = "SIZE", value_parser = parse_uint32)] + pub size: u32, +} + #[derive(Debug, Args)] struct FlashArgs { /// Connection configuration @@ -127,6 +166,11 @@ struct WriteBinArgs { connect_args: ConnectArgs, } +/// Parses a string as a 32-bit unsigned integer. +fn parse_uint32(input: &str) -> Result { + parse_int::parse(input) +} + fn main() -> Result<()> { miette::set_panic_hook(); initialize_logger(LevelFilter::Info); diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index e755da2d..0354d617 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -7,7 +7,6 @@ //! [cargo-espflash]: https://crates.io/crates/cargo-espflash //! [espflash]: https://crates.io/crates/espflash -use std::num::ParseIntError; use std::{ collections::HashMap, fs, @@ -163,50 +162,6 @@ pub struct MonitorArgs { connect_args: ConnectArgs, } -/// Erase entire flash of target device -#[derive(Debug, Args)] -pub struct EraseFlashArgs { - /// Connection configuration - #[clap(flatten)] - pub connect_args: ConnectArgs, -} - -/// Erase named partitions based on provided partition table -#[derive(Debug, Args)] -pub struct ErasePartsArgs { - /// Connection configuration - #[clap(flatten)] - pub connect_args: ConnectArgs, - - #[arg(value_name = "LABELS", value_delimiter = ',')] - pub erase_parts: Vec, - - /// Input partition table - #[arg(long, value_name = "FILE")] - pub partition_table: PathBuf, -} - -/// Erase specified region of flash -#[derive(Debug, Args)] -pub struct EraseRegionArgs { - /// Connection configuration - #[clap(flatten)] - pub connect_args: ConnectArgs, - - /// Offset to start erasing from - #[arg(value_name = "OFFSET", value_parser = parse_uint32)] - pub addr: u32, - - /// Size of the region to erase - #[arg(value_name = "SIZE", value_parser = parse_uint32)] - pub size: u32, -} - -/// Parses a string as a 32-bit unsigned integer. -pub fn parse_uint32(input: &str) -> Result { - parse_int::parse(input) -} - /// Select a serial port and establish a connection with a target device pub fn connect(args: &ConnectArgs, config: &Config) -> Result { let port_info = get_serial_port_info(args, config)?; From 8037dee791f458f5550e9879f61a082d247bfd48 Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Sun, 24 Sep 2023 12:20:41 -0700 Subject: [PATCH 07/10] Address PR comments. Add subcommands to `cargo-espflash` too. --- cargo-espflash/src/error.rs | 2 +- cargo-espflash/src/main.rs | 61 ++++++++++++++++++++++++++++- espflash/src/bin/espflash.rs | 76 +++++++++--------------------------- espflash/src/cli/mod.rs | 64 +++++++++++++++++++++++++++++- espflash/src/flasher/mod.rs | 4 +- 5 files changed, 143 insertions(+), 64 deletions(-) diff --git a/cargo-espflash/src/error.rs b/cargo-espflash/src/error.rs index df8e2b39..0afa8f92 100644 --- a/cargo-espflash/src/error.rs +++ b/cargo-espflash/src/error.rs @@ -54,7 +54,7 @@ pub enum Error { #[error("No package could be located in the current workspace")] #[diagnostic( code(cargo_espflash::no_package), - help("Ensure that you are executing from a valid package, and that the specified package name\ + help("Ensure that you are executing from a valid package, and that the specified package name \ exists in the current workspace.") )] NoPackage, diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index a7daba94..f327f67e 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -6,6 +6,7 @@ use std::{ use cargo_metadata::Message; use clap::{Args, CommandFactory, Parser, Subcommand}; +use espflash::cli::{erase_flash, erase_region, EraseFlashArgs, EraseRegionArgs}; use espflash::{ cli::{ self, board_info, completions, config::Config, connect, erase_partitions, flash_elf_image, @@ -18,8 +19,8 @@ use espflash::{ targets::Chip, update::check_for_update, }; -use log::{debug, LevelFilter}; -use miette::{IntoDiagnostic, Result, WrapErr}; +use log::{debug, info, LevelFilter}; +use miette::{bail, IntoDiagnostic, Result, WrapErr}; use crate::{ cargo_config::CargoConfig, @@ -66,6 +67,12 @@ enum Commands { /// depending on which shell is being used; consult your shell's /// documentation to determine the appropriate path. Completions(CompletionsArgs), + /// Erase Flash entirely + EraseFlash(EraseFlashArgs), + /// Erase specified partitions + EraseParts(ErasePartsArgs), + /// Erase specified region + EraseRegion(EraseRegionArgs), /// Flash an application in ELF format to a target device /// /// First convert the ELF file produced by cargo into the appropriate @@ -137,6 +144,26 @@ struct BuildArgs { pub flash_config_args: FlashConfigArgs, } +/// Erase named partitions based on provided partition table +#[derive(Debug, Args)] +pub struct ErasePartsArgs { + /// Connection configuration + #[clap(flatten)] + pub connect_args: ConnectArgs, + + /// Labels of the partitions to be erased + #[arg(value_name = "LABELS", value_delimiter = ',')] + pub erase_parts: Vec, + + /// Input partition table + #[arg(long, value_name = "FILE")] + pub partition_table: Option, + + /// Specify a (binary) package within a workspace which may provide a partition table + #[arg(long)] + pub package: Option, +} + /// Build and flash an application to a target device #[derive(Debug, Args)] struct FlashArgs { @@ -182,6 +209,9 @@ fn main() -> Result<()> { match args { Commands::BoardInfo(args) => board_info(&args, &config), Commands::Completions(args) => completions(&args, &mut Cli::command(), "cargo"), + Commands::EraseFlash(args) => erase_flash(args, &config), + Commands::EraseParts(args) => erase_parts(args, &config), + Commands::EraseRegion(args) => erase_region(args, &config), Commands::Flash(args) => flash(args, &config), Commands::Monitor(args) => serial_monitor(args, &config), Commands::PartitionTable(args) => partition_table(args), @@ -196,6 +226,33 @@ struct BuildContext { pub partition_table_path: Option, } +pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { + if args.connect_args.no_stub { + bail!("Cannot erase flash without the RAM stub") + } + + let metadata_partition_table = PackageMetadata::load(&args.package) + .ok() + .and_then(|m| m.partition_table); + + let partition_table = args + .partition_table + .as_deref() + .or(metadata_partition_table.as_deref()); + + let mut flash = connect(&args.connect_args, config)?; + let partition_table = match partition_table { + Some(path) => Some(parse_partition_table(&path)?), + None => None, + }; + + info!("Erasing the following partitions: {:?}", args.erase_parts); + erase_partitions(&mut flash, partition_table, Some(args.erase_parts), None)?; + flash.connection().reset()?; + + Ok(()) +} + fn flash(args: FlashArgs, config: &Config) -> Result<()> { let metadata = PackageMetadata::load(&args.build_args.package)?; let cargo_config = CargoConfig::load(&metadata.workspace_root, &metadata.package_root); diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index 273f36a0..14183f73 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -1,17 +1,17 @@ use std::{ fs::{self, File}, io::Read, - num::ParseIntError, path::PathBuf, }; use clap::{Args, CommandFactory, Parser, Subcommand}; +use espflash::cli::{EraseFlashArgs, EraseRegionArgs}; use espflash::{ cli::{ - self, board_info, completions, config::Config, connect, erase_partitions, flash_elf_image, - monitor::monitor, parse_partition_table, partition_table, print_board_info, - save_elf_as_image, serial_monitor, CompletionsArgs, ConnectArgs, EspflashProgress, - FlashConfigArgs, MonitorArgs, PartitionTableArgs, + self, board_info, completions, config::Config, connect, erase_flash, erase_partitions, + erase_region, flash_elf_image, monitor::monitor, parse_partition_table, parse_uint32, + partition_table, print_board_info, save_elf_as_image, serial_monitor, CompletionsArgs, + ConnectArgs, EspflashProgress, FlashConfigArgs, MonitorArgs, PartitionTableArgs, }, image_format::ImageFormatKind, logging::initialize_logger, @@ -19,7 +19,7 @@ use espflash::{ update::check_for_update, }; use log::{debug, info, LevelFilter}; -use miette::{IntoDiagnostic, Result, WrapErr}; +use miette::{bail, IntoDiagnostic, Result, WrapErr}; #[derive(Debug, Parser)] #[command(about, max_term_width = 100, propagate_version = true, version)] @@ -84,14 +84,6 @@ enum Commands { WriteBin(WriteBinArgs), } -/// Erase entire flash of target device -#[derive(Debug, Args)] -pub struct EraseFlashArgs { - /// Connection configuration - #[clap(flatten)] - pub connect_args: ConnectArgs, -} - /// Erase named partitions based on provided partition table #[derive(Debug, Args)] pub struct ErasePartsArgs { @@ -99,28 +91,13 @@ pub struct ErasePartsArgs { #[clap(flatten)] pub connect_args: ConnectArgs, + /// Labels of the partitions to be erased #[arg(value_name = "LABELS", value_delimiter = ',')] pub erase_parts: Vec, /// Input partition table #[arg(long, value_name = "FILE")] - pub partition_table: PathBuf, -} - -/// Erase specified region of flash -#[derive(Debug, Args)] -pub struct EraseRegionArgs { - /// Connection configuration - #[clap(flatten)] - pub connect_args: ConnectArgs, - - /// Offset to start erasing from - #[arg(value_name = "OFFSET", value_parser = parse_uint32)] - pub addr: u32, - - /// Size of the region to erase - #[arg(value_name = "SIZE", value_parser = parse_uint32)] - pub size: u32, + pub partition_table: Option, } #[derive(Debug, Args)] @@ -166,11 +143,6 @@ struct WriteBinArgs { connect_args: ConnectArgs, } -/// Parses a string as a 32-bit unsigned integer. -fn parse_uint32(input: &str) -> Result { - parse_int::parse(input) -} - fn main() -> Result<()> { miette::set_panic_hook(); initialize_logger(LevelFilter::Info); @@ -204,31 +176,19 @@ fn main() -> Result<()> { } } -fn erase_flash(args: EraseFlashArgs, config: &Config) -> Result<()> { - info!("Erasing Flash..."); - let mut flash = connect(&args.connect_args, config)?; - flash.erase_flash()?; - - Ok(()) -} +pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { + if args.connect_args.no_stub { + bail!("Cannot erase flash without the RAM stub") + } -fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { let mut flash = connect(&args.connect_args, config)?; - let partition_table = parse_partition_table(&args.partition_table)?; - erase_partitions( - &mut flash, - Some(partition_table), - Some(args.erase_parts), - None, - )?; - flash.connection().reset()?; + let partition_table = match args.partition_table { + Some(path) => Some(parse_partition_table(&path)?), + None => None, + }; - Ok(()) -} - -fn erase_region(args: EraseRegionArgs, config: &Config) -> Result<()> { - let mut flash = connect(&args.connect_args, config)?; - flash.erase_region(args.addr, args.size)?; + info!("Erasing the following partitions: {:?}", args.erase_parts); + erase_partitions(&mut flash, partition_table, Some(args.erase_parts), None)?; flash.connection().reset()?; Ok(()) diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index 0354d617..95e715d8 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -7,6 +7,7 @@ //! [cargo-espflash]: https://crates.io/crates/cargo-espflash //! [espflash]: https://crates.io/crates/espflash +use std::num::ParseIntError; use std::{ collections::HashMap, fs, @@ -20,7 +21,7 @@ use comfy_table::{modifiers, presets::UTF8_FULL, Attribute, Cell, Color, Table}; use esp_idf_part::{DataType, Partition, PartitionTable}; use indicatif::{style::ProgressStyle, HumanCount, ProgressBar}; use log::{debug, info}; -use miette::{IntoDiagnostic, Result, WrapErr}; +use miette::{bail, IntoDiagnostic, Result, WrapErr}; use serialport::{SerialPortType, UsbPortInfo}; use self::{config::Config, monitor::monitor, serial::get_serial_port_info}; @@ -67,6 +68,30 @@ pub struct CompletionsArgs { pub shell: Shell, } +/// Erase entire flash of target device +#[derive(Debug, Args)] +pub struct EraseFlashArgs { + /// Connection configuration + #[clap(flatten)] + pub connect_args: ConnectArgs, +} + +/// Erase specified region of flash +#[derive(Debug, Args)] +pub struct EraseRegionArgs { + /// Connection configuration + #[clap(flatten)] + pub connect_args: ConnectArgs, + + /// Offset to start erasing from + #[arg(value_name = "OFFSET", value_parser = parse_uint32)] + pub addr: u32, + + /// Size of the region to erase + #[arg(value_name = "SIZE", value_parser = parse_uint32)] + pub size: u32, +} + /// Configure communication with the target device's flash #[derive(Debug, Args)] pub struct FlashConfigArgs { @@ -445,6 +470,38 @@ impl ProgressCallbacks for EspflashProgress { } } +pub fn erase_flash(args: EraseFlashArgs, config: &Config) -> Result<()> { + if args.connect_args.no_stub { + bail!("Cannot erase flash without the RAM stub") + } + + let mut flash = connect(&args.connect_args, config)?; + + info!("Erasing Flash..."); + flash.erase_flash()?; + + flash.connection().reset()?; + + Ok(()) +} + +pub fn erase_region(args: EraseRegionArgs, config: &Config) -> Result<()> { + if args.connect_args.no_stub { + bail!("Cannot erase flash without the RAM stub") + } + + let mut flash = connect(&args.connect_args, config)?; + + info!( + "Erasing region at 0x{:08x} ({} bytes)", + args.addr, args.size + ); + flash.erase_region(args.addr, args.size)?; + flash.connection().reset()?; + + Ok(()) +} + /// Write an ELF image to a target device's flash pub fn flash_elf_image( flasher: &mut Flasher, @@ -637,3 +694,8 @@ fn pretty_print(table: PartitionTable) { println!("{pretty}"); } + +/// Parses a string as a 32-bit unsigned integer. +pub fn parse_uint32(input: &str) -> Result { + parse_int::parse(input) +} diff --git a/espflash/src/flasher/mod.rs b/espflash/src/flasher/mod.rs index f241451f..7399dd69 100644 --- a/espflash/src/flasher/mod.rs +++ b/espflash/src/flasher/mod.rs @@ -865,6 +865,8 @@ impl Flasher { } pub fn erase_flash(&mut self) -> Result<(), Error> { + debug!("Erasing the entire flash"); + self.connection .with_timeout(CommandType::EraseFlash.timeout(), |connection| { connection.command(Command::EraseFlash) @@ -872,8 +874,6 @@ impl Flasher { sleep(Duration::from_secs_f32(0.05)); self.connection.flush()?; - self.connection.reset()?; - Ok(()) } From e19ff23c5660376ed2740979e2ab25e2fcf4f1fd Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Sun, 24 Sep 2023 16:42:02 -0700 Subject: [PATCH 08/10] Fix clippy violation. --- cargo-espflash/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index f327f67e..f129eaac 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -242,7 +242,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { let mut flash = connect(&args.connect_args, config)?; let partition_table = match partition_table { - Some(path) => Some(parse_partition_table(&path)?), + Some(path) => Some(parse_partition_table(path)?), None => None, }; From 22d792ada3795ae0ce284b7e530aba89856b9de3 Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Thu, 28 Sep 2023 22:00:38 -0700 Subject: [PATCH 09/10] Factor out error for erase failure when `--no-stub` is specified. --- cargo-espflash/src/main.rs | 5 +++-- espflash/src/bin/espflash.rs | 9 +++++---- espflash/src/cli/mod.rs | 8 ++++---- espflash/src/error.rs | 7 +++++++ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index f129eaac..e639edd7 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -14,13 +14,14 @@ use espflash::{ save_elf_as_image, serial_monitor, CompletionsArgs, ConnectArgs, EspflashProgress, FlashConfigArgs, MonitorArgs, PartitionTableArgs, }, + error::Error as EspflashError, image_format::ImageFormatKind, logging::initialize_logger, targets::Chip, update::check_for_update, }; use log::{debug, info, LevelFilter}; -use miette::{bail, IntoDiagnostic, Result, WrapErr}; +use miette::{IntoDiagnostic, Result, WrapErr}; use crate::{ cargo_config::CargoConfig, @@ -228,7 +229,7 @@ struct BuildContext { pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { if args.connect_args.no_stub { - bail!("Cannot erase flash without the RAM stub") + return Err(EspflashError::StubRequiredToEraseFlash).into_diagnostic(); } let metadata_partition_table = PackageMetadata::load(&args.package) diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index 14183f73..e95cde63 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -5,21 +5,22 @@ use std::{ }; use clap::{Args, CommandFactory, Parser, Subcommand}; -use espflash::cli::{EraseFlashArgs, EraseRegionArgs}; use espflash::{ cli::{ self, board_info, completions, config::Config, connect, erase_flash, erase_partitions, erase_region, flash_elf_image, monitor::monitor, parse_partition_table, parse_uint32, partition_table, print_board_info, save_elf_as_image, serial_monitor, CompletionsArgs, - ConnectArgs, EspflashProgress, FlashConfigArgs, MonitorArgs, PartitionTableArgs, + ConnectArgs, EraseFlashArgs, EraseRegionArgs, EspflashProgress, FlashConfigArgs, + MonitorArgs, PartitionTableArgs, }, + error::Error, image_format::ImageFormatKind, logging::initialize_logger, targets::Chip, update::check_for_update, }; use log::{debug, info, LevelFilter}; -use miette::{bail, IntoDiagnostic, Result, WrapErr}; +use miette::{IntoDiagnostic, Result, WrapErr}; #[derive(Debug, Parser)] #[command(about, max_term_width = 100, propagate_version = true, version)] @@ -178,7 +179,7 @@ fn main() -> Result<()> { pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { if args.connect_args.no_stub { - bail!("Cannot erase flash without the RAM stub") + return Err(Error::StubRequiredToEraseFlash).into_diagnostic(); } let mut flash = connect(&args.connect_args, config)?; diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index 95e715d8..6377d4bd 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -21,13 +21,13 @@ use comfy_table::{modifiers, presets::UTF8_FULL, Attribute, Cell, Color, Table}; use esp_idf_part::{DataType, Partition, PartitionTable}; use indicatif::{style::ProgressStyle, HumanCount, ProgressBar}; use log::{debug, info}; -use miette::{bail, IntoDiagnostic, Result, WrapErr}; +use miette::{IntoDiagnostic, Result, WrapErr}; use serialport::{SerialPortType, UsbPortInfo}; use self::{config::Config, monitor::monitor, serial::get_serial_port_info}; use crate::{ elf::ElfFirmwareImage, - error::{MissingPartition, MissingPartitionTable}, + error::{Error, MissingPartition, MissingPartitionTable}, flasher::{FlashFrequency, FlashMode, FlashSize, Flasher, ProgressCallbacks}, image_format::ImageFormatKind, interface::Interface, @@ -472,7 +472,7 @@ impl ProgressCallbacks for EspflashProgress { pub fn erase_flash(args: EraseFlashArgs, config: &Config) -> Result<()> { if args.connect_args.no_stub { - bail!("Cannot erase flash without the RAM stub") + return Err(Error::StubRequiredToEraseFlash).into_diagnostic(); } let mut flash = connect(&args.connect_args, config)?; @@ -487,7 +487,7 @@ pub fn erase_flash(args: EraseFlashArgs, config: &Config) -> Result<()> { pub fn erase_region(args: EraseRegionArgs, config: &Config) -> Result<()> { if args.connect_args.no_stub { - bail!("Cannot erase flash without the RAM stub") + return Err(Error::StubRequiredToEraseFlash).into_diagnostic(); } let mut flash = connect(&args.connect_args, config)?; diff --git a/espflash/src/error.rs b/espflash/src/error.rs index a5169930..2d7a6b18 100644 --- a/espflash/src/error.rs +++ b/espflash/src/error.rs @@ -83,6 +83,13 @@ pub enum Error { )] NoSerial, + #[error("Cannot erase flash without the RAM stub")] + #[diagnostic( + code(espflash::stub_required_to_erase_flash), + help("Don't use the `--no-ram-stub` option with `erase` commands") + )] + StubRequiredToEraseFlash, + #[error("Incorrect serial port configuration")] #[diagnostic( code(espflash::serial_config), From 29fc25cfa474febd9f0c8767e4ee25a99b402b0a Mon Sep 17 00:00:00 2001 From: Joseph Ross Date: Fri, 29 Sep 2023 07:12:33 -0700 Subject: [PATCH 10/10] Improve guidance around StubRequiredToEraseFlash Co-authored-by: Sergio Gasquez Arcos --- espflash/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/espflash/src/error.rs b/espflash/src/error.rs index 2d7a6b18..133b7e08 100644 --- a/espflash/src/error.rs +++ b/espflash/src/error.rs @@ -83,10 +83,10 @@ pub enum Error { )] NoSerial, - #[error("Cannot erase flash without the RAM stub")] + #[error("Erase commands require using the RAM stub")] #[diagnostic( code(espflash::stub_required_to_erase_flash), - help("Don't use the `--no-ram-stub` option with `erase` commands") + help("Don't use the `--no-stub` option with erase commands") )] StubRequiredToEraseFlash,