refactor(examples/storage): update nvs_rw_blob and nvs_rw_value examples

This commit is contained in:
sonika.rathi
2025-03-26 08:50:26 +01:00
parent e4e56a4687
commit 24065c6bbd
6 changed files with 338 additions and 280 deletions

View File

@@ -14,7 +14,7 @@ Example also shows how to implement diagnostics if read / write operation was su
Detailed functional description of NVS and API is provided in [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_flash.html). Detailed functional description of NVS and API is provided in [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_flash.html).
If not done already, consider checking simpler example *storage/nvs_rw_value*, that has been used as a starting point for preparing this one. If not done already, consider checking simpler example *storage/nvs/nvs_rw_value*, that has been used as a starting point for preparing this one.
## How to use example ## How to use example
@@ -36,34 +36,27 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui
## Example Output ## Example Output
First run:
``` ```
Restart counter = 0 ...
Run time: I (288) main_task: Calling app_main()
Nothing saved yet! I (298) nvs_blob_example: Saving test data blob...
I (308) nvs_blob_example:
Reading updated blob data:
I (308) nvs_blob_example: Reading test data blob:
I (308) nvs_blob_example: ID: 123
I (308) nvs_blob_example: Name: Test Sample
I (308) nvs_blob_example: Values: 3.140, 2.718, -0.000, 0.000
I (318) nvs_blob_example: Flags: 0xABCD1234
I (318) nvs_blob_example: Counts: -100, 100
I (328) nvs_blob_example: Active: true
I (328) nvs_blob_example:
Reading array data blob:
I (338) nvs_blob_example: Array[0] = 30
I (338) nvs_blob_example: Array[1] = 20
I (338) nvs_blob_example:
Blob operations completed. Monitoring GPIO for reset...
I (348) gpio: GPIO[0]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
...
``` ```
At this point, press "Boot" button and hold it for a second. The board will perform software restart, printing: To reset nvs data, erase the contents of flash memory using `idf.py erase-flash`, then upload the program again as described above.
```
Restarting...
```
After booting again, restart counter and run time array will be printed:
```
Restart counter = 1
Run time:
1: 5110
```
After pressing "Boot" once more:
```
Restart counter = 2
Run time:
1: 5110
2: 5860
```
To reset the counter and run time array, erase the contents of flash memory using `idf.py erase-flash`, then upload the program again as described above.

View File

@@ -19,11 +19,15 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "nvs.h" #include "nvs.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#define STORAGE_NAMESPACE "storage" #define STORAGE_NAMESPACE "storage"
#define BLOB_EXAMPLE_DATA_SIZE 256
static const char *TAG = "nvs_blob_example";
#if CONFIG_IDF_TARGET_ESP32C3 #if CONFIG_IDF_TARGET_ESP32C3
#define BOOT_MODE_PIN GPIO_NUM_9 #define BOOT_MODE_PIN GPIO_NUM_9
@@ -31,96 +35,60 @@
#define BOOT_MODE_PIN GPIO_NUM_0 #define BOOT_MODE_PIN GPIO_NUM_0
#endif //CONFIG_IDF_TARGET_ESP32C3 #endif //CONFIG_IDF_TARGET_ESP32C3
/* Save the number of module restarts in NVS /* Test data structure to demonstrate different data types in blob */
by first reading and then incrementing typedef struct {
the number that has been saved previously. uint8_t id;
Return an error if anything goes wrong char name[32];
during this process. float values[2];
*/ uint32_t flags;
esp_err_t save_restart_counter(void) int16_t counts[2];
bool active;
} test_data_t;
/* Save test data as a blob in NVS */
esp_err_t save_test_data(void)
{ {
nvs_handle_t my_handle; nvs_handle_t my_handle;
esp_err_t err; esp_err_t err;
// Open // Create sample test data
test_data_t test_data = {
.id = 123,
.name = "Test Sample",
.values = {3.14f, 2.718f},
.flags = 0xABCD1234,
.counts = {-100, 100},
.active = true
};
// Open NVS handle
err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle); err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
if (err != ESP_OK) return err;
// Read
int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS
err = nvs_get_i32(my_handle, "restart_conter", &restart_counter);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
// Write
restart_counter++;
err = nvs_set_i32(my_handle, "restart_conter", restart_counter);
if (err != ESP_OK) return err;
// Commit written value.
// After setting any values, nvs_commit() must be called to ensure changes are written
// to flash storage. Implementations may write to storage at other times,
// but this is not guaranteed.
err = nvs_commit(my_handle);
if (err != ESP_OK) return err;
// Close
nvs_close(my_handle);
return ESP_OK;
}
/* Save new run time value in NVS
by first reading a table of previously saved values
and then adding the new value at the end of the table.
Return an error if anything goes wrong
during this process.
*/
esp_err_t save_run_time(void)
{
nvs_handle_t my_handle;
esp_err_t err;
// Open
err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
if (err != ESP_OK) return err;
// Read the size of memory space required for blob
size_t required_size = 0; // value will default to 0, if not set yet in NVS
err = nvs_get_blob(my_handle, "run_time", NULL, &required_size);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
// Read previously saved blob if available
uint32_t* run_time = malloc(required_size + sizeof(uint32_t));
if (required_size > 0) {
err = nvs_get_blob(my_handle, "run_time", run_time, &required_size);
if (err != ESP_OK) { if (err != ESP_OK) {
free(run_time); ESP_LOGE(TAG, "Error (%s) opening NVS handle!", esp_err_to_name(err));
return err; return err;
} }
// Write blob
ESP_LOGI(TAG, "Saving test data blob...");
err = nvs_set_blob(my_handle, "test_data", &test_data, sizeof(test_data_t));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to write test data blob!");
nvs_close(my_handle);
return err;
} }
// Write value including previously saved blob if available
required_size += sizeof(uint32_t);
run_time[required_size / sizeof(uint32_t) - 1] = xTaskGetTickCount() * portTICK_PERIOD_MS;
err = nvs_set_blob(my_handle, "run_time", run_time, required_size);
free(run_time);
if (err != ESP_OK) return err;
// Commit // Commit
err = nvs_commit(my_handle); err = nvs_commit(my_handle);
if (err != ESP_OK) return err; if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to commit data");
// Close
nvs_close(my_handle);
return ESP_OK;
} }
/* Read from NVS and print restart counter nvs_close(my_handle);
and the table with run times. return err;
Return an error if anything goes wrong }
during this process.
*/ /* Example of storing and appending array data as a blob */
esp_err_t print_what_saved(void) esp_err_t save_array_data(void)
{ {
nvs_handle_t my_handle; nvs_handle_t my_handle;
esp_err_t err; esp_err_t err;
@@ -129,70 +97,137 @@ esp_err_t print_what_saved(void)
err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle); err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
if (err != ESP_OK) return err; if (err != ESP_OK) return err;
// Read restart counter // First, get the size of existing data (if any)
int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS size_t required_size = 0;
err = nvs_get_i32(my_handle, "restart_conter", &restart_counter); err = nvs_get_blob(my_handle, "array_data", NULL, &required_size);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err; if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) {
printf("Restart counter = %" PRIu32 "\n", restart_counter); ESP_LOGE(TAG, "Error (%s) reading array size!", esp_err_to_name(err));
nvs_close(my_handle);
// Read run time blob
size_t required_size = 0; // value will default to 0, if not set yet in NVS
// obtain required memory space to store blob being read from NVS
err = nvs_get_blob(my_handle, "run_time", NULL, &required_size);
if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) return err;
printf("Run time:\n");
if (required_size == 0) {
printf("Nothing saved yet!\n");
} else {
uint32_t* run_time = malloc(required_size);
err = nvs_get_blob(my_handle, "run_time", run_time, &required_size);
if (err != ESP_OK) {
free(run_time);
return err; return err;
} }
for (int i = 0; i < required_size / sizeof(uint32_t); i++) {
printf("%d: %" PRIu32 "\n", i + 1, run_time[i]); // Allocate memory and read existing data
uint32_t* array_data = malloc(required_size + sizeof(uint32_t));
if (required_size > 0) {
err = nvs_get_blob(my_handle, "array_data", array_data, &required_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error (%s) reading array data!", esp_err_to_name(err));
free(array_data);
nvs_close(my_handle);
return err;
} }
free(run_time);
} }
// Close // Append new value
required_size += sizeof(uint32_t);
array_data[required_size / sizeof(uint32_t) - 1] = xTaskGetTickCount() * portTICK_PERIOD_MS;
// Save updated array
err = nvs_set_blob(my_handle, "array_data", array_data, required_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error (%s) saving array data!", esp_err_to_name(err));
}
free(array_data);
// Commit
err = nvs_commit(my_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error (%s) committing data!", esp_err_to_name(err));
}
nvs_close(my_handle);
return err;
}
/* Read and display all saved blobs */
esp_err_t read_stored_blobs(void)
{
nvs_handle_t my_handle;
esp_err_t err;
err = nvs_open(STORAGE_NAMESPACE, NVS_READONLY, &my_handle);
if (err != ESP_OK) return err;
// 1. Read test data blob
ESP_LOGI(TAG, "Reading test data blob:");
test_data_t test_data;
size_t test_data_size = sizeof(test_data_t);
err = nvs_get_blob(my_handle, "test_data", &test_data, &test_data_size);
if (err == ESP_OK) {
ESP_LOGI(TAG, "ID: %d", test_data.id);
ESP_LOGI(TAG, "Name: %s", test_data.name);
ESP_LOGI(TAG, "Values: %.3f, %.3f, %.3f, %.3f",
test_data.values[0], test_data.values[1],
test_data.values[2], test_data.values[3]);
ESP_LOGI(TAG, "Flags: 0x%08" PRIX32, test_data.flags);
ESP_LOGI(TAG, "Counts: %d, %d", test_data.counts[0], test_data.counts[1]);
ESP_LOGI(TAG, "Active: %s", test_data.active ? "true" : "false");
} else if (err == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGW(TAG, "Test data not found!");
}
// 2. Read array data blob
ESP_LOGI(TAG, "\nReading array data blob:");
size_t required_size = 0;
err = nvs_get_blob(my_handle, "array_data", NULL, &required_size);
if (err == ESP_OK) {
uint32_t* array_data = malloc(required_size);
err = nvs_get_blob(my_handle, "array_data", array_data, &required_size);
if (err == ESP_OK) {
for (int i = 0; i < required_size / sizeof(uint32_t); i++) {
ESP_LOGI(TAG, "Array[%d] = %" PRIu32, i, array_data[i]);
}
}
free(array_data);
} else if (err == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGW(TAG, "Array data not found!");
}
nvs_close(my_handle); nvs_close(my_handle);
return ESP_OK; return ESP_OK;
} }
void app_main(void) void app_main(void)
{ {
// Initialize NVS
esp_err_t err = nvs_flash_init(); esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase()); ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init(); err = nvs_flash_init();
} }
ESP_ERROR_CHECK(err); ESP_ERROR_CHECK(err);
err = print_what_saved(); // Save new test data
if (err != ESP_OK) printf("Error (%s) reading data from NVS!\n", esp_err_to_name(err)); err = save_test_data();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error (%s) saving test data!", esp_err_to_name(err));
}
err = save_restart_counter(); // Save new array data
if (err != ESP_OK) printf("Error (%s) saving restart counter to NVS!\n", esp_err_to_name(err)); err = save_array_data();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error (%s) saving array data!", esp_err_to_name(err));
}
// Read updated data
ESP_LOGI(TAG, "\nReading updated blob data:");
err = read_stored_blobs();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error (%s) reading updated data!", esp_err_to_name(err));
}
ESP_LOGI(TAG, "\nBlob operations completed. Monitoring GPIO for reset...");
// Setup GPIO for reset monitoring
gpio_reset_pin(BOOT_MODE_PIN); gpio_reset_pin(BOOT_MODE_PIN);
gpio_set_direction(BOOT_MODE_PIN, GPIO_MODE_INPUT); gpio_set_direction(BOOT_MODE_PIN, GPIO_MODE_INPUT);
/* Read the status of GPIO0. If GPIO0 is LOW for longer than 1000 ms,
then save module's run time and restart it
*/
while (1) { while (1) {
if (gpio_get_level(BOOT_MODE_PIN) == 0) { if (gpio_get_level(BOOT_MODE_PIN) == 0) {
vTaskDelay(1000 / portTICK_PERIOD_MS); vTaskDelay(1000 / portTICK_PERIOD_MS);
if(gpio_get_level(BOOT_MODE_PIN) == 0) { if(gpio_get_level(BOOT_MODE_PIN) == 0) {
err = save_run_time(); ESP_LOGI(TAG, "Reset button pressed, restarting...");
if (err != ESP_OK) printf("Error (%s) saving run time blob to NVS!\n", esp_err_to_name(err));
printf("Restarting...\n");
fflush(stdout);
esp_restart(); esp_restart();
} }
} }

View File

@@ -1,11 +1,5 @@
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0 # SPDX-License-Identifier: Unlicense OR CC0-1.0
import logging
import random
import re
import time
from typing import List
import pytest import pytest
from pytest_embedded import Dut from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize from pytest_embedded_idf.utils import idf_parametrize
@@ -14,28 +8,12 @@ from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target']) @idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target'])
def test_examples_nvs_rw_blob(dut: Dut) -> None: def test_examples_nvs_rw_blob(dut: Dut) -> None:
def expect_start_msg(index: int) -> None: # Save and read test data
dut.expect('Restart counter = {}'.format(index), timeout=10) dut.expect('Saving test data blob...', timeout=20)
dut.expect('Run time:', timeout=10) # Save array data
# Read updated data
expect_start_msg(0) dut.expect('Reading updated blob data:', timeout=20)
dut.expect('Nothing saved yet!', timeout=5) dut.expect('Reading test data blob:', timeout=20)
nvs_store: List[str] = [] # Verify array data reading
for i in range(1, 10): dut.expect('Reading array data blob:', timeout=20)
time.sleep(random.uniform(0.1, 2)) # in order to randomize the runtimes stored in NVS dut.expect('Blob operations completed. Monitoring GPIO for reset...', timeout=20)
try:
# Pulling pin low using DTR
dut.serial.proc.setDTR(True)
dut.expect('Restarting...', timeout=5) # the application waits for a second
finally:
dut.serial.proc.setDTR(False)
expect_start_msg(i)
for store_item in nvs_store:
dut.expect(store_item.encode(), timeout=10)
logging.info('Received: {}'.format(', '.join(nvs_store)))
new_runtime = (dut.expect(re.compile(str.encode('{}: (\\d+)'.format(i))), timeout=10)[0]).decode()
nvs_store.append(new_runtime)
logging.info('loop {} has finished with runtime {}'.format(i, new_runtime))

View File

@@ -13,7 +13,7 @@ Example also shows how to check if read / write operation was successful, or cer
Detailed functional description of NVS and API is provided in [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_flash.html). Detailed functional description of NVS and API is provided in [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/storage/nvs_flash.html).
Check another example *storage/nvs_rw_blob*, which shows how to read and write variable length binary data (blob). Check another example *storage/nvs/nvs_rw_blob*, which shows how to read and write variable length binary data (blob).
## How to use example ## How to use example
@@ -35,50 +35,32 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui
## Example Output ## Example Output
First run:
``` ```
Opening Non-Volatile Storage (NVS) handle... Done ...
Reading restart counter from NVS ... The value is not initialized yet! I (296) nvs_example:
Updating restart counter in NVS ... Done Opening Non-Volatile Storage (NVS) handle...
Committing updates in NVS ... Done I (296) nvs_example:
Writing counter to NVS...
Restarting in 10 seconds... I (306) nvs_example:
Restarting in 9 seconds... Reading counter from NVS...
Restarting in 8 seconds... I (306) nvs_example: Read counter = 42
Restarting in 7 seconds... I (306) nvs_example:
Restarting in 6 seconds... Writing string to NVS...
Restarting in 5 seconds... I (306) nvs_example:
Restarting in 4 seconds... Reading string from NVS...
Restarting in 3 seconds... I (306) nvs_example: Read string: Hello from NVS!
Restarting in 2 seconds... I (316) nvs_example:
Restarting in 1 seconds... Finding keys in NVS...
Restarting in 0 seconds... I (316) nvs_example: Key: 'message', Type: str
Restarting now. I (316) nvs_example: Key: 'counter', Type: i32
I (326) nvs_example:
Deleting key from NVS...
I (336) nvs_example:
Committing updates in NVS...
I (336) nvs_example: NVS handle closed.
I (336) nvs_example: Returned to app_main
I (346) main_task: Returned from app_main()
...
``` ```
Subsequent runs: To reset nvs data, erase the contents of flash memory using `idf.py erase-flash`, then upload the program again as described above.
```
Opening Non-Volatile Storage (NVS) handle... Done
Reading restart counter from NVS ... Done
Restart counter = 1
Updating restart counter in NVS ... Done
Committing updates in NVS ... Done
Restarting in 10 seconds...
Restarting in 9 seconds...
Restarting in 8 seconds...
Restarting in 7 seconds...
Restarting in 6 seconds...
Restarting in 5 seconds...
Restarting in 4 seconds...
Restarting in 3 seconds...
Restarting in 2 seconds...
Restarting in 1 seconds...
Restarting in 0 seconds...
Restarting now.
```
Restart counter will increment on each run.
To reset the counter, erase the contents of flash memory using `idf.py erase-flash`, then upload the program again as described above.

View File

@@ -19,9 +19,45 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "nvs.h" #include "nvs.h"
static const char *TAG = "nvs_example";
typedef struct {
nvs_type_t type;
const char *str;
} type_str_pair_t;
static const type_str_pair_t type_str_pair[] = {
{ NVS_TYPE_I8, "i8" },
{ NVS_TYPE_U8, "u8" },
{ NVS_TYPE_U16, "u16" },
{ NVS_TYPE_I16, "i16" },
{ NVS_TYPE_U32, "u32" },
{ NVS_TYPE_I32, "i32" },
{ NVS_TYPE_U64, "u64" },
{ NVS_TYPE_I64, "i64" },
{ NVS_TYPE_STR, "str" },
{ NVS_TYPE_BLOB, "blob" },
{ NVS_TYPE_ANY, "any" },
};
static const size_t TYPE_STR_PAIR_SIZE = sizeof(type_str_pair) / sizeof(type_str_pair[0]);
static const char *type_to_str(nvs_type_t type)
{
for (int i = 0; i < TYPE_STR_PAIR_SIZE; i++) {
const type_str_pair_t *p = &type_str_pair[i];
if (p->type == type) {
return p->str;
}
}
return "Unknown";
}
void app_main(void) void app_main(void)
{ {
// Initialize NVS // Initialize NVS
@@ -34,58 +70,92 @@ void app_main(void)
} }
ESP_ERROR_CHECK(err); ESP_ERROR_CHECK(err);
// Open // Open NVS handle
printf("\n"); ESP_LOGI(TAG, "\nOpening Non-Volatile Storage (NVS) handle...");
printf("Opening Non-Volatile Storage (NVS) handle... ");
nvs_handle_t my_handle; nvs_handle_t my_handle;
err = nvs_open("storage", NVS_READWRITE, &my_handle); err = nvs_open("storage", NVS_READWRITE, &my_handle);
if (err != ESP_OK) { if (err != ESP_OK) {
printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err)); ESP_LOGE(TAG, "Error (%s) opening NVS handle!", esp_err_to_name(err));
} else { return;
printf("Done\n");
// Read
printf("Reading restart counter from NVS ... ");
int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS
err = nvs_get_i32(my_handle, "restart_counter", &restart_counter);
switch (err) {
case ESP_OK:
printf("Done\n");
printf("Restart counter = %" PRIu32 "\n", restart_counter);
break;
case ESP_ERR_NVS_NOT_FOUND:
printf("The value is not initialized yet!\n");
break;
default :
printf("Error (%s) reading!\n", esp_err_to_name(err));
} }
// Write // Store and read an integer value
printf("Updating restart counter in NVS ... "); int32_t counter = 42;
restart_counter++; ESP_LOGI(TAG, "\nWriting counter to NVS...");
err = nvs_set_i32(my_handle, "restart_counter", restart_counter); err = nvs_set_i32(my_handle, "counter", counter);
printf((err != ESP_OK) ? "Failed!\n" : "Done\n"); if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to write counter!");
}
// Commit written value. // Read back the value
int32_t read_counter = 0;
ESP_LOGI(TAG, "\nReading counter from NVS...");
err = nvs_get_i32(my_handle, "counter", &read_counter);
switch (err) {
case ESP_OK:
ESP_LOGI(TAG, "Read counter = %" PRIu32, read_counter);
break;
case ESP_ERR_NVS_NOT_FOUND:
ESP_LOGW(TAG, "The value is not initialized yet!");
break;
default:
ESP_LOGE(TAG, "Error (%s) reading!", esp_err_to_name(err));
}
// Store and read a string
ESP_LOGI(TAG, "\nWriting string to NVS...");
err = nvs_set_str(my_handle, "message", "Hello from NVS!");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to write string!");
}
// Read back the string
size_t required_size = 0;
ESP_LOGI(TAG, "\nReading string from NVS...");
err = nvs_get_str(my_handle, "message", NULL, &required_size);
if (err == ESP_OK) {
char* message = malloc(required_size);
err = nvs_get_str(my_handle, "message", message, &required_size);
if (err == ESP_OK) {
ESP_LOGI(TAG, "Read string: %s", message);
}
free(message);
}
// Find keys in NVS
ESP_LOGI(TAG, "\nFinding keys in NVS...");
nvs_iterator_t it = NULL;
esp_err_t res = nvs_entry_find("nvs", "storage", NVS_TYPE_ANY, &it);
while(res == ESP_OK) {
nvs_entry_info_t info;
nvs_entry_info(it, &info);
const char *type_str = type_to_str(info.type);
ESP_LOGI(TAG, "Key: '%s', Type: %s", info.key, type_str);
res = nvs_entry_next(&it);
}
nvs_release_iterator(it);
// Delete a key from NVS
ESP_LOGI(TAG, "\nDeleting key from NVS...");
err = nvs_erase_key(my_handle, "counter");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to erase key!");
}
// Commit changes
// After setting any values, nvs_commit() must be called to ensure changes are written // After setting any values, nvs_commit() must be called to ensure changes are written
// to flash storage. Implementations may write to storage at other times, // to flash storage. Implementations may write to storage at other times,
// but this is not guaranteed. // but this is not guaranteed.
printf("Committing updates in NVS ... "); ESP_LOGI(TAG, "\nCommitting updates in NVS...");
err = nvs_commit(my_handle); err = nvs_commit(my_handle);
printf((err != ESP_OK) ? "Failed!\n" : "Done\n"); if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to commit NVS changes!");
}
// Close // Close
nvs_close(my_handle); nvs_close(my_handle);
} ESP_LOGI(TAG, "NVS handle closed.");
printf("\n"); ESP_LOGI(TAG, "Returned to app_main");
// Restart module
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");
fflush(stdout);
esp_restart();
} }

View File

@@ -1,8 +1,5 @@
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0 # SPDX-License-Identifier: Unlicense OR CC0-1.0
import logging
from itertools import zip_longest
import pytest import pytest
from pytest_embedded import Dut from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize from pytest_embedded_idf.utils import idf_parametrize
@@ -13,11 +10,14 @@ from pytest_embedded_idf.utils import idf_parametrize
def test_examples_nvs_rw_value(dut: Dut) -> None: def test_examples_nvs_rw_value(dut: Dut) -> None:
dut.serial.erase_flash() dut.serial.erase_flash()
dut.serial.flash() dut.serial.flash()
for i, counter_state in zip_longest(range(4), ('The value is not initialized yet!',), fillvalue='Done'):
dut.expect('Opening Non-Volatile Storage \\(NVS\\) handle... Done', timeout=20) dut.expect('Opening Non-Volatile Storage \\(NVS\\) handle...', timeout=20)
dut.expect('Reading restart counter from NVS ... {}'.format(counter_state), timeout=20) dut.expect('Writing counter to NVS...', timeout=20)
dut.expect('Restart counter = {}'.format(i) if int(i) > 0 else '', timeout=20) dut.expect('Reading counter from NVS...', timeout=20)
dut.expect('Updating restart counter in NVS ... Done', timeout=20) dut.expect('Writing string to NVS...', timeout=20)
dut.expect('Committing updates in NVS ... Done', timeout=20) dut.expect('Reading string from NVS...', timeout=20)
dut.expect('Restarting in 10 seconds...', timeout=20) dut.expect('Finding keys in NVS...', timeout=20)
logging.info('loop {} has finished'.format(i)) dut.expect('Deleting key from NVS...', timeout=20)
dut.expect('Committing updates in NVS...', timeout=20)
dut.expect('NVS handle closed.', timeout=20)
dut.expect('Returned to app_main', timeout=20)