diff --git a/components/fatfs/src/diskio.c b/components/fatfs/src/diskio.c index 004cfc5be..915bb8e2c 100644 --- a/components/fatfs/src/diskio.c +++ b/components/fatfs/src/diskio.c @@ -18,39 +18,70 @@ #include static const char* TAG = "ff_diskio"; -static ff_diskio_impl_t s_impls[_VOLUMES] = { { 0 } }; +static ff_diskio_impl_t * s_impls[_VOLUMES]; static sdmmc_card_t* s_cards[_VOLUMES] = { NULL }; +static bool s_impls_initialized = false; PARTITION VolToPart[] = { {0, 1}, /* Logical drive 0 ==> Physical drive 0, 1st partition */ {1, 0} /* Logical drive 1 ==> Physical drive 1, auto detection */ }; +BYTE ff_disk_getpdrv() +{ + BYTE i; + for(i=0; i<_VOLUMES; i++) { + if (!s_impls[i]) { + return i; + } + } + return 0xFF; +} + void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl) { assert(pdrv < _VOLUMES); - memcpy(&s_impls[pdrv], discio_impl, sizeof(ff_diskio_impl_t)); + + if (!s_impls_initialized) { + s_impls_initialized = true; + memset(s_impls, 0, _VOLUMES * sizeof(ff_diskio_impl_t*)); + } + + if (s_impls[pdrv]) { + ff_diskio_impl_t* im = s_impls[pdrv]; + s_impls[pdrv] = NULL; + free(im); + } + + if (!discio_impl) { + return; + } + + ff_diskio_impl_t * impl = (ff_diskio_impl_t *)malloc(sizeof(ff_diskio_impl_t)); + assert(impl != NULL); + memcpy(impl, discio_impl, sizeof(ff_diskio_impl_t)); + s_impls[pdrv] = impl; } DSTATUS ff_disk_initialize (BYTE pdrv) { - return s_impls[pdrv].init(pdrv); + return s_impls[pdrv]->init(pdrv); } DSTATUS ff_disk_status (BYTE pdrv) { - return s_impls[pdrv].status(pdrv); + return s_impls[pdrv]->status(pdrv); } DRESULT ff_disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { - return s_impls[pdrv].read(pdrv, buff, sector, count); + return s_impls[pdrv]->read(pdrv, buff, sector, count); } DRESULT ff_disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { - return s_impls[pdrv].write(pdrv, buff, sector, count); + return s_impls[pdrv]->write(pdrv, buff, sector, count); } DRESULT ff_disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) { - return s_impls[pdrv].ioctl(pdrv, cmd, buff); + return s_impls[pdrv]->ioctl(pdrv, cmd, buff); } DWORD get_fattime(void) diff --git a/components/fatfs/src/diskio.h b/components/fatfs/src/diskio.h index 7c224809f..2fd27a864 100644 --- a/components/fatfs/src/diskio.h +++ b/components/fatfs/src/diskio.h @@ -76,6 +76,13 @@ void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl); */ void ff_diskio_register_sdmmc(BYTE pdrv, sdmmc_card_t* card); +/** + * Get next available drive number + * + * @return 0xFF on fail, else the drive number + */ +BYTE ff_disk_getpdrv(); + /* Disk Status Bits (DSTATUS) */ #define STA_NOINIT 0x01 /* Drive not initialized */ diff --git a/components/fatfs/src/esp_vfs_fat.h b/components/fatfs/src/esp_vfs_fat.h index 087d6cf77..6dbef5cfb 100644 --- a/components/fatfs/src/esp_vfs_fat.h +++ b/components/fatfs/src/esp_vfs_fat.h @@ -57,6 +57,20 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, */ esp_err_t esp_vfs_fat_unregister(); +/** + * @brief Un-register FATFS from VFS + * + * @note FATFS structure returned by esp_vfs_fat_register is destroyed after + * this call. Make sure to call f_mount function to unmount it before + * calling esp_vfs_fat_unregister. + * @param base_path path prefix where FATFS is registered. This is the same + * used when esp_vfs_fat_register was called + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE if FATFS is not registered in VFS + */ +esp_err_t esp_vfs_fat_unregister_ctx(const char* base_path); + /** * @brief Configuration arguments for esp_vfs_fat_sdmmc_mount function */ diff --git a/components/fatfs/src/vfs_fat.c b/components/fatfs/src/vfs_fat.c index 4ef387b43..6390fbcf7 100644 --- a/components/fatfs/src/vfs_fat.c +++ b/components/fatfs/src/vfs_fat.c @@ -28,6 +28,7 @@ typedef struct { char fat_drive[8]; + char base_path[ESP_VFS_PATH_MAX]; size_t max_files; FATFS fs; FIL files[0]; @@ -42,7 +43,6 @@ typedef struct { struct dirent cur_dirent; } vfs_fat_dir_t; - static const char* TAG = "vfs_fat"; static size_t vfs_fat_write(void* p, int fd, const void * data, size_t size); @@ -64,15 +64,42 @@ static int vfs_fat_closedir(void* ctx, DIR* pdir); static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode); static int vfs_fat_rmdir(void* ctx, const char* name); - -static char s_base_path[ESP_VFS_PATH_MAX]; +static vfs_fat_ctx_t* s_fat_ctxs[_VOLUMES] = { NULL, NULL }; +//compatibility static vfs_fat_ctx_t* s_fat_ctx = NULL; +static unsigned char esp_vfs_fat_get_ctx(const char* base_path) +{ + for(unsigned char i=0; i<_VOLUMES; i++) { + if (s_fat_ctxs[i] && !strcmp(s_fat_ctxs[i]->base_path, base_path)) { + return i; + } + } + return _VOLUMES; +} + +static unsigned char esp_vfs_fat_get_empty_ctx() +{ + for(unsigned char i=0; i<_VOLUMES; i++) { + if (!s_fat_ctxs[i]) { + return i; + } + } + return _VOLUMES; +} + esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, size_t max_files, FATFS** out_fs) { - if (s_fat_ctx) { + unsigned char ctx = esp_vfs_fat_get_ctx(base_path); + if (ctx < _VOLUMES) { return ESP_ERR_INVALID_STATE; } + + ctx = esp_vfs_fat_get_empty_ctx(); + if (ctx == _VOLUMES) { + return ESP_ERR_NO_MEM; + } + const esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_CONTEXT_PTR, .write_p = &vfs_fat_write, @@ -95,22 +122,49 @@ esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, siz .rmdir_p = &vfs_fat_rmdir }; size_t ctx_size = sizeof(vfs_fat_ctx_t) + max_files * sizeof(FIL); - s_fat_ctx = (vfs_fat_ctx_t*) calloc(1, ctx_size); - if (s_fat_ctx == NULL) { + vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) calloc(1, ctx_size); + if (fat_ctx == NULL) { return ESP_ERR_NO_MEM; } - s_fat_ctx->max_files = max_files; - strncpy(s_fat_ctx->fat_drive, fat_drive, sizeof(s_fat_ctx->fat_drive) - 1); - *out_fs = &s_fat_ctx->fs; - esp_err_t err = esp_vfs_register(base_path, &vfs, s_fat_ctx); + fat_ctx->max_files = max_files; + + strncpy(fat_ctx->fat_drive, fat_drive, sizeof(fat_ctx->fat_drive) - 1); + fat_ctx->fat_drive[sizeof(fat_ctx->fat_drive) - 1] = 0; + + strncpy(fat_ctx->base_path, base_path, sizeof(fat_ctx->base_path) - 1); + fat_ctx->base_path[sizeof(fat_ctx->base_path) - 1] = 0; + + esp_err_t err = esp_vfs_register(base_path, &vfs, fat_ctx); if (err != ESP_OK) { - free(s_fat_ctx); - s_fat_ctx = NULL; + free(fat_ctx); return err; } - _lock_init(&s_fat_ctx->lock); - strncpy(s_base_path, base_path, sizeof(s_base_path) - 1); - s_base_path[sizeof(s_base_path) - 1] = 0; + + _lock_init(&fat_ctx->lock); + s_fat_ctxs[ctx] = fat_ctx; + + //compatibility + s_fat_ctx = fat_ctx; + + *out_fs = &fat_ctx->fs; + + return ESP_OK; +} + +esp_err_t esp_vfs_fat_unregister_ctx(const char* base_path) +{ + unsigned char ctx = esp_vfs_fat_get_ctx(base_path); + if (ctx == _VOLUMES) { + return ESP_ERR_INVALID_STATE; + } + vfs_fat_ctx_t* fat_ctx = s_fat_ctxs[ctx]; + esp_err_t err = esp_vfs_unregister(fat_ctx->base_path); + if (err != ESP_OK) { + return err; + } + _lock_close(&fat_ctx->lock); + free(fat_ctx); + s_fat_ctxs[ctx] = NULL; return ESP_OK; } @@ -119,12 +173,10 @@ esp_err_t esp_vfs_fat_unregister() if (s_fat_ctx == NULL) { return ESP_ERR_INVALID_STATE; } - esp_err_t err = esp_vfs_unregister(s_base_path); + esp_err_t err = esp_vfs_fat_unregister_ctx(s_fat_ctx->base_path); if (err != ESP_OK) { return err; } - _lock_close(&s_fat_ctx->lock); - free(s_fat_ctx); s_fat_ctx = NULL; return ESP_OK; } @@ -197,11 +249,19 @@ static void file_cleanup(vfs_fat_ctx_t* ctx, int fd) memset(&ctx->files[fd], 0, sizeof(FIL)); } +#define vfs_fat_fix_path(ctx, path) \ + if (((vfs_fat_ctx_t*)ctx)->fat_drive[0]) { \ + char buf_ ## path[strlen(path)+strlen(((vfs_fat_ctx_t*)ctx)->fat_drive)+1]; \ + sprintf(buf_ ## path,"%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, path); \ + path = (const char *)buf_ ## path; \ + } + static int vfs_fat_open(void* ctx, const char * path, int flags, int mode) { + vfs_fat_fix_path(ctx, path); ESP_LOGV(TAG, "%s: path=\"%s\", flags=%x, mode=%x", __func__, path, flags, mode); vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; - _lock_acquire(&s_fat_ctx->lock); + _lock_acquire(&fat_ctx->lock); int fd = get_next_fd(fat_ctx); if (fd < 0) { ESP_LOGE(TAG, "open: no free file descriptors"); @@ -218,7 +278,7 @@ static int vfs_fat_open(void* ctx, const char * path, int flags, int mode) goto out; } out: - _lock_release(&s_fat_ctx->lock); + _lock_release(&fat_ctx->lock); return fd; } @@ -257,7 +317,7 @@ static ssize_t vfs_fat_read(void* ctx, int fd, void * dst, size_t size) static int vfs_fat_close(void* ctx, int fd) { vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; - _lock_acquire(&s_fat_ctx->lock); + _lock_acquire(&fat_ctx->lock); FIL* file = &fat_ctx->files[fd]; FRESULT res = f_close(file); file_cleanup(fat_ctx, fd); @@ -267,7 +327,7 @@ static int vfs_fat_close(void* ctx, int fd) errno = fresult_to_errno(res); rc = -1; } - _lock_release(&s_fat_ctx->lock); + _lock_release(&fat_ctx->lock); return rc; } @@ -308,6 +368,7 @@ static int vfs_fat_fstat(void* ctx, int fd, struct stat * st) static int vfs_fat_stat(void* ctx, const char * path, struct stat * st) { + vfs_fat_fix_path(ctx, path); FILINFO info; FRESULT res = f_stat(path, &info); if (res != FR_OK) { @@ -337,6 +398,7 @@ static int vfs_fat_stat(void* ctx, const char * path, struct stat * st) static int vfs_fat_unlink(void* ctx, const char *path) { + vfs_fat_fix_path(ctx, path); FRESULT res = f_unlink(path); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); @@ -348,6 +410,8 @@ static int vfs_fat_unlink(void* ctx, const char *path) static int vfs_fat_link(void* ctx, const char* n1, const char* n2) { + vfs_fat_fix_path(ctx, n1); + vfs_fat_fix_path(ctx, n2); const size_t copy_buf_size = 4096; void* buf = malloc(copy_buf_size); if (buf == NULL) { @@ -402,6 +466,8 @@ fail1: static int vfs_fat_rename(void* ctx, const char *src, const char *dst) { + vfs_fat_fix_path(ctx, src); + vfs_fat_fix_path(ctx, dst); FRESULT res = f_rename(src, dst); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); @@ -413,6 +479,7 @@ static int vfs_fat_rename(void* ctx, const char *src, const char *dst) static DIR* vfs_fat_opendir(void* ctx, const char* name) { + vfs_fat_fix_path(ctx, name); vfs_fat_dir_t* fat_dir = calloc(1, sizeof(vfs_fat_dir_t)); if (!fat_dir) { errno = ENOMEM; @@ -517,6 +584,7 @@ static void vfs_fat_seekdir(void* ctx, DIR* pdir, long offset) static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode) { (void) mode; + vfs_fat_fix_path(ctx, name); FRESULT res = f_mkdir(name); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); @@ -528,6 +596,7 @@ static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode) static int vfs_fat_rmdir(void* ctx, const char* name) { + vfs_fat_fix_path(ctx, name); FRESULT res = f_unlink(name); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); diff --git a/components/fatfs/src/vfs_fat_sdmmc.c b/components/fatfs/src/vfs_fat_sdmmc.c index e5956dd7b..f5e4c5099 100644 --- a/components/fatfs/src/vfs_fat_sdmmc.c +++ b/components/fatfs/src/vfs_fat_sdmmc.c @@ -22,6 +22,7 @@ static const char* TAG = "vfs_fat_sdmmc"; static sdmmc_card_t* s_card = NULL; +static uint8_t s_pdrv = 0; esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, const sdmmc_host_t* host_config, @@ -56,11 +57,18 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, } // connect SDMMC driver to FATFS - ff_diskio_register_sdmmc(0, s_card); + BYTE pdrv = ff_disk_getpdrv(); + if (pdrv == 0xFF) { + ESP_LOGD(TAG, "the maximum count of volumes is already mounted"); + goto fail; + } + ff_diskio_register_sdmmc(pdrv, s_card); + s_pdrv = pdrv; + char drv[3] = {(char)('0' + pdrv), ':', 0}; // connect FATFS to VFS FATFS* fs; - err = esp_vfs_fat_register(base_path, "", mount_config->max_files, &fs); + err = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs); if (err == ESP_ERR_INVALID_STATE) { // it's okay, already registered with VFS } else if (err != ESP_OK) { @@ -69,7 +77,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, } // Try to mount partition - FRESULT res = f_mount(fs, "", 1); + FRESULT res = f_mount(fs, drv, 1); if (res != FR_OK) { err = ESP_FAIL; ESP_LOGW(TAG, "failed to mount card (%d)", res); @@ -79,7 +87,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, ESP_LOGW(TAG, "partitioning card"); DWORD plist[] = {100, 0, 0, 0}; workbuf = malloc(workbuf_size); - res = f_fdisk(0, plist, workbuf); + res = f_fdisk(s_pdrv, plist, workbuf); if (res != FR_OK) { err = ESP_FAIL; ESP_LOGD(TAG, "f_fdisk failed (%d)", res); @@ -94,7 +102,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, } free(workbuf); ESP_LOGW(TAG, "mounting again"); - res = f_mount(fs, "", 0); + res = f_mount(fs, drv, 0); if (res != FR_OK) { err = ESP_FAIL; ESP_LOGD(TAG, "f_mount failed after formatting (%d)", res); @@ -105,7 +113,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path, fail: free(workbuf); - esp_vfs_unregister(base_path); + esp_vfs_fat_unregister_ctx(base_path); free(s_card); s_card = NULL; return err; @@ -117,7 +125,8 @@ esp_err_t esp_vfs_fat_sdmmc_unmount() return ESP_ERR_INVALID_STATE; } // unmount - f_mount(0, "", 0); + char drv[3] = {(char)('0' + s_pdrv), ':', 0}; + f_mount(0, drv, 0); // release SD driver free(s_card); s_card = NULL;