Files
AC707N/SDK/apps/common/ui/lvgl_v8/lvgl_main.c
T
2025-12-03 11:12:34 +08:00

1179 lines
34 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".lv_ui_core.data.bss")
#pragma data_seg(".lv_ui_core.data")
#pragma const_seg(".lv_ui_core.text.const")
#pragma code_seg(".lv_ui_core.text")
#endif
#include "lv_conf.h"
#include "system/includes.h"
#include "lvgl.h"
#include "demos/benchmark/lv_demo_benchmark.h"
#include "demos/widgets/lv_demo_widgets.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "lv_port_fs.h"
#include "lvgl_v8/lv_ui.h"
#include "key_driver.h"
#include "event.h"
#include "rect.h"
#include "time.h"
#include "ui_key_remap.h"
#include "lcd/lcd_lvgl_api.h"
#define LVGL_TASK_NAME "ui"
void msleep(unsigned int ms);
static char lvgl_suspend_flag = 1;
static bool module_group_in_deal = false;
static bool module_msg_in_deal = false;
volatile static char lvgl_timerout_msg_remain_flag = 2;
static char lvgl_touch_msg_remain_cnt;
static char lvgl_key_msg_remain_cnt;
static char lvgl_touch_timer_status; //0:轮询定时器关闭 1:轮询定时器打开
static int lvgl_touch_timeout_id;
static u16 lvgl_timeout_id = 0;
static u8 wake_up_flag = 0;
int clock_lock(const char *name, u32 clk);
enum {
UI_MSG_TOUCH = 1,
UI_MSG_ENCODER,
UI_MSG_KEY,
UI_MSG_TIMER_TIMEOUT,
UI_MSG_MODULE_CHANGE,
UI_MSG_MODULE_CHANGE_REFRESH_NOW,
UI_MSG_SUSPEND,
UI_MSG_RESUME,
UI_MSG_RPC_FUNC,
};
#if 1
struct touch_event {
u16 x;
u16 y;
u8 status;
};
#endif
enum LVGL_Q_USER_TYPE {
LVGL_Q_USER_TYPE_TOUCH = 0x10000,//从这个立即数开始是为了删消息池使用,不可更改
LVGL_Q_USER_TYPE_KEY = 0x20000,
};
static struct key_event s_drop_key;
static struct key_event s_last_key;
static u16 lvgl_drop_key_hande_timeout_id;
void lv_port_get_touch_x_y_status(struct touch_event *e, u16 *x, u16 *y, u8 *status)
{
*x = e->x;
*y = e->y;
*status = e->status;
}
static void lvgl_key_drop_key_handle_timeout_cb(void *p)
{
int msg[2 + sizeof(struct key_event) / 4];
msg[0] = UI_MSG_KEY;
memcpy(&msg[1], &s_drop_key, sizeof(struct key_event));
if (os_taskq_post_type(LVGL_TASK_NAME, Q_USER, ARRAY_SIZE(msg), msg)) {
puts("lvgl_key_event_handler post failed 0\n");
lvgl_drop_key_hande_timeout_id = sys_timeout_add_2_task(NULL, lvgl_key_drop_key_handle_timeout_cb, 30, LVGL_TASK_NAME);
} else {
++lvgl_key_msg_remain_cnt;
lvgl_drop_key_hande_timeout_id = 0;
}
}
/*
* down事件不发给UI,等到按键抬起后up事件拆分为2次事件发给UI
* 这样做的好处是能区分出短按和长按,例如按键短按和长按分别有不同UI功能时
* */
static int lvgl_key_event_handler(struct key_event *key)
{
int msg_p[2 + sizeof(struct key_event) / 4];
//编码器旋钮
if (key->event == KEY_ACTION_RDEC_ROTATE) {
msg_p[0] = UI_MSG_ENCODER;
memcpy(&msg_p[1], key, sizeof(struct key_event));
int key_value_test = key->value;
if (os_taskq_post_type(LVGL_TASK_NAME, Q_USER, ARRAY_SIZE(msg_p), msg_p)) {
puts("lvgl_key_event_handler post failed 4");
goto __retry;
} else {
s_last_key.value = key->value;
++lvgl_key_msg_remain_cnt;
}
return 1;//接管事件
}
if ((key->event == KEY_ACTION_UP) && (key->value != s_last_key.value)) {
puts("lvgl_key_event_handler post failed 1\n");
return 1;
}
if (key->event == KEY_ACTION_LVGL_DOWN) {
//按下事件不发给UI
s_last_key.value = key->value;
s_last_key.event = key->event;
return -EINVAL;
}
if (lvgl_drop_key_hande_timeout_id) {
puts("lvgl_key_event_handler post failed 2\n");
return 1;
}
if (lvgl_key_msg_remain_cnt > 2) {
puts("lvgl_key_event_handler post failed 3\n");
goto __retry;
}
if (key->event == KEY_ACTION_UP) {
if (lvgl_suspend_flag) {
wake_up_flag = 1;
}
u8 event_split = 2;
if (s_last_key.event == KEY_ACTION_HOLD || s_last_key.event == KEY_ACTION_LONG) {
//长按后的抬起UI只响应一次up
event_split = 1;
}
//按键抬起后才开始分发2次key事件,一次down 一次up
s_last_key.event = key->event;
for (int i = 0; i < event_split; i++) {
msg_p[0] = UI_MSG_KEY;
if (event_split == 2) {
key->event = (i == 0) ? KEY_ACTION_LVGL_DOWN : KEY_ACTION_UP;
}
memcpy(&msg_p[1], key, sizeof(struct key_event));
if (os_taskq_post_type(LVGL_TASK_NAME, Q_USER, ARRAY_SIZE(msg_p), msg_p)) {
puts("lvgl_key_event_handler post failed 4");
goto __retry;
} else {
s_last_key.value = key->value;
++lvgl_key_msg_remain_cnt;
}
}
} else if (key->event == KEY_ACTION_LONG || key->event == KEY_ACTION_HOLD || key->event == KEY_ACTION_CLICK) {
//唤醒时不发送消息
if (wake_up_flag) {
wake_up_flag = 0;
return 1;
}
msg_p[0] = UI_MSG_KEY;
memcpy(&msg_p[1], key, sizeof(struct key_event));
s_last_key.event = key->event;
/*printf("lvgl key event->type:%d key->event:%d key->value:%d", key->type, key->event, key->value); */
if (os_taskq_post_type(LVGL_TASK_NAME, Q_USER, ARRAY_SIZE(msg_p), msg_p)) {
puts("lvgl_key_event_handler post failed 4");
goto __retry;
} else {
s_last_key.value = key->value;
++lvgl_key_msg_remain_cnt;
}
}
return 1;
__retry:
if ((key->event == KEY_ACTION_UP) && (key->value == s_last_key.value)) {
memcpy(&s_drop_key, key, sizeof(struct key_event));
lvgl_drop_key_hande_timeout_id = sys_timeout_add(NULL, lvgl_key_drop_key_handle_timeout_cb, 30);
}
return 1;
}
void lv_set_touch_timer_status(u8 status)
{
lvgl_touch_timer_status = status;
}
static void lv_set_timer_read_touch_mode(u16 x, u16 y, u8 status)
{
struct touch_event event;
event.x = x;
event.y = y;
event.status = status;
lv_indev_timer_read_touch(&event);
lv_indev_set_touch_timer_en(1);
}
int lcd_touch_interrupt_event(const char *tp_task_name, u16 x, u16 y, u8 status)
{
int err;
if (lvgl_suspend_flag) {
return 0;
}
lv_ui_auto_shut_down_re_run();
if (status) {
//检测到触摸,创建定时器启用轮询
if (!lvgl_touch_timer_status) {//这个标志是用来防止多次发消息
int msg[4];
msg[0] = UI_MSG_TOUCH;
msg[1] = (int)x;
msg[2] = (int)y;
msg[3] = (int)status;
err = os_taskq_post_type(LVGL_TASK_NAME, Q_USER, ARRAY_SIZE(msg), msg);
if (err) {
printf("lvgl touch msg drop2 err = %d\n", err);
return err;
}
lvgl_touch_timer_status = 1;
}
return 0;
}
return 0;
}
static void lvgl_timer_event_timeout(void *p)
{
int err;
int msg[2];
msg[0] = UI_MSG_TIMER_TIMEOUT;
lvgl_timeout_id = 0;
err = task_queue_post_event(LVGL_TASK_NAME, msg, ARRAY_SIZE(msg));
if (err) {
printf("lvgl_timer_event_timeout post_ui_msg err=%d\n", err);
} else {
/*printf("lvgl post timeout msg ok.\r\n");*/
lvgl_timerout_msg_remain_flag = 1;
}
}
_WEAK_ int gui_scr_action_cb_ext(int page_id, int action)
{
return 0;
}
void gui_scr_action_cb(int page_id, int action)
{
for (const struct ui_screen_action_handler *p = ui_screen_action_handler_begin; p < ui_screen_action_handler_end; p++) {
if (p->page_id == page_id) {
p->onchange(action);
break;
}
}
gui_scr_action_cb_ext(page_id, action);
}
typedef enum {
VALUE_INT = 1,
VALUE_CHAR,
VALUE_SHORT,
VALUE_COORD,
VALUE_BOOL,
VALUE_STRING,
VALUE_COLOR,
VALUE_DATE,
VALUE_POINT,
VALUE_TIME,
VALUE_ARRAY,
} gui_msg_data_type_t;
_WEAK_ int gui_msg_action_change_ext(int32_t msg_id, int access, void *data, gui_msg_data_type_t data_type)
{
return 0;
}
_WEAK_ void gui_msg_action_change_guider(int32_t msg_id, int access, void *data)
{
}
typedef union {
int32_t value_int;
lv_coord_t value_coord;
bool value_bool;
char *value_string;
lv_color_t value_color;
lv_calendar_date_t value_date;
lv_point_t value_point;
struct tm value_time;
struct {
void *ptr;
int32_t len;
} value_array;
} gui_msg_data_t;
static void gui_varable_reg_action_change(const struct ui_varable_reg_t *p, int access, gui_msg_data_t *data, gui_msg_data_type_t data_type)
{
if (access == 0 && p->get_set_value_cb) {
p->get_set_value_cb(0);
}
switch (data_type) {
case VALUE_CHAR:
case VALUE_BOOL:
if (access == 0) {
data->value_int = *(u8 *)p->ptr;
} else if (access == 1) {
*(u8 *)p->ptr = data->value_int;
}
break;
case VALUE_SHORT:
if (access == 0) {
data->value_int = *(u16 *)p->ptr;
} else if (access == 1) {
*(u16 *)p->ptr = data->value_int;
}
break;
case VALUE_INT:
if (access == 0) {
data->value_int = *(u32 *)p->ptr;
} else if (access == 1) {
*(u32 *)p->ptr = data->value_int;
}
break;
case VALUE_COORD:
if (access == 0) {
data->value_int = *(lv_coord_t *)p->ptr;
} else if (access == 1) {
*(lv_coord_t *)p->ptr = data->value_int;
}
break;
case VALUE_STRING:
if (access == 0) {
data->value_string = p->ptr;
} else if (access == 1) {
strcpy(p->ptr, (char *)data->value_string);
}
break;
case VALUE_COLOR:
if (access == 0) {
data->value_color = *(lv_color_t *)p->ptr;
} else if (access == 1) {
*(lv_color_t *)p->ptr = data->value_color;
}
break;
case VALUE_POINT:
if (access == 0) {
data->value_point = *(lv_point_t *)p->ptr;
} else if (access == 1) {
*(lv_point_t *)p->ptr = data->value_point;
}
break;
case VALUE_DATE:
if (access == 0) {
data->value_date = *(lv_calendar_date_t *)p->ptr;
} else if (access == 1) {
*(lv_calendar_date_t *)p->ptr = data->value_date;
}
break;
case VALUE_TIME:
if (access == 0) {
data->value_time = *(struct tm *)p->ptr;
} else if (access == 1) {
*(struct tm *)p->ptr = data->value_time;
}
break;
case VALUE_ARRAY:
if (access == 0) {
data->value_array.ptr = p->ptr;
data->value_array.len = p->len;
} else if (access == 1) {
memcpy(p->ptr, (char *)data->value_array.ptr, data->value_array.len);
}
break;
}
if (access == 1 && p->get_set_value_cb) {
p->get_set_value_cb(1);
}
}
void gui_msg_action_change(int32_t msg_id, int access, void *data, gui_msg_data_type_t data_type)
{
ASSERT(!(data == NULL && (access == 0 || access == 1)), "gui_msg_action_change data==NULL");
char found = 0;
for (const struct ui_module_event_handler *p = ui_module_event_handler_begin; p < ui_module_event_handler_end; p++) {
if (p->msg_id == msg_id) {
p->onchange(access, data);
found = 1;
break;
}
}
if (!found) {
for (const struct ui_varable_reg_t *p = ui_varable_reg_tab_begin; p < ui_varable_reg_tab_end; p++) {
if (p->msg_id == msg_id) {
gui_varable_reg_action_change(p, access, data, data_type);
found = 1;
break;
}
}
}
if (!found) {
gui_msg_action_change_guider(msg_id, access, data);
}
gui_msg_action_change_ext(msg_id, access, data, data_type);
}
////////
_WEAK_ int gui_msg_send(int32_t msg_id, void *value, int32_t len)
{
puts("MUST DEFINE gui_msg_send function !!!");
return 0;
}
////////
static struct list_head list_head = LIST_HEAD_INIT(list_head);
static struct list_head group_list_head = LIST_HEAD_INIT(group_list_head);
static spinlock_t list_spinlock;
static spinlock_t group_list_spinlock;
enum LVGL_MODULE_MSG_TYPE {
LVGL_MODULE_MSG_CONST_OR_VALUE = 0x10000,//从这个立即数开始是为了删消息池使用,不可更改
LVGL_MODULE_MSG_PTR = 0x20000,
LVGL_MODULE_MSG_GROUP = 0x40000,
};
typedef struct {
struct list_head entry;
u32 msg_id;
u32 msg_len;
enum LVGL_MODULE_MSG_TYPE msg_type;
char data[];
} lvgl_module_msg_t;
typedef struct {
struct list_head entry;
struct list_head head;
spinlock_t spinlock;
u32 group_id;
} lvgl_module_msg_group_t;
int lvgl_module_msg_send_global_ptr(unsigned int msg_id, const void *ptr, unsigned int len, char refr_now)
{
if (lvgl_suspend_flag) {
printf("lvgl_module_msg_send_global_ptr_or_value suspended \n");
return -1;
}
if (!strcmp(os_current_task(), LVGL_TASK_NAME)) {
int error = 0;
if (!module_msg_in_deal) {
module_msg_in_deal = true;
if (gui_msg_send(msg_id, (void *)ptr, len)) {
printf("%s[%d] gui msg_id[%d] had unsubscribe\r\n", __func__, __LINE__, msg_id);
error = -1;
}
module_msg_in_deal = false;
return error;
}
}
int err;
int msg[5];
msg[0] = refr_now ? UI_MSG_MODULE_CHANGE_REFRESH_NOW : UI_MSG_MODULE_CHANGE;
msg[1] = LVGL_MODULE_MSG_CONST_OR_VALUE;
msg[2] = msg_id;
msg[3] = (int)ptr;
msg[4] = len;
err = os_taskq_del_type(LVGL_TASK_NAME, Q_MSG | LVGL_MODULE_MSG_CONST_OR_VALUE | msg_id);
if (err == 0) {
printf("lvgl_module_msg_send_global_ptr_or_value[%u] del\n", msg_id);
}
err = os_taskq_post_type(LVGL_TASK_NAME, Q_MSG | LVGL_MODULE_MSG_CONST_OR_VALUE | msg_id, ARRAY_SIZE(msg), msg);
if (err) {
printf("lvgl_module_msg_send_global_ptr_or_value err=%d\n", err);
}
return err;
}
int lvgl_module_msg_send_string(unsigned int msg_id, const char *string, char refr_now)
{
return lvgl_module_msg_send_global_ptr(msg_id, (const void *)string, 4, refr_now);
}
int lvgl_module_msg_send_value(unsigned int msg_id, unsigned int value, char refr_now)
{
return lvgl_module_msg_send_global_ptr(msg_id, (const void *)value, 4, refr_now);
}
void *lvgl_module_msg_get_ptr(unsigned int msg_id, unsigned int len)
{
if (lvgl_suspend_flag) {
printf("lvgl_module_msg_get_ptr suspended \n");
return NULL;
}
lvgl_module_msg_t *p = malloc(sizeof(lvgl_module_msg_t) + len);
LV_ASSERT_MALLOC(p);
p->msg_id = msg_id;
p->msg_len = len;
return p->data;
}
int lvgl_module_msg_send_ptr(void *ptr, char refr_now)
{
if (ptr == NULL) {
return -1;
}
if (lvgl_suspend_flag) {
printf("lvgl_module_msg_send_ptr suspended \n");
free(ptr);
return -1;
}
lvgl_module_msg_t *p = (lvgl_module_msg_t *)ptr - 1;
if (!strcmp(os_current_task(), LVGL_TASK_NAME)) {
int error = 0;
if (!module_msg_in_deal) {
module_msg_in_deal = true;
if (gui_msg_send(p->msg_id, (void *)p->data, p->msg_len)) {
printf("%s[%d] gui msg_id[%d] had unsubscribe\r\n", __func__, __LINE__, p->msg_id);
error = -1;
}
free(p);
module_msg_in_deal = false;
return error;
}
}
spin_lock(&list_spinlock);
list_add_tail(&p->entry, &list_head);
spin_unlock(&list_spinlock);
int err;
int msg[3];
msg[0] = refr_now ? UI_MSG_MODULE_CHANGE_REFRESH_NOW : UI_MSG_MODULE_CHANGE;
msg[1] = LVGL_MODULE_MSG_PTR;
msg[2] = (int)p;
err = os_taskq_del_type(LVGL_TASK_NAME, Q_MSG | LVGL_MODULE_MSG_PTR | p->msg_id);
if (err == 0) {
printf("lvgl_module_msg[%d] del\n", p->msg_id);
//同时把链表里面的节点内存释放掉
struct list_head *pos, *node;
lvgl_module_msg_t *oldp;
char find = 0;
spin_lock(&list_spinlock);
list_for_each_safe(pos, node, &list_head) {
oldp = list_entry(pos, lvgl_module_msg_t, entry);
if (oldp && oldp->msg_id == p->msg_id) {
list_del(&oldp->entry);
spin_unlock(&list_spinlock);
free(oldp);
find = 1;
break;
}
}
ASSERT(find, "%s list_del failed!\n", __FUNCTION__);
if (!find) {
spin_unlock(&list_spinlock);
}
}
err = os_taskq_post_type(LVGL_TASK_NAME, Q_MSG | LVGL_MODULE_MSG_PTR | p->msg_id, ARRAY_SIZE(msg), msg);
if (err) {
printf("lvgl_module_msg_send err=%d\n", err);
spin_lock(&list_spinlock);
list_del(&p->entry);
spin_unlock(&list_spinlock);
free(p);
}
return err;
}
void *lvgl_module_group_create(unsigned int group_id)
{
if (lvgl_suspend_flag) {
printf("lvgl_module_msg_group_create suspended \n");
return NULL;
}
lvgl_module_msg_group_t *pgroup = malloc(sizeof(lvgl_module_msg_group_t));
LV_ASSERT_MALLOC(pgroup);
spin_lock_init(&pgroup->spinlock);
INIT_LIST_HEAD(&pgroup->head);
pgroup->group_id = group_id;
spin_lock(&group_list_spinlock);
list_add_tail(&pgroup->entry, &group_list_head);
spin_unlock(&group_list_spinlock);
return pgroup;
}
int lvgl_module_msg_group_add_global_ptr(void *group, unsigned int msg_id, const void *ptr, unsigned int len)
{
if (group == NULL) {
return -1;
}
if (lvgl_suspend_flag) {
printf("lvgl_module_msg_group_add_global_ptr_or_value suspended \n");
return -1;
}
lvgl_module_msg_group_t *pgroup = group;
lvgl_module_msg_t *p = malloc(sizeof(lvgl_module_msg_t) + 4);
LV_ASSERT_MALLOC(p);
p->msg_type = LVGL_MODULE_MSG_CONST_OR_VALUE;
p->msg_id = msg_id;
p->msg_len = len;
*(int *)p->data = (int)ptr;
spin_lock(&pgroup->spinlock);
list_add_tail(&p->entry, &pgroup->head);
spin_unlock(&pgroup->spinlock);
return 0;
}
int lvgl_module_msg_group_add_value(void *group, unsigned int msg_id, unsigned int value)
{
return lvgl_module_msg_group_add_global_ptr(group, msg_id, (void *)value, 4);
}
int lvgl_module_msg_group_add_string(void *group, unsigned int msg_id, const char *string)
{
return lvgl_module_msg_group_add_global_ptr(group, msg_id, (const void *)string, 4);
}
void *lvgl_module_msg_group_add_ptr(void *group, unsigned int msg_id, unsigned int len)
{
if (group == NULL) {
return NULL;
}
if (lvgl_suspend_flag) {
printf("lvgl_module_msg_group_add_ptr suspended \n");
return NULL;
}
lvgl_module_msg_group_t *pgroup = group;
lvgl_module_msg_t *p = malloc(sizeof(lvgl_module_msg_t) + len);
LV_ASSERT_MALLOC(p);
p->msg_type = LVGL_MODULE_MSG_PTR;
p->msg_id = msg_id;
p->msg_len = len;
spin_lock(&pgroup->spinlock);
list_add_tail(&p->entry, &pgroup->head);
spin_unlock(&pgroup->spinlock);
return p->data;
}
int lvgl_module_msg_group_send(void *group, char refr_now)
{
if (group == NULL) {
return -1;
}
lvgl_module_msg_group_t *pgroup = group;
if (lvgl_suspend_flag) {
printf("lvgl_module_msg_group_send suspended \n");
spin_lock(&group_list_spinlock);
list_del(&pgroup->entry);
spin_unlock(&group_list_spinlock);
lvgl_module_msg_t *p, *n;
list_for_each_entry_safe(p, n, &pgroup->head, entry) {
free(p);
}
free(pgroup);
return -1;
}
if (!strcmp(os_current_task(), LVGL_TASK_NAME)) {
if (!module_group_in_deal) {
module_group_in_deal = true;
spin_lock(&group_list_spinlock);
list_del(&pgroup->entry);
spin_unlock(&group_list_spinlock);
lvgl_module_msg_t *p, *n;
int error = 0;
list_for_each_entry_safe(p, n, &pgroup->head, entry) {
if (p->msg_type == LVGL_MODULE_MSG_CONST_OR_VALUE) {
if (gui_msg_send(p->msg_id, (void *)(*(int *)p->data), p->msg_len)) {
printf("%s[%d] gui msg_id[%d] had unsubscribe\r\n", __func__, __LINE__, p->msg_id);
error = -1;
}
} else if (p->msg_type == LVGL_MODULE_MSG_PTR) {
if (gui_msg_send(p->msg_id, (void *)p->data, p->msg_len)) {
printf("%s[%d] gui msg_id[%d] had unsubscribe\r\n", __func__, __LINE__, p->msg_id);
error = -1;
}
}
free(p);
}
free(pgroup);
module_group_in_deal = false;
return error;
}
}
int err;
int msg[3];
msg[0] = refr_now ? UI_MSG_MODULE_CHANGE_REFRESH_NOW : UI_MSG_MODULE_CHANGE;
msg[1] = LVGL_MODULE_MSG_GROUP;
msg[2] = (int)pgroup;
err = os_taskq_del_type(LVGL_TASK_NAME, Q_MSG | LVGL_MODULE_MSG_GROUP | pgroup->group_id);
if (err == 0) {
printf("lvgl_module_msg[%d] del\n", pgroup->group_id);
//同时把组链表里面的节点内存释放掉
struct list_head *pos, *node;
lvgl_module_msg_group_t *oldg;
char find = 0;
spin_lock(&group_list_spinlock);
list_for_each_safe(pos, node, &group_list_head) {
oldg = list_entry(pos, lvgl_module_msg_group_t, entry);
if (oldg && oldg->group_id == pgroup->group_id) {
list_del(&oldg->entry);
spin_unlock(&group_list_spinlock);
lvgl_module_msg_t *oldp;
//同时把链表里面的节点内存释放掉,链表已经脱钩,不需要保护
list_for_each_safe(pos, node, &oldg->head) {
oldp = list_entry(pos, lvgl_module_msg_t, entry);
list_del(&oldp->entry);
free(oldp);
}
free(oldg);
find = 1;
break;
}
}
ASSERT(find, "%s list_del failed!\n", __FUNCTION__);
if (!find) {
spin_unlock(&group_list_spinlock);
}
}
err = os_taskq_post_type(LVGL_TASK_NAME, Q_MSG | LVGL_MODULE_MSG_GROUP | pgroup->group_id, ARRAY_SIZE(msg), msg);
if (err) {
printf("lvgl_module_group_send err=%d\n", err);
spin_lock(&group_list_spinlock);
list_del(&pgroup->entry);
spin_unlock(&group_list_spinlock);
lvgl_module_msg_t *p, *n;
list_for_each_entry_safe(p, n, &pgroup->head, entry) {
free(p);
}
free(pgroup);
}
return err;
}
int lvgl_module_varable_reg_send(unsigned int msg_id, char refr_now)
{
for (const struct ui_varable_reg_t *p = ui_varable_reg_tab_begin; p < ui_varable_reg_tab_end; p++) {
if (p->msg_id == msg_id) {
lvgl_module_msg_send_global_ptr(msg_id, p->ptr, p->len, refr_now);
break;
}
}
return 0;
}
int lvgl_module_varable_reg_group_add(void *group, unsigned int msg_id)
{
for (const struct ui_varable_reg_t *p = ui_varable_reg_tab_begin; p < ui_varable_reg_tab_end; p++) {
if (p->msg_id == msg_id) {
lvgl_module_msg_group_add_global_ptr(group, msg_id, p->ptr, p->len);
break;
}
}
return 0;
}
int lvgl_module_varable_reg_group_send(void *group, char refr_now)
{
return lvgl_module_msg_group_send(group, refr_now);
}
static void lvgl_module_msg_deal(int *msg)
{
if (msg[1] == LVGL_MODULE_MSG_CONST_OR_VALUE) {
if (gui_msg_send(msg[2], (void *)msg[3], msg[4])) {
printf("%s[%d] gui msg_id[%d] had unsubscribe\r\n", __func__, __LINE__, msg[2]);
}
} else if (msg[1] == LVGL_MODULE_MSG_PTR) {
lvgl_module_msg_t *p = (lvgl_module_msg_t *)msg[2];
if (gui_msg_send(p->msg_id, (void *)p->data, p->msg_len)) {
printf("%s[%d] gui msg_id[%d] had unsubscribe\r\n", __func__, __LINE__, p->msg_id);
}
spin_lock(&list_spinlock);
list_del(&p->entry);
spin_unlock(&list_spinlock);
free(p);
} else if (msg[1] == LVGL_MODULE_MSG_GROUP) {
lvgl_module_msg_group_t *pgroup = (lvgl_module_msg_group_t *)msg[2];
spin_lock(&group_list_spinlock);
list_del(&pgroup->entry);
spin_unlock(&group_list_spinlock);
lvgl_module_msg_t *p, *n;
list_for_each_entry_safe(p, n, &pgroup->head, entry) {
if (p->msg_type == LVGL_MODULE_MSG_CONST_OR_VALUE) {
if (gui_msg_send(p->msg_id, (void *)(*(int *)p->data), p->msg_len)) {
printf("%s[%d] gui msg_id[%d] had unsubscribe\r\n", __func__, __LINE__, p->msg_id);
}
} else if (p->msg_type == LVGL_MODULE_MSG_PTR) {
if (gui_msg_send(p->msg_id, (void *)p->data, p->msg_len)) {
printf("%s[%d] gui msg_id[%d] had unsubscribe\r\n", __func__, __LINE__, p->msg_id);
}
}
free(p);
}
free(pgroup);
}
}
static void lvgl_rpc_post_func_deal(int msg[])
{
if (msg[1] == 0) {
((void (*)(void))msg[2])();
} else if (msg[1] == 1) {
((void (*)(int))msg[2])(msg[3]);
} else if (msg[1] == 2) {
((void (*)(int, int))msg[2])(msg[3], msg[4]);
} else if (msg[1] == 3) {
((void (*)(int, int, int))msg[2])(msg[3], msg[4], msg[5]);
} else if (msg[1] == 4) {
((void (*)(int, int, int, int))msg[2])(msg[3], msg[4], msg[5], msg[6]);
} else if (msg[1] == 5) {
((void (*)(int, int, int, int, int))msg[2])(msg[3], msg[4], msg[5], msg[6], msg[7]);
}
}
int lvgl_rpc_post_func(void (*rpc_func)(void *, ...), int argc, ...)
{
int err;
if (lvgl_suspend_flag) {
printf("lvgl_rpc_post suspended \n");
return -1;
}
int msg[8];
msg[0] = UI_MSG_RPC_FUNC;
msg[1] = argc;
msg[2] = (int)rpc_func;
ASSERT(argc <= ARRAY_SIZE(msg) - 3, "%s argc too long!\n", __FUNCTION__);
va_list argptr;
va_start(argptr, argc);
for (int i = 0; i < argc; i++) {
msg[i + 3] = va_arg(argptr, int);
}
va_end(argptr);
_RETRY:
err = os_taskq_post_type(LVGL_TASK_NAME, Q_USER, ARRAY_SIZE(msg), msg);
if (err) {
printf("lvgl_rpc_post_func err=%d\n", err);
msleep(20);
goto _RETRY;
}
return 0;
}
/**
* @brief lvgl 暂停函数
* @param: state: 1:开 0:关
* @param: cb: 执行成功的回调函数
* @return: none
**/
void lvgl_ui_task_suspend_resume(uint8_t state)
{
OS_SEM sem_wait;
int err;
int msg[2];
u8 is_need_wait = 1;
msg[0] = state ? UI_MSG_RESUME : UI_MSG_SUSPEND;
msg[1] = (int)&sem_wait;
if (!strcmp(os_current_task(), LVGL_TASK_NAME)) {
//当前如果不在lvgl线程则需要等待
is_need_wait = 0;
msg[1] = 0;
}
os_sem_create(&sem_wait, 0);
err = os_taskq_post_type(LVGL_TASK_NAME, Q_MSG, ARRAY_SIZE(msg), msg);
if (err) {
printf("lvgl_ui_start_stop post err=%d\n", err);
} else {
if (is_need_wait) {
err = os_sem_pend(&sem_wait, 300);
ASSERT(err != OS_TIMEOUT, "%s %s no response\n", __FUNCTION__, state ? "RESUME" : "SUSPEND");
}
}
os_sem_del(&sem_wait, OS_DEL_ALWAYS);
}
u8 lvgl_ui_is_suspended(void)
{
return lvgl_suspend_flag;
}
_WEAK_ void jl_gui_init(void)
{
#if LV_USE_MONKEY != 0
/*Create pointer monkey test*/
lv_monkey_config_t monkey_pointer_config;
monkey_pointer_config.type = LV_INDEV_TYPE_POINTER;
monkey_pointer_config.period_range.min = 20;
monkey_pointer_config.period_range.max = 20;
lv_monkey_set_enable(lv_monkey_create(&monkey_pointer_config), true);
/*Create keypad monkey test*/
lv_monkey_config_t monkey_keypad_config;
monkey_keypad_config.type = LV_INDEV_TYPE_KEYPAD;
monkey_keypad_config.period_range.min = 20;
monkey_keypad_config.period_range.max = 20;
lv_monkey_set_enable(lv_monkey_create(&monkey_keypad_config), true);
/*Create encoder monkey test*/
lv_monkey_config_t monkey_encode_config;
monkey_encode_config.type = LV_INDEV_TYPE_ENCODER;
monkey_encode_config.period_range.min = 20;
monkey_encode_config.period_range.max = 20;
monkey_encode_config.input_range.min = -5;
monkey_encode_config.input_range.max = 5;
lv_monkey_set_enable(lv_monkey_create(&monkey_encode_config), true);
#endif
#if LV_USE_DEMO_BENCHMARK
lv_demo_benchmark();
#elif LV_USE_DEMO_WIDGETS
lv_demo_widgets();
#else
puts("\r\n\r\n LVGL APP NOT DEFINE...");
#endif
}
__attribute__((weak)) void ui_sysinfo_init()
{
}
static void lvgl_main_task(void *priv)
{
clock_lock("ui_show", clk_get_max_frequency());
lv_init();
lv_port_fs_init();
lv_port_disp_init(priv);
lv_port_indev_init();
lv_screen_manage_init();
lv_ui_src_pack_mode_init();
#if LV_USE_GPU_COMPRESS
lv_c1_init();
#endif
lvgl_ui_key_set_send_event_cb(lvgl_key_event_handler);
lvgl_suspend_flag = 0;
jl_gui_init();
int msg[8] = {0};
int ret;
lvgl_touch_timer_status = 0;
char lvgl_task_pend_timeout_refr_flag = 0;
u32 time_till_next;
u8 timeout = 3;
//刷新第一帧不需要事件触发
time_till_next = lv_timer_handler();
if (time_till_next != 0xFFFFFFFF) {
sys_hi_timeout_add(NULL, lvgl_timer_event_timeout, time_till_next);
}
ui_sysinfo_init();
while (1) {
ret = os_taskq_pend_timeout(NULL, msg, ARRAY_SIZE(msg), timeout); //超时是为了模型改变,但未触发刷屏,设置最大延时30毫秒
if (ret != OS_TASKQ && ret != OS_TIMEOUT) {
printf("lvgl_main_task os_taskq_pend err=%d %d\n", ret, msg[0]);
continue;
}
if (ret == OS_TIMEOUT) {
if (lvgl_task_pend_timeout_refr_flag == 0) {
/*puts("ui task pend timeout, nothing happend\r\n");*/
continue; //如果没有模型改变消息,不需要刷新屏幕
} else {
puts("ui task pend timeout, module change happend\r\n");
}
lvgl_task_pend_timeout_refr_flag = 0;
} else if (msg[1] == UI_MSG_TOUCH) {
lv_set_timer_read_touch_mode((u16)msg[2], (u16)msg[3], (u8)msg[4]);
} else if (msg[1] == UI_MSG_KEY) {
--lvgl_key_msg_remain_cnt;
if (lv_get_screen_saver_status()) {
//唤醒lvgl
lvgl_ui_task_suspend_resume(1);
continue;
} else {
lv_ui_auto_shut_down_re_run();
}
if (lvgl_suspend_flag) {
continue;
}
/*printf("lvgl_key_msg_remain_cnt = %d\r\n", lvgl_key_msg_remain_cnt);*/
struct key_event *e = (struct key_event *)&msg[2];
lv_indev_timer_read_key(e);
} else if (msg[1] == UI_MSG_ENCODER) {
--lvgl_key_msg_remain_cnt;
struct key_event *e = (struct key_event *)&msg[2];
lv_indev_timer_read_encoder(e);
} else if (msg[1] == UI_MSG_MODULE_CHANGE || msg[1] == UI_MSG_MODULE_CHANGE_REFRESH_NOW) {
lvgl_module_msg_deal(&msg[1]);
if (msg[1] == UI_MSG_MODULE_CHANGE) {
if (timer_get_ms() - lv_get_timer_handler_start_time_ms() < 20) {//对于不需要立刻刷屏的模型改变的消息,限制最大间隔20毫秒刷屏一次
/*printf("UI_MSG_MODULE_CHANGE DELAY");*/
lvgl_task_pend_timeout_refr_flag = 1;
continue;
} else {
/*printf("UI_MSG_MODULE_CHANGE REFRESH NOW");*/
}
}
} else if (msg[1] == UI_MSG_TIMER_TIMEOUT) {
lvgl_timerout_msg_remain_flag = 2; //标记LVGL定时器超时消息已经消耗掉
} else if (msg[1] == UI_MSG_SUSPEND) {
timeout = 0;
lvgl_suspend_flag = 1;
if (msg[2]) {
os_sem_post((OS_SEM *)msg[2]);
}
continue;
} else if (msg[1] == UI_MSG_RESUME) {
timeout = 3;
lvgl_suspend_flag = 0;
lv_screen_recover();
if (msg[2]) {
os_sem_post((OS_SEM *)msg[2]);
}
} else if (msg[1] == UI_MSG_RPC_FUNC) {
lvgl_rpc_post_func_deal(&msg[1]);
}
if (lvgl_suspend_flag) {
time_till_next = 0xFFFFFFFF;
} else {
//__repeat_run:
time_till_next = lv_timer_handler();
}
if (time_till_next == 0) {//没有时间释放CPU了
/*printf("lvgl time_till_next == 0\r\n");*/
}
if (lvgl_key_msg_remain_cnt <= 0) { //如果按键事件还没消耗完,利用按键事件来调度运行,不需要超时事件来调度, LVGL任务会持续运转
/*printf("lvgl time_till_next %d ms, lvgl_timerout_msg_remain_flag=%d\r\n", time_till_next,lvgl_timerout_msg_remain_flag); */
if (time_till_next != 0xFFFFFFFF) {//如果LVGL内部有注册超时定时器
if (lvgl_timerout_msg_remain_flag == 2) { //定时器超时消息已经被消耗掉
lvgl_timerout_msg_remain_flag = 0;
/* printf("lvgl add timeout msg %d\r\n",time_till_next); */
lvgl_timeout_id = sys_timeout_add(NULL, lvgl_timer_event_timeout, time_till_next < 3 ? 3 : time_till_next); //FIX_ME:系统未支持1ms时间超时释放cpu
} else if (lvgl_timerout_msg_remain_flag == 1) { //超时函数已跑起,并且post消息成功,但是消息还在队列内未消耗
lvgl_timerout_msg_remain_flag = 0;
if (os_taskq_del_type(LVGL_TASK_NAME, Q_EVENT)) {
//puts("lvgl_timeout_event_del err\r\n"); //有可能由于超时定时器和lvgl任务不同gpu导致lvgl_timerout_msg_remain_flag执行乱序,不过不会造成不良影响
}
/* printf("lvgl add timeout msg %d\r\n", time_till_next); */
lvgl_timeout_id = sys_timeout_add(NULL, lvgl_timer_event_timeout, time_till_next < 3 ? 3 : time_till_next); //FIX_ME:系统未支持1ms时间超时释放cpu
} else { //超时函数未跑起
if (lvgl_timeout_id) {
sys_timer_modify(lvgl_timeout_id, time_till_next < 3 ? 3 : time_till_next); //有可能由于超时函数已经跑起修改不成功,但是也没所谓, 主要担心修改到其他ID的注册定时器
}
}
}
}
}//while(1)
}
int lvgl_ui_init(void *param)
{
puts("lvgl_main_task_init \n\n");
return task_create(lvgl_main_task, param, LVGL_TASK_NAME);
}