From 84ba1a323c9873957cb691ae97c67b337157595c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Wed, 29 May 2024 14:12:43 +0200 Subject: [PATCH 01/13] fix(storage/fatfs): move test app to correct directory --- examples/storage/.build-test-rules.yml | 8 -------- examples/storage/README.md | 1 - tools/test_apps/storage/.build-test-rules.yml | 8 ++++++++ .../test_apps}/storage/fatfsgen/CMakeLists.txt | 0 {examples => tools/test_apps}/storage/fatfsgen/README.md | 0 .../test_apps}/storage/fatfsgen/fatfs_image/hello.txt | 0 .../test_apps}/storage/fatfsgen/fatfs_image/sub/test.txt | 0 .../fatfsgen/fatfs_long_name_image/hellolongname.txt | 0 .../sublongnames/testlongfilenames.txt | 0 .../test_apps}/storage/fatfsgen/main/CMakeLists.txt | 0 .../test_apps}/storage/fatfsgen/main/Kconfig.projbuild | 0 .../storage/fatfsgen/main/fatfsgen_example_main.c | 0 .../test_apps}/storage/fatfsgen/partitions_example.csv | 0 .../storage/fatfsgen/pytest_fatfsgen_example.py | 0 .../fatfsgen/sdkconfig.ci.test_read_only_partition_gen | 0 .../sdkconfig.ci.test_read_only_partition_gen_default_dt | 0 .../fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln | 0 ...dkconfig.ci.test_read_only_partition_gen_ln_default_dt | 0 .../fatfsgen/sdkconfig.ci.test_read_write_partition_gen | 0 .../sdkconfig.ci.test_read_write_partition_gen_default_dt | 0 .../sdkconfig.ci.test_read_write_partition_gen_ln | 0 ...kconfig.ci.test_read_write_partition_gen_ln_default_dt | 0 .../test_apps}/storage/fatfsgen/sdkconfig.defaults | 0 23 files changed, 8 insertions(+), 9 deletions(-) rename {examples => tools/test_apps}/storage/fatfsgen/CMakeLists.txt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/README.md (100%) rename {examples => tools/test_apps}/storage/fatfsgen/fatfs_image/hello.txt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/fatfs_image/sub/test.txt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/fatfs_long_name_image/hellolongname.txt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/fatfs_long_name_image/sublongnames/testlongfilenames.txt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/main/CMakeLists.txt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/main/Kconfig.projbuild (100%) rename {examples => tools/test_apps}/storage/fatfsgen/main/fatfsgen_example_main.c (100%) rename {examples => tools/test_apps}/storage/fatfsgen/partitions_example.csv (100%) rename {examples => tools/test_apps}/storage/fatfsgen/pytest_fatfsgen_example.py (100%) rename {examples => tools/test_apps}/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen (100%) rename {examples => tools/test_apps}/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_default_dt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln (100%) rename {examples => tools/test_apps}/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln_default_dt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen (100%) rename {examples => tools/test_apps}/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_default_dt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln (100%) rename {examples => tools/test_apps}/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln_default_dt (100%) rename {examples => tools/test_apps}/storage/fatfsgen/sdkconfig.defaults (100%) diff --git a/examples/storage/.build-test-rules.yml b/examples/storage/.build-test-rules.yml index 4e7e8c66cb..341e0f595a 100644 --- a/examples/storage/.build-test-rules.yml +++ b/examples/storage/.build-test-rules.yml @@ -34,14 +34,6 @@ examples/storage/ext_flash_fatfs: temporary: true reason: lack of runners -examples/storage/fatfsgen: - depends_components: - - fatfs - - vfs - disable_test: - - if: IDF_TARGET != "esp32" - reason: only one target needed - examples/storage/nvs_rw_blob: depends_components: - nvs_flash diff --git a/examples/storage/README.md b/examples/storage/README.md index bb5c821fe8..4705e72615 100644 --- a/examples/storage/README.md +++ b/examples/storage/README.md @@ -10,7 +10,6 @@ The examples are grouped into sub-directories by category. Each category directo * `custom_flash_driver` example demonstrates how to implement your own flash chip driver by overriding the default driver. * `emmc` example demonstrates how to use an eMMC chip with an ESP device. * `ext_flash_fatfs` example demonstrates how to use FATFS partition with external SPI FLASH chip. -* `fatfsgen` example demonstrates how to use FATFS partition * `nvs_rw_blob` example demonstrates how to read and write a single integer value and a blob (binary large object) using NVS to preserve them between ESP module restarts. * `nvs_rw_value` example demonstrates how to read and write a single integer value using NVS. * `nvs_rw_value_cxx` example demonstrates how to read and write a single integer value using NVS (it uses the C++ NVS handle API). diff --git a/tools/test_apps/storage/.build-test-rules.yml b/tools/test_apps/storage/.build-test-rules.yml index d27c0ab893..f0ab55097c 100644 --- a/tools/test_apps/storage/.build-test-rules.yml +++ b/tools/test_apps/storage/.build-test-rules.yml @@ -1,5 +1,13 @@ # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps +tools/test_apps/storage/fatfsgen: + depends_components: + - fatfs + - vfs + disable_test: + - if: IDF_TARGET != "esp32" + reason: only one target needed + tools/test_apps/storage/partition_table_readonly: disable_test: - if: IDF_TARGET not in ["esp32", "esp32c3"] diff --git a/examples/storage/fatfsgen/CMakeLists.txt b/tools/test_apps/storage/fatfsgen/CMakeLists.txt similarity index 100% rename from examples/storage/fatfsgen/CMakeLists.txt rename to tools/test_apps/storage/fatfsgen/CMakeLists.txt diff --git a/examples/storage/fatfsgen/README.md b/tools/test_apps/storage/fatfsgen/README.md similarity index 100% rename from examples/storage/fatfsgen/README.md rename to tools/test_apps/storage/fatfsgen/README.md diff --git a/examples/storage/fatfsgen/fatfs_image/hello.txt b/tools/test_apps/storage/fatfsgen/fatfs_image/hello.txt similarity index 100% rename from examples/storage/fatfsgen/fatfs_image/hello.txt rename to tools/test_apps/storage/fatfsgen/fatfs_image/hello.txt diff --git a/examples/storage/fatfsgen/fatfs_image/sub/test.txt b/tools/test_apps/storage/fatfsgen/fatfs_image/sub/test.txt similarity index 100% rename from examples/storage/fatfsgen/fatfs_image/sub/test.txt rename to tools/test_apps/storage/fatfsgen/fatfs_image/sub/test.txt diff --git a/examples/storage/fatfsgen/fatfs_long_name_image/hellolongname.txt b/tools/test_apps/storage/fatfsgen/fatfs_long_name_image/hellolongname.txt similarity index 100% rename from examples/storage/fatfsgen/fatfs_long_name_image/hellolongname.txt rename to tools/test_apps/storage/fatfsgen/fatfs_long_name_image/hellolongname.txt diff --git a/examples/storage/fatfsgen/fatfs_long_name_image/sublongnames/testlongfilenames.txt b/tools/test_apps/storage/fatfsgen/fatfs_long_name_image/sublongnames/testlongfilenames.txt similarity index 100% rename from examples/storage/fatfsgen/fatfs_long_name_image/sublongnames/testlongfilenames.txt rename to tools/test_apps/storage/fatfsgen/fatfs_long_name_image/sublongnames/testlongfilenames.txt diff --git a/examples/storage/fatfsgen/main/CMakeLists.txt b/tools/test_apps/storage/fatfsgen/main/CMakeLists.txt similarity index 100% rename from examples/storage/fatfsgen/main/CMakeLists.txt rename to tools/test_apps/storage/fatfsgen/main/CMakeLists.txt diff --git a/examples/storage/fatfsgen/main/Kconfig.projbuild b/tools/test_apps/storage/fatfsgen/main/Kconfig.projbuild similarity index 100% rename from examples/storage/fatfsgen/main/Kconfig.projbuild rename to tools/test_apps/storage/fatfsgen/main/Kconfig.projbuild diff --git a/examples/storage/fatfsgen/main/fatfsgen_example_main.c b/tools/test_apps/storage/fatfsgen/main/fatfsgen_example_main.c similarity index 100% rename from examples/storage/fatfsgen/main/fatfsgen_example_main.c rename to tools/test_apps/storage/fatfsgen/main/fatfsgen_example_main.c diff --git a/examples/storage/fatfsgen/partitions_example.csv b/tools/test_apps/storage/fatfsgen/partitions_example.csv similarity index 100% rename from examples/storage/fatfsgen/partitions_example.csv rename to tools/test_apps/storage/fatfsgen/partitions_example.csv diff --git a/examples/storage/fatfsgen/pytest_fatfsgen_example.py b/tools/test_apps/storage/fatfsgen/pytest_fatfsgen_example.py similarity index 100% rename from examples/storage/fatfsgen/pytest_fatfsgen_example.py rename to tools/test_apps/storage/fatfsgen/pytest_fatfsgen_example.py diff --git a/examples/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen b/tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen similarity index 100% rename from examples/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen rename to tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen diff --git a/examples/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_default_dt b/tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_default_dt similarity index 100% rename from examples/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_default_dt rename to tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_default_dt diff --git a/examples/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln b/tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln similarity index 100% rename from examples/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln rename to tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln diff --git a/examples/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln_default_dt b/tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln_default_dt similarity index 100% rename from examples/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln_default_dt rename to tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln_default_dt diff --git a/examples/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen b/tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen similarity index 100% rename from examples/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen rename to tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen diff --git a/examples/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_default_dt b/tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_default_dt similarity index 100% rename from examples/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_default_dt rename to tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_default_dt diff --git a/examples/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln b/tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln similarity index 100% rename from examples/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln rename to tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln diff --git a/examples/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln_default_dt b/tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln_default_dt similarity index 100% rename from examples/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln_default_dt rename to tools/test_apps/storage/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln_default_dt diff --git a/examples/storage/fatfsgen/sdkconfig.defaults b/tools/test_apps/storage/fatfsgen/sdkconfig.defaults similarity index 100% rename from examples/storage/fatfsgen/sdkconfig.defaults rename to tools/test_apps/storage/fatfsgen/sdkconfig.defaults From b9a54fb1f3f9fc992f5db142b30f130212d6c156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Wed, 29 May 2024 10:10:38 +0200 Subject: [PATCH 02/13] feat(storage/fatfs): add minimal FatFS example --- examples/storage/.build-test-rules.yml | 8 ++ examples/storage/README.md | 1 + examples/storage/fatfs_basic/CMakeLists.txt | 6 ++ examples/storage/fatfs_basic/README.md | 43 +++++++++ .../storage/fatfs_basic/main/CMakeLists.txt | 2 + .../fatfs_basic/main/fat_example_main.c | 87 +++++++++++++++++++ .../fatfs_basic/partitions_example.csv | 6 ++ .../storage/fatfs_basic/pytest_fat_example.py | 17 ++++ .../storage/fatfs_basic/sdkconfig.defaults | 4 + 9 files changed, 174 insertions(+) create mode 100644 examples/storage/fatfs_basic/CMakeLists.txt create mode 100644 examples/storage/fatfs_basic/README.md create mode 100644 examples/storage/fatfs_basic/main/CMakeLists.txt create mode 100644 examples/storage/fatfs_basic/main/fat_example_main.c create mode 100644 examples/storage/fatfs_basic/partitions_example.csv create mode 100644 examples/storage/fatfs_basic/pytest_fat_example.py create mode 100644 examples/storage/fatfs_basic/sdkconfig.defaults diff --git a/examples/storage/.build-test-rules.yml b/examples/storage/.build-test-rules.yml index 341e0f595a..a15e95e333 100644 --- a/examples/storage/.build-test-rules.yml +++ b/examples/storage/.build-test-rules.yml @@ -34,6 +34,14 @@ examples/storage/ext_flash_fatfs: temporary: true reason: lack of runners +examples/storage/fatfs_basic: + depends_components: + - fatfs + - vfs + disable_test: + - if: IDF_TARGET != "esp32" + reason: only one target needed + examples/storage/nvs_rw_blob: depends_components: - nvs_flash diff --git a/examples/storage/README.md b/examples/storage/README.md index 4705e72615..ade0b883a1 100644 --- a/examples/storage/README.md +++ b/examples/storage/README.md @@ -7,6 +7,7 @@ This directory contains a range of examples ESP-IDF projects. These are intended The examples are grouped into sub-directories by category. Each category directory contains one or more example projects: +* `fatfs_basic` minimal example of FatFS usage on SPI FLASH * `custom_flash_driver` example demonstrates how to implement your own flash chip driver by overriding the default driver. * `emmc` example demonstrates how to use an eMMC chip with an ESP device. * `ext_flash_fatfs` example demonstrates how to use FATFS partition with external SPI FLASH chip. diff --git a/examples/storage/fatfs_basic/CMakeLists.txt b/examples/storage/fatfs_basic/CMakeLists.txt new file mode 100644 index 0000000000..1c0c2b8a1a --- /dev/null +++ b/examples/storage/fatfs_basic/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(fatfsgen) diff --git a/examples/storage/fatfs_basic/README.md b/examples/storage/fatfs_basic/README.md new file mode 100644 index 0000000000..0ee84f105d --- /dev/null +++ b/examples/storage/fatfs_basic/README.md @@ -0,0 +1,43 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | + +# FATFS minimal example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example demonstrates the minimal setup required to store persistent data on SPI Flash using the FAT filesystem. +Beware that the minimal required size of the flash is 4 MB. + +## How to use example + +### Build and flash + +To run the example, type the following command: + +```CMake +# CMake +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example output + +Here is the example's console output: + +``` +... +I (339) example: Mounting FAT filesystem +I (339) example: Filesystem mounted +I (339) example: Opening file +I (729) example: File written +I (729) example: Reading file +I (739) example: Read from file: 'This is written by the device' +I (739) example: Unmounting FAT filesystem +I (849) example: Done +``` + +The logic of the example is contained in a [single source file](./main/fat_example_main.c), +and it should be relatively simple to match points in its execution with the log outputs above. diff --git a/examples/storage/fatfs_basic/main/CMakeLists.txt b/examples/storage/fatfs_basic/main/CMakeLists.txt new file mode 100644 index 0000000000..827c3c2e8e --- /dev/null +++ b/examples/storage/fatfs_basic/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "fat_example_main.c" + INCLUDE_DIRS ".") diff --git a/examples/storage/fatfs_basic/main/fat_example_main.c b/examples/storage/fatfs_basic/main/fat_example_main.c new file mode 100644 index 0000000000..2a57821e70 --- /dev/null +++ b/examples/storage/fatfs_basic/main/fat_example_main.c @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include "esp_vfs.h" +#include "esp_vfs_fat.h" +#include "sdkconfig.h" + +static const char *TAG = "example"; + +// Mount path for the partition +const char *base_path = "/spiflash"; + +// Handle of the wear levelling library instance +static wl_handle_t s_wl_handle = WL_INVALID_HANDLE; + +void app_main(void) +{ + ESP_LOGI(TAG, "Mounting FAT filesystem"); + // To mount device we need name of device partition, define base_path + // and allow format partition in case if it is new one and was not formatted before + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, // Number of files that can be open at a time + .format_if_mount_failed = true, // If true, try to format the partition if mount fails + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, // Size of allocation unit, cluster size. + .use_one_fat = false, // Use only one FAT table (reduce memory usage), but decrease reliability of file system in case of power failure. + }; + + esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, "storage", &mount_config, &s_wl_handle); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); + return; + } + + ESP_LOGI(TAG, "Filesystem mounted"); + + ESP_LOGI(TAG, "Opening file"); + + const char *filename = "/spiflash/example.txt"; + + FILE *f = fopen(filename, "wb"); + if (f == NULL) { + perror("fopen"); + ESP_LOGE(TAG, "Failed to open file for writing"); + return; + } + + fprintf(f, "This is written by the device"); + fclose(f); + + ESP_LOGI(TAG, "File written"); + + // Open file for reading + ESP_LOGI(TAG, "Reading file"); + + f = fopen(filename, "r"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for reading"); + return; + } + + char line[128]; + + fgets(line, sizeof(line), f); + fclose(f); + + // strip newline + char *pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; + } + + ESP_LOGI(TAG, "Read from file: '%s'", line); + + // Unmount FATFS + ESP_LOGI(TAG, "Unmounting FAT filesystem"); + + ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_rw_wl(base_path, s_wl_handle)); + + ESP_LOGI(TAG, "Done"); +} diff --git a/examples/storage/fatfs_basic/partitions_example.csv b/examples/storage/fatfs_basic/partitions_example.csv new file mode 100644 index 0000000000..1c79321a10 --- /dev/null +++ b/examples/storage/fatfs_basic/partitions_example.csv @@ -0,0 +1,6 @@ +# 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, +storage, data, fat, , 1M, diff --git a/examples/storage/fatfs_basic/pytest_fat_example.py b/examples/storage/fatfs_basic/pytest_fat_example.py new file mode 100644 index 0000000000..7abafe062d --- /dev/null +++ b/examples/storage/fatfs_basic/pytest_fat_example.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32 +@pytest.mark.generic +def test_examples_fatfs_basic(dut: Dut) -> None: + dut.expect('example: Mounting FAT filesystem', timeout=90) + dut.expect('example: Filesystem mounted', timeout=90) + dut.expect('example: Opening file', timeout=90) + dut.expect('example: File written', timeout=90) + dut.expect('example: Reading file', timeout=90) + dut.expect('example: Read from file: \'This is written by the device\'', timeout=90) + dut.expect('example: Unmounting FAT filesystem', timeout=90) + dut.expect('example: Done', timeout=90) diff --git a/examples/storage/fatfs_basic/sdkconfig.defaults b/examples/storage/fatfs_basic/sdkconfig.defaults new file mode 100644 index 0000000000..47363c32d5 --- /dev/null +++ b/examples/storage/fatfs_basic/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y From f633839eceffd424c20dacbec8f597ed46d1294e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Mon, 3 Jun 2024 08:22:52 +0200 Subject: [PATCH 03/13] feat(storage/fatfs): add advanced example for fatfs --- examples/storage/.build-test-rules.yml | 8 + examples/storage/README.md | 1 + .../storage/fatfs_advanced/CMakeLists.txt | 6 + examples/storage/fatfs_advanced/README.md | 69 +++++++++ .../filegeneratedonhost.txt | 1 + .../subdirectoryfromhost/innerfile.txt | 1 + .../fatfs_advanced/main/CMakeLists.txt | 26 ++++ .../fatfs_advanced/main/Kconfig.projbuild | 24 +++ .../main/fatfs_advanced_example_main.c | 138 ++++++++++++++++++ .../fatfs_advanced/partitions_example.csv | 6 + .../pytest_fatfs_advanced_example.py | 112 ++++++++++++++ .../sdkconfig.ci.test_read_only_partition_gen | 5 + ...ci.test_read_only_partition_gen_default_dt | 6 + ...sdkconfig.ci.test_read_write_partition_gen | 5 + ...i.test_read_write_partition_gen_default_dt | 6 + .../storage/fatfs_advanced/sdkconfig.defaults | 7 + 16 files changed, 421 insertions(+) create mode 100644 examples/storage/fatfs_advanced/CMakeLists.txt create mode 100644 examples/storage/fatfs_advanced/README.md create mode 100644 examples/storage/fatfs_advanced/fatfs_long_name_image/filegeneratedonhost.txt create mode 100644 examples/storage/fatfs_advanced/fatfs_long_name_image/subdirectoryfromhost/innerfile.txt create mode 100644 examples/storage/fatfs_advanced/main/CMakeLists.txt create mode 100644 examples/storage/fatfs_advanced/main/Kconfig.projbuild create mode 100644 examples/storage/fatfs_advanced/main/fatfs_advanced_example_main.c create mode 100644 examples/storage/fatfs_advanced/partitions_example.csv create mode 100644 examples/storage/fatfs_advanced/pytest_fatfs_advanced_example.py create mode 100644 examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen create mode 100644 examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen_default_dt create mode 100644 examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen create mode 100644 examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen_default_dt create mode 100644 examples/storage/fatfs_advanced/sdkconfig.defaults diff --git a/examples/storage/.build-test-rules.yml b/examples/storage/.build-test-rules.yml index a15e95e333..5999ae95ea 100644 --- a/examples/storage/.build-test-rules.yml +++ b/examples/storage/.build-test-rules.yml @@ -34,6 +34,14 @@ examples/storage/ext_flash_fatfs: temporary: true reason: lack of runners +examples/storage/fatfs_advanced: + depends_components: + - fatfs + - vfs + disable_test: + - if: IDF_TARGET != "esp32" + reason: only one target needed + examples/storage/fatfs_basic: depends_components: - fatfs diff --git a/examples/storage/README.md b/examples/storage/README.md index ade0b883a1..ebfb75833d 100644 --- a/examples/storage/README.md +++ b/examples/storage/README.md @@ -8,6 +8,7 @@ This directory contains a range of examples ESP-IDF projects. These are intended The examples are grouped into sub-directories by category. Each category directory contains one or more example projects: * `fatfs_basic` minimal example of FatFS usage on SPI FLASH +* `fatfs_advanced` example demonstrates how to use advanced features for working with FatFS such as automatic partition generation * `custom_flash_driver` example demonstrates how to implement your own flash chip driver by overriding the default driver. * `emmc` example demonstrates how to use an eMMC chip with an ESP device. * `ext_flash_fatfs` example demonstrates how to use FATFS partition with external SPI FLASH chip. diff --git a/examples/storage/fatfs_advanced/CMakeLists.txt b/examples/storage/fatfs_advanced/CMakeLists.txt new file mode 100644 index 0000000000..1c0c2b8a1a --- /dev/null +++ b/examples/storage/fatfs_advanced/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(fatfsgen) diff --git a/examples/storage/fatfs_advanced/README.md b/examples/storage/fatfs_advanced/README.md new file mode 100644 index 0000000000..34ab038fc5 --- /dev/null +++ b/examples/storage/fatfs_advanced/README.md @@ -0,0 +1,69 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | + +# FATFS partition generation example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example demonstrates how to use the FATFS partition +generation tool [fatfsgen.py](../../../components/fatfs/fatfsgen.py) to automatically create a FATFS +filesystem image from the contents of a host folder during build, with an option of +automatically flashing the created image on invocation of `idf.py -p PORT flash` as well as usage of long file names for FATFS. +Beware that the minimal required size of the flash is 4 MB. +You can specify using menuconfig weather example will use read-only or read-write mode. The default option is read-write mode. +To change it just use menuconfig: + +```shell +idf.py menuconfig +``` + +Then select `Example Configuration` a chose `Mode for generated FATFS image` either `Read-Write Mode` or `Read-Only Mode`. +`Read-Only` option indicates generating raw fatfs image without wear levelling support. +On the other hand, for `Read-Write` the generated fatfs image will support wear levelling thus can be mounted in read-write mode. + + +The following gives an overview of the example: + +1. There is a directory `fatfs_image` from which the FATFS filesystem image will be created. + +2. The function `fatfs_create_rawflash_image` is used to specify that a FATFS image +should be created during build for the `storage` partition. +For CMake, it is called from [the main component's CMakeLists.txt](./main/CMakeLists.txt). +`FLASH_IN_PROJECT` specifies that the created image +should be flashed on invocation of `idf.py -p PORT flash` together with app, bootloader, partition table, etc. +The image is created on the example's build directory with the output filename `storage.bin`. + +3. Upon invocation of `idf.py -p PORT flash monitor`, application loads and +finds there is already a valid FATFS filesystem in the `storage` partition with files same as those in `fatfs_image` directory. The application is then +able to read those files. + +## How to use example + +### Build and flash + +To run the example, type the following command: + +```CMake +# CMake +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example output + +Here is the example's console output: + +``` +... +I (322) example: Mounting FAT filesystem +I (332) example: Reading file +I (332) example: Read from file: 'this is test' +I (332) example: Unmounting FAT filesystem +I (342) example: Done +``` + +The logic of the example is contained in a [single source file](./main/fatfsgen_example_main.c), +and it should be relatively simple to match points in its execution with the log outputs above. diff --git a/examples/storage/fatfs_advanced/fatfs_long_name_image/filegeneratedonhost.txt b/examples/storage/fatfs_advanced/fatfs_long_name_image/filegeneratedonhost.txt new file mode 100644 index 0000000000..33f47c9b1d --- /dev/null +++ b/examples/storage/fatfs_advanced/fatfs_long_name_image/filegeneratedonhost.txt @@ -0,0 +1 @@ +This is generated on the host; it has long name diff --git a/examples/storage/fatfs_advanced/fatfs_long_name_image/subdirectoryfromhost/innerfile.txt b/examples/storage/fatfs_advanced/fatfs_long_name_image/subdirectoryfromhost/innerfile.txt new file mode 100644 index 0000000000..84505e3d3e --- /dev/null +++ b/examples/storage/fatfs_advanced/fatfs_long_name_image/subdirectoryfromhost/innerfile.txt @@ -0,0 +1 @@ +this is test; it has long name diff --git a/examples/storage/fatfs_advanced/main/CMakeLists.txt b/examples/storage/fatfs_advanced/main/CMakeLists.txt new file mode 100644 index 0000000000..28eed4c7c3 --- /dev/null +++ b/examples/storage/fatfs_advanced/main/CMakeLists.txt @@ -0,0 +1,26 @@ +idf_component_register(SRCS "fatfs_advanced_example_main.c" + INCLUDE_DIRS ".") + +# Create a FATFS image from the contents of the 'fatfs_image' directory +# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that +# the generated image should be flashed when the entire project is flashed to +# the target with 'idf.py -p PORT flash'. +# If read-only mode is set (CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY) +# the generated image will be raw without wear levelling support. +# Otherwise it will support wear levelling and thus enable read-write mounting of the image in the device. + +set(image ../fatfs_long_name_image) + +if(CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY) + if(CONFIG_EXAMPLE_FATFS_DEFAULT_DATETIME) + fatfs_create_rawflash_image(storage ${image} FLASH_IN_PROJECT) + else() + fatfs_create_rawflash_image(storage ${image} FLASH_IN_PROJECT PRESERVE_TIME) + endif() +else() + if(CONFIG_EXAMPLE_FATFS_DEFAULT_DATETIME) + fatfs_create_spiflash_image(storage ${image} FLASH_IN_PROJECT) + else() + fatfs_create_spiflash_image(storage ${image} FLASH_IN_PROJECT PRESERVE_TIME) + endif() +endif() diff --git a/examples/storage/fatfs_advanced/main/Kconfig.projbuild b/examples/storage/fatfs_advanced/main/Kconfig.projbuild new file mode 100644 index 0000000000..b715c917b8 --- /dev/null +++ b/examples/storage/fatfs_advanced/main/Kconfig.projbuild @@ -0,0 +1,24 @@ +menu "Example Configuration" + + config EXAMPLE_FATFS_MODE_READ_ONLY + bool "Read only mode for generated FATFS image" + default n + help + If read-only mode is set, the generated fatfs image will be raw (without wear levelling support). + Otherwise it will support wear levelling that enables read-write mounting. + + config EXAMPLE_FATFS_WRITE_COUNT + int "Number of volumes" + default 1 + range 1 600 + help + Number of writes to the file (for testing purposes). + + config EXAMPLE_FATFS_DEFAULT_DATETIME + bool "Default modification date and time for generated FATFS image" + default n + help + If default datetime is set, all files created in the generated FATFS partition have default time + equal to FATFS origin time (1 January 1980) + +endmenu diff --git a/examples/storage/fatfs_advanced/main/fatfs_advanced_example_main.c b/examples/storage/fatfs_advanced/main/fatfs_advanced_example_main.c new file mode 100644 index 0000000000..3d8032b163 --- /dev/null +++ b/examples/storage/fatfs_advanced/main/fatfs_advanced_example_main.c @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include +#include "esp_vfs.h" +#include "esp_vfs_fat.h" +#include "sdkconfig.h" + +static const char *TAG = "example"; + +// Mount path for the partition +const char *base_path = "/spiflash"; + +void write_file(const char *filename, const char *data) +{ + ESP_LOGI(TAG, "Opening file '%s' for writing", filename); + + FILE *f = fopen(filename, "w"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for writing: %s", strerror(errno)); + return; + } + + ESP_LOGI(TAG, "Writing to file"); + + fputs(data, f); + + ESP_LOGI(TAG, "File written"); + + ESP_LOGI(TAG, "Closing file"); + fclose(f); +} + +void read_file(const char *filename) +{ + ESP_LOGI(TAG, "Opening file '%s' for reading", filename); + + FILE *f = fopen(filename, "r"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for reading: %s", strerror(errno)); + return; + } + + ESP_LOGI(TAG, "Reading from file"); + + char line[128]; + fgets(line, sizeof(line), f); + + // strip newline + char *pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; // strip newline + } + + ESP_LOGI(TAG, "Read from file: '%s'", line); + + ESP_LOGI(TAG, "Closing file '%s'", filename); + fclose(f); +} + +void stat_file(const char *filename) +{ + + struct stat info; + struct tm timeinfo; + char buffer[32]; + + ESP_LOGI(TAG, "Stating file '%s' for modification time", filename); + + if(stat(filename, &info) < 0){ + ESP_LOGE(TAG, "Failed to read file stats: %s", strerror(errno)); + return; + } + localtime_r(&info.st_mtime, &timeinfo); + strftime(buffer, sizeof(buffer), "%Y-%m-%d", &timeinfo); + + ESP_LOGI(TAG, "The file '%s' was modified at date: %s", filename, buffer); +} + +void app_main(void) +{ + ESP_LOGI(TAG, "Mounting FAT filesystem"); + + // To mount device we need name of device partition, define base_path + // and allow format partition in case if it is new one and was not formatted before + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = false, + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, + .use_one_fat = false, + }; + + esp_err_t err; + +#ifdef CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + err = esp_vfs_fat_spiflash_mount_ro(base_path, "storage", &mount_config); +#else // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + + // Handle of the wear levelling library instance + wl_handle_t wl_handle = WL_INVALID_HANDLE; + err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, "storage", &mount_config, &wl_handle); +#endif // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)python $IDF_PATH/tools/ci/ci_build_apps.py . --target esp32 -vv --pytest-apps", esp_err_to_name(err)); + return; + } + + // Read contents of a file + read_file("/spiflash/filegeneratedonhost.txt"); + + +#ifndef CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + // Create and write to a file + write_file("/spiflash/messagefromthedevice.txt", "This is written by the device"); + read_file("/spiflash/messagefromthedevice.txt"); +#endif // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + + // Check when the file was last modified + stat_file("/spiflash/subdirectoryfromhost/innerfile.txt"); + + // Unmount FATFS + ESP_LOGI(TAG, "Unmounting FAT filesystem"); + +#ifdef CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_ro(base_path, "storage")); +#else // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_rw_wl(base_path, wl_handle)); +#endif // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + + ESP_LOGI(TAG, "Done"); +} diff --git a/examples/storage/fatfs_advanced/partitions_example.csv b/examples/storage/fatfs_advanced/partitions_example.csv new file mode 100644 index 0000000000..1c79321a10 --- /dev/null +++ b/examples/storage/fatfs_advanced/partitions_example.csv @@ -0,0 +1,6 @@ +# 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, +storage, data, fat, , 1M, diff --git a/examples/storage/fatfs_advanced/pytest_fatfs_advanced_example.py b/examples/storage/fatfs_advanced/pytest_fatfs_advanced_example.py new file mode 100644 index 0000000000..ea7f491a8f --- /dev/null +++ b/examples/storage/fatfs_advanced/pytest_fatfs_advanced_example.py @@ -0,0 +1,112 @@ +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import re +from datetime import datetime +from typing import List + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32 +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'test_read_only_partition_gen', + 'test_read_only_partition_gen_default_dt', + 'test_read_write_partition_gen', + 'test_read_write_partition_gen_default_dt', + ], + indirect=True, +) +def test_examples_fatfs_advanced(config: str, dut: Dut) -> None: + # Expects list of strings sequentially + def expect_all(msg_list: List[str], to: int) -> None: + for msg in msg_list: + dut.expect(msg, timeout=to) + + # Expects prefix string followed by date in the format 'yyyy-mm-dd' + def expect_date(prefix: str, to: int) -> datetime: + expect_str = prefix + '(\\d+)-(\\d+)-(\\d+)' + match_ = dut.expect(re.compile(str.encode(expect_str)), timeout=to) + year_ = int(match_[1].decode()) + month_ = int(match_[2].decode()) + day_ = int(match_[3].decode()) + return datetime(year_, month_, day_) + + # Calculates absolute difference in days between date_reference and date_actual. + # Raises exception if difference exceeds tolerance + def evaluate_dates( + date_reference: datetime, date_actual: datetime, days_tolerance: int + ) -> None: + td = date_actual - date_reference + if abs(td.days) > days_tolerance: + raise Exception( + f'Too big date difference. Actual: {date_actual}, reference: {date_reference}, tolerance: {days_tolerance} day(s)' + ) + + # Expect timeout + timeout = 20 + + # We tolerate 30 days difference between actual file creation and date when test was executed. + tolerance = 30 + + expected_date = ( + datetime(1980, 1, 1) if config.endswith('default_dt') else datetime.today() + ) + + base_path = '/spiflash/' + folder_name = 'subdirectoryfromhost/' + read_filename = base_path + 'filegeneratedonhost.txt' + write_filename = base_path + 'messagefromthedevice.txt' + stat_filename = base_path + folder_name + 'innerfile.txt' + + dut.expect('example: Mounting FAT filesystem', timeout=timeout) + + # Check read + expect_all( + [ + f'example: Opening file \'{read_filename}\' for reading', + f'example: Reading from file', + 'example: Read from file: \'This is generated on the host; it has long name\'', + f'example: Closing file \'{read_filename}\'', + ], + timeout, + ) + + # Check write + if config.startswith('test_read_write'): + expect_all( + [ + f'example: Opening file \'{write_filename}\' for writing', + 'example: Writing to file', + 'example: File written', + 'example: Closing file', + f'example: Opening file \'{write_filename}\' for reading', + f'example: Reading from file', + 'example: Read from file: \'This is written by the device\'', + f'example: Closing file \'{write_filename}\'', + ], + timeout, + ) + + # Check date using stat + dut.expect( + f'example: Stating file \'{stat_filename}\' for modification time', timeout=timeout + ) + + actual_date = expect_date( + f'The file \'{stat_filename}\' was modified at date: ', timeout + ) + + evaluate_dates(expected_date, actual_date, tolerance) + + # Finish + expect_all( + [ + 'example: Unmounting FAT filesystem', + 'example: Done', + ], + timeout, + ) diff --git a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen new file mode 100644 index 0000000000..21a7938068 --- /dev/null +++ b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen @@ -0,0 +1,5 @@ +CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=y +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_LFN_STACK=n +CONFIG_FATFS_LFN_NONE=n +CONFIG_EXAMPLE_FATFS_WRITE_COUNT=300 diff --git a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen_default_dt b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen_default_dt new file mode 100644 index 0000000000..ed0be2575b --- /dev/null +++ b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen_default_dt @@ -0,0 +1,6 @@ +CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=y +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_LFN_STACK=n +CONFIG_FATFS_LFN_NONE=n +CONFIG_EXAMPLE_FATFS_DEFAULT_DATETIME=y +CONFIG_EXAMPLE_FATFS_WRITE_COUNT=300 diff --git a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen new file mode 100644 index 0000000000..4ffa553233 --- /dev/null +++ b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen @@ -0,0 +1,5 @@ +CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=n +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_LFN_STACK=n +CONFIG_FATFS_LFN_NONE=n +CONFIG_EXAMPLE_FATFS_WRITE_COUNT=300 diff --git a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen_default_dt b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen_default_dt new file mode 100644 index 0000000000..6413768f3e --- /dev/null +++ b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen_default_dt @@ -0,0 +1,6 @@ +CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=n +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_LFN_STACK=n +CONFIG_FATFS_LFN_NONE=n +CONFIG_EXAMPLE_FATFS_DEFAULT_DATETIME=y +CONFIG_EXAMPLE_FATFS_WRITE_COUNT=300 diff --git a/examples/storage/fatfs_advanced/sdkconfig.defaults b/examples/storage/fatfs_advanced/sdkconfig.defaults new file mode 100644 index 0000000000..e5ac937533 --- /dev/null +++ b/examples/storage/fatfs_advanced/sdkconfig.defaults @@ -0,0 +1,7 @@ +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_LFN_NONE=n +CONFIG_FATFS_LFN_STACK=n From 85b5869053e2ba928c3b5553379fa605f85fd491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Mon, 5 Aug 2024 14:09:09 +0200 Subject: [PATCH 04/13] feat(storage/fatfs): restructure basic example --- examples/storage/.build-test-rules.yml | 8 ------- examples/storage/fatfs/.build-test-rules.yml | 9 ++++++++ .../getting_started}/CMakeLists.txt | 0 .../getting_started}/README.md | 23 ++++++++++--------- .../fatfs/getting_started/main/CMakeLists.txt | 2 ++ .../main/fatfs_getting_started_main.c} | 6 ++--- .../getting_started}/partitions_example.csv | 0 .../pytest_fatfs_getting_started_example.py} | 4 ++-- .../getting_started}/sdkconfig.defaults | 0 .../storage/fatfs_basic/main/CMakeLists.txt | 2 -- 10 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 examples/storage/fatfs/.build-test-rules.yml rename examples/storage/{fatfs_basic => fatfs/getting_started}/CMakeLists.txt (100%) rename examples/storage/{fatfs_basic => fatfs/getting_started}/README.md (67%) create mode 100644 examples/storage/fatfs/getting_started/main/CMakeLists.txt rename examples/storage/{fatfs_basic/main/fat_example_main.c => fatfs/getting_started/main/fatfs_getting_started_main.c} (93%) rename examples/storage/{fatfs_basic => fatfs/getting_started}/partitions_example.csv (100%) rename examples/storage/{fatfs_basic/pytest_fat_example.py => fatfs/getting_started/pytest_fatfs_getting_started_example.py} (81%) rename examples/storage/{fatfs_basic => fatfs/getting_started}/sdkconfig.defaults (100%) delete mode 100644 examples/storage/fatfs_basic/main/CMakeLists.txt diff --git a/examples/storage/.build-test-rules.yml b/examples/storage/.build-test-rules.yml index 5999ae95ea..8ec3101a5a 100644 --- a/examples/storage/.build-test-rules.yml +++ b/examples/storage/.build-test-rules.yml @@ -42,14 +42,6 @@ examples/storage/fatfs_advanced: - if: IDF_TARGET != "esp32" reason: only one target needed -examples/storage/fatfs_basic: - depends_components: - - fatfs - - vfs - disable_test: - - if: IDF_TARGET != "esp32" - reason: only one target needed - examples/storage/nvs_rw_blob: depends_components: - nvs_flash diff --git a/examples/storage/fatfs/.build-test-rules.yml b/examples/storage/fatfs/.build-test-rules.yml new file mode 100644 index 0000000000..f652dd52d8 --- /dev/null +++ b/examples/storage/fatfs/.build-test-rules.yml @@ -0,0 +1,9 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +examples/storage/fatfs: + depends_components: + - fatfs + - vfs + disable_test: + - if: IDF_TARGET != "esp32" + reason: only one target needed diff --git a/examples/storage/fatfs_basic/CMakeLists.txt b/examples/storage/fatfs/getting_started/CMakeLists.txt similarity index 100% rename from examples/storage/fatfs_basic/CMakeLists.txt rename to examples/storage/fatfs/getting_started/CMakeLists.txt diff --git a/examples/storage/fatfs_basic/README.md b/examples/storage/fatfs/getting_started/README.md similarity index 67% rename from examples/storage/fatfs_basic/README.md rename to examples/storage/fatfs/getting_started/README.md index 0ee84f105d..626f9323cb 100644 --- a/examples/storage/fatfs_basic/README.md +++ b/examples/storage/fatfs/getting_started/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # FATFS minimal example @@ -29,15 +29,16 @@ Here is the example's console output: ``` ... -I (339) example: Mounting FAT filesystem -I (339) example: Filesystem mounted -I (339) example: Opening file -I (729) example: File written -I (729) example: Reading file -I (739) example: Read from file: 'This is written by the device' -I (739) example: Unmounting FAT filesystem -I (849) example: Done +I (321) example: Mounting FAT filesystem +I (331) example: Filesystem mounted +I (331) example: Opening file +I (731) example: File written +I (731) example: Reading file +I (741) example: Read from file: 'Hello World!' +I (741) example: Unmounting FAT filesystem +I (851) example: Done +... ``` -The logic of the example is contained in a [single source file](./main/fat_example_main.c), +The logic of the example is contained in a [single source file](./main/fatfs_getting_started_main.c), and it should be relatively simple to match points in its execution with the log outputs above. diff --git a/examples/storage/fatfs/getting_started/main/CMakeLists.txt b/examples/storage/fatfs/getting_started/main/CMakeLists.txt new file mode 100644 index 0000000000..fec5d19cad --- /dev/null +++ b/examples/storage/fatfs/getting_started/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "fatfs_getting_started_main.c" + INCLUDE_DIRS ".") diff --git a/examples/storage/fatfs_basic/main/fat_example_main.c b/examples/storage/fatfs/getting_started/main/fatfs_getting_started_main.c similarity index 93% rename from examples/storage/fatfs_basic/main/fat_example_main.c rename to examples/storage/fatfs/getting_started/main/fatfs_getting_started_main.c index 2a57821e70..ae8529160e 100644 --- a/examples/storage/fatfs_basic/main/fat_example_main.c +++ b/examples/storage/fatfs/getting_started/main/fatfs_getting_started_main.c @@ -31,8 +31,8 @@ void app_main(void) .use_one_fat = false, // Use only one FAT table (reduce memory usage), but decrease reliability of file system in case of power failure. }; + // Mount FATFS filesystem located on "storage" partition in read-write mode esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, "storage", &mount_config, &s_wl_handle); - if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); return; @@ -46,12 +46,12 @@ void app_main(void) FILE *f = fopen(filename, "wb"); if (f == NULL) { - perror("fopen"); + perror("fopen"); // Print reason why fopen failed ESP_LOGE(TAG, "Failed to open file for writing"); return; } - fprintf(f, "This is written by the device"); + fprintf(f, "Hello World!\n"); fclose(f); ESP_LOGI(TAG, "File written"); diff --git a/examples/storage/fatfs_basic/partitions_example.csv b/examples/storage/fatfs/getting_started/partitions_example.csv similarity index 100% rename from examples/storage/fatfs_basic/partitions_example.csv rename to examples/storage/fatfs/getting_started/partitions_example.csv diff --git a/examples/storage/fatfs_basic/pytest_fat_example.py b/examples/storage/fatfs/getting_started/pytest_fatfs_getting_started_example.py similarity index 81% rename from examples/storage/fatfs_basic/pytest_fat_example.py rename to examples/storage/fatfs/getting_started/pytest_fatfs_getting_started_example.py index 7abafe062d..e7f9d7d78a 100644 --- a/examples/storage/fatfs_basic/pytest_fat_example.py +++ b/examples/storage/fatfs/getting_started/pytest_fatfs_getting_started_example.py @@ -6,12 +6,12 @@ from pytest_embedded import Dut @pytest.mark.esp32 @pytest.mark.generic -def test_examples_fatfs_basic(dut: Dut) -> None: +def test_examples_fatfs_getting_started(dut: Dut) -> None: dut.expect('example: Mounting FAT filesystem', timeout=90) dut.expect('example: Filesystem mounted', timeout=90) dut.expect('example: Opening file', timeout=90) dut.expect('example: File written', timeout=90) dut.expect('example: Reading file', timeout=90) - dut.expect('example: Read from file: \'This is written by the device\'', timeout=90) + dut.expect('example: Read from file: \'Hello World!\'', timeout=90) dut.expect('example: Unmounting FAT filesystem', timeout=90) dut.expect('example: Done', timeout=90) diff --git a/examples/storage/fatfs_basic/sdkconfig.defaults b/examples/storage/fatfs/getting_started/sdkconfig.defaults similarity index 100% rename from examples/storage/fatfs_basic/sdkconfig.defaults rename to examples/storage/fatfs/getting_started/sdkconfig.defaults diff --git a/examples/storage/fatfs_basic/main/CMakeLists.txt b/examples/storage/fatfs_basic/main/CMakeLists.txt deleted file mode 100644 index 827c3c2e8e..0000000000 --- a/examples/storage/fatfs_basic/main/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -idf_component_register(SRCS "fat_example_main.c" - INCLUDE_DIRS ".") From 587290567d8a6df7820e0f809c55a17385c479f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Mon, 5 Aug 2024 14:12:16 +0200 Subject: [PATCH 05/13] feat(storage/fatfs): restructure advanced example --- examples/storage/.build-test-rules.yml | 8 - .../fs_operations}/CMakeLists.txt | 0 .../storage/fatfs/fs_operations/README.md | 94 ++++++++ .../fatfs/fs_operations/main/CMakeLists.txt | 2 + .../main/fatfs_fs_operations_example_main.c | 207 ++++++++++++++++++ .../fs_operations}/partitions_example.csv | 0 .../pytest_fatfs_fs_operations_example.py | 80 +++++++ .../fs_operations}/sdkconfig.defaults | 0 examples/storage/fatfs_advanced/README.md | 69 ------ .../filegeneratedonhost.txt | 1 - .../subdirectoryfromhost/innerfile.txt | 1 - .../fatfs_advanced/main/CMakeLists.txt | 26 --- .../fatfs_advanced/main/Kconfig.projbuild | 24 -- .../main/fatfs_advanced_example_main.c | 138 ------------ .../pytest_fatfs_advanced_example.py | 112 ---------- .../sdkconfig.ci.test_read_only_partition_gen | 5 - ...ci.test_read_only_partition_gen_default_dt | 6 - ...sdkconfig.ci.test_read_write_partition_gen | 5 - ...i.test_read_write_partition_gen_default_dt | 6 - 19 files changed, 383 insertions(+), 401 deletions(-) rename examples/storage/{fatfs_advanced => fatfs/fs_operations}/CMakeLists.txt (100%) create mode 100644 examples/storage/fatfs/fs_operations/README.md create mode 100644 examples/storage/fatfs/fs_operations/main/CMakeLists.txt create mode 100644 examples/storage/fatfs/fs_operations/main/fatfs_fs_operations_example_main.c rename examples/storage/{fatfs_advanced => fatfs/fs_operations}/partitions_example.csv (100%) create mode 100644 examples/storage/fatfs/fs_operations/pytest_fatfs_fs_operations_example.py rename examples/storage/{fatfs_advanced => fatfs/fs_operations}/sdkconfig.defaults (100%) delete mode 100644 examples/storage/fatfs_advanced/README.md delete mode 100644 examples/storage/fatfs_advanced/fatfs_long_name_image/filegeneratedonhost.txt delete mode 100644 examples/storage/fatfs_advanced/fatfs_long_name_image/subdirectoryfromhost/innerfile.txt delete mode 100644 examples/storage/fatfs_advanced/main/CMakeLists.txt delete mode 100644 examples/storage/fatfs_advanced/main/Kconfig.projbuild delete mode 100644 examples/storage/fatfs_advanced/main/fatfs_advanced_example_main.c delete mode 100644 examples/storage/fatfs_advanced/pytest_fatfs_advanced_example.py delete mode 100644 examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen delete mode 100644 examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen_default_dt delete mode 100644 examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen delete mode 100644 examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen_default_dt diff --git a/examples/storage/.build-test-rules.yml b/examples/storage/.build-test-rules.yml index 8ec3101a5a..341e0f595a 100644 --- a/examples/storage/.build-test-rules.yml +++ b/examples/storage/.build-test-rules.yml @@ -34,14 +34,6 @@ examples/storage/ext_flash_fatfs: temporary: true reason: lack of runners -examples/storage/fatfs_advanced: - depends_components: - - fatfs - - vfs - disable_test: - - if: IDF_TARGET != "esp32" - reason: only one target needed - examples/storage/nvs_rw_blob: depends_components: - nvs_flash diff --git a/examples/storage/fatfs_advanced/CMakeLists.txt b/examples/storage/fatfs/fs_operations/CMakeLists.txt similarity index 100% rename from examples/storage/fatfs_advanced/CMakeLists.txt rename to examples/storage/fatfs/fs_operations/CMakeLists.txt diff --git a/examples/storage/fatfs/fs_operations/README.md b/examples/storage/fatfs/fs_operations/README.md new file mode 100644 index 0000000000..e11f3077b5 --- /dev/null +++ b/examples/storage/fatfs/fs_operations/README.md @@ -0,0 +1,94 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | + +# FATFS Filesystem Operations Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example demonstrates some of the POSIX functions available for working with the FATFS filesystem. +Including basic read and write operations, as well as creating moving, and deleting files and directories. + +## Overview + +1. Partition labeled `storage` is mounted (and formatted if necessary) as FATFS filesystem to `/spiflash` mountpoint. + +2. All existing files and directories in the root directory are deleted. + +3. File `hello.txt` is created and written to. + +4. File `hello.txt` is inspected using `fstat` function showing file size and last modification time. + +5. File `hello.txt` is written to again, appending to the end of the file. + +6. File `hello.txt` is read from and the contents are printed to the console. + +7. New directory `new_dir` is created. + +8. All files and directories in the root directory are listed. + +9. File `hello.txt` is moved and renamed to `new_dir/hello_renamed.txt`. + +## How to use example + +### Build and flash + +To run the example, type the following command: + +```CMake +# CMake +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example output + +Here is the example's console output: + +``` +... +I (323) example: Mounting FAT filesystem +I (333) example: Deleting everything in /spiflash: +I (333) example: Deleting everything in /spiflash/new_dir: +I (673) example: Creating a file +I (683) example: Writing to the file +I (733) example: File stats: + File size: 13 bytes + File modification time: Thu Jan 1 00:00:00 1970 + +I (743) example: Wait for 1 seconds +I (1743) example: Write more to the file +I (1743) example: File stats: + File size: 26 bytes + File modification time: Thu Jan 1 00:00:00 1970 + +I (1743) example: Go to the beginning of the file +I (1753) example: Reading from file: +Hello World! +Hello World! + +I (1753) example: Closing file +I (1993) example: Listing files in /spiflash: +/spiflash: + file : hello.txt +I (1993) example: Creating a new directory +I (2383) example: Listing files in /spiflash: +/spiflash: + file : hello.txt + directory: new_dir +I (2383) example: Rename a file +I (2503) example: Listing files in /spiflash: +/spiflash: + directory: new_dir +I (2503) example: Listing files in /spiflash/new_dir: +/spiflash/new_dir: + file : hello_renamed.txt +I (2513) example: Unmounting FAT filesystem +I (2643) example: Done +... +``` + +The logic of the example is contained in a [single source file](./main/fatfs_fs_operations_example_main.c), +and it should be relatively simple to match points in its execution with the log outputs above. diff --git a/examples/storage/fatfs/fs_operations/main/CMakeLists.txt b/examples/storage/fatfs/fs_operations/main/CMakeLists.txt new file mode 100644 index 0000000000..a5ae965fc4 --- /dev/null +++ b/examples/storage/fatfs/fs_operations/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "fatfs_fs_operations_example_main.c" + INCLUDE_DIRS ".") diff --git a/examples/storage/fatfs/fs_operations/main/fatfs_fs_operations_example_main.c b/examples/storage/fatfs/fs_operations/main/fatfs_fs_operations_example_main.c new file mode 100644 index 0000000000..c2dd5bc226 --- /dev/null +++ b/examples/storage/fatfs/fs_operations/main/fatfs_fs_operations_example_main.c @@ -0,0 +1,207 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "esp_vfs.h" +#include "esp_vfs_fat.h" +#include "sdkconfig.h" + +static const char *TAG = "example"; + +// Mount path for the partition +static const char *base_path = "/spiflash"; + +// File name +static const char *filename = "/spiflash/hello.txt"; + +// Function to dump contents of a directory +static void list_dir(const char *path); + +// Best effort recursive function to clean a directory +static void clean_dir(const char *path); + +void app_main(void) +{ + ESP_LOGI(TAG, "Mounting FAT filesystem"); + + // To mount device we need name of device partition, define base_path + // and allow format partition in case if it is new one and was not formatted before + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true, + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, + .use_one_fat = false, + }; + + wl_handle_t wl_handle = WL_INVALID_HANDLE; + + esp_err_t err = ESP_OK; + + err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, "storage", &mount_config, &wl_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); + return; + } + + // Ensure the working directory is empty + clean_dir(base_path); + + ESP_LOGI(TAG, "Creating a file"); + + // Unlike C standard library which uses FILE*, POSIX API uses file descriptors for file operations + int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0); + if (fd < 0) { + ESP_LOGE(TAG, "Failed to open file for writing"); + return; + } + + ESP_LOGI(TAG, "Writing to the file"); + const char *text = "Hello World!\n"; + write(fd, text, strlen(text)); + + struct stat info; + // We have to use `stat` instead of `fstat`, because `fstat` currently isn't fully supported + if (stat(filename, &info) < 0) { + ESP_LOGE(TAG, "Failed to stat file: %s", strerror(errno)); + close(fd); + return; + } + + ESP_LOGI( + TAG, + "File stats:\n" + "\tFile size: %ld bytes\n" + "\tFile modification time: %s", + info.st_size, + ctime(&info.st_mtime) + ); + + ESP_LOGI(TAG, "Wait for 3 seconds"); + sleep(3); + + ESP_LOGI(TAG, "Write more to the file"); + write(fd, text, strlen(text)); + + ESP_LOGI(TAG, "Force cached data and metadata to the filesystem"); + fsync(fd); + + if (stat(filename, &info) < 0) { + ESP_LOGE(TAG, "Failed to stat file: %s", strerror(errno)); + close(fd); + return; + } + + ESP_LOGI( + TAG, + "File stats:\n" + "\tFile size: %ld bytes\n" + "\tFile modification time: %s", + info.st_size, + ctime(&info.st_mtime) + ); + + ESP_LOGI(TAG, "Go to the beginning of the file"); + lseek(fd, 0, SEEK_SET); + + ESP_LOGI(TAG, "Reading from file:"); + + char buf[128] = {0}; + + ssize_t len = read(fd, buf, sizeof(buf) - 1); + if (len < 0) { + ESP_LOGE(TAG, "Failed to read file: %s", strerror(errno)); + close(fd); + return; + } + + printf("%.*s\n", len, buf); + + ESP_LOGI(TAG, "Closing file"); + close(fd); + + // List files in the directory + list_dir(base_path); + + ESP_LOGI(TAG, "Creating a new directory"); + if (mkdir("/spiflash/new_dir", 0777) < 0) { + ESP_LOGE(TAG, "Failed to create a new directory: %s", strerror(errno)); + return; + } + + // List files in the directory + list_dir(base_path); + + ESP_LOGI(TAG, "Rename a file"); + + if (rename(filename, "/spiflash/new_dir/hello_renamed.txt") < 0) { + ESP_LOGE(TAG, "Failed to rename file: %s", strerror(errno)); + return; + } + + // List files in the directory + list_dir(base_path); + list_dir("/spiflash/new_dir"); + + ESP_LOGI(TAG, "Unmounting FAT filesystem"); + ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_rw_wl(base_path, wl_handle)); + + ESP_LOGI(TAG, "Done"); +} + +void list_dir(const char *path) +{ + ESP_LOGI(TAG, "Listing files in %s:", path); + + DIR *dir = opendir(path); + if (!dir) { + ESP_LOGE(TAG, "Failed to open directory: %s", strerror(errno)); + return; + } + + printf("%s:\n", path); + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + printf( + " %s: %s\n", + (entry->d_type == DT_DIR) + ? "directory" + : "file ", + entry->d_name + ); + } + + closedir(dir); +} + +void clean_dir(const char *path) +{ + ESP_LOGI(TAG, "Deleting everything in %s:", path); + + DIR *dir = opendir(path); + if (!dir) { + ESP_LOGE(TAG, "Failed to open directory: %s", strerror(errno)); + return; + } + + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + char full_path[64] = {0}; + snprintf(full_path, sizeof(full_path), "%.20s/%.40s", path, entry->d_name); + if (entry->d_type == DT_DIR) + clean_dir(full_path); + if (remove(full_path) != 0) { + ESP_LOGE(TAG, "Failed to remove %s: %s", full_path, strerror(errno)); + } + } + + closedir(dir); +} diff --git a/examples/storage/fatfs_advanced/partitions_example.csv b/examples/storage/fatfs/fs_operations/partitions_example.csv similarity index 100% rename from examples/storage/fatfs_advanced/partitions_example.csv rename to examples/storage/fatfs/fs_operations/partitions_example.csv diff --git a/examples/storage/fatfs/fs_operations/pytest_fatfs_fs_operations_example.py b/examples/storage/fatfs/fs_operations/pytest_fatfs_fs_operations_example.py new file mode 100644 index 0000000000..4067c80d13 --- /dev/null +++ b/examples/storage/fatfs/fs_operations/pytest_fatfs_fs_operations_example.py @@ -0,0 +1,80 @@ +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +from datetime import datetime +from typing import List + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32 +@pytest.mark.generic +def test_examples_fatfs_fs_operations(config: str, dut: Dut) -> None: + # Expects list of strings sequentially + def expect_all(msg_list: List[str], to: int) -> None: + for msg in msg_list: + dut.expect(msg, timeout=to) + + def parse_date() -> datetime: + months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + + pattern = r'([A-Z][a-z]{2}) ([A-Z][a-z]{2}) ([ \d]\d) (\d{2}):(\d{2}):(\d{2}) (\d{4})' + + match = dut.expect(pattern) + return datetime( + month=months.index(match[2].decode('utf-8')) + 1, + day=int(match[3]), + hour=int(match[4]), + minute=int(match[5]), + second=int(match[6]), + year=int(match[7]), + ) + + expect_all( + [ + 'example: Mounting FAT filesystem', + 'example: Creating a file', + 'example: Writing to the file', + 'example: File stats:', + 'File size:', + ], + 5 + ) + + original = parse_date() + + expect_all( + [ + 'example: Wait for 3 seconds', + 'example: Write more to the file', + 'example: Force cached data and metadata to the filesystem', + 'File size:', + ], + 5 + ) + + updated = parse_date() + + assert updated > original + + expect_all( + [ + 'example: Go to the beginning of the file', + 'example: Reading from file', + 'Hello World!', + 'Hello World!', + 'example: Closing file', + 'example: Listing files in /spiflash:', + 'hello.txt', + 'example: Creating a new directory', + 'example: Listing files in /spiflash:', + 'hello.txt', + 'new_dir', + 'example: Rename a file', + 'example: Listing files in /spiflash:', + 'new_dir', + 'example: Listing files in /spiflash/new_dir:', + 'hello_renamed.txt', + ], + 5 + ) diff --git a/examples/storage/fatfs_advanced/sdkconfig.defaults b/examples/storage/fatfs/fs_operations/sdkconfig.defaults similarity index 100% rename from examples/storage/fatfs_advanced/sdkconfig.defaults rename to examples/storage/fatfs/fs_operations/sdkconfig.defaults diff --git a/examples/storage/fatfs_advanced/README.md b/examples/storage/fatfs_advanced/README.md deleted file mode 100644 index 34ab038fc5..0000000000 --- a/examples/storage/fatfs_advanced/README.md +++ /dev/null @@ -1,69 +0,0 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | - -# FATFS partition generation example - -(See the README.md file in the upper level 'examples' directory for more information about examples.) - -This example demonstrates how to use the FATFS partition -generation tool [fatfsgen.py](../../../components/fatfs/fatfsgen.py) to automatically create a FATFS -filesystem image from the contents of a host folder during build, with an option of -automatically flashing the created image on invocation of `idf.py -p PORT flash` as well as usage of long file names for FATFS. -Beware that the minimal required size of the flash is 4 MB. -You can specify using menuconfig weather example will use read-only or read-write mode. The default option is read-write mode. -To change it just use menuconfig: - -```shell -idf.py menuconfig -``` - -Then select `Example Configuration` a chose `Mode for generated FATFS image` either `Read-Write Mode` or `Read-Only Mode`. -`Read-Only` option indicates generating raw fatfs image without wear levelling support. -On the other hand, for `Read-Write` the generated fatfs image will support wear levelling thus can be mounted in read-write mode. - - -The following gives an overview of the example: - -1. There is a directory `fatfs_image` from which the FATFS filesystem image will be created. - -2. The function `fatfs_create_rawflash_image` is used to specify that a FATFS image -should be created during build for the `storage` partition. -For CMake, it is called from [the main component's CMakeLists.txt](./main/CMakeLists.txt). -`FLASH_IN_PROJECT` specifies that the created image -should be flashed on invocation of `idf.py -p PORT flash` together with app, bootloader, partition table, etc. -The image is created on the example's build directory with the output filename `storage.bin`. - -3. Upon invocation of `idf.py -p PORT flash monitor`, application loads and -finds there is already a valid FATFS filesystem in the `storage` partition with files same as those in `fatfs_image` directory. The application is then -able to read those files. - -## How to use example - -### Build and flash - -To run the example, type the following command: - -```CMake -# CMake -idf.py -p PORT flash monitor -``` - -(To exit the serial monitor, type ``Ctrl-]``.) - -See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. - -## Example output - -Here is the example's console output: - -``` -... -I (322) example: Mounting FAT filesystem -I (332) example: Reading file -I (332) example: Read from file: 'this is test' -I (332) example: Unmounting FAT filesystem -I (342) example: Done -``` - -The logic of the example is contained in a [single source file](./main/fatfsgen_example_main.c), -and it should be relatively simple to match points in its execution with the log outputs above. diff --git a/examples/storage/fatfs_advanced/fatfs_long_name_image/filegeneratedonhost.txt b/examples/storage/fatfs_advanced/fatfs_long_name_image/filegeneratedonhost.txt deleted file mode 100644 index 33f47c9b1d..0000000000 --- a/examples/storage/fatfs_advanced/fatfs_long_name_image/filegeneratedonhost.txt +++ /dev/null @@ -1 +0,0 @@ -This is generated on the host; it has long name diff --git a/examples/storage/fatfs_advanced/fatfs_long_name_image/subdirectoryfromhost/innerfile.txt b/examples/storage/fatfs_advanced/fatfs_long_name_image/subdirectoryfromhost/innerfile.txt deleted file mode 100644 index 84505e3d3e..0000000000 --- a/examples/storage/fatfs_advanced/fatfs_long_name_image/subdirectoryfromhost/innerfile.txt +++ /dev/null @@ -1 +0,0 @@ -this is test; it has long name diff --git a/examples/storage/fatfs_advanced/main/CMakeLists.txt b/examples/storage/fatfs_advanced/main/CMakeLists.txt deleted file mode 100644 index 28eed4c7c3..0000000000 --- a/examples/storage/fatfs_advanced/main/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -idf_component_register(SRCS "fatfs_advanced_example_main.c" - INCLUDE_DIRS ".") - -# Create a FATFS image from the contents of the 'fatfs_image' directory -# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that -# the generated image should be flashed when the entire project is flashed to -# the target with 'idf.py -p PORT flash'. -# If read-only mode is set (CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY) -# the generated image will be raw without wear levelling support. -# Otherwise it will support wear levelling and thus enable read-write mounting of the image in the device. - -set(image ../fatfs_long_name_image) - -if(CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY) - if(CONFIG_EXAMPLE_FATFS_DEFAULT_DATETIME) - fatfs_create_rawflash_image(storage ${image} FLASH_IN_PROJECT) - else() - fatfs_create_rawflash_image(storage ${image} FLASH_IN_PROJECT PRESERVE_TIME) - endif() -else() - if(CONFIG_EXAMPLE_FATFS_DEFAULT_DATETIME) - fatfs_create_spiflash_image(storage ${image} FLASH_IN_PROJECT) - else() - fatfs_create_spiflash_image(storage ${image} FLASH_IN_PROJECT PRESERVE_TIME) - endif() -endif() diff --git a/examples/storage/fatfs_advanced/main/Kconfig.projbuild b/examples/storage/fatfs_advanced/main/Kconfig.projbuild deleted file mode 100644 index b715c917b8..0000000000 --- a/examples/storage/fatfs_advanced/main/Kconfig.projbuild +++ /dev/null @@ -1,24 +0,0 @@ -menu "Example Configuration" - - config EXAMPLE_FATFS_MODE_READ_ONLY - bool "Read only mode for generated FATFS image" - default n - help - If read-only mode is set, the generated fatfs image will be raw (without wear levelling support). - Otherwise it will support wear levelling that enables read-write mounting. - - config EXAMPLE_FATFS_WRITE_COUNT - int "Number of volumes" - default 1 - range 1 600 - help - Number of writes to the file (for testing purposes). - - config EXAMPLE_FATFS_DEFAULT_DATETIME - bool "Default modification date and time for generated FATFS image" - default n - help - If default datetime is set, all files created in the generated FATFS partition have default time - equal to FATFS origin time (1 January 1980) - -endmenu diff --git a/examples/storage/fatfs_advanced/main/fatfs_advanced_example_main.c b/examples/storage/fatfs_advanced/main/fatfs_advanced_example_main.c deleted file mode 100644 index 3d8032b163..0000000000 --- a/examples/storage/fatfs_advanced/main/fatfs_advanced_example_main.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Unlicense OR CC0-1.0 - */ - -#include -#include -#include -#include -#include "esp_vfs.h" -#include "esp_vfs_fat.h" -#include "sdkconfig.h" - -static const char *TAG = "example"; - -// Mount path for the partition -const char *base_path = "/spiflash"; - -void write_file(const char *filename, const char *data) -{ - ESP_LOGI(TAG, "Opening file '%s' for writing", filename); - - FILE *f = fopen(filename, "w"); - if (f == NULL) { - ESP_LOGE(TAG, "Failed to open file for writing: %s", strerror(errno)); - return; - } - - ESP_LOGI(TAG, "Writing to file"); - - fputs(data, f); - - ESP_LOGI(TAG, "File written"); - - ESP_LOGI(TAG, "Closing file"); - fclose(f); -} - -void read_file(const char *filename) -{ - ESP_LOGI(TAG, "Opening file '%s' for reading", filename); - - FILE *f = fopen(filename, "r"); - if (f == NULL) { - ESP_LOGE(TAG, "Failed to open file for reading: %s", strerror(errno)); - return; - } - - ESP_LOGI(TAG, "Reading from file"); - - char line[128]; - fgets(line, sizeof(line), f); - - // strip newline - char *pos = strchr(line, '\n'); - if (pos) { - *pos = '\0'; // strip newline - } - - ESP_LOGI(TAG, "Read from file: '%s'", line); - - ESP_LOGI(TAG, "Closing file '%s'", filename); - fclose(f); -} - -void stat_file(const char *filename) -{ - - struct stat info; - struct tm timeinfo; - char buffer[32]; - - ESP_LOGI(TAG, "Stating file '%s' for modification time", filename); - - if(stat(filename, &info) < 0){ - ESP_LOGE(TAG, "Failed to read file stats: %s", strerror(errno)); - return; - } - localtime_r(&info.st_mtime, &timeinfo); - strftime(buffer, sizeof(buffer), "%Y-%m-%d", &timeinfo); - - ESP_LOGI(TAG, "The file '%s' was modified at date: %s", filename, buffer); -} - -void app_main(void) -{ - ESP_LOGI(TAG, "Mounting FAT filesystem"); - - // To mount device we need name of device partition, define base_path - // and allow format partition in case if it is new one and was not formatted before - const esp_vfs_fat_mount_config_t mount_config = { - .max_files = 4, - .format_if_mount_failed = false, - .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, - .use_one_fat = false, - }; - - esp_err_t err; - -#ifdef CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY - err = esp_vfs_fat_spiflash_mount_ro(base_path, "storage", &mount_config); -#else // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY - - // Handle of the wear levelling library instance - wl_handle_t wl_handle = WL_INVALID_HANDLE; - err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, "storage", &mount_config, &wl_handle); -#endif // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY - - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to mount FATFS (%s)python $IDF_PATH/tools/ci/ci_build_apps.py . --target esp32 -vv --pytest-apps", esp_err_to_name(err)); - return; - } - - // Read contents of a file - read_file("/spiflash/filegeneratedonhost.txt"); - - -#ifndef CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY - // Create and write to a file - write_file("/spiflash/messagefromthedevice.txt", "This is written by the device"); - read_file("/spiflash/messagefromthedevice.txt"); -#endif // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY - - // Check when the file was last modified - stat_file("/spiflash/subdirectoryfromhost/innerfile.txt"); - - // Unmount FATFS - ESP_LOGI(TAG, "Unmounting FAT filesystem"); - -#ifdef CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY - ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_ro(base_path, "storage")); -#else // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY - ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_rw_wl(base_path, wl_handle)); -#endif // CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY - - ESP_LOGI(TAG, "Done"); -} diff --git a/examples/storage/fatfs_advanced/pytest_fatfs_advanced_example.py b/examples/storage/fatfs_advanced/pytest_fatfs_advanced_example.py deleted file mode 100644 index ea7f491a8f..0000000000 --- a/examples/storage/fatfs_advanced/pytest_fatfs_advanced_example.py +++ /dev/null @@ -1,112 +0,0 @@ -# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD -# SPDX-License-Identifier: Unlicense OR CC0-1.0 -import re -from datetime import datetime -from typing import List - -import pytest -from pytest_embedded import Dut - - -@pytest.mark.esp32 -@pytest.mark.generic -@pytest.mark.parametrize( - 'config', - [ - 'test_read_only_partition_gen', - 'test_read_only_partition_gen_default_dt', - 'test_read_write_partition_gen', - 'test_read_write_partition_gen_default_dt', - ], - indirect=True, -) -def test_examples_fatfs_advanced(config: str, dut: Dut) -> None: - # Expects list of strings sequentially - def expect_all(msg_list: List[str], to: int) -> None: - for msg in msg_list: - dut.expect(msg, timeout=to) - - # Expects prefix string followed by date in the format 'yyyy-mm-dd' - def expect_date(prefix: str, to: int) -> datetime: - expect_str = prefix + '(\\d+)-(\\d+)-(\\d+)' - match_ = dut.expect(re.compile(str.encode(expect_str)), timeout=to) - year_ = int(match_[1].decode()) - month_ = int(match_[2].decode()) - day_ = int(match_[3].decode()) - return datetime(year_, month_, day_) - - # Calculates absolute difference in days between date_reference and date_actual. - # Raises exception if difference exceeds tolerance - def evaluate_dates( - date_reference: datetime, date_actual: datetime, days_tolerance: int - ) -> None: - td = date_actual - date_reference - if abs(td.days) > days_tolerance: - raise Exception( - f'Too big date difference. Actual: {date_actual}, reference: {date_reference}, tolerance: {days_tolerance} day(s)' - ) - - # Expect timeout - timeout = 20 - - # We tolerate 30 days difference between actual file creation and date when test was executed. - tolerance = 30 - - expected_date = ( - datetime(1980, 1, 1) if config.endswith('default_dt') else datetime.today() - ) - - base_path = '/spiflash/' - folder_name = 'subdirectoryfromhost/' - read_filename = base_path + 'filegeneratedonhost.txt' - write_filename = base_path + 'messagefromthedevice.txt' - stat_filename = base_path + folder_name + 'innerfile.txt' - - dut.expect('example: Mounting FAT filesystem', timeout=timeout) - - # Check read - expect_all( - [ - f'example: Opening file \'{read_filename}\' for reading', - f'example: Reading from file', - 'example: Read from file: \'This is generated on the host; it has long name\'', - f'example: Closing file \'{read_filename}\'', - ], - timeout, - ) - - # Check write - if config.startswith('test_read_write'): - expect_all( - [ - f'example: Opening file \'{write_filename}\' for writing', - 'example: Writing to file', - 'example: File written', - 'example: Closing file', - f'example: Opening file \'{write_filename}\' for reading', - f'example: Reading from file', - 'example: Read from file: \'This is written by the device\'', - f'example: Closing file \'{write_filename}\'', - ], - timeout, - ) - - # Check date using stat - dut.expect( - f'example: Stating file \'{stat_filename}\' for modification time', timeout=timeout - ) - - actual_date = expect_date( - f'The file \'{stat_filename}\' was modified at date: ', timeout - ) - - evaluate_dates(expected_date, actual_date, tolerance) - - # Finish - expect_all( - [ - 'example: Unmounting FAT filesystem', - 'example: Done', - ], - timeout, - ) diff --git a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen deleted file mode 100644 index 21a7938068..0000000000 --- a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=y -CONFIG_FATFS_LFN_HEAP=y -CONFIG_FATFS_LFN_STACK=n -CONFIG_FATFS_LFN_NONE=n -CONFIG_EXAMPLE_FATFS_WRITE_COUNT=300 diff --git a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen_default_dt b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen_default_dt deleted file mode 100644 index ed0be2575b..0000000000 --- a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_only_partition_gen_default_dt +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=y -CONFIG_FATFS_LFN_HEAP=y -CONFIG_FATFS_LFN_STACK=n -CONFIG_FATFS_LFN_NONE=n -CONFIG_EXAMPLE_FATFS_DEFAULT_DATETIME=y -CONFIG_EXAMPLE_FATFS_WRITE_COUNT=300 diff --git a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen deleted file mode 100644 index 4ffa553233..0000000000 --- a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=n -CONFIG_FATFS_LFN_HEAP=y -CONFIG_FATFS_LFN_STACK=n -CONFIG_FATFS_LFN_NONE=n -CONFIG_EXAMPLE_FATFS_WRITE_COUNT=300 diff --git a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen_default_dt b/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen_default_dt deleted file mode 100644 index 6413768f3e..0000000000 --- a/examples/storage/fatfs_advanced/sdkconfig.ci.test_read_write_partition_gen_default_dt +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=n -CONFIG_FATFS_LFN_HEAP=y -CONFIG_FATFS_LFN_STACK=n -CONFIG_FATFS_LFN_NONE=n -CONFIG_EXAMPLE_FATFS_DEFAULT_DATETIME=y -CONFIG_EXAMPLE_FATFS_WRITE_COUNT=300 From 33788de97955d9e57508313661099c9cf39e66fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Mon, 5 Aug 2024 14:16:58 +0200 Subject: [PATCH 06/13] feat(storage/fatfs): restructure ext_flash example --- examples/storage/.build-test-rules.yml | 15 --------------- .../storage/ext_flash_fatfs/main/CMakeLists.txt | 1 - examples/storage/fatfs/.build-test-rules.yml | 15 +++++++++++++++ .../ext_flash}/CMakeLists.txt | 0 .../ext_flash}/README.md | 0 .../storage/fatfs/ext_flash/main/CMakeLists.txt | 1 + .../main/fatfs_ext_flash_example_main.c} | 5 +++++ .../ext_flash/pytest_fatfs_ext_flash.py} | 2 -- tools/ci/check_copyright_ignore.txt | 1 - 9 files changed, 21 insertions(+), 19 deletions(-) delete mode 100644 examples/storage/ext_flash_fatfs/main/CMakeLists.txt rename examples/storage/{ext_flash_fatfs => fatfs/ext_flash}/CMakeLists.txt (100%) rename examples/storage/{ext_flash_fatfs => fatfs/ext_flash}/README.md (100%) create mode 100644 examples/storage/fatfs/ext_flash/main/CMakeLists.txt rename examples/storage/{ext_flash_fatfs/main/ext_flash_fatfs_example_main.c => fatfs/ext_flash/main/fatfs_ext_flash_example_main.c} (98%) rename examples/storage/{ext_flash_fatfs/pytest_ext_flash_fatfs.py => fatfs/ext_flash/pytest_fatfs_ext_flash.py} (99%) diff --git a/examples/storage/.build-test-rules.yml b/examples/storage/.build-test-rules.yml index 341e0f595a..967d8ed5b8 100644 --- a/examples/storage/.build-test-rules.yml +++ b/examples/storage/.build-test-rules.yml @@ -19,21 +19,6 @@ examples/storage/emmc: - if: IDF_TARGET == "esp32s3" reason: only support on esp32s3 -examples/storage/ext_flash_fatfs: - depends_components: - - fatfs - - vfs - - spi_flash - - driver - disable: - - if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32c61"] - temporary: true - reason: not supported on p4 and c5 # TODO: [ESP32C5] IDF-8715, [ESP32C61] IDF-9314 - disable_test: - - if: IDF_TARGET not in ["esp32"] - temporary: true - reason: lack of runners - examples/storage/nvs_rw_blob: depends_components: - nvs_flash diff --git a/examples/storage/ext_flash_fatfs/main/CMakeLists.txt b/examples/storage/ext_flash_fatfs/main/CMakeLists.txt deleted file mode 100644 index c8a5c30e46..0000000000 --- a/examples/storage/ext_flash_fatfs/main/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -idf_component_register(SRCS "ext_flash_fatfs_example_main.c") diff --git a/examples/storage/fatfs/.build-test-rules.yml b/examples/storage/fatfs/.build-test-rules.yml index f652dd52d8..4f3ae3aa16 100644 --- a/examples/storage/fatfs/.build-test-rules.yml +++ b/examples/storage/fatfs/.build-test-rules.yml @@ -7,3 +7,18 @@ examples/storage/fatfs: disable_test: - if: IDF_TARGET != "esp32" reason: only one target needed + +examples/storage/fatfs/ext_flash: + depends_components: + - fatfs + - vfs + - spi_flash + - driver + disable: + - if: IDF_TARGET in ["esp32p4", "esp32c5", "esp32c61"] + temporary: true + reason: not supported on p4 and c5 # TODO: [ESP32C5] IDF-8715, [ESP32C61] IDF-9314 + disable_test: + - if: IDF_TARGET not in ["esp32"] + temporary: true + reason: lack of runners diff --git a/examples/storage/ext_flash_fatfs/CMakeLists.txt b/examples/storage/fatfs/ext_flash/CMakeLists.txt similarity index 100% rename from examples/storage/ext_flash_fatfs/CMakeLists.txt rename to examples/storage/fatfs/ext_flash/CMakeLists.txt diff --git a/examples/storage/ext_flash_fatfs/README.md b/examples/storage/fatfs/ext_flash/README.md similarity index 100% rename from examples/storage/ext_flash_fatfs/README.md rename to examples/storage/fatfs/ext_flash/README.md diff --git a/examples/storage/fatfs/ext_flash/main/CMakeLists.txt b/examples/storage/fatfs/ext_flash/main/CMakeLists.txt new file mode 100644 index 0000000000..dea52d1cb4 --- /dev/null +++ b/examples/storage/fatfs/ext_flash/main/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register(SRCS "fatfs_ext_flash_example_main.c") diff --git a/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c b/examples/storage/fatfs/ext_flash/main/fatfs_ext_flash_example_main.c similarity index 98% rename from examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c rename to examples/storage/fatfs/ext_flash/main/fatfs_ext_flash_example_main.c index aa2a2c0990..4e10057d10 100644 --- a/examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c +++ b/examples/storage/fatfs/ext_flash/main/fatfs_ext_flash_example_main.c @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ /* Example of FAT filesystem on external Flash. This example code is in the Public Domain (or CC0 licensed, at your option.) diff --git a/examples/storage/ext_flash_fatfs/pytest_ext_flash_fatfs.py b/examples/storage/fatfs/ext_flash/pytest_fatfs_ext_flash.py similarity index 99% rename from examples/storage/ext_flash_fatfs/pytest_ext_flash_fatfs.py rename to examples/storage/fatfs/ext_flash/pytest_fatfs_ext_flash.py index afe81763a3..56dd334a49 100644 --- a/examples/storage/ext_flash_fatfs/pytest_ext_flash_fatfs.py +++ b/examples/storage/fatfs/ext_flash/pytest_fatfs_ext_flash.py @@ -1,7 +1,5 @@ # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 - - import pytest from pytest_embedded import Dut diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index f605b7cd05..8ffb0dc2e2 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -1023,7 +1023,6 @@ examples/security/flash_encryption/main/flash_encrypt_main.c examples/storage/custom_flash_driver/components/custom_chip_driver/chip_drivers.c examples/storage/custom_flash_driver/components/custom_chip_driver/spi_flash_chip_eon.c examples/storage/custom_flash_driver/main/main.c -examples/storage/ext_flash_fatfs/main/ext_flash_fatfs_example_main.c examples/storage/nvs_rw_blob/main/nvs_blob_example_main.c examples/storage/nvs_rw_value/main/nvs_value_example_main.c examples/storage/nvs_rw_value_cxx/main/nvs_value_example_main.cpp From d43669b2d7bb9c88a669eab661cff56aef730f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Thu, 8 Aug 2024 10:13:41 +0200 Subject: [PATCH 07/13] feat(storage/fatfs): restructure fatfsgen example --- .../storage/fatfs/fatfsgen/CMakeLists.txt | 6 ++ examples/storage/fatfs/fatfsgen/README.md | 69 ++++++++++++++ .../fatfsgen/fatfs_image/hellolongname.txt | 1 + .../fatfs_image/subdir/testlongfilenames.txt | 1 + .../fatfs/fatfsgen/main/CMakeLists.txt | 18 ++++ .../fatfs/fatfsgen/main/Kconfig.projbuild | 10 ++ .../fatfsgen/main/fatfsgen_example_main.c | 92 +++++++++++++++++++ .../fatfs/fatfsgen/partitions_example.csv | 6 ++ .../fatfsgen/pytest_fatfs_fatfsgen_example.py | 72 +++++++++++++++ ...kconfig.ci.test_read_only_partition_gen_ln | 4 + ...config.ci.test_read_write_partition_gen_ln | 4 + .../storage/fatfs/fatfsgen/sdkconfig.defaults | 4 + 12 files changed, 287 insertions(+) create mode 100644 examples/storage/fatfs/fatfsgen/CMakeLists.txt create mode 100644 examples/storage/fatfs/fatfsgen/README.md create mode 100644 examples/storage/fatfs/fatfsgen/fatfs_image/hellolongname.txt create mode 100644 examples/storage/fatfs/fatfsgen/fatfs_image/subdir/testlongfilenames.txt create mode 100644 examples/storage/fatfs/fatfsgen/main/CMakeLists.txt create mode 100644 examples/storage/fatfs/fatfsgen/main/Kconfig.projbuild create mode 100644 examples/storage/fatfs/fatfsgen/main/fatfsgen_example_main.c create mode 100644 examples/storage/fatfs/fatfsgen/partitions_example.csv create mode 100644 examples/storage/fatfs/fatfsgen/pytest_fatfs_fatfsgen_example.py create mode 100644 examples/storage/fatfs/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln create mode 100644 examples/storage/fatfs/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln create mode 100644 examples/storage/fatfs/fatfsgen/sdkconfig.defaults diff --git a/examples/storage/fatfs/fatfsgen/CMakeLists.txt b/examples/storage/fatfs/fatfsgen/CMakeLists.txt new file mode 100644 index 0000000000..1c0c2b8a1a --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(fatfsgen) diff --git a/examples/storage/fatfs/fatfsgen/README.md b/examples/storage/fatfs/fatfsgen/README.md new file mode 100644 index 0000000000..aa203d8356 --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/README.md @@ -0,0 +1,69 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | + +# FATFS partition generation example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example demonstrates how to use the FATFS partition +generation tool [fatfsgen.py](../../../components/fatfs/fatfsgen.py) to automatically create a FATFS +filesystem image from the contents of a host folder during build, with an option of +automatically flashing the created image on invocation of `idf.py -p PORT flash`. +Beware that the minimal required size of the flash is 4 MB. +You can specify using menuconfig weather example will use read-only or read-write mode. The default option is read-write mode. +To change it just use menuconfig: + +```shell +idf.py menuconfig +``` + +Then select `Example Configuration` a chose `Mode for generated FATFS image` either `Read-Write Mode` or `Read-Only Mode`. +`Read-Only` option indicates generating raw fatfs image without wear levelling support. +On the other hand, for `Read-Write` the generated fatfs image will support wear levelling thus can be mounted in read-write mode. + + +The following gives an overview of the example: + +1. There is a directory `fatfs_long_name_image` from which the FATFS filesystem image will be created. + +2. Based on the RO/RW configuration either `fatfs_create_rawflash_image` or `fatfs_create_spiflash_image` respectively, +is used to specify that a FATFS image should be created during build for the `storage` partition. +For CMake, it is called from [the main component's CMakeLists.txt](./main/CMakeLists.txt). +`FLASH_IN_PROJECT` specifies that the created image +should be flashed on invocation of `idf.py -p PORT flash` together with app, bootloader, partition table, etc. +The image is created on the example's build directory with the output filename `storage.bin`. + +3. Upon invocation of `idf.py -p PORT flash monitor`, application loads and +finds there is already a valid FATFS filesystem in the `storage` partition with files same as those in `fatfs_image` directory. The application is then +able to read those files. + +## How to use example + +### Build and flash + +To run the example, type the following command: + +```CMake +# CMake +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example output + +Here is the example's console output: + +``` +... +I (322) example: Mounting FAT filesystem +I (332) example: Reading file +I (332) example: Read from file: 'this is test' +I (332) example: Unmounting FAT filesystem +I (342) example: Done +``` + +The logic of the example is contained in a [single source file](./main/fatfsgen_example_main.c), +and it should be relatively simple to match points in its execution with the log outputs above. diff --git a/examples/storage/fatfs/fatfsgen/fatfs_image/hellolongname.txt b/examples/storage/fatfs/fatfsgen/fatfs_image/hellolongname.txt new file mode 100644 index 0000000000..45caad2725 --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/fatfs_image/hellolongname.txt @@ -0,0 +1 @@ +This is generated on the host; long name it has diff --git a/examples/storage/fatfs/fatfsgen/fatfs_image/subdir/testlongfilenames.txt b/examples/storage/fatfs/fatfsgen/fatfs_image/subdir/testlongfilenames.txt new file mode 100644 index 0000000000..e8c8c6d51f --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/fatfs_image/subdir/testlongfilenames.txt @@ -0,0 +1 @@ +this is test; long name it has diff --git a/examples/storage/fatfs/fatfsgen/main/CMakeLists.txt b/examples/storage/fatfs/fatfsgen/main/CMakeLists.txt new file mode 100644 index 0000000000..1b625a3722 --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/main/CMakeLists.txt @@ -0,0 +1,18 @@ +idf_component_register(SRCS "fatfsgen_example_main.c" + INCLUDE_DIRS ".") + +# Create a FATFS image from the contents of the 'fatfs_long_name_image' directory +# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that +# the generated image should be flashed when the entire project is flashed to +# the target with 'idf.py -p PORT flash'. +# If read-only mode is set (CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY) +# the generated image will be raw without wear levelling support. +# Otherwise it will support wear levelling and thus enable read-write mounting of the image in the device. + +set(image ../fatfs_image) + +if(CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY) + fatfs_create_rawflash_image(storage ${image} FLASH_IN_PROJECT PRESERVE_TIME) +else() + fatfs_create_spiflash_image(storage ${image} FLASH_IN_PROJECT PRESERVE_TIME) +endif() diff --git a/examples/storage/fatfs/fatfsgen/main/Kconfig.projbuild b/examples/storage/fatfs/fatfsgen/main/Kconfig.projbuild new file mode 100644 index 0000000000..ef79d39456 --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/main/Kconfig.projbuild @@ -0,0 +1,10 @@ +menu "Example Configuration" + + config EXAMPLE_FATFS_MODE_READ_ONLY + bool "Read only mode for generated FATFS image" + default y + help + If read-only mode is set, the generated fatfs image will be raw (without wear levelling support). + Otherwise it will support wear levelling that enables read-write mounting. + +endmenu diff --git a/examples/storage/fatfs/fatfsgen/main/fatfsgen_example_main.c b/examples/storage/fatfs/fatfsgen/main/fatfsgen_example_main.c new file mode 100644 index 0000000000..abc01a900a --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/main/fatfsgen_example_main.c @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include +#include +#include "esp_vfs.h" +#include "esp_vfs_fat.h" +#include "esp_err.h" +#include "sdkconfig.h" + +static const char *TAG = "example"; + +// Mount path for the partition +const char *base_path = "/spiflash"; + + +void app_main(void) +{ + // To mount device we need name of device partition, define base_path + // and allow format partition in case if it is new one and was not formatted before + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = false, + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, + .use_one_fat = false, + }; + +#if CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + ESP_LOGI(TAG, "Mounting FAT filesystem in read-only mode"); + esp_err_t err = esp_vfs_fat_spiflash_mount_ro(base_path, "storage", &mount_config); +#else + ESP_LOGI(TAG, "Mounting FAT filesystem in read/write mode"); + static wl_handle_t wl_handle = WL_INVALID_HANDLE; + esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, "storage", &mount_config, &wl_handle); +#endif + + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); + return; + } + + char line[128]; + + FILE *f; + char *pos; + ESP_LOGI(TAG, "Reading file"); + + const char *host_filename1 = "/spiflash/subdir/testlongfilenames.txt"; + + struct stat info; + struct tm timeinfo; + char buffer[32]; + + if(stat(host_filename1, &info) < 0){ + ESP_LOGE(TAG, "Failed to read file stats"); + return; + } + localtime_r(&info.st_mtime, &timeinfo); + strftime(buffer, sizeof(buffer), "%Y-%m-%d", &timeinfo); + + ESP_LOGI(TAG, "The file '%s' was modified at date: %s", host_filename1, buffer); + + + f = fopen(host_filename1, "rb"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for reading"); + return; + } + fgets(line, sizeof(line), f); + fclose(f); + // strip newline + pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; + } + ESP_LOGI(TAG, "Read from file: '%s'", line); + + // Unmount FATFS + ESP_LOGI(TAG, "Unmounting FAT filesystem"); + +#if CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY + ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_ro(base_path, "storage")); +#else + ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_rw_wl(base_path, wl_handle)); +#endif + + ESP_LOGI(TAG, "Done"); +} diff --git a/examples/storage/fatfs/fatfsgen/partitions_example.csv b/examples/storage/fatfs/fatfsgen/partitions_example.csv new file mode 100644 index 0000000000..a3fee302e2 --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/partitions_example.csv @@ -0,0 +1,6 @@ +# 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, +storage, data, fat, , 1M, diff --git a/examples/storage/fatfs/fatfsgen/pytest_fatfs_fatfsgen_example.py b/examples/storage/fatfs/fatfsgen/pytest_fatfs_fatfsgen_example.py new file mode 100644 index 0000000000..e0966604eb --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/pytest_fatfs_fatfsgen_example.py @@ -0,0 +1,72 @@ +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import os +import re +from datetime import datetime +from typing import List + +import pytest +from pytest_embedded import Dut + +idf_path = os.environ['IDF_PATH'] # get value of IDF_PATH from environment +parttool_dir = os.path.join(idf_path, 'components', 'partition_table') + + +@pytest.mark.esp32 +@pytest.mark.generic +@pytest.mark.parametrize('config', ['test_read_only_partition_gen_ln', + 'test_read_write_partition_gen_ln', + ], indirect=True) +def test_examples_fatfs_fatfsgen(config: str, dut: Dut) -> None: + # Expects list of strings sequentially + def expect_all(msg_list: List[str], to: int) -> None: + for msg in msg_list: + dut.expect(msg, timeout=to) + + # Expects prefix string followed by date in the format 'yyyy-mm-dd' + def expect_date(prefix: str, to: int) -> datetime: + expect_str = prefix + '(\\d+)-(\\d+)-(\\d+)' + match_ = dut.expect(re.compile(str.encode(expect_str)), timeout=to) + year_ = int(match_[1].decode()) + month_ = int(match_[2].decode()) + day_ = int(match_[3].decode()) + return datetime(year_, month_, day_) + + # Calculates absolute difference in days between date_reference and date_actual. + # Raises exception if difference exceeds tolerance + def evaluate_dates(date_reference: datetime, date_actual: datetime, days_tolerance: int) -> None: + td = date_actual - date_reference + if abs(td.days) > days_tolerance: + raise Exception(f'Too big date difference. Actual: {date_actual}, reference: {date_reference}, tolerance: {days_tolerance} day(s)') + + # Expect timeout + timeout = 20 + + # We tolerate 30 days difference between actual file creation and date when test was executed. + tolerance = 30 + filename = 'sublongnames/testlongfilenames.txt' + date_ref = datetime.today() + + if config in ['test_read_write_partition_gen']: + filename_expected = f'/spiflash/{filename}' + expect_all(['example: Mounting FAT filesystem', + 'example: Opening file', + 'example: File written', + 'example: Reading file', + 'example: Read from file: \'This is written by the device\'', + 'example: Reading file'], timeout) + date_act = expect_date(f'The file \'{filename_expected}\' was modified at date: ', timeout) + evaluate_dates(date_ref, date_act, tolerance) + expect_all(['example: Read from file: \'This is generated on the host\'', + 'example: Unmounting FAT filesystem', + 'example: Done'], timeout) + + elif config in ['test_read_only_partition_gen']: + filename_expected = f'/spiflash/{filename}' + expect_all(['example: Mounting FAT filesystem', + 'example: Reading file'], timeout) + date_act = expect_date(f'The file \'{filename_expected}\' was modified at date: ', timeout) + evaluate_dates(date_ref, date_act, tolerance) + expect_all(['example: Read from file: \'this is test\'', + 'example: Unmounting FAT filesystem', + 'example: Done'], timeout) diff --git a/examples/storage/fatfs/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln b/examples/storage/fatfs/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln new file mode 100644 index 0000000000..5122126dcb --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/sdkconfig.ci.test_read_only_partition_gen_ln @@ -0,0 +1,4 @@ +CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=y +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_LFN_NONE=n +CONFIG_FATFS_LFN_STACK=n diff --git a/examples/storage/fatfs/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln b/examples/storage/fatfs/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln new file mode 100644 index 0000000000..33a0ccfad3 --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/sdkconfig.ci.test_read_write_partition_gen_ln @@ -0,0 +1,4 @@ +CONFIG_EXAMPLE_FATFS_MODE_READ_ONLY=n +CONFIG_FATFS_LFN_HEAP=y +CONFIG_FATFS_LFN_NONE=n +CONFIG_FATFS_LFN_STACK=n diff --git a/examples/storage/fatfs/fatfsgen/sdkconfig.defaults b/examples/storage/fatfs/fatfsgen/sdkconfig.defaults new file mode 100644 index 0000000000..7dd3c63608 --- /dev/null +++ b/examples/storage/fatfs/fatfsgen/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" +CONFIG_FATFS_LFN_HEAP=y From 46982e69da245da50119c3ee6446abc23f922a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Tue, 3 Sep 2024 13:30:45 +0200 Subject: [PATCH 08/13] feat(storage/vfs): update example references in documentation --- docs/en/api-reference/storage/fatfs.rst | 4 +- docs/en/api-reference/storage/index.rst | 64 ++++++++++++++++++------- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/docs/en/api-reference/storage/fatfs.rst b/docs/en/api-reference/storage/fatfs.rst index f45007607c..20bdbac6a3 100644 --- a/docs/en/api-reference/storage/fatfs.rst +++ b/docs/en/api-reference/storage/fatfs.rst @@ -123,7 +123,7 @@ If you decide for any reason to use ``fatfs_create_rawflash_image`` (without wea The arguments of the function are as follows: -#. partition - the name of the partition as defined in the partition table (e.g., :example_file:`storage/fatfsgen/partitions_example.csv`). +#. partition - the name of the partition as defined in the partition table (e.g., :example_file:`storage/fatfs/fatfsgen/partitions_example.csv`). #. base_dir - the directory that will be encoded to FatFs partition and optionally flashed into the device. Beware that you have to specify the suitable size of the partition in the partition table. @@ -139,7 +139,7 @@ For example:: If FLASH_IN_PROJECT is not specified, the image will still be generated, but you will have to flash it manually using ``esptool.py`` or a custom build system target. -For an example, see :example:`storage/fatfsgen`. +For an example, see :example:`storage/fatfs/fatfsgen`. .. _fatfs-partition-analyzer: diff --git a/docs/en/api-reference/storage/index.rst b/docs/en/api-reference/storage/index.rst index 19bf5b6b92..22d5197fcb 100644 --- a/docs/en/api-reference/storage/index.rst +++ b/docs/en/api-reference/storage/index.rst @@ -37,22 +37,15 @@ For information about storage security, please refer to :doc:`Storage Security < wear-levelling storage-security.rst -.. list-table:: Code Examples for Storage API +Examples +-------- + +.. list-table:: NVS API examples :widths: 25 75 :header-rows: 0 * - **Code Example** - **Description** - * - :doc:`fatfs` - - - * - :example:`wear_leveling ` - - Demonstrates using FATFS over wear leveling on internal flash. - * - :example:`ext_flash_fatfs ` - - Demonstrates using FATFS over wear leveling on external flash. - * - :example:`fatfsgen ` - - Demonstrates the capabilities of Python-based tooling for FATFS images available on host computers. - * - :doc:`nvs_flash` - - * - :example:`nvs_rw_blob ` - Shows the use of the C-style API to read and write blob data types in NVS flash. * - :example:`nvs_rw_value ` @@ -61,20 +54,57 @@ For information about storage security, please refer to :doc:`Storage Security < - Shows the use of the C++-style API to read and write integer data types in NVS flash. * - :example:`nvsgen ` - Demonstrates how to use the Python-based NVS image generation tool to create an NVS partition image from the contents of a CSV file. - * - :doc:`spiffs` - - + +.. list-table:: Common Filesystem API + :widths: 25 75 + :header-rows: 0 + + * - **Code Example** + - **Description** + * - :example:`fatfs/getting_started ` + - Demonstrates basic common file API(stdio.h) usage over internal flash using FATFS. + * - :example:`fatfs/fs_operations ` + - Demonstrates POSIX API for filesystem manipulation, such as moving, removing and renaming files. + +.. list-table:: FATFS API examples + :widths: 25 75 + :header-rows: 0 + + * - :example:`fatfsgen ` + - Demonstrates the capabilities of Python-based tooling for FATFS images available on host computers. + * - :example:`ext_flash_fatfs ` + - Demonstrates using FATFS over wear leveling on external flash. + * - :example:`wear_leveling ` + - Demonstrates using FATFS over wear leveling on internal flash. + +.. list-table:: SPIFFS API examples + :widths: 25 75 + :header-rows: 0 + + * - **Code Example** + - **Description** * - :example:`spiffs ` - Shows the use of the SPIFFS API to initialize the filesystem and work with files using POSIX functions. * - :example:`spiffsgen ` - Demonstrates the capabilities of Python-based tooling for SPIFFS images available on host computers. - * - :doc:`partition` - - + +.. list-table:: Partition API examples + :widths: 25 75 + :header-rows: 0 + + * - **Code Example** + - **Description** * - :example:`partition_api ` - Provides an overview of API functions to look up particular partitions, perform basic I/O operations, and use partitions via CPU memory mapping. * - :example:`parttool ` - Demonstrates the capabilities of Python-based tooling for partition images available on host computers. - * - :doc:`vfs` - - + +.. list-table:: VFS related examples + :widths: 25 75 + :header-rows: 0 + + * - **Code Example** + - **Description** * - :example:`littlefs ` - Shows the use of the LittleFS component to initialize the filesystem and work with a file using POSIX functions. * - :example:`semihost_vfs ` From ebe5ac900bc17be361f0d2f78754b60116f475bf Mon Sep 17 00:00:00 2001 From: renpeiying Date: Wed, 18 Sep 2024 14:39:24 +0800 Subject: [PATCH 09/13] docs: Update CN translation for api-reference/storage/index.rst --- docs/en/api-reference/storage/index.rst | 4 +- docs/zh_CN/api-reference/storage/index.rst | 66 ++++++++++++++++------ 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/docs/en/api-reference/storage/index.rst b/docs/en/api-reference/storage/index.rst index 22d5197fcb..f3f184270f 100644 --- a/docs/en/api-reference/storage/index.rst +++ b/docs/en/api-reference/storage/index.rst @@ -62,7 +62,7 @@ Examples * - **Code Example** - **Description** * - :example:`fatfs/getting_started ` - - Demonstrates basic common file API(stdio.h) usage over internal flash using FATFS. + - Demonstrates basic common file API (stdio.h) usage over internal flash using FATFS. * - :example:`fatfs/fs_operations ` - Demonstrates POSIX API for filesystem manipulation, such as moving, removing and renaming files. @@ -70,6 +70,8 @@ Examples :widths: 25 75 :header-rows: 0 + * - **Code Example** + - **Description** * - :example:`fatfsgen ` - Demonstrates the capabilities of Python-based tooling for FATFS images available on host computers. * - :example:`ext_flash_fatfs ` diff --git a/docs/zh_CN/api-reference/storage/index.rst b/docs/zh_CN/api-reference/storage/index.rst index 0687d98c05..820987a555 100644 --- a/docs/zh_CN/api-reference/storage/index.rst +++ b/docs/zh_CN/api-reference/storage/index.rst @@ -37,44 +37,76 @@ wear-levelling storage-security.rst +示例 +---- + .. list-table:: 存储 API 相关例程 :widths: 25 75 :header-rows: 0 * - **例程** - **描述** - * - :doc:`fatfs` - - - * - :example:`wear_leveling ` - - 演示了如何在内部 flash 上使用 FATFS 磨损均衡。 - * - :example:`ext_flash_fatfs ` - - 演示了如何在外部 flash 上使用 FATFS 磨损均衡。 - * - :example:`fatfsgen ` - - 演示了在主机计算机上使用 Python 工具生成 FATFS 镜像的功能。 - * - :doc:`nvs_flash` - - * - :example:`nvs_rw_blob ` - 演示了如何在 NVS flash 中使用 C 语言 API 读写 blob 数据类型。 * - :example:`nvs_rw_value ` - 演示了如何在 NVS flash 中使用 C 语言 API 读写整数数据类型。 - * - :example:`nvs_rw_value_cxx ` + * - :example:`nvs_rw_value ` - 演示了如何在 NVS flash 中使用 C++ 语言 API 读写整数数据类型。 * - :example:`nvsgen ` - 演示了如何使用基于 Python 的 NVS 镜像生成工具,根据 CSV 文件内容创建 NVS 分区镜像。 - * - :doc:`spiffs` - - + +.. list-table:: 常用文件系统 API + :widths: 25 75 + :header-rows: 0 + + * - **代码示例** + - **描述** + * - :example:`fatfs/getting_started ` + - 演示了使用 FATFS 库在内部 flash 上应用标准文件 API (stdio.h)。 + * - :example:`fatfs/fs_operations ` + - 演示了使用 POSIX API 进行文件系统操作,如移动、删除和重命名文件等。 + +.. list-table:: FATFS API 示例 + :widths: 25 75 + :header-rows: 0 + + * - **代码示例** + - **描述** + * - :example:`fatfsgen ` + - 演示了在主机上使用 Python 工具生成 FATFS 镜像的相关功能。 + * - :example:`ext_flash_fatfs ` + - 演示了在外部 flash 上使用带有损耗均衡功能的 FATFS。 + * - :example:`wear_leveling ` + - 演示了在内部 flash 上使用带有损耗均衡功能的 FATFS。 + +.. list-table:: SPIFFS API 示例 + :widths: 25 75 + :header-rows: 0 + + * - **代码示例** + - **描述** * - :example:`spiffs ` - 演示了如何使用 SPIFFS API 初始化文件系统,并使用 POSIX 函数处理文件。 * - :example:`spiffsgen ` - 演示了在主机计算机上使用 Python 工具生成 SPIFFS 镜像的功能。 - * - :doc:`partition` - - + +.. list-table:: 分区 API 示例 + :widths: 25 75 + :header-rows: 0 + + * - **代码示例** + - **描述** * - :example:`partition_api ` - 介绍了用于查找特定分区、执行基本 I/O 操作以及通过 CPU 内存映射使用分区的 API 函数。 * - :example:`parttool ` - 演示了在主机计算机上使用 Python 工具生成分区镜像的功能。 - * - :doc:`vfs` - - + +.. list-table:: VFS 相关示例 + :widths: 25 75 + :header-rows: 0 + + * - **代码示例** + - **描述** * - :example:`littlefs ` - 演示了如何使用 LittleFS 组件初始化文件系统,并使用 POSIX 函数处理文件。 * - :example:`semihost_vfs ` From 908c4c7ce632d107c942cd99d6a0a1dbf8691429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Wed, 18 Sep 2024 10:13:01 +0200 Subject: [PATCH 10/13] docs(storage/fatfs): fix fatfs example links in docs --- docs/en/api-guides/file-system-considerations.rst | 2 +- docs/en/api-guides/performance/speed.rst | 4 ++-- docs/zh_CN/api-guides/performance/speed.rst | 4 ++-- docs/zh_CN/api-reference/storage/fatfs.rst | 4 ++-- docs/zh_CN/api-reference/storage/index.rst | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/en/api-guides/file-system-considerations.rst b/docs/en/api-guides/file-system-considerations.rst index a57ab01c87..2cf5c17661 100644 --- a/docs/en/api-guides/file-system-considerations.rst +++ b/docs/en/api-guides/file-system-considerations.rst @@ -105,7 +105,7 @@ The most supported file system, recommended for common applications - file/direc **Examples:** * :example:`storage/sd_card`: access the SD card which uses the FAT file system -* :example:`storage/ext_flash_fatfs`: access the external flash chip which uses the FAT file system +* :example:`storage/fatfs/ext_flash`: access the external flash chip which uses the FAT file system .. _spiffs-fs-section: diff --git a/docs/en/api-guides/performance/speed.rst b/docs/en/api-guides/performance/speed.rst index 0cce05a571..c374a32746 100644 --- a/docs/en/api-guides/performance/speed.rst +++ b/docs/en/api-guides/performance/speed.rst @@ -301,9 +301,9 @@ Improving I/O Performance Using standard C library functions like ``fread`` and ``fwrite`` instead of platform-specific unbuffered syscalls such as ``read`` and ``write``, may result in slower performance. -The ``fread`` and ``fwrite`` functions are designed for portability rather than speed, introducing some overhead due to their buffered nature. Check the example :example:`storage/fatfsgen` to see how to use these two functions. +The ``fread`` and ``fwrite`` functions are designed for portability rather than speed, introducing some overhead due to their buffered nature. Check the example :example:`storage/fatfs/getting_started` to see how to use these two functions. -In contrast, the ``read`` and ``write`` functions are standard POSIX APIs that can be used directly when working with FatFs through VFS, with ESP-IDF handling the underlying implementation. Check the example :example:`storage/perf_benchmark` to see how to use the two functions. +In contrast, the ``read`` and ``write`` functions are standard POSIX APIs that can be used directly when working with FatFs through VFS, with ESP-IDF handling the underlying implementation. Check the example :example:`storage/fatfs/fs_operations` to see how to use the two functions. Additional tips are provided below, and further details can be found in :doc:`/api-reference/storage/fatfs`. diff --git a/docs/zh_CN/api-guides/performance/speed.rst b/docs/zh_CN/api-guides/performance/speed.rst index 25601b4dad..55f0a2da74 100644 --- a/docs/zh_CN/api-guides/performance/speed.rst +++ b/docs/zh_CN/api-guides/performance/speed.rst @@ -301,9 +301,9 @@ ESP-IDF 支持动态 :doc:`/api-reference/system/intr_alloc` 和中断抢占。 使用标准 C 库函数,如 ``fread`` 和 ``fwrite``,相较于使用平台特定的不带缓冲系统调用,如 ``read`` 和 ``write``,可能会导致 I/O 性能下降。 -``fread`` 与 ``fwrite`` 函数是为可移植性而设计的,而非速度,其缓冲性质会引入一些额外的开销。关于如何使用这两个函数,请参考示例 :example:`storage/fatfsgen`。 +``fread`` 与 ``fwrite`` 函数是为可移植性而设计的,而非速度,其缓冲性质会引入一些额外的开销。关于如何使用这两个函数,请参考示例 :example:`storage/fatfs/getting_started`。 -与之相比,``read`` 与 ``write`` 函数是标准的 POSIX API,可直接通过 VFS 处理 FatFs,由 ESP-IDF 负责底层实现。关于如何使用这两个函数,请参考示例 :example:`storage/perf_benchmark`。 +与之相比,``read`` 与 ``write`` 函数是标准的 POSIX API,可直接通过 VFS 处理 FatFs,由 ESP-IDF 负责底层实现。关于如何使用这两个函数,请参考示例 :example:`storage/fatfs/fs_operations`。 下面提供了一些提示,更多信息请见 :doc:`/api-reference/storage/fatfs`。 diff --git a/docs/zh_CN/api-reference/storage/fatfs.rst b/docs/zh_CN/api-reference/storage/fatfs.rst index 65f281bd79..bc3671659f 100644 --- a/docs/zh_CN/api-reference/storage/fatfs.rst +++ b/docs/zh_CN/api-reference/storage/fatfs.rst @@ -123,7 +123,7 @@ FatFs 分区生成器 该函数的参数如下: -#. partition - 分区的名称,需要在分区表中定义(如 :example_file:`storage/fatfsgen/partitions_example.csv`)。 +#. partition - 分区的名称,需要在分区表中定义(如 :example_file:`storage/fatfs/fatfsgen/partitions_example.csv`)。 #. base_dir - 目录名称,该目录会被编码为 FatFs 分区,也可以选择将其被烧录进设备。但注意必须在分区表中指定合适的分区大小。 @@ -139,7 +139,7 @@ FatFs 分区生成器 没有指定 FLASH_IN_PROJECT 时也可以生成分区镜像,但是用户需要使用 ``esptool.py`` 或自定义的构建系统目标对其手动烧录。 -相关示例请查看 :example:`storage/fatfsgen`。 +相关示例请查看 :example:`storage/fatfs/fatfsgen`。 .. _fatfs-partition-analyzer: diff --git a/docs/zh_CN/api-reference/storage/index.rst b/docs/zh_CN/api-reference/storage/index.rst index 820987a555..b643c2b7de 100644 --- a/docs/zh_CN/api-reference/storage/index.rst +++ b/docs/zh_CN/api-reference/storage/index.rst @@ -74,7 +74,7 @@ - **描述** * - :example:`fatfsgen ` - 演示了在主机上使用 Python 工具生成 FATFS 镜像的相关功能。 - * - :example:`ext_flash_fatfs ` + * - :example:`ext_flash_fatfs ` - 演示了在外部 flash 上使用带有损耗均衡功能的 FATFS。 * - :example:`wear_leveling ` - 演示了在内部 flash 上使用带有损耗均衡功能的 FATFS。 From bcc060b98e81b1ddfa39a00f45f40636c3cb6d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Fri, 20 Sep 2024 09:42:27 +0200 Subject: [PATCH 11/13] docs(storage/fatfs): fix relative links in fatfs examples --- examples/storage/fatfs/ext_flash/README.md | 2 +- examples/storage/fatfs/fatfsgen/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/storage/fatfs/ext_flash/README.md b/examples/storage/fatfs/ext_flash/README.md index 0014bd8d31..349fd1ba3e 100644 --- a/examples/storage/fatfs/ext_flash/README.md +++ b/examples/storage/fatfs/ext_flash/README.md @@ -5,7 +5,7 @@ (See the README.md file in the upper level 'examples' directory for more information about examples.) -This example is similar to the [wear levelling](../wear_levelling/README.md) example, except that it uses an external SPI Flash chip. This can be useful if you need to add more storage to a module with only 4 MB flash size. +This example is similar to the [wear levelling](../../wear_levelling/README.md) example, except that it uses an external SPI Flash chip. This can be useful if you need to add more storage to a module with only 4 MB flash size. The flow of the example is as follows: diff --git a/examples/storage/fatfs/fatfsgen/README.md b/examples/storage/fatfs/fatfsgen/README.md index aa203d8356..772cf9cd8e 100644 --- a/examples/storage/fatfs/fatfsgen/README.md +++ b/examples/storage/fatfs/fatfsgen/README.md @@ -6,7 +6,7 @@ (See the README.md file in the upper level 'examples' directory for more information about examples.) This example demonstrates how to use the FATFS partition -generation tool [fatfsgen.py](../../../components/fatfs/fatfsgen.py) to automatically create a FATFS +generation tool [fatfsgen.py](../../../../components/fatfs/fatfsgen.py) to automatically create a FATFS filesystem image from the contents of a host folder during build, with an option of automatically flashing the created image on invocation of `idf.py -p PORT flash`. Beware that the minimal required size of the flash is 4 MB. From fef1d6278eee34e2ca2a3c3232cfb02a620c83e0 Mon Sep 17 00:00:00 2001 From: renpeiying Date: Mon, 23 Sep 2024 14:53:27 +0800 Subject: [PATCH 12/13] docs: update CN trans according to review --- docs/zh_CN/api-reference/storage/index.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/zh_CN/api-reference/storage/index.rst b/docs/zh_CN/api-reference/storage/index.rst index b643c2b7de..3b71db1be0 100644 --- a/docs/zh_CN/api-reference/storage/index.rst +++ b/docs/zh_CN/api-reference/storage/index.rst @@ -62,9 +62,9 @@ * - **代码示例** - **描述** * - :example:`fatfs/getting_started ` - - 演示了使用 FATFS 库在内部 flash 上应用标准文件 API (stdio.h)。 + - 演示了如何使用 FATFS 库在内部 flash 上应用标准文件 API (stdio.h)。 * - :example:`fatfs/fs_operations ` - - 演示了使用 POSIX API 进行文件系统操作,如移动、删除和重命名文件等。 + - 演示了如何使用 POSIX API 进行文件系统操作,如移动、删除和重命名文件等。 .. list-table:: FATFS API 示例 :widths: 25 75 @@ -75,13 +75,13 @@ * - :example:`fatfsgen ` - 演示了在主机上使用 Python 工具生成 FATFS 镜像的相关功能。 * - :example:`ext_flash_fatfs ` - - 演示了在外部 flash 上使用带有损耗均衡功能的 FATFS。 + - 演示了在外部 flash 上使用带有磨损均衡功能的 FATFS。 * - :example:`wear_leveling ` - - 演示了在内部 flash 上使用带有损耗均衡功能的 FATFS。 + - 演示了在内部 flash 上使用带有磨损均衡功能的 FATFS。 .. list-table:: SPIFFS API 示例 :widths: 25 75 - :header-rows: 0 + :header-rows: 0 * - **代码示例** - **描述** From 5841495e7f474c12be486c7364edf16a46b3e3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Thu, 17 Oct 2024 09:21:33 +0200 Subject: [PATCH 13/13] fix(storage/fatfs): fix CMake project names in fatfs examples --- examples/storage/fatfs/ext_flash/CMakeLists.txt | 2 +- examples/storage/fatfs/fatfsgen/CMakeLists.txt | 2 +- examples/storage/fatfs/fs_operations/CMakeLists.txt | 2 +- examples/storage/fatfs/getting_started/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/storage/fatfs/ext_flash/CMakeLists.txt b/examples/storage/fatfs/ext_flash/CMakeLists.txt index 93841c0e29..66233663cd 100644 --- a/examples/storage/fatfs/ext_flash/CMakeLists.txt +++ b/examples/storage/fatfs/ext_flash/CMakeLists.txt @@ -4,4 +4,4 @@ cmake_minimum_required(VERSION 3.16) # external SPI flash driver not currently supported for ESP32-S2 include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(ext_flash_fatfs) +project(fatfs_ext_flash) diff --git a/examples/storage/fatfs/fatfsgen/CMakeLists.txt b/examples/storage/fatfs/fatfsgen/CMakeLists.txt index 1c0c2b8a1a..0399bf40c5 100644 --- a/examples/storage/fatfs/fatfsgen/CMakeLists.txt +++ b/examples/storage/fatfs/fatfsgen/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(fatfsgen) +project(fatfs_fatfsgen) diff --git a/examples/storage/fatfs/fs_operations/CMakeLists.txt b/examples/storage/fatfs/fs_operations/CMakeLists.txt index 1c0c2b8a1a..2f478de10d 100644 --- a/examples/storage/fatfs/fs_operations/CMakeLists.txt +++ b/examples/storage/fatfs/fs_operations/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(fatfsgen) +project(fatfs_fs_operations) diff --git a/examples/storage/fatfs/getting_started/CMakeLists.txt b/examples/storage/fatfs/getting_started/CMakeLists.txt index 1c0c2b8a1a..b595983679 100644 --- a/examples/storage/fatfs/getting_started/CMakeLists.txt +++ b/examples/storage/fatfs/getting_started/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(fatfsgen) +project(fatfs_getting_started)