Files
lvgl/src/drivers/nuttx/lv_nuttx_libuv.c
2024-04-10 15:17:44 +08:00

341 lines
8.5 KiB
C

/**
* @file lv_nuttx_libuv.c
*/
/*********************
* INCLUDES
*********************/
#include "lv_nuttx_libuv.h"
#include <stdlib.h>
#include "../../../lvgl.h"
#include "../../lvgl_private.h"
#if LV_USE_NUTTX
#if LV_USE_NUTTX_LIBUV
#include <uv.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
int fd;
bool polling;
uv_poll_t fb_poll;
uv_poll_t vsync_poll;
} lv_nuttx_uv_fb_ctx_t;
typedef struct {
int fd;
uv_poll_t input_poll;
lv_indev_t * indev;
} lv_nuttx_uv_input_ctx_t;
typedef struct {
uv_timer_t uv_timer;
lv_nuttx_uv_fb_ctx_t fb_ctx;
lv_nuttx_uv_input_ctx_t input_ctx;
int32_t ref_count;
} lv_nuttx_uv_ctx_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_nuttx_uv_timer_cb(uv_timer_t * handle);
static int lv_nuttx_uv_timer_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx);
static void lv_nuttx_uv_timer_deinit(lv_nuttx_uv_ctx_t * uv_ctx);
static void lv_nuttx_uv_vsync_poll_cb(uv_poll_t * handle, int status, int events);
static void lv_nuttx_uv_disp_poll_cb(uv_poll_t * handle, int status, int events);
static void lv_nuttx_uv_disp_refr_req_cb(lv_event_t * e);
static int lv_nuttx_uv_fb_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx);
static void lv_nuttx_uv_fb_deinit(lv_nuttx_uv_ctx_t * uv_ctx);
static void lv_nuttx_uv_input_poll_cb(uv_poll_t * handle, int status, int events);
static int lv_nuttx_uv_input_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx);
static void lv_nuttx_uv_input_deinit(lv_nuttx_uv_ctx_t * uv_ctx);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void * lv_nuttx_uv_init(lv_nuttx_uv_t * uv_info)
{
lv_nuttx_uv_ctx_t * uv_ctx;
int ret;
uv_ctx = lv_malloc_zeroed(sizeof(lv_nuttx_uv_ctx_t));
LV_ASSERT_MALLOC(uv_ctx);
if(uv_ctx == NULL) return NULL;
if((ret = lv_nuttx_uv_timer_init(uv_info, uv_ctx)) < 0) {
LV_LOG_ERROR("lv_nuttx_uv_timer_init fail : %d", ret);
goto err_out;
}
if((ret = lv_nuttx_uv_fb_init(uv_info, uv_ctx)) < 0) {
LV_LOG_ERROR("lv_nuttx_uv_fb_init fail : %d", ret);
goto err_out;
}
if((ret = lv_nuttx_uv_input_init(uv_info, uv_ctx)) < 0) {
LV_LOG_ERROR("lv_nuttx_uv_input_init fail : %d", ret);
goto err_out;
}
return uv_ctx;
err_out:
lv_free(uv_ctx);
return NULL;
}
void lv_nuttx_uv_deinit(void ** data)
{
lv_nuttx_uv_ctx_t * uv_ctx = *data;
if(uv_ctx == NULL) return;
lv_nuttx_uv_input_deinit(uv_ctx);
lv_nuttx_uv_fb_deinit(uv_ctx);
lv_nuttx_uv_timer_deinit(uv_ctx);
*data = NULL;
LV_LOG_USER("Done");
}
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_nuttx_uv_timer_cb(uv_timer_t * handle)
{
uint32_t sleep_ms;
sleep_ms = lv_timer_handler();
if(sleep_ms == LV_NO_TIMER_READY) {
uv_timer_stop(handle);
return;
}
/* Prevent busy loops. */
if(sleep_ms == 0) {
sleep_ms = 1;
}
LV_LOG_TRACE("sleep_ms = %" LV_PRIu32, sleep_ms);
uv_timer_start(handle, lv_nuttx_uv_timer_cb, sleep_ms, 0);
}
static void lv_nuttx_uv_timer_resume(void * data)
{
uv_timer_t * timer = (uv_timer_t *)data;
if(timer)
uv_timer_start(timer, lv_nuttx_uv_timer_cb, 0, 0);
}
static int lv_nuttx_uv_timer_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx)
{
uv_loop_t * loop = uv_info->loop;
LV_ASSERT_NULL(uv_ctx);
LV_ASSERT_NULL(loop);
uv_ctx->uv_timer.data = uv_ctx;
uv_timer_init(loop, &uv_ctx->uv_timer);
uv_ctx->ref_count++;
uv_timer_start(&uv_ctx->uv_timer, lv_nuttx_uv_timer_cb, 1, 1);
lv_timer_handler_set_resume_cb(lv_nuttx_uv_timer_resume, &uv_ctx->uv_timer);
return 0;
}
static void lv_nuttx_uv_deinit_cb(uv_handle_t * handle)
{
lv_nuttx_uv_ctx_t * uv_ctx = handle->data;
if(--uv_ctx->ref_count <= 0) {
LV_LOG_USER("Done");
lv_free(uv_ctx);
}
}
static void lv_nuttx_uv_timer_deinit(lv_nuttx_uv_ctx_t * uv_ctx)
{
lv_timer_handler_set_resume_cb(NULL, NULL);
uv_close((uv_handle_t *)&uv_ctx->uv_timer, lv_nuttx_uv_deinit_cb);
LV_LOG_USER("Done");
}
static void lv_nuttx_uv_vsync_poll_cb(uv_poll_t * handle, int status, int events)
{
LV_UNUSED(handle);
LV_UNUSED(status);
LV_UNUSED(events);
lv_display_t * d;
d = lv_display_get_next(NULL);
while(d) {
lv_display_send_event(d, LV_EVENT_VSYNC, NULL);
d = lv_display_get_next(d);
}
}
static void lv_nuttx_uv_disp_poll_cb(uv_poll_t * handle, int status, int events)
{
lv_nuttx_uv_fb_ctx_t * fb_ctx = &((lv_nuttx_uv_ctx_t *)(handle->data))->fb_ctx;
LV_UNUSED(status);
LV_UNUSED(events);
uv_poll_stop(handle);
_lv_display_refr_timer(NULL);
fb_ctx->polling = false;
}
static void lv_nuttx_uv_disp_refr_req_cb(lv_event_t * e)
{
lv_nuttx_uv_fb_ctx_t * fb_ctx = lv_event_get_user_data(e);
if(fb_ctx->polling) {
return;
}
fb_ctx->polling = true;
uv_poll_start(&fb_ctx->fb_poll, UV_WRITABLE, lv_nuttx_uv_disp_poll_cb);
}
static int lv_nuttx_uv_fb_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx)
{
uv_loop_t * loop = uv_info->loop;
lv_display_t * disp = uv_info->disp;
LV_ASSERT_NULL(uv_ctx);
LV_ASSERT_NULL(disp);
LV_ASSERT_NULL(loop);
lv_nuttx_uv_fb_ctx_t * fb_ctx = &uv_ctx->fb_ctx;
fb_ctx->fd = *(int *)lv_display_get_driver_data(disp);
if(fb_ctx->fd <= 0) {
LV_LOG_USER("skip uv fb init.");
return 0;
}
if(!disp->refr_timer) {
LV_LOG_ERROR("disp->refr_timer is NULL");
return -EINVAL;
}
/* Remove default refr timer. */
lv_timer_delete(disp->refr_timer);
disp->refr_timer = NULL;
fb_ctx->fb_poll.data = uv_ctx;
uv_poll_init(loop, &fb_ctx->fb_poll, fb_ctx->fd);
uv_ctx->ref_count++;
uv_poll_start(&fb_ctx->fb_poll, UV_WRITABLE, lv_nuttx_uv_disp_poll_cb);
fb_ctx->vsync_poll.data = uv_ctx;
uv_poll_init(loop, &fb_ctx->vsync_poll, fb_ctx->fd);
uv_ctx->ref_count++;
uv_poll_start(&fb_ctx->vsync_poll, UV_PRIORITIZED, lv_nuttx_uv_vsync_poll_cb);
LV_LOG_USER("lvgl fb loop start OK");
/* Register for the invalidate area event */
lv_event_add(&disp->event_list, lv_nuttx_uv_disp_refr_req_cb, LV_EVENT_REFR_REQUEST, fb_ctx);
return 0;
}
static void lv_nuttx_uv_fb_deinit(lv_nuttx_uv_ctx_t * uv_ctx)
{
/* should remove event */
lv_nuttx_uv_fb_ctx_t * fb_ctx = &uv_ctx->fb_ctx;
if(fb_ctx->fd > 0) {
uv_close((uv_handle_t *)&fb_ctx->fb_poll, lv_nuttx_uv_deinit_cb);
uv_close((uv_handle_t *)&fb_ctx->vsync_poll, lv_nuttx_uv_deinit_cb);
}
LV_LOG_USER("Done");
}
static void lv_nuttx_uv_input_poll_cb(uv_poll_t * handle, int status, int events)
{
lv_indev_t * indev = ((lv_nuttx_uv_ctx_t *)(handle->data))->input_ctx.indev;
if(status < 0) {
LV_LOG_WARN("input poll error: %s ", uv_strerror(status));
return;
}
if(events & UV_READABLE) {
lv_indev_read(indev);
}
}
static int lv_nuttx_uv_input_init(lv_nuttx_uv_t * uv_info, lv_nuttx_uv_ctx_t * uv_ctx)
{
uv_loop_t * loop = uv_info->loop;
lv_indev_t * indev = uv_info->indev;
if(indev == NULL) {
LV_LOG_USER("skip uv input init.");
return 0;
}
LV_ASSERT_NULL(uv_ctx);
LV_ASSERT_NULL(loop);
if(lv_indev_get_mode(indev) == LV_INDEV_MODE_EVENT) {
LV_LOG_ERROR("input device has been running in event-driven mode");
return -EINVAL;
}
lv_nuttx_uv_input_ctx_t * input_ctx = &uv_ctx->input_ctx;
input_ctx->fd = *(int *)lv_indev_get_driver_data(indev);
if(input_ctx->fd <= 0) {
LV_LOG_ERROR("can't get valid input fd");
return 0;
}
input_ctx->indev = indev;
lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT);
input_ctx->input_poll.data = uv_ctx;
uv_poll_init(loop, &input_ctx->input_poll, input_ctx->fd);
uv_ctx->ref_count++;
uv_poll_start(&input_ctx->input_poll, UV_READABLE, lv_nuttx_uv_input_poll_cb);
LV_LOG_USER("lvgl input loop start OK");
return 0;
}
static void lv_nuttx_uv_input_deinit(lv_nuttx_uv_ctx_t * uv_ctx)
{
lv_nuttx_uv_input_ctx_t * input_ctx = &uv_ctx->input_ctx;
if(input_ctx->fd > 0) {
uv_close((uv_handle_t *)&input_ctx->input_poll, lv_nuttx_uv_deinit_cb);
}
LV_LOG_USER("Done");
}
#endif /*LV_USE_NUTTX_LIBUV*/
#endif /*LV_USE_NUTTX*/