summaryrefslogtreecommitdiff
path: root/lib/lvgl/src/hal
diff options
context:
space:
mode:
Diffstat (limited to 'lib/lvgl/src/hal')
m---------lib/lvgl0
-rw-r--r--lib/lvgl/src/hal/lv_hal.h48
-rw-r--r--lib/lvgl/src/hal/lv_hal.mk8
-rw-r--r--lib/lvgl/src/hal/lv_hal_disp.c710
-rw-r--r--lib/lvgl/src/hal/lv_hal_disp.h371
-rw-r--r--lib/lvgl/src/hal/lv_hal_indev.c195
-rw-r--r--lib/lvgl/src/hal/lv_hal_indev.h239
-rw-r--r--lib/lvgl/src/hal/lv_hal_tick.c104
-rw-r--r--lib/lvgl/src/hal/lv_hal_tick.h69
9 files changed, 1744 insertions, 0 deletions
diff --git a/lib/lvgl b/lib/lvgl
deleted file mode 160000
-Subproject 0732400e7b564dd0e7dc4a924619d8e19c5b23a
diff --git a/lib/lvgl/src/hal/lv_hal.h b/lib/lvgl/src/hal/lv_hal.h
new file mode 100644
index 00000000..167da1f4
--- /dev/null
+++ b/lib/lvgl/src/hal/lv_hal.h
@@ -0,0 +1,48 @@
+/**
+ * @file lv_hal.h
+ *
+ */
+
+#ifndef LV_HAL_H
+#define LV_HAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "lv_hal_disp.h"
+#include "lv_hal_indev.h"
+#include "lv_hal_tick.h"
+
+/*********************
+ * DEFINES
+ *********************/
+/**
+ * Same as Android's DIP. (Different name is chosen to avoid mistype between LV_DPI and LV_DIP)
+ * 1 dip is 1 px on a 160 DPI screen
+ * 1 dip is 2 px on a 320 DPI screen
+ * https://stackoverflow.com/questions/2025282/what-is-the-difference-between-px-dip-dp-and-sp
+ */
+#define _LV_DPX_CALC(dpi, n) ((n) == 0 ? 0 :LV_MAX((( (dpi) * (n) + 80) / 160), 1)) /*+80 for rounding*/
+#define LV_DPX(n) _LV_DPX_CALC(lv_disp_get_dpi(NULL), n)
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+
+/**********************
+ * MACROS
+ **********************/
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif
diff --git a/lib/lvgl/src/hal/lv_hal.mk b/lib/lvgl/src/hal/lv_hal.mk
new file mode 100644
index 00000000..c35ec2d7
--- /dev/null
+++ b/lib/lvgl/src/hal/lv_hal.mk
@@ -0,0 +1,8 @@
+CSRCS += lv_hal_disp.c
+CSRCS += lv_hal_indev.c
+CSRCS += lv_hal_tick.c
+
+DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/hal
+VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/hal
+
+CFLAGS += "-I$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/hal"
diff --git a/lib/lvgl/src/hal/lv_hal_disp.c b/lib/lvgl/src/hal/lv_hal_disp.c
new file mode 100644
index 00000000..0dd8f6b3
--- /dev/null
+++ b/lib/lvgl/src/hal/lv_hal_disp.c
@@ -0,0 +1,710 @@
+/**
+ * @file lv_hal_disp.c
+ *
+ * @description HAL layer for display driver
+ *
+ */
+
+/*********************
+ * INCLUDES
+ *********************/
+#include <stdint.h>
+#include <stddef.h>
+#include "lv_hal.h"
+#include "../misc/lv_mem.h"
+#include "../misc/lv_gc.h"
+#include "../misc/lv_assert.h"
+#include "../core/lv_obj.h"
+#include "../core/lv_refr.h"
+#include "../core/lv_theme.h"
+#include "../draw/sdl/lv_draw_sdl.h"
+#include "../draw/sw/lv_draw_sw.h"
+#include "../draw/sdl/lv_draw_sdl.h"
+#include "../draw/stm32_dma2d/lv_gpu_stm32_dma2d.h"
+#include "../draw/swm341_dma2d/lv_gpu_swm341_dma2d.h"
+#include "../draw/arm2d/lv_gpu_arm2d.h"
+#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE
+ #include "../draw/nxp/lv_gpu_nxp.h"
+#endif
+
+#if LV_USE_THEME_DEFAULT
+ #include "../extra/themes/default/lv_theme_default.h"
+#endif
+
+/*********************
+ * DEFINES
+ *********************/
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * STATIC PROTOTYPES
+ **********************/
+static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_data);
+
+static void set_px_true_color_alpha(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);
+
+static void set_px_cb_alpha1(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);
+
+static void set_px_cb_alpha2(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);
+
+static void set_px_cb_alpha4(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);
+
+static void set_px_cb_alpha8(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);
+
+static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
+
+/**********************
+ * STATIC VARIABLES
+ **********************/
+static lv_disp_t * disp_def;
+
+/**********************
+ * MACROS
+ **********************/
+
+/**********************
+ * GLOBAL FUNCTIONS
+ **********************/
+
+/**
+ * Initialize a display driver with default values.
+ * It is used to surly have known values in the fields ant not memory junk.
+ * After it you can set the fields.
+ * @param driver pointer to driver variable to initialize
+ */
+void lv_disp_drv_init(lv_disp_drv_t * driver)
+{
+ lv_memset_00(driver, sizeof(lv_disp_drv_t));
+
+ driver->hor_res = 320;
+ driver->ver_res = 240;
+ driver->physical_hor_res = -1;
+ driver->physical_ver_res = -1;
+ driver->offset_x = 0;
+ driver->offset_y = 0;
+ driver->antialiasing = LV_COLOR_DEPTH > 8 ? 1 : 0;
+ driver->screen_transp = 0;
+ driver->dpi = LV_DPI_DEF;
+ driver->color_chroma_key = LV_COLOR_CHROMA_KEY;
+
+
+#if LV_USE_GPU_STM32_DMA2D
+ driver->draw_ctx_init = lv_draw_stm32_dma2d_ctx_init;
+ driver->draw_ctx_deinit = lv_draw_stm32_dma2d_ctx_init;
+ driver->draw_ctx_size = sizeof(lv_draw_stm32_dma2d_ctx_t);
+#elif LV_USE_GPU_SWM341_DMA2D
+ driver->draw_ctx_init = lv_draw_swm341_dma2d_ctx_init;
+ driver->draw_ctx_deinit = lv_draw_swm341_dma2d_ctx_init;
+ driver->draw_ctx_size = sizeof(lv_draw_swm341_dma2d_ctx_t);
+#elif LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE
+ driver->draw_ctx_init = lv_draw_nxp_ctx_init;
+ driver->draw_ctx_deinit = lv_draw_nxp_ctx_deinit;
+ driver->draw_ctx_size = sizeof(lv_draw_nxp_ctx_t);
+#elif LV_USE_GPU_SDL
+ driver->draw_ctx_init = lv_draw_sdl_init_ctx;
+ driver->draw_ctx_deinit = lv_draw_sdl_deinit_ctx;
+ driver->draw_ctx_size = sizeof(lv_draw_sdl_ctx_t);
+#elif LV_USE_GPU_ARM2D
+ driver->draw_ctx_init = lv_draw_arm2d_ctx_init;
+ driver->draw_ctx_deinit = lv_draw_arm2d_ctx_init;
+ driver->draw_ctx_size = sizeof(lv_draw_arm2d_ctx_t);
+#else
+ driver->draw_ctx_init = lv_draw_sw_init_ctx;
+ driver->draw_ctx_deinit = lv_draw_sw_init_ctx;
+ driver->draw_ctx_size = sizeof(lv_draw_sw_ctx_t);
+#endif
+
+}
+
+/**
+ * Initialize a display buffer
+ * @param draw_buf pointer `lv_disp_draw_buf_t` variable to initialize
+ * @param buf1 A buffer to be used by LVGL to draw the image.
+ * Always has to specified and can't be NULL.
+ * Can be an array allocated by the user. E.g. `static lv_color_t disp_buf1[1024 * 10]`
+ * Or a memory address e.g. in external SRAM
+ * @param buf2 Optionally specify a second buffer to make image rendering and image flushing
+ * (sending to the display) parallel.
+ * In the `disp_drv->flush` you should use DMA or similar hardware to send
+ * the image to the display in the background.
+ * It lets LVGL to render next frame into the other buffer while previous is being
+ * sent. Set to `NULL` if unused.
+ * @param size_in_px_cnt size of the `buf1` and `buf2` in pixel count.
+ */
+void lv_disp_draw_buf_init(lv_disp_draw_buf_t * draw_buf, void * buf1, void * buf2, uint32_t size_in_px_cnt)
+{
+ lv_memset_00(draw_buf, sizeof(lv_disp_draw_buf_t));
+
+ draw_buf->buf1 = buf1;
+ draw_buf->buf2 = buf2;
+ draw_buf->buf_act = draw_buf->buf1;
+ draw_buf->size = size_in_px_cnt;
+}
+
+/**
+ * Register an initialized display driver.
+ * Automatically set the first display as active.
+ * @param driver pointer to an initialized 'lv_disp_drv_t' variable. Only its pointer is saved!
+ * @return pointer to the new display or NULL on error
+ */
+lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
+{
+ lv_disp_t * disp = _lv_ll_ins_head(&LV_GC_ROOT(_lv_disp_ll));
+ LV_ASSERT_MALLOC(disp);
+ if(!disp) {
+ return NULL;
+ }
+
+ /*Create a draw context if not created yet*/
+ if(driver->draw_ctx == NULL) {
+ lv_draw_ctx_t * draw_ctx = lv_mem_alloc(driver->draw_ctx_size);
+ LV_ASSERT_MALLOC(draw_ctx);
+ if(draw_ctx == NULL) return NULL;
+ driver->draw_ctx_init(driver, draw_ctx);
+ driver->draw_ctx = draw_ctx;
+ }
+
+ lv_memset_00(disp, sizeof(lv_disp_t));
+
+ disp->driver = driver;
+
+ disp->inv_en_cnt = 1;
+
+ lv_disp_t * disp_def_tmp = disp_def;
+ disp_def = disp; /*Temporarily change the default screen to create the default screens on the
+ new display*/
+ /*Create a refresh timer*/
+ disp->refr_timer = lv_timer_create(_lv_disp_refr_timer, LV_DISP_DEF_REFR_PERIOD, disp);
+ LV_ASSERT_MALLOC(disp->refr_timer);
+ if(disp->refr_timer == NULL) {
+ lv_mem_free(disp);
+ return NULL;
+ }
+
+ if(driver->full_refresh && driver->draw_buf->size < (uint32_t)driver->hor_res * driver->ver_res) {
+ driver->full_refresh = 0;
+ LV_LOG_WARN("full_refresh requires at least screen sized draw buffer(s)");
+ }
+
+ disp->bg_color = lv_color_white();
+#if LV_COLOR_SCREEN_TRANSP
+ disp->bg_opa = LV_OPA_TRANSP;
+#else
+ disp->bg_opa = LV_OPA_COVER;
+#endif
+
+#if LV_USE_THEME_DEFAULT
+ if(lv_theme_default_is_inited() == false) {
+ disp->theme = lv_theme_default_init(disp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED),
+ LV_THEME_DEFAULT_DARK, LV_FONT_DEFAULT);
+ }
+ else {
+ disp->theme = lv_theme_default_get();
+ }
+#endif
+
+ disp->act_scr = lv_obj_create(NULL); /*Create a default screen on the display*/
+ disp->top_layer = lv_obj_create(NULL); /*Create top layer on the display*/
+ disp->sys_layer = lv_obj_create(NULL); /*Create sys layer on the display*/
+ lv_obj_remove_style_all(disp->top_layer);
+ lv_obj_remove_style_all(disp->sys_layer);
+ lv_obj_clear_flag(disp->top_layer, LV_OBJ_FLAG_CLICKABLE);
+ lv_obj_clear_flag(disp->sys_layer, LV_OBJ_FLAG_CLICKABLE);
+
+ lv_obj_set_scrollbar_mode(disp->top_layer, LV_SCROLLBAR_MODE_OFF);
+ lv_obj_set_scrollbar_mode(disp->sys_layer, LV_SCROLLBAR_MODE_OFF);
+
+ lv_obj_invalidate(disp->act_scr);
+
+ disp_def = disp_def_tmp; /*Revert the default display*/
+ if(disp_def == NULL) disp_def = disp; /*Initialize the default display*/
+
+ lv_timer_ready(disp->refr_timer); /*Be sure the screen will be refreshed immediately on start up*/
+
+ return disp;
+}
+
+/**
+ * Update the driver in run time.
+ * @param disp pointer to a display. (return value of `lv_disp_drv_register`)
+ * @param new_drv pointer to the new driver
+ */
+void lv_disp_drv_update(lv_disp_t * disp, lv_disp_drv_t * new_drv)
+{
+ disp->driver = new_drv;
+
+ if(disp->driver->full_refresh &&
+ disp->driver->draw_buf->size < (uint32_t)disp->driver->hor_res * disp->driver->ver_res) {
+ disp->driver->full_refresh = 0;
+ LV_LOG_WARN("full_refresh requires at least screen sized draw buffer(s)");
+ }
+
+ lv_coord_t w = lv_disp_get_hor_res(disp);
+ lv_coord_t h = lv_disp_get_ver_res(disp);
+ uint32_t i;
+ for(i = 0; i < disp->screen_cnt; i++) {
+ lv_area_t prev_coords;
+ lv_obj_get_coords(disp->screens[i], &prev_coords);
+ lv_area_set_width(&disp->screens[i]->coords, w);
+ lv_area_set_height(&disp->screens[i]->coords, h);
+ lv_event_send(disp->screens[i], LV_EVENT_SIZE_CHANGED, &prev_coords);
+ }
+
+ /*
+ * This method is usually called upon orientation change, thus the screen is now a
+ * different size.
+ * The object invalidated its previous area. That area is now out of the screen area
+ * so we reset all invalidated areas and invalidate the active screen's new area only.
+ */
+ lv_memset_00(disp->inv_areas, sizeof(disp->inv_areas));
+ lv_memset_00(disp->inv_area_joined, sizeof(disp->inv_area_joined));
+ disp->inv_p = 0;
+ if(disp->act_scr != NULL) lv_obj_invalidate(disp->act_scr);
+
+ lv_obj_tree_walk(NULL, invalidate_layout_cb, NULL);
+
+ if(disp->driver->drv_update_cb) disp->driver->drv_update_cb(disp->driver);
+}
+
+/**
+ * Remove a display
+ * @param disp pointer to display
+ */
+void lv_disp_remove(lv_disp_t * disp)
+{
+ bool was_default = false;
+ if(disp == lv_disp_get_default()) was_default = true;
+
+ /*Detach the input devices*/
+ lv_indev_t * indev;
+ indev = lv_indev_get_next(NULL);
+ while(indev) {
+ if(indev->driver->disp == disp) {
+ indev->driver->disp = NULL;
+ }
+ indev = lv_indev_get_next(indev);
+ }
+
+ /** delete screen and other obj */
+ if(disp->sys_layer) {
+ lv_obj_del(disp->sys_layer);
+ disp->sys_layer = NULL;
+ }
+ if(disp->top_layer) {
+ lv_obj_del(disp->top_layer);
+ disp->top_layer = NULL;
+ }
+ while(disp->screen_cnt != 0) {
+ /*Delete the screenst*/
+ lv_obj_del(disp->screens[0]);
+ }
+
+ _lv_ll_remove(&LV_GC_ROOT(_lv_disp_ll), disp);
+ if(disp->refr_timer) lv_timer_del(disp->refr_timer);
+ lv_mem_free(disp);
+
+ if(was_default) lv_disp_set_default(_lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll)));
+}
+
+/**
+ * Set a default display. The new screens will be created on it by default.
+ * @param disp pointer to a display
+ */
+void lv_disp_set_default(lv_disp_t * disp)
+{
+ disp_def = disp;
+}
+
+/**
+ * Get the default display
+ * @return pointer to the default display
+ */
+lv_disp_t * lv_disp_get_default(void)
+{
+ return disp_def;
+}
+
+/**
+ * Get the horizontal resolution of a display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the horizontal resolution of the display
+ */
+lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+
+ if(disp == NULL) {
+ return 0;
+ }
+ else {
+ switch(disp->driver->rotated) {
+ case LV_DISP_ROT_90:
+ case LV_DISP_ROT_270:
+ return disp->driver->ver_res;
+ default:
+ return disp->driver->hor_res;
+ }
+ }
+}
+
+/**
+ * Get the vertical resolution of a display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the vertical resolution of the display
+ */
+lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+
+ if(disp == NULL) {
+ return 0;
+ }
+ else {
+ switch(disp->driver->rotated) {
+ case LV_DISP_ROT_90:
+ case LV_DISP_ROT_270:
+ return disp->driver->hor_res;
+ default:
+ return disp->driver->ver_res;
+ }
+ }
+}
+
+/**
+ * Get the full / physical horizontal resolution of a display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the full / physical horizontal resolution of the display
+ */
+lv_coord_t lv_disp_get_physical_hor_res(lv_disp_t * disp)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+
+ if(disp == NULL) {
+ return 0;
+ }
+ else {
+ switch(disp->driver->rotated) {
+ case LV_DISP_ROT_90:
+ case LV_DISP_ROT_270:
+ return disp->driver->physical_ver_res > 0 ? disp->driver->physical_ver_res : disp->driver->ver_res;
+ default:
+ return disp->driver->physical_hor_res > 0 ? disp->driver->physical_hor_res : disp->driver->hor_res;
+ }
+ }
+}
+
+/**
+ * Get the full / physical vertical resolution of a display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the full / physical vertical resolution of the display
+ */
+lv_coord_t lv_disp_get_physical_ver_res(lv_disp_t * disp)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+
+ if(disp == NULL) {
+ return 0;
+ }
+ else {
+ switch(disp->driver->rotated) {
+ case LV_DISP_ROT_90:
+ case LV_DISP_ROT_270:
+ return disp->driver->physical_hor_res > 0 ? disp->driver->physical_hor_res : disp->driver->hor_res;
+ default:
+ return disp->driver->physical_ver_res > 0 ? disp->driver->physical_ver_res : disp->driver->ver_res;
+ }
+ }
+}
+
+/**
+ * Get the horizontal offset from the full / physical display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the horizontal offset from the full / physical display
+ */
+lv_coord_t lv_disp_get_offset_x(lv_disp_t * disp)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+
+ if(disp == NULL) {
+ return 0;
+ }
+ else {
+ switch(disp->driver->rotated) {
+ case LV_DISP_ROT_90:
+ return disp->driver->offset_y;
+ case LV_DISP_ROT_180:
+ return lv_disp_get_physical_hor_res(disp) - disp->driver->offset_x;
+ case LV_DISP_ROT_270:
+ return lv_disp_get_physical_hor_res(disp) - disp->driver->offset_y;
+ default:
+ return disp->driver->offset_x;
+ }
+ }
+}
+
+/**
+ * Get the vertical offset from the full / physical display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the horizontal offset from the full / physical display
+ */
+lv_coord_t lv_disp_get_offset_y(lv_disp_t * disp)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+
+ if(disp == NULL) {
+ return 0;
+ }
+ else {
+ switch(disp->driver->rotated) {
+ case LV_DISP_ROT_90:
+ return disp->driver->offset_x;
+ case LV_DISP_ROT_180:
+ return lv_disp_get_physical_ver_res(disp) - disp->driver->offset_y;
+ case LV_DISP_ROT_270:
+ return lv_disp_get_physical_ver_res(disp) - disp->driver->offset_x;
+ default:
+ return disp->driver->offset_y;
+ }
+ }
+}
+
+/**
+ * Get if anti-aliasing is enabled for a display or not
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return true: anti-aliasing is enabled; false: disabled
+ */
+bool lv_disp_get_antialiasing(lv_disp_t * disp)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+ if(disp == NULL) return false;
+
+ return disp->driver->antialiasing ? true : false;
+}
+
+/**
+ * Get the DPI of the display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return dpi of the display
+ */
+lv_coord_t lv_disp_get_dpi(const lv_disp_t * disp)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+ if(disp == NULL) return LV_DPI_DEF; /*Do not return 0 because it might be a divider*/
+ return disp->driver->dpi;
+}
+
+/**
+ * Call in the display driver's `flush_cb` function when the flushing is finished
+ * @param disp_drv pointer to display driver in `flush_cb` where this function is called
+ */
+LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv)
+{
+ disp_drv->draw_buf->flushing = 0;
+ disp_drv->draw_buf->flushing_last = 0;
+}
+
+/**
+ * Tell if it's the last area of the refreshing process.
+ * Can be called from `flush_cb` to execute some special display refreshing if needed when all areas area flushed.
+ * @param disp_drv pointer to display driver
+ * @return true: it's the last area to flush; false: there are other areas too which will be refreshed soon
+ */
+LV_ATTRIBUTE_FLUSH_READY bool lv_disp_flush_is_last(lv_disp_drv_t * disp_drv)
+{
+ return disp_drv->draw_buf->flushing_last;
+}
+
+/**
+ * Get the next display.
+ * @param disp pointer to the current display. NULL to initialize.
+ * @return the next display or NULL if no more. Give the first display when the parameter is NULL
+ */
+lv_disp_t * lv_disp_get_next(lv_disp_t * disp)
+{
+ if(disp == NULL)
+ return _lv_ll_get_head(&LV_GC_ROOT(_lv_disp_ll));
+ else
+ return _lv_ll_get_next(&LV_GC_ROOT(_lv_disp_ll), disp);
+}
+
+/**
+ * Get the internal buffer of a display
+ * @param disp pointer to a display
+ * @return pointer to the internal buffers
+ */
+lv_disp_draw_buf_t * lv_disp_get_draw_buf(lv_disp_t * disp)
+{
+ return disp->driver->draw_buf;
+}
+
+/**
+ * Set the rotation of this display.
+ * @param disp pointer to a display (NULL to use the default display)
+ * @param rotation rotation angle
+ */
+void lv_disp_set_rotation(lv_disp_t * disp, lv_disp_rot_t rotation)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+ if(disp == NULL) return;
+
+ disp->driver->rotated = rotation;
+ lv_disp_drv_update(disp, disp->driver);
+}
+
+/**
+ * Get the current rotation of this display.
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return rotation angle
+ */
+lv_disp_rot_t lv_disp_get_rotation(lv_disp_t * disp)
+{
+ if(disp == NULL) disp = lv_disp_get_default();
+ if(disp == NULL) return LV_DISP_ROT_NONE;
+ return disp->driver->rotated;
+}
+
+void lv_disp_drv_use_generic_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf)
+{
+ switch(cf) {
+ case LV_IMG_CF_TRUE_COLOR_ALPHA:
+ disp_drv->set_px_cb = set_px_true_color_alpha;
+ break;
+ case LV_IMG_CF_ALPHA_1BIT:
+ disp_drv->set_px_cb = set_px_cb_alpha1;
+ break;
+ case LV_IMG_CF_ALPHA_2BIT:
+ disp_drv->set_px_cb = set_px_cb_alpha2;
+ break;
+ case LV_IMG_CF_ALPHA_4BIT:
+ disp_drv->set_px_cb = set_px_cb_alpha4;
+ break;
+ case LV_IMG_CF_ALPHA_8BIT:
+ disp_drv->set_px_cb = set_px_cb_alpha8;
+ break;
+ default:
+ disp_drv->set_px_cb = NULL;
+ }
+}
+
+/**********************
+ * STATIC FUNCTIONS
+ **********************/
+
+static lv_obj_tree_walk_res_t invalidate_layout_cb(lv_obj_t * obj, void * user_data)
+{
+ LV_UNUSED(user_data);
+ lv_obj_mark_layout_as_dirty(obj);
+ return LV_OBJ_TREE_WALK_NEXT;
+}
+
+static void set_px_cb_alpha1(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) disp_drv; /*Unused*/
+
+ if(opa <= LV_OPA_MIN) return;
+ lv_img_dsc_t d;
+ d.data = buf;
+ d.header.w = buf_w;
+ d.header.cf = LV_IMG_CF_ALPHA_1BIT;
+
+ set_px_alpha_generic(&d, x, y, color, opa);
+}
+
+static void set_px_cb_alpha2(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) disp_drv; /*Unused*/
+
+ if(opa <= LV_OPA_MIN) return;
+ lv_img_dsc_t d;
+ d.data = buf;
+ d.header.w = buf_w;
+ d.header.cf = LV_IMG_CF_ALPHA_2BIT;
+
+ set_px_alpha_generic(&d, x, y, color, opa);
+}
+
+static void set_px_cb_alpha4(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) disp_drv; /*Unused*/
+
+ if(opa <= LV_OPA_MIN) return;
+ lv_img_dsc_t d;
+ d.data = buf;
+ d.header.w = buf_w;
+ d.header.cf = LV_IMG_CF_ALPHA_4BIT;
+
+ set_px_alpha_generic(&d, x, y, color, opa);
+}
+
+static void set_px_cb_alpha8(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) disp_drv; /*Unused*/
+
+ if(opa <= LV_OPA_MIN) return;
+ lv_img_dsc_t d;
+ d.data = buf;
+ d.header.w = buf_w;
+ d.header.cf = LV_IMG_CF_ALPHA_8BIT;
+
+ set_px_alpha_generic(&d, x, y, color, opa);
+}
+
+static void set_px_alpha_generic(lv_img_dsc_t * d, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa)
+{
+ d->header.always_zero = 0;
+ d->header.h = 1; /*Doesn't matter*/
+
+ uint8_t br = lv_color_brightness(color);
+ if(opa < LV_OPA_MAX) {
+ uint8_t bg = lv_img_buf_get_px_alpha(d, x, y);
+ br = (uint16_t)((uint16_t)br * opa + (bg * (255 - opa))) >> 8;
+ }
+
+ lv_img_buf_set_px_alpha(d, x, y, br);
+}
+
+static void set_px_true_color_alpha(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) disp_drv; /*Unused*/
+
+ uint8_t * buf_px = buf + (buf_w * y * LV_IMG_PX_SIZE_ALPHA_BYTE + x * LV_IMG_PX_SIZE_ALPHA_BYTE);
+
+ lv_color_t bg_color;
+ lv_color_t res_color;
+ lv_opa_t bg_opa = buf_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
+#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
+ bg_color.full = buf_px[0];
+ lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf_px[2]);
+ if(buf_px[1] <= LV_OPA_MIN) return;
+ buf_px[0] = res_color.full;
+#elif LV_COLOR_DEPTH == 16
+ bg_color.full = buf_px[0] + (buf_px[1] << 8);
+ lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf_px[2]);
+ if(buf_px[2] <= LV_OPA_MIN) return;
+ buf_px[0] = res_color.full & 0xff;
+ buf_px[1] = res_color.full >> 8;
+#elif LV_COLOR_DEPTH == 32
+ bg_color = *((lv_color_t *)buf_px);
+ lv_color_mix_with_alpha(bg_color, bg_opa, color, opa, &res_color, &buf_px[3]);
+ if(buf_px[3] <= LV_OPA_MIN) return;
+ buf_px[0] = res_color.ch.blue;
+ buf_px[1] = res_color.ch.green;
+ buf_px[2] = res_color.ch.red;
+#endif
+
+}
diff --git a/lib/lvgl/src/hal/lv_hal_disp.h b/lib/lvgl/src/hal/lv_hal_disp.h
new file mode 100644
index 00000000..d3425fe4
--- /dev/null
+++ b/lib/lvgl/src/hal/lv_hal_disp.h
@@ -0,0 +1,371 @@
+/**
+ * @file lv_hal_disp.h
+ *
+ * @description Display Driver HAL interface header file
+ *
+ */
+
+#ifndef LV_HAL_DISP_H
+#define LV_HAL_DISP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ * INCLUDES
+ *********************/
+#include <stdint.h>
+#include <stdbool.h>
+#include "lv_hal.h"
+#include "../draw/lv_draw.h"
+#include "../misc/lv_color.h"
+#include "../misc/lv_area.h"
+#include "../misc/lv_ll.h"
+#include "../misc/lv_timer.h"
+
+/*********************
+ * DEFINES
+ *********************/
+#ifndef LV_INV_BUF_SIZE
+#define LV_INV_BUF_SIZE 32 /*Buffer size for invalid areas*/
+#endif
+
+#ifndef LV_ATTRIBUTE_FLUSH_READY
+#define LV_ATTRIBUTE_FLUSH_READY
+#endif
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+struct _lv_obj_t;
+struct _lv_disp_t;
+struct _lv_disp_drv_t;
+struct _lv_theme_t;
+
+/**
+ * Structure for holding display buffer information.
+ */
+typedef struct _lv_disp_draw_buf_t {
+ void * buf1; /**< First display buffer.*/
+ void * buf2; /**< Second display buffer.*/
+
+ /*Internal, used by the library*/
+ void * buf_act;
+ uint32_t size; /*In pixel count*/
+ /*1: flushing is in progress. (It can't be a bit field because when it's cleared from IRQ Read-Modify-Write issue might occur)*/
+ volatile int flushing;
+ /*1: It was the last chunk to flush. (It can't be a bit field because when it's cleared from IRQ Read-Modify-Write issue might occur)*/
+ volatile int flushing_last;
+ volatile uint32_t last_area : 1; /*1: the last area is being rendered*/
+ volatile uint32_t last_part : 1; /*1: the last part of the current area is being rendered*/
+} lv_disp_draw_buf_t;
+
+typedef enum {
+ LV_DISP_ROT_NONE = 0,
+ LV_DISP_ROT_90,
+ LV_DISP_ROT_180,
+ LV_DISP_ROT_270
+} lv_disp_rot_t;
+
+/**
+ * Display Driver structure to be registered by HAL.
+ * Only its pointer will be saved in `lv_disp_t` so it should be declared as
+ * `static lv_disp_drv_t my_drv` or allocated dynamically.
+ */
+typedef struct _lv_disp_drv_t {
+
+ lv_coord_t hor_res; /**< Horizontal resolution.*/
+ lv_coord_t ver_res; /**< Vertical resolution.*/
+
+ lv_coord_t
+ physical_hor_res; /**< Horizontal resolution of the full / physical display. Set to -1 for fullscreen mode.*/
+ lv_coord_t
+ physical_ver_res; /**< Vertical resolution of the full / physical display. Set to -1 for fullscreen mode.*/
+ lv_coord_t
+ offset_x; /**< Horizontal offset from the full / physical display. Set to 0 for fullscreen mode.*/
+ lv_coord_t offset_y; /**< Vertical offset from the full / physical display. Set to 0 for fullscreen mode.*/
+
+ /** Pointer to a buffer initialized with `lv_disp_draw_buf_init()`.
+ * LVGL will use this buffer(s) to draw the screens contents*/
+ lv_disp_draw_buf_t * draw_buf;
+
+ uint32_t direct_mode : 1; /**< 1: Use screen-sized buffers and draw to absolute coordinates*/
+ uint32_t full_refresh : 1; /**< 1: Always make the whole screen redrawn*/
+ uint32_t sw_rotate : 1; /**< 1: use software rotation (slower)*/
+ uint32_t antialiasing : 1; /**< 1: anti-aliasing is enabled on this display.*/
+ uint32_t rotated : 2; /**< 1: turn the display by 90 degree. @warning Does not update coordinates for you!*/
+ uint32_t screen_transp : 1; /**Handle if the screen doesn't have a solid (opa == LV_OPA_COVER) background.
+ * Use only if required because it's slower.*/
+
+ uint32_t dpi : 10; /** DPI (dot per inch) of the display. Default value is `LV_DPI_DEF`.*/
+
+ /** MANDATORY: Write the internal buffer (draw_buf) to the display. 'lv_disp_flush_ready()' has to be
+ * called when finished*/
+ void (*flush_cb)(struct _lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
+
+ /** OPTIONAL: Extend the invalidated areas to match with the display drivers requirements
+ * E.g. round `y` to, 8, 16 ..) on a monochrome display*/
+ void (*rounder_cb)(struct _lv_disp_drv_t * disp_drv, lv_area_t * area);
+
+ /** OPTIONAL: Set a pixel in a buffer according to the special requirements of the display
+ * Can be used for color format not supported in LittelvGL. E.g. 2 bit -> 4 gray scales
+ * @note Much slower then drawing with supported color formats.*/
+ void (*set_px_cb)(struct _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 (*clear_cb)(struct _lv_disp_drv_t * disp_drv, uint8_t * buf, uint32_t size);
+
+
+ /** OPTIONAL: Called after every refresh cycle to tell the rendering and flushing time + the
+ * number of flushed pixels*/
+ void (*monitor_cb)(struct _lv_disp_drv_t * disp_drv, uint32_t time, uint32_t px);
+
+ /** OPTIONAL: Called periodically while lvgl waits for operation to be completed.
+ * For example flushing or GPU
+ * User can execute very simple tasks here or yield the task*/
+ void (*wait_cb)(struct _lv_disp_drv_t * disp_drv);
+
+ /** OPTIONAL: Called when lvgl needs any CPU cache that affects rendering to be cleaned*/
+ void (*clean_dcache_cb)(struct _lv_disp_drv_t * disp_drv);
+
+ /** OPTIONAL: called when driver parameters are updated */
+ void (*drv_update_cb)(struct _lv_disp_drv_t * disp_drv);
+
+ /** OPTIONAL: called when start rendering */
+ void (*render_start_cb)(struct _lv_disp_drv_t * disp_drv);
+
+ /** On CHROMA_KEYED images this color will be transparent.
+ * `LV_COLOR_CHROMA_KEY` by default. (lv_conf.h)*/
+ lv_color_t color_chroma_key;
+
+ lv_draw_ctx_t * draw_ctx;
+ void (*draw_ctx_init)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx);
+ void (*draw_ctx_deinit)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx);
+ size_t draw_ctx_size;
+
+#if LV_USE_USER_DATA
+ void * user_data; /**< Custom display driver user data*/
+#endif
+
+} lv_disp_drv_t;
+
+/**
+ * Display structure.
+ * @note `lv_disp_drv_t` should be the first member of the structure.
+ */
+typedef struct _lv_disp_t {
+ /**< Driver to the display*/
+ struct _lv_disp_drv_t * driver;
+
+ /**< A timer which periodically checks the dirty areas and refreshes them*/
+ lv_timer_t * refr_timer;
+
+ /**< The theme assigned to the screen*/
+ struct _lv_theme_t * theme;
+
+ /** Screens of the display*/
+ struct _lv_obj_t ** screens; /**< Array of screen objects.*/
+ struct _lv_obj_t * act_scr; /**< Currently active screen on this display*/
+ struct _lv_obj_t * prev_scr; /**< Previous screen. Used during screen animations*/
+ struct _lv_obj_t * scr_to_load; /**< The screen prepared to load in lv_scr_load_anim*/
+ struct _lv_obj_t * top_layer; /**< @see lv_disp_get_layer_top*/
+ struct _lv_obj_t * sys_layer; /**< @see lv_disp_get_layer_sys*/
+ uint32_t screen_cnt;
+uint8_t draw_prev_over_act :
+ 1; /**< 1: Draw previous screen over active screen*/
+uint8_t del_prev :
+ 1; /**< 1: Automatically delete the previous screen when the screen load animation is ready*/
+ uint8_t rendering_in_progress : 1; /**< 1: The current screen rendering is in progress*/
+
+ lv_opa_t bg_opa; /**<Opacity of the background color or wallpaper*/
+ lv_color_t bg_color; /**< Default display color when screens are transparent*/
+ const void * bg_img; /**< An image source to display as wallpaper*/
+
+ /** Invalidated (marked to redraw) areas*/
+ lv_area_t inv_areas[LV_INV_BUF_SIZE];
+ uint8_t inv_area_joined[LV_INV_BUF_SIZE];
+ uint16_t inv_p;
+ int32_t inv_en_cnt;
+
+ /*Miscellaneous data*/
+ uint32_t last_activity_time; /**< Last time when there was activity on this display*/
+} lv_disp_t;
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+
+/**
+ * Initialize a display driver with default values.
+ * It is used to have known values in the fields and not junk in memory.
+ * After it you can safely set only the fields you need.
+ * @param driver pointer to driver variable to initialize
+ */
+void lv_disp_drv_init(lv_disp_drv_t * driver);
+
+/**
+ * Initialize a display buffer
+ * @param draw_buf pointer `lv_disp_draw_buf_t` variable to initialize
+ * @param buf1 A buffer to be used by LVGL to draw the image.
+ * Always has to specified and can't be NULL.
+ * Can be an array allocated by the user. E.g. `static lv_color_t disp_buf1[1024 * 10]`
+ * Or a memory address e.g. in external SRAM
+ * @param buf2 Optionally specify a second buffer to make image rendering and image flushing
+ * (sending to the display) parallel.
+ * In the `disp_drv->flush` you should use DMA or similar hardware to send
+ * the image to the display in the background.
+ * It lets LVGL to render next frame into the other buffer while previous is being
+ * sent. Set to `NULL` if unused.
+ * @param size_in_px_cnt size of the `buf1` and `buf2` in pixel count.
+ */
+void lv_disp_draw_buf_init(lv_disp_draw_buf_t * draw_buf, void * buf1, void * buf2, uint32_t size_in_px_cnt);
+
+/**
+ * Register an initialized display driver.
+ * Automatically set the first display as active.
+ * @param driver pointer to an initialized 'lv_disp_drv_t' variable. Only its pointer is saved!
+ * @return pointer to the new display or NULL on error
+ */
+lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver);
+
+/**
+ * Update the driver in run time.
+ * @param disp pointer to a display. (return value of `lv_disp_drv_register`)
+ * @param new_drv pointer to the new driver
+ */
+void lv_disp_drv_update(lv_disp_t * disp, lv_disp_drv_t * new_drv);
+
+/**
+ * Remove a display
+ * @param disp pointer to display
+ */
+void lv_disp_remove(lv_disp_t * disp);
+
+/**
+ * Set a default display. The new screens will be created on it by default.
+ * @param disp pointer to a display
+ */
+void lv_disp_set_default(lv_disp_t * disp);
+
+/**
+ * Get the default display
+ * @return pointer to the default display
+ */
+lv_disp_t * lv_disp_get_default(void);
+
+/**
+ * Get the horizontal resolution of a display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the horizontal resolution of the display
+ */
+lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp);
+
+/**
+ * Get the vertical resolution of a display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the vertical resolution of the display
+ */
+lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp);
+
+/**
+ * Get the full / physical horizontal resolution of a display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the full / physical horizontal resolution of the display
+ */
+lv_coord_t lv_disp_get_physical_hor_res(lv_disp_t * disp);
+
+/**
+ * Get the full / physical vertical resolution of a display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the full / physical vertical resolution of the display
+ */
+lv_coord_t lv_disp_get_physical_ver_res(lv_disp_t * disp);
+
+/**
+ * Get the horizontal offset from the full / physical display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the horizontal offset from the full / physical display
+ */
+lv_coord_t lv_disp_get_offset_x(lv_disp_t * disp);
+
+/**
+ * Get the vertical offset from the full / physical display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return the horizontal offset from the full / physical display
+ */
+lv_coord_t lv_disp_get_offset_y(lv_disp_t * disp);
+
+/**
+ * Get if anti-aliasing is enabled for a display or not
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return true: anti-aliasing is enabled; false: disabled
+ */
+bool lv_disp_get_antialiasing(lv_disp_t * disp);
+
+/**
+ * Get the DPI of the display
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return dpi of the display
+ */
+lv_coord_t lv_disp_get_dpi(const lv_disp_t * disp);
+
+
+/**
+ * Set the rotation of this display.
+ * @param disp pointer to a display (NULL to use the default display)
+ * @param rotation rotation angle
+ */
+void lv_disp_set_rotation(lv_disp_t * disp, lv_disp_rot_t rotation);
+
+/**
+ * Get the current rotation of this display.
+ * @param disp pointer to a display (NULL to use the default display)
+ * @return rotation angle
+ */
+lv_disp_rot_t lv_disp_get_rotation(lv_disp_t * disp);
+
+//! @cond Doxygen_Suppress
+
+/**
+ * Call in the display driver's `flush_cb` function when the flushing is finished
+ * @param disp_drv pointer to display driver in `flush_cb` where this function is called
+ */
+LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv);
+
+/**
+ * Tell if it's the last area of the refreshing process.
+ * Can be called from `flush_cb` to execute some special display refreshing if needed when all areas area flushed.
+ * @param disp_drv pointer to display driver
+ * @return true: it's the last area to flush; false: there are other areas too which will be refreshed soon
+ */
+LV_ATTRIBUTE_FLUSH_READY bool lv_disp_flush_is_last(lv_disp_drv_t * disp_drv);
+
+//! @endcond
+
+/**
+ * Get the next display.
+ * @param disp pointer to the current display. NULL to initialize.
+ * @return the next display or NULL if no more. Give the first display when the parameter is NULL
+ */
+lv_disp_t * lv_disp_get_next(lv_disp_t * disp);
+
+/**
+ * Get the internal buffer of a display
+ * @param disp pointer to a display
+ * @return pointer to the internal buffers
+ */
+lv_disp_draw_buf_t * lv_disp_get_draw_buf(lv_disp_t * disp);
+
+void lv_disp_drv_use_generic_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf);
+
+/**********************
+ * MACROS
+ **********************/
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif
diff --git a/lib/lvgl/src/hal/lv_hal_indev.c b/lib/lvgl/src/hal/lv_hal_indev.c
new file mode 100644
index 00000000..c3661e42
--- /dev/null
+++ b/lib/lvgl/src/hal/lv_hal_indev.c
@@ -0,0 +1,195 @@
+/**
+ * @file lv_hal_indev.c
+ *
+ * @description Input device HAL interface
+ *
+ */
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "../misc/lv_assert.h"
+#include "../hal/lv_hal_indev.h"
+#include "../core/lv_indev.h"
+#include "../misc/lv_mem.h"
+#include "../misc/lv_gc.h"
+#include "lv_hal_disp.h"
+
+/*********************
+ * DEFINES
+ *********************/
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+
+/**********************
+ * STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ * STATIC VARIABLES
+ **********************/
+
+/**********************
+ * MACROS
+ **********************/
+#if LV_LOG_TRACE_INDEV
+ #define INDEV_TRACE(...) LV_LOG_TRACE(__VA_ARGS__)
+#else
+ #define INDEV_TRACE(...)
+#endif
+
+/**********************
+ * GLOBAL FUNCTIONS
+ **********************/
+
+/**
+ * Initialize an input device driver with default values.
+ * It is used to surly have known values in the fields ant not memory junk.
+ * After it you can set the fields.
+ * @param driver pointer to driver variable to initialize
+ */
+void lv_indev_drv_init(lv_indev_drv_t * driver)
+{
+ lv_memset_00(driver, sizeof(lv_indev_drv_t));
+
+ driver->type = LV_INDEV_TYPE_NONE;
+ driver->scroll_limit = LV_INDEV_DEF_SCROLL_LIMIT;
+ driver->scroll_throw = LV_INDEV_DEF_SCROLL_THROW;
+ driver->long_press_time = LV_INDEV_DEF_LONG_PRESS_TIME;
+ driver->long_press_repeat_time = LV_INDEV_DEF_LONG_PRESS_REP_TIME;
+ driver->gesture_limit = LV_INDEV_DEF_GESTURE_LIMIT;
+ driver->gesture_min_velocity = LV_INDEV_DEF_GESTURE_MIN_VELOCITY;
+}
+
+/**
+ * Register an initialized input device driver.
+ * @param driver pointer to an initialized 'lv_indev_drv_t' variable.
+ * Only pointer is saved, so the driver should be static or dynamically allocated.
+ * @return pointer to the new input device or NULL on error
+ */
+lv_indev_t * lv_indev_drv_register(lv_indev_drv_t * driver)
+{
+ if(driver->disp == NULL) driver->disp = lv_disp_get_default();
+
+ if(driver->disp == NULL) {
+ LV_LOG_WARN("lv_indev_drv_register: no display registered hence can't attach the indev to "
+ "a display");
+ return NULL;
+ }
+
+ lv_indev_t * indev = _lv_ll_ins_head(&LV_GC_ROOT(_lv_indev_ll));
+ LV_ASSERT_MALLOC(indev);
+ if(!indev) {
+ return NULL;
+ }
+
+ lv_memset_00(indev, sizeof(lv_indev_t));
+ indev->driver = driver;
+
+ indev->proc.reset_query = 1;
+ indev->driver->read_timer = lv_timer_create(lv_indev_read_timer_cb, LV_INDEV_DEF_READ_PERIOD, indev);
+
+ return indev;
+}
+
+/**
+ * Update the driver in run time.
+ * @param indev pointer to a input device. (return value of `lv_indev_drv_register`)
+ * @param new_drv pointer to the new driver
+ */
+void lv_indev_drv_update(lv_indev_t * indev, lv_indev_drv_t * new_drv)
+{
+ LV_ASSERT_NULL(indev);
+ LV_ASSERT_NULL(indev->driver);
+ LV_ASSERT_NULL(indev->driver->read_timer);
+ lv_timer_del(indev->driver->read_timer);
+
+ LV_ASSERT_NULL(new_drv);
+ if(new_drv->disp == NULL) {
+ new_drv->disp = lv_disp_get_default();
+ }
+ if(new_drv->disp == NULL) {
+ LV_LOG_WARN("lv_indev_drv_register: no display registered hence can't attach the indev to "
+ "a display");
+ indev->proc.disabled = true;
+ return;
+ }
+
+ indev->driver = new_drv;
+ indev->driver->read_timer = lv_timer_create(lv_indev_read_timer_cb, LV_INDEV_DEF_READ_PERIOD, indev);
+ indev->proc.reset_query = 1;
+}
+
+/**
+* Remove the provided input device. Make sure not to use the provided input device afterwards anymore.
+* @param indev pointer to delete
+*/
+void lv_indev_delete(lv_indev_t * indev)
+{
+ LV_ASSERT_NULL(indev);
+ LV_ASSERT_NULL(indev->driver);
+ LV_ASSERT_NULL(indev->driver->read_timer);
+ /*Clean up the read timer first*/
+ lv_timer_del(indev->driver->read_timer);
+ /*Remove the input device from the list*/
+ _lv_ll_remove(&LV_GC_ROOT(_lv_indev_ll), indev);
+ /*Free the memory of the input device*/
+ lv_mem_free(indev);
+}
+
+/**
+ * Get the next input device.
+ * @param indev pointer to the current input device. NULL to initialize.
+ * @return the next input devise or NULL if no more. Give the first input device when the parameter
+ * is NULL
+ */
+lv_indev_t * lv_indev_get_next(lv_indev_t * indev)
+{
+ if(indev == NULL)
+ return _lv_ll_get_head(&LV_GC_ROOT(_lv_indev_ll));
+ else
+ return _lv_ll_get_next(&LV_GC_ROOT(_lv_indev_ll), indev);
+}
+
+/**
+ * Read data from an input device.
+ * @param indev pointer to an input device
+ * @param data input device will write its data here
+ */
+void _lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data)
+{
+ lv_memset_00(data, sizeof(lv_indev_data_t));
+
+ /* For touchpad sometimes users don't set the last pressed coordinate on release.
+ * So be sure a coordinates are initialized to the last point */
+ if(indev->driver->type == LV_INDEV_TYPE_POINTER) {
+ data->point.x = indev->proc.types.pointer.last_raw_point.x;
+ data->point.y = indev->proc.types.pointer.last_raw_point.y;
+ }
+ /*Similarly set at least the last key in case of the user doesn't set it on release*/
+ else if(indev->driver->type == LV_INDEV_TYPE_KEYPAD) {
+ data->key = indev->proc.types.keypad.last_key;
+ }
+ /*For compatibility assume that used button was enter (encoder push)*/
+ else if(indev->driver->type == LV_INDEV_TYPE_ENCODER) {
+ data->key = LV_KEY_ENTER;
+ }
+
+ if(indev->driver->read_cb) {
+ INDEV_TRACE("calling indev_read_cb");
+ indev->driver->read_cb(indev->driver, data);
+ }
+ else {
+ LV_LOG_WARN("indev_read_cb is not registered");
+ }
+}
+
+/**********************
+ * STATIC FUNCTIONS
+ **********************/
diff --git a/lib/lvgl/src/hal/lv_hal_indev.h b/lib/lvgl/src/hal/lv_hal_indev.h
new file mode 100644
index 00000000..ca51a08c
--- /dev/null
+++ b/lib/lvgl/src/hal/lv_hal_indev.h
@@ -0,0 +1,239 @@
+/**
+ * @file lv_hal_indev.h
+ *
+ * @description Input Device HAL interface layer header file
+ *
+ */
+
+#ifndef LV_HAL_INDEV_H
+#define LV_HAL_INDEV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "../lv_conf_internal.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "../misc/lv_area.h"
+#include "../misc/lv_timer.h"
+
+/*********************
+ * DEFINES
+ *********************/
+
+/*Drag threshold in pixels*/
+#define LV_INDEV_DEF_SCROLL_LIMIT 10
+
+/*Drag throw slow-down in [%]. Greater value -> faster slow-down*/
+#define LV_INDEV_DEF_SCROLL_THROW 10
+
+/*Long press time in milliseconds.
+ *Time to send `LV_EVENT_LONG_PRESSSED`)*/
+#define LV_INDEV_DEF_LONG_PRESS_TIME 400
+
+/*Repeated trigger period in long press [ms]
+ *Time between `LV_EVENT_LONG_PRESSED_REPEAT*/
+#define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100
+
+
+/*Gesture threshold in pixels*/
+#define LV_INDEV_DEF_GESTURE_LIMIT 50
+
+/*Gesture min velocity at release before swipe (pixels)*/
+#define LV_INDEV_DEF_GESTURE_MIN_VELOCITY 3
+
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+struct _lv_obj_t;
+struct _lv_disp_t;
+struct _lv_group_t;
+struct _lv_indev_t;
+struct _lv_indev_drv_t;
+
+/** Possible input device types*/
+typedef enum {
+ LV_INDEV_TYPE_NONE, /**< Uninitialized state*/
+ LV_INDEV_TYPE_POINTER, /**< Touch pad, mouse, external button*/
+ LV_INDEV_TYPE_KEYPAD, /**< Keypad or keyboard*/
+ LV_INDEV_TYPE_BUTTON, /**< External (hardware button) which is assigned to a specific point of the screen*/
+ LV_INDEV_TYPE_ENCODER, /**< Encoder with only Left, Right turn and a Button*/
+} lv_indev_type_t;
+
+/** States for input devices*/
+typedef enum {
+ LV_INDEV_STATE_RELEASED = 0,
+ LV_INDEV_STATE_PRESSED
+} lv_indev_state_t;
+
+/** Data structure passed to an input driver to fill*/
+typedef struct {
+ lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/
+ uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/
+ uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/
+ int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/
+
+ lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/
+ bool continue_reading; /**< If set to true, the read callback is invoked again*/
+} lv_indev_data_t;
+
+/** Initialized by the user and registered by 'lv_indev_add()'*/
+typedef struct _lv_indev_drv_t {
+
+ /**< Input device type*/
+ lv_indev_type_t type;
+
+ /**< Function pointer to read input device data.*/
+ void (*read_cb)(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
+
+ /** Called when an action happened on the input device.
+ * The second parameter is the event from `lv_event_t`*/
+ void (*feedback_cb)(struct _lv_indev_drv_t *, uint8_t);
+
+#if LV_USE_USER_DATA
+ void * user_data;
+#endif
+
+ /**< Pointer to the assigned display*/
+ struct _lv_disp_t * disp;
+
+ /**< Timer to periodically read the input device*/
+ lv_timer_t * read_timer;
+
+ /**< Number of pixels to slide before actually drag the object*/
+ uint8_t scroll_limit;
+
+ /**< Drag throw slow-down in [%]. Greater value means faster slow-down*/
+ uint8_t scroll_throw;
+
+ /**< At least this difference should be between two points to evaluate as gesture*/
+ uint8_t gesture_min_velocity;
+
+ /**< At least this difference should be to send a gesture*/
+ uint8_t gesture_limit;
+
+ /**< Long press time in milliseconds*/
+ uint16_t long_press_time;
+
+ /**< Repeated trigger period in long press [ms]*/
+ uint16_t long_press_repeat_time;
+} lv_indev_drv_t;
+
+/** Run time data of input devices
+ * Internally used by the library, you should not need to touch it.
+ */
+typedef struct _lv_indev_proc_t {
+ lv_indev_state_t state; /**< Current state of the input device.*/
+ /*Flags*/
+ uint8_t long_pr_sent : 1;
+ uint8_t reset_query : 1;
+ uint8_t disabled : 1;
+ uint8_t wait_until_release : 1;
+
+ union {
+ struct {
+ /*Pointer and button data*/
+ lv_point_t act_point; /**< Current point of input device.*/
+ lv_point_t last_point; /**< Last point of input device.*/
+ lv_point_t last_raw_point; /**< Last point read from read_cb. */
+ lv_point_t vect; /**< Difference between `act_point` and `last_point`.*/
+ lv_point_t scroll_sum; /*Count the dragged pixels to check LV_INDEV_DEF_SCROLL_LIMIT*/
+ lv_point_t scroll_throw_vect;
+ lv_point_t scroll_throw_vect_ori;
+ struct _lv_obj_t * act_obj; /*The object being pressed*/
+ struct _lv_obj_t * last_obj; /*The last object which was pressed*/
+ struct _lv_obj_t * scroll_obj; /*The object being scrolled*/
+ struct _lv_obj_t * last_pressed; /*The lastly pressed object*/
+ lv_area_t scroll_area;
+
+ lv_point_t gesture_sum; /*Count the gesture pixels to check LV_INDEV_DEF_GESTURE_LIMIT*/
+ /*Flags*/
+ lv_dir_t scroll_dir : 4;
+ lv_dir_t gesture_dir : 4;
+ uint8_t gesture_sent : 1;
+ } pointer;
+ struct {
+ /*Keypad data*/
+ lv_indev_state_t last_state;
+ uint32_t last_key;
+ } keypad;
+ } types;
+
+ uint32_t pr_timestamp; /**< Pressed time stamp*/
+ uint32_t longpr_rep_timestamp; /**< Long press repeat time stamp*/
+} _lv_indev_proc_t;
+
+/** The main input device descriptor with driver, runtime data ('proc') and some additional
+ * information*/
+typedef struct _lv_indev_t {
+ struct _lv_indev_drv_t * driver;
+ _lv_indev_proc_t proc;
+ struct _lv_obj_t * cursor; /**< Cursor for LV_INPUT_TYPE_POINTER*/
+ struct _lv_group_t * group; /**< Keypad destination group*/
+ const lv_point_t * btn_points; /**< Array points assigned to the button ()screen will be pressed
+ here by the buttons*/
+} lv_indev_t;
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+
+/**
+ * Initialize an input device driver with default values.
+ * It is used to surely have known values in the fields and not memory junk.
+ * After it you can set the fields.
+ * @param driver pointer to driver variable to initialize
+ */
+void lv_indev_drv_init(struct _lv_indev_drv_t * driver);
+
+/**
+ * Register an initialized input device driver.
+ * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable)
+ * @return pointer to the new input device or NULL on error
+ */
+lv_indev_t * lv_indev_drv_register(struct _lv_indev_drv_t * driver);
+
+/**
+ * Update the driver in run time.
+ * @param indev pointer to an input device. (return value of `lv_indev_drv_register`)
+ * @param new_drv pointer to the new driver
+ */
+void lv_indev_drv_update(lv_indev_t * indev, struct _lv_indev_drv_t * new_drv);
+
+/**
+* Remove the provided input device. Make sure not to use the provided input device afterwards anymore.
+* @param indev pointer to delete
+*/
+void lv_indev_delete(lv_indev_t * indev);
+
+/**
+ * Get the next input device.
+ * @param indev pointer to the current input device. NULL to initialize.
+ * @return the next input device or NULL if there are no more. Provide the first input device when
+ * the parameter is NULL
+ */
+lv_indev_t * lv_indev_get_next(lv_indev_t * indev);
+
+/**
+ * Read data from an input device.
+ * @param indev pointer to an input device
+ * @param data input device will write its data here
+ */
+void _lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data);
+
+/**********************
+ * MACROS
+ **********************/
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif
diff --git a/lib/lvgl/src/hal/lv_hal_tick.c b/lib/lvgl/src/hal/lv_hal_tick.c
new file mode 100644
index 00000000..c12a5942
--- /dev/null
+++ b/lib/lvgl/src/hal/lv_hal_tick.c
@@ -0,0 +1,104 @@
+/**
+ * @file lv_hal_tick.c
+ * Provide access to the system tick with 1 millisecond resolution
+ */
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "lv_hal_tick.h"
+#include <stddef.h>
+
+#if LV_TICK_CUSTOM == 1
+ #include LV_TICK_CUSTOM_INCLUDE
+#endif
+
+/*********************
+ * DEFINES
+ *********************/
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * STATIC PROTOTYPES
+ **********************/
+
+/**********************
+ * STATIC VARIABLES
+ **********************/
+#if !LV_TICK_CUSTOM
+ static uint32_t sys_time = 0;
+ static volatile uint8_t tick_irq_flag;
+#endif
+
+/**********************
+ * MACROS
+ **********************/
+
+/**********************
+ * GLOBAL FUNCTIONS
+ **********************/
+
+#if !LV_TICK_CUSTOM
+/**
+ * You have to call this function periodically
+ * @param tick_period the call period of this function in milliseconds
+ */
+LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period)
+{
+ tick_irq_flag = 0;
+ sys_time += tick_period;
+}
+#endif
+
+/**
+ * Get the elapsed milliseconds since start up
+ * @return the elapsed milliseconds
+ */
+uint32_t lv_tick_get(void)
+{
+#if LV_TICK_CUSTOM == 0
+
+ /*If `lv_tick_inc` is called from an interrupt while `sys_time` is read
+ *the result might be corrupted.
+ *This loop detects if `lv_tick_inc` was called while reading `sys_time`.
+ *If `tick_irq_flag` was cleared in `lv_tick_inc` try to read again
+ *until `tick_irq_flag` remains `1`.*/
+ uint32_t result;
+ do {
+ tick_irq_flag = 1;
+ result = sys_time;
+ } while(!tick_irq_flag); /*Continue until see a non interrupted cycle*/
+
+ return result;
+#else
+ return LV_TICK_CUSTOM_SYS_TIME_EXPR;
+#endif
+}
+
+/**
+ * Get the elapsed milliseconds since a previous time stamp
+ * @param prev_tick a previous time stamp (return value of lv_tick_get() )
+ * @return the elapsed milliseconds since 'prev_tick'
+ */
+uint32_t lv_tick_elaps(uint32_t prev_tick)
+{
+ uint32_t act_time = lv_tick_get();
+
+ /*If there is no overflow in sys_time simple subtract*/
+ if(act_time >= prev_tick) {
+ prev_tick = act_time - prev_tick;
+ }
+ else {
+ prev_tick = UINT32_MAX - prev_tick + 1;
+ prev_tick += act_time;
+ }
+
+ return prev_tick;
+}
+
+/**********************
+ * STATIC FUNCTIONS
+ **********************/
diff --git a/lib/lvgl/src/hal/lv_hal_tick.h b/lib/lvgl/src/hal/lv_hal_tick.h
new file mode 100644
index 00000000..949f56b8
--- /dev/null
+++ b/lib/lvgl/src/hal/lv_hal_tick.h
@@ -0,0 +1,69 @@
+/**
+ * @file lv_hal_tick.h
+ * Provide access to the system tick with 1 millisecond resolution
+ */
+
+#ifndef LV_HAL_TICK_H
+#define LV_HAL_TICK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "../lv_conf_internal.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/*********************
+ * DEFINES
+ *********************/
+#ifndef LV_ATTRIBUTE_TICK_INC
+#define LV_ATTRIBUTE_TICK_INC
+#endif
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+
+//! @cond Doxygen_Suppress
+
+#if !LV_TICK_CUSTOM
+/**
+ * You have to call this function periodically
+ * @param tick_period the call period of this function in milliseconds
+ */
+LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period);
+#endif
+
+//! @endcond
+
+/**
+ * Get the elapsed milliseconds since start up
+ * @return the elapsed milliseconds
+ */
+uint32_t lv_tick_get(void);
+
+/**
+ * Get the elapsed milliseconds since a previous time stamp
+ * @param prev_tick a previous time stamp (return value of lv_tick_get() )
+ * @return the elapsed milliseconds since 'prev_tick'
+ */
+uint32_t lv_tick_elaps(uint32_t prev_tick);
+
+/**********************
+ * MACROS
+ **********************/
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif /*LV_HAL_TICK_H*/