Parse and vibrate using standard pattern 03/196803/7
authorpr.jung <pr.jung@samsung.com>
Fri, 4 Jan 2019 08:45:25 +0000 (17:45 +0900)
committerpr.jung <pr.jung@samsung.com>
Mon, 7 Jan 2019 08:46:03 +0000 (17:46 +0900)
- Example)
- FEEDBACK_PATTERN_NOTIFICATION_1=1,J_W
- FEEDBACK_PATTERN_ALARM_1_STRONG_BUZZ=A,K_WB
- 1: one time, A: unlimit(Vibrate until stop)
- J_W, K_WB, and so on: standard pattern

- Standard pattern is defined under /usr/share/feedback/vibration/xxx
- Duration, Intensity, frequency, overdriving
- Wait time, intensity(should be 0), frequency(Not used value), overdriving(Not used value)
- Standard pattern example)
85,10000,205,0,
90,0,205,0,
105,10000,205,0,
0,end

Change-Id: I5b6d6071983c8e8f4eaf9cd6cd9981ed906662de
Signed-off-by: pr.jung <pr.jung@samsung.com>
src/haptic/circle.c
src/haptic/gpio_haptic.c
src/haptic/haptic.h
src/haptic/standard-vibcore.c
src/haptic/standard-vibcore.h
src/haptic/standard.c

index 1b63660..9c756e7 100644 (file)
@@ -320,8 +320,6 @@ static const struct haptic_plugin_ops default_plugin = {
 
 static bool is_valid(void)
 {
-       int ret;
-
        if ((access(CIRCLE_ON_PATH, R_OK) != 0) ||
                (access(CIRCLE_OFF_PATH, R_OK) != 0)) {
                _E("Do not support wearable haptic device");
@@ -329,9 +327,7 @@ static bool is_valid(void)
                return false;
        }
 
-       ret = standard_config_parse();
-       if (ret < 0)
-               _E("failed to load standard vibration configuration file : %d", ret);
+       standard_config_parse();
 
        state = true;
        _I("Support wearable haptic device");
index 45ffdac..3d91b5a 100644 (file)
@@ -348,7 +348,6 @@ static bool is_valid(void)
 {
        uint8_t result;
        peripheral_i2c_h handle;
-       int ret;
 
        if (peripheral_i2c_open(GPIO_I2C_BUS_INDEX, DRV2605L_DEFAULT_ADDR, &handle) < PERIPHERAL_ERROR_NONE) {
                _E("Failed to open I2C");
@@ -368,9 +367,7 @@ static bool is_valid(void)
                return false;
        }
 
-       ret = standard_config_parse();
-       if (ret < 0)
-               _E("failed to load standard vibration configuration file : %d", ret);
+       standard_config_parse();
 
        state = true;
        _I("Support gpio haptic device");
index 3f57723..7951d4b 100644 (file)
@@ -60,6 +60,7 @@ struct haptic_data {
        int level;
        int priority;
        bool stop;
+       int unlimit;
 };
 
 #define INVALID_HANDLE 0
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;
index a55d7d2..0d4f254 100644 (file)
@@ -22,7 +22,7 @@
 
 typedef int (*t_vibrate_monotone)(int device_handle, int duration, int feedback, int priority, int *effect_handle);
 
-int standard_config_parse(void);
+void standard_config_parse(void);
 int standard_is_supported(const char *pattern);
 int standard_vibrate_effect(int device_handle, const char *pattern, int feedback, int priority);
 int standard_set_vib_function(t_vibrate_monotone func);
index 6a42bd1..c0436fe 100644 (file)
@@ -678,9 +678,7 @@ static bool is_valid(void)
                return false;
        }
 
-       ret = standard_config_parse();
-       if (ret < 0)
-               _E("failed to load standard vibration configuration file : %d", ret);
+       standard_config_parse();
 
        _I("Support standard haptic device");
        return true;