1 /*
2  * Copyright (c) 2018-2019 Jan Van Winkel <jan.van_winkel@dxplore.eu>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <lvgl.h>
8 #include <zephyr.h>
9 #include <fs/fs.h>
10 #include "lvgl_fs.h"
11 
lvgl_fs_ready(struct _lv_fs_drv_t * drv)12 static bool lvgl_fs_ready(struct _lv_fs_drv_t *drv)
13 {
14 	return true;
15 }
16 
errno_to_lv_fs_res(int err)17 static lv_fs_res_t errno_to_lv_fs_res(int err)
18 {
19 	switch (err) {
20 	case 0:
21 		return LV_FS_RES_OK;
22 	case -EIO:
23 		/*Low level hardware error*/
24 		return LV_FS_RES_HW_ERR;
25 	case -EBADF:
26 		/*Error in the file system structure */
27 		return LV_FS_RES_FS_ERR;
28 	case -ENOENT:
29 		/*Driver, file or directory is not exists*/
30 		return LV_FS_RES_NOT_EX;
31 	case -EFBIG:
32 		/*Disk full*/
33 		return LV_FS_RES_FULL;
34 	case -EACCES:
35 		/*Access denied. Check 'fs_open' modes and write protect*/
36 		return LV_FS_RES_DENIED;
37 	case -EBUSY:
38 		/*The file system now can't handle it, try later*/
39 		return LV_FS_RES_BUSY;
40 	case -ENOMEM:
41 		/*Not enough memory for an internal operation*/
42 		return LV_FS_RES_OUT_OF_MEM;
43 	case -EINVAL:
44 		/*Invalid parameter among arguments*/
45 		return LV_FS_RES_INV_PARAM;
46 	default:
47 		return LV_FS_RES_UNKNOWN;
48 	}
49 }
50 
lvgl_fs_open(struct _lv_fs_drv_t * drv,void * file,const char * path,lv_fs_mode_t mode)51 static lv_fs_res_t lvgl_fs_open(struct _lv_fs_drv_t *drv, void *file,
52 		const char *path, lv_fs_mode_t mode)
53 {
54 	int err;
55 	int zmode = FS_O_CREATE;
56 
57 	/* LVGL is passing absolute paths without the root slash add it back
58 	 * by decrementing the path pointer.
59 	 */
60 	path--;
61 
62 	zmode |= (mode & LV_FS_MODE_WR) ? FS_O_WRITE : 0;
63 	zmode |= (mode & LV_FS_MODE_RD) ? FS_O_READ : 0;
64 
65 	err = fs_open((struct fs_file_t *)file, path, zmode);
66 	return errno_to_lv_fs_res(err);
67 }
68 
lvgl_fs_close(struct _lv_fs_drv_t * drv,void * file)69 static lv_fs_res_t lvgl_fs_close(struct _lv_fs_drv_t *drv, void *file)
70 {
71 	int err;
72 
73 	err = fs_close((struct fs_file_t *)file);
74 	return errno_to_lv_fs_res(err);
75 }
76 
lvgl_fs_remove(struct _lv_fs_drv_t * drv,const char * path)77 static lv_fs_res_t lvgl_fs_remove(struct _lv_fs_drv_t *drv, const char *path)
78 {
79 	int err;
80 
81 	/* LVGL is passing absolute paths without the root slash add it back
82 	 * by decrementing the path pointer.
83 	 */
84 	path--;
85 
86 	err = fs_unlink(path);
87 	return errno_to_lv_fs_res(err);
88 }
89 
lvgl_fs_read(struct _lv_fs_drv_t * drv,void * file,void * buf,uint32_t btr,uint32_t * br)90 static lv_fs_res_t lvgl_fs_read(struct _lv_fs_drv_t *drv, void *file,
91 		void *buf, uint32_t btr, uint32_t *br)
92 {
93 	int err;
94 
95 	err = fs_read((struct fs_file_t *)file, buf, btr);
96 	if (err > 0) {
97 		if (br != NULL) {
98 			*br = err;
99 		}
100 		err = 0;
101 	} else if (br != NULL) {
102 		*br = 0U;
103 	}
104 	return errno_to_lv_fs_res(err);
105 }
106 
lvgl_fs_write(struct _lv_fs_drv_t * drv,void * file,const void * buf,uint32_t btw,uint32_t * bw)107 static lv_fs_res_t lvgl_fs_write(struct _lv_fs_drv_t *drv, void *file,
108 		const void *buf, uint32_t btw, uint32_t *bw)
109 {
110 	int err;
111 
112 	err = fs_write((struct fs_file_t *)file, buf, btw);
113 	if (err == btw) {
114 		if (bw != NULL) {
115 			*bw = btw;
116 		}
117 		err = 0;
118 	} else if (err < 0) {
119 		if (bw != NULL) {
120 			*bw = 0U;
121 		}
122 	} else {
123 		if (bw != NULL) {
124 			*bw = err;
125 		}
126 		err = -EFBIG;
127 	}
128 	return errno_to_lv_fs_res(err);
129 }
130 
lvgl_fs_seek(struct _lv_fs_drv_t * drv,void * file,uint32_t pos)131 static lv_fs_res_t lvgl_fs_seek(struct _lv_fs_drv_t *drv, void *file, uint32_t pos)
132 {
133 	int err;
134 
135 	err = fs_seek((struct fs_file_t *)file, pos, FS_SEEK_SET);
136 	return errno_to_lv_fs_res(err);
137 }
138 
lvgl_fs_tell(struct _lv_fs_drv_t * drv,void * file,uint32_t * pos_p)139 static lv_fs_res_t lvgl_fs_tell(struct _lv_fs_drv_t *drv, void *file,
140 		uint32_t *pos_p)
141 {
142 	*pos_p = fs_tell((struct fs_file_t *)file);
143 	return LV_FS_RES_OK;
144 }
145 
lvgl_fs_trunc(struct _lv_fs_drv_t * drv,void * file)146 static lv_fs_res_t lvgl_fs_trunc(struct _lv_fs_drv_t *drv, void *file)
147 {
148 	int err;
149 	off_t length;
150 
151 	length = fs_tell((struct fs_file_t *) file);
152 	++length;
153 	err = fs_truncate((struct fs_file_t *)file, length);
154 	return errno_to_lv_fs_res(err);
155 }
156 
lvgl_fs_size(struct _lv_fs_drv_t * drv,void * file,uint32_t * fsize)157 static lv_fs_res_t lvgl_fs_size(struct _lv_fs_drv_t *drv, void *file,
158 		uint32_t *fsize)
159 {
160 	int err;
161 	off_t org_pos;
162 
163 	/* LVGL does not provided path but pointer to file struct as such
164 	 * we can not use fs_stat, instead use a combination of fs_tell and
165 	 * fs_seek to get the files size.
166 	 */
167 
168 	org_pos = fs_tell((struct fs_file_t *) file);
169 
170 	err = fs_seek((struct fs_file_t *) file, 0, FS_SEEK_END);
171 	if (err != 0) {
172 		*fsize = 0U;
173 		return errno_to_lv_fs_res(err);
174 	}
175 
176 	*fsize = fs_tell((struct fs_file_t *) file) + 1;
177 
178 	err = fs_seek((struct fs_file_t *) file, org_pos, FS_SEEK_SET);
179 
180 	return errno_to_lv_fs_res(err);
181 }
182 
lvgl_fs_rename(struct _lv_fs_drv_t * drv,const char * from,const char * to)183 static lv_fs_res_t lvgl_fs_rename(struct _lv_fs_drv_t *drv, const char *from,
184 		const char *to)
185 {
186 	int err;
187 
188 	/* LVGL is passing absolute paths without the root slash add it back
189 	 * by decrementing the path pointer.
190 	 */
191 	from--;
192 	to--;
193 
194 	err = fs_rename(from, to);
195 	return errno_to_lv_fs_res(err);
196 }
197 
lvgl_fs_free(struct _lv_fs_drv_t * drv,uint32_t * total_p,uint32_t * free_p)198 static lv_fs_res_t lvgl_fs_free(struct _lv_fs_drv_t *drv, uint32_t *total_p,
199 		uint32_t *free_p)
200 {
201 	/* We have no easy way of telling the total file system size.
202 	 * Zephyr can only return this information per mount point.
203 	 */
204 	return LV_FS_RES_NOT_IMP;
205 }
206 
lvgl_fs_dir_open(struct _lv_fs_drv_t * drv,void * dir,const char * path)207 static lv_fs_res_t lvgl_fs_dir_open(struct _lv_fs_drv_t *drv, void *dir,
208 		const char *path)
209 {
210 	int err;
211 
212 	/* LVGL is passing absolute paths without the root slash add it back
213 	 * by decrementing the path pointer.
214 	 */
215 	path--;
216 
217 	fs_dir_t_init((struct fs_dir_t *)dir);
218 	err = fs_opendir((struct fs_dir_t *)dir, path);
219 	return errno_to_lv_fs_res(err);
220 }
221 
lvgl_fs_dir_read(struct _lv_fs_drv_t * drv,void * dir,char * fn)222 static lv_fs_res_t lvgl_fs_dir_read(struct _lv_fs_drv_t *drv, void *dir,
223 		char *fn)
224 {
225 	/* LVGL expects a string as return parameter but the format of the
226 	 * string is not documented.
227 	 */
228 	return LV_FS_RES_NOT_IMP;
229 }
230 
lvgl_fs_dir_close(struct _lv_fs_drv_t * drv,void * dir)231 static lv_fs_res_t lvgl_fs_dir_close(struct _lv_fs_drv_t *drv, void *dir)
232 {
233 	int err;
234 
235 	err = fs_closedir((struct fs_dir_t *)dir);
236 	return errno_to_lv_fs_res(err);
237 }
238 
lvgl_fs_init(void)239 void lvgl_fs_init(void)
240 {
241 	lv_fs_drv_t fs_drv;
242 	lv_fs_drv_init(&fs_drv);
243 
244 	fs_drv.file_size = sizeof(struct fs_file_t);
245 	fs_drv.rddir_size = sizeof(struct fs_dir_t);
246 	/* LVGL uses letter based mount points, just pass the root slash as a
247 	 * letter. Note that LVGL will remove the drive letter, or in this case
248 	 * the root slash, from the path passed via the FS callbacks.
249 	 * Zephyr FS API assumes this slash is present so we will need to add
250 	 * it back.
251 	 */
252 	fs_drv.letter = '/';
253 	fs_drv.ready_cb = lvgl_fs_ready;
254 
255 	fs_drv.open_cb = lvgl_fs_open;
256 	fs_drv.close_cb = lvgl_fs_close;
257 	fs_drv.remove_cb = lvgl_fs_remove;
258 	fs_drv.read_cb = lvgl_fs_read;
259 	fs_drv.write_cb = lvgl_fs_write;
260 	fs_drv.seek_cb = lvgl_fs_seek;
261 	fs_drv.tell_cb = lvgl_fs_tell;
262 	fs_drv.trunc_cb = lvgl_fs_trunc;
263 	fs_drv.size_cb = lvgl_fs_size;
264 	fs_drv.rename_cb = lvgl_fs_rename;
265 	fs_drv.free_space_cb = lvgl_fs_free;
266 
267 	fs_drv.dir_open_cb = lvgl_fs_dir_open;
268 	fs_drv.dir_read_cb = lvgl_fs_dir_read;
269 	fs_drv.dir_close_cb = lvgl_fs_dir_close;
270 
271 	lv_fs_drv_register(&fs_drv);
272 }
273