1 /**
2  * @file lv_fs_memfs.c
3  *
4  * File System Interface driver for memory-mapped files
5  *
6  * This driver allows using a memory area as a file that can be read by normal file operations. It can
7  * be used, e.g., to store font files in slow flash memory, and load them into RAM on demand.
8  *
9  * You can enable it in lv_conf.h:
10  *
11  * #define LV_USE_FS_MEMFS 1
12  *
13  * The actual implementation uses the built-in cache mechanism of the file system interface.
14  *
15  * Since this is not an actual file system, file write and directories are not supported.
16  *
17  * The default drive letter is 'M', but this can be changed in lv_conf.h:
18  *
19  * #define LV_FS_MEMFS_LETTER 'M'
20  *
21  * To use it seamlessly with the file system interface a new extended path object has been introduced:
22  *
23  * lv_fs_path_ex_t mempath;
24  *
25  * This structure can be initialized with the helper function:
26  *
27  * lv_fs_make_path_ex(&mempath, (const uint8_t *) & my_mem_buffer, sizeof(my_mem_buffer));
28  *
29  * Then the "file" can be opened with:
30  *
31  * lv_fs_file_t file;
32  * lv_fs_res_t res = lv_fs_open(&file, (const char *) & mempath, LV_FS_MODE_RD);
33  *
34  * The path object can be used at any place where a file path is required, e.g.:
35  *
36  * lv_font_t* my_font = lv_binfont_create((const char *) & mempath);
37  *
38  */
39 
40 /*********************
41  *      INCLUDES
42  *********************/
43 #include "../../misc/lv_fs_private.h"
44 #include "../../../lvgl.h"
45 #if LV_USE_FS_MEMFS
46 
47 /*********************
48  *      DEFINES
49  *********************/
50 
51 #if !LV_FS_IS_VALID_LETTER(LV_FS_MEMFS_LETTER)
52     #error "Invalid drive letter"
53 #endif
54 
55 /**********************
56  *      TYPEDEFS
57  **********************/
58 
59 /**********************
60 *  STATIC PROTOTYPES
61 **********************/
62 
63 static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
64 static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p);
65 static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
66 static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
67 static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
68 
69 /**********************
70  *  STATIC VARIABLES
71  **********************/
72 
73 static lv_fs_drv_t fs_drv; /*A driver descriptor*/
74 
75 /**********************
76  *      MACROS
77  **********************/
78 
79 /**********************
80  *   GLOBAL FUNCTIONS
81  **********************/
82 
83 /**
84  * Register a driver for the File system interface
85  */
lv_fs_memfs_init(void)86 void lv_fs_memfs_init(void)
87 {
88     /*---------------------------------------------------
89      * Register the file system interface in LVGL
90      *--------------------------------------------------*/
91 
92     lv_fs_drv_init(&fs_drv);
93 
94     /*Set up fields...*/
95     fs_drv.letter = LV_FS_MEMFS_LETTER;
96     fs_drv.cache_size = LV_FS_CACHE_FROM_BUFFER;
97 
98     fs_drv.open_cb = fs_open;
99     fs_drv.close_cb = fs_close;
100     fs_drv.read_cb = fs_read;
101     fs_drv.write_cb = NULL;
102     fs_drv.seek_cb = fs_seek;
103     fs_drv.tell_cb = fs_tell;
104 
105     fs_drv.dir_close_cb = NULL;
106     fs_drv.dir_open_cb = NULL;
107     fs_drv.dir_read_cb = NULL;
108 
109     lv_fs_drv_register(&fs_drv);
110 }
111 
112 /**********************
113  *   STATIC FUNCTIONS
114  **********************/
115 
116 /**
117  * Open a file
118  * @param drv   pointer to a driver where this function belongs
119  * @param path  pointer to an extended path object containing the memory buffer address and size
120  * @param mode  read: FS_MODE_RD (currently only reading from the buffer is supported)
121  * @return pointer to FIL struct or NULL in case of fail
122  */
fs_open(lv_fs_drv_t * drv,const char * path,lv_fs_mode_t mode)123 static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
124 {
125     LV_UNUSED(drv);
126     LV_UNUSED(mode);
127     return (void *)path;
128 }
129 
130 /**
131  * Close an opened file
132  * @param drv       pointer to a driver where this function belongs
133  * @param file_p    pointer to a FILE variable. (opened with fs_open)
134  * @return LV_FS_RES_OK: no error, the file is read
135  *         any error from lv_fs_res_t enum
136  */
fs_close(lv_fs_drv_t * drv,void * file_p)137 static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p)
138 {
139     LV_UNUSED(drv);
140     LV_UNUSED(file_p);
141     return LV_FS_RES_OK;
142 }
143 
144 /**
145  * Read data from an opened file
146  * @param drv       pointer to a driver where this function belongs
147  * @param file_p    pointer to a FILE variable.
148  * @param buf       pointer to a memory block where to store the read data
149  * @param btr       number of Bytes To Read
150  * @param br        the real number of read bytes (Byte Read)
151  * @return LV_FS_RES_OK: no error, the file is read
152  *         any error from lv_fs_res_t enum
153  */
fs_read(lv_fs_drv_t * drv,void * file_p,void * buf,uint32_t btr,uint32_t * br)154 static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
155 {
156     LV_UNUSED(drv);
157     LV_UNUSED(file_p);
158     LV_UNUSED(buf);
159     LV_UNUSED(btr);
160     *br = 0;
161     return LV_FS_RES_OK;
162 }
163 
164 /**
165  * Set the read pointer.
166  * @param drv       pointer to a driver where this function belongs
167  * @param file_p    pointer to a FILE variable. (opened with fs_open )
168  * @param pos       the new position of read pointer
169  * @return LV_FS_RES_OK: no error, the file is read
170  *         any error from lv_fs_res_t enum
171  */
fs_seek(lv_fs_drv_t * drv,void * file_p,uint32_t pos,lv_fs_whence_t whence)172 static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
173 {
174     /* NOTE: this function is only called to determine the end of the buffer when LV_FS_SEEK_END was given to lv_fs_seek() */
175     LV_UNUSED(drv);
176     lv_fs_file_t * fp = (lv_fs_file_t *)file_p;
177     switch(whence) {
178         case LV_FS_SEEK_SET: {
179                 fp->cache->file_position = pos;
180                 break;
181             }
182         case LV_FS_SEEK_CUR: {
183                 fp->cache->file_position += pos;
184                 break;
185             }
186         case LV_FS_SEEK_END: {
187                 fp->cache->file_position = fp->cache->end - pos;
188                 break;
189             }
190     }
191     if(fp->cache->file_position < fp->cache->start)
192         fp->cache->file_position = fp->cache->start;
193     else if(fp->cache->file_position > fp->cache->end)
194         fp->cache->file_position = fp->cache->end;
195     return LV_FS_RES_OK;
196 }
197 
198 /**
199  * Give the position of the read write pointer
200  * @param drv       pointer to a driver where this function belongs
201  * @param file_p    pointer to a FILE variable
202  * @param pos_p     pointer to store the result
203  * @return LV_FS_RES_OK: no error, the file is read
204  *         any error from lv_fs_res_t enum
205  */
fs_tell(lv_fs_drv_t * drv,void * file_p,uint32_t * pos_p)206 static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
207 {
208     LV_UNUSED(drv);
209     *pos_p = ((lv_fs_file_t *)file_p)->cache->file_position;
210     return LV_FS_RES_OK;
211 }
212 
213 #else /*LV_USE_FS_MEMFS == 0*/
214 
215 #if defined(LV_FS_MEMFS_LETTER) && LV_FS_MEMFS_LETTER != '\0'
216     #warning "LV_USE_FS_MEMFS is not enabled but LV_FS_MEMFS_LETTER is set"
217 #endif
218 
219 #endif /*LV_USE_FS_MEMFS*/
220