123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623 |
- /*================================================================
- Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
- Quectel Wireless Solution Proprietary and Confidential.
- =================================================================*/
- /*=================================================================
- EDIT HISTORY FOR MODULE
- This section contains comments describing changes made to the module.
- Notice that changes are listed in reverse chronological order.
- WHEN WHO WHAT, WHERE, WHY
- ------------ ------- -------------------------------------------------------------------------------
- 2020/12/14 lambert.zhao Init version
- =================================================================*/
- /*===========================================================================
- * include files
- ===========================================================================*/
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "ql_log.h"
- #include "ql_gpio.h"
- #include "ql_lcd.h"
- #include "lvgl_demo.h"
- #include "lvgl.h"
- #include "ql_keypad.h"
- #include "ql_app_feature_config.h"
- /*===========================================================================
- * Macro Definition
- ===========================================================================*/
- #define QL_LVGLDEMO_LOG_LEVEL QL_LOG_LEVEL_INFO
- #define QL_LVGLDEMO_LOG(msg, ...) QL_LOG(QL_LVGLDEMO_LOG_LEVEL, "ql_LVGLDEMO", msg, ##__VA_ARGS__)
- #define QL_LVGLDEMO_LOG_PUSH(msg, ...) QL_LOG_PUSH("ql_LVGLDEMO", msg, ##__VA_ARGS__)
- #define QL_Lvgl_TASK_STACK_SIZE 1024*4
- #define QL_Lvgl_TASK_PRIO APP_PRIORITY_NORMAL
- #define QL_LVGL_TASK_EVENT_CNT 5
- #define FALSE 0
- #define TRUE 1
- #if !defined(require_action)
- #define require_action(x, action, str) \
- do \
- { \
- if(x != 0) \
- { \
- QL_LVGLDEMO_LOG(str); \
- {action;} \
- } \
- } while( 1==0 )
- #endif
- /*===========================================================================
- * struct
- ===========================================================================*/
- typedef struct
- {
- bool screen_on; // state of screen on
- bool keypad_pending; // keypad pending, set in ISR, clear in thread
- bool anim_inactive; // property of whether animation is regarded as inactive
- ql_task_t thread; // gui thread
- ql_timer_t task_timer; // timer to trigger task handler
- lv_disp_buf_t disp_buf; // display buffer
- lv_disp_t *disp; // display device
- lv_indev_t *keypad; // keypad device
- #ifdef QL_APP_FEATURE_KEYPAD
- ql_keymap_e last_key; // last key from ISR
- ql_keystate_e last_key_state; // last key state from ISR
- #endif
- uint32_t screen_on_users; // screen on user bitmap
- uint32_t inactive_timeout; // property of inactive timeout
- } lvglContext_t;
- typedef struct
- {
- uint8_t keypad;
- uint8_t lv_key;
- } lvGuiKeypadMap_t;
- uint32_t g_lcd_width = CONFIG_LV_GUI_HOR_RES;
- uint32_t g_lcd_height = CONFIG_LV_GUI_VER_RES;
- static lv_group_t *lv_group;
- static lvglContext_t gLvCtx;
- ql_task_t lvgl_gui_task=NULL;
- #ifdef QL_APP_FEATURE_KEYPAD
- static const lvGuiKeypadMap_t gLvKeyMap[] = {
- {QL_KEY_MAP_1, '0'},
- {QL_KEY_MAP_2, '1'},
- {QL_KEY_MAP_3, '2'},
- {QL_KEY_MAP_4, '3'},
- {QL_KEY_MAP_5, '4'},
- {QL_KEY_MAP_6, '5'},
- {QL_KEY_MAP_7, '6'},
- {QL_KEY_MAP_8, '7'},
- {QL_KEY_MAP_9, '8'},
- {QL_KEY_MAP_10, '9'},
- {QL_KEY_MAP_11, '*'},
- {QL_KEY_MAP_12, '#'},
- {QL_KEY_MAP_13, LV_KEY_ENTER},
- {QL_KEY_MAP_14, LV_KEY_LEFT},
- {QL_KEY_MAP_15, LV_KEY_RIGHT},
- {QL_KEY_MAP_16, LV_KEY_UP},
- {QL_KEY_MAP_17, LV_KEY_DOWN},
- {QL_KEY_MAP_18, LV_KEY_PREV},
- {QL_KEY_MAP_19, LV_KEY_NEXT},
- };
- #endif
- /*===========================================================================
- * Functions
- ===========================================================================*/
- /**
- * display device flush_cb
- */
- static void prvDispFlush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
- {
- QL_LVGLDEMO_LOG("disp flush %d/%d/%d/%d", area->x1, area->y1, area->x2, area->y2);
- ql_lcd_write((uint16_t*)color_p, area->x1 , area->y1, area->x2 , area->y2);
- lv_disp_flush_ready(disp);
- }
- /**
- * initialize LCD display device
- */
- static bool prvLvInitLcd(void)
- {
- lvglContext_t *d = &gLvCtx;
- unsigned pixel_cnt = g_lcd_width * g_lcd_height;
- lv_color_t *buf = (lv_color_t *)malloc(pixel_cnt * sizeof(lv_color_t));
- if (buf == NULL)
- return false;
- lv_disp_buf_init(&(d->disp_buf), buf, buf, pixel_cnt);
-
- lv_disp_drv_t disp_drv;
- lv_disp_drv_init(&disp_drv);
- disp_drv.flush_cb = prvDispFlush;
- disp_drv.buffer = &(d->disp_buf);
- lv_disp_drv_register(&disp_drv); // pointer copy;
-
- return true;
- }
- /**
- * callback of keypad driver, called in ISR
- */
- #ifdef QL_APP_FEATURE_KEYPAD
- static void prvKeypadCallback(ql_keymatrix_t keymatrix)
- {
- lvglContext_t *d = &gLvCtx;
- d->last_key = keymatrix.keymap;
- d->last_key_state = keymatrix.keystate;
- d->keypad_pending = true;
- QL_LVGLDEMO_LOG("keypad last key:%d , state:%d", keymatrix.keymap, keymatrix.keystate);
- }
- /**
- * keypad device read_cb
- */
- static bool prvLvKeypadRead(lv_indev_drv_t *kp, lv_indev_data_t *data)
- {
- lvglContext_t *d = &gLvCtx;
- uint32_t critical = ql_rtos_enter_critical();
- ql_keymap_e last_key = d->last_key;
- ql_keystate_e last_key_state = d->last_key_state;
- bool keypad_pending = d->keypad_pending;
- d->keypad_pending = false;
- ql_rtos_exit_critical(critical);
- if (keypad_pending)
- {
- data->state = (last_key_state & QL_KEY_STATE_RELEASE) ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
- data->key = 0xff;
- for (unsigned n = 0; n < OSI_ARRAY_SIZE(gLvKeyMap); n++)
- {
- if (gLvKeyMap[n].keypad == last_key)
- {
- data->key = gLvKeyMap[n].lv_key;
- break;
- }
- }
- QL_LVGLDEMO_LOG("lvgl keymap:%d key:%d state:%d", last_key, data->key, data->state);
- //lvGuiScreenOn();
- }
- // no more to be read
- return false;
- }
- #endif
- /**
- * get dev
- */
- lv_indev_t* Get_indev(void)
- {
- return gLvCtx.keypad;
- }
- /**
- * get group
- */
- lv_group_t* Get_group(void)
- {
- return lv_group;
- }
- /**
- * initialize keypad device
- */
- #ifdef QL_APP_FEATURE_KEYPAD
- static bool prvLvInitKeypad(void)
- {
- // configure keypad matrix here
- // example:configure out port:keyout0/keyout1/keyout2/keyout3/keyout4,in port:keyin1/keyin2/keyin3
- ql_keypad_out_e row[QL_KEYPAD_ROW_LENGTH] = {QL_KP_OUT0, QL_KP_OUT1, QL_KP_OUT2, QL_KP_OUT3, QL_KP_OUT4, QL_KP_OUT_NO_VALID};
- ql_keypad_in_e col[QL_KEYPAD_COL_LENGTH] = {QL_KP_IN1,QL_KP_IN2, QL_KP_IN3, QL_KP_IN4, QL_KP_IN5};
-
- lvglContext_t *d = &gLvCtx;
- lv_indev_drv_t kp_drv;
- lv_indev_drv_init(&kp_drv);
- kp_drv.type = LV_INDEV_TYPE_KEYPAD;
- kp_drv.read_cb = prvLvKeypadRead;
- d->keypad = lv_indev_drv_register(&kp_drv);
-
- lv_group = lv_group_create(); // create group
- lv_indev_set_group(d->keypad, lv_group); // connect group to dev
- ql_keypad_init(prvKeypadCallback, row, col); // keypad init
- return true;
- }
- #endif
- /**
- * run littlevgl task handler
- */
- static void prvLvTaskHandler(void)
- {
- lvglContext_t *d = &gLvCtx;
- lv_task_handler();
-
- unsigned next_run = lv_task_get_tick_next_run();
-
- ql_rtos_timer_start_relaxed(d->task_timer, next_run, TRUE, QL_WAIT_FOREVER);
-
- lv_refr_now(d->disp);
- }
- /**
- * whether inactive timeout
- */
- static bool prvIsInactiveTimeout(void)
- {
- lvglContext_t *d = &gLvCtx;
- if (d->screen_on_users != 0)
- return false;
- if (d->inactive_timeout == 0)
- return false;
- if (!d->anim_inactive && lv_anim_count_running())
- return false;
- return lv_disp_get_inactive_time(d->disp) > d->inactive_timeout;
- }
- /**
- * get keypad input device
- */
- #ifdef QL_APP_FEATURE_KEYPAD
- lv_indev_t *lvGuiGetKeyPad(void)
- {
- lvglContext_t *d = &gLvCtx;
- return d->keypad;
- }
- #endif
- /**
- * send event to gui thread
- */
- void lvGuiSendEvent(ql_event_t *evt)
- {
- lvglContext_t *d = &gLvCtx;
- ql_rtos_event_send(d->thread, evt);
- }
- /**
- * request screen on
- */
- bool lvGuiRequestSceenOn(uint8_t id)
- {
- lvglContext_t *d = &gLvCtx;
- if (id > 31)
- return false;
- unsigned mask = (1 << id);
- d->screen_on_users |= mask;
- return true;
- }
- /**
- * release screen on request
- */
- bool lvGuiReleaseScreenOn(uint8_t id)
- {
- lvglContext_t *d = &gLvCtx;
- if (id > 31)
- return false;
- unsigned mask = (1 << id);
- d->screen_on_users &= ~mask;
- return true;
- }
- /**
- * turn off screen
- */
- void lvGuiScreenOff(void)
- {
- QL_LVGLDEMO_LOG("screen off");
- lvglContext_t *d = &gLvCtx;
-
- if (!d->screen_on)
- return;
- ql_lcd_display_off();
- d->screen_on = false;
- }
- /**
- * turn on screen
- */
- void lvGuiScreenOn(void)
- {
- lvglContext_t *d = &gLvCtx;
- if (d->screen_on)
- return;
- QL_LVGLDEMO_LOG("screen on");
- ql_lcd_display_on();
- d->screen_on = true;
- }
- /**
- * set screen off timeout at inactive
- */
- void lvGuiSetInactiveTimeout(unsigned timeout)
- {
- lvglContext_t *d = &gLvCtx;
- d->inactive_timeout = timeout;
- }
- /**
- * set whether animation is regarded as inactive
- */
- void lvGuiSetAnimationInactive(bool inactive)
- {
- lvglContext_t *d = &gLvCtx;
- d->anim_inactive = inactive;
- }
- /**
- * button event cb entry
- */
- #ifdef QL_APP_FEATURE_KEYPAD
- static void lvglBtnEventCb(lv_obj_t * obj, lv_event_t event)
- {
- lv_obj_t* lv_label = lv_list_get_btn_label(obj);
- char* str1 = lv_label_get_text(lv_label);
- char* str2 = "ON";
- if(event == LV_EVENT_CLICKED) //click event
- {
- printf("Clicked\n");
- if(strcmp(str1,str2))
- {
- lv_label_set_text(lv_label, "ON");
- }
- else
- {
- lv_label_set_text(lv_label, "OFF");
- }
- }
- else if(event == LV_EVENT_VALUE_CHANGED) //switch change event
- {
- printf("Toggled\n");
- if(lv_btn_get_state(obj) == LV_BTN_STATE_REL)
- {
- lv_label_set_text(lv_label, "OFF");
- }
- else
- {
- lv_label_set_text(lv_label, "ON");
- }
- }
- }
- #endif
- static void lvglAnimCreate(void)
- {
- #ifndef QL_APP_FEATURE_KEYPAD
- static lv_style_t btn3_style;
- lv_theme_t *th = lv_theme_material_init(210, NULL);
- lv_theme_set_current(th);
- lv_obj_t *scr = lv_disp_get_scr_act(NULL); /*Get the current screen*/
- lv_obj_t *label;
- /*Create a button the demonstrate built-in animations*/
- lv_obj_t *btn1;
- btn1 = lv_btn_create(scr, NULL);
- lv_obj_set_pos(btn1, 10, 10); /*Set a position. It will be the animation's destination*/
- lv_obj_set_size(btn1, 80, 50);
- label = lv_label_create(btn1, NULL);
- lv_label_set_text(label, "Float");
- /* Float in the button using a built-in function
- * Delay the animation with 2000 ms and float in 300 ms. NULL means no end callback*/
- lv_anim_t a;
- a.var = btn1;
- a.start = -lv_obj_get_height(btn1);
- a.end = lv_obj_get_y(btn1);
- a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_y;
- a.path_cb = lv_anim_path_linear;
- a.ready_cb = NULL;
- a.act_time = -2000; /*Delay the animation*/
- a.time = 300;
- a.playback = 0;
- a.playback_pause = 0;
- a.repeat = 0;
- a.repeat_pause = 0;
- #if LV_USE_USER_DATA
- a.user_data = NULL;
- #endif
- lv_anim_create(&a);
- /*Create a button to demonstrate user defined animations*/
- lv_obj_t *btn2;
- btn2 = lv_btn_create(scr, NULL);
- lv_obj_set_pos(btn2, 10, 80); /*Set a position. It will be the animation's destination*/
- lv_obj_set_size(btn2, 80, 50);
- label = lv_label_create(btn2, NULL);
- lv_label_set_text(label, "Move");
- /*Create an animation to move the button continuously left to right*/
- a.var = btn2;
- a.start = lv_obj_get_x(btn2);
- a.end = a.start + (100);
- a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_x;
- a.path_cb = lv_anim_path_linear;
- a.ready_cb = NULL;
- a.act_time = -1000; /*Negative number to set a delay*/
- a.time = 400; /*Animate in 400 ms*/
- a.playback = 1; /*Make the animation backward too when it's ready*/
- a.playback_pause = 0; /*Wait before playback*/
- a.repeat = 1; /*Repeat the animation*/
- a.repeat_pause = 500; /*Wait before repeat*/
- lv_anim_create(&a);
- /*Create a button to demonstrate the style animations*/
- lv_obj_t *btn3;
- btn3 = lv_btn_create(scr, NULL);
- lv_obj_set_pos(btn3, 10, 150); /*Set a position. It will be the animation's destination*/
- lv_obj_set_size(btn3, 80, 50);
- label = lv_label_create(btn3, NULL);
- lv_label_set_text(label, "Style");
- /*Create a unique style for the button*/
- lv_style_copy(&btn3_style, lv_btn_get_style(btn3, LV_BTN_STYLE_REL));
- lv_btn_set_style(btn3, LV_BTN_STATE_REL, &btn3_style);
- /*Animate the new style*/
- lv_anim_t sa;
- lv_style_anim_init(&sa);
- lv_style_anim_set_styles(&sa, &btn3_style, &lv_style_btn_rel, &lv_style_pretty);
- lv_style_anim_set_time(&sa, 500, 500);
- lv_style_anim_set_playback(&sa, 500);
- lv_style_anim_set_repeat(&sa, 500);
- lv_style_anim_create(&sa);
- #else
- static lv_style_t rel_style, pr_style;
- lv_style_copy(&rel_style, &lv_style_btn_rel); /*Create styles for the keyboard*/
- rel_style.body.radius = 0;
- rel_style.body.border.width = 1;
-
- lv_style_copy(&pr_style, &lv_style_btn_pr);
- pr_style.body.radius = 0;
- pr_style.body.border.width = 1;
-
- lv_obj_t *kb = lv_kb_create(lv_disp_get_scr_act(NULL), NULL); /*Create a keyboard and apply the styles*/
- lv_kb_set_cursor_manage(kb, true);
- lv_kb_set_style(kb, LV_KB_STYLE_BG, &lv_style_transp_tight);
- lv_kb_set_style(kb, LV_KB_STYLE_BTN_REL, &rel_style);
- lv_kb_set_style(kb, LV_KB_STYLE_BTN_PR, &pr_style);
-
- lv_obj_t *ta = lv_ta_create(lv_disp_get_scr_act(NULL), NULL); /*Create a text area. The keyboard will write here*/
- lv_obj_align(ta, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
- lv_ta_set_text(ta, "");
-
- lv_kb_set_ta(kb, ta); /*Assign the text area to the keyboard*/
- lv_obj_t *label;
- lv_obj_t *btn;
- btn = lv_btn_create(lv_disp_get_scr_act(NULL), NULL);
- lv_obj_set_pos(btn, 10, 115); /*Set a position. It will be the animation's destination*/
- lv_obj_set_size(btn, 80, 40);
- label = lv_label_create(btn, NULL);
- lv_label_set_text(label, "ON");
- lv_obj_set_event_cb(btn, lvglBtnEventCb); /*set the callback function of the current button*/
- lv_group_t *group = Get_group();
- lv_group_add_obj(group ,kb); /*add to group*/
- lv_group_add_obj(group ,ta);
- lv_group_add_obj(group ,btn);
- #endif
- }
- static void ql_lvgl_demo_thread(void *param)
- {
- lvglContext_t *d = &gLvCtx;
- QlOSStatus err = 0;
- ql_event_t event;
- QL_LVGLDEMO_LOG("lvgl demo thread enter, param 0x%x", param);
- d->screen_on = true;
- d->keypad_pending = false;
- d->anim_inactive = false;
- d->screen_on_users = 0;
- d->inactive_timeout = CONFIG_LV_GUI_SCREEN_OFF_TIMEOUT;
-
-
- err=ql_rtos_task_get_current_ref(&d->thread);
- require_action(err, goto exit, "lvgl_demo_taskref get failed");
- err=ql_rtos_timer_create(&d->task_timer, d->thread, (lvgl_Callback_t)prvLvTaskHandler, NULL);
- require_action(err, goto exit, "lvgl_demo_timer created failed");
-
- if(ql_lcd_init() != QL_LCD_SUCCESS )
- {
- QL_LVGLDEMO_LOG("LCD init failed");
- goto exit;
- }
- lv_init();
- prvLvInitLcd();
-
- #ifdef QL_APP_FEATURE_KEYPAD
- prvLvInitKeypad();
- #endif
- lvGuiCreate_t create = (lvGuiCreate_t)param;
- if (create != NULL)
- {
- create();
- }
- err = ql_rtos_timer_start(d->task_timer, 10, 1);
- require_action(err, goto exit, "lvgl_demo_timer start failed");
-
- lv_disp_trig_activity(d->disp);
-
- while(1)
- {
- ql_event_try_wait(&event);
- if (event.id == QUEC_LVGL_QUIT_IND)
- break;
- if (d->screen_on && prvIsInactiveTimeout())
- {
- QL_LVGLDEMO_LOG("inactive timeout, screen off");
- lvGuiScreenOff();
- }
- }
-
- exit:
- QL_LVGLDEMO_LOG("lvgl demo thread exit, param 0x%x", param);
- ql_rtos_timer_delete(d->task_timer);
- d->task_timer = NULL;
-
- err = ql_rtos_task_delete(NULL);
- if(err != QL_OSI_SUCCESS)
- {
- QL_LVGLDEMO_LOG("lvgl task deleted failed");
- }
- }
- void ql_lvgl_app_init(void)
- {
- QlOSStatus err = 0;
-
- err = ql_rtos_task_create(&lvgl_gui_task, QL_Lvgl_TASK_STACK_SIZE, QL_Lvgl_TASK_PRIO, "QLVGLDEMO", ql_lvgl_demo_thread, lvglAnimCreate, QL_LVGL_TASK_EVENT_CNT);
- if (err != QL_OSI_SUCCESS)
- {
- QL_LVGLDEMO_LOG("lvgl demo task created failed");
- }
- }
|