led: handle rgb play requests in the list 33/103933/4
authortaeyoung <ty317.kim@samsung.com>
Sun, 11 Dec 2016 10:33:28 +0000 (19:33 +0900)
committertaeyoung <ty317.kim@samsung.com>
Sun, 11 Dec 2016 11:59:22 +0000 (20:59 +0900)
- rgb play requests are handled by the request list.
  Thus deviced can know if a play stop request is
  valid or not.
- Timer is added to check invalid requests
  in the request list. If the process which requests
  to play rgb does not exist anymore, the request
  from the process is removed.

Change-Id: I34ed6d9dfdab95e5fcbe18c0fb89a96ed6ce92b1
Signed-off-by: taeyoung <ty317.kim@samsung.com>
src/led/rgb.c

index 47afc9d..9058269 100644 (file)
 #include <stdio.h>
 #include <errno.h>
 #include <assert.h>
+#include <glib.h>
 #include <device-node.h>
 #include <Ecore.h>
 #include <vconf.h>
 #include <hw/led.h>
 
 #include "core/log.h"
+#include "core/list.h"
 #include "core/common.h"
 #include "core/edbus-handler.h"
 #include "core/devices.h"
 #include "core/device-notifier.h"
 
+struct rgb_request {
+       pid_t pid;
+       struct led_state state;
+};
+
 /* enum values defined in capi-system-device */
 typedef enum {
        LED_CUSTOM_DUTY_ON = 1 << 0,                /**< blink LED */
        LED_CUSTOM_DEFAULT = (LED_CUSTOM_DUTY_ON),  /**< Default flag */
 } led_custom_flags;
 
-struct led_device *rgb_dev;
+static struct led_device *rgb_dev;
+static dd_list *rgb_list;
+static struct rgb_request *top;
+static guint timer;
+
+static int find_rgb_req(pid_t pid, struct rgb_request **request)
+{
+       dd_list *l;
+       struct rgb_request *req;
+
+       DD_LIST_FOREACH(rgb_list, l, req) {
+               if (req->pid == pid) {
+                       *request = req;
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+static int remove_req_from_list(pid_t pid)
+{
+       dd_list *l;
+       struct rgb_request *req;
+
+       DD_LIST_FOREACH(rgb_list, l, req) {
+               if (req->pid == pid) {
+                       _I("remove rgb play request from pid (%d)", pid);
+                       if (req == top)
+                               top = NULL;
+                       DD_LIST_REMOVE(rgb_list, req);
+                       free(req);
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int add_req_to_list(pid_t pid, struct led_state *state)
+{
+       int ret;
+       struct rgb_request *req;
+
+       if (!state)
+               return -EINVAL;
+
+       ret = find_rgb_req(pid, &req);
+       if (ret < 0) {
+               req = calloc(1, sizeof(struct rgb_request));
+               if (!req) {
+                       _E("calloc() failed");
+                       return -ENOMEM;
+               }
+               req->pid = pid;
+               DD_LIST_APPEND(rgb_list, req);
+       }
+
+       req->state.color = state->color;
+       req->state.duty_on = state->duty_on;
+       req->state.duty_off = state->duty_off;
+       req->state.type = state->type;
+
+       top = req;
+
+       return 0;
+}
 
 static int rgb_play(struct led_state *state)
 {
+       struct led_state off = { 0, };
+
        if (!rgb_dev) {
                _E("There is NO HAL");
                return -ENODEV;
@@ -51,7 +125,48 @@ static int rgb_play(struct led_state *state)
                return -ENOTSUP;
        }
 
-       return rgb_dev->set_state(state);
+       if (state)
+               return rgb_dev->set_state(state);
+
+       return rgb_dev->set_state(&off);
+}
+
+static gboolean remove_not_handled_req(gpointer data)
+{
+       dd_list *l;
+       int ret = 0;
+       struct rgb_request *req;
+
+       DD_LIST_FOREACH(rgb_list, l, req) {
+               if (kill(req->pid, 0) == -1) {
+                       ret = remove_req_from_list(req->pid);
+                       if (ret < 0)
+                               _E("Failed to remove rgb request (%d)", ret);
+               }
+       }
+
+       if (!top) {
+               ret = rgb_play(NULL);
+               if (ret < 0)
+                       _E("Failed to turn off removed request (%d)", ret);
+       }
+
+       if (DD_LIST_LENGTH(rgb_list) == 0) {
+               timer = 0;
+               return G_SOURCE_REMOVE;
+       }
+
+       return G_SOURCE_CONTINUE;
+}
+
+static void add_timer_to_check_invalid_req(void)
+{
+       if (timer > 0)
+               return;
+
+       timer = g_timeout_add(5000, remove_not_handled_req, NULL);
+       if (timer == 0)
+               _E("Failed to add timer");
 }
 
 static DBusMessage *edbus_playcustom(E_DBus_Object *obj, DBusMessage *msg)
@@ -86,8 +201,13 @@ static DBusMessage *edbus_playcustom(E_DBus_Object *obj, DBusMessage *msg)
                state.type = LED_TYPE_MANUAL;
 
        ret = rgb_play(&state);
-       if (ret < 0)
+       if (ret < 0) {
                _E("Failed to play LED notification (%d)", ret);
+               goto out;
+       }
+
+       add_req_to_list(pid, &state);
+       add_timer_to_check_invalid_req();
 
 out:
        return make_reply_message(msg, ret);
@@ -95,7 +215,6 @@ out:
 
 static DBusMessage *edbus_stopcustom(E_DBus_Object *obj, DBusMessage *msg)
 {
-       struct led_state state = { 0, };
        int ret;
        pid_t pid;
 
@@ -103,10 +222,21 @@ static DBusMessage *edbus_stopcustom(E_DBus_Object *obj, DBusMessage *msg)
 
        _I("pid %d led stop custom", pid);
 
-       ret = rgb_play(&state);
-       if (ret < 0)
-               _E("Failed to play LED notification (%d)", ret);
+       ret = remove_req_from_list(pid);
+       if (ret < 0) {
+               _E("There is no request from pid (%d) to remove", pid);
+               goto out;
+       }
 
+       if (!top) {
+               ret = rgb_play(NULL);
+               if (ret < 0) {
+                       _E("Failed to play LED notification (%d)", ret);
+                       goto out;
+               }
+       }
+
+out:
        return make_reply_message(msg, ret);
 }