| /****************************************************************************** |
| *(C) Copyright 2014 Marvell International Ltd. |
| * All Rights Reserved |
| ******************************************************************************/ |
| /* ------------------------------------------------------------------------------------------------------------------- |
| * |
| * Filename: mgui.h |
| * |
| * Authors: Tomer Eliyahu |
| * |
| * Description: mgui |
| * |
| * HISTORY: |
| * Nov 23, 2014 - Initial Version |
| * |
| * Notes: |
| * |
| ******************************************************************************/ |
| #define _GNU_SOURCE |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <time.h> |
| #include <unistd.h> |
| #include <time.h> |
| #include <pthread.h> |
| #include <uci.h> |
| #include <uci_blob.h> |
| #include <dirent.h> |
| #include <libgen.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <linux/input.h> |
| #include "mgui_icons.h" |
| #include "mgui_utils.h" |
| #include "mgui_config.h" |
| #include "mgui_ubus.h" |
| #include "mgui_ril.h" |
| #include "mgui_charger.h" |
| #include "mgui_onkey.h" |
| #include "mgui_wifi.h" |
| #include "mgui_hawk.h" |
| #include "mgui_version.h" |
| #include "mgui.h" |
| #include <poll.h> |
| #include "gpio.h" |
| typedef union sigval sigval_t; |
| #define to_mgui_context(u) container_of(u, struct mgui_context, ubus_fd) |
| |
| #define FB_DEV "/dev/fb0" |
| |
| /****************************************************************************** |
| * Global variables |
| ******************************************************************************/ |
| extern struct mgui_background background; |
| extern struct mgui_icon *mgui_icons[]; |
| extern size_t mgui_num_icons; |
| extern struct mgui_icon *mgui_buttons[]; |
| extern size_t mgui_num_buttons; |
| |
| /****************************************************************************** |
| * Code |
| ******************************************************************************/ |
| |
| #ifdef MARVELL_ORIGIN_LCD |
| static void touch_handler(int event, void *params) |
| { |
| struct mgui_context *ctx = (struct mgui_context *)params; |
| struct itimerspec its; |
| |
| pthread_mutex_lock(&ctx->lock); |
| timer_gettime(ctx->idle_timer, &its); |
| pthread_mutex_unlock(&ctx->lock); |
| if (its.it_value.tv_sec || its.it_value.tv_nsec) { |
| /* timer is active, reschedule */ |
| its.it_value.tv_nsec = its.it_interval.tv_nsec; |
| its.it_value.tv_sec = its.it_interval.tv_sec; |
| timer_settime(ctx->idle_timer, 0, &its, NULL); |
| MGUI_DMSG("touch timer reschedulred\n"); |
| } |
| } |
| #endif |
| |
| /* top icons layout: |
| * ---------------------------------------------------------- |
| * | clk sd sms wifi gps rssi bat | |
| * |--------------------------------------------------------- |
| * | Cellular Operator |
| * | WIFI SSID |
| * | |
| * ... |
| * ... |
| * | _______________________ |
| * | | | |
| * | | EXIT BUTTON | |
| * | |_______________________| |
| * | |
| * ---------------------------------------------------------- |
| */ |
| |
| static int mgui_layout_top_left[] = { MGUI_CLOCK_ICON, }; |
| static int mgui_layout_top_right[] = { MGUI_BATTERY_ICON, MGUI_CELLULAR_ICON, |
| MGUI_GPS_ICON, MGUI_WIFI_ICON, |
| MGUI_SDCARD_ICON, MGUI_SIM_ICON, |
| MGUI_SMS_ICON }; |
| |
| enum e_layout_dir { |
| DIR_LEFT_TO_RIGHT, |
| DIR_RIGHT_TO_LEFT, |
| }; |
| |
| #define GET_SCALED_WIDTH(orig_w, orig_h, new_h) \ |
| ((orig_w) * (new_h)) / (orig_h) |
| |
| #define GET_SCALED_HEIGHT(orig_w, orig_h, new_w) \ |
| ((orig_h) * (new_w)) / (orig_w) |
| |
| static inline OBJECT_RECT layout_icons(struct mgui_context *ctx, |
| int *layout_table, |
| int layout_table_size, |
| int x, int y, int height, |
| enum e_layout_dir dir) |
| { |
| struct mgui_icon *icon; |
| OBJECT_RECT rect = {}; |
| int i, width; |
| |
| rect.lx = x; |
| rect.ly = y; |
| |
| for (i = 0; i < layout_table_size; i++) { |
| icon = mgui_icons[layout_table[i]]; |
| if (icon->type == MGUI_ICON_TYPE_TEXT) { |
| TextBoxSetup(icon->h, NULL, x, height, TA_LEFT, icon->text.color); |
| width = TextBoxGetWidth(icon->h) + 10; /* 10 pixel space beteen text icons */ |
| } else if (icon->type == MGUI_ICON_TYPE_IMAGE) { |
| ImageGetGeometry(icon->h, &rect); |
| width = GET_SCALED_WIDTH(rect.w, rect.h, height); |
| icon->image.rect.h = height; |
| icon->image.rect.w = width; |
| icon->image.rect.lx = x - width; |
| icon->image.rect.ly = y; |
| ImageSetup2(icon->h, icon->image.rect); |
| } else { |
| MGUI_EMSG("unsupported icon type %d in icons layout!\n", icon->type); |
| continue; |
| } |
| x = (dir == DIR_RIGHT_TO_LEFT) ? x - width : x + width; |
| rect.h = MAX(rect.h, height); |
| rect.w = MAX(rect.w, width); |
| } |
| |
| return rect; |
| } |
| |
| static inline enum hawk_req to_hawk_request(int id) |
| { |
| switch (id) { |
| case MGUI_FOTA_BUTTON: return HAWK_FOTA; |
| case MGUI_NODATA_ASSERT_BUTTON: return HAWK_PING; |
| case MGUI_RESET_BUTTON: return HAWK_RESET; |
| default: |
| MGUI_EMSG("id mismatch"); |
| case MGUI_KEEPALIVE_BUTTON: return HAWK_KEEP_ALIVE; |
| } |
| } |
| |
| static __attribute__((unused)) void button_handler(int event, void *data) |
| { |
| struct mgui_icon *icon = (struct mgui_icon *)data; |
| struct mgui_context *ctx; |
| struct mgui_event mevent; |
| int send_event = 0; |
| |
| MASSERT(icon); |
| ctx = icon->mgui; |
| MASSERT(ctx); |
| |
| switch (event) { |
| case DIRECTFB_EVT_PRESS: |
| MASSERT(!icon->button.status); |
| icon->button.status = 1; |
| break; |
| case DIRECTFB_EVT_RELEASE: |
| send_event = 1; |
| case DIRECTFB_EVT_RELEASE_OUT_OF_BOUNDS: |
| MASSERT(icon->button.status); |
| icon->button.status = 0; |
| break; |
| } |
| |
| ButtonSetFromArray(icon->h, icon->button.status); |
| ButtonSetup2(icon->h, icon->image.rect); |
| //MGUI_EMSG("event=%d, icon=%s, status=%d\n", event, icon->name, icon->button.status); |
| //MGUI_EMSG("BEFORE REFRESH\n"); |
| //mgui_screen_refresh(ctx); /* TODO: change to only refresh button! */ |
| //MGUI_EMSG("AFTER REFRESH\n"); |
| #if 1 |
| if (send_event) { |
| mevent.id = MGUI_BUTTON_EVENT; |
| mevent.data = icon->id; |
| write(ctx->pipes_fd[1], &mevent, sizeof(struct mgui_event)); |
| } |
| #endif |
| } |
| |
| static inline void setup_buttons(struct mgui_context *ctx) |
| { |
| struct mgui_icon *icon; |
| OBJECT_RECT rect = {}; |
| int i, lx, ly, dy; |
| |
| MASSERT(ctx); |
| |
| lx = background.info.buttons_x; |
| ly = background.info.buttons_y; |
| dy = background.info.buttons_space; |
| |
| for (i = 0; i < mgui_num_buttons; i++) { |
| icon = mgui_buttons[i]; |
| icon->button.click_params.cb = button_handler; |
| icon->button.click_params.cb_data = icon; |
| ButtonGetGeometry(icon->h, &rect); |
| icon->image.rect.lx = lx; |
| icon->image.rect.ly = ly; |
| icon->image.rect.h = rect.h; |
| icon->image.rect.w = rect.w; |
| ButtonSetup2(icon->h, icon->image.rect); |
| ButtonSetupOnClick(icon->h, &icon->button.click_params); |
| ly += rect.h + dy; |
| } |
| } |
| |
| static inline int init_layout(struct mgui_context *ctx) |
| { |
| OBJECT_RECT rect = {}; |
| |
| MASSERT(ctx); |
| |
| /* background Image */ |
| ImageGetGeometry(background.h, &rect); |
| ImageSetup2(background.h, rect); |
| |
| /* buttons */ |
| setup_buttons(ctx); |
| |
| #ifdef MARVELL_ORIGIN_LCD |
| /* touch handler */ |
| rect.h = ctx->screen.height; |
| rect.w = ctx->screen.width; |
| rect.lx = rect.ly = 0; |
| ctx->dfb_touch = DirectFbRegisterEventHandler(ctx->dfb, &rect, |
| DIRECTFB_EVT_TOUCH, |
| touch_handler, ctx); |
| MASSERT(ctx->dfb_touch); |
| #endif |
| |
| /* top icons left */ |
| layout_icons(ctx, mgui_layout_top_left, |
| ARRAY_SIZE(mgui_layout_top_left), 0, 1, |
| background.info.icons_height, DIR_LEFT_TO_RIGHT); |
| /* top icons right */ |
| layout_icons(ctx, mgui_layout_top_right, |
| ARRAY_SIZE(mgui_layout_top_right), |
| ctx->screen.width, 1, |
| background.info.icons_height, DIR_RIGHT_TO_LEFT); |
| |
| /* network tech is special - put on top of signal icon */ |
| mgui_icons[MGUI_NETWORK_TECH_ICON]->image.rect = mgui_icons[MGUI_CELLULAR_ICON]->image.rect; |
| ImageSetup2(mgui_icons[MGUI_NETWORK_TECH_ICON]->h, mgui_icons[MGUI_NETWORK_TECH_ICON]->image.rect); |
| |
| /* operator and ssid are drawn according to background info */ |
| TextBoxSetup(mgui_icons[MGUI_OPERATOR_ICON]->h, NULL, |
| background.info.operator_x, background.info.operator_y, TA_CENTER, |
| mgui_icons[MGUI_OPERATOR_ICON]->text.color); |
| TextBoxSetup(mgui_icons[MGUI_WIFI_SSID_ICON]->h, NULL, |
| background.info.wifi_ssid_x, background.info.wifi_ssid_y, TA_CENTER, |
| mgui_icons[MGUI_OPERATOR_ICON]->text.color); |
| |
| /* Version is in the bottom */ |
| TextBoxSetup(mgui_icons[MGUI_VERSION_ICON]->h, NULL, |
| ctx->screen.width / 2, ctx->screen.height - 3, TA_CENTER, |
| mgui_icons[MGUI_VERSION_ICON]->text.color); |
| |
| return 0; |
| } |
| |
| void mgui_reset_all_icons(struct mgui_context *ctx) |
| { |
| struct mgui_icon *ic; |
| int i; |
| |
| MASSERT(ctx); |
| |
| MGUI_IMSG("reset all icons\n"); |
| |
| /* reset all icons to default */ |
| for (i = 0; i < mgui_num_icons; i++) { |
| ic = mgui_icons[i]; |
| switch (ic->type) { |
| case MGUI_ICON_TYPE_IMAGE: |
| ic->image.current_key = ic->image.default_key; |
| ImageSetFromArray(ic->h, ic->image.current_key); |
| break; |
| case MGUI_ICON_TYPE_TEXT: |
| TextBoxSetText(ic->h, ic->text.default_string); |
| TextBoxSetColor(ic->h, ic->text.color); |
| break; |
| default: /* do nothing */ |
| break; |
| } |
| } |
| } |
| |
| |
| /** |
| * updates a given icon using it's val2key function. |
| * |
| * @param ctx mgui context |
| * @param i icon enum |
| * @param data opaque data used by the val2key function |
| * |
| * @return 0 if no change was necessary, 1 otherwise (indicates that screen refresh is needed) |
| */ |
| int mgui_update_icon(struct mgui_context *ctx, enum e_mgui_icons i, void *data) |
| { |
| struct mgui_icon *ic; |
| const char *text; |
| int key; |
| |
| MASSERT(ctx); |
| ic = mgui_icons[i]; |
| |
| switch (ic->type) { |
| case MGUI_ICON_TYPE_IMAGE: |
| key = ic->image.val_to_key(ic, data); |
| MGUI_DMSG("icon %s: current_key %d, new key=%d\n", ic->name, ic->image.current_key, key); |
| //if (ic->image.current_key != key) { |
| ic->image.current_key = key; |
| ImageSetFromArray(ic->h, key); |
| MGUI_IMSG("update icon %s data=%d\n", ic->name, data); |
| return 1; |
| //} |
| break; |
| case MGUI_ICON_TYPE_TEXT: |
| text = ic->text.val_to_string(ic, data); |
| MGUI_DMSG("icon %s: current text %s, new text %s\n", ic->name, TextBoxGetText(ic->h), text); |
| //if (TextBoxGetText(ic->h) && strcmp(TextBoxGetText(ic->h), text)) { |
| TextBoxSetText(ic->h, text); |
| TextBoxSetColor(ic->h, ic->text.color); |
| MGUI_IMSG("update icon %s data=%s color=ARGB=%08x\n", ic->name, text, ic->text.color); |
| return 1; |
| //} |
| break; |
| default: |
| MGUI_EMSG("unsupported icon type\n"); |
| break; |
| } |
| |
| return 0; /* no icon was changed */ |
| } |
| |
| static inline void pm_set_screen(struct mgui_context *ctx, int on) |
| { |
| GuiScreenSetPower(ctx->dfb, on); |
| mril_request_screen(ctx->ril, 0, on); |
| } |
| |
| #define TOUCH_RUNTIME_PM_PATH "/sys/bus/i2c/drivers/cyttsp-i2c/0-0024/power/control" |
| #define VERSION_PATH "/etc/mversion" |
| |
| static inline int pm_set_touch(struct mgui_context *ctx, int on) |
| { |
| int fd; |
| int ret = 0; |
| const char *mode[] = {"auto", "on"}; |
| |
| fd = open(TOUCH_RUNTIME_PM_PATH, O_RDWR); |
| if (fd < 0) { |
| MGUI_EMSG("Can't open touchscreen runtime control (%s)\n", TOUCH_RUNTIME_PM_PATH); |
| return -1; |
| } |
| |
| ret = write(fd, mode[!!on], strlen(mode[!!on])); |
| if (ret < 0) { |
| MGUI_EMSG("%s runtime suspend failed\n", on ? "disable" : "enable"); |
| goto out; |
| } |
| MGUI_IMSG("%s runtime suspend success\n", on ? "disable" : "enable"); |
| out: |
| close(fd); |
| return ret; |
| } |
| |
| |
| /** |
| * refresh the screen with new data |
| * |
| * Might sleep, do not hold mutex when calling this function! |
| * |
| * @param ctx mgui context |
| */ |
| void mgui_screen_refresh(struct mgui_context *ctx) |
| { |
| MASSERT(ctx); |
| |
| pthread_mutex_lock(&ctx->lock); |
| if (ctx->state != MGUI_STATE_OFF) { |
| MGUI_DMSG("refreshing screen\n"); |
| GuiRefreshScreenObjects(ctx->dfb); |
| } |
| pthread_mutex_unlock(&ctx->lock); |
| } |
| |
| static void clock_timer_handler(sigval_t sigval) |
| { |
| struct mgui_context *ctx = (struct mgui_context *)sigval.sival_ptr; |
| |
| mgui_update_icon(ctx, MGUI_CLOCK_ICON, NULL); |
| MGUI_DMSG("update mgui clock\n"); |
| /* TODO: change to only refresh clock! */ |
| mgui_screen_refresh(ctx); |
| } |
| |
| static void mgui_refresh_clock_wakeup(struct mgui_context *ctx) |
| { |
| mgui_update_icon(ctx, MGUI_CLOCK_ICON, NULL); |
| MGUI_DMSG("wakeup_refresh_clock update mgui clock\n"); |
| /* TODO: change to only refresh clock! */ |
| mgui_screen_refresh(ctx); |
| } |
| |
| static void idle_timer_handler(sigval_t sigval) |
| { |
| struct mgui_context *ctx = (struct mgui_context *)sigval.sival_ptr; |
| struct mgui_event e = { |
| .id = MGUI_IDLE_TIMEOUT_EVENT, |
| }; |
| |
| MGUI_DMSG("idle timeout reached\n"); |
| write(ctx->pipes_fd[1], &e, sizeof(struct mgui_event)); |
| } |
| |
| static void modules_timer_handler(sigval_t sigval) |
| { |
| struct mgui_context *ctx = (struct mgui_context *)sigval.sival_ptr; |
| struct mgui_event e = {.id = MGUI_MODULES_TIMEOUT_EVENT,}; |
| |
| MGUI_EMSG("modules timeout reached\n"); |
| write(ctx->pipes_fd[1], &e, sizeof(struct mgui_event)); |
| } |
| |
| static int mgui_timer_start(struct mgui_context *ctx, |
| timer_t timerid, |
| long long freq_nanosecs) |
| { |
| struct itimerspec its; |
| |
| its.it_value.tv_sec = freq_nanosecs / 1000000000; |
| its.it_value.tv_nsec = freq_nanosecs % 1000000000; |
| its.it_interval.tv_sec = its.it_value.tv_sec; |
| its.it_interval.tv_nsec = its.it_value.tv_nsec; |
| |
| pthread_mutex_lock(&ctx->lock); |
| if (timer_settime(timerid, 0, &its, NULL) == -1) { |
| pthread_mutex_unlock(&ctx->lock); |
| return -1; |
| } |
| pthread_mutex_unlock(&ctx->lock); |
| |
| return 0; |
| } |
| |
| static inline int mgui_timer_stop(struct mgui_context *ctx, timer_t timerid) |
| { |
| return mgui_timer_start(ctx, timerid, 0); |
| } |
| |
| static int mgui_timer_init(struct mgui_context *ctx, |
| timer_t *timerid, |
| void (*handler)(sigval_t)) |
| { |
| struct sigevent sev; |
| /* must clear, otherwise may cause timer_create crash */ |
| memset(&sev, 0, sizeof(sev)); |
| MASSERT(ctx); |
| |
| sev.sigev_notify = SIGEV_THREAD; |
| sev.sigev_notify_function = handler; |
| sev.sigev_value.sival_ptr = ctx; |
| if (timer_create(CLOCK_REALTIME, &sev, timerid) == -1) |
| return -1; |
| return 0; |
| } |
| |
| static struct uci_package * config_try_load(struct uci_context *ctx, char *path) |
| { |
| char *file = basename(path); |
| char *dir = dirname(path); |
| char *err; |
| struct uci_package *pkg; |
| |
| uci_set_confdir(ctx, dir); |
| MGUI_IMSG("attempting to load %s/%s\n", dir, file); |
| |
| if (uci_load(ctx, file, &pkg)) { |
| uci_get_errorstr(ctx, &err, file); |
| MGUI_EMSG("unable to load configuration (%s)\n", err); |
| |
| free(err); |
| return NULL; |
| } |
| |
| return pkg; |
| } |
| |
| enum { |
| MOUNT_UUID, |
| MOUNT_LABEL, |
| MOUNT_ENABLE, |
| MOUNT_TARGET, |
| MOUNT_DEVICE, |
| MOUNT_OPTIONS, |
| __MOUNT_MAX |
| }; |
| |
| static const struct blobmsg_policy mount_policy[__MOUNT_MAX] = { |
| [MOUNT_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING }, |
| [MOUNT_LABEL] = { .name = "label", .type = BLOBMSG_TYPE_STRING }, |
| [MOUNT_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING }, |
| [MOUNT_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING }, |
| [MOUNT_OPTIONS] = { .name = "options", .type = BLOBMSG_TYPE_STRING }, |
| [MOUNT_ENABLE] = { .name = "enabled", .type = BLOBMSG_TYPE_INT32 }, |
| }; |
| |
| static const struct uci_blob_param_list mount_attr_list = { |
| .n_params = __MOUNT_MAX, |
| .params = mount_policy, |
| }; |
| |
| static struct blob_buf b; |
| |
| static int mgui_detect_sdcard(char *cfg) |
| { |
| struct uci_context *ctx = uci_alloc_context(); |
| struct uci_package *pkg = NULL; |
| struct uci_element *e; |
| char path[64]; |
| |
| if (cfg) { |
| snprintf(path, sizeof(path), "%s/upper/etc/config/fstab", cfg); |
| pkg = config_try_load(ctx, path); |
| |
| if (!pkg) { |
| snprintf(path, sizeof(path), "%s/etc/config/fstab", cfg); |
| pkg = config_try_load(ctx, path); |
| } |
| } |
| |
| if (!pkg) { |
| snprintf(path, sizeof(path), "/etc/config/fstab"); |
| pkg = config_try_load(ctx, path); |
| } |
| |
| if (!pkg) { |
| MGUI_EMSG("no usable configuration\n"); |
| return -1; |
| } |
| |
| uci_foreach_element(&pkg->sections, e) { |
| struct uci_section *s = uci_to_section(e); |
| |
| if (!strcmp(s->type, "mount")) { |
| struct blob_attr *tb[__MOUNT_MAX] = { 0 }; |
| |
| blob_buf_init(&b, 0); |
| uci_to_blob(&b, s, &mount_attr_list); |
| blobmsg_parse(mount_policy, __MOUNT_MAX, tb, blob_data(b.head), blob_len(b.head)); |
| if (!tb[MOUNT_LABEL] && !tb[MOUNT_UUID] && !tb[MOUNT_DEVICE]) |
| return -1; |
| |
| if (tb[MOUNT_ENABLE] && !blobmsg_get_u32(tb[MOUNT_ENABLE])) |
| return -1; |
| return 1; |
| } |
| } |
| return -1; |
| } |
| |
| #if 0 |
| static void mgui_get_version(struct mgui_context *ctx) |
| { |
| FILE *fp; |
| char *line = NULL; |
| size_t len = 0; |
| |
| fp = fopen(VERSION_PATH, "r"); |
| if (fp == NULL) { |
| MGUI_EMSG("Can't open version file (%s)\n", VERSION_PATH); |
| return NULL; |
| } |
| |
| getline(&line, &len, fp); |
| |
| return line; |
| } |
| #endif |
| |
| static void deinit_icons(struct mgui_context *ctx, struct mgui_icon **icons, size_t num_icons) |
| { |
| int i; |
| |
| for (i = 0; i < num_icons; i++) { |
| if (icons[i]->type == MGUI_ICON_TYPE_IMAGE) |
| ImageDeinit(icons[i]->h); |
| else if (icons[i]->type == MGUI_ICON_TYPE_TEXT) |
| TextBoxDeinit(icons[i]->h); |
| else if (icons[i]->type == MGUI_ICON_TYPE_BUTTON) |
| ButtonDeinit(icons[i]->h); |
| } |
| } |
| |
| #define BAT_CAPACITY_FILE "/sys/class/power_supply/battery/capacity" |
| #define BAT_PRESENT_FILE "/sys/class/power_supply/battery/present" |
| #define BAT_STATUS_FILE "/sys/class/power_supply/battery/status" |
| |
| static int read_file(char *file_name, char *buf) |
| { |
| int fd = -1; |
| int ret; |
| char str_temp[20]; |
| |
| memset(str_temp, 0, sizeof(str_temp)); |
| fd = open(file_name, O_RDONLY); |
| if (fd < 0){ |
| MGUI_EMSG("open %s failed\n", file_name); |
| return -1; |
| } |
| ret = read(fd, str_temp, sizeof(str_temp)); |
| if(ret < 0) { |
| MGUI_EMSG("[%s] file read error\n", __FUNCTION__); |
| close(fd); |
| return -1; |
| } |
| memcpy(buf, str_temp, sizeof(str_temp)); |
| close(fd); |
| |
| return 0; |
| } |
| |
| |
| static int prepare_charger_key(void) |
| { |
| int preset, capacity; |
| int ret; |
| char buf[20]; |
| int charging = 0; |
| //char cmd_buf[100]; |
| |
| memset(buf, 0, sizeof(buf)); |
| ret = read_file(BAT_PRESENT_FILE, buf); |
| if(ret < 0) |
| return -1; |
| preset = atoi(buf); |
| if(preset == 0) |
| return STATUS_UNKNOWN; |
| |
| memset(buf, 0, sizeof(buf)); |
| ret = read_file(BAT_STATUS_FILE, buf); |
| if(ret < 0) |
| return -1; |
| if(strcmp(buf, "Charging") == 0) |
| charging = 1; |
| |
| memset(buf, 0, sizeof(buf)); |
| ret = read_file(BAT_CAPACITY_FILE, buf); |
| if(ret < 0) |
| return -1; |
| capacity = atoi(buf); |
| |
| //memset(cmd_buf, 0, sizeof(cmd_buf)); |
| //snprintf(cmd_buf, sizeof(cmd_buf), "echo \"preset = %d, charging = %d, cap = %d\" > /tmp/xiehj.log", |
| // preset, charging, capacity); |
| //system(cmd_buf); |
| |
| if (capacity == 100) |
| return 100 + charging; |
| if (capacity >= 80) |
| return 80 + charging; |
| if (capacity >= 60) |
| return 60 + charging; |
| if (capacity >= 50) |
| return 50 + charging; |
| if (capacity >= 30) |
| return 30 + charging; |
| if (capacity >= 20) |
| return 20 + charging; |
| return 0 + charging; |
| } |
| |
| |
| |
| static void init_icons(struct mgui_context *ctx, struct mgui_icon **icons, size_t num_icons, int text_height) |
| { |
| struct mgui_icon *ic; |
| int i; |
| |
| for (i = 0; i < num_icons; i++) { |
| ic = icons[i]; |
| ic->id = i; |
| ic->mgui = ctx; |
| if (ic->type == MGUI_ICON_TYPE_IMAGE) { |
| if (strcmp(ic->name, "bluetooth") == 0) |
| continue; |
| ic->h = ImageInit(ctx->dfb); |
| if(strcmp(ic->name, "battery")) |
| ic->image.current_key = ic->image.val_to_key(ic, NULL); |
| else{ |
| ic->image.current_key = prepare_charger_key(); |
| } |
| ImageSetArray(ic->h, ic->image.arr, ic->image.arr_size); |
| ImageSetFromArray(ic->h, ic->image.current_key); |
| } else if (ic->type == MGUI_ICON_TYPE_TEXT) { |
| ic->h = TextBoxInit(ctx->dfb, text_height, -1, |
| ic->text.font_path); |
| TextBoxSetText(ic->h, ic->text.val_to_string(ic, NULL)); |
| TextBoxSetColor(ic->h, ic->text.color); |
| } else if (ic->type == MGUI_ICON_TYPE_BUTTON) { |
| ic->h = ButtonInit(ctx->dfb); |
| ic->image.current_key = ic->image.val_to_key(ic, NULL); |
| ButtonSetArray(ic->h, ic->image.arr, ic->image.arr_size); |
| ButtonSetFromArray(ic->h, ic->image.current_key); |
| } |
| } |
| } |
| |
| /* use F_DL key as qrcode key */ |
| #define QRCODE_KEY_DEV "/dev/input/event1" |
| static void *mgui_qrcode_key_detect(void *context) |
| { |
| int fd, rd, i; |
| struct input_event ev[64]; |
| struct mgui_context *ctx = (struct mgui_context *)context; |
| fd = open(QRCODE_KEY_DEV, O_RDONLY); |
| if (fd < 0) { |
| MGUI_EMSG("open %s error!!!", QRCODE_KEY_DEV); |
| pthread_exit(NULL); |
| } |
| |
| while (1) { |
| rd = read(fd, ev, sizeof(struct input_event) * 64); |
| for (i = 0; i < rd / sizeof(struct input_event); i++) { |
| if (ev[i].type == EV_KEY && ev[i].code == KEY_MENU /* 139 */) { |
| MGUI_DMSG("qrcode key %s\n", ev[i].value ? "pressed" : "released"); |
| if (ev[i].value) { |
| /* pressed */ |
| char str[256]; |
| char *encryption = ctx->wifi->status.encryption; |
| if (encryption && strstr(encryption, "psk")) |
| encryption = "WPA"; |
| memset(str, 0, sizeof(str)); |
| sprintf(str, "WIFI:T:%s;S:%s;P:%s;;", |
| encryption, |
| ctx->wifi->status.ssid, |
| ctx->wifi->status.key); |
| lvgl_show_qrcode(str); |
| } |
| } |
| } |
| } |
| |
| pthread_exit(NULL); |
| } |
| |
| static void mgui_gpio_key_init(void *ctx) |
| { |
| pthread_t id; |
| pthread_create(&id, NULL, (void *)mgui_qrcode_key_detect, ctx); |
| } |
| |
| struct mgui_context *mgui_init(int argc, char *argv[]) |
| { |
| struct mgui_context *ctx; |
| int tmp; |
| if(access(FB_DEV, F_OK) != 0) { |
| MGUI_EMSG("no %s, quit\n", FB_DEV); |
| return NULL; |
| } |
| |
| ctx = malloc(sizeof(*ctx)); |
| if (!ctx) |
| return NULL; |
| |
| memset(ctx, 0, sizeof(*ctx)); |
| |
| /* init pipe */ |
| if (pipe(ctx->pipes_fd)) { |
| MGUI_EMSG("pipe failed with error %s\n", |
| strerror(errno)); |
| goto out_pipe; |
| } |
| |
| if (pthread_mutex_init(&ctx->lock, NULL) != 0) { |
| MGUI_EMSG("mutex init failed\n"); |
| goto out_mutex; |
| } |
| |
| if (mgui_timer_init(ctx, &ctx->clock_timer, clock_timer_handler) != 0) { |
| MGUI_EMSG("timer init failed\n"); |
| goto out_clock_timer; |
| } |
| |
| if (mgui_timer_init(ctx, &ctx->idle_timer, idle_timer_handler) != 0) { |
| MGUI_EMSG("timer init failed\n"); |
| goto out_idle_timer; |
| } |
| |
| if (mgui_timer_init(ctx, &ctx->modules_timer, modules_timer_handler) != 0) { |
| MGUI_EMSG("timer init failed\n"); |
| goto out_modules_timer; |
| } |
| |
| /* init gui interface */ |
| ctx->dfb = GuiInit(); |
| if (!ctx->dfb) { |
| MGUI_EMSG("gui init failed\n"); |
| goto out_gui_init; |
| } |
| GuiScreenClear(ctx->dfb, BACKGROUND_COLOR); |
| background.h = ImageInit(ctx->dfb); |
| if (!background.h) { |
| MGUI_EMSG("background image init failed\n"); |
| goto out_bg_image_init; |
| } |
| |
| GuiGetScreenDim(ctx->dfb, &ctx->screen); |
| if (ctx->screen.width == 240 && ctx->screen.height == 320) |
| background.path = IMAGEDIR"/background_lcd_240x320.png"; |
| ImageSetFromPath(background.h, background.path); |
| |
| /* init icons and buttons */ |
| init_icons(ctx, mgui_icons, mgui_num_icons, background.info.icons_height-3); |
| #ifdef MARVELL_ORIGIN_LCD |
| init_icons(ctx, mgui_buttons, mgui_num_buttons, 0); |
| #endif |
| init_layout(ctx); |
| |
| /* detect SD card*/ |
| tmp = mgui_detect_sdcard(NULL); |
| mgui_update_icon(ctx, MGUI_SDCARD_ICON, (void *)tmp); |
| |
| ctx->onkey = mgui_onkey_init(ctx); |
| if (!ctx->onkey) |
| goto out_onkey_init; |
| |
| ctx->ubus = mgui_ubus_init(); |
| if (!ctx->ubus) |
| goto out_ubus_init; |
| |
| ctx->charger = mgui_charger_init(ctx); |
| if (!ctx->charger) |
| MGUI_IMSG("charger service not ready\n"); |
| |
| ctx->ril = mgui_ril_init(ctx); |
| if (!ctx->ril) |
| MGUI_IMSG("ril service not ready\n"); |
| |
| ctx->wifi = mgui_wifi_init(ctx); |
| if (!ctx->wifi) |
| MGUI_IMSG("wifi service not ready\n"); |
| #ifdef MARVELL_ORIGIN_LCD |
| ctx->hawk = mgui_hawk_init(ctx); |
| if (!ctx->hawk) |
| MGUI_IMSG("hawk service not ready\n"); |
| #endif |
| ctx->ver = mgui_version_init(ctx); |
| if (!ctx->ver) |
| MGUI_IMSG("version service not ready\n"); |
| |
| mgui_gpio_key_init(ctx); |
| return ctx; |
| |
| out_ubus_init: |
| mgui_onkey_exit(ctx->onkey); |
| out_onkey_init: |
| deinit_icons(ctx, mgui_icons, mgui_num_icons); |
| deinit_icons(ctx, mgui_buttons, mgui_num_buttons); |
| #ifdef MARVELL_ORIGIN_LCD |
| DirectFbUnregisterEventHandler(ctx->dfb, ctx->dfb_touch); |
| #endif |
| ImageDeinit(background.h); |
| out_bg_image_init: |
| GuiDeinit(ctx->dfb); |
| out_gui_init: |
| timer_delete(ctx->modules_timer); |
| out_modules_timer: |
| timer_delete(ctx->idle_timer); |
| out_idle_timer: |
| timer_delete(ctx->clock_timer); |
| out_clock_timer: |
| pthread_mutex_destroy(&ctx->lock); |
| out_mutex: |
| close(ctx->pipes_fd[0]); |
| close(ctx->pipes_fd[1]); |
| out_pipe: |
| free(ctx); |
| return NULL; |
| } |
| |
| int mgui_exit(struct mgui_context *ctx) |
| { |
| MASSERT(ctx); |
| |
| #ifdef MARVELL_ORIGIN_LCD |
| if (ctx->hawk != NULL) |
| mgui_hawk_exit(ctx->hawk); |
| #endif |
| if (ctx->wifi != NULL) |
| mgui_wifi_exit(ctx->wifi); |
| if (ctx->ril != NULL) |
| mgui_ril_exit(ctx->ril); |
| if (ctx->charger != NULL) |
| mgui_charger_exit(ctx->charger); |
| if (ctx->ubus != NULL) |
| mgui_ubus_exit(ctx->ubus); |
| if (ctx->onkey != NULL) |
| mgui_onkey_exit(ctx->onkey); |
| if (ctx->ver != NULL) |
| mgui_version_exit(ctx->ver); |
| |
| MGUI_EMSG("mgui_init deinit_icons"); |
| deinit_icons(ctx, mgui_icons, mgui_num_icons); |
| #ifdef MARVELL_ORIGIN_LCD |
| deinit_icons(ctx, mgui_buttons, mgui_num_buttons); |
| DirectFbUnregisterEventHandler(ctx->dfb, ctx->dfb_touch); |
| #endif |
| ImageDeinit(background.h); |
| GuiDeinit(ctx->dfb); |
| |
| timer_delete(ctx->idle_timer); |
| timer_delete(ctx->clock_timer); |
| timer_delete(ctx->modules_timer); |
| pthread_mutex_destroy(&ctx->lock); |
| |
| close(ctx->pipes_fd[0]); |
| close(ctx->pipes_fd[1]); |
| free(ctx); |
| return 0; |
| } |
| |
| static void mgui_wakeup(struct mgui_context *ctx) |
| { |
| enum e_mgui_state state; |
| |
| pthread_mutex_lock(&ctx->lock); |
| state = ctx->state; |
| pthread_mutex_unlock(&ctx->lock); |
| |
| switch (state) { |
| case MGUI_STATE_ON: |
| MGUI_EMSG("already awake!!!\n"); |
| break; |
| case MGUI_STATE_OFF: |
| ctx->state = MGUI_STATE_ON; |
| pm_set_screen(ctx, 1); |
| #ifdef MARVELL_ORIGIN_LCD |
| pm_set_touch(ctx, 1); |
| #endif |
| mgui_timer_start(ctx, ctx->clock_timer, CLOCK_TIMER_FREQ_NANOSECS); |
| mgui_timer_start(ctx, ctx->idle_timer, IDLE_TIMER_FREQ_NANOSECS); |
| mgui_timer_start(ctx, ctx->modules_timer, MODULES_TIMER_FREQ_NANOSECS); |
| //mgui_ril_wakeup(ctx->ril); |
| mgui_refresh_clock_wakeup(ctx); |
| break; |
| default: |
| MGUI_EMSG("unknown state!!!\n"); |
| break; |
| } |
| } |
| |
| void mgui_cp_assert_wakeup(struct mgui_context *ctx) |
| { |
| enum e_mgui_state state; |
| |
| pthread_mutex_lock(&ctx->lock); |
| state = ctx->state; |
| pthread_mutex_unlock(&ctx->lock); |
| |
| switch (state) { |
| case MGUI_STATE_ON: |
| MGUI_EMSG("already awake!!!\n"); |
| break; |
| case MGUI_STATE_OFF: |
| ctx->state = MGUI_STATE_ON; |
| pm_set_screen(ctx, 1); |
| #ifdef MARVELL_ORIGIN_LCD |
| pm_set_touch(ctx, 1); |
| #endif |
| mgui_timer_start(ctx, ctx->clock_timer, CLOCK_TIMER_FREQ_NANOSECS); |
| //cp assert not start idle timer |
| //mgui_timer_start(ctx, ctx->idle_timer, IDLE_TIMER_FREQ_NANOSECS); |
| mgui_timer_start(ctx, ctx->modules_timer, MODULES_TIMER_FREQ_NANOSECS); |
| //mgui_ril_wakeup(ctx->ril); |
| mgui_refresh_clock_wakeup(ctx); |
| break; |
| default: |
| MGUI_EMSG("unknown state!!!\n"); |
| break; |
| } |
| } |
| |
| |
| static void mgui_sleep(struct mgui_context *ctx) |
| { |
| enum e_mgui_state state; |
| |
| pthread_mutex_lock(&ctx->lock); |
| state = ctx->state; |
| pthread_mutex_unlock(&ctx->lock); |
| |
| switch (state) { |
| case MGUI_STATE_ON: |
| ctx->state = MGUI_STATE_OFF; |
| pm_set_screen(ctx, 0); |
| #ifdef MARVELL_ORIGIN_LCD |
| pm_set_touch(ctx, 0); |
| #endif |
| mgui_timer_stop(ctx, ctx->clock_timer); |
| mgui_timer_stop(ctx, ctx->idle_timer); |
| mgui_timer_stop(ctx, ctx->modules_timer); |
| //mgui_ril_sleep(ctx->ril); |
| break; |
| case MGUI_STATE_OFF: |
| MGUI_EMSG("already sleeping!!!\n"); |
| break; |
| default: |
| MGUI_EMSG("unknown state!!!\n"); |
| break; |
| } |
| } |
| |
| static void mgui_probe_modules(struct mgui_context *ctx) |
| { |
| int need_resched = 0; |
| |
| if ((ctx->charger == NULL) && |
| (ctx->charger = mgui_charger_init(ctx)) == NULL) { |
| MGUI_IMSG("charger service still not ready\n"); |
| need_resched = 1; |
| } |
| |
| if ((ctx->ril == NULL) && |
| (ctx->ril = mgui_ril_init(ctx)) == NULL) { |
| MGUI_IMSG("ril service still not ready\n"); |
| need_resched = 1; |
| } |
| |
| if ((ctx->wifi == NULL) && |
| (ctx->wifi = mgui_wifi_init(ctx)) == NULL) { |
| MGUI_IMSG("wifi service still not ready\n"); |
| need_resched = 1; |
| } |
| |
| #ifdef MARVELL_ORIGIN_LCD |
| if ((ctx->hawk == NULL) && |
| (ctx->hawk = mgui_hawk_init(ctx)) == NULL) { |
| MGUI_IMSG("hawk service still not ready\n"); |
| need_resched = 1; |
| } |
| #endif |
| |
| if ((ctx->ver == NULL) && |
| (ctx->ver = mgui_version_init(ctx)) == NULL) { |
| MGUI_IMSG("version service still not ready\n"); |
| need_resched = 1; |
| } |
| MGUI_EMSG("service ready need_resched = %d\n", need_resched); |
| |
| if (!need_resched) { |
| MGUI_EMSG("service ready stop modules timer\n"); |
| mgui_timer_stop(ctx, ctx->modules_timer); |
| } |
| } |
| |
| static void mgui_event_handle(struct uloop_fd *u, unsigned int events) |
| { |
| struct mgui_context *ctx = to_mgui_context(u); |
| struct mgui_event e; |
| |
| MASSERT(ctx); |
| |
| read(u->fd, &e, sizeof(struct mgui_event)); |
| |
| switch (e.id) { |
| case MGUI_EXIT_EVENT: |
| MGUI_IMSG("Exit event received\n"); |
| uloop_end(); |
| break; |
| case MGUI_ONKEY_EVENT: |
| MGUI_IMSG("onkey event received\n"); |
| if (ctx->state == MGUI_STATE_ON) |
| mgui_sleep(ctx); |
| else |
| mgui_wakeup(ctx); |
| return; |
| case MGUI_IDLE_TIMEOUT_EVENT: |
| MGUI_IMSG("idle timeout event received\n"); |
| if (ctx->state == MGUI_STATE_ON) |
| mgui_sleep(ctx); |
| return; |
| case MGUI_MODULES_TIMEOUT_EVENT: |
| MGUI_IMSG("modules timeout event received\n"); |
| mgui_probe_modules(ctx); |
| return; |
| #ifdef MARVELL_ORIGIN_LCD |
| case MGUI_BUTTON_EVENT: |
| MGUI_IMSG("button clicked\n"); |
| mgui_hawk_request(ctx->hawk, to_hawk_request(e.data)); |
| return; |
| #endif |
| default: |
| MGUI_EMSG("Unknown event!!!\n"); |
| break; |
| } |
| } |
| |
| int mgui_run(struct mgui_context *ctx) |
| { |
| MASSERT(ctx); |
| |
| /* refresh the screen for the first time */ |
| pm_set_screen(ctx, 1); |
| |
| #ifdef MARVELL_ORIGIN_LCD |
| pm_set_touch(ctx, 1); |
| #endif |
| |
| mgui_screen_refresh(ctx); |
| |
| /* start timers */ |
| mgui_timer_start(ctx, ctx->clock_timer, CLOCK_TIMER_FREQ_NANOSECS); |
| mgui_timer_start(ctx, ctx->idle_timer, IDLE_TIMER_FREQ_NANOSECS); |
| mgui_timer_start(ctx, ctx->modules_timer, MODULES_TIMER_FREQ_NANOSECS); |
| |
| /* setup uloop and run main loop to get indications */ |
| memset(&ctx->ubus_fd, 0, sizeof(ctx->ubus_fd)); |
| ctx->ubus_fd.cb = mgui_event_handle; |
| ctx->ubus_fd.fd = ctx->pipes_fd[0]; |
| mgui_ubus_fd_add(&ctx->ubus_fd); |
| mgui_ubus_uloop_run(); |
| |
| pm_set_screen(ctx, 0); /* make sure screen is off */ |
| |
| #ifdef MARVELL_ORIGIN_LCD |
| pm_set_touch(ctx, 0); |
| #endif |
| |
| /* stop timers */ |
| mgui_timer_stop(ctx, ctx->clock_timer); |
| mgui_timer_stop(ctx, ctx->idle_timer); |
| mgui_timer_stop(ctx, ctx->modules_timer); |
| |
| return 0; |
| } |