Skip to content

Commit a7a022b

Browse files
committed
libs/lv_utils: Add lv_utils module.
Signed-off-by: lbuque <[email protected]>
1 parent 43666f5 commit a7a022b

File tree

15 files changed

+313
-128
lines changed

15 files changed

+313
-128
lines changed

m5stack/cmodules/adf_module/vfs_stream.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef enum {
5959
STREAM_TYPE_AMRWB,
6060
} wr_stream_type_t;
6161

62+
// micropython/extmod/vfs_lfs.c line: 115
6263
typedef struct _mp_obj_vfs_lfs2_t {
6364
mp_obj_base_t base;
6465
mp_vfs_blockdev_t blockdev;

m5stack/cmodules/cmodules.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@ endif()
4444

4545
if(MICROPY_PY_LVGL)
4646
include(${CMAKE_CURRENT_LIST_DIR}/lv_binding_micropython/micropython.cmake)
47+
include(${CMAKE_CURRENT_LIST_DIR}/lv_utils/lv_utils.cmake)
4748
endif()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
add_library(usermod_lv_utils INTERFACE)
6+
7+
target_sources(usermod_lv_utils INTERFACE
8+
${CMAKE_CURRENT_LIST_DIR}/modlv_utils.c
9+
)
10+
11+
target_include_directories(usermod_lv_utils INTERFACE
12+
${CMAKE_CURRENT_LIST_DIR}
13+
)
14+
15+
target_link_libraries(usermod INTERFACE usermod_lv_utils)
16+
17+
set_source_files_properties(
18+
${CMAKE_CURRENT_LIST_DIR}/modlv_utils.c
19+
PROPERTIES COMPILE_FLAGS
20+
"-Wno-discarded-qualifiers -Wno-implicit-int"
21+
)
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
7+
#include <esp_log.h>
8+
#include "py/runtime.h"
9+
#include "py/stream.h"
10+
11+
#include <extmod/vfs.h>
12+
#include <extmod/vfs_lfs.h>
13+
#include "extmod/vfs_fat.h"
14+
#include "lib/littlefs/lfs2.h"
15+
#include "lib/oofatfs/ff.h"
16+
17+
#include "lvgl/lvgl.h"
18+
#include "./../../cmodules/lv_binding_micropython/driver/include/common.h"
19+
#include "string.h"
20+
21+
static const char *TAG = "lv_utils";
22+
23+
// micropython/extmod/vfs_lfs.c line: 115
24+
typedef struct _mp_obj_vfs_lfs2_t {
25+
mp_obj_base_t base;
26+
mp_vfs_blockdev_t blockdev;
27+
bool enable_mtime;
28+
vstr_t cur_dir;
29+
struct lfs2_config config;
30+
lfs2_t lfs;
31+
} mp_obj_vfs_lfs2_t;
32+
33+
typedef struct vfs_stream_t {
34+
bool is_open;
35+
FATFS *fatfs;
36+
lfs2_t *lfs2;
37+
struct lfs2_file_config lfs2_file_conf;
38+
union {
39+
FIL fat_file;
40+
lfs2_file_t *lfs2_file;
41+
} file;
42+
} vfs_stream_t;
43+
44+
45+
static void *lv_utils_fs_open_cb(lv_fs_drv_t *drv, const char *path, lv_fs_mode_t mode) {
46+
LV_UNUSED(drv);
47+
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
48+
49+
ESP_LOGI("lv_utils", "fs_open_cb: path=%s, mode=%d\n", path, mode);
50+
51+
vfs_stream_t *vfs = lv_malloc(sizeof(vfs_stream_t));
52+
53+
const char *path_out;
54+
mp_vfs_mount_t *existing_mount = mp_vfs_lookup_path(path, &path_out);
55+
if (existing_mount == MP_VFS_NONE || existing_mount == MP_VFS_ROOT) {
56+
ESP_LOGE(TAG, "No vfs mount");
57+
goto _vfs_init_exit;
58+
}
59+
if (strstr(path, "flash")) {
60+
ESP_LOGD(TAG, "in flash");
61+
vfs->lfs2 = &((mp_obj_vfs_lfs2_t *)MP_OBJ_TO_PTR(existing_mount->obj))->lfs;
62+
} else if (strstr(path, "sd")) {
63+
ESP_LOGD(TAG, "in sd");
64+
vfs->fatfs = &((fs_user_mount_t *)MP_OBJ_TO_PTR(existing_mount->obj))->fatfs;
65+
}
66+
67+
if (vfs->lfs2) {
68+
vfs->lfs2_file_conf.buffer = lv_malloc(vfs->lfs2->cfg->cache_size * sizeof(uint8_t));
69+
vfs->file.lfs2_file = (lfs2_file_t *)lv_malloc(1 * sizeof(lfs2_file_t));
70+
int flags = 0;
71+
if (mode == LV_FS_MODE_WR) {
72+
flags = LFS2_O_WRONLY;
73+
} else if (mode == LV_FS_MODE_RD) {
74+
flags = LFS2_O_RDONLY;
75+
} else if (mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) {
76+
flags = LFS2_O_RDWR;
77+
}
78+
int res = lfs2_file_opencfg(vfs->lfs2, vfs->file.lfs2_file, path_out, flags, &vfs->lfs2_file_conf);
79+
if (res != LFS2_ERR_OK) {
80+
ESP_LOGE(TAG, "failed to open %s(%d)", path_out, res);
81+
goto _vfs_init_exit;
82+
}
83+
} else if (vfs->fatfs) {
84+
BYTE fmode = 0;
85+
if (mode == LV_FS_MODE_WR) {
86+
fmode = FA_WRITE;
87+
} else if (mode == LV_FS_MODE_RD) {
88+
fmode = FA_READ;
89+
} else if (mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) {
90+
fmode = FA_OPEN_ALWAYS;
91+
}
92+
FRESULT ret = f_open(vfs->fatfs, &vfs->file.fat_file, path_out, fmode);
93+
if (ret != FR_OK) {
94+
ESP_LOGE(TAG, "failed to open %s(%d)", path_out, ret);
95+
goto _vfs_init_exit;
96+
}
97+
}
98+
99+
return vfs;
100+
_vfs_init_exit:
101+
if (vfs->lfs2_file_conf.buffer) {
102+
lv_free(vfs->lfs2_file_conf.buffer);
103+
}
104+
if (vfs->file.lfs2_file) {
105+
lv_free(vfs->file.lfs2_file);
106+
}
107+
lv_free(vfs);
108+
109+
return NULL;
110+
}
111+
DEFINE_PTR_OBJ(lv_utils_fs_open_cb);
112+
113+
114+
static lv_fs_res_t lv_utils_fs_read_cb(lv_fs_drv_t *drv, void *file_p, void *buf, uint32_t btr, uint32_t *br) {
115+
LV_UNUSED(drv);
116+
vfs_stream_t *vfs = file_p;
117+
118+
if (vfs->lfs2) {
119+
*br = lfs2_file_read(vfs->lfs2, vfs->file.lfs2_file, (uint8_t *)buf, btr);
120+
return (int32_t)(*br) < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK;
121+
} else if (vfs->fatfs) {
122+
FRESULT res = f_read(&vfs->file.fat_file, buf, btr, (UINT *)br);
123+
return res == FR_OK ? LV_FS_RES_OK : LV_FS_RES_UNKNOWN;
124+
}
125+
126+
return LV_FS_RES_UNKNOWN;
127+
}
128+
DEFINE_PTR_OBJ(lv_utils_fs_read_cb);
129+
130+
131+
static lv_fs_res_t lv_utils_fs_write_cb(lv_fs_drv_t *drv, void *file_p, const void *buf, uint32_t btw, uint32_t *bw) {
132+
LV_UNUSED(drv);
133+
vfs_stream_t *vfs = file_p;
134+
135+
if (vfs->lfs2) {
136+
*bw = lfs2_file_write(vfs->lfs2, vfs->file.lfs2_file, (uint8_t *)buf, btw);
137+
lfs2_file_sync(vfs->lfs2, vfs->file.lfs2_file);
138+
} else if (vfs->fatfs) {
139+
f_write(&vfs->file.fat_file, (uint8_t *)buf, btw, (UINT *)bw);
140+
f_sync(&vfs->file.fat_file);
141+
}
142+
return (int32_t)(*bw) < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK;
143+
}
144+
DEFINE_PTR_OBJ(lv_utils_fs_write_cb);
145+
146+
147+
static lv_fs_res_t lv_utils_fs_seek_cb(lv_fs_drv_t *drv, void *file_p, uint32_t pos, lv_fs_whence_t whence) {
148+
LV_UNUSED(drv);
149+
vfs_stream_t *vfs = file_p;
150+
151+
if (vfs->lfs2) {
152+
int mode = 0;
153+
if (whence == LV_FS_SEEK_SET) {
154+
mode = LFS2_SEEK_SET;
155+
} else if (whence == LV_FS_SEEK_CUR) {
156+
mode = LFS2_SEEK_CUR;
157+
} else if (whence == LV_FS_SEEK_END) {
158+
mode = LFS2_SEEK_END;
159+
}
160+
161+
int rc = lfs2_file_seek(vfs->lfs2, vfs->file.lfs2_file, pos, mode);
162+
return rc < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK;
163+
} else if (vfs->fatfs) {
164+
FRESULT res = FR_INT_ERR;
165+
switch (whence) {
166+
case LV_FS_SEEK_SET:
167+
res = f_lseek(&vfs->file.fat_file, pos);
168+
break;
169+
case LV_FS_SEEK_CUR:
170+
res = f_lseek(&vfs->file.fat_file, f_tell((FIL *)&vfs->file.fat_file) + pos);
171+
break;
172+
case LV_FS_SEEK_END:
173+
res = f_lseek(&vfs->file.fat_file, f_size((FIL *)&vfs->file.fat_file) + pos);
174+
break;
175+
default:
176+
break;
177+
}
178+
return res == FR_OK ? LV_FS_RES_OK : LV_FS_RES_UNKNOWN;
179+
}
180+
181+
return LV_FS_RES_UNKNOWN;
182+
}
183+
DEFINE_PTR_OBJ(lv_utils_fs_seek_cb);
184+
185+
186+
static lv_fs_res_t lv_utils_fs_tell_cb(lv_fs_drv_t *drv, void *file_p, uint32_t *pos_p) {
187+
LV_UNUSED(drv);
188+
vfs_stream_t *vfs = file_p;
189+
190+
if (vfs->lfs2) {
191+
*pos_p = lfs2_file_tell(vfs->lfs2, vfs->file.lfs2_file);
192+
} else if (vfs->fatfs) {
193+
*pos_p = f_tell((FIL *)&vfs->file.fat_file);
194+
}
195+
196+
return (int32_t)(*pos_p) < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK;
197+
}
198+
DEFINE_PTR_OBJ(lv_utils_fs_tell_cb);
199+
200+
static lv_fs_res_t lv_utils_fs_close_cb(lv_fs_drv_t *drv, void *file_p) {
201+
LV_UNUSED(drv);
202+
vfs_stream_t *vfs = file_p;
203+
204+
if (vfs->lfs2) {
205+
lfs2_file_close(vfs->lfs2, vfs->file.lfs2_file);
206+
lv_free(vfs->file.lfs2_file);
207+
lv_free(vfs->lfs2_file_conf.buffer);
208+
} else if (vfs->fatfs) {
209+
f_close(&vfs->file.fat_file);
210+
}
211+
212+
return LV_FS_RES_OK;
213+
}
214+
DEFINE_PTR_OBJ(lv_utils_fs_close_cb);
215+
216+
217+
static const mp_rom_map_elem_t lv_utils_module_globals_table[] = {
218+
/* *FORMAT-OFF* */
219+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__lv_utils) },
220+
{ MP_ROM_QSTR(MP_QSTR_fs_open_cb), MP_ROM_PTR(&PTR_OBJ(lv_utils_fs_open_cb)) },
221+
{ MP_ROM_QSTR(MP_QSTR_fs_read_cb), MP_ROM_PTR(&PTR_OBJ(lv_utils_fs_read_cb)) },
222+
{ MP_ROM_QSTR(MP_QSTR_fs_write_cb), MP_ROM_PTR(&PTR_OBJ(lv_utils_fs_write_cb)) },
223+
{ MP_ROM_QSTR(MP_QSTR_fs_seek_cb), MP_ROM_PTR(&PTR_OBJ(lv_utils_fs_seek_cb)) },
224+
{ MP_ROM_QSTR(MP_QSTR_fs_tell_cb), MP_ROM_PTR(&PTR_OBJ(lv_utils_fs_tell_cb)) },
225+
{ MP_ROM_QSTR(MP_QSTR_fs_close_cb), MP_ROM_PTR(&PTR_OBJ(lv_utils_fs_close_cb)) },
226+
/* *FORMAT-ON* */
227+
};
228+
229+
static MP_DEFINE_CONST_DICT(lv_utils_module_globals, lv_utils_module_globals_table);
230+
231+
const mp_obj_module_t lv_utils_module = {
232+
.base = {&mp_type_module},
233+
.globals = (mp_obj_dict_t *)&lv_utils_module_globals,
234+
};
235+
236+
MP_REGISTER_MODULE(MP_QSTR__lv_utils, lv_utils_module);

m5stack/cmodules/m5unified/m5unified.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ endif()
3030

3131
target_link_libraries(usermod INTERFACE usermod_M5UNIFIED)
3232

33-
# target_compile_options(usermod_M5UNIFIED INTERFACE "-g")
33+
target_compile_options(usermod_M5UNIFIED INTERFACE "-g")
3434

3535
set_source_files_properties(
3636
${CMAKE_CURRENT_LIST_DIR}/m5unified.c

m5stack/components/M5Unified/mpy_lvgl.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ void gfx_lvgl_flush(lv_display_t *disp_drv, const lv_area_t * area, uint8_t * px
88
{
99
mp_obj_t gfx_obj = mp_obj_dict_get(disp_drv->user_data, MP_OBJ_NEW_QSTR(MP_QSTR_display));
1010
M5GFX *lvgl_gfx = (M5GFX *)((((gfx_obj_t *)MP_OBJ_TO_PTR(gfx_obj))->gfx));
11-
// ESP_LOGE("lvgl", "gfx: %p", lvgl_gfx);
1211
if (lvgl_gfx == nullptr) {
1312
return;
1413
}

m5stack/components/M5Unified/mpy_m5lfs2.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <extmod/vfs_lfs.h>
1010
#include <lib/littlefs/lfs2.h>
1111

12+
13+
// micropython/extmod/vfs_lfs.c line: 115
1214
typedef struct _mp_obj_vfs_lfs2_t {
1315
mp_obj_base_t base;
1416
mp_vfs_blockdev_t blockdev;

m5stack/libs/lv_utils/__init__.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import lvgl as lv
6+
import _lv_utils
7+
8+
9+
def fs_register(fs_drv, letter, cache_size=500):
10+
fs_drv.init()
11+
fs_drv.letter = ord(letter)
12+
fs_drv.open_cb = _lv_utils.fs_open_cb
13+
fs_drv.read_cb = _lv_utils.fs_read_cb
14+
fs_drv.write_cb = _lv_utils.fs_write_cb
15+
fs_drv.seek_cb = _lv_utils.fs_seek_cb
16+
fs_drv.tell_cb = _lv_utils.fs_tell_cb
17+
fs_drv.close_cb = _lv_utils.fs_close_cb
18+
19+
if cache_size >= 0:
20+
fs_drv.cache_size = cache_size
21+
22+
fs_drv.register()
File renamed without changes.

m5stack/libs/lvgl/manifest.py renamed to m5stack/libs/lv_utils/manifest.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,9 @@
22
#
33
# SPDX-License-Identifier: MIT
44

5-
module("lv_utils.py")
6-
module("fs_driver.py")
5+
package(
6+
"lv_utils",
7+
("__init__.py",),
8+
base_path="..",
9+
opt=0,
10+
)

0 commit comments

Comments
 (0)