1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-14 06:42:58 +08:00
lvgl/lv_misc/lv_fs.c

543 lines
13 KiB
C
Raw Normal View History

2017-11-23 20:42:14 +01:00
/**
2017-11-26 11:38:28 +01:00
* @file lv_fs.c
2017-11-23 20:42:14 +01:00
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_fs.h"
#if USE_LV_FILESYSTEM
2017-11-23 20:42:14 +01:00
#include "lv_ll.h"
#include <string.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
2017-11-24 17:48:47 +01:00
static const char * lv_fs_get_real_path(const char * path);
static lv_fs_drv_t* lv_fs_get_drv(char letter);
2017-11-23 20:42:14 +01:00
/**********************
* STATIC VARIABLES
**********************/
2017-11-24 17:48:47 +01:00
static lv_ll_t drv_ll;
2017-11-23 20:42:14 +01:00
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the File system interface
*/
2017-11-24 17:48:47 +01:00
void lv_fs_init(void)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
lv_ll_init(&drv_ll, sizeof(lv_fs_drv_t));
2017-11-23 20:42:14 +01:00
}
/**
* Open a file
2017-11-24 17:48:47 +01:00
* @param file_p pointer to a lv_fs_file_t variable
2017-11-23 20:42:14 +01:00
* @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
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
lv_fs_res_t lv_fs_open (lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode)
2017-11-23 20:42:14 +01:00
{
file_p->drv = NULL;
file_p->file_d = NULL;
2017-12-03 22:32:09 +01:00
if(path == NULL) return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
char letter = path[0];
2017-11-24 17:48:47 +01:00
file_p->drv = lv_fs_get_drv(letter);
2017-11-23 20:42:14 +01:00
if(file_p->drv == NULL) {
file_p->file_d = NULL;
2017-12-03 22:32:09 +01:00
return LV_FS_RES_NOT_EX;
2017-11-23 20:42:14 +01:00
}
if(file_p->drv->ready != NULL) {
if(file_p->drv->ready() == false) {
file_p->drv = NULL;
file_p->file_d = NULL;
2017-12-03 22:32:09 +01:00
return LV_FS_RES_HW_ERR;
2017-11-23 20:42:14 +01:00
}
}
2017-11-23 21:28:36 +01:00
file_p->file_d = lv_mem_alloc(file_p->drv->file_size);
2017-11-23 20:42:14 +01:00
if(file_p->file_d == NULL) {
file_p->drv = NULL;
2017-12-03 22:32:09 +01:00
return LV_FS_RES_OUT_OF_MEM; /* Out of memory */
2017-11-23 20:42:14 +01:00
}
if(file_p->drv->open == NULL) {
2017-12-03 22:32:09 +01:00
return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
}
2017-11-24 17:48:47 +01:00
const char * real_path = lv_fs_get_real_path(path);
lv_fs_res_t res = file_p->drv->open(file_p->file_d, real_path, mode);
2017-11-23 20:42:14 +01:00
2017-12-03 22:32:09 +01:00
if(res != LV_FS_RES_OK) {
file_p->drv = NULL;
}
2017-11-23 20:42:14 +01:00
return res;
}
/**
* Close an already opened file
2017-11-24 17:48:47 +01:00
* @param file_p pointer to a lv_fs_file_t variable
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
lv_fs_res_t lv_fs_close (lv_fs_file_t * file_p)
2017-11-23 20:42:14 +01:00
{
if(file_p->drv == NULL) {
2017-12-03 22:32:09 +01:00
return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
}
if(file_p->drv->close == NULL) {
2017-12-03 22:32:09 +01:00
return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
}
2017-11-24 17:48:47 +01:00
lv_fs_res_t res = file_p->drv->close(file_p->file_d);
2017-11-23 20:42:14 +01:00
2017-11-23 21:28:36 +01:00
lv_mem_free(file_p->file_d); /*Clean up*/
2017-11-23 20:42:14 +01:00
file_p->file_d = NULL;
file_p->drv = NULL;
file_p->file_d = NULL;
return res;
}
/**
* Delete a file
* @param path path of the file to delete
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
lv_fs_res_t lv_fs_remove (const char * path)
2017-11-23 20:42:14 +01:00
{
2017-12-03 22:32:09 +01:00
if(path == NULL) return LV_FS_RES_INV_PARAM;
2017-11-24 17:48:47 +01:00
lv_fs_drv_t * drv = NULL;
2017-11-23 20:42:14 +01:00
char letter = path[0];
2017-11-24 17:48:47 +01:00
drv = lv_fs_get_drv(letter);
2017-12-03 22:32:09 +01:00
if(drv == NULL) return LV_FS_RES_NOT_EX;
2017-11-23 20:42:14 +01:00
if(drv->ready != NULL) {
2017-12-03 22:32:09 +01:00
if(drv->ready() == false) return LV_FS_RES_HW_ERR;
2017-11-23 20:42:14 +01:00
}
2017-12-03 22:32:09 +01:00
if(drv->remove == NULL) return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
2017-11-24 17:48:47 +01:00
const char * real_path = lv_fs_get_real_path(path);
lv_fs_res_t res = drv->remove(real_path);
2017-11-23 20:42:14 +01:00
return res;
}
/**
* Read from a file
2017-11-24 17:48:47 +01:00
* @param file_p pointer to a lv_fs_file_t variable
2017-11-23 20:42:14 +01:00
* @param buf pointer to a buffer where the read bytes are stored
* @param btr Bytes To Read
* @param br the number of real read bytes (Bytes Read). NULL if unused.
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
lv_fs_res_t lv_fs_read (lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br)
2017-11-23 20:42:14 +01:00
{
if(br != NULL) *br = 0;
2017-12-03 22:32:09 +01:00
if(file_p->drv == NULL || file_p->drv == NULL) return LV_FS_RES_INV_PARAM;
if(file_p->drv->read == NULL) return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
uint32_t br_tmp = 0;
2017-11-24 17:48:47 +01:00
lv_fs_res_t res = file_p->drv->read(file_p->file_d, buf, btr, &br_tmp);
2017-11-23 20:42:14 +01:00
if(br != NULL) *br = br_tmp;
return res;
}
/**
* Write into a file
2017-11-24 17:48:47 +01:00
* @param file_p pointer to a lv_fs_file_t variable
2017-11-23 20:42:14 +01:00
* @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.
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
lv_fs_res_t lv_fs_write (lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw)
2017-11-23 20:42:14 +01:00
{
if(bw != NULL) *bw = 0;
if(file_p->drv == NULL || file_p->drv == NULL) {
2017-12-03 22:32:09 +01:00
return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
}
if(file_p->drv->write == NULL) {
2017-12-03 22:32:09 +01:00
return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
}
uint32_t bw_tmp = 0;
2017-11-24 17:48:47 +01:00
lv_fs_res_t res = file_p->drv->write(file_p->file_d, buf, btw, &bw_tmp);
2017-11-23 20:42:14 +01:00
if(bw != NULL) *bw = bw_tmp;
return res;
}
/**
* Set the position of the 'cursor' (read write pointer) in a file
2017-11-24 17:48:47 +01:00
* @param file_p pointer to a lv_fs_file_t variable
2017-11-23 20:42:14 +01:00
* @param pos the new position expressed in bytes index (0: start of file)
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
lv_fs_res_t lv_fs_seek (lv_fs_file_t * file_p, uint32_t pos)
2017-11-23 20:42:14 +01:00
{
if(file_p->drv == NULL || file_p->drv == NULL) {
2017-12-03 22:32:09 +01:00
return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
}
if(file_p->drv->seek == NULL) {
2017-12-03 22:32:09 +01:00
return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
}
2017-11-24 17:48:47 +01:00
lv_fs_res_t res = file_p->drv->seek(file_p->file_d, pos);
2017-11-23 20:42:14 +01:00
return res;
}
/**
* Give the position of the read write pointer
2017-11-24 17:48:47 +01:00
* @param file_p pointer to a lv_fs_file_t variable
2017-11-23 20:42:14 +01:00
* @param pos_p pointer to store the position of the read write pointer
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from 'fs_res_t'
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
lv_fs_res_t lv_fs_tell (lv_fs_file_t * file_p, uint32_t * pos)
2017-11-23 20:42:14 +01:00
{
if(file_p->drv == NULL || file_p->drv == NULL) {
pos = 0;
2017-12-03 22:32:09 +01:00
return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
}
if(file_p->drv->tell == NULL) {
pos = 0;
2017-12-03 22:32:09 +01:00
return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
}
2017-11-24 17:48:47 +01:00
lv_fs_res_t res = file_p->drv->tell(file_p->file_d, pos);
2017-11-23 20:42:14 +01:00
return res;
}
/**
* Give the size of a file bytes
2017-11-24 17:48:47 +01:00
* @param file_p pointer to a lv_fs_file_t variable
2017-11-23 20:42:14 +01:00
* @param size pointer to a variable to store the size
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
lv_fs_res_t lv_fs_size (lv_fs_file_t * file_p, uint32_t * size)
2017-11-23 20:42:14 +01:00
{
if(file_p->drv == NULL || file_p->drv == NULL) {
2017-12-03 22:32:09 +01:00
return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
}
2017-12-03 22:32:09 +01:00
if(file_p->drv->size == NULL) return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
2017-12-03 22:32:09 +01:00
if(size == NULL) return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
2017-11-24 17:48:47 +01:00
lv_fs_res_t res = file_p->drv->size(file_p->file_d, size);
2017-11-23 20:42:14 +01:00
return res;
}
/**
* Initialize a 'fs_read_dir_t' variable for directory reading
* @param rddir_p pointer to a 'fs_read_dir_t' variable
* @param path path to a directory
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-12-03 22:32:09 +01:00
lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path)
2017-11-23 20:42:14 +01:00
{
2017-12-03 22:32:09 +01:00
if(path == NULL) return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
char letter = path[0];
2017-11-24 17:48:47 +01:00
rddir_p->drv = lv_fs_get_drv(letter);
2017-11-23 20:42:14 +01:00
if(rddir_p->drv == NULL) {
2017-12-03 22:32:09 +01:00
rddir_p->dir_d = NULL;
return LV_FS_RES_NOT_EX;
2017-11-23 20:42:14 +01:00
}
2017-12-03 22:32:09 +01:00
rddir_p->dir_d = lv_mem_alloc(rddir_p->drv->file_size);
if(rddir_p->dir_d == NULL) {
rddir_p->dir_d = NULL;
return LV_FS_RES_OUT_OF_MEM; /* Out of memory */
2017-11-23 20:42:14 +01:00
}
2017-12-03 22:32:09 +01:00
if(rddir_p->drv->dir_open == NULL) {
return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
}
2017-11-24 17:48:47 +01:00
const char * real_path = lv_fs_get_real_path(path);
2017-12-03 22:32:09 +01:00
lv_fs_res_t res = rddir_p->drv->dir_open(rddir_p->dir_d, real_path);
2017-11-23 20:42:14 +01:00
return res;
}
/**
* Read the next filename form a directory.
* The name of the directories will begin with '/'
* @param rddir_p pointer to an initialized 'fs_read_dir_t' variable
* @param fn pointer to a buffer to store the filename
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-12-03 22:32:09 +01:00
lv_fs_res_t lv_fs_dir_read (lv_fs_dir_t * rddir_p, char * fn)
2017-11-23 20:42:14 +01:00
{
2017-12-03 22:32:09 +01:00
if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {
return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
}
2017-12-03 22:32:09 +01:00
if(rddir_p->drv->dir_read == NULL) {
return LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
}
2017-12-03 22:32:09 +01:00
lv_fs_res_t res = rddir_p->drv->dir_read(rddir_p->dir_d, fn);
2017-11-23 20:42:14 +01:00
return res;
}
/**
* Close the directory reading
* @param rddir_p pointer to an initialized 'fs_read_dir_t' variable
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-12-03 22:32:09 +01:00
lv_fs_res_t lv_fs_dir_close (lv_fs_dir_t * rddir_p)
2017-11-23 20:42:14 +01:00
{
2017-12-03 22:32:09 +01:00
if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {
return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
}
2017-11-24 17:48:47 +01:00
lv_fs_res_t res;
2017-11-23 20:42:14 +01:00
2017-12-03 22:32:09 +01:00
if(rddir_p->drv->dir_close == NULL) {
res = LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
} else {
2017-12-03 22:32:09 +01:00
res = rddir_p->drv->dir_close(rddir_p->dir_d);
2017-11-23 20:42:14 +01:00
}
2017-12-03 22:32:09 +01:00
lv_mem_free(rddir_p->dir_d); /*Clean up*/
rddir_p->dir_d = NULL;
2017-11-23 20:42:14 +01:00
rddir_p->drv = NULL;
2017-12-03 22:32:09 +01:00
rddir_p->dir_d = NULL;
2017-11-23 20:42:14 +01:00
return res;
}
/**
* Get the free and total size of a driver in kB
* @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]
2017-12-03 22:32:09 +01:00
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
lv_fs_res_t lv_fs_free (char letter, uint32_t * total_p, uint32_t * free_p)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
lv_fs_drv_t * drv = lv_fs_get_drv(letter);
2017-11-23 20:42:14 +01:00
if(drv == NULL) {
2017-12-03 22:32:09 +01:00
return LV_FS_RES_INV_PARAM;
2017-11-23 20:42:14 +01:00
}
2017-11-24 17:48:47 +01:00
lv_fs_res_t res;
2017-11-23 20:42:14 +01:00
if(drv->free == NULL) {
2017-12-03 22:32:09 +01:00
res = LV_FS_RES_NOT_IMP;
2017-11-23 20:42:14 +01:00
} else {
uint32_t total_tmp = 0;
uint32_t free_tmp = 0;
res = drv->free(&total_tmp, &free_tmp);
if(total_p != NULL) *total_p = total_tmp;
if(free_p != NULL) *free_p = free_tmp;
}
return res;
}
/**
* Add a new drive
2017-11-24 17:48:47 +01:00
* @param drv_p pointer to an lv_fs_drv_t structure which is inited with the
2017-12-03 22:32:09 +01:00
* corresponding function pointers. The data will be copied so the variable can be local.
2017-11-23 20:42:14 +01:00
*/
2017-11-24 17:48:47 +01:00
void lv_fs_add_drv(lv_fs_drv_t * drv_p)
2017-11-23 20:42:14 +01:00
{
/*Save the new driver*/
2017-11-24 17:48:47 +01:00
lv_fs_drv_t* new_drv;
new_drv = lv_ll_ins_head(&drv_ll);
2017-11-26 11:38:28 +01:00
lv_mem_assert(new_drv);
2017-11-24 17:48:47 +01:00
memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t));
2017-11-23 20:42:14 +01:00
}
/**
* Fill a buffer with the letters of existing drivers
* @param buf buffer to store the letters ('\0' added after the last letter)
* @return the buffer
*/
2017-11-24 17:48:47 +01:00
char * lv_fs_get_letters(char * buf)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
lv_fs_drv_t* drv;
2017-11-23 20:42:14 +01:00
uint8_t i = 0;
LL_READ(drv_ll, drv) {
buf[i] = drv->letter;
i++;
}
buf[i] = '\0';
return buf;
}
/**
* Return with the extension of the filename
* @param fn string with a filename
* @return pointer to the beginning extension or empty string if no extension
*/
2017-11-24 17:48:47 +01:00
const char * lv_fs_get_ext(const char * fn)
2017-11-23 20:42:14 +01:00
{
uint16_t i;
for(i = strlen(fn); i > 0; i --) {
if(fn[i] == '.') {
return &fn[i + 1];
} else if(fn[i] == '/' || fn[i] == '\\') {
return ""; /*No extension if a '\' or '/' found*/
}
}
return ""; /*Empty string if no '.' in the file name. */
}
/**
* Step up one level
* @param path pointer to a file name
* @return the truncated file name
*/
2017-11-24 17:48:47 +01:00
char * lv_fs_up(char * path)
2017-11-23 20:42:14 +01:00
{
uint16_t len = strlen(path);
if(len == 0) return path;
len --; /*Go before the trailing '\0'*/
/*Ignore trailing '/' or '\'*/
while(path[len] == '/' || path[len] == '\\') {
path[len] = '\0';
if(len > 0) len --;
else return path;
}
uint16_t i;
for(i = len; i > 0; i --) {
if(path[i] == '/' || path[i] == '\\') break;
}
path[i] = '\0';
return path;
}
/**
* Get the last element of a path (e.g. U:/folder/file -> file)
* @param path a character sting with the path to search in
* @return pointer to the beginning of the last element in the path
*/
2017-11-24 17:48:47 +01:00
const char * lv_fs_get_last(const char * path)
2017-11-23 20:42:14 +01:00
{
uint16_t len = strlen(path);
if(len == 0) return path;
len --; /*Go before the trailing '\0'*/
/*Ignore trailing '/' or '\'*/
while(path[len] == '/' || path[len] == '\\') {
if(len > 0) len --;
else return path;
}
uint16_t i;
for(i = len; i > 0; i --) {
if(path[i] == '/' || path[i] == '\\') break;
}
/*No '/' or '\' in the path so return with path itself*/
if(i == 0) return path;
return &path[i + 1];
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Leave the driver letters and / or \ letters from beginning of the path
* @param path path string (E.g. S:/folder/file.txt)
* @return pointer to the beginning of the real path (E.g. folder/file.txt)
*/
2017-11-24 17:48:47 +01:00
static const char * lv_fs_get_real_path(const char * path)
2017-11-23 20:42:14 +01:00
{
/* Example path: "S:/folder/file.txt"
* Leave the letter and the : / \ characters*/
path ++; /*Ignore the driver letter*/
while(*path != '\0') {
if(*path == ':' || *path == '\\' || *path == '/'){
path ++;
}
else {
break;
}
}
return path;
}
/**
* Give a pointer to a driver from its letter
* @param letter the driver letter
* @return pointer to a driver or NULL if not found
*/
2017-11-24 17:48:47 +01:00
static lv_fs_drv_t* lv_fs_get_drv(char letter)
2017-11-23 20:42:14 +01:00
{
2017-11-24 17:48:47 +01:00
lv_fs_drv_t* drv;
2017-11-23 20:42:14 +01:00
LL_READ(drv_ll, drv) {
if(drv->letter == letter) {
return drv;
}
}
return NULL;
}
#endif /*USE_LV_FILESYSTEM*/