Parse and vibrate using standard pattern
[platform/core/system/feedbackd.git] / src / haptic / standard-vibcore.c
index 528875f..358942b 100644 (file)
@@ -16,7 +16,9 @@
  * limitations under the License.
  */
 
-
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <stdbool.h>
 #include <device/power.h>
 #include "haptic.h"
 #include "standard-vibcore.h"
 
-#define VIBRATION_CONF_PATH        "/usr/share/feedback/vibration.conf"
+#define FEEDBACK_BASE_PATH         "/usr/share/feedback/"
+#define STANDARD_FILE_PATH         FEEDBACK_BASE_PATH"vibration/"
+#define VIBRATION_CONF_PATH        FEEDBACK_BASE_PATH"vibration.conf"
+
+#define VALUE_MAX_LEN 10
+#define VIB_LOCK_TIMEOUT_MAX       (300000) /* 5minutes */
+
+/*
+               1,A_W or A,A_W or 250D250W250D750W
 
+               85,10000,205,0,
+               90,0,205,0,
+               105,10000,205,0,
+               0,end
+*/
 struct vibration_config {
-       char *pattern;
+       char *pattern; /* pattern name */
+       char *standard; /* assigned standard pattern name */
+       dd_list *data; /* duration_data list */
        int pattern_duration;
-       dd_list *data;
+       int len; /* string length of pattern */
+       int unlimit;
 };
 
 struct duration_data {
        int duration;
+       int intensity;
+       int frequency;
+       int overdriving;
        int wait;
 };
 
@@ -45,10 +66,217 @@ static guint duration_timer;
 
 static t_vibrate_monotone real_vibrate_monotone;
 
+static int insert_conf_data(dd_list **conf_data, struct duration_data *update)
+{
+       struct duration_data *data;
+
+       if (update->duration < 0 || update->intensity < 0 || update->frequency < 0 || update->overdriving < 0)
+               return 0;
+
+       data = (struct duration_data *)calloc(1, sizeof(struct duration_data));
+       if (!data) {
+               _E("not enough memory");
+               return -ENOMEM;
+       }
+       memcpy(data, update, sizeof(struct duration_data));
+       /* insert vibration pattern data */
+       // to debug :
+       // _D("%dD%dI%dF%dO%dW", data->duration, data->intensity, data->frequency, data->overdriving, data->wait);
+       DD_LIST_APPEND(*conf_data, data);
+       memset(update, 0, sizeof(struct duration_data));
+       return 0;
+}
+
+/* [A]xxxDxxxIxxxFxxxOxxxW format */
+static int insert_law_data_format(dd_list **conf_data, char *value)
+{
+       struct duration_data update;
+       int len = 0;
+       char *check;
+       int pattern_duration = 0;
+
+       if (!value) {
+               memset(&update, 0, sizeof(struct duration_data));
+               return insert_conf_data(conf_data, &update);
+       }
+
+       len = strlen(value);
+       do {
+               memset(&update, 0, sizeof(struct duration_data));
+               check = strchr(value, 'D');
+               if (check) {
+                       *check = '\0';
+                       update.duration = strtol(value, NULL, 10);
+                       pattern_duration += update.duration;
+                       if (pattern_duration > VIB_LOCK_TIMEOUT_MAX) {
+                               _D("reached max pattern duration");
+                               pattern_duration = VIB_LOCK_TIMEOUT_MAX;
+                       }
+                       len = len - strlen(value) - 1;
+                       value = check + 1;
+                       check = strchr(value, 'I');
+                       if (check) {
+                               *check = '\0';
+                               update.intensity = strtol(value, NULL, 10);
+                               len = len - strlen(value) - 1;
+                               value = check + 1;
+                       }
+                       check = strchr(value, 'F');
+                       if (check) {
+                               *check = '\0';
+                               update.frequency = strtol(value, NULL, 10);
+                               len = len - strlen(value) - 1;
+                               value = check + 1;
+                       }
+                       check = strchr(value, 'O');
+                       if (check) {
+                               *check = '\0';
+                               update.overdriving = strtol(value, NULL, 10);
+                               len = len - strlen(value) - 1;
+                               value = check + 1;
+                       }
+               }
+
+               check = strchr(value, 'W');
+               if (check) {
+                       *check = '\0';
+                       update.wait = strtol(value, NULL, 10);
+                       pattern_duration += update.wait;
+                       if (pattern_duration > VIB_LOCK_TIMEOUT_MAX) {
+                               _D("reached max pattern duration");
+                               pattern_duration = VIB_LOCK_TIMEOUT_MAX;
+                       }
+                       len = len - strlen(value) - 1;
+                       value = check + 1;
+               }
+               if (update.duration == 0 && update.wait == 0)
+                       break;
+               if (insert_conf_data(conf_data, &update) < 0)
+                       return -EINVAL;
+       } while (len > 0);
+
+       return pattern_duration;
+}
+
+/*
+       duration, intensity, frequency, overdriving
+       waiting duration, intensity=0, frequency, overdriving
+       85,10000,205,0,
+       90,0,205,0,
+       105,10000,205,0,
+       0,end
+*/
+static int load_standard_format(char *pattern)
+{
+       struct vibration_config *conf;
+       struct duration_data update = {0, };
+       bool packed = false;
+       int duration = 0, intensity = 0, ret = 0, count = 0, end = 2;
+       int fd;
+       char path[PATH_MAX], elem, val[VALUE_MAX_LEN] = {0, };
+
+       snprintf(path, sizeof(path), STANDARD_FILE_PATH"%s", pattern);
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return -ENOENT;
+
+       conf = (struct vibration_config *)calloc(1, sizeof(struct vibration_config));
+       if (!conf) {
+               _E("fail to alloc");
+               ret = -errno;
+               goto error_out;
+       }
+
+       conf->pattern = strdup(pattern);
+       if (!conf->pattern) {
+               _E("fail to copy %s pattern data", pattern);
+               ret = -errno;
+               goto error_out;
+       }
+       conf->len = strlen(conf->pattern) + 1;
+
+       /* make feedback pattern(xDxIxFxOxW) format from d,i,f,o, */
+       while (read(fd, &elem, 1) != 0) {
+               if (end == 0) {
+                       if (insert_conf_data(&conf->data, &update) < 0)
+                                       goto error_out;
+                       break;
+               }
+               if (elem == 'e' || elem == 'n' || elem == 'd') {
+                       end--;
+                       continue;
+               }
+               if (elem == '\n') {
+                       count = 0;
+                       continue;
+               }
+               if (elem == ',') {
+                       count++;
+                       val[ret] = '\0';
+                       ret = 0;
+                       switch (count) {
+                       case 1: /* D */
+                               duration = strtol(val, NULL, 10);
+                               conf->pattern_duration += duration;
+                               if (conf->pattern_duration > VIB_LOCK_TIMEOUT_MAX) {
+                                       _D("Reached max pattern duration");
+                                       conf->pattern_duration = VIB_LOCK_TIMEOUT_MAX;
+                               }
+                               break;
+                       case 2: /* I or W */
+                               intensity = strtol(val, NULL, 10);
+                               if (!packed) {
+                                       update.duration = duration;
+                                       update.intensity = intensity;
+                                       break;
+                               }
+                               /* Intensity should be 0 for wait(off) time */
+                               if (intensity == 0)
+                                       update.wait = duration;
+                               else
+                                       update.wait = 0;
+                               packed = false;
+
+                               if (insert_conf_data(&conf->data, &update) < 0)
+                                       goto error_out;
+                               break;
+                       case 3: /* F */
+                               if (intensity != 0)
+                                       update.frequency = strtol(val, NULL, 10);
+                               break;
+                       case 4: /* O */
+                               count = 0;
+                               if (intensity != 0) {
+                                       packed = true;
+                                       update.overdriving = strtol(val, NULL, 10);
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               } else {
+                       if (ret < (VALUE_MAX_LEN - 2))
+                               val[ret++] = elem;
+               }
+       }
+       close(fd);
+       DD_LIST_APPEND(vib_conf_list, conf);
+       return 0;
+
+error_out:
+       if (fd >= 0)
+               close(fd);
+       if (conf) {
+               if (conf->pattern)
+                       free(conf->pattern);
+               free(conf);
+       }
+       return -ENOENT;
+}
+
 static int vibration_load_config(struct parse_result *result, void *user_data)
 {
        struct vibration_config *conf;
-       struct duration_data *data;
        char *value;
        char *check;
        int len;
@@ -56,7 +284,9 @@ static int vibration_load_config(struct parse_result *result, void *user_data)
        if (!result)
                return 0;
 
-       if (!MATCH(result->section, "Vibration"))
+       if (!MATCH(result->section, "vibration") &&
+           !MATCH(result->section, "Vibration") &&
+           !MATCH(result->section, "VIBRATION"))
                return 0;
 
 
@@ -73,72 +303,95 @@ static int vibration_load_config(struct parse_result *result, void *user_data)
        conf->pattern = strdup(result->name);
        if (!conf->pattern) {
                _E("fail to copy %s pattern data", result->name);
-               free(conf);
-               return -ENOMEM;
+               goto error_out;
        }
+       conf->len = strlen(conf->pattern) + 1;
 
        value = result->value;
        len = strlen(value);
 
        if (len == 0) {
-               data = (struct duration_data *)malloc(sizeof(struct duration_data));
-               if (!data) {
-                       _E("not enough memory");
-                       free(conf->pattern);
-                       free(conf);
-                       return -ENOMEM;
-               }
-               data->duration = 0;
-               data->wait = 0;
-
-               DD_LIST_APPEND(conf->data, data);
+               if (insert_law_data_format(&conf->data, NULL) < 0)
+                       goto error_out;
                DD_LIST_APPEND(vib_conf_list, conf);
                return 0;
        }
 
-       /* value : 100D or 100D0W or 250D250W250D750W*/
-       do {
-               data = (struct duration_data *)malloc(sizeof(struct duration_data));
-               if (!data) {
-                       _E("not enough memory");
-                       free(conf->pattern);
-                       free(conf);
-                       return -ENOMEM;
+       /* Load Standard Pattern Name */
+       /* value: 1,A_W or A,A_W */
+       if ((check = strchr(value, ','))) {
+               *check = '\0';
+               if (strncmp(value, "A", 1) == 0)
+                       conf->unlimit = 1;
+               value = check + 1;
+               conf->standard = strdup(value);
+               if (!conf->standard) {
+                       _E("fail to copy standard name");
+                       goto error_out;
                }
-               data->duration = 0;
-               data->wait = 0;
+               DD_LIST_APPEND(vib_conf_list, conf);
+               return 0;
+       }
 
-               check = strchr(value, 'D');
-               if (check) {
-                       *check = '\0';
-                       data->duration = strtol(value, NULL, 10);
+       /* value : A100D or 100D0W or 250D250W250D750W */
+       /* Load Vibration Pattern Data */
+       check = strchr(value, 'A');
+       if (check) {
+               *check = '\0';
+               conf->unlimit = 1;
+               if (!value)
+                       len = len - 1;
+               else
                        len = len - strlen(value) - 1;
-                       value = check + 1;
-                       conf->pattern_duration += data->duration;
-               }
+               value = check + 1;
+       }
+       conf->pattern_duration = insert_law_data_format(&conf->data, value);
+       if (conf->pattern_duration < 0) {
+               conf->pattern_duration = 0;
+               goto error_out;
+       }
+       DD_LIST_APPEND(vib_conf_list, conf);
 
-               check = strchr(value, 'W');
-               if (check) {
-                       *check = '\0';
-                       data->wait = strtol(value, NULL, 10);
-                       len = len - strlen(value) - 1;
-                       value = check + 1;
-                       conf->pattern_duration += data->wait;
-               }
+       return 0;
 
-               DD_LIST_APPEND(conf->data, data);
-               if (data->duration == 0 && data->wait == 0)
-                       break;
-       } while (len > 0);
+error_out:
+       if (conf) {
+               if (conf->pattern)
+                       free(conf->pattern);
+               if (conf->standard)
+                       free(conf->standard);
+       }
+       return -ENOMEM;
+}
 
-       DD_LIST_APPEND(vib_conf_list, conf);
+static void load_standard_vibration_patterns(void)
+{
+       DIR *dir;
+       struct dirent *dent;
 
-       return 0;
+       dir = opendir(STANDARD_FILE_PATH);
+       if (!dir) {
+               _E("Failed to load %s Use default value!", STANDARD_FILE_PATH);
+               return;
+       }
+       while ((dent = readdir(dir))) {
+               if (dent->d_type == DT_DIR)
+                       continue;
+               load_standard_format(dent->d_name);
+       }
+       closedir(dir);
+       _D("Success to load %s", STANDARD_FILE_PATH);
 }
 
-int standard_config_parse()
+void standard_config_parse(void)
 {
-       return config_parse(VIBRATION_CONF_PATH, vibration_load_config, NULL);
+       int ret;
+
+       ret = config_parse(VIBRATION_CONF_PATH, vibration_load_config, NULL);
+       if (ret < 0)
+               _E("Failed to load %s, %d Use default value!", VIBRATION_CONF_PATH, ret);
+
+       load_standard_vibration_patterns();
 }
 
 int standard_is_supported(const char *pattern)
@@ -154,7 +407,7 @@ int standard_is_supported(const char *pattern)
        len = strlen(pattern) + 1;
        ret = 0;
        DD_LIST_FOREACH(vib_conf_list, elem, conf) {
-               if (!conf->pattern)
+               if (!conf->pattern || conf->len  != len)
                        continue;
                if (!strncmp(conf->pattern, pattern, len)) {
                        ret = true;
@@ -227,11 +480,12 @@ int standard_set_vib_function(t_vibrate_monotone func)
        return 0;
 }
 
-int standard_vibrate_effect(int device_handle, const char *pattern, int feedback, int priority)
+int standard_vibrate_effect(int device_handle, const char *requested_pattern, int feedback, int priority)
 {
        dd_list *elem;
        struct vibration_config *conf;
        size_t len;
+       char pattern[PATH_MAX];
        int ret;
 
        if (device_handle < 0)
@@ -243,12 +497,18 @@ int standard_vibrate_effect(int device_handle, const char *pattern, int feedback
                return -EPERM;
        }
 
+       snprintf(pattern, sizeof(pattern), "%s", requested_pattern);
        len = strlen(pattern) + 1;
        DD_LIST_FOREACH(vib_conf_list, elem, conf) {
-               if (!conf->pattern)
+               if (!conf->pattern || conf->len != len)
                        continue;
                if (strncmp(conf->pattern, pattern, len))
                        continue;
+               if (conf->standard) {
+                       snprintf(pattern, sizeof(pattern), "%s", conf->standard);
+                       len = strlen(pattern) + 1;
+                       continue;
+               }
 
                cur_h_data.vibration_data = conf->data;
                cur_h_data.handle = device_handle;
@@ -270,7 +530,7 @@ int standard_vibrate_effect(int device_handle, const char *pattern, int feedback
        return 0;
 }
 
-int standard_vibrate_close()
+int standard_vibrate_close(void)
 {
        cur_h_data.handle = INVALID_HANDLE;
        cur_h_data.priority = PRIORITY_MIN;