Skip to content

Add esp nvs partition tool#21

Open
niclo wants to merge 4 commits intolhemala:mainfrom
niclo:main
Open

Add esp nvs partition tool#21
niclo wants to merge 4 commits intolhemala:mainfrom
niclo:main

Conversation

@niclo
Copy link
Collaborator

@niclo niclo commented Feb 23, 2026

No description provided.

@niclo niclo requested review from lhemala and renkenono February 23, 2026 13:20
@niclo niclo self-assigned this Feb 23, 2026
for entry in &partition.entries {
// Emit a namespace row when the namespace changes
if current_namespace != Some(&entry.namespace) {
wtr.write_record([&entry.namespace, "namespace", "", ""])?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should migrate to relying on serialization in the future to simplify the maintenance of this code in the future, see https://docs.rs/csv/latest/csv/struct.Writer.html#method.serialize.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done ^^

Comment on lines +8 to +12
// Page states
pub const PAGE_STATE_ACTIVE: u32 = 0xFFFFFFFE;
pub const PAGE_STATE_FULL: u32 = 0xFFFFFFFC;
pub const PAGE_STATE_FREEING: u32 = 0xFFFFFFF8;
pub const PAGE_STATE_CORRUPT: u32 = 0x00000000;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use esp_nvs::PageState, don't hesitate to modify esp_nvs to expose these types to avoid duplication.

Comment on lines +1 to +6
// NVS page layout
pub const FLASH_SECTOR_SIZE: usize = 4096;
pub const PAGE_HEADER_SIZE: usize = 32;
pub const ENTRY_STATE_BITMAP_SIZE: usize = 32;
pub const ENTRY_SIZE: usize = 32;
pub const ENTRIES_PER_PAGE: usize = 126;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should expose the consts defined at https://github.com/lhemala/esp-nvs/blob/main/src/raw.rs#L15-L21 and re-use them here.

///
/// This function is intentionally public so that callers can verify or compute
/// CRCs over NVS data independently of the higher-level partition APIs.
pub fn crc32(data: &[u8]) -> u32 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is a good software fallback implementation of CRC32 that can be used anywhere, I'd recommend that we create an issue to move it to esp_nvs and use it for the tests as well. This allows us to drop the dependency on libz-sys which would also make us drop the dependency on pkg-config in devenv.nix. BTW I think libz-sys is missing in the devenv.nix then?

This is where it'd be called in tests

libz_sys::crc32(init as core::ffi::c_ulong, data.as_ptr(), data.len() as u32) as u32
.

/// Generate an NVS partition binary in memory and return it as a `Vec<u8>`.
///
/// `size` must be a multiple of 4096 (the ESP-IDF flash sector size).
pub(crate) fn generate_partition_data(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO you should esp_nvs underneath to implement the generator to avoid partially re-implementing it. I think re-using Flash from the test suite or something similar would reduce this implementation by a lot since it uses the abstractions that esp_nvs is based on such as NorFlash and esp_nvs::platform::Crc.

Because Flash contains the binary representation in memory, you can dump it whenever you want similarly to what you do here by returning Vec<u8>.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ this

/// Parse an NVS partition binary file at the given `path`.
pub(crate) fn parse_binary<P: AsRef<Path>>(path: P) -> Result<NvsPartition, Error> {
let data = fs::read(path)?;
parse_binary_data(&data)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this implementation should re-use esp_nvs as well as the in-memory implementation Flash::new_from_file() to parse the binary file. However, the difficulty here would be the fact that there is currently no API to iterate the partition AFAIK which is why #10 exists. We could work in the direction of merging that PR and re-using its API here as well to simplify the implementation, I'd like @lhemala opinion since he knows the codebase better than me.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it would make sense to push #10 . I commented there as it also needs to be rebased. I need to take another thorough look again as well

Copy link
Owner

@lhemala lhemala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not fully through yet, I'll continue tomorrow

fmt:
runs-on: ubuntu-latest
name: stable / fmt
name: nightly / fmt
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not going to merge things that depend on nightly

Copy link
Collaborator Author

@niclo niclo Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only pertains to the code formatting, nightly is not used for anything else. esp-hal has a similar rustfmt.toml which also depends on nightly.

All of the rustfmt options used are not yet stable (as of rustfmt v1.8.0):

/// Generate an NVS partition binary in memory and return it as a `Vec<u8>`.
///
/// `size` must be a multiple of 4096 (the ESP-IDF flash sector size).
pub(crate) fn generate_partition_data(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ this

/// Parse an NVS partition binary file at the given `path`.
pub(crate) fn parse_binary<P: AsRef<Path>>(path: P) -> Result<NvsPartition, Error> {
let data = fs::read(path)?;
parse_binary_data(&data)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it would make sense to push #10 . I commented there as it also needs to be rebased. I need to take another thorough look again as well


#[test]
fn test_parse_legacy_blob() {
// Hand-craft a minimal NVS binary containing a legacy blob (0x41) entry.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not support them

@@ -0,0 +1,507 @@
use std::fs;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that a lot of tests are redundant, especially as we should reuse more code from esp-nvs direcly as @renkenono has mentioned

[dev-dependencies]
embedded-storage = "0.3.1"
esp-nvs = { path = "../esp-nvs" }
libz-sys = "1.1.22"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didn't you implement crc32 yourself? why is libz still needed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants