blob: 5c7b594d0176726cbd00ac71abee2ac3b694d79d [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/******************************************************************************
2*(C) Copyright 2014 Marvell International Ltd.
3* All Rights Reserved
4******************************************************************************/
5/* -------------------------------------------------------------------------------------------------------------------
6 *
7 * Filename: mgui.h
8 *
9 * Authors: Tomer Eliyahu
10 *
11 * Description: mgui
12 *
13 * HISTORY:
14 * Nov 23, 2014 - Initial Version
15 *
16 * Notes:
17 *
18 ******************************************************************************/
19#define _GNU_SOURCE
20#include <stdlib.h>
21#include <stdio.h>
22#include <time.h>
23#include <unistd.h>
24#include <time.h>
25#include <pthread.h>
26#include <uci.h>
27#include <uci_blob.h>
28#include <dirent.h>
29#include <libgen.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <linux/input.h>
34#include "mgui_icons.h"
35#include "mgui_utils.h"
36#include "mgui_config.h"
37#include "mgui_ubus.h"
38#include "mgui_ril.h"
39#include "mgui_charger.h"
40#include "mgui_onkey.h"
41#include "mgui_wifi.h"
42#include "mgui_hawk.h"
43#include "mgui_version.h"
44#include "mgui.h"
45#include <poll.h>
46#include "gpio.h"
47typedef union sigval sigval_t;
48#define to_mgui_context(u) container_of(u, struct mgui_context, ubus_fd)
49
50#define FB_DEV "/dev/fb0"
51
52/******************************************************************************
53 * Global variables
54 ******************************************************************************/
55extern struct mgui_background background;
56extern struct mgui_icon *mgui_icons[];
57extern size_t mgui_num_icons;
58extern struct mgui_icon *mgui_buttons[];
59extern size_t mgui_num_buttons;
60
61/******************************************************************************
62 * Code
63 ******************************************************************************/
64
65#ifdef MARVELL_ORIGIN_LCD
66static void touch_handler(int event, void *params)
67{
68 struct mgui_context *ctx = (struct mgui_context *)params;
69 struct itimerspec its;
70
71 pthread_mutex_lock(&ctx->lock);
72 timer_gettime(ctx->idle_timer, &its);
73 pthread_mutex_unlock(&ctx->lock);
74 if (its.it_value.tv_sec || its.it_value.tv_nsec) {
75 /* timer is active, reschedule */
76 its.it_value.tv_nsec = its.it_interval.tv_nsec;
77 its.it_value.tv_sec = its.it_interval.tv_sec;
78 timer_settime(ctx->idle_timer, 0, &its, NULL);
79 MGUI_DMSG("touch timer reschedulred\n");
80 }
81}
82#endif
83
84/* top icons layout:
85 * ----------------------------------------------------------
86 * | clk sd sms wifi gps rssi bat |
87 * |---------------------------------------------------------
88 * | Cellular Operator
89 * | WIFI SSID
90 * |
91 * ...
92 * ...
93 * | _______________________
94 * | | |
95 * | | EXIT BUTTON |
96 * | |_______________________|
97 * |
98 * ----------------------------------------------------------
99 */
100
101static int mgui_layout_top_left[] = { MGUI_CLOCK_ICON, };
102static int mgui_layout_top_right[] = { MGUI_BATTERY_ICON, MGUI_CELLULAR_ICON,
103 MGUI_GPS_ICON, MGUI_WIFI_ICON,
104 MGUI_SDCARD_ICON, MGUI_SIM_ICON,
105 MGUI_SMS_ICON };
106
107enum e_layout_dir {
108 DIR_LEFT_TO_RIGHT,
109 DIR_RIGHT_TO_LEFT,
110};
111
112#define GET_SCALED_WIDTH(orig_w, orig_h, new_h) \
113 ((orig_w) * (new_h)) / (orig_h)
114
115#define GET_SCALED_HEIGHT(orig_w, orig_h, new_w) \
116 ((orig_h) * (new_w)) / (orig_w)
117
118static inline OBJECT_RECT layout_icons(struct mgui_context *ctx,
119 int *layout_table,
120 int layout_table_size,
121 int x, int y, int height,
122 enum e_layout_dir dir)
123{
124 struct mgui_icon *icon;
125 OBJECT_RECT rect = {};
126 int i, width;
127
128 rect.lx = x;
129 rect.ly = y;
130
131 for (i = 0; i < layout_table_size; i++) {
132 icon = mgui_icons[layout_table[i]];
133 if (icon->type == MGUI_ICON_TYPE_TEXT) {
134 TextBoxSetup(icon->h, NULL, x, height, TA_LEFT, icon->text.color);
135 width = TextBoxGetWidth(icon->h) + 10; /* 10 pixel space beteen text icons */
136 } else if (icon->type == MGUI_ICON_TYPE_IMAGE) {
137 ImageGetGeometry(icon->h, &rect);
138 width = GET_SCALED_WIDTH(rect.w, rect.h, height);
139 icon->image.rect.h = height;
140 icon->image.rect.w = width;
141 icon->image.rect.lx = x - width;
142 icon->image.rect.ly = y;
143 ImageSetup2(icon->h, icon->image.rect);
144 } else {
145 MGUI_EMSG("unsupported icon type %d in icons layout!\n", icon->type);
146 continue;
147 }
148 x = (dir == DIR_RIGHT_TO_LEFT) ? x - width : x + width;
149 rect.h = MAX(rect.h, height);
150 rect.w = MAX(rect.w, width);
151 }
152
153 return rect;
154}
155
156static inline enum hawk_req to_hawk_request(int id)
157{
158 switch (id) {
159 case MGUI_FOTA_BUTTON: return HAWK_FOTA;
160 case MGUI_NODATA_ASSERT_BUTTON: return HAWK_PING;
161 case MGUI_RESET_BUTTON: return HAWK_RESET;
162 default:
163 MGUI_EMSG("id mismatch");
164 case MGUI_KEEPALIVE_BUTTON: return HAWK_KEEP_ALIVE;
165 }
166}
167
168static __attribute__((unused)) void button_handler(int event, void *data)
169{
170 struct mgui_icon *icon = (struct mgui_icon *)data;
171 struct mgui_context *ctx;
172 struct mgui_event mevent;
173 int send_event = 0;
174
175 MASSERT(icon);
176 ctx = icon->mgui;
177 MASSERT(ctx);
178
179 switch (event) {
180 case DIRECTFB_EVT_PRESS:
181 MASSERT(!icon->button.status);
182 icon->button.status = 1;
183 break;
184 case DIRECTFB_EVT_RELEASE:
185 send_event = 1;
186 case DIRECTFB_EVT_RELEASE_OUT_OF_BOUNDS:
187 MASSERT(icon->button.status);
188 icon->button.status = 0;
189 break;
190 }
191
192 ButtonSetFromArray(icon->h, icon->button.status);
193 ButtonSetup2(icon->h, icon->image.rect);
194 //MGUI_EMSG("event=%d, icon=%s, status=%d\n", event, icon->name, icon->button.status);
195 //MGUI_EMSG("BEFORE REFRESH\n");
196 //mgui_screen_refresh(ctx); /* TODO: change to only refresh button! */
197 //MGUI_EMSG("AFTER REFRESH\n");
198#if 1
199 if (send_event) {
200 mevent.id = MGUI_BUTTON_EVENT;
201 mevent.data = icon->id;
202 write(ctx->pipes_fd[1], &mevent, sizeof(struct mgui_event));
203 }
204#endif
205}
206
207static inline void setup_buttons(struct mgui_context *ctx)
208{
209 struct mgui_icon *icon;
210 OBJECT_RECT rect = {};
211 int i, lx, ly, dy;
212
213 MASSERT(ctx);
214
215 lx = background.info.buttons_x;
216 ly = background.info.buttons_y;
217 dy = background.info.buttons_space;
218
219 for (i = 0; i < mgui_num_buttons; i++) {
220 icon = mgui_buttons[i];
221 icon->button.click_params.cb = button_handler;
222 icon->button.click_params.cb_data = icon;
223 ButtonGetGeometry(icon->h, &rect);
224 icon->image.rect.lx = lx;
225 icon->image.rect.ly = ly;
226 icon->image.rect.h = rect.h;
227 icon->image.rect.w = rect.w;
228 ButtonSetup2(icon->h, icon->image.rect);
229 ButtonSetupOnClick(icon->h, &icon->button.click_params);
230 ly += rect.h + dy;
231 }
232}
233
234static inline int init_layout(struct mgui_context *ctx)
235{
236 OBJECT_RECT rect = {};
237
238 MASSERT(ctx);
239
240 /* background Image */
241 ImageGetGeometry(background.h, &rect);
242 ImageSetup2(background.h, rect);
243
244 /* buttons */
245 setup_buttons(ctx);
246
247#ifdef MARVELL_ORIGIN_LCD
248 /* touch handler */
249 rect.h = ctx->screen.height;
250 rect.w = ctx->screen.width;
251 rect.lx = rect.ly = 0;
252 ctx->dfb_touch = DirectFbRegisterEventHandler(ctx->dfb, &rect,
253 DIRECTFB_EVT_TOUCH,
254 touch_handler, ctx);
255 MASSERT(ctx->dfb_touch);
256#endif
257
258 /* top icons left */
259 layout_icons(ctx, mgui_layout_top_left,
260 ARRAY_SIZE(mgui_layout_top_left), 0, 1,
261 background.info.icons_height, DIR_LEFT_TO_RIGHT);
262 /* top icons right */
263 layout_icons(ctx, mgui_layout_top_right,
264 ARRAY_SIZE(mgui_layout_top_right),
265 ctx->screen.width, 1,
266 background.info.icons_height, DIR_RIGHT_TO_LEFT);
267
268 /* network tech is special - put on top of signal icon */
269 mgui_icons[MGUI_NETWORK_TECH_ICON]->image.rect = mgui_icons[MGUI_CELLULAR_ICON]->image.rect;
270 ImageSetup2(mgui_icons[MGUI_NETWORK_TECH_ICON]->h, mgui_icons[MGUI_NETWORK_TECH_ICON]->image.rect);
271
272 /* operator and ssid are drawn according to background info */
273 TextBoxSetup(mgui_icons[MGUI_OPERATOR_ICON]->h, NULL,
274 background.info.operator_x, background.info.operator_y, TA_CENTER,
275 mgui_icons[MGUI_OPERATOR_ICON]->text.color);
276 TextBoxSetup(mgui_icons[MGUI_WIFI_SSID_ICON]->h, NULL,
277 background.info.wifi_ssid_x, background.info.wifi_ssid_y, TA_CENTER,
278 mgui_icons[MGUI_OPERATOR_ICON]->text.color);
279
280 /* Version is in the bottom */
281 TextBoxSetup(mgui_icons[MGUI_VERSION_ICON]->h, NULL,
282 ctx->screen.width / 2, ctx->screen.height - 3, TA_CENTER,
283 mgui_icons[MGUI_VERSION_ICON]->text.color);
284
285 return 0;
286}
287
288void mgui_reset_all_icons(struct mgui_context *ctx)
289{
290 struct mgui_icon *ic;
291 int i;
292
293 MASSERT(ctx);
294
295 MGUI_IMSG("reset all icons\n");
296
297 /* reset all icons to default */
298 for (i = 0; i < mgui_num_icons; i++) {
299 ic = mgui_icons[i];
300 switch (ic->type) {
301 case MGUI_ICON_TYPE_IMAGE:
302 ic->image.current_key = ic->image.default_key;
303 ImageSetFromArray(ic->h, ic->image.current_key);
304 break;
305 case MGUI_ICON_TYPE_TEXT:
306 TextBoxSetText(ic->h, ic->text.default_string);
307 TextBoxSetColor(ic->h, ic->text.color);
308 break;
309 default: /* do nothing */
310 break;
311 }
312 }
313}
314
315
316/**
317 * updates a given icon using it's val2key function.
318 *
319 * @param ctx mgui context
320 * @param i icon enum
321 * @param data opaque data used by the val2key function
322 *
323 * @return 0 if no change was necessary, 1 otherwise (indicates that screen refresh is needed)
324 */
325int mgui_update_icon(struct mgui_context *ctx, enum e_mgui_icons i, void *data)
326{
327 struct mgui_icon *ic;
328 const char *text;
329 int key;
330
331 MASSERT(ctx);
332 ic = mgui_icons[i];
333
334 switch (ic->type) {
335 case MGUI_ICON_TYPE_IMAGE:
336 key = ic->image.val_to_key(ic, data);
337 MGUI_DMSG("icon %s: current_key %d, new key=%d\n", ic->name, ic->image.current_key, key);
338 //if (ic->image.current_key != key) {
339 ic->image.current_key = key;
340 ImageSetFromArray(ic->h, key);
341 MGUI_IMSG("update icon %s data=%d\n", ic->name, data);
342 return 1;
343 //}
344 break;
345 case MGUI_ICON_TYPE_TEXT:
346 text = ic->text.val_to_string(ic, data);
347 MGUI_DMSG("icon %s: current text %s, new text %s\n", ic->name, TextBoxGetText(ic->h), text);
348 //if (TextBoxGetText(ic->h) && strcmp(TextBoxGetText(ic->h), text)) {
349 TextBoxSetText(ic->h, text);
350 TextBoxSetColor(ic->h, ic->text.color);
351 MGUI_IMSG("update icon %s data=%s color=ARGB=%08x\n", ic->name, text, ic->text.color);
352 return 1;
353 //}
354 break;
355 default:
356 MGUI_EMSG("unsupported icon type\n");
357 break;
358 }
359
360 return 0; /* no icon was changed */
361}
362
363static inline void pm_set_screen(struct mgui_context *ctx, int on)
364{
365 GuiScreenSetPower(ctx->dfb, on);
366 mril_request_screen(ctx->ril, 0, on);
367}
368
369#define TOUCH_RUNTIME_PM_PATH "/sys/bus/i2c/drivers/cyttsp-i2c/0-0024/power/control"
370#define VERSION_PATH "/etc/mversion"
371
372static inline int pm_set_touch(struct mgui_context *ctx, int on)
373{
374 int fd;
375 int ret = 0;
376 const char *mode[] = {"auto", "on"};
377
378 fd = open(TOUCH_RUNTIME_PM_PATH, O_RDWR);
379 if (fd < 0) {
380 MGUI_EMSG("Can't open touchscreen runtime control (%s)\n", TOUCH_RUNTIME_PM_PATH);
381 return -1;
382 }
383
384 ret = write(fd, mode[!!on], strlen(mode[!!on]));
385 if (ret < 0) {
386 MGUI_EMSG("%s runtime suspend failed\n", on ? "disable" : "enable");
387 goto out;
388 }
389 MGUI_IMSG("%s runtime suspend success\n", on ? "disable" : "enable");
390out:
391 close(fd);
392 return ret;
393}
394
395
396/**
397 * refresh the screen with new data
398 *
399 * Might sleep, do not hold mutex when calling this function!
400 *
401 * @param ctx mgui context
402 */
403void mgui_screen_refresh(struct mgui_context *ctx)
404{
405 MASSERT(ctx);
406
407 pthread_mutex_lock(&ctx->lock);
408 if (ctx->state != MGUI_STATE_OFF) {
409 MGUI_DMSG("refreshing screen\n");
410 GuiRefreshScreenObjects(ctx->dfb);
411 }
412 pthread_mutex_unlock(&ctx->lock);
413}
414
415static void clock_timer_handler(sigval_t sigval)
416{
417 struct mgui_context *ctx = (struct mgui_context *)sigval.sival_ptr;
418
419 mgui_update_icon(ctx, MGUI_CLOCK_ICON, NULL);
420 MGUI_DMSG("update mgui clock\n");
421 /* TODO: change to only refresh clock! */
422 mgui_screen_refresh(ctx);
423}
424
425static void mgui_refresh_clock_wakeup(struct mgui_context *ctx)
426{
427 mgui_update_icon(ctx, MGUI_CLOCK_ICON, NULL);
428 MGUI_DMSG("wakeup_refresh_clock update mgui clock\n");
429 /* TODO: change to only refresh clock! */
430 mgui_screen_refresh(ctx);
431}
432
433static void idle_timer_handler(sigval_t sigval)
434{
435 struct mgui_context *ctx = (struct mgui_context *)sigval.sival_ptr;
436 struct mgui_event e = {
437 .id = MGUI_IDLE_TIMEOUT_EVENT,
438 };
439
440 MGUI_DMSG("idle timeout reached\n");
441 write(ctx->pipes_fd[1], &e, sizeof(struct mgui_event));
442}
443
444static void modules_timer_handler(sigval_t sigval)
445{
446 struct mgui_context *ctx = (struct mgui_context *)sigval.sival_ptr;
447 struct mgui_event e = {.id = MGUI_MODULES_TIMEOUT_EVENT,};
448
449 MGUI_EMSG("modules timeout reached\n");
450 write(ctx->pipes_fd[1], &e, sizeof(struct mgui_event));
451}
452
453static int mgui_timer_start(struct mgui_context *ctx,
454 timer_t timerid,
455 long long freq_nanosecs)
456{
457 struct itimerspec its;
458
459 its.it_value.tv_sec = freq_nanosecs / 1000000000;
460 its.it_value.tv_nsec = freq_nanosecs % 1000000000;
461 its.it_interval.tv_sec = its.it_value.tv_sec;
462 its.it_interval.tv_nsec = its.it_value.tv_nsec;
463
464 pthread_mutex_lock(&ctx->lock);
465 if (timer_settime(timerid, 0, &its, NULL) == -1) {
466 pthread_mutex_unlock(&ctx->lock);
467 return -1;
468 }
469 pthread_mutex_unlock(&ctx->lock);
470
471 return 0;
472}
473
474static inline int mgui_timer_stop(struct mgui_context *ctx, timer_t timerid)
475{
476 return mgui_timer_start(ctx, timerid, 0);
477}
478
479static int mgui_timer_init(struct mgui_context *ctx,
480 timer_t *timerid,
481 void (*handler)(sigval_t))
482{
483 struct sigevent sev;
484 /* must clear, otherwise may cause timer_create crash */
485 memset(&sev, 0, sizeof(sev));
486 MASSERT(ctx);
487
488 sev.sigev_notify = SIGEV_THREAD;
489 sev.sigev_notify_function = handler;
490 sev.sigev_value.sival_ptr = ctx;
491 if (timer_create(CLOCK_REALTIME, &sev, timerid) == -1)
492 return -1;
493 return 0;
494}
495
496static struct uci_package * config_try_load(struct uci_context *ctx, char *path)
497{
498 char *file = basename(path);
499 char *dir = dirname(path);
500 char *err;
501 struct uci_package *pkg;
502
503 uci_set_confdir(ctx, dir);
504 MGUI_IMSG("attempting to load %s/%s\n", dir, file);
505
506 if (uci_load(ctx, file, &pkg)) {
507 uci_get_errorstr(ctx, &err, file);
508 MGUI_EMSG("unable to load configuration (%s)\n", err);
509
510 free(err);
511 return NULL;
512 }
513
514 return pkg;
515}
516
517enum {
518 MOUNT_UUID,
519 MOUNT_LABEL,
520 MOUNT_ENABLE,
521 MOUNT_TARGET,
522 MOUNT_DEVICE,
523 MOUNT_OPTIONS,
524 __MOUNT_MAX
525};
526
527static const struct blobmsg_policy mount_policy[__MOUNT_MAX] = {
528 [MOUNT_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING },
529 [MOUNT_LABEL] = { .name = "label", .type = BLOBMSG_TYPE_STRING },
530 [MOUNT_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
531 [MOUNT_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING },
532 [MOUNT_OPTIONS] = { .name = "options", .type = BLOBMSG_TYPE_STRING },
533 [MOUNT_ENABLE] = { .name = "enabled", .type = BLOBMSG_TYPE_INT32 },
534};
535
536static const struct uci_blob_param_list mount_attr_list = {
537 .n_params = __MOUNT_MAX,
538 .params = mount_policy,
539};
540
541static struct blob_buf b;
542
543static int mgui_detect_sdcard(char *cfg)
544{
545 struct uci_context *ctx = uci_alloc_context();
546 struct uci_package *pkg = NULL;
547 struct uci_element *e;
548 char path[64];
549
550 if (cfg) {
551 snprintf(path, sizeof(path), "%s/upper/etc/config/fstab", cfg);
552 pkg = config_try_load(ctx, path);
553
554 if (!pkg) {
555 snprintf(path, sizeof(path), "%s/etc/config/fstab", cfg);
556 pkg = config_try_load(ctx, path);
557 }
558 }
559
560 if (!pkg) {
561 snprintf(path, sizeof(path), "/etc/config/fstab");
562 pkg = config_try_load(ctx, path);
563 }
564
565 if (!pkg) {
566 MGUI_EMSG("no usable configuration\n");
567 return -1;
568 }
569
570 uci_foreach_element(&pkg->sections, e) {
571 struct uci_section *s = uci_to_section(e);
572
573 if (!strcmp(s->type, "mount")) {
574 struct blob_attr *tb[__MOUNT_MAX] = { 0 };
575
576 blob_buf_init(&b, 0);
577 uci_to_blob(&b, s, &mount_attr_list);
578 blobmsg_parse(mount_policy, __MOUNT_MAX, tb, blob_data(b.head), blob_len(b.head));
579 if (!tb[MOUNT_LABEL] && !tb[MOUNT_UUID] && !tb[MOUNT_DEVICE])
580 return -1;
581
582 if (tb[MOUNT_ENABLE] && !blobmsg_get_u32(tb[MOUNT_ENABLE]))
583 return -1;
584 return 1;
585 }
586 }
587 return -1;
588}
589
590#if 0
591static void mgui_get_version(struct mgui_context *ctx)
592{
593 FILE *fp;
594 char *line = NULL;
595 size_t len = 0;
596
597 fp = fopen(VERSION_PATH, "r");
598 if (fp == NULL) {
599 MGUI_EMSG("Can't open version file (%s)\n", VERSION_PATH);
600 return NULL;
601 }
602
603 getline(&line, &len, fp);
604
605 return line;
606}
607#endif
608
609static void deinit_icons(struct mgui_context *ctx, struct mgui_icon **icons, size_t num_icons)
610{
611 int i;
612
613 for (i = 0; i < num_icons; i++) {
614 if (icons[i]->type == MGUI_ICON_TYPE_IMAGE)
615 ImageDeinit(icons[i]->h);
616 else if (icons[i]->type == MGUI_ICON_TYPE_TEXT)
617 TextBoxDeinit(icons[i]->h);
618 else if (icons[i]->type == MGUI_ICON_TYPE_BUTTON)
619 ButtonDeinit(icons[i]->h);
620 }
621}
622
623#define BAT_CAPACITY_FILE "/sys/class/power_supply/battery/capacity"
624#define BAT_PRESENT_FILE "/sys/class/power_supply/battery/present"
625#define BAT_STATUS_FILE "/sys/class/power_supply/battery/status"
626
627static int read_file(char *file_name, char *buf)
628{
629 int fd = -1;
630 int ret;
631 char str_temp[20];
632
633 memset(str_temp, 0, sizeof(str_temp));
634 fd = open(file_name, O_RDONLY);
635 if (fd < 0){
636 MGUI_EMSG("open %s failed\n", file_name);
637 return -1;
638 }
639 ret = read(fd, str_temp, sizeof(str_temp));
640 if(ret < 0) {
641 MGUI_EMSG("[%s] file read error\n", __FUNCTION__);
642 close(fd);
643 return -1;
644 }
645 memcpy(buf, str_temp, sizeof(str_temp));
646 close(fd);
647
648 return 0;
649}
650
651
652static int prepare_charger_key(void)
653{
654 int preset, capacity;
655 int ret;
656 char buf[20];
657 int charging = 0;
658 //char cmd_buf[100];
659
660 memset(buf, 0, sizeof(buf));
661 ret = read_file(BAT_PRESENT_FILE, buf);
662 if(ret < 0)
663 return -1;
664 preset = atoi(buf);
665 if(preset == 0)
666 return STATUS_UNKNOWN;
667
668 memset(buf, 0, sizeof(buf));
669 ret = read_file(BAT_STATUS_FILE, buf);
670 if(ret < 0)
671 return -1;
672 if(strcmp(buf, "Charging") == 0)
673 charging = 1;
674
675 memset(buf, 0, sizeof(buf));
676 ret = read_file(BAT_CAPACITY_FILE, buf);
677 if(ret < 0)
678 return -1;
679 capacity = atoi(buf);
680
681 //memset(cmd_buf, 0, sizeof(cmd_buf));
682 //snprintf(cmd_buf, sizeof(cmd_buf), "echo \"preset = %d, charging = %d, cap = %d\" > /tmp/xiehj.log",
683 // preset, charging, capacity);
684 //system(cmd_buf);
685
686 if (capacity == 100)
687 return 100 + charging;
688 if (capacity >= 80)
689 return 80 + charging;
690 if (capacity >= 60)
691 return 60 + charging;
692 if (capacity >= 50)
693 return 50 + charging;
694 if (capacity >= 30)
695 return 30 + charging;
696 if (capacity >= 20)
697 return 20 + charging;
698 return 0 + charging;
699}
700
701
702
703static void init_icons(struct mgui_context *ctx, struct mgui_icon **icons, size_t num_icons, int text_height)
704{
705 struct mgui_icon *ic;
706 int i;
707
708 for (i = 0; i < num_icons; i++) {
709 ic = icons[i];
710 ic->id = i;
711 ic->mgui = ctx;
712 if (ic->type == MGUI_ICON_TYPE_IMAGE) {
713 if (strcmp(ic->name, "bluetooth") == 0)
714 continue;
715 ic->h = ImageInit(ctx->dfb);
716 if(strcmp(ic->name, "battery"))
717 ic->image.current_key = ic->image.val_to_key(ic, NULL);
718 else{
719 ic->image.current_key = prepare_charger_key();
720 }
721 ImageSetArray(ic->h, ic->image.arr, ic->image.arr_size);
722 ImageSetFromArray(ic->h, ic->image.current_key);
723 } else if (ic->type == MGUI_ICON_TYPE_TEXT) {
724 ic->h = TextBoxInit(ctx->dfb, text_height, -1,
725 ic->text.font_path);
726 TextBoxSetText(ic->h, ic->text.val_to_string(ic, NULL));
727 TextBoxSetColor(ic->h, ic->text.color);
728 } else if (ic->type == MGUI_ICON_TYPE_BUTTON) {
729 ic->h = ButtonInit(ctx->dfb);
730 ic->image.current_key = ic->image.val_to_key(ic, NULL);
731 ButtonSetArray(ic->h, ic->image.arr, ic->image.arr_size);
732 ButtonSetFromArray(ic->h, ic->image.current_key);
733 }
734 }
735}
736
737/* use F_DL key as qrcode key */
738#define QRCODE_KEY_DEV "/dev/input/event1"
739static void *mgui_qrcode_key_detect(void *context)
740{
741 int fd, rd, i;
742 struct input_event ev[64];
743 struct mgui_context *ctx = (struct mgui_context *)context;
744 fd = open(QRCODE_KEY_DEV, O_RDONLY);
745 if (fd < 0) {
746 MGUI_EMSG("open %s error!!!", QRCODE_KEY_DEV);
747 pthread_exit(NULL);
748 }
749
750 while (1) {
751 rd = read(fd, ev, sizeof(struct input_event) * 64);
752 for (i = 0; i < rd / sizeof(struct input_event); i++) {
753 if (ev[i].type == EV_KEY && ev[i].code == KEY_MENU /* 139 */) {
754 MGUI_DMSG("qrcode key %s\n", ev[i].value ? "pressed" : "released");
755 if (ev[i].value) {
756 /* pressed */
757 char str[256];
758 char *encryption = ctx->wifi->status.encryption;
759 if (encryption && strstr(encryption, "psk"))
760 encryption = "WPA";
761 memset(str, 0, sizeof(str));
762 sprintf(str, "WIFI:T:%s;S:%s;P:%s;;",
763 encryption,
764 ctx->wifi->status.ssid,
765 ctx->wifi->status.key);
766 lvgl_show_qrcode(str);
767 }
768 }
769 }
770 }
771
772 pthread_exit(NULL);
773}
774
775static void mgui_gpio_key_init(void *ctx)
776{
777 pthread_t id;
778 pthread_create(&id, NULL, (void *)mgui_qrcode_key_detect, ctx);
779}
780
781struct mgui_context *mgui_init(int argc, char *argv[])
782{
783 struct mgui_context *ctx;
784 int tmp;
785 if(access(FB_DEV, F_OK) != 0) {
786 MGUI_EMSG("no %s, quit\n", FB_DEV);
787 return NULL;
788 }
789
790 ctx = malloc(sizeof(*ctx));
791 if (!ctx)
792 return NULL;
793
794 memset(ctx, 0, sizeof(*ctx));
795
796 /* init pipe */
797 if (pipe(ctx->pipes_fd)) {
798 MGUI_EMSG("pipe failed with error %s\n",
799 strerror(errno));
800 goto out_pipe;
801 }
802
803 if (pthread_mutex_init(&ctx->lock, NULL) != 0) {
804 MGUI_EMSG("mutex init failed\n");
805 goto out_mutex;
806 }
807
808 if (mgui_timer_init(ctx, &ctx->clock_timer, clock_timer_handler) != 0) {
809 MGUI_EMSG("timer init failed\n");
810 goto out_clock_timer;
811 }
812
813 if (mgui_timer_init(ctx, &ctx->idle_timer, idle_timer_handler) != 0) {
814 MGUI_EMSG("timer init failed\n");
815 goto out_idle_timer;
816 }
817
818 if (mgui_timer_init(ctx, &ctx->modules_timer, modules_timer_handler) != 0) {
819 MGUI_EMSG("timer init failed\n");
820 goto out_modules_timer;
821 }
822
823 /* init gui interface */
824 ctx->dfb = GuiInit();
825 if (!ctx->dfb) {
826 MGUI_EMSG("gui init failed\n");
827 goto out_gui_init;
828 }
829 GuiScreenClear(ctx->dfb, BACKGROUND_COLOR);
830 background.h = ImageInit(ctx->dfb);
831 if (!background.h) {
832 MGUI_EMSG("background image init failed\n");
833 goto out_bg_image_init;
834 }
835
836 GuiGetScreenDim(ctx->dfb, &ctx->screen);
837 if (ctx->screen.width == 240 && ctx->screen.height == 320)
838 background.path = IMAGEDIR"/background_lcd_240x320.png";
839 ImageSetFromPath(background.h, background.path);
840
841 /* init icons and buttons */
842 init_icons(ctx, mgui_icons, mgui_num_icons, background.info.icons_height-3);
843#ifdef MARVELL_ORIGIN_LCD
844 init_icons(ctx, mgui_buttons, mgui_num_buttons, 0);
845#endif
846 init_layout(ctx);
847
848 /* detect SD card*/
849 tmp = mgui_detect_sdcard(NULL);
850 mgui_update_icon(ctx, MGUI_SDCARD_ICON, (void *)tmp);
851
852 ctx->onkey = mgui_onkey_init(ctx);
853 if (!ctx->onkey)
854 goto out_onkey_init;
855
856 ctx->ubus = mgui_ubus_init();
857 if (!ctx->ubus)
858 goto out_ubus_init;
859
860 ctx->charger = mgui_charger_init(ctx);
861 if (!ctx->charger)
862 MGUI_IMSG("charger service not ready\n");
863
864 ctx->ril = mgui_ril_init(ctx);
865 if (!ctx->ril)
866 MGUI_IMSG("ril service not ready\n");
867
868 ctx->wifi = mgui_wifi_init(ctx);
869 if (!ctx->wifi)
870 MGUI_IMSG("wifi service not ready\n");
871#ifdef MARVELL_ORIGIN_LCD
872 ctx->hawk = mgui_hawk_init(ctx);
873 if (!ctx->hawk)
874 MGUI_IMSG("hawk service not ready\n");
875#endif
876 ctx->ver = mgui_version_init(ctx);
877 if (!ctx->ver)
878 MGUI_IMSG("version service not ready\n");
879
880 mgui_gpio_key_init(ctx);
881 return ctx;
882
883out_ubus_init:
884 mgui_onkey_exit(ctx->onkey);
885out_onkey_init:
886 deinit_icons(ctx, mgui_icons, mgui_num_icons);
887 deinit_icons(ctx, mgui_buttons, mgui_num_buttons);
888#ifdef MARVELL_ORIGIN_LCD
889 DirectFbUnregisterEventHandler(ctx->dfb, ctx->dfb_touch);
890#endif
891 ImageDeinit(background.h);
892out_bg_image_init:
893 GuiDeinit(ctx->dfb);
894out_gui_init:
895 timer_delete(ctx->modules_timer);
896out_modules_timer:
897 timer_delete(ctx->idle_timer);
898out_idle_timer:
899 timer_delete(ctx->clock_timer);
900out_clock_timer:
901 pthread_mutex_destroy(&ctx->lock);
902out_mutex:
903 close(ctx->pipes_fd[0]);
904 close(ctx->pipes_fd[1]);
905out_pipe:
906 free(ctx);
907 return NULL;
908}
909
910int mgui_exit(struct mgui_context *ctx)
911{
912 MASSERT(ctx);
913
914#ifdef MARVELL_ORIGIN_LCD
915 if (ctx->hawk != NULL)
916 mgui_hawk_exit(ctx->hawk);
917#endif
918 if (ctx->wifi != NULL)
919 mgui_wifi_exit(ctx->wifi);
920 if (ctx->ril != NULL)
921 mgui_ril_exit(ctx->ril);
922 if (ctx->charger != NULL)
923 mgui_charger_exit(ctx->charger);
924 if (ctx->ubus != NULL)
925 mgui_ubus_exit(ctx->ubus);
926 if (ctx->onkey != NULL)
927 mgui_onkey_exit(ctx->onkey);
928 if (ctx->ver != NULL)
929 mgui_version_exit(ctx->ver);
930
931 MGUI_EMSG("mgui_init deinit_icons");
932 deinit_icons(ctx, mgui_icons, mgui_num_icons);
933#ifdef MARVELL_ORIGIN_LCD
934 deinit_icons(ctx, mgui_buttons, mgui_num_buttons);
935 DirectFbUnregisterEventHandler(ctx->dfb, ctx->dfb_touch);
936#endif
937 ImageDeinit(background.h);
938 GuiDeinit(ctx->dfb);
939
940 timer_delete(ctx->idle_timer);
941 timer_delete(ctx->clock_timer);
942 timer_delete(ctx->modules_timer);
943 pthread_mutex_destroy(&ctx->lock);
944
945 close(ctx->pipes_fd[0]);
946 close(ctx->pipes_fd[1]);
947 free(ctx);
948 return 0;
949}
950
951static void mgui_wakeup(struct mgui_context *ctx)
952{
953 enum e_mgui_state state;
954
955 pthread_mutex_lock(&ctx->lock);
956 state = ctx->state;
957 pthread_mutex_unlock(&ctx->lock);
958
959 switch (state) {
960 case MGUI_STATE_ON:
961 MGUI_EMSG("already awake!!!\n");
962 break;
963 case MGUI_STATE_OFF:
964 ctx->state = MGUI_STATE_ON;
965 pm_set_screen(ctx, 1);
966#ifdef MARVELL_ORIGIN_LCD
967 pm_set_touch(ctx, 1);
968#endif
969 mgui_timer_start(ctx, ctx->clock_timer, CLOCK_TIMER_FREQ_NANOSECS);
970 mgui_timer_start(ctx, ctx->idle_timer, IDLE_TIMER_FREQ_NANOSECS);
971 mgui_timer_start(ctx, ctx->modules_timer, MODULES_TIMER_FREQ_NANOSECS);
972 //mgui_ril_wakeup(ctx->ril);
973 mgui_refresh_clock_wakeup(ctx);
974 break;
975 default:
976 MGUI_EMSG("unknown state!!!\n");
977 break;
978 }
979}
980
981void mgui_cp_assert_wakeup(struct mgui_context *ctx)
982{
983 enum e_mgui_state state;
984
985 pthread_mutex_lock(&ctx->lock);
986 state = ctx->state;
987 pthread_mutex_unlock(&ctx->lock);
988
989 switch (state) {
990 case MGUI_STATE_ON:
991 MGUI_EMSG("already awake!!!\n");
992 break;
993 case MGUI_STATE_OFF:
994 ctx->state = MGUI_STATE_ON;
995 pm_set_screen(ctx, 1);
996#ifdef MARVELL_ORIGIN_LCD
997 pm_set_touch(ctx, 1);
998#endif
999 mgui_timer_start(ctx, ctx->clock_timer, CLOCK_TIMER_FREQ_NANOSECS);
1000 //cp assert not start idle timer
1001 //mgui_timer_start(ctx, ctx->idle_timer, IDLE_TIMER_FREQ_NANOSECS);
1002 mgui_timer_start(ctx, ctx->modules_timer, MODULES_TIMER_FREQ_NANOSECS);
1003 //mgui_ril_wakeup(ctx->ril);
1004 mgui_refresh_clock_wakeup(ctx);
1005 break;
1006 default:
1007 MGUI_EMSG("unknown state!!!\n");
1008 break;
1009 }
1010}
1011
1012
1013static void mgui_sleep(struct mgui_context *ctx)
1014{
1015 enum e_mgui_state state;
1016
1017 pthread_mutex_lock(&ctx->lock);
1018 state = ctx->state;
1019 pthread_mutex_unlock(&ctx->lock);
1020
1021 switch (state) {
1022 case MGUI_STATE_ON:
1023 ctx->state = MGUI_STATE_OFF;
1024 pm_set_screen(ctx, 0);
1025#ifdef MARVELL_ORIGIN_LCD
1026 pm_set_touch(ctx, 0);
1027#endif
1028 mgui_timer_stop(ctx, ctx->clock_timer);
1029 mgui_timer_stop(ctx, ctx->idle_timer);
1030 mgui_timer_stop(ctx, ctx->modules_timer);
1031 //mgui_ril_sleep(ctx->ril);
1032 break;
1033 case MGUI_STATE_OFF:
1034 MGUI_EMSG("already sleeping!!!\n");
1035 break;
1036 default:
1037 MGUI_EMSG("unknown state!!!\n");
1038 break;
1039 }
1040}
1041
1042static void mgui_probe_modules(struct mgui_context *ctx)
1043{
1044 int need_resched = 0;
1045
1046 if ((ctx->charger == NULL) &&
1047 (ctx->charger = mgui_charger_init(ctx)) == NULL) {
1048 MGUI_IMSG("charger service still not ready\n");
1049 need_resched = 1;
1050 }
1051
1052 if ((ctx->ril == NULL) &&
1053 (ctx->ril = mgui_ril_init(ctx)) == NULL) {
1054 MGUI_IMSG("ril service still not ready\n");
1055 need_resched = 1;
1056 }
1057
1058 if ((ctx->wifi == NULL) &&
1059 (ctx->wifi = mgui_wifi_init(ctx)) == NULL) {
1060 MGUI_IMSG("wifi service still not ready\n");
1061 need_resched = 1;
1062 }
1063
1064#ifdef MARVELL_ORIGIN_LCD
1065 if ((ctx->hawk == NULL) &&
1066 (ctx->hawk = mgui_hawk_init(ctx)) == NULL) {
1067 MGUI_IMSG("hawk service still not ready\n");
1068 need_resched = 1;
1069 }
1070#endif
1071
1072 if ((ctx->ver == NULL) &&
1073 (ctx->ver = mgui_version_init(ctx)) == NULL) {
1074 MGUI_IMSG("version service still not ready\n");
1075 need_resched = 1;
1076 }
1077 MGUI_EMSG("service ready need_resched = %d\n", need_resched);
1078
1079 if (!need_resched) {
1080 MGUI_EMSG("service ready stop modules timer\n");
1081 mgui_timer_stop(ctx, ctx->modules_timer);
1082 }
1083}
1084
1085static void mgui_event_handle(struct uloop_fd *u, unsigned int events)
1086{
1087 struct mgui_context *ctx = to_mgui_context(u);
1088 struct mgui_event e;
1089
1090 MASSERT(ctx);
1091
1092 read(u->fd, &e, sizeof(struct mgui_event));
1093
1094 switch (e.id) {
1095 case MGUI_EXIT_EVENT:
1096 MGUI_IMSG("Exit event received\n");
1097 uloop_end();
1098 break;
1099 case MGUI_ONKEY_EVENT:
1100 MGUI_IMSG("onkey event received\n");
1101 if (ctx->state == MGUI_STATE_ON)
1102 mgui_sleep(ctx);
1103 else
1104 mgui_wakeup(ctx);
1105 return;
1106 case MGUI_IDLE_TIMEOUT_EVENT:
1107 MGUI_IMSG("idle timeout event received\n");
1108 if (ctx->state == MGUI_STATE_ON)
1109 mgui_sleep(ctx);
1110 return;
1111 case MGUI_MODULES_TIMEOUT_EVENT:
1112 MGUI_IMSG("modules timeout event received\n");
1113 mgui_probe_modules(ctx);
1114 return;
1115#ifdef MARVELL_ORIGIN_LCD
1116 case MGUI_BUTTON_EVENT:
1117 MGUI_IMSG("button clicked\n");
1118 mgui_hawk_request(ctx->hawk, to_hawk_request(e.data));
1119 return;
1120#endif
1121 default:
1122 MGUI_EMSG("Unknown event!!!\n");
1123 break;
1124 }
1125}
1126
1127int mgui_run(struct mgui_context *ctx)
1128{
1129 MASSERT(ctx);
1130
1131 /* refresh the screen for the first time */
1132 pm_set_screen(ctx, 1);
1133
1134#ifdef MARVELL_ORIGIN_LCD
1135 pm_set_touch(ctx, 1);
1136#endif
1137
1138 mgui_screen_refresh(ctx);
1139
1140 /* start timers */
1141 mgui_timer_start(ctx, ctx->clock_timer, CLOCK_TIMER_FREQ_NANOSECS);
1142 mgui_timer_start(ctx, ctx->idle_timer, IDLE_TIMER_FREQ_NANOSECS);
1143 mgui_timer_start(ctx, ctx->modules_timer, MODULES_TIMER_FREQ_NANOSECS);
1144
1145 /* setup uloop and run main loop to get indications */
1146 memset(&ctx->ubus_fd, 0, sizeof(ctx->ubus_fd));
1147 ctx->ubus_fd.cb = mgui_event_handle;
1148 ctx->ubus_fd.fd = ctx->pipes_fd[0];
1149 mgui_ubus_fd_add(&ctx->ubus_fd);
1150 mgui_ubus_uloop_run();
1151
1152 pm_set_screen(ctx, 0); /* make sure screen is off */
1153
1154#ifdef MARVELL_ORIGIN_LCD
1155 pm_set_touch(ctx, 0);
1156#endif
1157
1158 /* stop timers */
1159 mgui_timer_stop(ctx, ctx->clock_timer);
1160 mgui_timer_stop(ctx, ctx->idle_timer);
1161 mgui_timer_stop(ctx, ctx->modules_timer);
1162
1163 return 0;
1164}