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] 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