1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/pkg/lvgl/contrib/lvgl.c
2023-05-08 15:00:53 +02:00

213 lines
5.2 KiB
C

/*
* Copyright (C) 2019-2020 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_lvgl
* @{
*
* @file
* @brief LVGL glue code
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
* @}
*/
#include <assert.h>
#include "kernel_defines.h"
#include "thread.h"
#include "timex.h"
#include "ztimer.h"
#include "log.h"
#include "lvgl/lvgl.h"
#include "lvgl_riot.h"
#include "screen_dev.h"
#if IS_USED(MODULE_LV_DRIVERS_INDEV_MOUSE)
#include "indev/mouse.h"
#endif
#if IS_USED(MODULE_LV_DRIVERS_SDL)
#include "sdl/sdl.h"
#endif
#ifndef LVGL_COLOR_BUF_SIZE
#define LVGL_COLOR_BUF_SIZE (LV_HOR_RES_MAX * 10)
#endif
#ifndef CONFIG_LVGL_INACTIVITY_PERIOD_MS
#define CONFIG_LVGL_INACTIVITY_PERIOD_MS (5 * MS_PER_SEC) /* 5s */
#endif
#ifndef CONFIG_LVGL_TASK_HANDLER_DELAY_MS
#define CONFIG_LVGL_TASK_HANDLER_DELAY_MS (5) /* 5ms */
#endif
#ifndef LVGL_THREAD_FLAG
#define LVGL_THREAD_FLAG (1 << 7)
#endif
#if IS_USED(MODULE_LV_DRIVERS_SDL)
#ifndef LCD_SCREEN_WIDTH
#define LCD_SCREEN_WIDTH SDL_HOR_RES
#endif
#ifndef LCD_SCREEN_HEIGHT
#define LCD_SCREEN_HEIGHT SDL_VER_RES
#endif
#endif
static kernel_pid_t _task_thread_pid;
static lv_disp_draw_buf_t disp_buf;
static lv_color_t draw_buf[LVGL_COLOR_BUF_SIZE];
static lv_disp_drv_t disp_drv;
#if IS_USED(MODULE_TOUCH_DEV)
static lv_indev_drv_t indev_drv;
#endif
#if !IS_USED(MODULE_LV_DRIVERS_SDL)
static screen_dev_t *_screen_dev = NULL;
static void _disp_map(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p)
{
if (!_screen_dev->display) {
return;
}
if (!area) {
return;
}
const disp_dev_area_t disp_area = {
area->x1, area->x2, area->y1, area->y2
};
disp_dev_map(_screen_dev->display, &disp_area, (const uint16_t *)color_p);
LOG_DEBUG("[lvgl] flush display\n");
lv_disp_flush_ready(drv);
}
#endif
#if IS_USED(MODULE_TOUCH_DEV) && !IS_USED(MODULE_LV_DRIVERS_SDL)
/* adapted from https://github.com/lvgl/lvgl/tree/v6.1.2#add-littlevgl-to-your-project */
static void _touch_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
if (!_screen_dev->touch) {
return;
}
if (!data) {
return;
}
(void)indev_driver;
static lv_coord_t last_x = 0;
static lv_coord_t last_y = 0;
touch_t positions[1];
uint8_t touches = touch_dev_touches(_screen_dev->touch, positions, 1);
/* Save the state and save the pressed coordinates */
data->state = (touches > 0) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
if (data->state == LV_INDEV_STATE_PR) {
last_x = positions[0].x;
last_y = positions[0].y;
}
/* Set the coordinates (if released use the last pressed coordinates) */
data->point.x = last_x;
data->point.y = last_y;
return;
}
#endif
void lvgl_init(screen_dev_t *screen_dev)
{
lv_init();
#if !IS_USED(MODULE_LV_DRIVERS_SDL)
_screen_dev = screen_dev;
assert(screen_dev->display);
#else
(void)screen_dev;
#endif
lv_disp_draw_buf_init(&disp_buf, draw_buf, NULL, LVGL_COLOR_BUF_SIZE);
lv_disp_drv_init(&disp_drv);
disp_drv.draw_buf = &disp_buf;
#if IS_USED(MODULE_LV_DRIVERS_SDL)
/* Use SDL driver which creates window on PC's monitor to simulate a display */
sdl_init();
/* Used when `LV_VDB_SIZE != 0` in lv_conf.h (buffered drawing) */
disp_drv.flush_cb = sdl_display_flush;
disp_drv.hor_res = LCD_SCREEN_WIDTH;
disp_drv.ver_res = LCD_SCREEN_HEIGHT;
#else
disp_drv.flush_cb = _disp_map;
/* Configure horizontal and vertical resolutions based on the
underlying display device parameters */
disp_drv.hor_res = disp_dev_width(screen_dev->display);
disp_drv.ver_res = disp_dev_height(screen_dev->display);
#endif
lv_disp_drv_register(&disp_drv);
#if IS_USED(MODULE_TOUCH_DEV)
#if IS_USED(MODULE_LV_DRIVERS_SDL)
/* Add the mouse as input device, use SDL driver which reads the PC's mouse */
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = sdl_mouse_read;
lv_indev_drv_register(&indev_drv);
#else
if (screen_dev->touch) {
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = _touch_read;
lv_indev_drv_register(&indev_drv);
}
#endif
#endif
}
void lvgl_run(void)
{
_task_thread_pid = thread_getpid();
while (1) {
/* Normal operation (no sleep) in < CONFIG_LVGL_INACTIVITY_PERIOD_MS msec
inactivity */
if (lv_disp_get_inactive_time(NULL) < CONFIG_LVGL_INACTIVITY_PERIOD_MS) {
lv_timer_handler();
}
else {
/* Block after LVGL_ACTIVITY_PERIOD msec inactivity */
thread_flags_wait_one(LVGL_THREAD_FLAG);
/* trigger an activity so the task handler is called on the next loop */
lv_disp_trig_activity(NULL);
}
ztimer_sleep(ZTIMER_MSEC, CONFIG_LVGL_TASK_HANDLER_DELAY_MS);
}
}
void lvgl_wakeup(void)
{
thread_t *tcb = thread_get(_task_thread_pid);
thread_flags_set(tcb, LVGL_THREAD_FLAG);
}