Make a singleton form FlashStorage constructor, removed Default (#4132)

* Make a singleton form FlashStorage constructor, removed Default

* changelog

* Simplify, don't need the Singleton

* changelog

* reviews and build errors

* fix dead links

* fmt
This commit is contained in:
Juraj Sadel
2025-09-18 16:33:42 +02:00
committed by GitHub
parent 1eed542f64
commit 3d0d20002e
8 changed files with 100 additions and 19 deletions

View File

@@ -22,7 +22,7 @@
//! ## Examples
//! Visit the [ECC] test for an example of using the ECC Accelerator.
//!
//! [ECC]: https://github.com/esp-rs/esp-hal/blob/main/hil-test/tests/ecc.rs
//! [ECC]: https://github.com/esp-rs/esp-hal/blob/main/hil-test/src/bin/ecc.rs
use core::marker::PhantomData;

View File

@@ -18,7 +18,7 @@
//! ### Modular Exponentiation, Modular Multiplication, and Multiplication
//! Visit the [RSA test suite] for an example of using the peripheral.
//!
//! [RSA test suite]: https://github.com/esp-rs/esp-hal/blob/main/hil-test/tests/rsa.rs
//! [RSA test suite]: https://github.com/esp-rs/esp-hal/blob/main/hil-test/src/bin/rsa.rs
use core::{marker::PhantomData, ptr::NonNull, task::Poll};

View File

@@ -9,16 +9,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- `defmt` feature and `FlashStorage`, `FlashStorageError` now implements `Defmt` (#4127)
- `defmt` feature and `FlashStorage`, `FlashStorageError` now implements `Defmt` (#4127)
- `Drop` impl for `FlashStorage` (#4132)
### Changed
- `FlashStorage::new()` now panics when it's already being in use (#4132)
### Fixed
### Removed
- `Default` impl for `FlashStorage` (#4132)
## [v0.8.0] - 2025-09-10
### Added

View File

@@ -21,6 +21,7 @@ bench = false
embedded-storage = "0.3.1"
procmacros = { version = "0.19.0", package = "esp-hal-procmacros", path = "../esp-hal-procmacros" }
cfg-if = "1.0.0"
portable-atomic = { version = "1.11.0", default-features = false }
# Optional dependencies
esp-sync = { version = "0.0.0", path = "../esp-sync", optional = true }

View File

@@ -1,9 +1,16 @@
use core::mem::MaybeUninit;
use core::{
mem::MaybeUninit,
sync::atomic::Ordering::{Acquire, Release},
};
use portable_atomic::AtomicBool;
use crate::chip_specific;
#[cfg(multi_core)]
use crate::multi_core::MultiCoreStrategy;
static IS_TAKEN: AtomicBool = AtomicBool::new(false);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -63,21 +70,30 @@ impl FlashStorage {
pub const SECTOR_SIZE: u32 = 4096;
/// Create a new flash storage instance.
pub fn new() -> FlashStorage {
let mut storage = FlashStorage {
capacity: 0,
unlocked: false,
#[cfg(multi_core)]
multi_core_strategy: MultiCoreStrategy::Error,
};
///
/// # Panics
///
/// Panics if called more than once.
pub fn new() -> Self {
if IS_TAKEN.fetch_or(true, Acquire) {
panic!("FlashStorage::new() called more than once!");
}
#[cfg(not(any(feature = "esp32", feature = "esp32s2")))]
const ADDR: u32 = 0x0000;
#[cfg(any(feature = "esp32", feature = "esp32s2"))]
const ADDR: u32 = 0x1000;
let mut storage = Self {
capacity: 0,
unlocked: false,
#[cfg(multi_core)]
multi_core_strategy: MultiCoreStrategy::Error,
};
let mut buffer = crate::buffer::FlashWordBuffer::uninit();
storage.internal_read(ADDR, buffer.as_bytes_mut()).unwrap();
let buffer = unsafe { buffer.assume_init_bytes() };
let mb = match buffer[3] & 0xf0 {
0x00 => 1,
@@ -89,6 +105,7 @@ impl FlashStorage {
_ => 0,
};
storage.capacity = mb * 1024 * 1024;
storage
}
@@ -171,3 +188,39 @@ impl FlashStorage {
Ok(())
}
}
impl Drop for FlashStorage {
fn drop(&mut self) {
IS_TAKEN.store(false, Release);
}
}
#[cfg(test)]
mod tests {
use crate::FlashStorage;
#[test]
fn test_singleton_behavior() {
// First call should succeed
let flash1 = FlashStorage::new();
assert_eq!(flash1.capacity > 0, true); // or check some field
// Second call should panic
let result = std::panic::catch_unwind(|| {
FlashStorage::new();
});
assert!(result.is_err(), "expected panic on second init");
// Third call should also panic
let result = std::panic::catch_unwind(|| {
FlashStorage::new();
});
assert!(result.is_err(), "expected panic on third init");
}
#[test]
#[should_panic(expected = "FlashStorage::new() called more than once!")]
fn test_expect_panics() {
let _flash1 = FlashStorage::new(); // first call is fine
let _flash2 = FlashStorage::new(); // this panics
}
}

View File

@@ -319,6 +319,7 @@ mod tests {
#[cfg(feature = "bytewise-read")]
fn bytewise_read_aligned_buffer() {
let mut flash = FlashStorage::new();
flash.capacity = 4 * 4096;
let src = TestBuffer::seq();
let mut data = TestBuffer::default();
@@ -339,6 +340,7 @@ mod tests {
#[cfg(feature = "bytewise-read")]
fn bytewise_read_not_aligned_buffer() {
let mut flash = FlashStorage::new();
flash.capacity = 4 * 4096;
let src = TestBuffer::seq();
let mut data = TestBuffer::default();

View File

@@ -45,6 +45,7 @@ use esp_hal::{
main,
};
use esp_println::println;
use esp_storage::FlashStorage;
esp_bootloader_esp_idf::esp_app_desc!();
@@ -55,11 +56,11 @@ fn main() -> ! {
esp_println::logger::init_logger_from_env();
let peripherals = esp_hal::init(esp_hal::Config::default());
let mut storage = esp_storage::FlashStorage::new();
let mut flash = FlashStorage::new();
let mut buffer = [0u8; esp_bootloader_esp_idf::partitions::PARTITION_TABLE_MAX_LEN];
let pt = esp_bootloader_esp_idf::partitions::read_partition_table(&mut storage, &mut buffer)
.unwrap();
let pt =
esp_bootloader_esp_idf::partitions::read_partition_table(&mut flash, &mut buffer).unwrap();
// List all partitions - this is just FYI
for i in 0..pt.len() {
@@ -75,7 +76,7 @@ fn main() -> ! {
))
.unwrap()
.unwrap();
let mut ota_part = ota_part.as_embedded_storage(&mut storage);
let mut ota_part = ota_part.as_embedded_storage(&mut flash);
println!("Found ota data");
let mut ota = esp_bootloader_esp_idf::ota::Ota::new(&mut ota_part).unwrap();
@@ -140,7 +141,7 @@ fn main() -> ! {
}
.unwrap();
println!("Found partition: {:?}", next_app_partition);
let mut next_app_partition = next_app_partition.as_embedded_storage(&mut storage);
let mut next_app_partition = next_app_partition.as_embedded_storage(&mut flash);
// write to the app partition
for (sector, chunk) in OTA_IMAGE.chunks(4096).enumerate() {
@@ -157,7 +158,7 @@ fn main() -> ! {
))
.unwrap()
.unwrap();
let mut ota_part = ota_part.as_embedded_storage(&mut storage);
let mut ota_part = ota_part.as_embedded_storage(&mut flash);
let mut ota = esp_bootloader_esp_idf::ota::Ota::new(&mut ota_part).unwrap();
ota.set_current_slot(next_slot).unwrap();
ota.set_current_ota_state(esp_bootloader_esp_idf::ota::OtaImageState::New)

View File

@@ -277,7 +277,15 @@ impl Package {
features.push("defmt-espflash".to_owned());
features.push("critical-section".to_owned());
}
Package::EspStorage => {}
Package::EspStorage => {
if config.name() == "esp32c2"
|| config.name() == "esp32c3"
|| config.name() == "esp32s2"
{
println!("pizda usho");
features.push("portable-atomic/unsafe-assume-single-core".to_owned());
}
}
Package::EspBootloaderEspIdf => {
features.push("defmt".to_owned());
features.push("validation".to_owned());
@@ -389,7 +397,19 @@ impl Package {
cases.push(vec!["esp-alloc".to_owned(), "esp-hal/unstable".to_owned()])
}
Package::EspStorage => {
cases.push(vec!["defmt".to_owned()]);
// TODO: https://github.com/esp-rs/esp-hal/issues/4136
if config.name() == "esp32c2"
|| config.name() == "esp32c3"
|| config.name() == "esp32s2"
{
// println!("kokot usho");
cases.push(vec![
"defmt".to_owned(),
"portable-atomic/unsafe-assume-single-core".to_owned(),
]);
} else {
cases.push(vec!["defmt".to_owned()]);
}
}
_ => {}
}