nuttx-apps/graphics/lvgl/lv_fs_interface.c
pengyiqiang 1b5b8c5167 lvgl: Add file system interface.
N/A

Change-Id: Iae291f0250284ef7fe8af60e02f66c326b54d979
Signed-off-by: pengyiqiang <pengyiqiang@xiaomi.com>
2021-01-03 08:04:34 -06:00

576 lines
16 KiB
C

/****************************************************************************
* graphics/lvgl/lv_fs_interface.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/statfs.h>
#include "lv_fs_interface.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define LV_FS_LETTER '/'
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/* Create a type to store the required data about your file. */
typedef int file_t;
/* Similarly to `file_t` create a type for directory reading too */
typedef DIR *dir_t;
/****************************************************************************
* Private Function 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);
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: fs_open
*
* Description:
* Open a file.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* file_p - pointer to a file_t variable.
* path - path to the file beginning with the driver letter.
* (e.g. /folder/file.txt)
* mode - read: FS_MODE_RD, write: FS_MODE_WR,
* both: FS_MODE_RD | FS_MODE_WR
*
* Returned Value:
* 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)
{
uint32_t flags = 0;
if (mode == LV_FS_MODE_WR)
{
flags = O_WRONLY | O_CREAT;
}
else if (mode == LV_FS_MODE_RD)
{
flags = O_RDONLY;
}
else if (mode == (LV_FS_MODE_WR | LV_FS_MODE_RD))
{
flags = O_RDWR | O_CREAT;
}
else
{
return LV_FS_RES_UNKNOWN;
}
file_t f = open(--path, flags);
if (f < 0)
{
return LV_FS_RES_FS_ERR;
}
/* '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;
}
/****************************************************************************
* Name: fs_close
*
* Description:
* Close an opened file.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* file_p - pointer to a file_t variable.
*
* Returned Value:
* 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)
{
/* Just avoid the confusing casings */
file_t *fp = file_p;
return close(*fp) < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_read
*
* Description:
* Read data from an opened file.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* file_p - pointer to a file_t variable.
* buf - pointer to a memory block where to store the read data.
* btr - number of Bytes To Read.
* br - the real number of read bytes (Byte Read).
*
* Returned Value:
* 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)
{
/* Just avoid the confusing casings */
file_t *fp = file_p;
*br = read(*fp, buf, btr);
return (int32_t)*br < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_write
*
* Description:
* Write into a file.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* file_p - pointer to a file_t variable.
* buf - pointer to a buffer with the bytes to write.
* btw - Bytes To Write.
* bw - the number of real written bytes (Bytes Written).
* NULL if unused.
*
* Returned Value:
* 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)
{
/* Just avoid the confusing casings */
file_t *fp = file_p;
*bw = write(*fp, buf, btw);
return (int32_t)*bw < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_seek
*
* Description:
* Set the read write pointer. Also expand the file size if necessary.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* file_p - pointer to a file_t variable.
* pos - the new position of read write pointer.
*
* Returned Value:
* 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)
{
/* Just avoid the confusing casings */
file_t *fp = file_p;
off_t offset = lseek(*fp, pos, SEEK_SET);
return offset < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_size
*
* Description:
* Give the size of a file bytes.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* file_p - pointer to a file_t variable.
* size - pointer to a variable to store the size.
*
* Returned Value:
* 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)
{
/* Just avoid the confusing casings */
file_t *fp = file_p;
off_t cur = lseek(*fp, 0, SEEK_CUR);
*size_p = lseek(*fp, 0L, SEEK_END);
/* Restore file pointer */
lseek(*fp, cur, SEEK_SET);
return (int32_t)*size_p < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_tell
*
* Description:
* Give the position of the read write pointer.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* file_p - pointer to a file_t variable.
* pos_p - pointer to to store the result.
*
* Returned Value:
* 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)
{
/* Just avoid the confusing casings */
file_t *fp = file_p;
*pos_p = lseek(*fp, 0, SEEK_CUR);
return (int32_t)*pos_p < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_remove
*
* Description:
* Delete a file.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* path - path of the file to delete.
*
* Returned Value:
* 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)
{
return remove(--path) < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_trunc
*
* Description:
* Truncate the file size to the current position of
* the read write pointer.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* file_p - pointer to a file_t variable.
*
* Returned Value:
* LV_FS_RES_OK or any error from lv_fs_res_t enum.
*
****************************************************************************/
static lv_fs_res_t fs_trunc(lv_fs_drv_t *drv, void *file_p)
{
/* Just avoid the confusing casings */
file_t *fp = file_p;
off_t p = lseek(*fp, 0, SEEK_CUR);
return ftruncate(*fp, p) < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_rename
*
* Description:
* Rename a file.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* oldname - path to the file.
* newname - path with the new name
*
* Returned Value:
* LV_FS_RES_OK or any error from lv_fs_res_t enum.
*
****************************************************************************/
static lv_fs_res_t fs_rename(lv_fs_drv_t *drv, const char *oldname,
const char *newname)
{
return rename(--oldname, --newname) < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_free
*
* Description:
* Get the free and total size of a driver in kB.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* total_p - pointer to store the total size [kB].
* free_p - pointer to store the free size [kB]
*
* Returned Value:
* 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)
{
struct statfs sfs;
if (statfs(CONFIG_LV_FILESYSTEM_MOUNTPOINT, &sfs) < 0)
{
return LV_FS_RES_FS_ERR;
}
else
{
*total_p = sfs.f_blocks * sfs.f_bsize / 1024;
*free_p = sfs.f_bfree * sfs.f_bsize / 1024;
return LV_FS_RES_OK;
}
}
/****************************************************************************
* Name: fs_dir_open
*
* Description:
* Initialize a 'fs_read_dir_t' variable for directory reading.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* dir_p - pointer to a 'fs_read_dir_t' variable.
* path - path to a directory.
*
* Returned Value:
* 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)
{
dir_t d;
/* Make the path relative to the current directory
* (the projects root folder)
*/
if ((d = opendir(--path)) == 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
*/
/* Just avoid the confusing casings */
dir_t *dp = dir_p;
*dp = d;
}
return LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_dir_read
*
* Description:
* Read the next filename form a directory.
* The name of the directories will begin with '/'.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* dir_p - pointer to an initialized 'fs_read_dir_t' variable.
* fn - pointer to a buffer to store the filename.
*
* Returned Value:
* 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)
{
/* Just avoid the confusing casings */
dir_t *dp = dir_p;
do
{
struct dirent *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);
return LV_FS_RES_OK;
}
/****************************************************************************
* Name: fs_dir_read
*
* Description:
* Close the directory reading.
*
* Input Parameters:
* drv - pointer to a driver where this function belongs.
* dir_p - pointer to an initialized 'fs_read_dir_t' variable.
*
* Returned Value:
* 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)
{
dir_t *dp = dir_p;
return closedir(*dp) < 0 ? LV_FS_RES_FS_ERR : LV_FS_RES_OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: lv_fs_interface_init
*
* Description:
* Register a driver for the File system interface.
*
****************************************************************************/
void lv_fs_interface_init(void)
{
/* 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_LETTER;
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);
}