Filesystem SPIFFS - end of file after open

Description

Im trying to implement Littlev Filesystem with SPIFFS from the esp-idf. I copied the functions from the WIN32 Implementation lv_fs_pc.c and changed some small things, but basically its the same.

What MCU/Processor/Board and compiler are you using?

ESP32
xtensa-esp32-elf-gcc

What do you experience?

I’m trying to draw an image which is flashed in a spiffs image. But after “spiffs_driver_open” is called in “spiffs_driver_read” the file can’t be read, because it’s already at end of file.

What do you expect?

Normally read the file.

Code to reproduce

This is my spiffs implementation.

#include "esp_spi_flash.h"
#include "esp_log.h"
#include "esp_spiffs.h"
#include "lvgl/lvgl.h"
#include "lv_fs.h"

#include "spiffs_driver.h"

/* Create a type to store the required data about your file. */
typedef  FILE * file_t;

static const char *TAG = "SPIFFS-DRIVER";

static lv_fs_res_t spiffs_driver_open(struct _lv_fs_drv_t *drv, void *file_p, const char *path, lv_fs_mode_t mode)
{
    (void) drv;		/*Unused*/

	const char * flags = "";

	if(mode == LV_FS_MODE_WR) flags = "w";
	else if(mode == LV_FS_MODE_RD) flags = "r";
	else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = "rb+";

	/*Make the path relative to the current directory (the projects root folder)*/

    char complete_path[strlen(path) + 1];
    complete_path[0] = '/';
    complete_path[1] = '\0';
    strcat(complete_path, path);

	file_t f = fopen(complete_path, flags);
	if(f == NULL) return LV_FS_RES_UNKNOWN;

	/*Be sure we are the beginning of the file*/
	fseek(f, 0, SEEK_SET);
    ESP_LOGI(TAG, "Open eof f %d", feof(f));

	/* 'file_p' is pointer to a file descriptor and
	 * we need to store our file descriptor here*/
	file_t * fp = file_p;        /*Just avoid the confusing casings*/
	*fp = f;
    ESP_LOGI(TAG, "Open eof file_p %d", feof(file_p));
	return LV_FS_RES_OK;
}

static lv_fs_res_t spiffs_driver_read(struct _lv_fs_drv_t *drv, void *file_p, void *buf, uint32_t btr, uint32_t *br)
{
    ESP_LOGI(TAG, "Read eof %d", feof(file_p));
    (void) drv;		/*Unused*/
	file_t * fp = file_p;        /*Just avoid the confusing casings*/
	*br = fread(buf, 1, btr, *fp);
	return LV_FS_RES_OK;
}

static lv_fs_res_t spiffs_driver_close(struct _lv_fs_drv_t *drv, void *file_p)
{
    (void) drv;		/*Unused*/
	file_t * fp = file_p;        /*Just avoid the confusing casings*/
	fclose(*fp);
	return LV_FS_RES_OK;
}

static lv_fs_res_t spiffs_driver_seek(struct _lv_fs_drv_t *drv, void *file_p, uint32_t pos)
{
    (void) drv;		/*Unused*/
	file_t * fp = file_p;        /*Just avoid the confusing casings*/
	fseek(*fp, pos, SEEK_SET);
	return LV_FS_RES_OK;
}

static lv_fs_res_t spiffs_driver_tell(struct _lv_fs_drv_t *drv, void *file_p, uint32_t *pos_p)
{
    (void) drv;		/*Unused*/
	file_t * fp = file_p;        /*Just avoid the confusing casings*/
	*pos_p = ftell(*fp);
	return LV_FS_RES_OK;
}

esp_err_t spiffs_driver_init()
{
    esp_vfs_spiffs_conf_t conf = {
        .base_path = SPIFFS_BASE,
        .partition_label = "spiffs",
        .max_files = 20,
        .format_if_mount_failed = false};

    esp_err_t ret = esp_vfs_spiffs_register(&conf);

    if (ret != ESP_OK)
    {
        if (ret == ESP_FAIL)
        {
            ESP_LOGE(TAG, "Failed to mount or format filesystem");
        }
        else if (ret == ESP_ERR_NOT_FOUND)
        {
            ESP_LOGE(TAG, "Failed to find SPIFFS partition");
        }
        else
        {
            ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
        }
        return ESP_FAIL;
    }

    size_t total = 0, used = 0;
    ret = esp_spiffs_info(conf.partition_label, &total, &used);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
    }
    else
    {
        ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
    }

    lv_fs_drv_t drv;
    lv_fs_drv_init(&drv);

    drv.letter = 'F';
    drv.file_size = sizeof(FILE);
    drv.rddir_size = 0; //TODO: maybe not zero
    drv.open_cb = spiffs_driver_open;
    drv.read_cb = spiffs_driver_read;
    drv.close_cb = spiffs_driver_close;
    drv.seek_cb = spiffs_driver_seek;
    drv.tell_cb = spiffs_driver_tell;
    drv.ready_cb = NULL;
    drv.trunc_cb = NULL;
    drv.size_cb = NULL;
    drv.rename_cb = NULL;
    drv.write_cb = NULL;

    drv.dir_open_cb = NULL;
    drv.dir_read_cb = NULL;
    drv.dir_close_cb = NULL;
    drv.free_space_cb = NULL;


    lv_fs_drv_register(&drv);

    lv_obj_t* img_obj = lv_img_create(lv_scr_act(), NULL);
    lv_img_set_src(img_obj, "F:spiffs/01_shop_device_welcome.jpg");

    return ESP_OK;
}

To conform that the spiffs image is working i just read the file without Littlev and it’s working.

FILE* f = fopen("/spiffs/01_shop_device_welcome.jpg", "r");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for reading");
        return;
    }

    fseek (f , 0 , SEEK_END);
    long lSize = ftell (f);
    rewind (f);
    ESP_LOGI(TAG, "Lsize %ld", lSize);
    void* buf = (char*) malloc (sizeof(char)*lSize);
    int br = fread(buf, 1, lSize, f);
    ESP_LOGI(TAG, "Bytes read %d", br);

Screenshot and/or video

Here a screenshot from the monitor. I put some foef between to show the problem.

I’m not 100% sure but

    ESP_LOGI(TAG, "Open eof file_p %d", feof(file_p));

should be

    ESP_LOGI(TAG, "Open eof file_p %d", feof(*fp));

I found the problem my self. The problem was at the template definition:

drv.file_size = sizeof(FILE);

should be

drv.file_size = sizeof(file_t);

But thank you for your help.

1 Like

It seems it’s already fixed: https://github.com/littlevgl/lvgl/blob/master/porting/lv_port_fs_template.c#L92

Or was it an issue only in your implementation?

No it was only an issue in my implementation. I just used the port you linked as sample.