You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
4.9 KiB
242 lines
4.9 KiB
/* |
|
* Copyright (c) 2018-2019 Jan Van Winkel <jan.van_winkel@dxplore.eu> |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <lvgl.h> |
|
#include <zephyr/kernel.h> |
|
#include <zephyr/fs/fs.h> |
|
#include "lvgl_fs.h" |
|
#include "lv_conf.h" |
|
#include LV_STDLIB_INCLUDE |
|
|
|
static bool lvgl_fs_ready(lv_fs_drv_t *drv) |
|
{ |
|
return true; |
|
} |
|
|
|
static lv_fs_res_t errno_to_lv_fs_res(int err) |
|
{ |
|
switch (err) { |
|
case 0: |
|
return LV_FS_RES_OK; |
|
case -EIO: |
|
/*Low level hardware error*/ |
|
return LV_FS_RES_HW_ERR; |
|
case -EBADF: |
|
/*Error in the file system structure */ |
|
return LV_FS_RES_FS_ERR; |
|
case -ENOENT: |
|
/*Driver, file or directory is not exists*/ |
|
return LV_FS_RES_NOT_EX; |
|
case -EFBIG: |
|
/*Disk full*/ |
|
return LV_FS_RES_FULL; |
|
case -EACCES: |
|
/*Access denied. Check 'fs_open' modes and write protect*/ |
|
return LV_FS_RES_DENIED; |
|
case -EBUSY: |
|
/*The file system now can't handle it, try later*/ |
|
return LV_FS_RES_BUSY; |
|
case -ENOMEM: |
|
/*Not enough memory for an internal operation*/ |
|
return LV_FS_RES_OUT_OF_MEM; |
|
case -EINVAL: |
|
/*Invalid parameter among arguments*/ |
|
return LV_FS_RES_INV_PARAM; |
|
case -ENOTSUP: |
|
/*Not supported by the filesystem*/ |
|
return LV_FS_RES_NOT_IMP; |
|
default: |
|
return LV_FS_RES_UNKNOWN; |
|
} |
|
} |
|
|
|
static void *lvgl_fs_open(lv_fs_drv_t *drv, const char *path, lv_fs_mode_t mode) |
|
{ |
|
int err; |
|
int zmode = 0; |
|
void *file; |
|
|
|
/* LVGL is passing absolute paths without the root slash add it back |
|
* by decrementing the path pointer. |
|
*/ |
|
path--; |
|
|
|
zmode |= (mode & LV_FS_MODE_WR) ? FS_O_WRITE | FS_O_CREATE : 0; |
|
zmode |= (mode & LV_FS_MODE_RD) ? FS_O_READ : 0; |
|
|
|
if (zmode == 0) { |
|
return NULL; |
|
} |
|
|
|
file = lv_malloc(sizeof(struct fs_file_t)); |
|
if (!file) { |
|
return NULL; |
|
} |
|
|
|
fs_file_t_init((struct fs_file_t *)file); |
|
|
|
err = fs_open((struct fs_file_t *)file, path, zmode); |
|
if (err) { |
|
lv_free(file); |
|
return NULL; |
|
} |
|
|
|
return file; |
|
} |
|
|
|
static lv_fs_res_t lvgl_fs_close(lv_fs_drv_t *drv, void *file) |
|
{ |
|
int err; |
|
|
|
err = fs_close((struct fs_file_t *)file); |
|
lv_free(file); |
|
return errno_to_lv_fs_res(err); |
|
} |
|
|
|
static lv_fs_res_t lvgl_fs_read(lv_fs_drv_t *drv, void *file, void *buf, uint32_t btr, uint32_t *br) |
|
{ |
|
int err; |
|
|
|
err = fs_read((struct fs_file_t *)file, buf, btr); |
|
if (err > 0) { |
|
if (br != NULL) { |
|
*br = err; |
|
} |
|
err = 0; |
|
} else if (br != NULL) { |
|
*br = 0U; |
|
} |
|
return errno_to_lv_fs_res(err); |
|
} |
|
|
|
static lv_fs_res_t lvgl_fs_write(lv_fs_drv_t *drv, void *file, const void *buf, uint32_t btw, |
|
uint32_t *bw) |
|
{ |
|
int err; |
|
|
|
err = fs_write((struct fs_file_t *)file, buf, btw); |
|
if (err == btw) { |
|
if (bw != NULL) { |
|
*bw = btw; |
|
} |
|
err = 0; |
|
} else if (err < 0) { |
|
if (bw != NULL) { |
|
*bw = 0U; |
|
} |
|
} else { |
|
if (bw != NULL) { |
|
*bw = err; |
|
} |
|
err = -EFBIG; |
|
} |
|
return errno_to_lv_fs_res(err); |
|
} |
|
|
|
static lv_fs_res_t lvgl_fs_seek(lv_fs_drv_t *drv, void *file, uint32_t pos, lv_fs_whence_t whence) |
|
{ |
|
int err, fs_whence; |
|
|
|
switch (whence) { |
|
case LV_FS_SEEK_END: |
|
fs_whence = FS_SEEK_END; |
|
break; |
|
case LV_FS_SEEK_CUR: |
|
fs_whence = FS_SEEK_CUR; |
|
break; |
|
case LV_FS_SEEK_SET: |
|
default: |
|
fs_whence = FS_SEEK_SET; |
|
break; |
|
} |
|
|
|
err = fs_seek((struct fs_file_t *)file, pos, fs_whence); |
|
return errno_to_lv_fs_res(err); |
|
} |
|
|
|
static lv_fs_res_t lvgl_fs_tell(lv_fs_drv_t *drv, void *file, uint32_t *pos_p) |
|
{ |
|
off_t pos; |
|
|
|
pos = fs_tell((struct fs_file_t *)file); |
|
if (pos < 0) { |
|
return errno_to_lv_fs_res(pos); |
|
} |
|
|
|
*pos_p = pos; |
|
return LV_FS_RES_OK; |
|
} |
|
|
|
static void *lvgl_fs_dir_open(lv_fs_drv_t *drv, const char *path) |
|
{ |
|
void *dir; |
|
int err; |
|
|
|
/* LVGL is passing absolute paths without the root slash add it back |
|
* by decrementing the path pointer. |
|
*/ |
|
path--; |
|
|
|
dir = lv_malloc(sizeof(struct fs_dir_t)); |
|
if (!dir) { |
|
return NULL; |
|
} |
|
|
|
fs_dir_t_init((struct fs_dir_t *)dir); |
|
err = fs_opendir((struct fs_dir_t *)dir, path); |
|
if (err) { |
|
lv_free(dir); |
|
return NULL; |
|
} |
|
|
|
return dir; |
|
} |
|
|
|
static lv_fs_res_t lvgl_fs_dir_read(lv_fs_drv_t *drv, void *dir, char *fn, uint32_t fn_len) |
|
{ |
|
/* LVGL expects a string as return parameter but the format of the |
|
* string is not documented. |
|
*/ |
|
return LV_FS_RES_NOT_IMP; |
|
} |
|
|
|
static lv_fs_res_t lvgl_fs_dir_close(lv_fs_drv_t *drv, void *dir) |
|
{ |
|
int err; |
|
|
|
err = fs_closedir((struct fs_dir_t *)dir); |
|
lv_free(dir); |
|
return errno_to_lv_fs_res(err); |
|
} |
|
|
|
static lv_fs_drv_t fs_drv; |
|
|
|
void lvgl_fs_init(void) |
|
{ |
|
lv_fs_drv_init(&fs_drv); |
|
|
|
/* LVGL uses letter based mount points, just pass the root slash as a |
|
* letter. Note that LVGL will remove the drive letter, or in this case |
|
* the root slash, from the path passed via the FS callbacks. |
|
* Zephyr FS API assumes this slash is present so we will need to add |
|
* it back. |
|
*/ |
|
fs_drv.letter = '/'; |
|
fs_drv.ready_cb = lvgl_fs_ready; |
|
|
|
fs_drv.open_cb = lvgl_fs_open; |
|
fs_drv.close_cb = lvgl_fs_close; |
|
fs_drv.read_cb = lvgl_fs_read; |
|
fs_drv.write_cb = lvgl_fs_write; |
|
fs_drv.seek_cb = lvgl_fs_seek; |
|
fs_drv.tell_cb = lvgl_fs_tell; |
|
|
|
fs_drv.dir_open_cb = lvgl_fs_dir_open; |
|
fs_drv.dir_read_cb = lvgl_fs_dir_read; |
|
fs_drv.dir_close_cb = lvgl_fs_dir_close; |
|
|
|
lv_fs_drv_register(&fs_drv); |
|
}
|
|
|