lvgl_demo.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. /*================================================================
  2. Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
  3. Quectel Wireless Solution Proprietary and Confidential.
  4. =================================================================*/
  5. /*=================================================================
  6. EDIT HISTORY FOR MODULE
  7. This section contains comments describing changes made to the module.
  8. Notice that changes are listed in reverse chronological order.
  9. WHEN WHO WHAT, WHERE, WHY
  10. ------------ ------- -------------------------------------------------------------------------------
  11. 2020/12/14 lambert.zhao Init version
  12. =================================================================*/
  13. /*===========================================================================
  14. * include files
  15. ===========================================================================*/
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include "ql_log.h"
  20. #include "ql_gpio.h"
  21. #include "ql_lcd.h"
  22. #include "lvgl_demo.h"
  23. #include "lvgl.h"
  24. #include "ql_keypad.h"
  25. #include "ql_app_feature_config.h"
  26. /*===========================================================================
  27. * Macro Definition
  28. ===========================================================================*/
  29. #define QL_LVGLDEMO_LOG_LEVEL QL_LOG_LEVEL_INFO
  30. #define QL_LVGLDEMO_LOG(msg, ...) QL_LOG(QL_LVGLDEMO_LOG_LEVEL, "ql_LVGLDEMO", msg, ##__VA_ARGS__)
  31. #define QL_LVGLDEMO_LOG_PUSH(msg, ...) QL_LOG_PUSH("ql_LVGLDEMO", msg, ##__VA_ARGS__)
  32. #define QL_Lvgl_TASK_STACK_SIZE 1024*4
  33. #define QL_Lvgl_TASK_PRIO APP_PRIORITY_NORMAL
  34. #define QL_LVGL_TASK_EVENT_CNT 5
  35. #define FALSE 0
  36. #define TRUE 1
  37. #if !defined(require_action)
  38. #define require_action(x, action, str) \
  39. do \
  40. { \
  41. if(x != 0) \
  42. { \
  43. QL_LVGLDEMO_LOG(str); \
  44. {action;} \
  45. } \
  46. } while( 1==0 )
  47. #endif
  48. /*===========================================================================
  49. * struct
  50. ===========================================================================*/
  51. typedef struct
  52. {
  53. bool screen_on; // state of screen on
  54. bool keypad_pending; // keypad pending, set in ISR, clear in thread
  55. bool anim_inactive; // property of whether animation is regarded as inactive
  56. ql_task_t thread; // gui thread
  57. ql_timer_t task_timer; // timer to trigger task handler
  58. lv_disp_buf_t disp_buf; // display buffer
  59. lv_disp_t *disp; // display device
  60. lv_indev_t *keypad; // keypad device
  61. #ifdef QL_APP_FEATURE_KEYPAD
  62. ql_keymap_e last_key; // last key from ISR
  63. ql_keystate_e last_key_state; // last key state from ISR
  64. #endif
  65. uint32_t screen_on_users; // screen on user bitmap
  66. uint32_t inactive_timeout; // property of inactive timeout
  67. } lvglContext_t;
  68. typedef struct
  69. {
  70. uint8_t keypad;
  71. uint8_t lv_key;
  72. } lvGuiKeypadMap_t;
  73. uint32_t g_lcd_width = CONFIG_LV_GUI_HOR_RES;
  74. uint32_t g_lcd_height = CONFIG_LV_GUI_VER_RES;
  75. static lv_group_t *lv_group;
  76. static lvglContext_t gLvCtx;
  77. ql_task_t lvgl_gui_task=NULL;
  78. #ifdef QL_APP_FEATURE_KEYPAD
  79. static const lvGuiKeypadMap_t gLvKeyMap[] = {
  80. {QL_KEY_MAP_1, '0'},
  81. {QL_KEY_MAP_2, '1'},
  82. {QL_KEY_MAP_3, '2'},
  83. {QL_KEY_MAP_4, '3'},
  84. {QL_KEY_MAP_5, '4'},
  85. {QL_KEY_MAP_6, '5'},
  86. {QL_KEY_MAP_7, '6'},
  87. {QL_KEY_MAP_8, '7'},
  88. {QL_KEY_MAP_9, '8'},
  89. {QL_KEY_MAP_10, '9'},
  90. {QL_KEY_MAP_11, '*'},
  91. {QL_KEY_MAP_12, '#'},
  92. {QL_KEY_MAP_13, LV_KEY_ENTER},
  93. {QL_KEY_MAP_14, LV_KEY_LEFT},
  94. {QL_KEY_MAP_15, LV_KEY_RIGHT},
  95. {QL_KEY_MAP_16, LV_KEY_UP},
  96. {QL_KEY_MAP_17, LV_KEY_DOWN},
  97. {QL_KEY_MAP_18, LV_KEY_PREV},
  98. {QL_KEY_MAP_19, LV_KEY_NEXT},
  99. };
  100. #endif
  101. /*===========================================================================
  102. * Functions
  103. ===========================================================================*/
  104. /**
  105. * display device flush_cb
  106. */
  107. static void prvDispFlush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
  108. {
  109. QL_LVGLDEMO_LOG("disp flush %d/%d/%d/%d", area->x1, area->y1, area->x2, area->y2);
  110. ql_lcd_write((uint16_t*)color_p, area->x1 , area->y1, area->x2 , area->y2);
  111. lv_disp_flush_ready(disp);
  112. }
  113. /**
  114. * initialize LCD display device
  115. */
  116. static bool prvLvInitLcd(void)
  117. {
  118. lvglContext_t *d = &gLvCtx;
  119. unsigned pixel_cnt = g_lcd_width * g_lcd_height;
  120. lv_color_t *buf = (lv_color_t *)malloc(pixel_cnt * sizeof(lv_color_t));
  121. if (buf == NULL)
  122. return false;
  123. lv_disp_buf_init(&(d->disp_buf), buf, buf, pixel_cnt);
  124. lv_disp_drv_t disp_drv;
  125. lv_disp_drv_init(&disp_drv);
  126. disp_drv.flush_cb = prvDispFlush;
  127. disp_drv.buffer = &(d->disp_buf);
  128. lv_disp_drv_register(&disp_drv); // pointer copy;
  129. return true;
  130. }
  131. /**
  132. * callback of keypad driver, called in ISR
  133. */
  134. #ifdef QL_APP_FEATURE_KEYPAD
  135. static void prvKeypadCallback(ql_keymatrix_t keymatrix)
  136. {
  137. lvglContext_t *d = &gLvCtx;
  138. d->last_key = keymatrix.keymap;
  139. d->last_key_state = keymatrix.keystate;
  140. d->keypad_pending = true;
  141. QL_LVGLDEMO_LOG("keypad last key:%d , state:%d", keymatrix.keymap, keymatrix.keystate);
  142. }
  143. /**
  144. * keypad device read_cb
  145. */
  146. static bool prvLvKeypadRead(lv_indev_drv_t *kp, lv_indev_data_t *data)
  147. {
  148. lvglContext_t *d = &gLvCtx;
  149. uint32_t critical = ql_rtos_enter_critical();
  150. ql_keymap_e last_key = d->last_key;
  151. ql_keystate_e last_key_state = d->last_key_state;
  152. bool keypad_pending = d->keypad_pending;
  153. d->keypad_pending = false;
  154. ql_rtos_exit_critical(critical);
  155. if (keypad_pending)
  156. {
  157. data->state = (last_key_state & QL_KEY_STATE_RELEASE) ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
  158. data->key = 0xff;
  159. for (unsigned n = 0; n < OSI_ARRAY_SIZE(gLvKeyMap); n++)
  160. {
  161. if (gLvKeyMap[n].keypad == last_key)
  162. {
  163. data->key = gLvKeyMap[n].lv_key;
  164. break;
  165. }
  166. }
  167. QL_LVGLDEMO_LOG("lvgl keymap:%d key:%d state:%d", last_key, data->key, data->state);
  168. //lvGuiScreenOn();
  169. }
  170. // no more to be read
  171. return false;
  172. }
  173. #endif
  174. /**
  175. * get dev
  176. */
  177. lv_indev_t* Get_indev(void)
  178. {
  179. return gLvCtx.keypad;
  180. }
  181. /**
  182. * get group
  183. */
  184. lv_group_t* Get_group(void)
  185. {
  186. return lv_group;
  187. }
  188. /**
  189. * initialize keypad device
  190. */
  191. #ifdef QL_APP_FEATURE_KEYPAD
  192. static bool prvLvInitKeypad(void)
  193. {
  194. // configure keypad matrix here
  195. // example:configure out port:keyout0/keyout1/keyout2/keyout3/keyout4,in port:keyin1/keyin2/keyin3
  196. 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};
  197. ql_keypad_in_e col[QL_KEYPAD_COL_LENGTH] = {QL_KP_IN1,QL_KP_IN2, QL_KP_IN3, QL_KP_IN4, QL_KP_IN5};
  198. lvglContext_t *d = &gLvCtx;
  199. lv_indev_drv_t kp_drv;
  200. lv_indev_drv_init(&kp_drv);
  201. kp_drv.type = LV_INDEV_TYPE_KEYPAD;
  202. kp_drv.read_cb = prvLvKeypadRead;
  203. d->keypad = lv_indev_drv_register(&kp_drv);
  204. lv_group = lv_group_create(); // create group
  205. lv_indev_set_group(d->keypad, lv_group); // connect group to dev
  206. ql_keypad_init(prvKeypadCallback, row, col); // keypad init
  207. return true;
  208. }
  209. #endif
  210. /**
  211. * run littlevgl task handler
  212. */
  213. static void prvLvTaskHandler(void)
  214. {
  215. lvglContext_t *d = &gLvCtx;
  216. lv_task_handler();
  217. unsigned next_run = lv_task_get_tick_next_run();
  218. ql_rtos_timer_start_relaxed(d->task_timer, next_run, TRUE, QL_WAIT_FOREVER);
  219. lv_refr_now(d->disp);
  220. }
  221. /**
  222. * whether inactive timeout
  223. */
  224. static bool prvIsInactiveTimeout(void)
  225. {
  226. lvglContext_t *d = &gLvCtx;
  227. if (d->screen_on_users != 0)
  228. return false;
  229. if (d->inactive_timeout == 0)
  230. return false;
  231. if (!d->anim_inactive && lv_anim_count_running())
  232. return false;
  233. return lv_disp_get_inactive_time(d->disp) > d->inactive_timeout;
  234. }
  235. /**
  236. * get keypad input device
  237. */
  238. #ifdef QL_APP_FEATURE_KEYPAD
  239. lv_indev_t *lvGuiGetKeyPad(void)
  240. {
  241. lvglContext_t *d = &gLvCtx;
  242. return d->keypad;
  243. }
  244. #endif
  245. /**
  246. * send event to gui thread
  247. */
  248. void lvGuiSendEvent(ql_event_t *evt)
  249. {
  250. lvglContext_t *d = &gLvCtx;
  251. ql_rtos_event_send(d->thread, evt);
  252. }
  253. /**
  254. * request screen on
  255. */
  256. bool lvGuiRequestSceenOn(uint8_t id)
  257. {
  258. lvglContext_t *d = &gLvCtx;
  259. if (id > 31)
  260. return false;
  261. unsigned mask = (1 << id);
  262. d->screen_on_users |= mask;
  263. return true;
  264. }
  265. /**
  266. * release screen on request
  267. */
  268. bool lvGuiReleaseScreenOn(uint8_t id)
  269. {
  270. lvglContext_t *d = &gLvCtx;
  271. if (id > 31)
  272. return false;
  273. unsigned mask = (1 << id);
  274. d->screen_on_users &= ~mask;
  275. return true;
  276. }
  277. /**
  278. * turn off screen
  279. */
  280. void lvGuiScreenOff(void)
  281. {
  282. QL_LVGLDEMO_LOG("screen off");
  283. lvglContext_t *d = &gLvCtx;
  284. if (!d->screen_on)
  285. return;
  286. ql_lcd_display_off();
  287. d->screen_on = false;
  288. }
  289. /**
  290. * turn on screen
  291. */
  292. void lvGuiScreenOn(void)
  293. {
  294. lvglContext_t *d = &gLvCtx;
  295. if (d->screen_on)
  296. return;
  297. QL_LVGLDEMO_LOG("screen on");
  298. ql_lcd_display_on();
  299. d->screen_on = true;
  300. }
  301. /**
  302. * set screen off timeout at inactive
  303. */
  304. void lvGuiSetInactiveTimeout(unsigned timeout)
  305. {
  306. lvglContext_t *d = &gLvCtx;
  307. d->inactive_timeout = timeout;
  308. }
  309. /**
  310. * set whether animation is regarded as inactive
  311. */
  312. void lvGuiSetAnimationInactive(bool inactive)
  313. {
  314. lvglContext_t *d = &gLvCtx;
  315. d->anim_inactive = inactive;
  316. }
  317. /**
  318. * button event cb entry
  319. */
  320. #ifdef QL_APP_FEATURE_KEYPAD
  321. static void lvglBtnEventCb(lv_obj_t * obj, lv_event_t event)
  322. {
  323. lv_obj_t* lv_label = lv_list_get_btn_label(obj);
  324. char* str1 = lv_label_get_text(lv_label);
  325. char* str2 = "ON";
  326. if(event == LV_EVENT_CLICKED) //click event
  327. {
  328. printf("Clicked\n");
  329. if(strcmp(str1,str2))
  330. {
  331. lv_label_set_text(lv_label, "ON");
  332. }
  333. else
  334. {
  335. lv_label_set_text(lv_label, "OFF");
  336. }
  337. }
  338. else if(event == LV_EVENT_VALUE_CHANGED) //switch change event
  339. {
  340. printf("Toggled\n");
  341. if(lv_btn_get_state(obj) == LV_BTN_STATE_REL)
  342. {
  343. lv_label_set_text(lv_label, "OFF");
  344. }
  345. else
  346. {
  347. lv_label_set_text(lv_label, "ON");
  348. }
  349. }
  350. }
  351. #endif
  352. static void lvglAnimCreate(void)
  353. {
  354. #ifndef QL_APP_FEATURE_KEYPAD
  355. static lv_style_t btn3_style;
  356. lv_theme_t *th = lv_theme_material_init(210, NULL);
  357. lv_theme_set_current(th);
  358. lv_obj_t *scr = lv_disp_get_scr_act(NULL); /*Get the current screen*/
  359. lv_obj_t *label;
  360. /*Create a button the demonstrate built-in animations*/
  361. lv_obj_t *btn1;
  362. btn1 = lv_btn_create(scr, NULL);
  363. lv_obj_set_pos(btn1, 10, 10); /*Set a position. It will be the animation's destination*/
  364. lv_obj_set_size(btn1, 80, 50);
  365. label = lv_label_create(btn1, NULL);
  366. lv_label_set_text(label, "Float");
  367. /* Float in the button using a built-in function
  368. * Delay the animation with 2000 ms and float in 300 ms. NULL means no end callback*/
  369. lv_anim_t a;
  370. a.var = btn1;
  371. a.start = -lv_obj_get_height(btn1);
  372. a.end = lv_obj_get_y(btn1);
  373. a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_y;
  374. a.path_cb = lv_anim_path_linear;
  375. a.ready_cb = NULL;
  376. a.act_time = -2000; /*Delay the animation*/
  377. a.time = 300;
  378. a.playback = 0;
  379. a.playback_pause = 0;
  380. a.repeat = 0;
  381. a.repeat_pause = 0;
  382. #if LV_USE_USER_DATA
  383. a.user_data = NULL;
  384. #endif
  385. lv_anim_create(&a);
  386. /*Create a button to demonstrate user defined animations*/
  387. lv_obj_t *btn2;
  388. btn2 = lv_btn_create(scr, NULL);
  389. lv_obj_set_pos(btn2, 10, 80); /*Set a position. It will be the animation's destination*/
  390. lv_obj_set_size(btn2, 80, 50);
  391. label = lv_label_create(btn2, NULL);
  392. lv_label_set_text(label, "Move");
  393. /*Create an animation to move the button continuously left to right*/
  394. a.var = btn2;
  395. a.start = lv_obj_get_x(btn2);
  396. a.end = a.start + (100);
  397. a.exec_cb = (lv_anim_exec_xcb_t)lv_obj_set_x;
  398. a.path_cb = lv_anim_path_linear;
  399. a.ready_cb = NULL;
  400. a.act_time = -1000; /*Negative number to set a delay*/
  401. a.time = 400; /*Animate in 400 ms*/
  402. a.playback = 1; /*Make the animation backward too when it's ready*/
  403. a.playback_pause = 0; /*Wait before playback*/
  404. a.repeat = 1; /*Repeat the animation*/
  405. a.repeat_pause = 500; /*Wait before repeat*/
  406. lv_anim_create(&a);
  407. /*Create a button to demonstrate the style animations*/
  408. lv_obj_t *btn3;
  409. btn3 = lv_btn_create(scr, NULL);
  410. lv_obj_set_pos(btn3, 10, 150); /*Set a position. It will be the animation's destination*/
  411. lv_obj_set_size(btn3, 80, 50);
  412. label = lv_label_create(btn3, NULL);
  413. lv_label_set_text(label, "Style");
  414. /*Create a unique style for the button*/
  415. lv_style_copy(&btn3_style, lv_btn_get_style(btn3, LV_BTN_STYLE_REL));
  416. lv_btn_set_style(btn3, LV_BTN_STATE_REL, &btn3_style);
  417. /*Animate the new style*/
  418. lv_anim_t sa;
  419. lv_style_anim_init(&sa);
  420. lv_style_anim_set_styles(&sa, &btn3_style, &lv_style_btn_rel, &lv_style_pretty);
  421. lv_style_anim_set_time(&sa, 500, 500);
  422. lv_style_anim_set_playback(&sa, 500);
  423. lv_style_anim_set_repeat(&sa, 500);
  424. lv_style_anim_create(&sa);
  425. #else
  426. static lv_style_t rel_style, pr_style;
  427. lv_style_copy(&rel_style, &lv_style_btn_rel); /*Create styles for the keyboard*/
  428. rel_style.body.radius = 0;
  429. rel_style.body.border.width = 1;
  430. lv_style_copy(&pr_style, &lv_style_btn_pr);
  431. pr_style.body.radius = 0;
  432. pr_style.body.border.width = 1;
  433. lv_obj_t *kb = lv_kb_create(lv_disp_get_scr_act(NULL), NULL); /*Create a keyboard and apply the styles*/
  434. lv_kb_set_cursor_manage(kb, true);
  435. lv_kb_set_style(kb, LV_KB_STYLE_BG, &lv_style_transp_tight);
  436. lv_kb_set_style(kb, LV_KB_STYLE_BTN_REL, &rel_style);
  437. lv_kb_set_style(kb, LV_KB_STYLE_BTN_PR, &pr_style);
  438. lv_obj_t *ta = lv_ta_create(lv_disp_get_scr_act(NULL), NULL); /*Create a text area. The keyboard will write here*/
  439. lv_obj_align(ta, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
  440. lv_ta_set_text(ta, "");
  441. lv_kb_set_ta(kb, ta); /*Assign the text area to the keyboard*/
  442. lv_obj_t *label;
  443. lv_obj_t *btn;
  444. btn = lv_btn_create(lv_disp_get_scr_act(NULL), NULL);
  445. lv_obj_set_pos(btn, 10, 115); /*Set a position. It will be the animation's destination*/
  446. lv_obj_set_size(btn, 80, 40);
  447. label = lv_label_create(btn, NULL);
  448. lv_label_set_text(label, "ON");
  449. lv_obj_set_event_cb(btn, lvglBtnEventCb); /*set the callback function of the current button*/
  450. lv_group_t *group = Get_group();
  451. lv_group_add_obj(group ,kb); /*add to group*/
  452. lv_group_add_obj(group ,ta);
  453. lv_group_add_obj(group ,btn);
  454. #endif
  455. }
  456. static void ql_lvgl_demo_thread(void *param)
  457. {
  458. lvglContext_t *d = &gLvCtx;
  459. QlOSStatus err = 0;
  460. ql_event_t event;
  461. QL_LVGLDEMO_LOG("lvgl demo thread enter, param 0x%x", param);
  462. d->screen_on = true;
  463. d->keypad_pending = false;
  464. d->anim_inactive = false;
  465. d->screen_on_users = 0;
  466. d->inactive_timeout = CONFIG_LV_GUI_SCREEN_OFF_TIMEOUT;
  467. err=ql_rtos_task_get_current_ref(&d->thread);
  468. require_action(err, goto exit, "lvgl_demo_taskref get failed");
  469. err=ql_rtos_timer_create(&d->task_timer, d->thread, (lvgl_Callback_t)prvLvTaskHandler, NULL);
  470. require_action(err, goto exit, "lvgl_demo_timer created failed");
  471. if(ql_lcd_init() != QL_LCD_SUCCESS )
  472. {
  473. QL_LVGLDEMO_LOG("LCD init failed");
  474. goto exit;
  475. }
  476. lv_init();
  477. prvLvInitLcd();
  478. #ifdef QL_APP_FEATURE_KEYPAD
  479. prvLvInitKeypad();
  480. #endif
  481. lvGuiCreate_t create = (lvGuiCreate_t)param;
  482. if (create != NULL)
  483. {
  484. create();
  485. }
  486. err = ql_rtos_timer_start(d->task_timer, 10, 1);
  487. require_action(err, goto exit, "lvgl_demo_timer start failed");
  488. lv_disp_trig_activity(d->disp);
  489. while(1)
  490. {
  491. ql_event_try_wait(&event);
  492. if (event.id == QUEC_LVGL_QUIT_IND)
  493. break;
  494. if (d->screen_on && prvIsInactiveTimeout())
  495. {
  496. QL_LVGLDEMO_LOG("inactive timeout, screen off");
  497. lvGuiScreenOff();
  498. }
  499. }
  500. exit:
  501. QL_LVGLDEMO_LOG("lvgl demo thread exit, param 0x%x", param);
  502. ql_rtos_timer_delete(d->task_timer);
  503. d->task_timer = NULL;
  504. err = ql_rtos_task_delete(NULL);
  505. if(err != QL_OSI_SUCCESS)
  506. {
  507. QL_LVGLDEMO_LOG("lvgl task deleted failed");
  508. }
  509. }
  510. void ql_lvgl_app_init(void)
  511. {
  512. QlOSStatus err = 0;
  513. 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);
  514. if (err != QL_OSI_SUCCESS)
  515. {
  516. QL_LVGLDEMO_LOG("lvgl demo task created failed");
  517. }
  518. }