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"
30 #include "core/common.h"
31 #include "core/edbus-handler.h"
32 #include "core/devices.h"
33 #include "core/device-notifier.h"
34 #include "core/device-handler.h"
35 #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 bool charging_key;
57 static bool 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 bool 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;
68 static int led_prop(int mode, int on, int off, unsigned int color)
72 if (mode < 0 || mode > LED_MODE_MAX)
75 led = find_led_data(mode);
77 _E("no find data(%d)", mode);
83 case LED_VOICE_RECORDING:
90 led->data.color = color;
93 /* the others couldn't change any property */
97 _D("changed mode(%d) : on(%d), off(%d), color(%x)",
98 mode, led->data.on, led->data.off, led->data.color);
102 static int led_mode(int mode, bool enable)
104 struct led_mode *led;
106 if (mode < 0 || mode > LED_MODE_MAX)
109 led = find_led_data(mode);
111 _E("no find data(%d)", mode);
119 static int get_led_mode_state(int mode, bool *state)
121 struct led_mode *led;
123 if (mode < 0 || mode > LED_MODE_MAX)
126 led = find_led_data(mode);
128 _E("no find data(%d)", mode);
139 static unsigned int led_blend(unsigned int before)
141 unsigned int alpha, alpha_inv;
142 unsigned char red, grn, blu;
144 alpha = GET_ALPHA(before) + 1;
145 alpha_inv = 256 - alpha;
147 red = ((alpha * GET_RED(before) + alpha_inv * GET_RED(BG_COLOR)) >> 8);
148 grn = ((alpha * GET_GREEN(before) + alpha_inv * GET_GREEN(BG_COLOR)) >> 8);
149 blu = ((alpha * GET_BLUE(before) + alpha_inv * GET_BLUE(BG_COLOR)) >> 8);
150 return COMBINE_RGB(red, grn, blu);
153 static int led_mode_to_device(struct led_mode *led)
163 if (rgb_blocked && led->mode != LED_POWER_OFF && led->mode != LED_OFF)
166 val = LED_VALUE(led->data.on, led->data.off);
167 color = led_blend(led->data.color);
169 /* if wave status is ON, color should be combined with WAVE_BIT */
171 color |= SET_WAVE_BIT;
173 device_set_property(DEVICE_TYPE_LED, PROP_LED_COLOR, color);
174 device_set_property(DEVICE_TYPE_LED, PROP_LED_BLINK, val);
178 static int led_display_changed_cb(void *data)
180 struct led_mode *led = NULL;
183 /* store last display condition */
184 lcd_state = (enum state_t)data;
186 /* charging error state */
190 if (lcd_state == S_LCDOFF)
191 led = get_valid_led_data();
192 else if (lcd_state == S_NORMAL || lcd_state == S_LCDDIM)
193 led = find_led_data(LED_OFF);
195 return led_mode_to_device(led);
198 static int led_charging_changed_cb(void *data)
202 if (v == CHARGER_CHARGING)
203 charging_state = true;
205 charging_state = false;
208 led_mode(LED_CHARGING, charging_state);
213 static int led_lowbat_changed_cb(void *data)
215 lowbat_state = (bool)data;
218 led_mode(LED_LOW_BATTERY, lowbat_state);
223 static int led_fullbat_changed_cb(void *data)
225 full_state = (bool)data;
228 led_mode(LED_FULLY_CHARGED, full_state);
233 static int led_battery_health_changed_cb(void *data)
235 struct led_mode *led;
238 cur = ((int)data == HEALTH_BAD) ? true : false;
240 /* do not enter below scenario in case of same state */
241 if (cur == badbat_state)
246 /* set charging error mode */
247 led_mode(LED_CHARGING_ERROR, badbat_state);
249 /* update the led state */
250 if (badbat_state) { /* charging error */
251 led = find_led_data(LED_CHARGING_ERROR);
252 led_mode_to_device(led);
254 led = find_led_data(LED_OFF);
255 led_mode_to_device(led);
256 if (lcd_state == S_LCDOFF)
257 led_display_changed_cb((void*)S_LCDOFF);
263 static int led_battery_ovp_changed_cb(void *data)
267 /* do not enter below flow in case of same state */
268 if (cur == ovp_state)
273 if (ovp_state == OVP_NORMAL && lcd_state == S_LCDOFF)
274 led_display_changed_cb((void*)S_LCDOFF);
279 static void led_poweron_changed_cb(keynode_t *key, void *data)
282 struct led_mode *led;
284 state = vconf_keynode_get_int(key);
286 if (state != BOOT_ANIMATION_FINISHED)
289 led = find_led_data(LED_OFF);
290 led_mode_to_device(led);
292 vconf_ignore_key_changed(VCONFKEY_BOOT_ANIMATION_FINISHED,
293 led_poweron_changed_cb);
296 static void led_poweroff_changed_cb(keynode_t *key, void *data)
299 struct led_mode *led;
301 state = vconf_keynode_get_int(key);
303 if (state == VCONFKEY_SYSMAN_POWER_OFF_NONE ||
304 state == VCONFKEY_SYSMAN_POWER_OFF_POPUP)
307 led = find_led_data(LED_POWER_OFF);
308 led_mode_to_device(led);
310 vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
311 led_poweroff_changed_cb);
314 static void led_vconf_charging_cb(keynode_t *key, void *data)
316 charging_key = vconf_keynode_get_bool(key);
319 led_mode(LED_CHARGING, charging_state);
320 led_mode(LED_FULLY_CHARGED, full_state);
322 led_mode(LED_CHARGING, false);
323 led_mode(LED_FULLY_CHARGED, false);
327 static void led_vconf_lowbat_cb(keynode_t *key, void *data)
329 lowbat_key = vconf_keynode_get_bool(key);
332 led_mode(LED_LOW_BATTERY, lowbat_state);
334 led_mode(LED_LOW_BATTERY, false);
337 static void led_vconf_blocking_cb(keynode_t *key, void *data)
339 rgb_blocked = vconf_keynode_get_bool(key);
340 _I("rgbled blocking mode %s", (rgb_blocked ? "started" : "stopped"));
343 static DBusMessage *edbus_playcustom(E_DBus_Object *obj, DBusMessage *msg)
345 DBusMessageIter iter;
349 unsigned int color, flags;
351 ret = dbus_message_get_args(msg, NULL,
352 DBUS_TYPE_INT32, &on,
353 DBUS_TYPE_INT32, &off,
354 DBUS_TYPE_UINT32, &color,
355 DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID);
357 _I("there is no message");
362 /* not to play blink, on and off value should be zero */
363 if (!(flags & LED_CUSTOM_DUTY_ON))
366 /* set new value in case of LED_CUSTOM value */
367 ret = led_mode(LED_CUSTOM, true);
368 ret = led_prop(LED_CUSTOM, on, off, color);
370 _D("play custom %d, %d, %x, %d", on, off, color, ret);
373 reply = dbus_message_new_method_return(msg);
374 dbus_message_iter_init_append(reply, &iter);
375 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
379 static DBusMessage *edbus_stopcustom(E_DBus_Object *obj, DBusMessage *msg)
381 DBusMessageIter iter;
385 /* reset default value */
386 ret = led_mode(LED_CUSTOM, false);
387 ret = led_prop(LED_CUSTOM, 500, 5000, 255);
389 _D("stop custom %d", ret);
391 reply = dbus_message_new_method_return(msg);
392 dbus_message_iter_init_append(reply, &iter);
393 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
397 static DBusMessage *edbus_set_mode(E_DBus_Object *obj, DBusMessage *msg)
399 DBusMessageIter iter;
402 int mode, val, on, off, ret;
403 struct led_mode *led;
404 bool mode_enabled = false;
406 ret = dbus_message_get_args(msg, NULL,
407 DBUS_TYPE_INT32, &mode,
408 DBUS_TYPE_INT32, &val,
409 DBUS_TYPE_INT32, &on,
410 DBUS_TYPE_INT32, &off,
411 DBUS_TYPE_UINT32, &color, DBUS_TYPE_INVALID);
413 _I("there is no message");
418 ret = get_led_mode_state(mode, &mode_enabled);
420 _I("failed to get led mode state : %d", ret);
424 ret = led_mode(mode, val);
425 ret = led_prop(mode, on, off, color);
428 in case of display off condition,
429 who requests missed noti event, it should change the device value */
430 if (mode == LED_MISSED_NOTI && lcd_state == S_LCDOFF) {
431 if (!mode_enabled || on == 0) {
432 /* turn off previous setting */
433 led = find_led_data(LED_OFF);
434 led_mode_to_device(led);
435 /* update the led state */
436 led_display_changed_cb((void*)S_LCDOFF);
441 reply = dbus_message_new_method_return(msg);
442 dbus_message_iter_init_append(reply, &iter);
443 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
447 static void set_dumpmode(bool on)
449 struct led_mode *led;
453 val = LED_VALUE(200, 100);
454 color = led_blend(0xFFFF0000);
455 device_set_property(DEVICE_TYPE_LED, PROP_LED_COLOR, color);
456 device_set_property(DEVICE_TYPE_LED, PROP_LED_BLINK, val);
460 if (dumpmode_timer) {
461 ecore_timer_del(dumpmode_timer);
462 dumpmode_timer = NULL;
465 rgb_dumpmode = false;
468 led = find_led_data(LED_OFF);
469 led_mode_to_device(led);
474 static void dumpmode_timer_cb(void *data)
479 static DBusMessage *edbus_dump_mode(E_DBus_Object *obj, DBusMessage *msg)
481 DBusMessageIter iter;
486 ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &on,
490 _E("fail to get dumpmode state %d", ret);
495 if (!strcmp(on, "on")) {
497 dumpmode_timer = ecore_timer_add(DUMPMODE_WAITING_TIME,
498 (Ecore_Task_Cb)dumpmode_timer_cb, NULL);
499 } else if (!strcmp(on, "off")) {
505 reply = dbus_message_new_method_return(msg);
506 dbus_message_iter_init_append(reply, &iter);
507 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
512 static DBusMessage *edbus_print_mode(E_DBus_Object *obj, DBusMessage *msg)
515 return dbus_message_new_method_return(msg);
518 static const struct edbus_method edbus_methods[] = {
519 { "playcustom", "iiuu", "i", edbus_playcustom },
520 { "stopcustom", NULL, "i", edbus_stopcustom },
521 { "SetMode", "iiiiu", "i", edbus_set_mode },
522 { "PrintMode", NULL, NULL, edbus_print_mode },
523 { "Dumpmode", "s", "i", edbus_dump_mode },
524 /* Add methods here */
527 static void rgb_init(void *data)
529 int ta_connected, boot;
531 struct led_mode *led;
533 /* init dbus interface */
534 ret = register_edbus_method(DEVICED_PATH_LED, edbus_methods, ARRAY_SIZE(edbus_methods));
536 _E("fail to init edbus method(%d)", ret);
538 /* get led mode data from xml */
541 /* verify booting or restart */
542 ret = vconf_get_int(VCONFKEY_BOOT_ANIMATION_FINISHED, &boot);
544 boot = 0; /* set booting state */
546 /* in case of restart */
550 /* when booting, led indicator will be work */
551 led = find_led_data(LED_POWER_OFF);
552 led_mode_to_device(led);
553 vconf_notify_key_changed(VCONFKEY_BOOT_ANIMATION_FINISHED,
554 led_poweron_changed_cb, NULL);
557 /* register power off callback */
558 vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
559 led_poweroff_changed_cb, NULL);
561 /* register notifier for each event */
562 register_notifier(DEVICE_NOTIFIER_LCD, led_display_changed_cb);
563 register_notifier(DEVICE_NOTIFIER_BATTERY_CHARGING, led_charging_changed_cb);
564 register_notifier(DEVICE_NOTIFIER_LOWBAT, led_lowbat_changed_cb);
565 register_notifier(DEVICE_NOTIFIER_FULLBAT, led_fullbat_changed_cb);
566 register_notifier(DEVICE_NOTIFIER_BATTERY_HEALTH, led_battery_health_changed_cb);
567 register_notifier(DEVICE_NOTIFIER_BATTERY_OVP, led_battery_ovp_changed_cb);
569 /* initialize vconf value */
570 vconf_get_bool(VCONFKEY_SETAPPL_LED_INDICATOR_CHARGING, (int*)&charging_key);
571 vconf_get_bool(VCONFKEY_SETAPPL_LED_INDICATOR_LOW_BATT, (int*)&lowbat_key);
573 /* initialize led indicator blocking value */
574 vconf_get_bool(VCONFKEY_SETAPPL_BLOCKINGMODE_LED_INDICATOR, (int*)&rgb_blocked);
576 /* register vconf callback */
577 vconf_notify_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_CHARGING,
578 led_vconf_charging_cb, NULL);
579 vconf_notify_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_LOW_BATT,
580 led_vconf_lowbat_cb, NULL);
582 /* register led indicator blocking vconf callback */
583 vconf_notify_key_changed(VCONFKEY_SETAPPL_BLOCKINGMODE_LED_INDICATOR,
584 led_vconf_blocking_cb, NULL);
586 ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CHARGE_NOW, &ta_connected);
587 if (!ret && ta_connected)
588 led_charging_changed_cb((void*)ta_connected);
591 static void rgb_exit(void *data)
593 struct led_mode *led;
595 /* unregister vconf callback */
596 vconf_ignore_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_CHARGING,
597 led_vconf_charging_cb);
598 vconf_ignore_key_changed(VCONFKEY_SETAPPL_LED_INDICATOR_LOW_BATT,
599 led_vconf_lowbat_cb);
601 /* unregister led indicatore blocking vconf callback */
602 vconf_ignore_key_changed(VCONFKEY_SETAPPL_BLOCKINGMODE_LED_INDICATOR,
603 led_vconf_blocking_cb);
605 /* unregister notifier for each event */
606 unregister_notifier(DEVICE_NOTIFIER_LCD, led_display_changed_cb);
607 unregister_notifier(DEVICE_NOTIFIER_BATTERY_CHARGING, led_charging_changed_cb);
608 unregister_notifier(DEVICE_NOTIFIER_LOWBAT, led_lowbat_changed_cb);
609 unregister_notifier(DEVICE_NOTIFIER_FULLBAT, led_fullbat_changed_cb);
610 unregister_notifier(DEVICE_NOTIFIER_BATTERY_HEALTH, led_battery_health_changed_cb);
611 unregister_notifier(DEVICE_NOTIFIER_BATTERY_OVP, led_battery_ovp_changed_cb);
615 led = find_led_data(LED_OFF);
616 led_mode_to_device(led);
618 /* release led mode data */
622 static int rgb_start(void)
624 _I("rgbled device will be started");
629 static int rgb_stop(void)
631 _I("rgbled device will be stopped");
636 static const struct device_ops rgbled_device_ops = {
637 .priority = DEVICE_PRIORITY_NORMAL,
645 DEVICE_OPS_REGISTER(&rgbled_device_ops)