diff --git a/.gitignore b/.gitignore index e9868bd2..93d2cdaa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target +/Cargo.lock *.swp +/.vscode diff --git a/espflash/src/error.rs b/espflash/src/error.rs index 61fc27f0..a184e60b 100644 --- a/espflash/src/error.rs +++ b/espflash/src/error.rs @@ -314,7 +314,7 @@ pub enum PartitionTableError { InvalidSubType(#[from] InvalidSubTypeError), #[error(transparent)] #[diagnostic(transparent)] - NoFactoryApp(#[from] NoFactoryAppError), + NoApp(#[from] NoAppError), #[error(transparent)] #[diagnostic(transparent)] UnalignedPartitionError(#[from] UnalignedPartitionError), @@ -469,19 +469,19 @@ impl InvalidSubTypeError { } #[derive(Debug, Error, Diagnostic)] -#[error("No factory app partition was found")] +#[error("No app partition was found")] #[diagnostic( - code(espflash::partition_table::no_factory_app), - help("Partition table must contain a factory app partition") + code(espflash::partition_table::no_app), + help("Partition table must contain a factory or ota app partition") )] -pub struct NoFactoryAppError { +pub struct NoAppError { #[source_code] source_code: String, } -impl NoFactoryAppError { +impl NoAppError { pub fn new(source: &str) -> Self { - NoFactoryAppError { + NoAppError { source_code: source.into(), } } diff --git a/espflash/src/image_format/esp32bootloader.rs b/espflash/src/image_format/esp32bootloader.rs index 08e4fb9c..2644e765 100644 --- a/espflash/src/image_format/esp32bootloader.rs +++ b/espflash/src/image_format/esp32bootloader.rs @@ -12,6 +12,7 @@ use crate::{ error::{Error, FlashDetectError}, flasher::FlashSize, image_format::{EspCommonHeader, ImageFormat, SegmentHeader, ESP_MAGIC, WP_PIN_DISABLED}, + partition_table::Type, Chip, PartitionTable, }; @@ -123,8 +124,12 @@ impl<'a> Esp32BootloaderFormat<'a> { // The default partition table contains the "factory" partition, and if a user // provides a partition table via command-line then the validation step confirms - // this is present, so it's safe to unwrap. - let factory_partition = partition_table.find("factory").unwrap(); + // that at least one "app" partition is present. We prefer the "factory" partition, + // and use any available "app" partitions if not present. + let factory_partition = partition_table + .find("factory") + .or_else(|| partition_table.find_by_type(Type::App)) + .unwrap(); let flash_segment = RomSegment { addr: factory_partition.offset(), diff --git a/espflash/src/partition_table.rs b/espflash/src/partition_table.rs index f802c01f..5359df3b 100644 --- a/espflash/src/partition_table.rs +++ b/espflash/src/partition_table.rs @@ -10,7 +10,7 @@ use regex::Regex; use serde::{Deserialize, Deserializer, Serialize}; use crate::error::{ - CSVError, DuplicatePartitionsError, InvalidSubTypeError, NoFactoryAppError, + CSVError, DuplicatePartitionsError, InvalidSubTypeError, NoAppError, OverlappingPartitionsError, PartitionTableError, UnalignedPartitionError, }; @@ -264,6 +264,10 @@ impl PartitionTable { self.partitions.iter().find(|&p| p.name == name) } + pub fn find_by_type(&self, ty: Type) -> Option<&Partition> { + self.partitions.iter().find(|&p| p.ty == ty) + } + fn validate(&self, source: &str) -> Result<(), PartitionTableError> { for partition in &self.partitions { if let Some(line) = &partition.line { @@ -318,10 +322,8 @@ impl PartitionTable { } } - if self.find("factory").is_none() { - return Err(PartitionTableError::NoFactoryApp(NoFactoryAppError::new( - source, - ))); + if self.find_by_type(Type::App).is_none() { + return Err(PartitionTableError::NoApp(NoAppError::new(source))); } Ok(()) @@ -590,6 +592,24 @@ phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, a, data, spiffs, 0x110000, 1M, b, data, spiffs, 0x210000, 1M, +"; + + const PTABLE_NO_FACTORY: &str = " +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x4000, +otadata, data, ota, 0xd000, 0x2000, +phy_init, data, phy, 0xf000, 0x1000, +ota_0, app, ota_0, , 1M, +ota_1, app, ota_1, , 1M, +"; + + const PTABLE_NO_APP: &str = " +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x4000, +otadata, data, ota, 0xd000, 0x2000, +phy_init, data, phy, 0xf000, 0x1000, "; #[test] @@ -629,6 +649,11 @@ b, data, spiffs, 0x210000, 1M, let pt_spiffs = PartitionTable::try_from_str(PTABLE_SPIFFS); assert!(pt_spiffs.is_ok()); + + PartitionTable::try_from_str(PTABLE_NO_FACTORY) + .expect("Failed to parse partition table without factory partition"); + PartitionTable::try_from_str(PTABLE_NO_APP) + .expect_err("Failed to reject partition table without factory or ota partition"); } #[test]