#include "storage.h" #include "esp_err.h" #include "esp_log.h" #include "esp_sntp.h" #include "esp_vfs_fat.h" #include "ff.h" #include #include static const char *TAG = "storage"; static const char *base_path = "/storage"; static wl_handle_t wl_handle = WL_INVALID_HANDLE; void fs_mount(void) { const esp_vfs_fat_mount_config_t mount_config = { .format_if_mount_failed = false, .max_files = 4, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false, .use_one_fat = false, }; ESP_LOGI(TAG, "Mounting FAT filesystem in read/write mode"); esp_err_t 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)); } } void fs_unmount(void) { if (wl_handle != WL_INVALID_HANDLE) { ESP_LOGI(TAG, "Unmounting FAT filesystem"); esp_err_t err = esp_vfs_fat_spiflash_unmount_rw_wl(base_path, wl_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to unmount FATFS (%s)", esp_err_to_name(err)); } else { ESP_LOGI(TAG, "FAT filesystem unmounted"); wl_handle = WL_INVALID_HANDLE; } } else { ESP_LOGW(TAG, "FAT filesystem is not mounted"); } } /** * Opens a file. * @param drv Pointer to the driver * @param path Path to the file * @param mode LV_FS_MODE_RD for reading, LV_FS_MODE_WR for writing * @return Pointer to a file object in case of success, otherwise NULL */ void *fs_open(lv_fs_drv_t *drv, const char *path, lv_fs_mode_t mode) { LV_UNUSED(drv); ESP_LOGI(TAG, "fs_open called for path: %s, mode: %d", path, mode); BYTE fatfs_mode; if (mode == LV_FS_MODE_WR) { fatfs_mode = FA_WRITE | FA_CREATE_ALWAYS; } else if (mode == LV_FS_MODE_RD) { fatfs_mode = FA_READ; } else { ESP_LOGE(TAG, "fs_open: Unknown mode: %d", mode); return NULL; } FIL *file_p = (FIL *)malloc(sizeof(FIL)); if (file_p == NULL) { ESP_LOGE(TAG, "fs_open: Failed to allocate memory for file object"); return NULL; } FRESULT res = f_open(file_p, path, fatfs_mode); if (res != FR_OK) { ESP_LOGE(TAG, "fs_open: f_open failed with error code: %d", res); free(file_p); return NULL; } ESP_LOGI(TAG, "fs_open: Successfully opened file: %s", path); return file_p; } /** * Closes an opened file. * @param drv Pointer to the driver * @param file_p Pointer to the file object * @return LV_FS_RES_OK on success, otherwise error code */ lv_fs_res_t fs_close(lv_fs_drv_t *drv, void *file_p) { LV_UNUSED(drv); ESP_LOGI(TAG, "fs_close called."); if (file_p == NULL) { ESP_LOGE(TAG, "fs_close: file pointer is NULL."); return LV_FS_RES_INV_PARAM; } f_close((FIL *)file_p); free(file_p); return LV_FS_RES_OK; } /** * Reads data from a file. * @param drv Pointer to the driver * @param file_p Pointer to the file object * @param buf Buffer to read the data into * @param btr Number of bytes to read (Bytes to Read) * @param br Pointer to store the number of bytes actually read * @return LV_FS_RES_OK on success, otherwise error code */ lv_fs_res_t fs_read(lv_fs_drv_t *drv, void *file_p, void *buf, uint32_t btr, uint32_t *br) { LV_UNUSED(drv); ESP_LOGI(TAG, "fs_read called, bytes to read: %" PRIu32, btr); FRESULT res = f_read((FIL *)file_p, buf, btr, (UINT *)br); if (res == FR_OK) { ESP_LOGI(TAG, "fs_read: Successfully read %" PRIu32 " bytes.", *br); return LV_FS_RES_OK; } else { ESP_LOGE(TAG, "fs_read: f_read failed with error code: %d", res); return LV_FS_RES_UNKNOWN; } } /** * Sets the read/write pointer in the file. * @param drv Pointer to the driver * @param file_p Pointer to the file object * @param pos Position to seek to * @param whence Starting point: LV_FS_SEEK_SET (beginning), LV_FS_SEEK_CUR (current), LV_FS_SEEK_END (end) * @return LV_FS_RES_OK on success, otherwise error code */ lv_fs_res_t fs_seek(lv_fs_drv_t *drv, void *file_p, uint32_t pos, lv_fs_whence_t whence) { LV_UNUSED(drv); ESP_LOGI(TAG, "fs_seek: pos=%" PRIu32 ", whence=%d", pos, whence); // Map LVGL whence to FatFS f_lseek (f_lseek always starts from the beginning) switch (whence) { case LV_FS_SEEK_SET: f_lseek((FIL *)file_p, pos); break; case LV_FS_SEEK_CUR: f_lseek((FIL *)file_p, f_tell((FIL *)file_p) + pos); break; case LV_FS_SEEK_END: { FSIZE_t fsize = f_size((FIL *)file_p); ESP_LOGI(TAG, "fs_seek to end, file size: %lu", (unsigned long)fsize); f_lseek((FIL *)file_p, fsize + pos); } break; default: break; } return LV_FS_RES_OK; } /** * Returns the current position of the read/write pointer. * @param drv Pointer to the driver * @param file_p Pointer to the file object * @param pos_p Pointer to store the current position * @return LV_FS_RES_OK on success, otherwise error code */ lv_fs_res_t fs_tell(lv_fs_drv_t *drv, void *file_p, uint32_t *pos_p) { LV_UNUSED(drv); ESP_LOGI(TAG, "fs_tell called."); *pos_p = f_tell((FIL *)file_p); ESP_LOGI(TAG, "fs_tell: Current position: %" PRIu32, *pos_p); return LV_FS_RES_OK; } /**************** */ void setup_fatfs() { const esp_vfs_fat_mount_config_t mount_config = { .format_if_mount_failed = false, .max_files = 4, .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, .disk_status_check_enable = false, .use_one_fat = false, }; 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); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); return; } FILE *f; ESP_LOGI(TAG, "Reading file"); const char *host_filename1 = "/storage/response.png"; 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; } fclose(f); ESP_LOGI(TAG, "Unmounting FAT filesystem"); ESP_ERROR_CHECK(esp_vfs_fat_spiflash_unmount_rw_wl(base_path, wl_handle)); ESP_LOGI(TAG, "Done"); }