Initial spiffs filesystem test

This commit is contained in:
fvanroie 2020-02-01 00:17:42 +01:00
parent 8915eb0b23
commit cf09094a02
8 changed files with 1423 additions and 0 deletions

21
lib/lv_fs_if/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Littlev Graphics Library
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

23
lib/lv_fs_if/README.md Normal file
View File

@ -0,0 +1,23 @@
# File System Interface
LittlevGL has a [File system](https://docs.littlevgl.com/en/html/overview/file-system.html) module to attach memories which can manipulate with files. Here you can find interfaces to
- FATFS
- PC (Linux and Windows)
file systems.
You still need to provide the drivers and libraries, this repo gives "only" the bridge between FATFS/PC/etc and LittlevGL.
## Usage
1. Add these lines to you `lv_conf.h`:
```c
/*File system interface*/
#define LV_USE_FS_IF 1
#if LV_USE_FS_IF
# define LV_FS_IF_FATFS '\0'
# define LV_FS_IF_PC '\0'
#endif /*LV_USE_FS_IF*/
```
2. Enable an interface you need by changing `'\0'` to letter you want to use for that drive. E.g. `'S'` for SD card with FATFS.
3. Call `lv_fs_if_init()` to register the enabled interfaces.

342
lib/lv_fs_if/lv_fs_fatfs.c Normal file
View File

@ -0,0 +1,342 @@
/**
* @file lv_fs_fatfs.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_fs_if.h"
#if LV_USE_FS_IF
#if LV_FS_IF_FATFS != '\0'
#include "ff.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/* Create a type to store the required data about your file.*/
typedef FIL file_t;
/*Similarly to `file_t` create a type for directory reading too */
typedef DIR dir_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void fs_init(void);
static lv_fs_res_t fs_open (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos);
static lv_fs_res_t fs_size (lv_fs_drv_t * drv, void * file_p, uint32_t * size_p);
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
static lv_fs_res_t fs_remove (lv_fs_drv_t * drv, const char *path);
static lv_fs_res_t fs_trunc (lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const char * newname);
static lv_fs_res_t fs_free (lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p);
static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * dir_p, const char *path);
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn);
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_fs_if_fatfs_init(void)
{
/*----------------------------------------------------
* Initialize your storage device and File System
* -------------------------------------------------*/
fs_init();
/*---------------------------------------------------
* Register the file system interface in LittlevGL
*--------------------------------------------------*/
/* Add a simple drive to open images */
lv_fs_drv_t fs_drv; /*A driver descriptor*/
lv_fs_drv_init(&fs_drv);
/*Set up fields...*/
fs_drv.file_size = sizeof(file_t);
fs_drv.letter = LV_FS_IF_FATFS;
fs_drv.open_cb = fs_open;
fs_drv.close_cb = fs_close;
fs_drv.read_cb = fs_read;
fs_drv.write_cb = fs_write;
fs_drv.seek_cb = fs_seek;
fs_drv.tell_cb = fs_tell;
fs_drv.free_space_cb = fs_free;
fs_drv.size_cb = fs_size;
fs_drv.remove_cb = fs_remove;
fs_drv.rename_cb = fs_rename;
fs_drv.trunc_cb = fs_trunc;
fs_drv.rddir_size = sizeof(dir_t);
fs_drv.dir_close_cb = fs_dir_close;
fs_drv.dir_open_cb = fs_dir_open;
fs_drv.dir_read_cb = fs_dir_read;
lv_fs_drv_register(&fs_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/* Initialize your Storage device and File system. */
static void fs_init(void)
{
/* Initialize the SD card and FatFS itself.
* Better to do it in your code to keep this library utouched for easy updating*/
}
/**
* Open a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_open (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode)
{
uint8_t flags = 0;
if(mode == LV_FS_MODE_WR) flags = FA_WRITE | FA_OPEN_ALWAYS;
else if(mode == LV_FS_MODE_RD) flags = FA_READ;
else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
FRESULT res = f_open(file_p, path, flags);
if(res == FR_OK) {
f_lseek(file_p, 0);
return LV_FS_RES_OK;
} else {
return LV_FS_RES_UNKNOWN;
}
}
/**
* Close an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p)
{
f_close(file_p);
return LV_FS_RES_OK;
}
/**
* Read data from an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param buf pointer to a memory block where to store the read data
* @param btr number of Bytes To Read
* @param br the real number of read bytes (Byte Read)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
FRESULT res = f_read(file_p, buf, btr, (UINT*)br);
if(res == FR_OK) return LV_FS_RES_OK;
else return LV_FS_RES_UNKNOWN;
}
/**
* Write into a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param buf pointer to a buffer with the bytes to write
* @param btr Bytes To Write
* @param br the number of real written bytes (Bytes Written). NULL if unused.
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
FRESULT res = f_write(file_p, buf, btw, (UINT*)bw);
if(res == FR_OK) return LV_FS_RES_OK;
else return LV_FS_RES_UNKNOWN;
}
/**
* Set the read write pointer. Also expand the file size if necessary.
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open )
* @param pos the new position of read write pointer
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos)
{
f_lseek(file_p, pos);
return LV_FS_RES_OK;
}
/**
* Give the size of a file bytes
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param size pointer to a variable to store the size
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_size (lv_fs_drv_t * drv, void * file_p, uint32_t * size_p)
{
(*size_p) = f_size(((file_t *)file_p));
return LV_FS_RES_OK;
}
/**
* Give the position of the read write pointer
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param pos_p pointer to to store the result
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
*pos_p = f_tell(((file_t *)file_p));
return LV_FS_RES_OK;
}
/**
* Delete a file
* @param drv pointer to a driver where this function belongs
* @param path path of the file to delete
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_remove (lv_fs_drv_t * drv, const char *path)
{
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
/* Add your code here*/
return res;
}
/**
* Truncate the file size to the current position of the read write pointer
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open )
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_trunc (lv_fs_drv_t * drv, void * file_p)
{
f_sync(file_p); /*If not syncronized fclose can write the truncated part*/
f_truncate(file_p);
return LV_FS_RES_OK;
}
/**
* Rename a file
* @param drv pointer to a driver where this function belongs
* @param oldname path to the file
* @param newname path with the new name
* @return LV_FS_RES_OK or any error from 'fs_res_t'
*/
static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const char * newname)
{
FRESULT res = f_rename(oldname, newname);
if(res == FR_OK) return LV_FS_RES_OK;
else return LV_FS_RES_UNKNOWN;
}
/**
* Get the free and total size of a driver in kB
* @param drv pointer to a driver where this function belongs
* @param letter the driver letter
* @param total_p pointer to store the total size [kB]
* @param free_p pointer to store the free size [kB]
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_free (lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p)
{
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
/* Add your code here*/
return res;
}
/**
* Initialize a 'fs_read_dir_t' variable for directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to a 'fs_read_dir_t' variable
* @param path path to a directory
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * dir_p, const char *path)
{
FRESULT res = f_opendir(dir_p, path);
if(res == FR_OK) return LV_FS_RES_OK;
else return LV_FS_RES_UNKNOWN;
}
/**
* Read the next filename form a directory.
* The name of the directories will begin with '/'
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @param fn pointer to a buffer to store the filename
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn)
{
FRESULT res;
FILINFO fno;
fn[0] = '\0';
do {
res = f_readdir(dir_p, &fno);
if(res != FR_OK) return LV_FS_RES_UNKNOWN;
if(fno.fattrib & AM_DIR) {
fn[0] = '/';
strcpy(&fn[1], fno.fname);
}
else strcpy(fn, fno.fname);
} while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0);
return LV_FS_RES_OK;
}
/**
* Close the directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p)
{
f_closedir(dir_p);
return LV_FS_RES_OK;
}
#endif /*LV_USE_FS_IF*/
#endif /*LV_FS_IF_FATFS*/

70
lib/lv_fs_if/lv_fs_if.c Normal file
View File

@ -0,0 +1,70 @@
/**
* @file lv_fs_if.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_fs_if.h"
#if LV_USE_FS_IF
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
#if LV_FS_IF_FATFS != '\0'
void lv_fs_if_fatfs_init(void);
#endif
#if LV_FS_IF_PC != '\0'
void lv_fs_if_pc_init(void);
#endif
#if LV_FS_IF_SPIFFS != '\0'
#include "lv_fs_spiffs.h"
#endif
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Register driver(s) for the File system interface
*/
void lv_fs_if_init(void)
{
#if LV_FS_IF_FATFS != '\0'
lv_fs_if_fatfs_init();
#endif
#if LV_FS_IF_PC != '\0'
lv_fs_if_pc_init();
#endif
#if LV_FS_IF_SPIFFS != '\0'
lv_fs_if_spiffs_init();
#endif
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif

47
lib/lv_fs_if/lv_fs_if.h Normal file
View File

@ -0,0 +1,47 @@
/**
* @file lv_fs_if.h
*
*/
#ifndef LV_FS_IF_H
#define LV_FS_IF_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lvgl.h"
#if LV_USE_FS_IF
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Register driver(s) for the File system interface
*/
void lv_fs_if_init(void);
/**********************
* MACROS
**********************/
#endif /*LV_USE_FS_IF*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_FS_IF_H*/

472
lib/lv_fs_if/lv_fs_pc.c Normal file
View File

@ -0,0 +1,472 @@
/**
* @file lv_fs_pc.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_fs_if.h"
#if LV_USE_FS_IF
#if LV_FS_IF_PC != '\0'
#include <stdio.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#ifdef WIN32
#include <windows.h>
#endif
/*********************
* DEFINES
*********************/
#ifndef LV_FS_PC_PATH
# ifndef WIN32
# define LV_FS_PC_PATH "./" /*Projet root*/
# else
# define LV_FS_PC_PATH ".\\" /*Projet root*/
# endif
#endif /*LV_FS_PATH*/
/**********************
* TYPEDEFS
**********************/
/* Create a type to store the required data about your file. */
typedef FILE * file_t;
/*Similarly to `file_t` create a type for directory reading too */
#ifndef WIN32
typedef DIR * dir_t;
#else
typedef HANDLE dir_t;
#endif
/**********************
* STATIC PROTOTYPES
**********************/
static lv_fs_res_t fs_open (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos);
static lv_fs_res_t fs_size (lv_fs_drv_t * drv, void * file_p, uint32_t * size_p);
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
static lv_fs_res_t fs_remove (lv_fs_drv_t * drv, const char *path);
static lv_fs_res_t fs_trunc (lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const char * newname);
static lv_fs_res_t fs_free (lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p);
static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * dir_p, const char *path);
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn);
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Register a driver for the File system interface
*/
void lv_fs_if_pc_init(void)
{
/*---------------------------------------------------
* Register the file system interface in LittlevGL
*--------------------------------------------------*/
/* Add a simple drive to open images */
lv_fs_drv_t fs_drv; /*A driver descriptor*/
lv_fs_drv_init(&fs_drv);
/*Set up fields...*/
fs_drv.file_size = sizeof(file_t);
fs_drv.letter = LV_FS_IF_PC;
fs_drv.open_cb = fs_open;
fs_drv.close_cb = fs_close;
fs_drv.read_cb = fs_read;
fs_drv.write_cb = fs_write;
fs_drv.seek_cb = fs_seek;
fs_drv.tell_cb = fs_tell;
fs_drv.free_space_cb = fs_free;
fs_drv.size_cb = fs_size;
fs_drv.remove_cb = fs_remove;
fs_drv.rename_cb = fs_rename;
fs_drv.trunc_cb = fs_trunc;
fs_drv.rddir_size = sizeof(dir_t);
fs_drv.dir_close_cb = fs_dir_close;
fs_drv.dir_open_cb = fs_dir_open;
fs_drv.dir_read_cb = fs_dir_read;
lv_fs_drv_register(&fs_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Open a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_open (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode)
{
(void) drv; /*Unused*/
errno = 0;
const char * flags = "";
if(mode == LV_FS_MODE_WR) flags = "wb";
else if(mode == LV_FS_MODE_RD) flags = "rb";
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)*/
#ifndef WIN32
char buf[256];
sprintf(buf, LV_FS_PC_PATH "/%s", path);
#else
char buf[256];
sprintf(buf, LV_FS_PC_PATH "\\%s", path);
#endif
file_t f = fopen(buf, flags);
if(f == NULL) return LV_FS_RES_UNKNOWN;
/*Be sure we are the beginning of the file*/
fseek(f, 0, SEEK_SET);
/* '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;
return LV_FS_RES_OK;
}
/**
* Close an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_close (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;
}
/**
* Read data from an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param buf pointer to a memory block where to store the read data
* @param btr number of Bytes To Read
* @param br the real number of read bytes (Byte Read)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
(void) drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/
*br = fread(buf, 1, btr, *fp);
return LV_FS_RES_OK;
}
/**
* Write into a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param buf pointer to a buffer with the bytes to write
* @param btr Bytes To Write
* @param br the number of real written bytes (Bytes Written). NULL if unused.
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
(void) drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/
*bw = fwrite(buf, 1, btw, *fp);
return LV_FS_RES_OK;
}
/**
* Set the read write pointer. Also expand the file size if necessary.
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open )
* @param pos the new position of read write pointer
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_seek (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;
}
/**
* Give the size of a file bytes
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param size pointer to a variable to store the size
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_size (lv_fs_drv_t * drv, void * file_p, uint32_t * size_p)
{
(void) drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/
uint32_t cur = ftell(*fp);
fseek(*fp, 0L, SEEK_END);
*size_p = ftell(*fp);
/*Restore file pointer*/
fseek(*fp, cur, SEEK_SET);
return LV_FS_RES_OK;
}
/**
* Give the position of the read write pointer
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param pos_p pointer to to store the result
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_tell (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;
}
/**
* Delete a file
* @param drv pointer to a driver where this function belongs
* @param path path of the file to delete
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_remove (lv_fs_drv_t * drv, const char *path)
{
(void) drv; /*Unused*/
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
/* Add your code here*/
return res;
}
/**
* Truncate the file size to the current position of the read write pointer
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open )
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_trunc (lv_fs_drv_t * drv, void * file_p)
{
(void) drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/
fflush(*fp); /*If not syncronized fclose can write the truncated part*/
uint32_t p = ftell(*fp);
ftruncate(fileno(*fp), p);
return LV_FS_RES_OK;
}
/**
* Rename a file
* @param drv pointer to a driver where this function belongs
* @param oldname path to the file
* @param newname path with the new name
* @return LV_FS_RES_OK or any error from 'fs_res_t'
*/
static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const char * newname)
{
(void) drv; /*Unused*/
static char new[512];
static char old[512];
sprintf(old, LV_FS_PC_PATH "/%s", oldname);
sprintf(new, LV_FS_PC_PATH "/%s", newname);
int r = rename(old, new);
if(r == 0) return LV_FS_RES_OK;
else return LV_FS_RES_UNKNOWN;
}
/**
* Get the free and total size of a driver in kB
* @param drv pointer to a driver where this function belongs
* @param letter the driver letter
* @param total_p pointer to store the total size [kB]
* @param free_p pointer to store the free size [kB]
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_free (lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p)
{
(void) drv; /*Unused*/
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
/* Add your code here*/
return res;
}
#ifdef WIN32
static char next_fn[256];
#endif
/**
* Initialize a 'fs_read_dir_t' variable for directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to a 'fs_read_dir_t' variable
* @param path path to a directory
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * dir_p, const char *path)
{
(void) drv; /*Unused*/
dir_t d;
#ifndef WIN32
/*Make the path relative to the current directory (the projects root folder)*/
char buf[256];
sprintf(buf, LV_FS_PC_PATH "/%s", path);
if ((d = opendir(buf)) == NULL) {
return LV_FS_RES_FS_ERR;
} else {
/* 'dir_p' is pointer to a file descriptor and
* we need to store our file descriptor here*/
dir_t * dp = dir_p; /*Just avoid the confusing casings*/
*dp = d;
}
#else
d = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA fdata;
/*Make the path relative to the current directory (the projects root folder)*/
char buf[256];
sprintf(buf, LV_FS_PC_PATH "\\%s\\*", path);
strcpy(next_fn, "");
d = FindFirstFile(buf, &fdata);
do {
if (strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0) {
continue;
} else {
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
sprintf(next_fn, "/%s", fdata.cFileName);
} else {
sprintf(next_fn, "%s", fdata.cFileName);
}
break;
}
} while(FindNextFileA(d, &fdata));
dir_t * dp = dir_p; /*Just avoid the confusing casings*/
*dp = d;
#endif
return LV_FS_RES_OK;
}
/**
* Read the next filename form a directory.
* The name of the directories will begin with '/'
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @param fn pointer to a buffer to store the filename
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn)
{
(void) drv; /*Unused*/
dir_t * dp = dir_p; /*Just avoid the confusing casings*/
#ifndef WIN32
struct dirent *entry;
do {
entry = readdir(*dp);
if(entry) {
if(entry->d_type == DT_DIR) sprintf(fn, "/%s", entry->d_name);
else strcpy(fn, entry->d_name);
} else {
strcpy(fn, "");
}
} while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0);
#else
strcpy(fn, next_fn);
strcpy(next_fn, "");
WIN32_FIND_DATA fdata;
if(FindNextFile(*dp, &fdata) == false) return LV_FS_RES_OK;
do {
if (strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0) {
continue;
} else {
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
sprintf(next_fn, "/%s", fdata.cFileName);
} else {
sprintf(next_fn, "%s", fdata.cFileName);
}
break;
}
} while(FindNextFile(*dp, &fdata));
#endif
return LV_FS_RES_OK;
}
/**
* Close the directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p)
{
(void) drv; /*Unused*/
dir_t * dp = dir_p;
#ifndef WIN32
closedir(*dp);
#else
FindClose(*dp);
*dp = INVALID_HANDLE_VALUE;
#endif
return LV_FS_RES_OK;
}
#endif /*LV_USE_FS_IF*/
#endif /*LV_FS_IF_FATFS*/

View File

@ -0,0 +1,429 @@
/**
* @file lv_fs_spiffs.c
*
*/
/*********************
* INCLUDES
*********************/
//#include <Arduino.h>
#include "lv_fs_if.h"
#include "lv_fs_spiffs.h"
#if LV_USE_FS_IF
#if LV_FS_IF_SPIFFS != '\0'
#if defined(ARDUINO_ARCH_ESP32)
#include "SPIFFS.h"
#endif
#include "FS.h" // Include the SPIFFS library
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/* Create a type to store the required data about your file.*/
typedef File lv_spiffs_file_t;
/*Similarly to `file_t` create a type for directory reading too */
typedef File lv_spiffs_dir_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void fs_init(void);
static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos);
static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p);
static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path);
static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * newname);
static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p);
static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * path);
static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn);
static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_fs_if_spiffs_init(void)
{
/*----------------------------------------------------
* Initialize your storage device and File System
* -------------------------------------------------*/
fs_init();
/*---------------------------------------------------
* Register the file system interface in LittlevGL
*--------------------------------------------------*/
/* Add a simple drive to open images */
lv_fs_drv_t fs_drv; /*A driver descriptor*/
lv_fs_drv_init(&fs_drv);
/*Set up fields...*/
fs_drv.file_size = sizeof(lv_spiffs_file_t);
fs_drv.letter = LV_FS_IF_SPIFFS;
fs_drv.open_cb = fs_open;
fs_drv.close_cb = fs_close;
fs_drv.read_cb = fs_read;
fs_drv.write_cb = fs_write;
fs_drv.seek_cb = fs_seek;
fs_drv.tell_cb = fs_tell;
fs_drv.free_space_cb = fs_free;
fs_drv.size_cb = fs_size;
fs_drv.remove_cb = fs_remove;
fs_drv.rename_cb = fs_rename;
fs_drv.trunc_cb = fs_trunc;
fs_drv.rddir_size = sizeof(lv_spiffs_dir_t);
fs_drv.dir_close_cb = fs_dir_close;
fs_drv.dir_open_cb = fs_dir_open;
fs_drv.dir_read_cb = fs_dir_read;
lv_fs_drv_register(&fs_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/* Initialize your Storage device and File system. */
static void fs_init(void)
{
SPIFFS.begin();
}
/**
* Open a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode)
{
Serial.print("Opening: ");
Serial.println(path);
String fullpath = "/" + String(path);
Serial.println(fullpath);
const char * fullfilename = fullpath.c_str();
Serial.println(fullfilename);
Serial.flush();
if(!SPIFFS.exists(fullfilename)) {
Serial.println("File does not exist");
return LV_FS_RES_NOT_EX;
}
// return LV_FS_RES_UNKNOWN;
static lv_spiffs_file_t file;
if(mode == LV_FS_MODE_WR)
file = SPIFFS.open(fullfilename, "a");
else if(mode == LV_FS_MODE_RD)
file = SPIFFS.open(fullfilename, "r");
else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD))
file = SPIFFS.open(fullfilename, "r+");
if(file) {
lv_spiffs_file_t * fp = (lv_spiffs_file_t *)file_p; /*Just avoid the confusing casings*/
*fp = file;
Serial.println("Opened OK");
Serial.flush();
// return LV_FS_RES_UNKNOWN;
return LV_FS_RES_OK;
} else {
Serial.println("Open failed");
return LV_FS_RES_UNKNOWN;
}
}
/**
* Close an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p)
{
// File file = *(File *)(file_p);
lv_spiffs_file_t * file = (lv_spiffs_file_t *)file_p; /*Convert type*/
char * msg;
sprintf(msg, "Closing: %s", file->name());
Serial.println(msg);
Serial.flush();
file->close();
return LV_FS_RES_OK;
}
/**
* Read data from an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param buf pointer to a memory block where to store the read data
* @param btr number of Bytes To Read
* @param br the real number of read bytes (Byte Read)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
lv_spiffs_file_t * file = (lv_spiffs_file_t *)file_p; /*Convert type*/
// lv_spiffs_file_t file = *(lv_spiffs_file_t *)(file_p);
char * msg;
sprintf(msg, "Reading: %s", file->name());
Serial.println(msg);
Serial.flush();
if(!*file || file->isDirectory()) {
return LV_FS_RES_UNKNOWN;
}
return LV_FS_RES_UNKNOWN;
*br = file->readBytes((char *)buf, btr);
return LV_FS_RES_OK;
}
/**
* Write into a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param buf pointer to a buffer with the bytes to write
* @param btr Bytes To Write
* @param br the number of real written bytes (Bytes Written). NULL if unused.
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
return LV_FS_RES_NOT_IMP;
/*
File file = SPIFFS.open((char *)file_p, "w");
if(!file) {
return LV_FS_RES_UNKNOWN;
}
char * message;
strncpy(buf, message, btw);
if(file.print(message)) {
*bw = (uint32_t)sizeof(message);
return LV_FS_RES_OK;
} else {
bw = 0;
return LV_FS_RES_UNKNOWN;
}*/
}
/**
* Set the read write pointer. Also expand the file size if necessary.
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open )
* @param pos the new position of read write pointer
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos)
{
lv_spiffs_file_t * file = (lv_spiffs_file_t *)file_p; /*Convert type*/
// lv_spiffs_file_t file = *(lv_spiffs_file_t *)(file_p);
char * msg;
sprintf(msg, "Seeking: %s", file->name());
Serial.println(msg);
Serial.flush();
if(file->seek(pos, SeekSet)) {
return LV_FS_RES_OK;
} else {
return LV_FS_RES_UNKNOWN;
}
}
/**
* Give the size of a file bytes
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param size pointer to a variable to store the size
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p)
{
lv_spiffs_file_t * file = (lv_spiffs_file_t *)file_p; /*Convert type*/
// lv_spiffs_file_t file = *(lv_spiffs_file_t *)(file_p);
char * msg;
sprintf(msg, "Filesize: %s", file->name());
Serial.println(msg);
Serial.flush();
*size_p = file->size();
return LV_FS_RES_OK;
}
/**
* Give the position of the read write pointer
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param pos_p pointer to to store the result
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
lv_spiffs_file_t * file = (lv_spiffs_file_t *)file_p; /*Convert type*/
// lv_spiffs_file_t file = *(lv_spiffs_file_t *)(file_p);
char * msg;
sprintf(msg, "Telling: %s", file->name());
Serial.println(msg);
Serial.flush();
uint32_t pos = file->position();
pos_p = &pos;
return LV_FS_RES_OK;
}
/**
* Delete a file
* @param drv pointer to a driver where this function belongs
* @param path path of the file to delete
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path)
{
Serial.println("Deleteing: " + (String)path);
Serial.flush();
if(SPIFFS.remove(path)) {
return LV_FS_RES_OK;
} else {
return LV_FS_RES_UNKNOWN;
}
}
/**
* Truncate the file size to the current position of the read write pointer
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open )
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p)
{
return LV_FS_RES_NOT_IMP;
}
/**
* Rename a file
* @param drv pointer to a driver where this function belongs
* @param oldname path to the file
* @param newname path with the new name
* @return LV_FS_RES_OK or any error from 'fs_res_t'
*/
static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * newname)
{
if(SPIFFS.rename(oldname, newname)) {
return LV_FS_RES_OK;
} else {
return LV_FS_RES_UNKNOWN;
}
}
/**
* Get the free and total size of a driver in kB
* @param drv pointer to a driver where this function belongs
* @param letter the driver letter
* @param total_p pointer to store the total size [kB]
* @param free_p pointer to store the free size [kB]
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p)
{
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
/* Add your code here*/
return res;
}
/**
* Initialize a 'fs_read_dir_t' variable for directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to a 'fs_read_dir_t' variable
* @param path path to a directory
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * path)
{
lv_spiffs_dir_t * dir = (lv_spiffs_file_t *)dir_p; /*Convert type*/
Serial.print("Open directory: ");
Serial.println(path);
Serial.flush();
*dir = SPIFFS.open(path, "r");
if(*dir) {
dir_p = &dir;
return LV_FS_RES_OK;
} else {
return LV_FS_RES_UNKNOWN;
}
}
/**
* Read the next filename form a directory.
* The name of the directories will begin with '/'
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @param fn pointer to a buffer to store the filename
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn)
{
lv_spiffs_dir_t * dir = (lv_spiffs_file_t *)dir_p; /*Convert type*/
lv_spiffs_file_t file = dir->openNextFile();
if(file) {
strcpy(fn, file.name());
return LV_FS_RES_OK;
} else {
return LV_FS_RES_UNKNOWN;
}
}
/**
* Close the directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p)
{
return LV_FS_RES_OK;
}
#endif /*LV_USE_FS_IF*/
#endif /*LV_FS_IF_SPIFFS*/

View File

@ -0,0 +1,19 @@
/**
* @file lv_fs_if.h
*
*/
#ifndef LV_FS_IF_SPIFFS_H
#define LV_FS_IF_SPIFFS_H
#ifdef __cplusplus
extern "C" {
#endif
void lv_fs_if_spiffs_init(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif