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/kernel.h>
9 #include <zephyr/fs/fs.h>
10 #include "lvgl_fs.h"
11 #include "lv_conf.h"
12 #include LV_STDLIB_INCLUDE
13
lvgl_fs_ready(lv_fs_drv_t * drv)14 static bool lvgl_fs_ready(lv_fs_drv_t *drv)
15 {
16 return true;
17 }
18
errno_to_lv_fs_res(int err)19 static lv_fs_res_t errno_to_lv_fs_res(int err)
20 {
21 switch (err) {
22 case 0:
23 return LV_FS_RES_OK;
24 case -EIO:
25 /*Low level hardware error*/
26 return LV_FS_RES_HW_ERR;
27 case -EBADF:
28 /*Error in the file system structure */
29 return LV_FS_RES_FS_ERR;
30 case -ENOENT:
31 /*Driver, file or directory is not exists*/
32 return LV_FS_RES_NOT_EX;
33 case -EFBIG:
34 /*Disk full*/
35 return LV_FS_RES_FULL;
36 case -EACCES:
37 /*Access denied. Check 'fs_open' modes and write protect*/
38 return LV_FS_RES_DENIED;
39 case -EBUSY:
40 /*The file system now can't handle it, try later*/
41 return LV_FS_RES_BUSY;
42 case -ENOMEM:
43 /*Not enough memory for an internal operation*/
44 return LV_FS_RES_OUT_OF_MEM;
45 case -EINVAL:
46 /*Invalid parameter among arguments*/
47 return LV_FS_RES_INV_PARAM;
48 case -ENOTSUP:
49 /*Not supported by the filesystem*/
50 return LV_FS_RES_NOT_IMP;
51 default:
52 return LV_FS_RES_UNKNOWN;
53 }
54 }
55
lvgl_fs_open(lv_fs_drv_t * drv,const char * path,lv_fs_mode_t mode)56 static void *lvgl_fs_open(lv_fs_drv_t *drv, const char *path, lv_fs_mode_t mode)
57 {
58 int err;
59 int zmode = FS_O_CREATE;
60 void *file;
61
62 /* LVGL is passing absolute paths without the root slash add it back
63 * by decrementing the path pointer.
64 */
65 path--;
66
67 zmode |= (mode & LV_FS_MODE_WR) ? FS_O_WRITE : 0;
68 zmode |= (mode & LV_FS_MODE_RD) ? FS_O_READ : 0;
69
70 file = lv_malloc(sizeof(struct fs_file_t));
71 if (!file) {
72 return NULL;
73 }
74
75 fs_file_t_init((struct fs_file_t *)file);
76
77 err = fs_open((struct fs_file_t *)file, path, zmode);
78 if (err) {
79 lv_free(file);
80 return NULL;
81 }
82
83 return file;
84 }
85
lvgl_fs_close(lv_fs_drv_t * drv,void * file)86 static lv_fs_res_t lvgl_fs_close(lv_fs_drv_t *drv, void *file)
87 {
88 int err;
89
90 err = fs_close((struct fs_file_t *)file);
91 lv_free(file);
92 return errno_to_lv_fs_res(err);
93 }
94
lvgl_fs_read(lv_fs_drv_t * drv,void * file,void * buf,uint32_t btr,uint32_t * br)95 static lv_fs_res_t lvgl_fs_read(lv_fs_drv_t *drv, void *file, void *buf, uint32_t btr, uint32_t *br)
96 {
97 int err;
98
99 err = fs_read((struct fs_file_t *)file, buf, btr);
100 if (err > 0) {
101 if (br != NULL) {
102 *br = err;
103 }
104 err = 0;
105 } else if (br != NULL) {
106 *br = 0U;
107 }
108 return errno_to_lv_fs_res(err);
109 }
110
lvgl_fs_write(lv_fs_drv_t * drv,void * file,const void * buf,uint32_t btw,uint32_t * bw)111 static lv_fs_res_t lvgl_fs_write(lv_fs_drv_t *drv, void *file, const void *buf, uint32_t btw,
112 uint32_t *bw)
113 {
114 int err;
115
116 err = fs_write((struct fs_file_t *)file, buf, btw);
117 if (err == btw) {
118 if (bw != NULL) {
119 *bw = btw;
120 }
121 err = 0;
122 } else if (err < 0) {
123 if (bw != NULL) {
124 *bw = 0U;
125 }
126 } else {
127 if (bw != NULL) {
128 *bw = err;
129 }
130 err = -EFBIG;
131 }
132 return errno_to_lv_fs_res(err);
133 }
134
lvgl_fs_seek(lv_fs_drv_t * drv,void * file,uint32_t pos,lv_fs_whence_t whence)135 static lv_fs_res_t lvgl_fs_seek(lv_fs_drv_t *drv, void *file, uint32_t pos, lv_fs_whence_t whence)
136 {
137 int err, fs_whence;
138
139 switch (whence) {
140 case LV_FS_SEEK_END:
141 fs_whence = FS_SEEK_END;
142 break;
143 case LV_FS_SEEK_CUR:
144 fs_whence = FS_SEEK_CUR;
145 break;
146 case LV_FS_SEEK_SET:
147 default:
148 fs_whence = FS_SEEK_SET;
149 break;
150 }
151
152 err = fs_seek((struct fs_file_t *)file, pos, fs_whence);
153 return errno_to_lv_fs_res(err);
154 }
155
lvgl_fs_tell(lv_fs_drv_t * drv,void * file,uint32_t * pos_p)156 static lv_fs_res_t lvgl_fs_tell(lv_fs_drv_t *drv, void *file, uint32_t *pos_p)
157 {
158 off_t pos;
159
160 pos = fs_tell((struct fs_file_t *)file);
161 if (pos < 0) {
162 return errno_to_lv_fs_res(pos);
163 }
164
165 *pos_p = pos;
166 return LV_FS_RES_OK;
167 }
168
lvgl_fs_dir_open(lv_fs_drv_t * drv,const char * path)169 static void *lvgl_fs_dir_open(lv_fs_drv_t *drv, const char *path)
170 {
171 void *dir;
172 int err;
173
174 /* LVGL is passing absolute paths without the root slash add it back
175 * by decrementing the path pointer.
176 */
177 path--;
178
179 dir = lv_malloc(sizeof(struct fs_dir_t));
180 if (!dir) {
181 return NULL;
182 }
183
184 fs_dir_t_init((struct fs_dir_t *)dir);
185 err = fs_opendir((struct fs_dir_t *)dir, path);
186 if (err) {
187 lv_free(dir);
188 return NULL;
189 }
190
191 return dir;
192 }
193
lvgl_fs_dir_read(lv_fs_drv_t * drv,void * dir,char * fn,uint32_t fn_len)194 static lv_fs_res_t lvgl_fs_dir_read(lv_fs_drv_t *drv, void *dir, char *fn, uint32_t fn_len)
195 {
196 /* LVGL expects a string as return parameter but the format of the
197 * string is not documented.
198 */
199 return LV_FS_RES_NOT_IMP;
200 }
201
lvgl_fs_dir_close(lv_fs_drv_t * drv,void * dir)202 static lv_fs_res_t lvgl_fs_dir_close(lv_fs_drv_t *drv, void *dir)
203 {
204 int err;
205
206 err = fs_closedir((struct fs_dir_t *)dir);
207 lv_free(dir);
208 return errno_to_lv_fs_res(err);
209 }
210
211 static lv_fs_drv_t fs_drv;
212
lvgl_fs_init(void)213 void lvgl_fs_init(void)
214 {
215 lv_fs_drv_init(&fs_drv);
216
217 /* LVGL uses letter based mount points, just pass the root slash as a
218 * letter. Note that LVGL will remove the drive letter, or in this case
219 * the root slash, from the path passed via the FS callbacks.
220 * Zephyr FS API assumes this slash is present so we will need to add
221 * it back.
222 */
223 fs_drv.letter = '/';
224 fs_drv.ready_cb = lvgl_fs_ready;
225
226 fs_drv.open_cb = lvgl_fs_open;
227 fs_drv.close_cb = lvgl_fs_close;
228 fs_drv.read_cb = lvgl_fs_read;
229 fs_drv.write_cb = lvgl_fs_write;
230 fs_drv.seek_cb = lvgl_fs_seek;
231 fs_drv.tell_cb = lvgl_fs_tell;
232
233 fs_drv.dir_open_cb = lvgl_fs_dir_open;
234 fs_drv.dir_read_cb = lvgl_fs_dir_read;
235 fs_drv.dir_close_cb = lvgl_fs_dir_close;
236
237 lv_fs_drv_register(&fs_drv);
238 }
239