#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); }