/** * @file lv_fs_memfs.c * * File System Interface driver for memory-mapped files * * This driver allows using a memory area as a file that can be read by normal file operations. It can * be used, e.g., to store font files in slow flash memory, and load them into RAM on demand. * * You can enable it in lv_conf.h: * * #define LV_USE_FS_MEMFS 1 * * The actual implementation uses the built-in cache mechanism of the file system interface. * * Since this is not an actual file system, file write and directories are not supported. * * The default drive letter is 'M', but this can be changed in lv_conf.h: * * #define LV_FS_MEMFS_LETTER 'M' * * To use it seamlessly with the file system interface a new extended path object has been introduced: * * lv_fs_path_ex_t mempath; * * This structure can be initialized with the helper function: * * lv_fs_make_path_ex(&mempath, (const uint8_t *) & my_mem_buffer, sizeof(my_mem_buffer)); * * Then the "file" can be opened with: * * lv_fs_file_t file; * lv_fs_res_t res = lv_fs_open(&file, (const char *) & mempath, LV_FS_MODE_RD); * * The path object can be used at any place where a file path is required, e.g.: * * lv_font_t* my_font = lv_binfont_create((const char *) & mempath); * */ /********************* * INCLUDES *********************/ #include "../../misc/lv_fs_private.h" #include "../../../lvgl.h" #if LV_USE_FS_MEMFS /********************* * DEFINES *********************/ #if !LV_FS_IS_VALID_LETTER(LV_FS_MEMFS_LETTER) #error "Invalid drive letter" #endif /********************** * TYPEDEFS **********************/ /********************** * STATIC PROTOTYPES **********************/ static void * fs_open(lv_fs_drv_t * drv, 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_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence); static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p); /********************** * STATIC VARIABLES **********************/ static lv_fs_drv_t fs_drv; /*A driver descriptor*/ /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ /** * Register a driver for the File system interface */ void lv_fs_memfs_init(void) { /*--------------------------------------------------- * Register the file system interface in LVGL *--------------------------------------------------*/ lv_fs_drv_init(&fs_drv); /*Set up fields...*/ fs_drv.letter = LV_FS_MEMFS_LETTER; fs_drv.cache_size = LV_FS_CACHE_FROM_BUFFER; fs_drv.open_cb = fs_open; fs_drv.close_cb = fs_close; fs_drv.read_cb = fs_read; fs_drv.write_cb = NULL; fs_drv.seek_cb = fs_seek; fs_drv.tell_cb = fs_tell; fs_drv.dir_close_cb = NULL; fs_drv.dir_open_cb = NULL; fs_drv.dir_read_cb = NULL; lv_fs_drv_register(&fs_drv); } /********************** * STATIC FUNCTIONS **********************/ /** * Open a file * @param drv pointer to a driver where this function belongs * @param path pointer to an extended path object containing the memory buffer address and size * @param mode read: FS_MODE_RD (currently only reading from the buffer is supported) * @return pointer to FIL struct or NULL in case of fail */ static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode) { LV_UNUSED(drv); LV_UNUSED(mode); return (void *)path; } /** * Close an opened file * @param drv pointer to a driver where this function belongs * @param file_p pointer to a FILE variable. (opened with 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_close(lv_fs_drv_t * drv, void * file_p) { LV_UNUSED(drv); LV_UNUSED(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 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_UNUSED(drv); LV_UNUSED(file_p); LV_UNUSED(buf); LV_UNUSED(btr); *br = 0; return LV_FS_RES_OK; } /** * Set the read pointer. * @param drv pointer to a driver where this function belongs * @param file_p pointer to a FILE variable. (opened with fs_open ) * @param pos the new position of read 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_fs_whence_t whence) { /* NOTE: this function is only called to determine the end of the buffer when LV_FS_SEEK_END was given to lv_fs_seek() */ LV_UNUSED(drv); lv_fs_file_t * fp = (lv_fs_file_t *)file_p; switch(whence) { case LV_FS_SEEK_SET: { fp->cache->file_position = pos; break; } case LV_FS_SEEK_CUR: { fp->cache->file_position += pos; break; } case LV_FS_SEEK_END: { fp->cache->file_position = fp->cache->end - pos; break; } } if(fp->cache->file_position < fp->cache->start) fp->cache->file_position = fp->cache->start; else if(fp->cache->file_position > fp->cache->end) fp->cache->file_position = fp->cache->end; 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 variable * @param pos_p pointer 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_UNUSED(drv); *pos_p = ((lv_fs_file_t *)file_p)->cache->file_position; return LV_FS_RES_OK; } #else /*LV_USE_FS_MEMFS == 0*/ #if defined(LV_FS_MEMFS_LETTER) && LV_FS_MEMFS_LETTER != '\0' #warning "LV_USE_FS_MEMFS is not enabled but LV_FS_MEMFS_LETTER is set" #endif #endif /*LV_USE_FS_MEMFS*/