* 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;
};
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;
if (!result)
return 0;
- if (!MATCH(result->section, "Vibration"))
+ if (!MATCH(result->section, "vibration") &&
+ !MATCH(result->section, "Vibration") &&
+ !MATCH(result->section, "VIBRATION"))
return 0;
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)
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;
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)
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;
return 0;
}
-int standard_vibrate_close()
+int standard_vibrate_close(void)
{
cur_h_data.handle = INVALID_HANDLE;
cur_h_data.priority = PRIORITY_MIN;