led: add notification led (rgb) 40/99940/4 accepted/tizen/3.0/common/20161201.135146 accepted/tizen/3.0/ivi/20161201.031528 accepted/tizen/3.0/mobile/20161201.031411 accepted/tizen/3.0/tv/20161201.031442 accepted/tizen/3.0/wearable/20161201.031506 submit/tizen_3.0/20161130.101437
authortaeyoung <ty317.kim@samsung.com>
Thu, 24 Nov 2016 12:09:34 +0000 (21:09 +0900)
committertaeyoung <ty317.kim@samsung.com>
Fri, 25 Nov 2016 08:20:09 +0000 (17:20 +0900)
Change-Id: Iccb5d75dfc8d20f32aa7e86e341c3d6672fc08db
Signed-off-by: taeyoung <ty317.kim@samsung.com>
hw/led/CMakeLists.txt
hw/led/led.c

index 017ddc6..7a39c56 100644 (file)
@@ -2,7 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 PROJECT(led C)
 
 INCLUDE(FindPkgConfig)
-pkg_check_modules(pkgs REQUIRED dlog hwcommon)
+pkg_check_modules(pkgs REQUIRED dlog hwcommon glib-2.0)
 
 FOREACH(flag ${pkgs_CFLAGS})
        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
index 008af01..bb49ac4 100644 (file)
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <errno.h>
 #include <linux/limits.h>
+#include <glib.h>
 
 #include <hw/led.h>
 #include "../shared.h"
 
 #define GET_BRIGHTNESS(val)     (((val) >> 24) & 0xFF)
 
+/* LED Notification (RGB) */
+#define NOTI_COLOR_TYPE_PATH "/sys/class/leds/led.%d/color"
+#define NOTI_COLOR_BRT_PATH "/sys/class/leds/led.%d/brightness"
+
+#define GET_TYPE(a)       (((a) >> 24) & 0xFF)
+#define GET_RED_ONLY(a)   ((a) & 0xFF0000)
+#define GET_GREEN_ONLY(a) ((a) & 0x00FF00)
+#define GET_BLUE_ONLY(a)  ((a) & 0x0000FF)
+#define GET_RED_BRT(a)    (((a) >> 16) & 0xFF)
+#define GET_GREEN_BRT(a)  (((a) >> 8) & 0xFF)
+#define GET_BLUE_BRT(a)   ((a) & 0xFF)
+
+typedef enum _led_rgb_type {
+       LED_RED,
+       LED_GREEN,
+       LED_BLUE,
+} led_rgb_type_e;
+
+struct led_notification_node {
+       char *name;
+       led_rgb_type_e type;
+       char *path;
+       int brt;
+} led_noti_nodes[] = {
+       { "RED",   LED_RED,   NULL, 0 },
+       { "GREEN", LED_GREEN, NULL, 0 },
+       { "BLUE",  LED_BLUE,  NULL, 0 },
+};
+
+struct notification_play_color_info {
+       unsigned int color;
+       int time;
+};
+
+struct notification_play_info {
+       GList *play_list;
+       int nr_play;
+       int index;
+       guint timer;
+} play_info;
+
+
 static int camera_back_set_state(struct led_state *state)
 {
        static int max = -1;
@@ -100,29 +143,284 @@ static int touch_key_set_state(struct led_state *state)
        return 0;
 }
 
+/* Find sysfs nodes for RGB*/
+static void notification_get_path(int index)
+{
+       char path[PATH_MAX];
+       char buf[8];
+       FILE *fp;
+       int i;
+       size_t len;
+
+       snprintf(path, sizeof(path), NOTI_COLOR_TYPE_PATH, index);
+       fp = fopen(path, "r");
+       if (!fp)
+               return;
+       len = fread(buf, 1, sizeof(buf) - 1, fp);
+       fclose(fp);
+       if (len == 0) {
+               _E("Failed to get contents");
+               return;
+       }
+       buf[len] = '\0';
+
+       for (i = 0 ; i < ARRAY_SIZE(led_noti_nodes) ; i++) {
+               if (strncmp(buf, led_noti_nodes[i].name, strlen(led_noti_nodes[i].name)))
+                       continue;
+               snprintf(path, sizeof(path), NOTI_COLOR_BRT_PATH, index);
+               led_noti_nodes[i].path = strdup(path);
+       }
+}
+
+static int notification_init_led(void)
+{
+       int i;
+
+       notification_get_path(1);
+       notification_get_path(2);
+       notification_get_path(3);
+
+       for (i = 0 ; i < ARRAY_SIZE(led_noti_nodes) ; i++)
+               _I("NOTI LED %s (%s)", led_noti_nodes[i].name, led_noti_nodes[i].path);
+
+       return 0;
+}
+
+/* Change led color and brightness */
+static int notification_set_brightness(struct led_state *state)
+{
+       int i;
+       int err, ret;
+       int brt;
+       unsigned int red, green, blue;
+
+       if (!state)
+               return -EINVAL;
+
+       red = GET_RED_BRT(state->color);
+       green = GET_GREEN_BRT(state->color);
+       blue = GET_BLUE_BRT(state->color);
+
+       _I("COLOR(%x) r(%x), g(%x), b(%x)", state->color, red, green, blue);
+
+       err = 0;
+       for (i = 0 ; i < ARRAY_SIZE(led_noti_nodes) ; i++) {
+               if (!led_noti_nodes[i].path)
+                       continue;
+               if (led_noti_nodes[i].type == LED_RED)
+                       brt = red;
+               else if (led_noti_nodes[i].type == LED_GREEN)
+                       brt = green;
+               else if (led_noti_nodes[i].type == LED_BLUE)
+                       brt = blue;
+               else
+                       continue;
+
+               ret = sys_set_int(led_noti_nodes[i].path, brt);
+               if (ret < 0) {
+                       _E("Failed to change brt of led (%s) to (%d)(ret:%d)", led_noti_nodes[i].name, brt, ret);
+                       err = ret;
+               }
+       }
+
+       return err;
+}
+
+/* turn off led */
+static int notification_turn_off(struct led_state *state)
+{
+       struct led_state st = { 0, };
+       return notification_set_brightness(&st);
+}
+
+/* release play list */
+static void free_func(gpointer data)
+{
+       struct notification_play_color_info *color = data;
+       free(color);
+}
+
+static void release_play_info(void)
+{
+       if (play_info.play_list) {
+               g_list_free_full(play_info.play_list, free_func);
+               play_info.play_list = NULL;
+       }
+       play_info.nr_play = 0;
+       play_info.index = 0;
+       if (play_info.timer) {
+               g_source_remove(play_info.timer);
+               play_info.timer = 0;
+       }
+
+       notification_turn_off(NULL);
+}
+
+/* timer callback to change colors which are stored in play_list */
+static gboolean notification_timer_expired(gpointer data)
+{
+       struct notification_play_color_info *color;
+       struct led_state state = { 0, };
+       int ret;
+
+       if (play_info.timer) {
+               g_source_remove(play_info.timer);
+               play_info.timer = 0;
+       }
+
+       color = g_list_nth_data(play_info.play_list, play_info.index);
+       if (!color) {
+               _E("Failed to get (%d)th item from the play list", play_info.index);
+               goto out;
+       }
+
+       play_info.timer = g_timeout_add(color->time, notification_timer_expired, data);
+       if (play_info.timer == 0) {
+               _E("Failed to add timeout for LED blinking");
+               goto out;
+       }
+
+       state.color = color->color;
+
+       ret = notification_set_brightness(&state);
+       if (ret < 0) {
+               _E("Failed to set brightness (%d)", ret);
+               goto out;
+       }
+
+       play_info.index++;
+       if (play_info.index == play_info.nr_play)
+               play_info.index = 0;
+
+       return G_SOURCE_CONTINUE;
+
+out:
+       release_play_info();
+
+       return G_SOURCE_REMOVE;
+}
+
+/* insert color info to the play_list */
+static int notification_insert_play_list(unsigned color, int on, int off)
+{
+       struct notification_play_color_info *on_info, *off_info;
+
+       if (color == 0)
+               return -EINVAL;
+       on_info = calloc(1, sizeof(struct notification_play_color_info));
+       if (!on_info)
+               return -ENOMEM;
+       off_info = calloc(1, sizeof(struct notification_play_color_info));
+       if (!off_info) {
+               free(on_info);
+               return -ENOMEM;
+       }
+
+       on_info->color = color;
+       on_info->time = on;
+       play_info.play_list = g_list_append(play_info.play_list, on_info);
+
+       off_info->color = 0;
+       off_info->time = off;
+       play_info.play_list = g_list_append(play_info.play_list, off_info);
+
+       return 0;
+}
+
+/* insert color info to the play list and start to play */
+static int notification_set_brightness_blink(struct led_state *state)
+{
+       unsigned int val;
+       int ret;
+
+       val = GET_RED_ONLY(state->color);
+       if (val) {
+               ret = notification_insert_play_list(val, state->duty_on, state->duty_off);
+               if (ret < 0)
+                       _E("Failed to insert color info to list (%d)", ret);
+       }
+       val = GET_GREEN_ONLY(state->color);
+       if (val) {
+               ret = notification_insert_play_list(val, state->duty_on, state->duty_off);
+               if (ret < 0)
+                       _E("Failed to insert color info to list (%d)", ret);
+       }
+       val = GET_BLUE_ONLY(state->color);
+       if (val) {
+               ret = notification_insert_play_list(val, state->duty_on, state->duty_off);
+               if (ret < 0)
+                       _E("Failed to insert color info to list (%d)", ret);
+       }
+
+       play_info.nr_play = g_list_length(play_info.play_list);
+       play_info.index = 0;
+
+       notification_timer_expired(NULL);
+       return 0;
+}
+
+/* turn on led notification */
+static int notification_turn_on(struct led_state *state)
+{
+       if (state->type == LED_TYPE_MANUAL)
+               return notification_set_brightness(state);
+
+       return notification_set_brightness_blink(state);
+}
+
+static int notification_set_state(struct led_state *state)
+{
+       if (!state)
+               return -EINVAL;
+
+       switch (state->type) {
+       case LED_TYPE_BLINK:
+       case LED_TYPE_MANUAL:
+               break;
+       default:
+               _E("Not suppoted type (%d)", state->type);
+               return -ENOTSUP;
+       }
+
+       release_play_info();
+
+       if (GET_TYPE(state->color) == 0)
+               return notification_turn_off(state);
+
+       return notification_turn_on(state);
+}
+
 static int led_open(struct hw_info *info,
                const char *id, struct hw_common **common)
 {
        struct led_device *led_dev;
+       size_t len;
 
        if (!info || !id || !common)
                return -EINVAL;
 
-       if (strcmp(id, LED_ID_CAMERA_BACK) != 0 &&
-           strcmp(id, LED_ID_TOUCH_KEY) != 0)
-               return -ENOTSUP;
-
        led_dev = calloc(1, sizeof(struct led_device));
        if (!led_dev)
                return -ENOMEM;
 
        led_dev->common.info = info;
 
-       if (!strcmp(id, LED_ID_CAMERA_BACK))
+       len = strlen(id) + 1;
+       if (!strncmp(id, LED_ID_CAMERA_BACK, len))
                led_dev->set_state = camera_back_set_state;
-       else if (!strcmp(id, LED_ID_TOUCH_KEY))
+
+       else if (!strncmp(id, LED_ID_TOUCH_KEY, len))
                led_dev->set_state = touch_key_set_state;
 
+       else if (!strncmp(id, LED_ID_NOTIFICATION, len)) {
+               notification_init_led();
+               led_dev->set_state = notification_set_state;
+
+       } else {
+               free(led_dev);
+               return -ENOTSUP;
+       }
+
        *common = (struct hw_common *)led_dev;
        return 0;
 }