From 77fd5b4417b6e2ab840fca0b9b6f33cead9608dc Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Arcos Date: Thu, 21 Dec 2023 14:32:47 +0100 Subject: [PATCH] Add `min_chip_rev` argument (#525) * Verify the minimum supported chip revision when flashing * Allow specifying a minimum chip revision when saving an image * feat: Use value parser * docs: Update chip revision docstring * feat: Update default value of mon_chip_rev --------- Co-authored-by: Jesse Braham --- cargo-espflash/src/main.rs | 3 ++ espflash/src/bin/espflash.rs | 3 ++ espflash/src/cli/mod.rs | 41 +++++++++++++++++++++ espflash/src/error.rs | 15 ++++++++ espflash/src/flasher/mod.rs | 19 ++++++++++ espflash/src/image_format/idf_bootloader.rs | 3 ++ espflash/src/image_format/mod.rs | 2 +- espflash/src/targets/esp32.rs | 2 + espflash/src/targets/esp32c2.rs | 2 + espflash/src/targets/esp32c3.rs | 2 + espflash/src/targets/esp32c6.rs | 2 + espflash/src/targets/esp32h2.rs | 2 + espflash/src/targets/esp32s2.rs | 2 + espflash/src/targets/esp32s3.rs | 2 + espflash/src/targets/esp8266.rs | 1 + espflash/src/targets/mod.rs | 1 + 16 files changed, 101 insertions(+), 1 deletion(-) diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index a33f43a6..67664caa 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -259,6 +259,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> { let cargo_config = CargoConfig::load(&metadata.workspace_root, &metadata.package_root); let mut flasher = connect(&args.connect_args, config)?; + flasher.verify_minimum_revision(args.flash_args.min_chip_rev)?; // If the user has provided a flash size via a command-line argument, we'll // override the detected (or default) value with this. @@ -329,6 +330,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> { args.build_args.flash_config_args.flash_size, args.build_args.flash_config_args.flash_freq, args.flash_args.partition_table_offset, + args.flash_args.min_chip_rev, )?; } @@ -556,6 +558,7 @@ fn save_image(args: SaveImageArgs) -> Result<()> { save_elf_as_image( args.save_image_args.chip, + args.save_image_args.min_chip_rev, &elf_data, args.save_image_args.file, args.format.or(metadata.format), diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index 3488a242..436bf48a 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -199,6 +199,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> { fn flash(args: FlashArgs, config: &Config) -> Result<()> { let mut flasher = connect(&args.connect_args, config)?; + flasher.verify_minimum_revision(args.flash_args.min_chip_rev)?; // If the user has provided a flash size via a command-line argument, we'll // override the detected (or default) value with this. @@ -253,6 +254,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> { args.flash_config_args.flash_size, args.flash_config_args.flash_freq, args.flash_args.partition_table_offset, + args.flash_args.min_chip_rev, )?; } @@ -301,6 +303,7 @@ fn save_image(args: SaveImageArgs) -> Result<()> { save_elf_as_image( args.save_image_args.chip, + args.save_image_args.min_chip_rev, &elf_data, args.save_image_args.file, args.format, diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index 3a2aad94..4c3d959e 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -142,6 +142,9 @@ pub struct FlashArgs { /// Logging format. #[arg(long, short = 'L', default_value = "serial", requires = "monitor")] pub log_format: LogFormat, + /// Minimum chip revision supported by image, in format: major.minor + #[arg(long, default_value = "0.0", value_parser = parse_chip_rev)] + pub min_chip_rev: u16, /// Open a serial monitor after flashing #[arg(short = 'M', long)] pub monitor: bool, @@ -193,6 +196,9 @@ pub struct SaveImageArgs { pub chip: Chip, /// File name to save the generated image to pub file: PathBuf, + /// Minimum chip revision supported by image, in format: major.minor + #[arg(long, default_value = "0.0", value_parser = parse_chip_rev)] + pub min_chip_rev: u16, /// Boolean flag to merge binaries into single binary #[arg(long)] pub merge: bool, @@ -285,6 +291,36 @@ pub fn completions(args: &CompletionsArgs, app: &mut clap::Command, bin_name: &s Ok(()) } +/// Parses chip revision from string to major * 100 + minor format +pub fn parse_chip_rev(chip_rev: &str) -> Result { + let mut split = chip_rev.split('.'); + + let parse_or_error = |value: Option<&str>| { + value + .ok_or_else(|| Error::ParseChipRevError { + chip_rev: chip_rev.to_string(), + }) + .and_then(|v| { + v.parse::().map_err(|_| Error::ParseChipRevError { + chip_rev: chip_rev.to_string(), + }) + }) + .into_diagnostic() + }; + + let major = parse_or_error(split.next())?; + let minor = parse_or_error(split.next())?; + + if split.next().is_some() { + return Err(Error::ParseChipRevError { + chip_rev: chip_rev.to_string(), + }) + .into_diagnostic(); + } + + Ok(major * 100 + minor) +} + /// Print information about a chip pub fn print_board_info(flasher: &mut Flasher) -> Result<()> { let info = flasher.device_info()?; @@ -342,6 +378,7 @@ pub fn serial_monitor(args: MonitorArgs, config: &Config) -> Result<()> { /// Convert the provided firmware image from ELF to binary pub fn save_elf_as_image( chip: Chip, + min_rev_full: u16, elf_data: &[u8], image_path: PathBuf, image_format: Option, @@ -397,6 +434,7 @@ pub fn save_elf_as_image( target_app_partition, image_format, None, + min_rev_full, flash_mode, flash_size, flash_freq, @@ -439,6 +477,7 @@ pub fn save_elf_as_image( None, image_format, None, + min_rev_full, flash_mode, flash_size, flash_freq, @@ -557,6 +596,7 @@ pub fn flash_elf_image( flash_size: Option, flash_freq: Option, partition_table_offset: Option, + min_rev_full: u16, ) -> Result<()> { // If the '--bootloader' option is provided, load the binary file at the // specified path. @@ -581,6 +621,7 @@ pub fn flash_elf_image( flash_size, flash_freq, partition_table_offset, + min_rev_full, Some(&mut EspflashProgress::default()), )?; info!("Flashing has completed!"); diff --git a/espflash/src/error.rs b/espflash/src/error.rs index 61bee7be..178e63fe 100644 --- a/espflash/src/error.rs +++ b/espflash/src/error.rs @@ -138,6 +138,21 @@ pub enum Error { frequency: FlashFrequency, }, + #[error( + "Minimum supported revision is {major}.{minor}, connected device's revision is {found_major}.{found_minor}" + )] + #[diagnostic(code(espflash::unsupported_chip_revision))] + UnsupportedChipRevision { + major: u16, + minor: u16, + found_major: u16, + found_minor: u16, + }, + + #[error("Failed to parse chip revision: {chip_rev}. Chip revision must be in the format `major.minor`")] + #[diagnostic(code(espflash::cli::parse_chip_rev_error))] + ParseChipRevError { chip_rev: String }, + #[error("Error while connecting to device")] #[diagnostic(transparent)] Connection(#[source] ConnectionError), diff --git a/espflash/src/flasher/mod.rs b/espflash/src/flasher/mod.rs index 2d369ebe..acaa6aaf 100644 --- a/espflash/src/flasher/mod.rs +++ b/espflash/src/flasher/mod.rs @@ -809,6 +809,7 @@ impl Flasher { flash_size: Option, flash_freq: Option, partition_table_offset: Option, + min_rev_full: u16, mut progress: Option<&mut dyn ProgressCallbacks>, ) -> Result<(), Error> { let image = ElfFirmwareImage::try_from(elf_data)?; @@ -835,6 +836,7 @@ impl Flasher { target_app_partition, image_format, chip_revision, + min_rev_full, flash_mode, flash_size.or(Some(self.flash_size)), flash_freq, @@ -897,6 +899,7 @@ impl Flasher { flash_size: Option, flash_freq: Option, partition_table_offset: Option, + min_rev_full: u16, progress: Option<&mut dyn ProgressCallbacks>, ) -> Result<(), Error> { self.load_elf_to_flash_with_format( @@ -909,6 +912,7 @@ impl Flasher { flash_size, flash_freq, partition_table_offset, + min_rev_full, progress, ) } @@ -976,6 +980,21 @@ impl Flasher { Ok(()) } + pub fn verify_minimum_revision(&mut self, minimum: u16) -> Result<(), Error> { + let (major, minor) = self.chip.into_target().chip_revision(self.connection())?; + let revision = (major * 100 + minor) as u16; + if revision < minimum { + return Err(Error::UnsupportedChipRevision { + major: minimum / 100, + minor: minimum % 100, + found_major: revision / 100, + found_minor: revision % 100, + }); + } + + Ok(()) + } + pub fn into_interface(self) -> Interface { self.connection.into_interface() } diff --git a/espflash/src/image_format/idf_bootloader.rs b/espflash/src/image_format/idf_bootloader.rs index d76cb787..9ff393ec 100644 --- a/espflash/src/image_format/idf_bootloader.rs +++ b/espflash/src/image_format/idf_bootloader.rs @@ -34,6 +34,7 @@ impl<'a> IdfBootloaderFormat<'a> { pub fn new( image: &'a dyn FirmwareImage<'a>, chip: Chip, + min_rev_full: u16, params: Esp32Params, partition_table: Option, target_app_partition: Option, @@ -80,6 +81,7 @@ impl<'a> IdfBootloaderFormat<'a> { header.wp_pin = WP_PIN_DISABLED; header.chip_id = params.chip_id; + header.min_chip_rev_full = min_rev_full; header.append_digest = 1; let mut data = bytes_of(&header).to_vec(); @@ -364,6 +366,7 @@ pub mod tests { let flash_image = IdfBootloaderFormat::new( &image, Chip::Esp32, + 0, PARAMS, None, None, diff --git a/espflash/src/image_format/mod.rs b/espflash/src/image_format/mod.rs index 5a41bdc8..ade8c666 100644 --- a/espflash/src/image_format/mod.rs +++ b/espflash/src/image_format/mod.rs @@ -56,7 +56,7 @@ struct ImageHeader { gd_wp_drv: u8, chip_id: u16, min_rev: u8, - /// Minimal chip revision supported by image, in format: major * 100 + minor + /// Minimum chip revision supported by image, in format: major * 100 + minor min_chip_rev_full: u16, /// Maximal chip revision supported by image, in format: major * 100 + minor max_chip_rev_full: u16, diff --git a/espflash/src/targets/esp32.rs b/espflash/src/targets/esp32.rs index c0ecee11..bbcee321 100644 --- a/espflash/src/targets/esp32.rs +++ b/espflash/src/targets/esp32.rs @@ -158,6 +158,7 @@ impl Target for Esp32 { target_app_partition: Option, image_format: Option, _chip_revision: Option<(u32, u32)>, + min_rev_full: u16, flash_mode: Option, flash_size: Option, flash_freq: Option, @@ -169,6 +170,7 @@ impl Target for Esp32 { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, Chip::Esp32, + min_rev_full, PARAMS, partition_table, target_app_partition, diff --git a/espflash/src/targets/esp32c2.rs b/espflash/src/targets/esp32c2.rs index a0142ce9..da12bf62 100644 --- a/espflash/src/targets/esp32c2.rs +++ b/espflash/src/targets/esp32c2.rs @@ -92,6 +92,7 @@ impl Target for Esp32c2 { target_app_partition: Option, image_format: Option, _chip_revision: Option<(u32, u32)>, + min_rev_full: u16, flash_mode: Option, flash_size: Option, flash_freq: Option, @@ -103,6 +104,7 @@ impl Target for Esp32c2 { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, Chip::Esp32c2, + min_rev_full, PARAMS, partition_table, target_app_partition, diff --git a/espflash/src/targets/esp32c3.rs b/espflash/src/targets/esp32c3.rs index 83d2a548..3ec97f04 100644 --- a/espflash/src/targets/esp32c3.rs +++ b/espflash/src/targets/esp32c3.rs @@ -79,6 +79,7 @@ impl Target for Esp32c3 { target_app_partition: Option, image_format: Option, chip_revision: Option<(u32, u32)>, + min_rev_full: u16, flash_mode: Option, flash_size: Option, flash_freq: Option, @@ -90,6 +91,7 @@ impl Target for Esp32c3 { (ImageFormatKind::EspBootloader, _) => Ok(Box::new(IdfBootloaderFormat::new( image, Chip::Esp32c3, + min_rev_full, PARAMS, partition_table, target_app_partition, diff --git a/espflash/src/targets/esp32c6.rs b/espflash/src/targets/esp32c6.rs index 6c6da22e..dd624bb0 100644 --- a/espflash/src/targets/esp32c6.rs +++ b/espflash/src/targets/esp32c6.rs @@ -76,6 +76,7 @@ impl Target for Esp32c6 { target_app_partition: Option, image_format: Option, _chip_revision: Option<(u32, u32)>, + min_rev_full: u16, flash_mode: Option, flash_size: Option, flash_freq: Option, @@ -87,6 +88,7 @@ impl Target for Esp32c6 { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, Chip::Esp32c6, + min_rev_full, PARAMS, partition_table, target_app_partition, diff --git a/espflash/src/targets/esp32h2.rs b/espflash/src/targets/esp32h2.rs index a0e58fd6..81a7523b 100644 --- a/espflash/src/targets/esp32h2.rs +++ b/espflash/src/targets/esp32h2.rs @@ -84,6 +84,7 @@ impl Target for Esp32h2 { target_app_partition: Option, image_format: Option, _chip_revision: Option<(u32, u32)>, + min_rev_full: u16, flash_mode: Option, flash_size: Option, flash_freq: Option, @@ -95,6 +96,7 @@ impl Target for Esp32h2 { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, Chip::Esp32h2, + min_rev_full, PARAMS, partition_table, target_app_partition, diff --git a/espflash/src/targets/esp32s2.rs b/espflash/src/targets/esp32s2.rs index 47c19123..822bccc9 100644 --- a/espflash/src/targets/esp32s2.rs +++ b/espflash/src/targets/esp32s2.rs @@ -144,6 +144,7 @@ impl Target for Esp32s2 { target_app_partition: Option, image_format: Option, _chip_revision: Option<(u32, u32)>, + min_rev_full: u16, flash_mode: Option, flash_size: Option, flash_freq: Option, @@ -155,6 +156,7 @@ impl Target for Esp32s2 { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, Chip::Esp32s2, + min_rev_full, PARAMS, partition_table, target_app_partition, diff --git a/espflash/src/targets/esp32s3.rs b/espflash/src/targets/esp32s3.rs index 14dc01a0..08d0b722 100644 --- a/espflash/src/targets/esp32s3.rs +++ b/espflash/src/targets/esp32s3.rs @@ -98,6 +98,7 @@ impl Target for Esp32s3 { target_app_partition: Option, image_format: Option, _chip_revision: Option<(u32, u32)>, + min_rev_full: u16, flash_mode: Option, flash_size: Option, flash_freq: Option, @@ -109,6 +110,7 @@ impl Target for Esp32s3 { ImageFormatKind::EspBootloader => Ok(Box::new(IdfBootloaderFormat::new( image, Chip::Esp32s3, + min_rev_full, PARAMS, partition_table, target_app_partition, diff --git a/espflash/src/targets/esp8266.rs b/espflash/src/targets/esp8266.rs index 83be5be9..1b03ddd0 100644 --- a/espflash/src/targets/esp8266.rs +++ b/espflash/src/targets/esp8266.rs @@ -78,6 +78,7 @@ impl Target for Esp8266 { _target_app_partition: Option, image_format: Option, _chip_revision: Option<(u32, u32)>, + _min_rev_full: u16, flash_mode: Option, flash_size: Option, flash_freq: Option, diff --git a/espflash/src/targets/mod.rs b/espflash/src/targets/mod.rs index 127d9ea6..06143a35 100644 --- a/espflash/src/targets/mod.rs +++ b/espflash/src/targets/mod.rs @@ -300,6 +300,7 @@ pub trait Target: ReadEFuse { target_app_partition: Option, image_format: Option, chip_revision: Option<(u32, u32)>, + min_rev_full: u16, flash_mode: Option, flash_size: Option, flash_freq: Option,