blob: 5c7b594d0176726cbd00ac71abee2ac3b694d79d [file] [log] [blame]
/******************************************************************************
*(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;
}