/**************************************************************************** * apps/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 #include #include #include #include #include #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); }