4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
23 #include <device-node.h>
27 #include "deviced/dd-led.h"
29 #include "core/common.h"
30 #include "core/edbus-handler.h"
31 #include "core/devices.h"
32 #include "core/device-notifier.h"
33 #include "core/device-handler.h"
34 #include "display/core.h"
37 #define BOOT_ANIMATION_FINISHED 1
39 #define LED_VALUE(high, low) (((high)<<16)|((low)&0xFFFF))
41 #define BG_COLOR 0x00000000
42 #define GET_ALPHA(x) (((x)>>24) & 0xFF)
43 #define GET_RED(x) (((x)>>16) & 0xFF)
44 #define GET_GREEN(x) (((x)>> 8) & 0xFF)
45 #define GET_BLUE(x) ((x) & 0xFF)
46 #define COMBINE_RGB(r,g,b) ((((r) & 0xFF) << 16) | (((g) & 0xFF) << 8) | ((b) & 0xFF))
48 #define SET_WAVE_BIT (0x6 << 24)
49 #define DUMPMODE_WAITING_TIME 600000
52 LED_CUSTOM_DUTY_ON = 1 << 0, /* this enum doesn't blink on led */
53 LED_CUSTOM_DEFAULT = (LED_CUSTOM_DUTY_ON),
56 static int charging_key;
57 static int lowbat_key;
58 static bool charging_state;
59 static bool lowbat_state;
60 static bool full_state;
61 static bool badbat_state;
62 static bool ovp_state;
63 static int rgb_blocked = false;
64 static bool rgb_dumpmode = false;
65 static Ecore_Timer *dumpmode_timer = NULL;
66 static enum state_t lcd_state = S_NORMAL;
67 static Ecore_Timer *reset_timer;
69 static int rgb_start(enum device_flags flags)
71 _I("rgbled device will be started");
76 static int rgb_stop(enum device_flags flags)
78 _I("rgbled device will be stopped");
83 static int led_prop(int mode, int on, int off, unsigned int color)
87 if (mode < 0 || mode > LED_MODE_MAX)
90 led = find_led_data(mode);
92 _E("no find data(%d)", mode);
98 case LED_VOICE_RECORDING:
105 led->data.color = color;
108 /* the others couldn't change any property */
112 _D("changed mode(%d) : state(%d), on(%d), off(%d), color(%x)",
113 mode, led->state, led->data.on, led->data.off, led->data.color);
117 static int led_mode(int mode, bool enable)
119 struct led_mode *led;
121 if (mode < 0 || mode > LED_MODE_MAX)
124 led = find_led_data(mode);
126 _E("no find data(%d)", mode);
134 static int get_led_mode_state(int mode, bool *state)
136 struct led_mode *led;
138 if (mode < 0 || mode > LED_MODE_MAX)
141 led = find_led_data(mode);
143 _E("no find data(%d)", mode);
154 static unsigned int led_blend(unsigned int before)
156 unsigned int alpha, alpha_inv;
157 unsigned char red, grn, blu;
159 alpha = GET_ALPHA(before) + 1;
160 alpha_inv = 256 - alpha;
162 red = ((alpha * GET_RED(before) + alpha_inv * GET_RED(BG_COLOR)) >> 8);
163 grn = ((alpha * GET_GREEN(before) + alpha_inv * GET_GREEN(BG_COLOR)) >> 8);
164 blu = ((alpha * GET_BLUE(before) + alpha_inv * GET_BLUE(BG_COLOR)) >> 8);
165 return COMBINE_RGB(red, grn, blu);
168 static Eina_Bool timer_reset_cb(void *data);
169 static int led_mode_to_device(struct led_mode *led)
180 if (rgb_blocked && led->mode != LED_POWER_OFF && led->mode != LED_OFF)
183 if (led->data.duration > 0) {
184 time = ((led->data.on + led->data.off) * led->data.duration) / 1000.f;
186 ecore_timer_del(reset_timer);
187 reset_timer = ecore_timer_add(time, timer_reset_cb, led);
189 _E("failed to add reset timer");
190 _D("add reset timer (mode:%d, %lfs)", led->mode, time);
193 val = LED_VALUE(led->data.on, led->data.off);
194 color = led_blend(led->data.color);
196 /* if wave status is ON, color should be combined with WAVE_BIT */
198 color |= SET_WAVE_BIT;
200 device_set_property(DEVICE_TYPE_LED, PROP_LED_COLOR, color);
201 device_set_property(DEVICE_TYPE_LED, PROP_LED_BLINK, val);
205 static Eina_Bool timer_reset_cb(void *data)
207 struct led_mode *led = (struct led_mode*)data;
210 return ECORE_CALLBACK_CANCEL;
213 _D("reset timer (mode:%d)", led->mode);
215 /* turn off previous setting */
216 led = find_led_data(LED_OFF);
217 led_mode_to_device(led);
219 led = get_valid_led_data(lcd_state);
220 /* preventing duplicated requests */
221 if (led && led->mode != LED_OFF)
222 led_mode_to_device(led);
224 return ECORE_CALLBACK_CANCEL;
227 static int led_display_changed_cb(void *data)
229 struct led_mode *led = NULL;
232 /* store last display condition */
233 lcd_state = (enum state_t)data;
235 /* charging error state */
239 if (lcd_state == S_LCDOFF)
240 state = DURING_LCD_OFF;
241 else if (lcd_state == S_NORMAL || lcd_state == S_LCDDIM)
242 state = DURING_LCD_ON;
246 /* turn off previous setting */
247 led = find_led_data(LED_OFF);
248 led_mode_to_device(led);
250 led = get_valid_led_data(state);
251 /* preventing duplicated requests */
252 if (led && led->mode != LED_OFF)
253 led_mode_to_device(led);
258 static int led_charging_changed_cb(void *data)
262 if (v == CHARGER_CHARGING)
263 charging_state = true;
265 charging_state = false;
268 led_mode(LED_CHARGING, charging_state);
273 static int led_lowbat_changed_cb(void *data)
275 lowbat_state = (bool)data;
278 led_mode(LED_LOW_BATTERY, lowbat_state);
283 static int led_fullbat_changed_cb(void *data)
285 full_state = (bool)data;
288 led_mode(LED_FULLY_CHARGED, full_state);
293 static int led_battery_health_changed_cb(void *data)
295 struct led_mode *led;
298 cur = ((int)data == HEALTH_BAD) ? true : false;
300 /* do not enter below scenario in case of same state */
301 if (cur == badbat_state)
306 /* set charging error mode */
307 led_mode(LED_CHARGING_ERROR, badbat_state);
309 /* update the led state */
310 if (badbat_state) { /* charging error */
311 led = find_led_data(LED_CHARGING_ERROR);
312 led_mode_to_device(led);
314 led = find_led_data(LED_OFF);
315 led_mode_to_device(led);
316 if (lcd_state == S_LCDOFF)
317 led_display_changed_cb((void*)S_LCDOFF);
323 static int led_battery_ovp_changed_cb(void *data)
327 /* do not enter below flow in case of same state */
328 if (cur == ovp_state)
333 if (ovp_state == OVP_NORMAL && lcd_state == S_LCDOFF)
334 led_display_changed_cb((void*)S_LCDOFF);
339 static void led_poweron_changed_cb(keynode_t *key, void *data)
342 struct led_mode *led;
344 state = vconf_keynode_get_int(key);
346 if (state != BOOT_ANIMATION_FINISHED)
349 led = find_led_data(LED_OFF);
350 led_mode_to_device(led);
352 vconf_ignore_key_changed(VCONFKEY_BOOT_ANIMATION_FINISHED,
353 led_poweron_changed_cb);
356 static void led_poweroff_changed_cb(keynode_t *key, void *data)
359 struct led_mode *led;
361 state = vconf_keynode_get_int(key);
363 if (state == VCONFKEY_SYSMAN_POWER_OFF_NONE ||
364 state == VCONFKEY_SYSMAN_POWER_OFF_POPUP)
367 led = find_led_data(LED_POWER_OFF);
368 led_mode_to_device(led);
370 vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
371 led_poweroff_changed_cb);
374 static void led_vconf_charging_cb(keynode_t *key, void *data)
376 charging_key = vconf_keynode_get_bool(key);
379 led_mode(LED_CHARGING, charging_state);
380 led_mode(LED_FULLY_CHARGED, full_state);
382 led_mode(LED_CHARGING, false);
383 led_mode(LED_FULLY_CHARGED, false);
387 static void led_vconf_lowbat_cb(keynode_t *key, void *data)
389 lowbat_key = vconf_keynode_get_bool(key);
392 led_mode(LED_LOW_BATTERY, lowbat_state);
394 led_mode(LED_LOW_BATTERY, false);
397 static void led_vconf_blocking_cb(keynode_t *key, void *data)
399 rgb_blocked = vconf_keynode_get_bool(key);
400 _I("rgbled blocking mode %s", (rgb_blocked ? "started" : "stopped"));
403 static void led_vconf_psmode_cb(keynode_t *key, void *data)
407 psmode = vconf_keynode_get_int(key);
408 if (psmode == SETTING_PSMODE_EMERGENCY)
409 rgb_stop(NORMAL_MODE);
411 rgb_start(NORMAL_MODE);
414 static DBusMessage *edbus_playcustom(E_DBus_Object *obj, DBusMessage *msg)
416 DBusMessageIter iter;
420 unsigned int color, flags;
422 ret = dbus_message_get_args(msg, NULL,
423 DBUS_TYPE_INT32, &on,
424 DBUS_TYPE_INT32, &off,
425 DBUS_TYPE_UINT32, &color,
426 DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID);
428 _I("there is no message");
433 /* not to play blink, on and off value should be zero */
434 if (!(flags & LED_CUSTOM_DUTY_ON))
437 /* set new value in case of LED_CUSTOM value */
438 ret = led_mode(LED_CUSTOM, true);
439 ret = led_prop(LED_CUSTOM, on, off, color);
441 _D("play custom %d, %d, %x, %d", on, off, color, ret);
444 reply = dbus_message_new_method_return(msg);
445 dbus_message_iter_init_append(reply, &iter);
446 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
450 static DBusMessage *edbus_stopcustom(E_DBus_Object *obj, DBusMessage *msg)
452 DBusMessageIter iter;
457 ret = get_led_mode_state(LED_CUSTOM, &state);
459 _E("failed to get led mode state : %d", ret);
465 _E("not play custom led");
470 /* reset default value */
471 ret = led_mode(LED_CUSTOM, false);
472 ret = led_prop(LED_CUSTOM, 500, 5000, 255);
474 _D("stop custom %d", ret);
477 reply = dbus_message_new_method_return(msg);
478 dbus_message_iter_init_append(reply, &iter);
479 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
483 static DBusMessage *edbus_set_mode(E_DBus_Object *obj, DBusMessage *msg)
485 DBusMessageIter iter;
488 int mode, val, on, off, ret;
489 struct led_mode *led;
490 bool mode_enabled = false;
492 ret = dbus_message_get_args(msg, NULL,
493 DBUS_TYPE_INT32, &mode,
494 DBUS_TYPE_INT32, &val,
495 DBUS_TYPE_INT32, &on,
496 DBUS_TYPE_INT32, &off,
497 DBUS_TYPE_UINT32, &color, DBUS_TYPE_INVALID);
499 _I("there is no message");
504 ret = get_led_mode_state(mode, &mode_enabled);
506 _I("failed to get led mode state : %d", ret);
510 ret = led_mode(mode, val);
511 ret = led_prop(mode, on, off, color);
513 /* If lcd prop has a during_lcd_on bit,
514 it should turn on/off during lcd on state */
515 led = find_led_data(mode);
516 if (led && (led->data.lcd & DURING_LCD_ON) &&
517 (lcd_state == S_NORMAL || lcd_state == S_LCDDIM)) {
518 led = get_valid_led_data(DURING_LCD_ON);
519 led_mode_to_device(led);
523 in case of display off condition,
524 who requests missed noti event, it should change the device value */
525 if (mode == LED_MISSED_NOTI && lcd_state == S_LCDOFF) {
526 if (!mode_enabled || on == 0) {
527 /* turn off previous setting */
528 led = find_led_data(LED_OFF);
529 led_mode_to_device(led);
530 /* update the led state */
531 led_display_changed_cb((void*)S_LCDOFF);
536 reply = dbus_message_new_method_return(msg);
537 dbus_message_iter_init_append(reply, &iter);
538 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
542 static void set_dumpmode(bool on)
544 struct led_mode *led;
548 val = LED_VALUE(200, 100);
549 color = led_blend(0xFFFF0000);
550 device_set_property(DEVICE_TYPE_LED, PROP_LED_COLOR, color);
551 device_set_property(DEVICE_TYPE_LED, PROP_LED_BLINK, val);
555 if (dumpmode_timer) {
556 ecore_timer_del(dumpmode_timer);
557 dumpmode_timer = NULL;
560 rgb_dumpmode = false;
563 led = find_led_data(LED_OFF);
564 led_mode_to_device(led);
569 static void dumpmode_timer_cb(void *data)
574 static DBusMessage *edbus_dump_mode(E_DBus_Object *obj, DBusMessage *msg)
576 DBusMessageIter iter;
581 ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &on,
585 _E("fail to get dumpmode state %d", ret);
590 if (!strcmp(on, "on")) {
592 dumpmode_timer = ecore_timer_add(DUMPMODE_WAITING_TIME,
593 (Ecore_Task_Cb)dumpmode_timer_cb, NULL);
594 } else if (!strcmp(on, "off")) {
600 reply = dbus_message_new_method_return(msg);
601 dbus_message_iter_init_append(reply, &iter);
602 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
607 static DBusMessage *edbus_print_mode(E_DBus_Object *obj, DBusMessage *msg)
610 return dbus_message_new_method_return(msg);
613 static const struct edbus_method edbus_methods[] = {
614 { "playcustom", "iiuu", "i", edbus_playcustom },
615 { "stopcustom", NULL, "i", edbus_stopcustom },
616 { "SetMode", "iiiiu", "i", edbus_set_mode },
617 { "PrintMode", NULL, NULL, edbus_print_mode },
618 { "Dumpmode", "s", "i", edbus_dump_mode },
619 /* Add methods here */
622 static void rgb_init(void *data)
624 int ta_connected, boot, psmode;
626 struct led_mode *led;
628 /* init dbus interface */
629 ret = register_edbus_method(DEVICED_PATH_LED, edbus_methods, ARRAY_SIZE(edbus_methods));
631 _E("fail to init edbus method(%d)", ret);
633 /* get led mode data from xml */
636 /* LED_OFF state must be always true */
637 led_mode(LED_OFF, true);
639 /* verify booting or restart */
640 ret = vconf_get_int(VCONFKEY_BOOT_ANIMATION_FINISHED, &boot);
642 boot = 0; /* set booting state */
644 /* in case of restart */
648 /* when booting, led indicator will be work */
649 led = find_led_data(LED_POWER_OFF);
650 led_mode_to_device(led);
651 vconf_notify_key_changed(VCONFKEY_BOOT_ANIMATION_FINISHED,
652 led_poweron_changed_cb, NULL);
655 /* register power off callback */
656 vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
657 led_poweroff_changed_cb, NULL);
659 /* register notifier for each event */
660 register_notifier(DEVICE_NOTIFIER_LCD, led_display_changed_cb);
661 register_notifier(DEVICE_NOTIFIER_BATTERY_CHARGING, led_charging_changed_cb);
662 register_notifier(DEVICE_NOTIFIER_LOWBAT, led_lowbat_changed_cb);
663 register_notifier(DEVICE_NOTIFIER_FULLBAT, led_fullbat_changed_cb);
664 register_notifier(DEVICE_NOTIFIER_BATTERY_HEALTH, led_battery_health_changed_cb);
665 register_notifier(DEVICE_NOTIFIER_BATTERY_OVP, led_battery_ovp_changed_cb);
667 /* initialize vconf value */
668 vconf_get_bool(VCONFKEY_SETAPPL_LED_INDICATOR_CHARGING, &charging_key);
669 vconf_get_bool(VCONFKEY_SETAPPL_LED_INDICATOR_LOW_BATT, &lowbat_key);
671 /* initialize led indicator blocking value */
672 vconf_get_bool(VCONFKEY_SETAPPL_BLOCKINGMODE_LED_INDICATOR, &rgb_blocked);
674 /* register vconf callback */
675 vconf_notify_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_CHARGING,
676 led_vconf_charging_cb, NULL);
677 vconf_notify_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_LOW_BATT,
678 led_vconf_lowbat_cb, NULL);
680 /* register led indicator blocking vconf callback */
681 vconf_notify_key_changed(VCONFKEY_SETAPPL_BLOCKINGMODE_LED_INDICATOR,
682 led_vconf_blocking_cb, NULL);
684 /* check power saving state */
685 vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &psmode);
686 if (psmode == SETTING_PSMODE_EMERGENCY)
687 rgb_stop(NORMAL_MODE);
689 /* register power saving callback */
690 vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, led_vconf_psmode_cb, NULL);
692 ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CHARGE_NOW, &ta_connected);
693 if (!ret && ta_connected)
694 led_charging_changed_cb((void*)ta_connected);
697 static void rgb_exit(void *data)
699 struct led_mode *led;
701 /* unregister vconf callback */
702 vconf_ignore_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_CHARGING,
703 led_vconf_charging_cb);
704 vconf_ignore_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_LOW_BATT,
705 led_vconf_lowbat_cb);
707 /* unregister led indicatore blocking vconf callback */
708 vconf_ignore_key_changed(VCONFKEY_SETAPPL_BLOCKINGMODE_LED_INDICATOR,
709 led_vconf_blocking_cb);
711 /* unregister power saving callback */
712 vconf_ignore_key_changed(VCONFKEY_SETAPPL_PSMODE, led_vconf_psmode_cb);
714 /* unregister notifier for each event */
715 unregister_notifier(DEVICE_NOTIFIER_LCD, led_display_changed_cb);
716 unregister_notifier(DEVICE_NOTIFIER_BATTERY_CHARGING, led_charging_changed_cb);
717 unregister_notifier(DEVICE_NOTIFIER_LOWBAT, led_lowbat_changed_cb);
718 unregister_notifier(DEVICE_NOTIFIER_FULLBAT, led_fullbat_changed_cb);
719 unregister_notifier(DEVICE_NOTIFIER_BATTERY_HEALTH, led_battery_health_changed_cb);
720 unregister_notifier(DEVICE_NOTIFIER_BATTERY_OVP, led_battery_ovp_changed_cb);
724 led = find_led_data(LED_OFF);
725 led_mode_to_device(led);
727 /* release led mode data */
731 static const struct device_ops rgbled_device_ops = {
732 .priority = DEVICE_PRIORITY_NORMAL,
740 DEVICE_OPS_REGISTER(&rgbled_device_ops)