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