diff --git a/components/fatfs/test_apps/flash_wl/main/test_fatfs_flash_wl.c b/components/fatfs/test_apps/flash_wl/main/test_fatfs_flash_wl.c index 1af50fe6cb..5374b88de3 100644 --- a/components/fatfs/test_apps/flash_wl/main/test_fatfs_flash_wl.c +++ b/components/fatfs/test_apps/flash_wl/main/test_fatfs_flash_wl.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,6 +23,7 @@ #include "wear_levelling.h" #include "esp_partition.h" #include "esp_memory_utils.h" +#include "vfs_fat_internal.h" void app_main(void) { @@ -32,7 +33,7 @@ void app_main(void) static wl_handle_t s_test_wl_handle; static void test_setup(void) { - esp_vfs_fat_sdmmc_mount_config_t mount_config = { + esp_vfs_fat_mount_config_t mount_config = { .format_if_mount_failed = true, .max_files = 5, }; @@ -45,14 +46,32 @@ static void test_teardown(void) TEST_ESP_OK(esp_vfs_fat_spiflash_unmount_rw_wl("/spiflash", s_test_wl_handle)); } -TEST_CASE("(WL) can format partition", "[fatfs][wear_levelling][timeout=180]") +TEST_CASE("(WL) can format partition", "[fatfs][wear_levelling][timeout=120]") { TEST_ESP_OK(esp_vfs_fat_spiflash_format_rw_wl("/spiflash", NULL)); test_setup(); + vfs_fat_spiflash_ctx_t* ctx = get_vfs_fat_spiflash_ctx(s_test_wl_handle); + TEST_ASSERT_NOT_NULL(ctx); + TEST_ASSERT_TRUE(ctx->fs->n_fats == 2); // 2 FATs are created by default test_teardown(); } -TEST_CASE("(WL) can format when the FAT is mounted already", "[fatfs][wear_levelling][timeout=180]") +TEST_CASE("(WL) can format partition with config", "[fatfs][wear_levelling][timeout=120]") +{ + esp_vfs_fat_mount_config_t format_config = { + .format_if_mount_failed = true, + .max_files = 5, + .use_one_fat = true, + }; + TEST_ESP_OK(esp_vfs_fat_spiflash_format_cfg_rw_wl("/spiflash", NULL, &format_config)); + test_setup(); + vfs_fat_spiflash_ctx_t* ctx = get_vfs_fat_spiflash_ctx(s_test_wl_handle); + TEST_ASSERT_NOT_NULL(ctx); + TEST_ASSERT_TRUE(ctx->fs->n_fats == 1); + test_teardown(); +} + +TEST_CASE("(WL) can format when the FAT is mounted already", "[fatfs][wear_levelling][timeout=120]") { test_setup(); TEST_ESP_OK(esp_vfs_fat_spiflash_format_rw_wl("/spiflash", NULL)); @@ -61,9 +80,28 @@ TEST_CASE("(WL) can format when the FAT is mounted already", "[fatfs][wear_level test_teardown(); } -TEST_CASE("(WL) can format specified FAT when more are mounted", "[fatfs][wear_levelling][timeout=180]") +TEST_CASE("(WL) can format when the FAT is mounted already with config", "[fatfs][wear_levelling][timeout=120]") { - esp_vfs_fat_sdmmc_mount_config_t mount_config = { + TEST_ESP_OK(esp_vfs_fat_spiflash_format_rw_wl("/spiflash", NULL)); // To reset the FAT number to 2 + test_setup(); + vfs_fat_spiflash_ctx_t* ctx = get_vfs_fat_spiflash_ctx(s_test_wl_handle); + TEST_ASSERT_NOT_NULL(ctx); + TEST_ASSERT_TRUE(ctx->fs->n_fats == 2); + esp_vfs_fat_mount_config_t format_config = { + .format_if_mount_failed = true, + .max_files = 5, + .use_one_fat = true, + }; + TEST_ESP_OK(esp_vfs_fat_spiflash_format_cfg_rw_wl("/spiflash", NULL, &format_config)); + TEST_ASSERT_TRUE(ctx->fs->n_fats == 1); + test_fatfs_create_file_with_text("/spiflash/hello.txt", fatfs_test_hello_str); + test_fatfs_pread_file("/spiflash/hello.txt"); + test_teardown(); +} + +TEST_CASE("(WL) can format specified FAT when more are mounted", "[fatfs][wear_levelling][timeout=120]") +{ + esp_vfs_fat_mount_config_t mount_config = { .format_if_mount_failed = true, .max_files = 5, }; @@ -126,7 +164,7 @@ TEST_CASE("(WL) pwrite() works well", "[fatfs][wear_levelling]") TEST_CASE("(WL) can open maximum number of files", "[fatfs][wear_levelling]") { size_t max_files = FOPEN_MAX - 3; /* account for stdin, stdout, stderr */ - esp_vfs_fat_sdmmc_mount_config_t mount_config = { + esp_vfs_fat_mount_config_t mount_config = { .format_if_mount_failed = true, .max_files = max_files }; diff --git a/components/fatfs/test_apps/sdcard/main/test_fatfs_sdmmc.c b/components/fatfs/test_apps/sdcard/main/test_fatfs_sdmmc.c index 4504a5d64c..bfda90cf45 100644 --- a/components/fatfs/test_apps/sdcard/main/test_fatfs_sdmmc.c +++ b/components/fatfs/test_apps/sdcard/main/test_fatfs_sdmmc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,7 @@ #include "ff.h" #include "test_fatfs_common.h" #include "soc/soc_caps.h" +#include "vfs_fat_internal.h" #if CONFIG_IDF_TARGET_ESP32 #define SDSPI_MISO_PIN 2 @@ -102,6 +103,35 @@ TEST_CASE("(SD) can format partition", "[fatfs][sdmmc][timeout=180]") test_teardown_sdmmc(card); } +TEST_CASE("(SD) can format partition with config", "[fatfs][sdmmc][timeout=180]") +{ + sdmmc_card_t *card = NULL; + test_setup_sdmmc(&card); + vfs_fat_sd_ctx_t* ctx = get_vfs_fat_get_sd_ctx(card); + TEST_ASSERT_NOT_NULL(ctx); + + esp_vfs_fat_mount_config_t format_config = { + .format_if_mount_failed = true, + .max_files = 5, + .allocation_unit_size = 16 * 1024, + .use_one_fat = true, + }; + TEST_ESP_OK(esp_vfs_fat_sdcard_format_cfg("/sdcard", card, &format_config)); + TEST_ASSERT_TRUE(ctx->fs->n_fats == 1); + + test_fatfs_create_file_with_text(test_filename, fatfs_test_hello_str); + test_fatfs_read_file(test_filename); + + format_config.use_one_fat = false; + TEST_ESP_OK(esp_vfs_fat_sdcard_format_cfg("/sdcard", card, &format_config)); + TEST_ASSERT_TRUE(ctx->fs->n_fats == 2); + + test_fatfs_create_file_with_text(test_filename, fatfs_test_hello_str); + test_fatfs_read_file(test_filename); + + test_teardown_sdmmc(card); +} + TEST_CASE("(SD) can create and write file", "[fatfs][sdmmc]") { sdmmc_card_t *card = NULL; diff --git a/components/fatfs/test_apps/sdcard/main/test_fatfs_sdspi.c b/components/fatfs/test_apps/sdcard/main/test_fatfs_sdspi.c index c1d567c095..7ff45e3caa 100644 --- a/components/fatfs/test_apps/sdcard/main/test_fatfs_sdspi.c +++ b/components/fatfs/test_apps/sdcard/main/test_fatfs_sdspi.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,7 @@ #include "ff.h" #include "test_fatfs_common.h" #include "soc/soc_caps.h" +#include "vfs_fat_internal.h" #if CONFIG_IDF_TARGET_ESP32 #define SDSPI_MISO_PIN 2 @@ -89,7 +90,7 @@ static void test_teardown_sdspi(sdspi_mem_t* mem) HEAP_SIZE_CHECK(mem->heap_size, 0); } -TEST_CASE("(SDSPI) write/read speed test", "[fatfs][sdspi]") +TEST_CASE("(SDSPI) write/read speed test", "[fatfs][sdspi][timeout=120]") { sdspi_mem_t mem; size_t file_size = 1 * 1024 * 1024; @@ -197,3 +198,55 @@ TEST_CASE("(SDSPI) can format card", "[fatfs][sdspi][timeout=180]") TEST_ESP_OK(esp_vfs_fat_sdcard_unmount(path, card)); test_teardown_sdspi(&mem); } + + +TEST_CASE("(SDSPI) can format card with config", "[fatfs][sdspi][timeout=180]") +{ + sdspi_mem_t mem; + test_setup_sdspi(&mem); + + const char path[] = "/sdcard"; + sdmmc_card_t *card; + card = NULL; + sdspi_device_config_t device_cfg = { + .gpio_cs = SDSPI_CS_PIN, + .host_id = SDSPI_HOST_ID, + .gpio_cd = SDSPI_SLOT_NO_CD, + .gpio_wp = SDSPI_SLOT_NO_WP, + .gpio_int = SDSPI_SLOT_NO_INT, + }; + + sdmmc_host_t host = SDSPI_HOST_DEFAULT(); + host.slot = SDSPI_HOST_ID; + esp_vfs_fat_sdmmc_mount_config_t mount_config = { + .format_if_mount_failed = true, + .max_files = 5, + .allocation_unit_size = 64 * 1024, + }; + TEST_ESP_OK(esp_vfs_fat_sdspi_mount(path, &host, &device_cfg, &mount_config, &card)); + + vfs_fat_sd_ctx_t* ctx = get_vfs_fat_get_sd_ctx(card); + TEST_ASSERT_NOT_NULL(ctx); + + esp_vfs_fat_mount_config_t format_config = { + .format_if_mount_failed = true, + .max_files = 5, + .allocation_unit_size = 64 * 1024, + .use_one_fat = true, + }; + TEST_ESP_OK(esp_vfs_fat_sdcard_format_cfg("/sdcard", card, &format_config)); + TEST_ASSERT_TRUE(ctx->fs->n_fats == 1); + + test_fatfs_create_file_with_text(s_test_filename, fatfs_test_hello_str); + test_fatfs_read_file(s_test_filename); + + format_config.use_one_fat = false; + TEST_ESP_OK(esp_vfs_fat_sdcard_format_cfg("/sdcard", card, &format_config)); + TEST_ASSERT_TRUE(ctx->fs->n_fats == 2); + + test_fatfs_create_file_with_text(s_test_filename, fatfs_test_hello_str); + test_fatfs_read_file(s_test_filename); + + TEST_ESP_OK(esp_vfs_fat_sdcard_unmount(path, card)); + test_teardown_sdspi(&mem); +} diff --git a/components/fatfs/test_apps/sdcard/pytest_fatfs_sdcard.py b/components/fatfs/test_apps/sdcard/pytest_fatfs_sdcard.py index 8088f7a7af..fec1fafbf9 100644 --- a/components/fatfs/test_apps/sdcard/pytest_fatfs_sdcard.py +++ b/components/fatfs/test_apps/sdcard/pytest_fatfs_sdcard.py @@ -1,6 +1,5 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut diff --git a/components/fatfs/vfs/esp_vfs_fat.h b/components/fatfs/vfs/esp_vfs_fat.h index 70e2392d7c..e89188b2d1 100644 --- a/components/fatfs/vfs/esp_vfs_fat.h +++ b/components/fatfs/vfs/esp_vfs_fat.h @@ -224,6 +224,25 @@ esp_err_t esp_vfs_fat_sdmmc_unmount(void) __attribute__((deprecated("Please use */ esp_err_t esp_vfs_fat_sdcard_unmount(const char* base_path, sdmmc_card_t *card); +/** + * @brief Format FAT filesystem with given configuration + * + * @note + * This API should be only called when the FAT is already mounted. + * + * @param base_path Path where partition should be registered (e.g. "/sdcard") + * @param card Pointer to the card handle, which should be initialised by calling `esp_vfs_fat_sdspi_mount` first + * @param cfg Pointer to structure with extra parameters for formatting FATFS (only relevant fields are used). + * If NULL, the previous configuration will be used. + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_STATE: FAT partition isn't mounted, call esp_vfs_fat_sdmmc_mount or esp_vfs_fat_sdspi_mount first + * - ESP_ERR_NO_MEM: if memory can not be allocated + * - ESP_FAIL: fail to format it, or fail to mount back + */ +esp_err_t esp_vfs_fat_sdcard_format_cfg(const char *base_path, sdmmc_card_t *card, esp_vfs_fat_mount_config_t *cfg); + /** * @brief Format FAT filesystem * @@ -284,6 +303,27 @@ esp_err_t esp_vfs_fat_spiflash_mount_rw_wl(const char* base_path, */ esp_err_t esp_vfs_fat_spiflash_unmount_rw_wl(const char* base_path, wl_handle_t wl_handle); +/** + * @brief Format FAT filesystem with given configuration + * + * @note + * This API can be called when the FAT is mounted / not mounted. + * If this API is called when the FAT isn't mounted (by calling esp_vfs_fat_spiflash_mount_rw_wl), + * this API will first mount the FAT then format it, then restore back to the original state. + * + * @param base_path Path where partition should be registered (e.g. "/spiflash") + * @param partition_label Label of the partition which should be used + * @param cfg Pointer to structure with extra parameters for formatting FATFS (only relevant fields are used). + * If NULL and mounted the previous configuration will be used. + * If NULL and unmounted the default configuration will be used. + * + * @return + * - ESP_OK + * - ESP_ERR_NO_MEM: if memory can not be allocated + * - Other errors from esp_vfs_fat_spiflash_mount_rw_wl + */ +esp_err_t esp_vfs_fat_spiflash_format_cfg_rw_wl(const char* base_path, const char* partition_label, esp_vfs_fat_mount_config_t *cfg); + /** * @brief Format FAT filesystem * diff --git a/components/fatfs/vfs/vfs_fat.c b/components/fatfs/vfs/vfs_fat.c index 5d70c09b23..310d625020 100644 --- a/components/fatfs/vfs/vfs_fat.c +++ b/components/fatfs/vfs/vfs_fat.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -152,6 +152,11 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz .utime_p = &vfs_fat_utime, #endif // CONFIG_VFS_SUPPORT_DIR }; + + if (max_files < 1) { + max_files = 1; // ff_memalloc(max_files * sizeof(bool)) below will fail if max_files == 0 + } + size_t ctx_size = sizeof(vfs_fat_ctx_t) + max_files * sizeof(FIL); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ff_memalloc(ctx_size); if (fat_ctx == NULL) { diff --git a/components/fatfs/vfs/vfs_fat_internal.h b/components/fatfs/vfs/vfs_fat_internal.h index dc3bae271c..373d5499bf 100644 --- a/components/fatfs/vfs/vfs_fat_internal.h +++ b/components/fatfs/vfs/vfs_fat_internal.h @@ -1,23 +1,41 @@ -// Copyright 2018 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once #include "esp_vfs_fat.h" +#include "diskio_impl.h" +#include "esp_partition.h" +#include "sdmmc_cmd.h" #include #include +typedef enum { + FORMATTED_DURING_LAST_MOUNT = 1 << 0, // The FATFS partition was formatted during the last mount +} vfs_fat_x_ctx_flags_t; + +typedef struct vfs_fat_spiflash_ctx_t { + const esp_partition_t *partition; //The partition where the FAT is located + bool by_label; //If the partition is mounted by lable or not + BYTE pdrv; //Drive number that is mounted + FATFS *fs; //FAT structure pointer that is registered + wl_handle_t wlhandle; //WL handle + esp_vfs_fat_mount_config_t mount_config; //Mount configuration + vfs_fat_x_ctx_flags_t flags; //Flags +} vfs_fat_spiflash_ctx_t; + +typedef struct vfs_fat_sd_ctx_t { + BYTE pdrv; //Drive number that is mounted + esp_vfs_fat_mount_config_t mount_config; //Mount configuration + FATFS *fs; //FAT structure pointer that is registered + sdmmc_card_t *card; //Card info + char *base_path; //Path where partition is registered + vfs_fat_x_ctx_flags_t flags; //Flags +} vfs_fat_sd_ctx_t; + static inline size_t esp_vfs_fat_get_allocation_unit_size( size_t sector_size, size_t requested_size) { @@ -28,3 +46,6 @@ static inline size_t esp_vfs_fat_get_allocation_unit_size( alloc_unit_size = MIN(alloc_unit_size, max_size); return alloc_unit_size; } + +vfs_fat_spiflash_ctx_t* get_vfs_fat_spiflash_ctx(wl_handle_t wlhandle); +vfs_fat_sd_ctx_t* get_vfs_fat_get_sd_ctx(const sdmmc_card_t *card); diff --git a/components/fatfs/vfs/vfs_fat_sdmmc.c b/components/fatfs/vfs/vfs_fat_sdmmc.c index 418b0880ba..fa36e8e043 100644 --- a/components/fatfs/vfs/vfs_fat_sdmmc.c +++ b/components/fatfs/vfs/vfs_fat_sdmmc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -31,14 +31,6 @@ static const char* TAG = "vfs_fat_sdmmc"; } \ } while(0) -typedef struct vfs_fat_sd_ctx_t { - BYTE pdrv; //Drive number that is mounted - esp_vfs_fat_mount_config_t mount_config; //Mount configuration - FATFS *fs; //FAT structure pointer that is registered - sdmmc_card_t *card; //Card info - char *base_path; //Path where partition is registered -} vfs_fat_sd_ctx_t; - static vfs_fat_sd_ctx_t *s_ctx[FF_VOLUMES] = {}; /** * This `s_saved_ctx_id` is only used by `esp_vfs_fat_sdmmc_unmount`, which is deprecated. @@ -75,6 +67,15 @@ static uint32_t s_get_unused_context_id(void) return FF_VOLUMES; } +vfs_fat_sd_ctx_t* get_vfs_fat_get_sd_ctx(const sdmmc_card_t *card) +{ + uint32_t id = FF_VOLUMES; + if (s_get_context_id_by_card(card, &id)) { + return s_ctx[id]; + } + return NULL; +} + static esp_err_t mount_prepare_mem(const char *base_path, BYTE *out_pdrv, char **out_dup_path, @@ -116,7 +117,7 @@ cleanup: return err; } -static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8_t pdrv, const esp_vfs_fat_mount_config_t *mount_config) +static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8_t pdrv, const esp_vfs_fat_mount_config_t *mount_config, vfs_fat_x_ctx_flags_t *out_flags) { esp_err_t err = ESP_OK; FRESULT res = f_mount(fs, drv, 1); @@ -134,6 +135,10 @@ static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8 return err; } + if (out_flags) { + *out_flags |= FORMATTED_DURING_LAST_MOUNT; // set flag + } + ESP_LOGW(TAG, "mounting again"); res = f_mount(fs, drv, 0); if (res != FR_OK) { @@ -141,13 +146,17 @@ static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8 ESP_LOGD(TAG, "f_mount failed after formatting (%d)", res); return err; } + } else { + if (out_flags) { + *out_flags &= ~FORMATTED_DURING_LAST_MOUNT; // reset flag + } } return ESP_OK; } static esp_err_t mount_to_vfs_fat(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, uint8_t pdrv, - const char *base_path, FATFS **out_fs) + const char *base_path, FATFS **out_fs, vfs_fat_x_ctx_flags_t *out_flags) { FATFS *fs = NULL; esp_err_t err; @@ -167,7 +176,7 @@ static esp_err_t mount_to_vfs_fat(const esp_vfs_fat_mount_config_t *mount_config } // Try to mount partition - err = s_f_mount(card, fs, drv, pdrv, mount_config); + err = s_f_mount(card, fs, drv, pdrv, mount_config, out_flags); if (err != ESP_OK) { goto fail; } @@ -265,7 +274,9 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, err = sdmmc_card_init(host_config, card); CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed"); - err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs); + vfs_fat_x_ctx_flags_t flags = 0; + + err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs, &flags); CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed"); if (out_card != NULL) { @@ -285,6 +296,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, ctx->card = card; ctx->base_path = dup_path; ctx->fs = fs; + ctx->flags = flags; ctx_id = s_get_unused_context_id(); assert(ctx_id != FF_VOLUMES); s_ctx[ctx_id] = ctx; @@ -360,7 +372,9 @@ esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path, err = sdmmc_card_init(host_config, card); CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed"); - err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs); + vfs_fat_x_ctx_flags_t flags = 0; + + err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path, &fs, &flags); CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed"); if (out_card != NULL) { @@ -380,6 +394,7 @@ esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path, ctx->card = card; ctx->base_path = dup_path; ctx->fs = fs; + ctx->flags = flags; ctx_id = s_get_unused_context_id(); assert(ctx_id != FF_VOLUMES); s_ctx[ctx_id] = ctx; @@ -450,7 +465,7 @@ esp_err_t esp_vfs_fat_sdcard_unmount(const char *base_path, sdmmc_card_t *card) return err; } -esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card) +esp_err_t esp_vfs_fat_sdcard_format_cfg(const char *base_path, sdmmc_card_t *card, esp_vfs_fat_mount_config_t *cfg) { esp_err_t ret = ESP_OK; if (!card) { @@ -482,6 +497,11 @@ esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card) uint32_t id = FF_VOLUMES; bool found = s_get_context_id_by_card(card, &id); assert(found); + + if (cfg) { + s_ctx[id]->mount_config = *cfg; + } + size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size( card->csd.sector_size, s_ctx[id]->mount_config.allocation_unit_size); @@ -495,7 +515,7 @@ esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card) } //mount back - esp_err_t err = s_f_mount(card, s_ctx[id]->fs, drv, pdrv, &s_ctx[id]->mount_config); + esp_err_t err = s_f_mount(card, s_ctx[id]->fs, drv, pdrv, &s_ctx[id]->mount_config, NULL); if (err != ESP_OK) { unmount_card_core(base_path, card); ESP_LOGE(TAG, "failed to format, resources recycled, please mount again"); @@ -503,3 +523,7 @@ esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card) return ret; } + +esp_err_t esp_vfs_fat_sdcard_format(const char *base_path, sdmmc_card_t *card) { + return esp_vfs_fat_sdcard_format_cfg(base_path, card, NULL); +} diff --git a/components/fatfs/vfs/vfs_fat_spiflash.c b/components/fatfs/vfs/vfs_fat_spiflash.c index f3ea28b8b0..9708814699 100644 --- a/components/fatfs/vfs/vfs_fat_spiflash.c +++ b/components/fatfs/vfs/vfs_fat_spiflash.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,15 +17,6 @@ static const char* TAG = "vfs_fat_spiflash"; -typedef struct vfs_fat_spiflash_ctx_t { - const esp_partition_t *partition; //The partition where the FAT is located - bool by_label; //If the partition is mounted by lable or not - BYTE pdrv; //Drive number that is mounted - FATFS *fs; //FAT structure pointer that is registered - wl_handle_t wlhandle; //WL handle - esp_vfs_fat_mount_config_t mount_config; //Mount configuration -} vfs_fat_spiflash_ctx_t; - static vfs_fat_spiflash_ctx_t *s_ctx[FF_VOLUMES] = {}; extern esp_err_t esp_vfs_set_readonly_flag(const char* base_path); // from vfs/vfs.c to set readonly flag in esp_vfs_t struct externally @@ -74,7 +65,16 @@ static uint32_t s_get_unused_context_id(void) return FF_VOLUMES; } -static esp_err_t s_f_mount_rw(FATFS *fs, const char *drv, const esp_vfs_fat_mount_config_t *mount_config) +vfs_fat_spiflash_ctx_t* get_vfs_fat_spiflash_ctx(wl_handle_t wlhandle) +{ + uint32_t id = FF_VOLUMES; + if (s_get_context_id_by_wl_handle(wlhandle, &id)) { + return s_ctx[id]; + } + return NULL; +} + +static esp_err_t s_f_mount_rw(FATFS *fs, const char *drv, const esp_vfs_fat_mount_config_t *mount_config, vfs_fat_x_ctx_flags_t *out_flags) { FRESULT fresult = f_mount(fs, drv, 1); if (fresult != FR_OK) { @@ -99,9 +99,17 @@ static esp_err_t s_f_mount_rw(FATFS *fs, const char *drv, const esp_vfs_fat_moun workbuf = NULL; ESP_RETURN_ON_FALSE(fresult == FR_OK, ESP_FAIL, TAG, "f_mkfs failed (%d)", fresult); + if (out_flags) { + *out_flags |= FORMATTED_DURING_LAST_MOUNT; // set flag + } + ESP_LOGI(TAG, "Mounting again"); fresult = f_mount(fs, drv, 0); ESP_RETURN_ON_FALSE(fresult == FR_OK, ESP_FAIL, TAG, "f_mount failed after formatting (%d)", fresult); + } else { + if (out_flags) { + *out_flags &= ~FORMATTED_DURING_LAST_MOUNT; // reset flag + } } return ESP_OK; } @@ -142,8 +150,10 @@ esp_err_t esp_vfs_fat_spiflash_mount_rw_wl(const char* base_path, goto fail; } + vfs_fat_x_ctx_flags_t flags = 0; + // Try to mount partition - ret = s_f_mount_rw(fs, drv, mount_config); + ret = s_f_mount_rw(fs, drv, mount_config, &flags); if (ret != ESP_OK) { goto fail; } @@ -155,6 +165,7 @@ esp_err_t esp_vfs_fat_spiflash_mount_rw_wl(const char* base_path, ctx->pdrv = pdrv; ctx->fs = fs; ctx->wlhandle = *wl_handle; + ctx->flags = flags; memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t)); ctx_id = s_get_unused_context_id(); //At this stage, we should always get a free context, otherwise program should return already @@ -201,7 +212,7 @@ esp_err_t esp_vfs_fat_spiflash_unmount_rw_wl(const char* base_path, wl_handle_t return err; } -esp_err_t esp_vfs_fat_spiflash_format_rw_wl(const char* base_path, const char* partition_label) +esp_err_t esp_vfs_fat_spiflash_format_cfg_rw_wl(const char* base_path, const char* partition_label, esp_vfs_fat_mount_config_t *cfg) { esp_err_t ret = ESP_OK; bool partition_was_mounted = false; @@ -211,15 +222,28 @@ esp_err_t esp_vfs_fat_spiflash_format_rw_wl(const char* base_path, const char* p bool found = s_get_context_id_by_label(partition_label, &id); if (!found) { - const esp_vfs_fat_mount_config_t mount_config = { + esp_vfs_fat_mount_config_t default_mount_config = { .max_files = 1, .format_if_mount_failed = true, }; - ESP_RETURN_ON_ERROR(esp_vfs_fat_spiflash_mount_rw_wl(base_path, partition_label, &mount_config, &temp_handle), TAG, "Failed to mount"); + esp_vfs_fat_mount_config_t *mount_cfg = NULL; + if (cfg) { + mount_cfg = cfg; + } else { + mount_cfg = &default_mount_config; + } + ESP_RETURN_ON_ERROR(esp_vfs_fat_spiflash_mount_rw_wl(base_path, partition_label, mount_cfg, &temp_handle), TAG, "Failed to mount"); found = s_get_context_id_by_label(partition_label, &id); assert(found); + if (s_ctx[id]->flags & FORMATTED_DURING_LAST_MOUNT) { + ESP_LOGD(TAG, "partition was formatted during mounting, skipping another format"); + return ESP_OK; + } } else { partition_was_mounted = true; + if (cfg) { + s_ctx[id]->mount_config = *cfg; + } } //unmount @@ -244,7 +268,7 @@ esp_err_t esp_vfs_fat_spiflash_format_rw_wl(const char* base_path, const char* p mount_back: if (partition_was_mounted) { - esp_err_t err = s_f_mount_rw(s_ctx[id]->fs, drv, &s_ctx[id]->mount_config); + esp_err_t err = s_f_mount_rw(s_ctx[id]->fs, drv, &s_ctx[id]->mount_config, NULL); if (err != ESP_OK) { ESP_LOGE(TAG, "failed to mount back, go to recycle"); goto recycle; @@ -265,6 +289,10 @@ recycle: return ret; } +esp_err_t esp_vfs_fat_spiflash_format_rw_wl(const char* base_path, const char* partition_label) +{ + return esp_vfs_fat_spiflash_format_cfg_rw_wl(base_path, partition_label, NULL); +} esp_err_t esp_vfs_fat_spiflash_mount_ro(const char* base_path, const char* partition_label, diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 519620bac9..8b69b0d6b8 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -499,7 +499,6 @@ components/fatfs/src/ff.h components/fatfs/src/ffconf.h components/fatfs/src/ffsystem.c components/fatfs/src/ffunicode.c -components/fatfs/vfs/vfs_fat_internal.h components/freertos/FreeRTOS-Kernel-SMP/croutine.c components/freertos/FreeRTOS-Kernel-SMP/event_groups.c components/freertos/FreeRTOS-Kernel-SMP/include/freertos/FreeRTOS.h