From ff3142d0abf6da46d6a713f54b98f95d576de002 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Fri, 28 Jul 2023 15:46:31 +0200 Subject: [PATCH] modules: lvgl: Move gluecode back to zephyr main repo Moves back the module specific gluecode into the main repository Signed-off-by: Fabian Blatz --- MAINTAINERS.yml | 2 +- modules/Kconfig | 5 +- modules/Kconfig.lvgl | 66 ----- modules/lvgl/CMakeLists.txt | 229 ++++++++++++++++++ modules/lvgl/Kconfig | 61 +++++ modules/lvgl/Kconfig.input | 41 ++++ modules/lvgl/Kconfig.memory | 119 +++++++++ modules/lvgl/Kconfig.shell | 19 ++ modules/lvgl/lv_conf.h | 50 ++++ modules/lvgl/lvgl.c | 385 ++++++++++++++++++++++++++++++ modules/lvgl/lvgl_display.c | 56 +++++ modules/lvgl/lvgl_display.h | 45 ++++ modules/lvgl/lvgl_display_16bit.c | 34 +++ modules/lvgl/lvgl_display_24bit.c | 48 ++++ modules/lvgl/lvgl_display_32bit.c | 41 ++++ modules/lvgl/lvgl_display_mono.c | 109 +++++++++ modules/lvgl/lvgl_fs.c | 226 ++++++++++++++++++ modules/lvgl/lvgl_fs.h | 20 ++ modules/lvgl/lvgl_mem.c | 67 ++++++ modules/lvgl/lvgl_mem.h | 29 +++ modules/lvgl/lvgl_shell.c | 204 ++++++++++++++++ west.yml | 2 +- 22 files changed, 1789 insertions(+), 69 deletions(-) delete mode 100644 modules/Kconfig.lvgl create mode 100644 modules/lvgl/CMakeLists.txt create mode 100644 modules/lvgl/Kconfig create mode 100644 modules/lvgl/Kconfig.input create mode 100644 modules/lvgl/Kconfig.memory create mode 100644 modules/lvgl/Kconfig.shell create mode 100644 modules/lvgl/lv_conf.h create mode 100644 modules/lvgl/lvgl.c create mode 100644 modules/lvgl/lvgl_display.c create mode 100644 modules/lvgl/lvgl_display.h create mode 100644 modules/lvgl/lvgl_display_16bit.c create mode 100644 modules/lvgl/lvgl_display_24bit.c create mode 100644 modules/lvgl/lvgl_display_32bit.c create mode 100644 modules/lvgl/lvgl_display_mono.c create mode 100644 modules/lvgl/lvgl_fs.c create mode 100644 modules/lvgl/lvgl_fs.h create mode 100644 modules/lvgl/lvgl_mem.c create mode 100644 modules/lvgl/lvgl_mem.h create mode 100644 modules/lvgl/lvgl_shell.c diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index d37cf5ac4d1c0bb..ee6bfd3e86e2c31 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -3095,7 +3095,7 @@ West: - brgl - pdgendt files: - - modules/Kconfig.lvgl + - modules/lvgl/ - tests/lib/gui/lvgl/ labels: - manifest-lvgl diff --git a/modules/Kconfig b/modules/Kconfig index f35dfdcbd486ccb..e581c3334f52044 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -24,7 +24,7 @@ source "modules/Kconfig.esp32" source "modules/Kconfig.imx" source "modules/Kconfig.infineon" source "modules/Kconfig.libmetal" -source "modules/Kconfig.lvgl" +source "modules/lvgl/Kconfig" source "modules/Kconfig.mcux" source "modules/Kconfig.microchip" source "modules/Kconfig.nuvoton" @@ -104,6 +104,9 @@ comment "THRIFT module not available." comment "Segger module not available." depends on !ZEPHYR_SEGGER_MODULE +comment "LVGL module not available." + depends on !ZEPHYR_LVGL_MODULE + # This ensures that symbols are available in Kconfig for dependency checking # and referencing, while keeping the settings themselves unavailable when the # modules are not present in the workspace diff --git a/modules/Kconfig.lvgl b/modules/Kconfig.lvgl deleted file mode 100644 index b51c5bc4e39058b..000000000000000 --- a/modules/Kconfig.lvgl +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2022 Huawei Inc. -# SPDX-License-Identifier: Apache-2.0 - -config LVGL - bool "LVGL GUI library" - help - This option enables the LVGL GUI library. - -if LVGL - -config LV_DPI_DEF - int - -config LV_Z_BITS_PER_PIXEL - int - -config LV_Z_DOUBLE_VDB - bool - -config LV_Z_FULL_REFRESH - bool - -config LV_Z_VBD_CUSTOM_SECTION - bool - -config LV_Z_VDB_ALIGN - int - -config LV_Z_VDB_SIZE - int - -config LV_Z_POINTER_KSCAN - bool - -config LV_Z_POINTER_KSCAN_MSGQ_COUNT - int - default 10 - -config LV_Z_POINTER_KSCAN_SWAP_XY - bool - -config LV_Z_POINTER_KSCAN_INVERT_X - bool - -config LV_Z_POINTER_KSCAN_INVERT_Y - bool - -choice LV_COLOR_DEPTH - default LV_COLOR_DEPTH_16 - prompt "Color depth (bits per pixel)" - depends on LVGL - - config LV_COLOR_DEPTH_32 - bool "32: ARGB8888" - config LV_COLOR_DEPTH_16 - bool "16: RGB565" - config LV_COLOR_DEPTH_8 - bool "8: RGB232" - config LV_COLOR_DEPTH_1 - bool "1: monochrome" -endchoice - -config LV_COLOR_16_SWAP - bool - -endif diff --git a/modules/lvgl/CMakeLists.txt b/modules/lvgl/CMakeLists.txt new file mode 100644 index 000000000000000..8aa99794411c8c0 --- /dev/null +++ b/modules/lvgl/CMakeLists.txt @@ -0,0 +1,229 @@ +# Copyright (c) 2019 jan.van_winkel@dxplore.eu +# Copyright (c) 2020 Teslabs Engineering S.L. +# Copyright (c) 2023 Fabian Blatz +# +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_LVGL) + +set(ZEPHYR_CURRENT_LIBRARY lvgl) +set(LVGL_DIR ${ZEPHYR_LVGL_MODULE_DIR}) + +zephyr_interface_library_named(LVGL) +zephyr_library() + +zephyr_include_directories(${LVGL_DIR}/src/) +zephyr_include_directories(.) + +zephyr_compile_definitions(LV_CONF_INCLUDE_SIMPLE=1) +zephyr_compile_definitions(LV_CONF_PATH=${CMAKE_CURRENT_SOURCE_DIR}/lv_conf.h) + +zephyr_library_sources( + ${LVGL_DIR}/src/core/lv_disp.c + ${LVGL_DIR}/src/core/lv_event.c + ${LVGL_DIR}/src/core/lv_group.c + ${LVGL_DIR}/src/core/lv_indev.c + ${LVGL_DIR}/src/core/lv_indev_scroll.c + ${LVGL_DIR}/src/core/lv_obj.c + ${LVGL_DIR}/src/core/lv_obj_class.c + ${LVGL_DIR}/src/core/lv_obj_draw.c + ${LVGL_DIR}/src/core/lv_obj_pos.c + ${LVGL_DIR}/src/core/lv_obj_scroll.c + ${LVGL_DIR}/src/core/lv_obj_style.c + ${LVGL_DIR}/src/core/lv_obj_style_gen.c + ${LVGL_DIR}/src/core/lv_obj_tree.c + ${LVGL_DIR}/src/core/lv_refr.c + ${LVGL_DIR}/src/core/lv_theme.c + + ${LVGL_DIR}/src/draw/arm2d/lv_gpu_arm2d.c + ${LVGL_DIR}/src/draw/lv_draw.c + ${LVGL_DIR}/src/draw/lv_draw_arc.c + ${LVGL_DIR}/src/draw/lv_draw_img.c + ${LVGL_DIR}/src/draw/lv_draw_label.c + ${LVGL_DIR}/src/draw/lv_draw_layer.c + ${LVGL_DIR}/src/draw/lv_draw_line.c + ${LVGL_DIR}/src/draw/lv_draw_mask.c + ${LVGL_DIR}/src/draw/lv_draw_rect.c + ${LVGL_DIR}/src/draw/lv_draw_transform.c + ${LVGL_DIR}/src/draw/lv_draw_triangle.c + ${LVGL_DIR}/src/draw/lv_img_buf.c + ${LVGL_DIR}/src/draw/lv_img_cache.c + ${LVGL_DIR}/src/draw/lv_img_decoder.c + ${LVGL_DIR}/src/draw/nxp/pxp/lv_draw_pxp_blend.c + ${LVGL_DIR}/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c + ${LVGL_DIR}/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_arc.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_blend.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_rect.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_arc.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_bg.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_composite.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_img.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_label.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_layer.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_line.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_mask.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_polygon.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_rect.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_stack_blur.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_texture_cache.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_utils.c + ${LVGL_DIR}/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_arc.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_blend.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_dither.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_gradient.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_img.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_layer.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_letter.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_line.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_polygon.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_rect.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw_transform.c + ${LVGL_DIR}/src/draw/swm341_dma2d/lv_gpu_swm341_dma2d.c + + ${LVGL_DIR}/src/extra/layouts/flex/lv_flex.c + ${LVGL_DIR}/src/extra/layouts/grid/lv_grid.c + ${LVGL_DIR}/src/extra/libs/bmp/lv_bmp.c + ${LVGL_DIR}/src/extra/libs/ffmpeg/lv_ffmpeg.c + ${LVGL_DIR}/src/extra/libs/freetype/lv_freetype.c + ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_fatfs.c + ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_posix.c + ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_stdio.c + ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_win32.c + ${LVGL_DIR}/src/extra/libs/gif/gifdec.c + ${LVGL_DIR}/src/extra/libs/gif/lv_gif.c + ${LVGL_DIR}/src/extra/libs/png/lodepng.c + ${LVGL_DIR}/src/extra/libs/png/lv_png.c + ${LVGL_DIR}/src/extra/libs/qrcode/lv_qrcode.c + ${LVGL_DIR}/src/extra/libs/qrcode/qrcodegen.c + ${LVGL_DIR}/src/extra/libs/rlottie/lv_rlottie.c + ${LVGL_DIR}/src/extra/libs/sjpg/lv_sjpg.c + ${LVGL_DIR}/src/extra/libs/sjpg/tjpgd.c + ${LVGL_DIR}/src/extra/lv_extra.c + ${LVGL_DIR}/src/extra/others/fragment/lv_fragment.c + ${LVGL_DIR}/src/extra/others/fragment/lv_fragment_manager.c + ${LVGL_DIR}/src/extra/others/gridnav/lv_gridnav.c + ${LVGL_DIR}/src/extra/others/ime/lv_ime_pinyin.c + ${LVGL_DIR}/src/extra/others/imgfont/lv_imgfont.c + ${LVGL_DIR}/src/extra/others/monkey/lv_monkey.c + ${LVGL_DIR}/src/extra/others/msg/lv_msg.c + ${LVGL_DIR}/src/extra/others/snapshot/lv_snapshot.c + ${LVGL_DIR}/src/extra/themes/basic/lv_theme_basic.c + ${LVGL_DIR}/src/extra/themes/default/lv_theme_default.c + ${LVGL_DIR}/src/extra/themes/mono/lv_theme_mono.c + ${LVGL_DIR}/src/extra/widgets/animimg/lv_animimg.c + ${LVGL_DIR}/src/extra/widgets/calendar/lv_calendar.c + ${LVGL_DIR}/src/extra/widgets/calendar/lv_calendar_header_arrow.c + ${LVGL_DIR}/src/extra/widgets/calendar/lv_calendar_header_dropdown.c + ${LVGL_DIR}/src/extra/widgets/chart/lv_chart.c + ${LVGL_DIR}/src/extra/widgets/colorwheel/lv_colorwheel.c + ${LVGL_DIR}/src/extra/widgets/imgbtn/lv_imgbtn.c + ${LVGL_DIR}/src/extra/widgets/keyboard/lv_keyboard.c + ${LVGL_DIR}/src/extra/widgets/led/lv_led.c + ${LVGL_DIR}/src/extra/widgets/list/lv_list.c + ${LVGL_DIR}/src/extra/widgets/menu/lv_menu.c + ${LVGL_DIR}/src/extra/widgets/meter/lv_meter.c + ${LVGL_DIR}/src/extra/widgets/msgbox/lv_msgbox.c + ${LVGL_DIR}/src/extra/widgets/span/lv_span.c + ${LVGL_DIR}/src/extra/widgets/spinbox/lv_spinbox.c + ${LVGL_DIR}/src/extra/widgets/spinner/lv_spinner.c + ${LVGL_DIR}/src/extra/widgets/tabview/lv_tabview.c + ${LVGL_DIR}/src/extra/widgets/tileview/lv_tileview.c + ${LVGL_DIR}/src/extra/widgets/win/lv_win.c + + ${LVGL_DIR}/src/font/lv_font.c + ${LVGL_DIR}/src/font/lv_font_dejavu_16_persian_hebrew.c + ${LVGL_DIR}/src/font/lv_font_fmt_txt.c + ${LVGL_DIR}/src/font/lv_font_loader.c + ${LVGL_DIR}/src/font/lv_font_montserrat_10.c + ${LVGL_DIR}/src/font/lv_font_montserrat_12.c + ${LVGL_DIR}/src/font/lv_font_montserrat_12_subpx.c + ${LVGL_DIR}/src/font/lv_font_montserrat_14.c + ${LVGL_DIR}/src/font/lv_font_montserrat_16.c + ${LVGL_DIR}/src/font/lv_font_montserrat_18.c + ${LVGL_DIR}/src/font/lv_font_montserrat_20.c + ${LVGL_DIR}/src/font/lv_font_montserrat_22.c + ${LVGL_DIR}/src/font/lv_font_montserrat_24.c + ${LVGL_DIR}/src/font/lv_font_montserrat_26.c + ${LVGL_DIR}/src/font/lv_font_montserrat_28.c + ${LVGL_DIR}/src/font/lv_font_montserrat_28_compressed.c + ${LVGL_DIR}/src/font/lv_font_montserrat_30.c + ${LVGL_DIR}/src/font/lv_font_montserrat_32.c + ${LVGL_DIR}/src/font/lv_font_montserrat_34.c + ${LVGL_DIR}/src/font/lv_font_montserrat_36.c + ${LVGL_DIR}/src/font/lv_font_montserrat_38.c + ${LVGL_DIR}/src/font/lv_font_montserrat_40.c + ${LVGL_DIR}/src/font/lv_font_montserrat_42.c + ${LVGL_DIR}/src/font/lv_font_montserrat_44.c + ${LVGL_DIR}/src/font/lv_font_montserrat_46.c + ${LVGL_DIR}/src/font/lv_font_montserrat_48.c + ${LVGL_DIR}/src/font/lv_font_montserrat_8.c + ${LVGL_DIR}/src/font/lv_font_simsun_16_cjk.c + ${LVGL_DIR}/src/font/lv_font_unscii_16.c + ${LVGL_DIR}/src/font/lv_font_unscii_8.c + + ${LVGL_DIR}/src/hal/lv_hal_disp.c + ${LVGL_DIR}/src/hal/lv_hal_indev.c + ${LVGL_DIR}/src/hal/lv_hal_tick.c + + ${LVGL_DIR}/src/misc/lv_anim.c + ${LVGL_DIR}/src/misc/lv_anim_timeline.c + ${LVGL_DIR}/src/misc/lv_area.c + ${LVGL_DIR}/src/misc/lv_async.c + ${LVGL_DIR}/src/misc/lv_bidi.c + ${LVGL_DIR}/src/misc/lv_color.c + ${LVGL_DIR}/src/misc/lv_fs.c + ${LVGL_DIR}/src/misc/lv_gc.c + ${LVGL_DIR}/src/misc/lv_ll.c + ${LVGL_DIR}/src/misc/lv_log.c + ${LVGL_DIR}/src/misc/lv_lru.c + ${LVGL_DIR}/src/misc/lv_math.c + ${LVGL_DIR}/src/misc/lv_mem.c + ${LVGL_DIR}/src/misc/lv_printf.c + ${LVGL_DIR}/src/misc/lv_style.c + ${LVGL_DIR}/src/misc/lv_style_gen.c + ${LVGL_DIR}/src/misc/lv_templ.c + ${LVGL_DIR}/src/misc/lv_timer.c + ${LVGL_DIR}/src/misc/lv_tlsf.c + ${LVGL_DIR}/src/misc/lv_txt.c + ${LVGL_DIR}/src/misc/lv_txt_ap.c + ${LVGL_DIR}/src/misc/lv_utils.c + + ${LVGL_DIR}/src/widgets/lv_arc.c + ${LVGL_DIR}/src/widgets/lv_bar.c + ${LVGL_DIR}/src/widgets/lv_btn.c + ${LVGL_DIR}/src/widgets/lv_btnmatrix.c + ${LVGL_DIR}/src/widgets/lv_canvas.c + ${LVGL_DIR}/src/widgets/lv_checkbox.c + ${LVGL_DIR}/src/widgets/lv_dropdown.c + ${LVGL_DIR}/src/widgets/lv_img.c + ${LVGL_DIR}/src/widgets/lv_label.c + ${LVGL_DIR}/src/widgets/lv_line.c + ${LVGL_DIR}/src/widgets/lv_objx_templ.c + ${LVGL_DIR}/src/widgets/lv_roller.c + ${LVGL_DIR}/src/widgets/lv_slider.c + ${LVGL_DIR}/src/widgets/lv_switch.c + ${LVGL_DIR}/src/widgets/lv_table.c + ${LVGL_DIR}/src/widgets/lv_textarea.c + + lvgl.c + lvgl_display.c + lvgl_display_mono.c + lvgl_display_16bit.c + lvgl_display_24bit.c + lvgl_display_32bit.c + lvgl_display_mono.c +) + +zephyr_library_sources_ifdef(CONFIG_LV_Z_USE_FILESYSTEM lvgl_fs.c) +zephyr_library_sources_ifdef(CONFIG_LV_Z_MEM_POOL_SYS_HEAP lvgl_mem.c) +zephyr_library_sources_ifdef(CONFIG_LV_Z_SHELL lvgl_shell.c) + +zephyr_library_link_libraries(LVGL) +target_link_libraries(LVGL INTERFACE zephyr_interface) + +endif() diff --git a/modules/lvgl/Kconfig b/modules/lvgl/Kconfig new file mode 100644 index 000000000000000..9d1b1bc1da1cd2a --- /dev/null +++ b/modules/lvgl/Kconfig @@ -0,0 +1,61 @@ +# Copyright (c) 2023 Fabian Blatz +# SPDX-License-Identifier: Apache-2.0 + +config ZEPHYR_LVGL_MODULE + bool + +config LVGL + bool "LVGL support" + help + This option enables the LVGL graphics library. + +if LVGL + +config LV_USE_MONKEY + bool + +config LV_DPI_DEF + int + +config LV_CONF_SKIP + bool + default n + +config APP_LINK_WITH_LVGL + bool "Link 'app' with LVGL" + default y + help + Add LVGL header files to the 'app' include path. It may be + disabled if the include paths for LVGL are causing aliasing + issues for 'app'. + +config LV_Z_USE_FILESYSTEM + bool "LVGL file system support" + depends on FILE_SYSTEM + default y if FILE_SYSTEM + help + Enable LittlevGL file system + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_16 + prompt "Color depth (bits per pixel)" + + config LV_COLOR_DEPTH_32 + bool "32: ARGB8888" + config LV_COLOR_DEPTH_16 + bool "16: RGB565" + config LV_COLOR_DEPTH_8 + bool "8: RGB232" + config LV_COLOR_DEPTH_1 + bool "1: monochrome" +endchoice + +config LV_COLOR_16_SWAP + bool + +rsource "Kconfig.memory" +rsource "Kconfig.input" +rsource "Kconfig.shell" + + +endif diff --git a/modules/lvgl/Kconfig.input b/modules/lvgl/Kconfig.input new file mode 100644 index 000000000000000..b743d353802b221 --- /dev/null +++ b/modules/lvgl/Kconfig.input @@ -0,0 +1,41 @@ +# Copyright (c) 2018-2019 Jan Van Winkel +# Copyright (c) 2020 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +menu "Input device settings" + +config LV_Z_POINTER_KSCAN + bool "Keyboard scan pointer input" + depends on KSCAN + help + Enable keyboard scan pointer input + +if LV_Z_POINTER_KSCAN + +config LV_Z_POINTER_KSCAN_MSGQ_COUNT + int "Keyboard scan message queue count maximum" + default 10 + help + Maximum number of items in the keyboard scan message queue. + +config LV_Z_POINTER_KSCAN_SWAP_XY + bool "Swap keyboard scan X,Y axes" + help + Swap keyboard scan X,Y axes. This option can be used to align keyboard + scan coordinates with the display. + +config LV_Z_POINTER_KSCAN_INVERT_X + bool "Invert keyboard scan X axis" + help + Invert keyboard scan X axis. This option can be used to align keyboard + scan coordinates with the display. + +config LV_Z_POINTER_KSCAN_INVERT_Y + bool "Invert keyboard scan Y axis" + help + Invert keyboard scan Y axis. This option can be used to align keyboard + scan coordinates with the display. + +endif # LV_Z_POINTER_KSCAN + +endmenu diff --git a/modules/lvgl/Kconfig.memory b/modules/lvgl/Kconfig.memory new file mode 100644 index 000000000000000..29ccc8e910a0311 --- /dev/null +++ b/modules/lvgl/Kconfig.memory @@ -0,0 +1,119 @@ +# Copyright (c) 2018-2019 Jan Van Winkel +# Copyright (c) 2020 Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +menu "Memory manager settings" + +config LV_Z_BITS_PER_PIXEL + int "Bits per pixel" + default 32 + range 1 32 + depends on LV_Z_BUFFER_ALLOC_STATIC + help + Number of bits per pixel. + +choice LV_Z_MEMORY_POOL + prompt "Memory pool" + default LV_Z_MEM_POOL_SYS_HEAP + help + Memory pool to use for lvgl allocated objects + + config LV_Z_MEM_POOL_HEAP_LIB_C + bool "C library Heap" + depends on !MINIMAL_LIBC || (MINIMAL_LIBC_MALLOC_ARENA_SIZE != 0) + help + Use C library malloc and free to allocate objects on the C library heap + + config LV_Z_MEM_POOL_SYS_HEAP + bool "User space lvgl pool" + help + Use a dedicated memory pool from a private sys heap. + +endchoice + +if LV_Z_MEM_POOL_SYS_HEAP + +config LV_Z_MEM_POOL_MIN_SIZE + int "Minimum memory pool block size" + default 16 + help + Size of the smallest block in the memory pool in bytes + +config LV_Z_MEM_POOL_MAX_SIZE + int "Maximum memory pool block size" + default 2048 + help + Size of the largest block in the memory pool in bytes + +config LV_Z_MEM_POOL_NUMBER_BLOCKS + int "Number of max size blocks in memory pool" + default 1 + help + Number of maximum sized blocks in the memory pool. + +endif + +config LV_Z_VDB_SIZE + int "Rendering buffer size" + default 10 + range 1 100 + help + Size of the buffer used for rendering screen content as a percentage + of total display size. + +config LV_Z_DOUBLE_VDB + bool "Use two rendering buffers" + help + Use two buffers to render and flush data in parallel + +config LV_Z_FULL_REFRESH + bool "Force full refresh mode" + help + Force full refresh of display on update. When combined with + LV_Z_VDB_SIZE, this setting can improve performance for display + controllers that require a framebuffer to be present in system memory, + since the controller can render the LVGL framebuffer directly + +config LV_Z_VDB_ALIGN + int "Rending buffer alignment" + default 4 + depends on LV_Z_BUFFER_ALLOC_STATIC + help + Rendering buffer alignment. Depending on chosen color depth, + buffer may be accessed as a uint8_t *, uint16_t *, or uint32_t *, + so buffer must be aligned to prevent unaligned memory access + +config LV_Z_VBD_CUSTOM_SECTION + bool "Link rendering buffers to custom section" + depends on LV_Z_BUFFER_ALLOC_STATIC + help + Place LVGL rendering buffers in custom section, with tag ".lvgl_buf". + This can be used by custom linker scripts to relocate the LVGL + rendering buffers to a custom location, such as tightly coupled or + external memory. + +choice LV_Z_RENDERING_BUFFER_ALLOCATION + prompt "Rendering Buffer Allocation" + default LV_Z_BUFFER_ALLOC_STATIC + help + Type of allocation that should be used for allocating rendering buffers + +config LV_Z_BUFFER_ALLOC_STATIC + bool "Static" + help + Rendering buffers are statically allocated based on the following + configuration parameters: + * Horizontal screen resolution + * Vertical screen resolution + * Rendering buffer size + * Bytes per pixel + +config LV_Z_BUFFER_ALLOC_DYNAMIC + bool "Dynamic" + help + Rendering buffers are dynamically allocated based on the actual + display parameters + +endchoice + +endmenu diff --git a/modules/lvgl/Kconfig.shell b/modules/lvgl/Kconfig.shell new file mode 100644 index 000000000000000..d4b04b506f4d6da --- /dev/null +++ b/modules/lvgl/Kconfig.shell @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Fabian Blatz +# SPDX-License-Identifier: Apache-2.0 + +config LV_Z_SHELL + bool "LVGL Shell" + depends on SHELL + help + Enable LVGL shell for testing. + +if LV_Z_SHELL + +config LV_Z_MAX_MONKEY_COUNT + int "Maximum number of monkeys" + default 4 + depends on LV_USE_MONKEY + help + Number of monkey instances that can exist in parallel + +endif diff --git a/modules/lvgl/lv_conf.h b/modules/lvgl/lv_conf.h new file mode 100644 index 000000000000000..cfa2e4b96216b15 --- /dev/null +++ b/modules/lvgl/lv_conf.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018-2020 Jan Van Winkel + * Copyright (c) 2020 Teslabs Engineering S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_GUI_LVGL_LV_CONF_H_ +#define ZEPHYR_LIB_GUI_LVGL_LV_CONF_H_ + +/* Memory manager settings */ + +#define LV_MEMCPY_MEMSET_STD 1 + +#if defined(CONFIG_LV_Z_MEM_POOL_HEAP_LIB_C) + +#define LV_MEM_CUSTOM_INCLUDE "stdlib.h" +#define LV_MEM_CUSTOM_ALLOC malloc +#define LV_MEM_CUSTOM_REALLOC realloc +#define LV_MEM_CUSTOM_FREE free + +#else + +#define LV_MEM_CUSTOM_INCLUDE "lvgl_mem.h" +#define LV_MEM_CUSTOM_ALLOC lvgl_malloc +#define LV_MEM_CUSTOM_REALLOC lvgl_realloc +#define LV_MEM_CUSTOM_FREE lvgl_free + +#endif + +/* HAL settings */ + +#define LV_TICK_CUSTOM 1 +#define LV_TICK_CUSTOM_INCLUDE +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (k_uptime_get_32()) + +/* Misc settings */ + +#define LV_SPRINTF_CUSTOM 1 +#define LV_SPRINTF_INCLUDE "stdio.h" +#define lv_snprintf snprintf +#define lv_vsnprintf vsnprintf + +/* + * Needed because of a workaround for a GCC bug, + * see https://github.com/lvgl/lvgl/issues/3078 + */ +#define LV_CONF_SUPPRESS_DEFINE_CHECK 1 + +#endif /* ZEPHYR_LIB_GUI_LVGL_LV_CONF_H_ */ diff --git a/modules/lvgl/lvgl.c b/modules/lvgl/lvgl.c new file mode 100644 index 000000000000000..6b7a68acd5bd224 --- /dev/null +++ b/modules/lvgl/lvgl.c @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2018-2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "lvgl_display.h" +#ifdef CONFIG_LV_Z_USE_FILESYSTEM +#include "lvgl_fs.h" +#endif +#ifdef CONFIG_LV_Z_POINTER_KSCAN +#include +#endif +#include LV_MEM_CUSTOM_INCLUDE + +#define LOG_LEVEL CONFIG_LV_LOG_LEVEL +#include +LOG_MODULE_REGISTER(lvgl); + +static lv_disp_drv_t disp_drv; +struct lvgl_disp_data disp_data = { + .blanking_on = false, +}; +#ifdef CONFIG_LV_Z_POINTER_KSCAN +static lv_indev_drv_t indev_drv; +#endif /* CONFIG_LV_Z_POINTER_KSCAN */ + +#define DISPLAY_NODE DT_CHOSEN(zephyr_display) +#define KSCAN_NODE DT_CHOSEN(zephyr_keyboard_scan) + +#ifdef CONFIG_LV_Z_BUFFER_ALLOC_STATIC + +static lv_disp_draw_buf_t disp_buf; + +#define DISPLAY_WIDTH DT_PROP(DISPLAY_NODE, width) +#define DISPLAY_HEIGHT DT_PROP(DISPLAY_NODE, height) + +#define BUFFER_SIZE \ + (CONFIG_LV_Z_BITS_PER_PIXEL * \ + ((CONFIG_LV_Z_VDB_SIZE * DISPLAY_WIDTH * DISPLAY_HEIGHT) / 100) / 8) + +#define NBR_PIXELS_IN_BUFFER (BUFFER_SIZE * 8 / CONFIG_LV_Z_BITS_PER_PIXEL) + +/* NOTE: depending on chosen color depth buffer may be accessed using uint8_t *, + * uint16_t * or uint32_t *, therefore buffer needs to be aligned accordingly to + * prevent unaligned memory accesses. + */ +static uint8_t buf0[BUFFER_SIZE] +#ifdef CONFIG_LV_Z_VBD_CUSTOM_SECTION + Z_GENERIC_SECTION(.lvgl_buf) +#endif + __aligned(CONFIG_LV_Z_VDB_ALIGN); + +#ifdef CONFIG_LV_Z_DOUBLE_VDB +static uint8_t buf1[BUFFER_SIZE] +#ifdef CONFIG_LV_Z_VBD_CUSTOM_SECTION + Z_GENERIC_SECTION(.lvgl_buf) +#endif + __aligned(CONFIG_LV_Z_VDB_ALIGN); +#endif /* CONFIG_LV_Z_DOUBLE_VDB */ + +#endif /* CONFIG_LV_Z_BUFFER_ALLOC_STATIC */ + +#if CONFIG_LV_LOG_LEVEL != 0 +/* + * In LVGLv8 the signature of the logging callback has changes and it no longer + * takes the log level as an integer argument. Instead, the log level is now + * already part of the buffer passed to the logging callback. It's not optimal + * but we need to live with it and parse the buffer manually to determine the + * level and then truncate the string we actually pass to the logging framework. + */ +static void lvgl_log(const char *buf) +{ + /* + * This is ugly and should be done in a loop or something but as it + * turned out, Z_LOG()'s first argument (that specifies the log level) + * cannot be an l-value... + * + * We also assume lvgl is sane and always supplies the level string. + */ + switch (buf[1]) { + case 'E': + LOG_ERR("%s", buf + strlen("[Error] ")); + break; + case 'W': + LOG_WRN("%s", buf + strlen("Warn] ")); + break; + case 'I': + LOG_INF("%s", buf + strlen("[Info] ")); + break; + case 'T': + LOG_DBG("%s", buf + strlen("[Trace] ")); + break; + } +} +#endif + +#ifdef CONFIG_LV_Z_BUFFER_ALLOC_STATIC + +static int lvgl_allocate_rendering_buffers(lv_disp_drv_t *disp_driver) +{ + struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_driver->user_data; + int err = 0; + + if (data->cap.x_resolution <= DISPLAY_WIDTH) { + disp_driver->hor_res = data->cap.x_resolution; + } else { + LOG_ERR("Horizontal resolution is larger than maximum"); + err = -ENOTSUP; + } + + if (data->cap.y_resolution <= DISPLAY_HEIGHT) { + disp_driver->ver_res = data->cap.y_resolution; + } else { + LOG_ERR("Vertical resolution is larger than maximum"); + err = -ENOTSUP; + } + + disp_driver->draw_buf = &disp_buf; +#ifdef CONFIG_LV_Z_DOUBLE_VDB + lv_disp_draw_buf_init(disp_driver->draw_buf, &buf0, &buf1, NBR_PIXELS_IN_BUFFER); +#else + lv_disp_draw_buf_init(disp_driver->draw_buf, &buf0, NULL, NBR_PIXELS_IN_BUFFER); +#endif /* CONFIG_LV_Z_DOUBLE_VDB */ + + return err; +} + +#else + +static int lvgl_allocate_rendering_buffers(lv_disp_drv_t *disp_driver) +{ + void *buf0 = NULL; + void *buf1 = NULL; + uint16_t buf_nbr_pixels; + uint32_t buf_size; + struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_driver->user_data; + + disp_driver->hor_res = data->cap.x_resolution; + disp_driver->ver_res = data->cap.y_resolution; + + buf_nbr_pixels = (CONFIG_LV_Z_VDB_SIZE * disp_driver->hor_res * disp_driver->ver_res) / 100; + /* one horizontal line is the minimum buffer requirement for lvgl */ + if (buf_nbr_pixels < disp_driver->hor_res) { + buf_nbr_pixels = disp_driver->hor_res; + } + + switch (data->cap.current_pixel_format) { + case PIXEL_FORMAT_ARGB_8888: + buf_size = 4 * buf_nbr_pixels; + break; + case PIXEL_FORMAT_RGB_888: + buf_size = 3 * buf_nbr_pixels; + break; + case PIXEL_FORMAT_RGB_565: + buf_size = 2 * buf_nbr_pixels; + break; + case PIXEL_FORMAT_MONO01: + case PIXEL_FORMAT_MONO10: + buf_size = buf_nbr_pixels / 8; + buf_size += (buf_nbr_pixels % 8) == 0 ? 0 : 1; + break; + default: + return -ENOTSUP; + } + + buf0 = LV_MEM_CUSTOM_ALLOC(buf_size); + if (buf0 == NULL) { + LOG_ERR("Failed to allocate memory for rendering buffer"); + return -ENOMEM; + } + +#ifdef CONFIG_LV_Z_DOUBLE_VDB + buf1 = LV_MEM_CUSTOM_ALLOC(buf_size); + if (buf1 == NULL) { + LV_MEM_CUSTOM_FREE(buf0); + LOG_ERR("Failed to allocate memory for rendering buffer"); + return -ENOMEM; + } +#endif + + disp_driver->draw_buf = LV_MEM_CUSTOM_ALLOC(sizeof(lv_disp_draw_buf_t)); + if (disp_driver->draw_buf == NULL) { + LV_MEM_CUSTOM_FREE(buf0); + LV_MEM_CUSTOM_FREE(buf1); + LOG_ERR("Failed to allocate memory to store rendering buffers"); + return -ENOMEM; + } + + lv_disp_draw_buf_init(disp_driver->draw_buf, buf0, buf1, buf_nbr_pixels); + return 0; +} +#endif /* CONFIG_LV_Z_BUFFER_ALLOC_STATIC */ + +#ifdef CONFIG_LV_Z_POINTER_KSCAN +K_MSGQ_DEFINE(kscan_msgq, sizeof(lv_indev_data_t), CONFIG_LV_Z_POINTER_KSCAN_MSGQ_COUNT, 4); + +static void lvgl_pointer_kscan_callback(const struct device *dev, uint32_t row, uint32_t col, + bool pressed) +{ + lv_indev_data_t data = { + .point.x = col, + .point.y = row, + .state = pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL, + }; + + if (k_msgq_put(&kscan_msgq, &data, K_NO_WAIT) != 0) { + LOG_DBG("Could not put input data into queue"); + } +} + +static void lvgl_pointer_kscan_read(lv_indev_drv_t *drv, lv_indev_data_t *data) +{ + lv_disp_t *disp; + struct lvgl_disp_data *disp_data; + struct display_capabilities *cap; + lv_indev_data_t curr; + + static lv_indev_data_t prev = { + .point.x = 0, + .point.y = 0, + .state = LV_INDEV_STATE_REL, + }; + + if (k_msgq_get(&kscan_msgq, &curr, K_NO_WAIT) != 0) { + goto set_and_release; + } + + prev = curr; + + disp = lv_disp_get_default(); + disp_data = disp->driver->user_data; + cap = &disp_data->cap; + + /* adjust kscan coordinates */ + if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN_SWAP_XY)) { + lv_coord_t x; + + x = prev.point.x; + prev.point.x = prev.point.y; + prev.point.y = x; + } + + if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN_INVERT_X)) { + if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL || + cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) { + prev.point.x = cap->x_resolution - prev.point.x; + } else { + prev.point.x = cap->y_resolution - prev.point.x; + } + } + + if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN_INVERT_Y)) { + if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL || + cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) { + prev.point.y = cap->y_resolution - prev.point.y; + } else { + prev.point.y = cap->x_resolution - prev.point.y; + } + } + + /* rotate touch point to match display rotation */ + if (cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_90) { + lv_coord_t x; + + x = prev.point.x; + prev.point.x = prev.point.y; + prev.point.y = cap->y_resolution - x; + } else if (cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) { + prev.point.x = cap->x_resolution - prev.point.x; + prev.point.y = cap->y_resolution - prev.point.y; + } else if (cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_270) { + lv_coord_t x; + + x = prev.point.x; + prev.point.x = cap->x_resolution - prev.point.y; + prev.point.y = x; + } + + /* filter readings within display */ + if (prev.point.x <= 0) { + prev.point.x = 0; + } else if (prev.point.x >= cap->x_resolution) { + prev.point.x = cap->x_resolution - 1; + } + + if (prev.point.y <= 0) { + prev.point.y = 0; + } else if (prev.point.y >= cap->y_resolution) { + prev.point.y = cap->y_resolution - 1; + } + +set_and_release: + *data = prev; + + data->continue_reading = k_msgq_num_used_get(&kscan_msgq) > 0; +} + +static int lvgl_pointer_kscan_init(void) +{ + const struct device *kscan_dev = DEVICE_DT_GET(KSCAN_NODE); + + if (!device_is_ready(kscan_dev)) { + LOG_ERR("Keyboard scan device not ready."); + return -ENODEV; + } + + if (kscan_config(kscan_dev, lvgl_pointer_kscan_callback) < 0) { + LOG_ERR("Could not configure keyboard scan device."); + return -ENODEV; + } + + lv_indev_drv_init(&indev_drv); + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.read_cb = lvgl_pointer_kscan_read; + + if (lv_indev_drv_register(&indev_drv) == NULL) { + LOG_ERR("Failed to register input device."); + return -EPERM; + } + + kscan_enable_callback(kscan_dev); + + return 0; +} +#endif /* CONFIG_LV_Z_POINTER_KSCAN */ + +static int lvgl_init(void) +{ + + const struct device *display_dev = DEVICE_DT_GET(DISPLAY_NODE); + + int err = 0; + + if (!device_is_ready(display_dev)) { + LOG_ERR("Display device not ready."); + return -ENODEV; + } + +#if CONFIG_LV_LOG_LEVEL != 0 + lv_log_register_print_cb(lvgl_log); +#endif + + lv_init(); + +#ifdef CONFIG_LV_Z_USE_FILESYSTEM + lvgl_fs_init(); +#endif + + disp_data.display_dev = display_dev; + display_get_capabilities(display_dev, &disp_data.cap); + + lv_disp_drv_init(&disp_drv); + disp_drv.user_data = (void *)&disp_data; + +#ifdef CONFIG_LV_Z_FULL_REFRESH + disp_drv.full_refresh = 1; +#endif + + err = lvgl_allocate_rendering_buffers(&disp_drv); + if (err != 0) { + return err; + } + + if (set_lvgl_rendering_cb(&disp_drv) != 0) { + LOG_ERR("Display not supported."); + return -ENOTSUP; + } + + if (lv_disp_drv_register(&disp_drv) == NULL) { + LOG_ERR("Failed to register display device."); + return -EPERM; + } + +#ifdef CONFIG_LV_Z_POINTER_KSCAN + lvgl_pointer_kscan_init(); +#endif /* CONFIG_LV_Z_POINTER_KSCAN */ + + return 0; +} + +SYS_INIT(lvgl_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/modules/lvgl/lvgl_display.c b/modules/lvgl/lvgl_display.c new file mode 100644 index 000000000000000..4770e7a42a02ebd --- /dev/null +++ b/modules/lvgl/lvgl_display.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "lvgl_display.h" + +int set_lvgl_rendering_cb(lv_disp_drv_t *disp_drv) +{ + int err = 0; + struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data; + + switch (data->cap.current_pixel_format) { + case PIXEL_FORMAT_ARGB_8888: + disp_drv->flush_cb = lvgl_flush_cb_32bit; + disp_drv->rounder_cb = NULL; +#ifdef CONFIG_LV_COLOR_DEPTH_32 + disp_drv->set_px_cb = NULL; +#else + disp_drv->set_px_cb = lvgl_set_px_cb_32bit; +#endif + break; + case PIXEL_FORMAT_RGB_888: + disp_drv->flush_cb = lvgl_flush_cb_24bit; + disp_drv->rounder_cb = NULL; + disp_drv->set_px_cb = lvgl_set_px_cb_24bit; + break; + case PIXEL_FORMAT_RGB_565: + case PIXEL_FORMAT_BGR_565: + disp_drv->flush_cb = lvgl_flush_cb_16bit; + disp_drv->rounder_cb = NULL; +#ifdef CONFIG_LV_COLOR_DEPTH_16 + disp_drv->set_px_cb = NULL; +#else + disp_drv->set_px_cb = lvgl_set_px_cb_16bit; +#endif + break; + case PIXEL_FORMAT_MONO01: + case PIXEL_FORMAT_MONO10: + disp_drv->flush_cb = lvgl_flush_cb_mono; + disp_drv->rounder_cb = lvgl_rounder_cb_mono; + disp_drv->set_px_cb = lvgl_set_px_cb_mono; + break; + default: + disp_drv->flush_cb = NULL; + disp_drv->rounder_cb = NULL; + disp_drv->set_px_cb = NULL; + err = -ENOTSUP; + break; + } + + return err; +} diff --git a/modules/lvgl/lvgl_display.h b/modules/lvgl/lvgl_display.h new file mode 100644 index 000000000000000..5a8da44a4e37c95 --- /dev/null +++ b/modules/lvgl/lvgl_display.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_GUI_LVGL_LVGL_DISPLAY_H_ +#define ZEPHYR_LIB_GUI_LVGL_LVGL_DISPLAY_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct lvgl_disp_data { + const struct device *display_dev; + struct display_capabilities cap; + bool blanking_on; +}; + +void lvgl_flush_cb_mono(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); +void lvgl_flush_cb_16bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); +void lvgl_flush_cb_24bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); +void lvgl_flush_cb_32bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p); + +void lvgl_set_px_cb_mono(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa); +void lvgl_set_px_cb_16bit(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa); +void lvgl_set_px_cb_24bit(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa); +void lvgl_set_px_cb_32bit(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa); + +void lvgl_rounder_cb_mono(lv_disp_drv_t *disp_drv, lv_area_t *area); + +int set_lvgl_rendering_cb(lv_disp_drv_t *disp_drv); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_GUI_LVGL_LVGL_DISPLAY_H */ diff --git a/modules/lvgl/lvgl_display_16bit.c b/modules/lvgl/lvgl_display_16bit.c new file mode 100644 index 000000000000000..cb529036c004453 --- /dev/null +++ b/modules/lvgl/lvgl_display_16bit.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "lvgl_display.h" + +void lvgl_flush_cb_16bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) +{ + struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data; + uint16_t w = area->x2 - area->x1 + 1; + uint16_t h = area->y2 - area->y1 + 1; + struct display_buffer_descriptor desc; + + desc.buf_size = w * 2U * h; + desc.width = w; + desc.pitch = w; + desc.height = h; + display_write(data->display_dev, area->x1, area->y1, &desc, (void *)color_p); + + lv_disp_flush_ready(disp_drv); +} + +#ifndef CONFIG_LV_COLOR_DEPTH_16 +void lvgl_set_px_cb_16bit(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa) +{ + uint16_t *buf_xy = (uint16_t *)(buf + x * 2U + y * 2U * buf_w); + *buf_xy = lv_color_to16(color); +} +#endif diff --git a/modules/lvgl/lvgl_display_24bit.c b/modules/lvgl/lvgl_display_24bit.c new file mode 100644 index 000000000000000..6e461f401b1f086 --- /dev/null +++ b/modules/lvgl/lvgl_display_24bit.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "lvgl_display.h" + +void lvgl_flush_cb_24bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) +{ + struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data; + uint16_t w = area->x2 - area->x1 + 1; + uint16_t h = area->y2 - area->y1 + 1; + struct display_buffer_descriptor desc; + + desc.buf_size = w * 3U * h; + desc.width = w; + desc.pitch = w; + desc.height = h; + display_write(data->display_dev, area->x1, area->y1, &desc, (void *)color_p); + + lv_disp_flush_ready(disp_drv); +} + +void lvgl_set_px_cb_24bit(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa) +{ + uint8_t *buf_xy = buf + x * 3U + y * 3U * buf_w; + lv_color32_t converted_color; + +#ifdef CONFIG_LV_COLOR_DEPTH_32 + if (opa != LV_OPA_COVER) { + lv_color_t mix_color; + + mix_color.ch.red = *buf_xy; + mix_color.ch.green = *(buf_xy + 1); + mix_color.ch.blue = *(buf_xy + 2); + color = lv_color_mix(color, mix_color, opa); + } +#endif + + converted_color.full = lv_color_to32(color); + *buf_xy = converted_color.ch.red; + *(buf_xy + 1) = converted_color.ch.green; + *(buf_xy + 2) = converted_color.ch.blue; +} diff --git a/modules/lvgl/lvgl_display_32bit.c b/modules/lvgl/lvgl_display_32bit.c new file mode 100644 index 000000000000000..65a1b0743c8c5dd --- /dev/null +++ b/modules/lvgl/lvgl_display_32bit.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "lvgl_display.h" + +void lvgl_flush_cb_32bit(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) +{ + struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data; + uint16_t w = area->x2 - area->x1 + 1; + uint16_t h = area->y2 - area->y1 + 1; + struct display_buffer_descriptor desc; + + desc.buf_size = w * 4U * h; + desc.width = w; + desc.pitch = w; + desc.height = h; + display_write(data->display_dev, area->x1, area->y1, &desc, (void *)color_p); + + lv_disp_flush_ready(disp_drv); +} + +#ifndef CONFIG_LV_COLOR_DEPTH_32 +void lvgl_set_px_cb_32bit(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa) +{ + uint32_t *buf_xy = (uint32_t *)(buf + x * 4U + y * 4U * buf_w); + + if (opa == LV_OPA_COVER) { + /* Do not mix if not required */ + *buf_xy = lv_color_to32(color); + } else { + lv_color_t bg_color = *((lv_color_t *)buf_xy); + *buf_xy = lv_color_to32(lv_color_mix(color, bg_color, opa)); + } +} +#endif diff --git a/modules/lvgl/lvgl_display_mono.c b/modules/lvgl/lvgl_display_mono.c new file mode 100644 index 000000000000000..07f84b7d19efc7a --- /dev/null +++ b/modules/lvgl/lvgl_display_mono.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "lvgl_display.h" + +void lvgl_flush_cb_mono(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) +{ + uint16_t w = area->x2 - area->x1 + 1; + uint16_t h = area->y2 - area->y1 + 1; + struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data; + const struct device *display_dev = data->display_dev; + struct display_buffer_descriptor desc; + const bool is_epd = data->cap.screen_info & SCREEN_INFO_EPD; + const bool is_last = lv_disp_flush_is_last(disp_drv); + + if (is_epd && !data->blanking_on && !is_last) { + /* + * Turn on display blanking when using an EPD + * display. This prevents updates and the associated + * flicker if the screen is rendered in multiple + * steps. + */ + display_blanking_on(display_dev); + data->blanking_on = true; + } + + desc.buf_size = (w * h) / 8U; + desc.width = w; + desc.pitch = w; + desc.height = h; + display_write(display_dev, area->x1, area->y1, &desc, (void *)color_p); + if (data->cap.screen_info & SCREEN_INFO_DOUBLE_BUFFER) { + display_write(display_dev, area->x1, area->y1, &desc, (void *)color_p); + } + + if (is_epd && is_last && data->blanking_on) { + /* + * The entire screen has now been rendered. Update the + * display by disabling blanking. + */ + display_blanking_off(display_dev); + data->blanking_on = false; + } + + lv_disp_flush_ready(disp_drv); +} + +void lvgl_set_px_cb_mono(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, + lv_coord_t y, lv_color_t color, lv_opa_t opa) +{ + struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data; + uint8_t *buf_xy; + uint8_t bit; + + if (data->cap.screen_info & SCREEN_INFO_MONO_VTILED) { + buf_xy = buf + x + y / 8 * buf_w; + + if (data->cap.screen_info & SCREEN_INFO_MONO_MSB_FIRST) { + bit = 7 - y % 8; + } else { + bit = y % 8; + } + } else { + buf_xy = buf + x / 8 + y * buf_w / 8; + + if (data->cap.screen_info & SCREEN_INFO_MONO_MSB_FIRST) { + bit = 7 - x % 8; + } else { + bit = x % 8; + } + } + + if (data->cap.current_pixel_format == PIXEL_FORMAT_MONO10) { + if (color.full == 0) { + *buf_xy &= ~BIT(bit); + } else { + *buf_xy |= BIT(bit); + } + } else { + if (color.full == 0) { + *buf_xy |= BIT(bit); + } else { + *buf_xy &= ~BIT(bit); + } + } +} + +void lvgl_rounder_cb_mono(lv_disp_drv_t *disp_drv, lv_area_t *area) +{ + struct lvgl_disp_data *data = (struct lvgl_disp_data *)disp_drv->user_data; + + if (data->cap.screen_info & SCREEN_INFO_X_ALIGNMENT_WIDTH) { + area->x1 = 0; + area->x2 = data->cap.x_resolution - 1; + } else { + if (data->cap.screen_info & SCREEN_INFO_MONO_VTILED) { + area->y1 &= ~0x7; + area->y2 |= 0x7; + } else { + area->x1 &= ~0x7; + area->x2 |= 0x7; + } + } +} diff --git a/modules/lvgl/lvgl_fs.c b/modules/lvgl/lvgl_fs.c new file mode 100644 index 000000000000000..92cbec3656960d6 --- /dev/null +++ b/modules/lvgl/lvgl_fs.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2018-2019 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "lvgl_fs.h" + +static bool lvgl_fs_ready(struct _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; + default: + return LV_FS_RES_UNKNOWN; + } +} + +static void *lvgl_fs_open(struct _lv_fs_drv_t *drv, const char *path, lv_fs_mode_t mode) +{ + int err; + int zmode = FS_O_CREATE; + 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 : 0; + zmode |= (mode & LV_FS_MODE_RD) ? FS_O_READ : 0; + + file = 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) { + return NULL; + } + + return file; +} + +static lv_fs_res_t lvgl_fs_close(struct _lv_fs_drv_t *drv, void *file) +{ + int err; + + err = fs_close((struct fs_file_t *)file); + return errno_to_lv_fs_res(err); +} + +static lv_fs_res_t lvgl_fs_read(struct _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(struct _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(struct _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(struct _lv_fs_drv_t *drv, void *file, uint32_t *pos_p) +{ + *pos_p = fs_tell((struct fs_file_t *)file); + return LV_FS_RES_OK; +} + +static void *lvgl_fs_dir_open(struct _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 = 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) { + return NULL; + } + + return dir; +} + +static lv_fs_res_t lvgl_fs_dir_read(struct _lv_fs_drv_t *drv, void *dir, char *fn) +{ + /* 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(struct _lv_fs_drv_t *drv, void *dir) +{ + int err; + + err = fs_closedir((struct fs_dir_t *)dir); + 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); +} diff --git a/modules/lvgl/lvgl_fs.h b/modules/lvgl/lvgl_fs.h new file mode 100644 index 000000000000000..02a3732c90f66e7 --- /dev/null +++ b/modules/lvgl/lvgl_fs.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_GUI_LVGL_LVGL_FS_H_ +#define ZEPHYR_LIB_GUI_LVGL_LVGL_FS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void lvgl_fs_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_GUI_LVGL_LVGL_FS_H */ diff --git a/modules/lvgl/lvgl_mem.c b/modules/lvgl/lvgl_mem.c new file mode 100644 index 000000000000000..f41ede520cb841e --- /dev/null +++ b/modules/lvgl/lvgl_mem.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 Jan Van Winkel + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lvgl_mem.h" +#include +#include +#include + +#define HEAP_BYTES (CONFIG_LV_Z_MEM_POOL_MAX_SIZE * CONFIG_LV_Z_MEM_POOL_NUMBER_BLOCKS) + +static char lvgl_heap_mem[HEAP_BYTES] __aligned(8); +static struct sys_heap lvgl_heap; +static struct k_spinlock lvgl_heap_lock; + +void *lvgl_malloc(size_t size) +{ + k_spinlock_key_t key; + void *ret; + + key = k_spin_lock(&lvgl_heap_lock); + ret = sys_heap_alloc(&lvgl_heap, size); + k_spin_unlock(&lvgl_heap_lock, key); + + return ret; +} + +void *lvgl_realloc(void *ptr, size_t size) +{ + k_spinlock_key_t key; + void *ret; + + key = k_spin_lock(&lvgl_heap_lock); + ret = sys_heap_realloc(&lvgl_heap, ptr, size); + k_spin_unlock(&lvgl_heap_lock, key); + + return ret; +} + +void lvgl_free(void *ptr) +{ + k_spinlock_key_t key; + + key = k_spin_lock(&lvgl_heap_lock); + sys_heap_free(&lvgl_heap, ptr); + k_spin_unlock(&lvgl_heap_lock, key); +} + +void lvgl_print_heap_info(bool dump_chunks) +{ + k_spinlock_key_t key; + + key = k_spin_lock(&lvgl_heap_lock); + sys_heap_print_info(&lvgl_heap, dump_chunks); + k_spin_unlock(&lvgl_heap_lock, key); +} + +static int lvgl_heap_init(void) +{ + sys_heap_init(&lvgl_heap, &lvgl_heap_mem[0], HEAP_BYTES); + return 0; +} + +SYS_INIT(lvgl_heap_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/modules/lvgl/lvgl_mem.h b/modules/lvgl/lvgl_mem.h new file mode 100644 index 000000000000000..ad3c29c1c90d5b9 --- /dev/null +++ b/modules/lvgl/lvgl_mem.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 Jan Van Winkel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_GUI_LVGL_MEM_H_ +#define ZEPHYR_LIB_GUI_LVGL_MEM_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *lvgl_malloc(size_t size); + +void *lvgl_realloc(void *ptr, size_t size); + +void lvgl_free(void *ptr); + +void lvgl_print_heap_info(bool dump_chunks); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_GUI_LVGL_MEM_H_i */ diff --git a/modules/lvgl/lvgl_shell.c b/modules/lvgl/lvgl_shell.c new file mode 100644 index 000000000000000..e8ac27e22f9067e --- /dev/null +++ b/modules/lvgl/lvgl_shell.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#ifdef CONFIG_LV_Z_MEM_POOL_SYS_HEAP +#include "lvgl_mem.h" +#endif + +#ifdef CONFIG_LV_USE_MONKEY +static lv_monkey_t *lvgl_monkeys[CONFIG_LV_Z_MAX_MONKEY_COUNT]; + +static const char *lvgl_monkey_indev_as_string(lv_monkey_t *monkey) +{ + lv_indev_t *input_device; + + input_device = lv_monkey_get_indev(monkey); + if (!input_device || !input_device->driver) { + return "unknown"; + } + + switch (input_device->driver->type) { + case LV_INDEV_TYPE_POINTER: + return "pointer"; + case LV_INDEV_TYPE_KEYPAD: + return "keypad"; + case LV_INDEV_TYPE_BUTTON: + return "button"; + case LV_INDEV_TYPE_ENCODER: + return "encoder"; + default: + return "unknown"; + } +} + +static int lvgl_monkey_indev_from_string(const char *str, lv_indev_type_t *input_device) +{ + if (strcmp(str, "pointer") == 0) { + *input_device = LV_INDEV_TYPE_POINTER; + } else if (strcmp(str, "keypad") == 0) { + *input_device = LV_INDEV_TYPE_KEYPAD; + } else if (strcmp(str, "button") == 0) { + *input_device = LV_INDEV_TYPE_BUTTON; + } else if (strcmp(str, "encoder") == 0) { + *input_device = LV_INDEV_TYPE_ENCODER; + } else { + return -EINVAL; + } + return 0; +} + +static void dump_monkey_info(const struct shell *sh) +{ + shell_print(sh, "id device active"); + for (size_t i = 0; i < CONFIG_LV_Z_MAX_MONKEY_COUNT; i++) { + if (lvgl_monkeys[i] != NULL) { + shell_print(sh, "%-4u %-9s %-3s", i, + lvgl_monkey_indev_as_string(lvgl_monkeys[i]), + lv_monkey_get_enable(lvgl_monkeys[i]) ? "yes" : "no"); + } + } +} + +static int cmd_lvgl_monkey(const struct shell *sh, size_t argc, char *argv[]) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + dump_monkey_info(sh); + shell_print(sh, ""); + shell_help(sh); + + return SHELL_CMD_HELP_PRINTED; +} + +static int cmd_lvgl_monkey_create(const struct shell *sh, size_t argc, char *argv[]) +{ + bool created_monkey = false; + lv_monkey_config_t default_config; + + lv_monkey_config_init(&default_config); + + if (argc == 2) { + if (lvgl_monkey_indev_from_string(argv[1], &default_config.type) < 0) { + shell_error(sh, "Invalid monkey input device %s", argv[1]); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + } + + for (size_t i = 0; i < CONFIG_LV_Z_MAX_MONKEY_COUNT; i++) { + if (lvgl_monkeys[i] == NULL) { + lvgl_monkeys[i] = lv_monkey_create(&default_config); + lv_monkey_set_enable(lvgl_monkeys[i], true); + created_monkey = true; + break; + } + } + + if (!created_monkey) { + shell_error(sh, "Error creating monkey instance"); + return -ENOSPC; + } + + dump_monkey_info(sh); + + return 0; +} + +static int cmd_lvgl_monkey_set(const struct shell *sh, size_t argc, char *argv[]) +{ + int index; + + index = atoi(argv[1]); + if (index < 0 || index >= CONFIG_LV_Z_MAX_MONKEY_COUNT || lvgl_monkeys[index] == NULL) { + shell_error(sh, "Invalid monkey index"); + return -ENOEXEC; + } + + if (strcmp(argv[2], "active") == 0) { + lv_monkey_set_enable(lvgl_monkeys[index], true); + } else if (strcmp(argv[2], "inactive") == 0) { + lv_monkey_set_enable(lvgl_monkeys[index], false); + } else { + shell_error(sh, "Invalid monkey state %s", argv[2]); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + + dump_monkey_info(sh); + + return 0; +} +#endif /* CONFIG_LV_USE_MONKEY */ + +static int cmd_lvgl_stats(const struct shell *sh, size_t argc, char *argv[]) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; +} + +static int cmd_lvgl_stats_memory(const struct shell *sh, size_t argc, char *argv[]) +{ +#ifdef CONFIG_LV_Z_MEM_POOL_SYS_HEAP + bool dump_chunks = false; + + if (argc == 2) { + if (strcmp(argv[1], "-c") == 0) { + dump_chunks = true; + } else { + shell_error(sh, "unsupported option %s", argv[1]); + shell_help(sh); + return SHELL_CMD_HELP_PRINTED; + } + } + + lvgl_print_heap_info(dump_chunks); + return 0; +#else + ARG_UNUSED(argc); + ARG_UNUSED(argv); + shell_error(sh, "Set CONFIG_LV_Z_MEM_POOL_SYS_HEAP to enable memory statistics support."); + return -ENOTSUP; +#endif +} + +SHELL_STATIC_SUBCMD_SET_CREATE(lvgl_cmd_stats, + SHELL_CMD_ARG(memory, NULL, + "Show LVGL memory statistics\n" + "Usage: lvgl stats memory [-c]\n" + "-c dump chunk information", + cmd_lvgl_stats_memory, 1, 1), + SHELL_SUBCMD_SET_END); + +#ifdef CONFIG_LV_USE_MONKEY +SHELL_STATIC_SUBCMD_SET_CREATE( + lvgl_cmd_monkey, + SHELL_CMD_ARG(create, NULL, + "Create a new monkey instance (default: pointer)\n" + "Usage: lvgl monkey create [pointer|keypad|button|encoder]", + cmd_lvgl_monkey_create, 1, 1), + SHELL_CMD_ARG(set, NULL, + "Activate/deactive a monkey instance\n" + "Usage: lvgl monkey set \n", + cmd_lvgl_monkey_set, 3, 0), + SHELL_SUBCMD_SET_END); +#endif /* CONFIG_LV_USE_MONKEY */ + +SHELL_STATIC_SUBCMD_SET_CREATE( + lvgl_cmds, SHELL_CMD(stats, &lvgl_cmd_stats, "Show LVGL statistics", cmd_lvgl_stats), +#ifdef CONFIG_LV_USE_MONKEY + SHELL_CMD(monkey, &lvgl_cmd_monkey, "LVGL monkey testing", cmd_lvgl_monkey), +#endif /* CONFIG_LV_USE_MONKEY */ + SHELL_SUBCMD_SET_END); + +SHELL_CMD_REGISTER(lvgl, &lvgl_cmds, "LVGL shell commands", NULL); diff --git a/west.yml b/west.yml index 27523c7b7653c86..98f33b614e36011 100644 --- a/west.yml +++ b/west.yml @@ -260,7 +260,7 @@ manifest: revision: ce57712f3e426bbbb13acaec97b45369f716f43a path: modules/lib/loramac-node - name: lvgl - revision: 5da257f782a8f9c6e265bdc60ebc2a93fdee24de + revision: pull/45/head path: modules/lib/gui/lvgl - name: lz4 revision: 8e303c264fc21c2116dc612658003a22e933124d