diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-06-01 15:41:47 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-06-01 15:41:47 +1000 |
| commit | dd27c3530432ea0b09f01e604bf577f31d8ef841 (patch) | |
| tree | bbf86cf81a78f0ff0b07f31f1c390db473f26fd3 /lib/lvgl/src/hal | |
| parent | 6fd588e970470b15936187980829916d0dbe77bb (diff) | |
| download | tangara-fw-dd27c3530432ea0b09f01e604bf577f31d8ef841.tar.gz | |
convert lvgl from submodule to a plain old directory
Diffstat (limited to 'lib/lvgl/src/hal')
| m--------- | lib/lvgl | 0 | ||||
| -rw-r--r-- | lib/lvgl/src/hal/lv_hal.h | 48 | ||||
| -rw-r--r-- | lib/lvgl/src/hal/lv_hal.mk | 8 | ||||
| -rw-r--r-- | lib/lvgl/src/hal/lv_hal_disp.c | 710 | ||||
| -rw-r--r-- | lib/lvgl/src/hal/lv_hal_disp.h | 371 | ||||
| -rw-r--r-- | lib/lvgl/src/hal/lv_hal_indev.c | 195 | ||||
| -rw-r--r-- | lib/lvgl/src/hal/lv_hal_indev.h | 239 | ||||
| -rw-r--r-- | lib/lvgl/src/hal/lv_hal_tick.c | 104 | ||||
| -rw-r--r-- | lib/lvgl/src/hal/lv_hal_tick.h | 69 |
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*/ |
