mirror of
https://github.com/espressif/esp-idf.git
synced 2025-11-17 18:18:01 +00:00
feat(storage): Added Block Device Layer support for esp_partition component
This commit is contained in:
7
components/esp_partition/test_apps/.build-test-rules.yml
Normal file
7
components/esp_partition/test_apps/.build-test-rules.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
|
||||
components/esp_partition/test_apps:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32", "esp32c3"]
|
||||
temporary: true
|
||||
reason: the other targets are not tested yet
|
||||
8
components/esp_partition/test_apps/CMakeLists.txt
Normal file
8
components/esp_partition/test_apps/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp_partition_test)
|
||||
18
components/esp_partition/test_apps/README.md
Normal file
18
components/esp_partition/test_apps/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- |
|
||||
|
||||
This is a test app for esp_partition component. It verifies all important APIs and properties, and prints the results.
|
||||
The Block Device Layer related tests have names with a prefix 'test_bdl', and they check all the BDL operations related to 'esp_partition' including parallel access to 2 partitions.
|
||||
|
||||
In CI, it is sufficient to run this test for one chip of each architecture.
|
||||
|
||||
# Building and Running
|
||||
|
||||
To run locally:
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
The tests will be executed and the summary will be printed.
|
||||
Note, when the Python test script is executed in internal CI, it will test each configuration one by one. When executing this script locally, it will use whichever binary is already built and available in `build` directory.
|
||||
5
components/esp_partition/test_apps/main/CMakeLists.txt
Normal file
5
components/esp_partition/test_apps/main/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
idf_component_register(SRCS test_part_app.c
|
||||
PRIV_INCLUDE_DIRS .
|
||||
PRIV_REQUIRES unity esp_partition spi_flash
|
||||
WHOLE_ARCHIVE
|
||||
)
|
||||
157
components/esp_partition/test_apps/main/test_part_app.c
Normal file
157
components/esp_partition/test_apps/main/test_part_app.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "unity.h"
|
||||
#include "unity_fixture.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_partition.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
TEST_GROUP(esp_partition);
|
||||
|
||||
TEST_SETUP(esp_partition)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_TEAR_DOWN(esp_partition)
|
||||
{
|
||||
}
|
||||
|
||||
TEST(esp_partition, test_bdl_interface)
|
||||
{
|
||||
//get the block-device interface instance
|
||||
esp_blockdev_handle_t part_blockdev = NULL;
|
||||
TEST_ESP_OK(esp_partition_get_blockdev(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1", &part_blockdev));
|
||||
|
||||
const size_t data_size = 256;
|
||||
uint8_t test_data[data_size];
|
||||
const off_t target_addr = 3*4*1024;
|
||||
uint8_t data_buffer[data_size];
|
||||
memset((void*)data_buffer, 0, data_size);
|
||||
|
||||
//erase the first sector data from the blockdev and check it's really wiped
|
||||
TEST_ESP_OK(part_blockdev->erase(part_blockdev, target_addr, part_blockdev->geometry.erase_size));
|
||||
memset((void*)test_data, 0xFF, data_size); //erased NOR flash sector contains only 1s
|
||||
TEST_ESP_OK(part_blockdev->read(part_blockdev, data_buffer, sizeof(data_buffer), target_addr, data_size));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer, data_size));
|
||||
|
||||
//write to the blockdev
|
||||
memset((void*)test_data, 'A', data_size);
|
||||
TEST_ESP_OK(part_blockdev->write(part_blockdev, test_data, target_addr, data_size));
|
||||
|
||||
//read from the blockdev the data written before
|
||||
TEST_ESP_OK(part_blockdev->read(part_blockdev, data_buffer, sizeof(data_buffer), target_addr, data_size));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer, data_size));
|
||||
|
||||
//release the BDL object - nothing to check here, the BDL memory is just freed
|
||||
esp_partition_release_blockdev(part_blockdev);
|
||||
}
|
||||
|
||||
TEST(esp_partition, test_bdl_interface_external)
|
||||
{
|
||||
//register external partition
|
||||
const esp_partition_t* ext_partition;
|
||||
TEST_ESP_OK(esp_partition_register_external(NULL, 0x1D0000, 0x20000, "storage3", ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, &ext_partition));
|
||||
|
||||
//get the block-device interface instance and test all the ops over external partition
|
||||
esp_blockdev_handle_t part_blockdev = NULL;
|
||||
TEST_ESP_OK(esp_partition_ptr_get_blockdev(ext_partition, &part_blockdev));
|
||||
|
||||
const size_t data_size = 256;
|
||||
uint8_t test_data[data_size];
|
||||
const off_t target_addr = 3*4*1024;
|
||||
uint8_t data_buffer[data_size];
|
||||
memset((void*)data_buffer, 0, data_size);
|
||||
|
||||
//erase the first sector data from the blockdev and check it's really wiped
|
||||
TEST_ESP_OK(part_blockdev->erase(part_blockdev, target_addr, part_blockdev->geometry.erase_size));
|
||||
memset((void*)test_data, 0xFF, data_size); //erased NOR flash sector contains only 1s
|
||||
TEST_ESP_OK(part_blockdev->read(part_blockdev, data_buffer, sizeof(data_buffer), target_addr, data_size));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer, data_size));
|
||||
|
||||
//write to the blockdev
|
||||
memset((void*)test_data, 'A', data_size);
|
||||
TEST_ESP_OK(part_blockdev->write(part_blockdev, test_data, target_addr, data_size));
|
||||
|
||||
//read from the blockdev the data written before
|
||||
TEST_ESP_OK(part_blockdev->read(part_blockdev, data_buffer, sizeof(data_buffer), target_addr, data_size));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer, data_size));
|
||||
|
||||
//release the BDL object - nothing to check here, the BDL memory is just freed
|
||||
esp_partition_release_blockdev(part_blockdev);
|
||||
|
||||
//deregister the external partition
|
||||
TEST_ESP_OK(esp_partition_deregister_external(ext_partition));
|
||||
}
|
||||
|
||||
TEST(esp_partition, test_bdl_two_partitions)
|
||||
{
|
||||
//get the block-device interface instance for partition 'storage1'
|
||||
esp_blockdev_handle_t part_blockdev_1 = NULL;
|
||||
TEST_ESP_OK(esp_partition_get_blockdev(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1", &part_blockdev_1));
|
||||
|
||||
//get pointer to esp_partition_t object for partition 'storage2'
|
||||
esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage2");
|
||||
TEST_ASSERT_NOT_NULL(iter);
|
||||
const esp_partition_t *part = esp_partition_get(iter);
|
||||
TEST_ASSERT_NOT_NULL(part);
|
||||
esp_partition_iterator_release(iter);
|
||||
|
||||
esp_blockdev_handle_t part_blockdev_2 = NULL;
|
||||
TEST_ESP_OK(esp_partition_ptr_get_blockdev(part, &part_blockdev_2));
|
||||
|
||||
//erase & write & read data on both partitions in parallel
|
||||
const size_t data_size = 256;
|
||||
uint8_t test_data[data_size];
|
||||
const off_t target_addr = 3*4*1024;
|
||||
uint8_t data_buffer_1[data_size];
|
||||
uint8_t data_buffer_2[data_size];
|
||||
memset((void*)data_buffer_1, 0, data_size);
|
||||
memset((void*)data_buffer_2, 0, data_size);
|
||||
|
||||
//erase the first sector data from the blockdev and check it's really wiped
|
||||
TEST_ESP_OK(part_blockdev_1->erase(part_blockdev_1, target_addr, part_blockdev_1->geometry.erase_size));
|
||||
TEST_ESP_OK(part_blockdev_2->erase(part_blockdev_2, target_addr, part_blockdev_2->geometry.erase_size));
|
||||
memset((void*)test_data, 0xFF, data_size); //erased NOR flash sector contains only 1s
|
||||
|
||||
TEST_ESP_OK(part_blockdev_1->read(part_blockdev_1, data_buffer_1, sizeof(data_buffer_1), target_addr, data_size));
|
||||
TEST_ESP_OK(part_blockdev_2->read(part_blockdev_2, data_buffer_2, sizeof(data_buffer_2), target_addr, data_size));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer_1, data_size));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer_2, data_size));
|
||||
|
||||
//write to the blockdev 1
|
||||
memset((void*)test_data, 'A', data_size);
|
||||
TEST_ESP_OK(part_blockdev_1->write(part_blockdev_1, test_data, target_addr, data_size));
|
||||
|
||||
//read the data written before from the blockdev 1
|
||||
TEST_ESP_OK(part_blockdev_1->read(part_blockdev_1, data_buffer_1, sizeof(data_buffer_1), target_addr, data_size));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer_1, data_size));
|
||||
|
||||
//write to the blockdev 2
|
||||
memset((void*)test_data, 'B', data_size);
|
||||
TEST_ESP_OK(part_blockdev_2->write(part_blockdev_2, test_data, target_addr, data_size));
|
||||
|
||||
//read the data written before from the blockdev 2
|
||||
TEST_ESP_OK(part_blockdev_2->read(part_blockdev_2, data_buffer_2, sizeof(data_buffer_2), target_addr, data_size));
|
||||
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer_2, data_size));
|
||||
|
||||
//release the BDL object - nothing to check here, the BDL memory is just freed
|
||||
esp_partition_release_blockdev(part_blockdev_1);
|
||||
esp_partition_release_blockdev(part_blockdev_2);
|
||||
}
|
||||
|
||||
TEST_GROUP_RUNNER(esp_partition)
|
||||
{
|
||||
RUN_TEST_CASE(esp_partition, test_bdl_interface)
|
||||
RUN_TEST_CASE(esp_partition, test_bdl_interface_external)
|
||||
RUN_TEST_CASE(esp_partition, test_bdl_two_partitions)
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
UNITY_MAIN(esp_partition);
|
||||
}
|
||||
7
components/esp_partition/test_apps/partitions.csv
Normal file
7
components/esp_partition/test_apps/partitions.csv
Normal file
@@ -0,0 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
storage1, data, , 0x110000, 512K
|
||||
storage2, data, , 0x190000, 256K,
|
||||
|
11
components/esp_partition/test_apps/pytest_esp_partition.py
Normal file
11
components/esp_partition/test_apps/pytest_esp_partition.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target'])
|
||||
def test_esp_partition(dut: Dut) -> None:
|
||||
dut.expect_unity_test_output()
|
||||
7
components/esp_partition/test_apps/sdkconfig.defaults
Normal file
7
components/esp_partition/test_apps/sdkconfig.defaults
Normal file
@@ -0,0 +1,7 @@
|
||||
# unity framework
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
|
||||
# use custom partition table
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
Reference in New Issue
Block a user