1 /**
2 * @file lv_fs_fatfs.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../../../lvgl.h"
10
11 #if LV_USE_FS_FATFS
12 #include "ff.h"
13
14 /*********************
15 * DEFINES
16 *********************/
17
18 #if LV_FS_FATFS_LETTER == '\0'
19 #error "LV_FS_FATFS_LETTER must be an upper case ASCII letter"
20 #endif
21
22 /**********************
23 * TYPEDEFS
24 **********************/
25
26 /**********************
27 * STATIC PROTOTYPES
28 **********************/
29 static void fs_init(void);
30
31 static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
32 static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p);
33 static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
34 static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
35 static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
36 static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
37 static void * fs_dir_open(lv_fs_drv_t * drv, const char * path);
38 static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn);
39 static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p);
40
41 /**********************
42 * STATIC VARIABLES
43 **********************/
44
45 /**********************
46 * MACROS
47 **********************/
48
49 /**********************
50 * GLOBAL FUNCTIONS
51 **********************/
52
lv_fs_fatfs_init(void)53 void lv_fs_fatfs_init(void)
54 {
55 /*----------------------------------------------------
56 * Initialize your storage device and File System
57 * -------------------------------------------------*/
58 fs_init();
59
60 /*---------------------------------------------------
61 * Register the file system interface in LVGL
62 *--------------------------------------------------*/
63
64 /*Add a simple drive to open images*/
65 static lv_fs_drv_t fs_drv; /*A driver descriptor*/
66 lv_fs_drv_init(&fs_drv);
67
68 /*Set up fields...*/
69 fs_drv.letter = LV_FS_FATFS_LETTER;
70 fs_drv.cache_size = LV_FS_FATFS_CACHE_SIZE;
71
72 fs_drv.open_cb = fs_open;
73 fs_drv.close_cb = fs_close;
74 fs_drv.read_cb = fs_read;
75 fs_drv.write_cb = fs_write;
76 fs_drv.seek_cb = fs_seek;
77 fs_drv.tell_cb = fs_tell;
78
79 fs_drv.dir_close_cb = fs_dir_close;
80 fs_drv.dir_open_cb = fs_dir_open;
81 fs_drv.dir_read_cb = fs_dir_read;
82
83 lv_fs_drv_register(&fs_drv);
84 }
85
86 /**********************
87 * STATIC FUNCTIONS
88 **********************/
89
90 /*Initialize your Storage device and File system.*/
fs_init(void)91 static void fs_init(void)
92 {
93 /*Initialize the SD card and FatFS itself.
94 *Better to do it in your code to keep this library untouched for easy updating*/
95 }
96
97 /**
98 * Open a file
99 * @param drv pointer to a driver where this function belongs
100 * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
101 * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
102 * @return pointer to FIL struct or NULL in case of fail
103 */
fs_open(lv_fs_drv_t * drv,const char * path,lv_fs_mode_t mode)104 static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
105 {
106 LV_UNUSED(drv);
107 uint8_t flags = 0;
108
109 if(mode == LV_FS_MODE_WR) flags = FA_WRITE | FA_OPEN_ALWAYS;
110 else if(mode == LV_FS_MODE_RD) flags = FA_READ;
111 else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
112
113 FIL * f = lv_mem_alloc(sizeof(FIL));
114 if(f == NULL) return NULL;
115
116 FRESULT res = f_open(f, path, flags);
117 if(res == FR_OK) {
118 return f;
119 }
120 else {
121 lv_mem_free(f);
122 return NULL;
123 }
124 }
125
126 /**
127 * Close an opened file
128 * @param drv pointer to a driver where this function belongs
129 * @param file_p pointer to a FIL variable. (opened with fs_open)
130 * @return LV_FS_RES_OK: no error, the file is read
131 * any error from lv_fs_res_t enum
132 */
fs_close(lv_fs_drv_t * drv,void * file_p)133 static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p)
134 {
135 LV_UNUSED(drv);
136 f_close(file_p);
137 lv_mem_free(file_p);
138 return LV_FS_RES_OK;
139 }
140
141 /**
142 * Read data from an opened file
143 * @param drv pointer to a driver where this function belongs
144 * @param file_p pointer to a FIL variable.
145 * @param buf pointer to a memory block where to store the read data
146 * @param btr number of Bytes To Read
147 * @param br the real number of read bytes (Byte Read)
148 * @return LV_FS_RES_OK: no error, the file is read
149 * any error from lv_fs_res_t enum
150 */
fs_read(lv_fs_drv_t * drv,void * file_p,void * buf,uint32_t btr,uint32_t * br)151 static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
152 {
153 LV_UNUSED(drv);
154 FRESULT res = f_read(file_p, buf, btr, (UINT *)br);
155 if(res == FR_OK) return LV_FS_RES_OK;
156 else return LV_FS_RES_UNKNOWN;
157 }
158
159 /**
160 * Write into a file
161 * @param drv pointer to a driver where this function belongs
162 * @param file_p pointer to a FIL variable
163 * @param buf pointer to a buffer with the bytes to write
164 * @param btw Bytes To Write
165 * @param bw the number of real written bytes (Bytes Written). NULL if unused.
166 * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
167 */
fs_write(lv_fs_drv_t * drv,void * file_p,const void * buf,uint32_t btw,uint32_t * bw)168 static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
169 {
170 LV_UNUSED(drv);
171 FRESULT res = f_write(file_p, buf, btw, (UINT *)bw);
172 if(res == FR_OK) return LV_FS_RES_OK;
173 else return LV_FS_RES_UNKNOWN;
174 }
175
176 /**
177 * Set the read write pointer. Also expand the file size if necessary.
178 * @param drv pointer to a driver where this function belongs
179 * @param file_p pointer to a FIL variable. (opened with fs_open )
180 * @param pos the new position of read write pointer
181 * @param whence only LV_SEEK_SET is supported
182 * @return LV_FS_RES_OK: no error, the file is read
183 * any error from lv_fs_res_t enum
184 */
fs_seek(lv_fs_drv_t * drv,void * file_p,uint32_t pos,lv_fs_whence_t whence)185 static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
186 {
187 LV_UNUSED(drv);
188 switch(whence) {
189 case LV_FS_SEEK_SET:
190 f_lseek(file_p, pos);
191 break;
192 case LV_FS_SEEK_CUR:
193 f_lseek(file_p, f_tell((FIL *)file_p) + pos);
194 break;
195 case LV_FS_SEEK_END:
196 f_lseek(file_p, f_size((FIL *)file_p) + pos);
197 break;
198 default:
199 break;
200 }
201 return LV_FS_RES_OK;
202 }
203
204 /**
205 * Give the position of the read write pointer
206 * @param drv pointer to a driver where this function belongs
207 * @param file_p pointer to a FIL variable.
208 * @param pos_p pointer to to store the result
209 * @return LV_FS_RES_OK: no error, the file is read
210 * any error from lv_fs_res_t enum
211 */
fs_tell(lv_fs_drv_t * drv,void * file_p,uint32_t * pos_p)212 static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
213 {
214 LV_UNUSED(drv);
215 *pos_p = f_tell((FIL *)file_p);
216 return LV_FS_RES_OK;
217 }
218
219 /**
220 * Initialize a 'DIR' variable for directory reading
221 * @param drv pointer to a driver where this function belongs
222 * @param path path to a directory
223 * @return pointer to an initialized 'DIR' variable
224 */
fs_dir_open(lv_fs_drv_t * drv,const char * path)225 static void * fs_dir_open(lv_fs_drv_t * drv, const char * path)
226 {
227 LV_UNUSED(drv);
228 DIR * d = lv_mem_alloc(sizeof(DIR));
229 if(d == NULL) return NULL;
230
231 FRESULT res = f_opendir(d, path);
232 if(res != FR_OK) {
233 lv_mem_free(d);
234 d = NULL;
235 }
236 return d;
237 }
238
239 /**
240 * Read the next filename from a directory.
241 * The name of the directories will begin with '/'
242 * @param drv pointer to a driver where this function belongs
243 * @param dir_p pointer to an initialized 'DIR' variable
244 * @param fn pointer to a buffer to store the filename
245 * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
246 */
fs_dir_read(lv_fs_drv_t * drv,void * dir_p,char * fn)247 static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn)
248 {
249 LV_UNUSED(drv);
250 FRESULT res;
251 FILINFO fno;
252 fn[0] = '\0';
253
254 do {
255 res = f_readdir(dir_p, &fno);
256 if(res != FR_OK) return LV_FS_RES_UNKNOWN;
257
258 if(fno.fattrib & AM_DIR) {
259 fn[0] = '/';
260 strcpy(&fn[1], fno.fname);
261 }
262 else strcpy(fn, fno.fname);
263
264 } while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0);
265
266 return LV_FS_RES_OK;
267 }
268
269 /**
270 * Close the directory reading
271 * @param drv pointer to a driver where this function belongs
272 * @param dir_p pointer to an initialized 'DIR' variable
273 * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
274 */
fs_dir_close(lv_fs_drv_t * drv,void * dir_p)275 static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p)
276 {
277 LV_UNUSED(drv);
278 f_closedir(dir_p);
279 lv_mem_free(dir_p);
280 return LV_FS_RES_OK;
281 }
282
283 #else /*LV_USE_FS_FATFS == 0*/
284
285 #if defined(LV_FS_FATFS_LETTER) && LV_FS_FATFS_LETTER != '\0'
286 #warning "LV_USE_FS_FATFS is not enabled but LV_FS_FATFS_LETTER is set"
287 #endif
288
289 #endif /*LV_USE_FS_POSIX*/
290
291