diff --git a/components/esp_blockdev/include/esp_blockdev.h b/components/esp_blockdev/include/esp_blockdev.h index 455a224d08..1e9c903c70 100644 --- a/components/esp_blockdev/include/esp_blockdev.h +++ b/components/esp_blockdev/include/esp_blockdev.h @@ -217,8 +217,8 @@ typedef struct esp_blockdev_t { /* Device context pointer */ void* ctx; - const esp_blockdev_flags_t device_flags; - const esp_blockdev_geometry_t geometry; + esp_blockdev_flags_t device_flags; + esp_blockdev_geometry_t geometry; const esp_blockdev_ops_t* ops; } esp_blockdev_t; diff --git a/components/esp_partition/host_test/.build-test-rules.yml b/components/esp_partition/host_test/.build-test-rules.yml index 958ef7d877..39b8d40db0 100644 --- a/components/esp_partition/host_test/.build-test-rules.yml +++ b/components/esp_partition/host_test/.build-test-rules.yml @@ -5,7 +5,6 @@ components/esp_partition/host_test/partition_api_test: - if: IDF_TARGET == "linux" reason: only test on linux depends_components: - - spi_flash - esp_partition components/esp_partition/host_test/partition_bdl_test: @@ -13,5 +12,5 @@ components/esp_partition/host_test/partition_bdl_test: - if: IDF_TARGET == "linux" reason: only test on linux depends_components: - - spi_flash + - esp_blockdev - esp_partition diff --git a/components/esp_partition/host_test/partition_api_test/README.md b/components/esp_partition/host_test/partition_api_test/README.md index e354c523e7..4ede983db8 100644 --- a/components/esp_partition/host_test/partition_api_test/README.md +++ b/components/esp_partition/host_test/partition_api_test/README.md @@ -1,9 +1,9 @@ | Supported Targets | Linux | | ----------------- | ----- | -This is a test project for verification of esp_partition component APIs on Linux target (CONFIG_IDF_TARGET_LINUX). +This is a test project for verification of 'esp_partition' component APIs on Linux target (CONFIG_IDF_TARGET_LINUX). It verifies all important APIs and properties, and prints the results. -The Block-Device Layer tests have names with a prefix 'test_parition_bdl', available in 'components/esp_partition/host_test/partition_bdl_test', and the tests check all the BDL operations and commands related to 'esp_partition' (on host side) +The Block-Device Layer tests have names with a prefix 'test_partition_bdl', available in 'components/esp_partition/host_test/partition_bdl_test', and the tests check all the BDL operations and commands related to 'esp_partition' (on host side) # Build Source the IDF environment as usual. diff --git a/components/esp_partition/host_test/partition_bdl_test/README.md b/components/esp_partition/host_test/partition_bdl_test/README.md index 95bd2390cd..51e28138d1 100644 --- a/components/esp_partition/host_test/partition_bdl_test/README.md +++ b/components/esp_partition/host_test/partition_bdl_test/README.md @@ -1,7 +1,7 @@ | Supported Targets | Linux | | ----------------- | ----- | -This is a test project for esp_partition Block Device Layer interface on Linux target (CONFIG_IDF_TARGET_LINUX). +This is a test project for 'esp_partition' Block Device Layer interface on Linux target (CONFIG_IDF_TARGET_LINUX). # Build Source the IDF environment as usual. diff --git a/components/esp_partition/host_test/partition_bdl_test/main/partition_bdl_test.c b/components/esp_partition/host_test/partition_bdl_test/main/partition_bdl_test.c index 0a15c14550..c246049f36 100644 --- a/components/esp_partition/host_test/partition_bdl_test/main/partition_bdl_test.c +++ b/components/esp_partition/host_test/partition_bdl_test/main/partition_bdl_test.c @@ -41,22 +41,22 @@ TEST(partition_bdl, test_partition_bdl_ops) 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)); + TEST_ESP_OK(part_blockdev->ops->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_ESP_OK(part_blockdev->ops->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)); + TEST_ESP_OK(part_blockdev->ops->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_ESP_OK(part_blockdev->ops->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); + //release the BDL object + TEST_ESP_OK(part_blockdev->ops->release(part_blockdev)); } /* Test parallel access to two independent partitions through BDL interface. @@ -89,34 +89,34 @@ TEST(partition_bdl, test_two_partitions_bdl_ops) 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)); + TEST_ESP_OK(part_blockdev_1->ops->erase(part_blockdev_1, target_addr, part_blockdev_1->geometry.erase_size)); + TEST_ESP_OK(part_blockdev_2->ops->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_ESP_OK(part_blockdev_1->ops->read(part_blockdev_1, data_buffer_1, sizeof(data_buffer_1), target_addr, data_size)); + TEST_ESP_OK(part_blockdev_2->ops->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)); + TEST_ESP_OK(part_blockdev_1->ops->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_ESP_OK(part_blockdev_1->ops->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)); + TEST_ESP_OK(part_blockdev_2->ops->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_ESP_OK(part_blockdev_2->ops->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); + //release the BDL objects + TEST_ESP_OK(part_blockdev_1->ops->release(part_blockdev_1)); + TEST_ESP_OK(part_blockdev_2->ops->release(part_blockdev_2)); } TEST_GROUP_RUNNER(partition_bdl) diff --git a/components/esp_partition/include/esp_partition.h b/components/esp_partition/include/esp_partition.h index 709819d4fd..5573380989 100644 --- a/components/esp_partition/include/esp_partition.h +++ b/components/esp_partition/include/esp_partition.h @@ -659,18 +659,6 @@ esp_err_t esp_partition_get_blockdev(const esp_partition_type_t type, const esp_ */ esp_err_t esp_partition_ptr_get_blockdev(const esp_partition_t *partition, esp_blockdev_handle_t *out_bdl_handle); -/** - * @brief Release BDL instance associated with specific partition - * - * Releases BDL structure instance and related internal data. It is strongly recommended to use this API for releasing the BDL handles - * created through 'esp_partition_get_blockdev()' or 'esp_partition_ptr_get_blockdev()'calls, due to possible internal dependencies - * and memory allocations not "visible" outside of the 'esp_partition' public BDL interface. - * - * @param[in] dev_handle Block device instance handle to close - * - */ -void esp_partition_release_blockdev(esp_blockdev_handle_t dev_handle); - #ifdef __cplusplus } #endif diff --git a/components/esp_partition/partition.c b/components/esp_partition/partition.c index f3b9180474..0925d9106e 100644 --- a/components/esp_partition/partition.c +++ b/components/esp_partition/partition.c @@ -67,12 +67,6 @@ typedef struct esp_partition_iterator_opaque_ { esp_partition_t *info; // pointer to info (it is redundant, but makes code more readable) } esp_partition_iterator_opaque_t; -typedef struct { - esp_blockdev_t blockdev; - const esp_partition_t *partition; -} esp_partition_bdl_t; - - static SLIST_HEAD(partition_list_head_, partition_list_item_) s_partition_list = SLIST_HEAD_INITIALIZER(s_partition_list); static _lock_t s_partition_list_lock; @@ -650,7 +644,7 @@ static esp_err_t esp_partition_blockdev_read(esp_blockdev_handle_t dev_handle, u return ESP_ERR_INVALID_ARG; } - const esp_partition_t* partition = ((esp_partition_bdl_t*)dev_handle)->partition; + const esp_partition_t* partition = ((const esp_partition_t*)dev_handle->ctx); assert(partition != NULL); esp_err_t res = esp_partition_read(partition, src_addr, dst_buf, data_read_len); @@ -666,7 +660,7 @@ static esp_err_t esp_partition_blockdev_write(esp_blockdev_handle_t dev_handle, return ESP_ERR_INVALID_SIZE; } - const esp_partition_t* partition = ((esp_partition_bdl_t*)dev_handle)->partition; + const esp_partition_t* partition = ((const esp_partition_t*)dev_handle->ctx); assert(partition != NULL); esp_err_t res = esp_partition_write(partition, dst_addr, src_buf, data_write_len); @@ -682,7 +676,7 @@ static esp_err_t esp_partition_blockdev_erase(esp_blockdev_handle_t dev_handle, return ESP_ERR_INVALID_SIZE; } - const esp_partition_t* partition = ((esp_partition_bdl_t*)dev_handle)->partition; + const esp_partition_t* partition = ((const esp_partition_t*)dev_handle->ctx); assert(partition != NULL); esp_err_t res = esp_partition_erase_range(partition, start_addr, erase_len); @@ -691,29 +685,42 @@ static esp_err_t esp_partition_blockdev_erase(esp_blockdev_handle_t dev_handle, return res; } +static esp_err_t esp_partition_blockdev_release(esp_blockdev_handle_t dev_handle) +{ + free(dev_handle); + return ESP_OK; +} + +//BDL ops singleton +static const esp_blockdev_ops_t s_bdl_ops = { + .read = esp_partition_blockdev_read, + .write = esp_partition_blockdev_write, + .erase = esp_partition_blockdev_erase, + .release = esp_partition_blockdev_release +}; + esp_err_t esp_partition_ptr_get_blockdev(const esp_partition_t* partition, esp_blockdev_handle_t *out_bdl_handle_ptr) { - esp_partition_bdl_t *out = calloc(1, sizeof(esp_partition_bdl_t)); + esp_blockdev_t *out = calloc(1, sizeof(esp_blockdev_t)); if (out == NULL) { return ESP_ERR_NO_MEM; } - //! the flags should be read from the bottom device - TBD (required for NAND flash etc) - ESP_BLOCKDEV_FLAGS_INST_CONFIG_DEFAULT(out->blockdev.device_flags); + out->ctx = (void*)partition; - out->blockdev.read = &esp_partition_blockdev_read; - out->blockdev.write = &esp_partition_blockdev_write; - out->blockdev.erase = &esp_partition_blockdev_erase; - out->blockdev.geometry.disk_size = partition->size; - out->blockdev.geometry.write_size = 1; - out->blockdev.geometry.read_size = 1; - out->blockdev.geometry.erase_size = partition->erase_size; - out->blockdev.geometry.recommended_write_size = 1; - out->blockdev.geometry.recommended_read_size = 1; - out->blockdev.geometry.recommended_erase_size = partition->erase_size; - out->partition = partition; + ESP_BLOCKDEV_FLAGS_INST_CONFIG_DEFAULT(out->device_flags); - *out_bdl_handle_ptr = (esp_blockdev_handle_t)out; + out->geometry.disk_size = partition->size; + out->geometry.write_size = 1; + out->geometry.read_size = 1; + out->geometry.erase_size = partition->erase_size; + out->geometry.recommended_write_size = 1; + out->geometry.recommended_read_size = 1; + out->geometry.recommended_erase_size = partition->erase_size; + + out->ops = &s_bdl_ops; + + *out_bdl_handle_ptr = out; return ESP_OK; } @@ -730,8 +737,3 @@ esp_err_t esp_partition_get_blockdev(const esp_partition_type_t type, const esp_ return res; } - -void esp_partition_release_blockdev(esp_blockdev_handle_t dev_handle) -{ - free((esp_partition_bdl_t*)dev_handle); -} diff --git a/components/esp_partition/test_apps/.build-test-rules.yml b/components/esp_partition/test_apps/.build-test-rules.yml index 4a1906602d..5205adef8c 100644 --- a/components/esp_partition/test_apps/.build-test-rules.yml +++ b/components/esp_partition/test_apps/.build-test-rules.yml @@ -3,5 +3,5 @@ components/esp_partition/test_apps: enable: - if: IDF_TARGET in ["esp32", "esp32c3"] - temporary: true - reason: the other targets are not tested yet + temporary: false + reason: sufficient to test on one Xtensa and one RISC-V target diff --git a/components/esp_partition/test_apps/README.md b/components/esp_partition/test_apps/README.md index 1fc457030c..2772e319b7 100644 --- a/components/esp_partition/test_apps/README.md +++ b/components/esp_partition/test_apps/README.md @@ -1,7 +1,7 @@ | 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. +This is a test app for 'esp_partition' component. It verifies all the 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. diff --git a/components/esp_partition/test_apps/main/test_part_app.c b/components/esp_partition/test_apps/main/test_part_app.c index a90df608c4..9ec5ad968d 100644 --- a/components/esp_partition/test_apps/main/test_part_app.c +++ b/components/esp_partition/test_apps/main/test_part_app.c @@ -34,21 +34,21 @@ TEST(esp_partition, test_bdl_interface) 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)); + TEST_ESP_OK(part_blockdev->ops->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_ESP_OK(part_blockdev->ops->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)); + TEST_ESP_OK(part_blockdev->ops->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_ESP_OK(part_blockdev->ops->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_OK(part_blockdev->ops->release(part_blockdev)); } TEST(esp_partition, test_bdl_interface_external) @@ -68,21 +68,21 @@ TEST(esp_partition, test_bdl_interface_external) 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)); + TEST_ESP_OK(part_blockdev->ops->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_ESP_OK(part_blockdev->ops->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)); + TEST_ESP_OK(part_blockdev->ops->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_ESP_OK(part_blockdev->ops->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_OK(part_blockdev->ops->release(part_blockdev)); //deregister the external partition TEST_ESP_OK(esp_partition_deregister_external(ext_partition)); @@ -114,34 +114,34 @@ TEST(esp_partition, test_bdl_two_partitions) 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)); + TEST_ESP_OK(part_blockdev_1->ops->erase(part_blockdev_1, target_addr, part_blockdev_1->geometry.erase_size)); + TEST_ESP_OK(part_blockdev_2->ops->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_ESP_OK(part_blockdev_1->ops->read(part_blockdev_1, data_buffer_1, sizeof(data_buffer_1), target_addr, data_size)); + TEST_ESP_OK(part_blockdev_2->ops->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)); + TEST_ESP_OK(part_blockdev_1->ops->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_ESP_OK(part_blockdev_1->ops->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)); + TEST_ESP_OK(part_blockdev_2->ops->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_ESP_OK(part_blockdev_2->ops->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); + //release the BDL objects + TEST_ESP_OK(part_blockdev_1->ops->release(part_blockdev_1)); + TEST_ESP_OK(part_blockdev_2->ops->release(part_blockdev_2)); } TEST_GROUP_RUNNER(esp_partition)