#define LONG(x) ((x)/BITS_PER_LONG)
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+#define MAX_DATA 16
+#define FF_INFO_MAGIC 0xDEADFEED
+
+struct ff_info_header {
+ unsigned int magic;
+ int iteration;
+ int ff_info_data_count;
+};
+
+struct ff_info_data {
+ int type;/* play, stop etc */
+ int magnitude; /* strength */
+ int length; /* in ms for stop, play*/
+};
+
+struct ff_info_buffer {
+ struct ff_info_header header;
+ struct ff_info_data data[MAX_DATA];
+};
struct ff_info {
- unsigned int id;
+ int handle;
Ecore_Timer *timer;
struct ff_effect effect;
+ struct ff_info_buffer *ffinfobuffer;
+ int currentindex;
};
static int ff_fd;
static dd_list *ff_list;
+static dd_list *handle_list;
static char ff_path[PATH_MAX];
+static int unique_number;
+
+struct ff_info *read_from_list(int handle)
+{
+ struct ff_info *temp;
+ dd_list *elem;
+
+ DD_LIST_FOREACH(ff_list, elem, temp) {
+ if (temp->handle == handle)
+ return temp;
+ }
+ return NULL;
+}
+
+/* for debug */
+static void print_list(void)
+{
+ struct ff_info *temp;
+ dd_list *elem;
+ int i = 0;
+
+ DD_LIST_FOREACH(ff_list, elem, temp)
+ _D("[%d] %x", i++, temp);
+}
static bool check_valid_handle(struct ff_info *info)
{
return true;
}
+static bool check_fd(int *fd)
+{
+ int ffd;
+
+ if (*fd > 0)
+ return true;
+
+ ffd = open(ff_path, O_RDWR);
+ if (!ffd)
+ return false;
+
+ *fd = ffd;
+ return true;
+}
+
static int ff_stop(int fd, struct ff_effect *effect);
static Eina_Bool timer_cb(void *data)
{
- struct ff_info *info = (struct ff_info*)data;
+ struct ff_info *info = (struct ff_info *)data;
if (!info)
return ECORE_CALLBACK_CANCEL;
if (test_bit(FF_RUMBLE, features))
_D("%s type : rumble", ev_path);
- if (test_bit(FF_PERIODIC, features)) {
+ if (test_bit(FF_RUMBLE, features)) {
memcpy(ff_path, ev_path, strlen(ev_path));
close(fd);
closedir(dir);
if (!effect)
return -EINVAL;
- /* initialize member variables in effect struct */
- effect->type = FF_PERIODIC;
+ /*Only rumble supported as of now*/
+ effect->type = FF_RUMBLE;
+ effect->replay.length = 0;
+ effect->replay.delay = 10;
effect->id = -1;
- effect->u.periodic.waveform = FF_SQUARE;
- effect->u.periodic.period = 0.1*0x100; /* 0.1 second */
- effect->u.periodic.magnitude = 0; /* temporary value */
- effect->u.periodic.offset = 0;
- effect->u.periodic.phase = 0;
- effect->direction = 0x4000; /* Along X axis */
- effect->u.periodic.envelope.attack_length = 0;
- effect->u.periodic.envelope.attack_level = 0;
- effect->u.periodic.envelope.fade_length = 0;
- effect->u.periodic.envelope.fade_level = 0;
- effect->trigger.button = 0;
- effect->trigger.interval = 0;
- effect->replay.length = 0; /* temporary value */
- effect->replay.delay = 0;
+ effect->u.rumble.strong_magnitude = 0x100;
+ effect->u.rumble.weak_magnitude = 0x50;
return 0;
}
static int ff_play(int fd, struct ff_effect *effect)
{
struct input_event play;
+ int ret;
- if (fd < 0 || !effect)
+ if (fd < 0 || !effect) {
+ if (fd < 0)
+ _E("fail to check fd");
+ else
+ _E("fail to check effect");
return -EINVAL;
+ }
/* upload an effect */
- if (ioctl(fd, EVIOCSFF, effect) == -1)
+ if (ioctl(fd, EVIOCSFF, effect) == -1) {
+ _E("fail to ioctl");
return -errno;
+ }
/* play vibration*/
play.type = EV_FF;
play.code = effect->id;
play.value = 1; /* 1 : PLAY, 0 : STOP */
- if (write(fd, (const void*)&play, sizeof(play)) == -1)
+ ret = write(fd, (const void *)&play, sizeof(play));
+ if (ret == -1) {
+ _E("fail to write");
return -errno;
+ }
return 0;
}
static int ff_stop(int fd, struct ff_effect *effect)
{
struct input_event stop;
+ int ret;
if (fd < 0)
return -EINVAL;
stop.type = EV_FF;
stop.code = effect->id;
stop.value = 0; /* 1 : PLAY, 0 : STOP */
-
- if (write(fd, (const void*)&stop, sizeof(stop)) == -1)
+ ret = write(fd, (const void *)&stop, sizeof(stop));
+ if (ret == -1)
return -errno;
/* removing an effect from the device */
return 0;
}
-static int create_unique_id(void)
-{
- static int i = 0;
- return i++; /* TODO: overflow */
-}
-
-static struct ff_info *get_element_from_list(int id)
-{
- dd_list *elem;
- struct ff_info *info;
-
- if (id < 0)
- return NULL;
-
- /* find matched element */
- DD_LIST_FOREACH(ff_list, elem, info) {
- if (info->id == id)
- return info;
- }
-
- return NULL;
-}
-
/* START: Haptic Module APIs */
static int get_device_count(int *count)
{
{
struct ff_info *info;
int n;
+ bool found = false;
+ dd_list *elem;
if (!device_handle)
return -EINVAL;
return -errno;
}
- /* create unique id */
- info->id = create_unique_id();
-
/* initialize ff_effect structure */
ff_init_effect(&info->effect);
+ if (unique_number == INT_MAX)
+ unique_number = 0;
+
+ while (found != true) {
+ ++unique_number;
+ elem = DD_LIST_FIND(handle_list, unique_number);
+ if (!elem)
+ found = true;
+ }
+
+ info->handle = unique_number;
+
/* add info to local list */
DD_LIST_APPEND(ff_list, info);
+ DD_LIST_APPEND(handle_list, info->handle);
- *device_handle = info->id;
+ *device_handle = info->handle;
return 0;
}
struct ff_info *info;
int r, n;
- info = get_element_from_list(device_handle);
+ info = read_from_list(device_handle);
if (!info)
return -EINVAL;
+ if (!check_valid_handle(info))
+ return -EINVAL;
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
/* stop vibration */
r = ff_stop(ff_fd, &info->effect);
if (r < 0)
/* unregister existing timer */
if (r >= 0 && info->timer) {
+ _D("device handle %d is closed and timer deleted", device_handle);
ecore_timer_del(info->timer);
info->timer = NULL;
}
+ DD_LIST_REMOVE(handle_list, info->handle);
+
+ safe_free(info->ffinfobuffer);
/* remove info from local list */
DD_LIST_REMOVE(ff_list, info);
safe_free(info);
struct ff_info *info;
int ret;
- info = get_element_from_list(device_handle);
- if (!info)
+ info = read_from_list(device_handle);
+ if (!info) {
+ _E("fail to check list");
+ return -EINVAL;
+ }
+
+ if (!check_valid_handle(info)) {
+ _E("fail to check handle");
return -EINVAL;
+ }
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
/* Zero(0) is the infinitely vibration value */
if (duration == HAPTIC_MODULE_DURATION_UNLIMITED)
duration = 0;
+ /* unregister existing timer */
+ if (info->timer) {
+ ff_stop(ff_fd, &info->effect);
+ ecore_timer_del(info->timer);
+ info->timer = NULL;
+ }
+
/* set effect as per arguments */
+ ff_init_effect(&info->effect);
ret = ff_set_effect(&info->effect, duration, feedback);
if (ret < 0) {
_E("failed to set effect(duration:%d, feedback:%d) : %d",
/* play effect as per arguments */
ret = ff_play(ff_fd, &info->effect);
if (ret < 0) {
- _E("failed to play haptic effect(id:%d) : %d",
- info->effect.id, ret);
+ _E("failed to play haptic effect(fd:%d id:%d) : %d",
+ ff_fd, info->effect.id, ret);
return ret;
}
- /* unregister existing timer */
- if (info->timer) {
- ecore_timer_del(info->timer);
- info->timer = NULL;
- }
-
/* register timer */
if (duration) {
info->timer = ecore_timer_add(duration/1000.f, timer_cb, info);
_E("Failed to add timer callback");
}
- _D("effect id : %d", info->effect.id);
+ _D("device handle %d effect id : %d %dms", device_handle, info->effect.id, duration);
if (effect_handle)
*effect_handle = info->effect.id;
return 0;
}
+static Eina_Bool _buffer_play(void *cbdata)
+{
+ struct ff_info *info = (struct ff_info *)cbdata;
+ struct ff_info_header *header = &info->ffinfobuffer->header;
+ struct ff_info_data *data = info->ffinfobuffer->data;
+ int index = info->currentindex;
+ int play_type = (index < header->ff_info_data_count) ? data[index].type : 0;
+ int length = (index < header->ff_info_data_count) ? data[index].length : 1;
+ int ret;
+
+ ff_set_effect(&info->effect, length, 1);
+ if (play_type != 0) {
+ _D("Going to play for %d ms", length);
+ ret = ff_play(ff_fd, &info->effect);
+ if (ret < 0)
+ _D("Failed to play the effect %d", ret);
+ } else {
+ _D("Going to stop for %d ms", length);
+ ret = ff_stop(ff_fd, &info->effect);
+ if (ret < 0)
+ _D("Failed to stop the effect %d", ret);
+ }
+
+ if (info->currentindex < header->ff_info_data_count) {
+ info->currentindex++;
+ info->timer = ecore_timer_add(length/1000.0f, _buffer_play, info);
+ } else {
+ --header->iteration;
+ if (header->iteration > 0) {
+ info->currentindex = 0;
+ info->timer = ecore_timer_add(0.0, _buffer_play, info);
+ } else
+ info->timer = NULL;
+ }
+
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static void print_buffer(const unsigned char *vibe_buffer)
+{
+ struct ff_info_buffer fb;
+ int i = 0;
+ memcpy(&fb.header, vibe_buffer, sizeof(struct ff_info_header));
+ memcpy(&fb.data, (unsigned char *)vibe_buffer+sizeof(struct ff_info_header),
+ sizeof(struct ff_info_data) * fb.header.ff_info_data_count);
+ _D("\nMagic %x\niteration %d\ncount %d\n", fb.header.magic,
+ fb.header.iteration, fb.header.ff_info_data_count);
+
+ for (i = 0; i < fb.header.ff_info_data_count; i++)
+ _D("type %d\nmagn 0x%x\nlen %d\n", fb.data[i].type,
+ fb.data[i].magnitude, fb.data[i].length);
+}
+
+static int vibrate_custom_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
+{
+ struct ff_info *info;
+ struct ff_info_header *header;
+ struct ff_info_data *data;
+
+ info = read_from_list(device_handle);
+ if (!info)
+ return -EINVAL;
+
+ if (!check_valid_handle(info))
+ return -EINVAL;
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
+ if (!info->ffinfobuffer)
+ info->ffinfobuffer = (struct ff_info_buffer *)calloc(sizeof(struct ff_info_buffer), 1);
+ if (!info->ffinfobuffer)
+ return -ENOMEM;
+
+ header = &info->ffinfobuffer->header;
+ data = info->ffinfobuffer->data;
+
+ memcpy(header, vibe_buffer, sizeof(struct ff_info_header));
+ if (header->ff_info_data_count < 0 || header->ff_info_data_count > MAX_DATA)
+ return -EINVAL;
+
+ memcpy(data, vibe_buffer+sizeof(struct ff_info_header), sizeof(struct ff_info_data) * header->ff_info_data_count);
+
+ info->currentindex = 0;
+ if (info->timer)
+ ecore_timer_del(info->timer);
+
+ if (header->iteration > 0)
+ _buffer_play(info);
+
+ return 0;
+}
+
static int vibrate_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
{
- /* temporary code */
- return vibrate_monotone(device_handle, 300, feedback, priority, effect_handle);
+ int magic = 0;
+
+ if (!device_handle)
+ return -EINVAL;
+
+ if (vibe_buffer)
+ magic = *(int *)vibe_buffer;
+
+ if (magic == FF_INFO_MAGIC) {
+ print_buffer(vibe_buffer);
+ return vibrate_custom_buffer(device_handle, vibe_buffer, iteration, feedback, priority, effect_handle);
+ } else
+ return vibrate_monotone(device_handle, 300, feedback, priority, effect_handle);
}
static int stop_device(int device_handle)
struct ff_info *info;
int r;
- info = get_element_from_list(device_handle);
+ info = read_from_list(device_handle);
if (!info)
return -EINVAL;
+ if (!check_valid_handle(info))
+ return -EINVAL;
+
+ if (!check_fd(&ff_fd))
+ return -ENODEV;
+
/* stop effect */
r = ff_stop(ff_fd, &info->effect);
if (r < 0)
#define TEMP_BUFFER_SIZE (64*1024)
/* START of Static Function Section */
-static unsigned char* convert_file_to_buffer(const char *file_name, int *size)
+static unsigned char *convert_file_to_buffer(const char *file_name, int *size)
{
FILE *pf;
long file_size;
if (file_size < 0)
goto error;
- pdata = (unsigned char*)malloc(file_size);
+ pdata = (unsigned char *)malloc(file_size);
if (!pdata)
goto error;
return -1;
switch (setting_fb_level) {
- case SETTING_VIB_FEEDBACK_LEVEL0 : return HAPTIC_FEEDBACK_0;
- case SETTING_VIB_FEEDBACK_LEVEL1 : return HAPTIC_FEEDBACK_1;
- case SETTING_VIB_FEEDBACK_LEVEL2 : return HAPTIC_FEEDBACK_2;
- case SETTING_VIB_FEEDBACK_LEVEL3 : return HAPTIC_FEEDBACK_3;
- case SETTING_VIB_FEEDBACK_LEVEL4 : return HAPTIC_FEEDBACK_4;
- case SETTING_VIB_FEEDBACK_LEVEL5 : return HAPTIC_FEEDBACK_5;
+ case SETTING_VIB_FEEDBACK_LEVEL0:
+ return HAPTIC_FEEDBACK_0;
+ case SETTING_VIB_FEEDBACK_LEVEL1:
+ return HAPTIC_FEEDBACK_1;
+ case SETTING_VIB_FEEDBACK_LEVEL2:
+ return HAPTIC_FEEDBACK_2;
+ case SETTING_VIB_FEEDBACK_LEVEL3:
+ return HAPTIC_FEEDBACK_3;
+ case SETTING_VIB_FEEDBACK_LEVEL4:
+ return HAPTIC_FEEDBACK_4;
+ case SETTING_VIB_FEEDBACK_LEVEL5:
+ return HAPTIC_FEEDBACK_5;
default:
break;
}
int ret;
/* check if handle is valid */
- if (device_handle < 0) {
- _E("Invalid parameter : device_handle(0)");
+ if (device_handle == NULL) {
+ _E("Invalid parameter : device_handle");
return HAPTIC_ERROR_INVALID_PARAMETER;
}
}
API int haptic_vibrate_monotone_with_detail(haptic_device_h device_handle,
- int duration,
- haptic_feedback_e feedback,
- haptic_priority_e priority,
- haptic_effect_h *effect_handle)
+ int duration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle)
{
char str_handle[32];
char str_duration[32];
int ret;
/* check if handle is valid */
- if (device_handle < 0) {
- _E("Invalid parameter : device_handle(0)");
+ if (device_handle == NULL) {
+ _E("Invalid parameter : device_handle");
return HAPTIC_ERROR_INVALID_PARAMETER;
}
if (ret < 0)
return HAPTIC_ERROR_OPERATION_FAILED;
- if (effect_handle)
+ if (effect_handle != NULL)
*effect_handle = (haptic_effect_h)ret;
return HAPTIC_ERROR_NONE;
}
API int haptic_vibrate_file_with_detail(haptic_device_h device_handle,
- const char *file_path,
- haptic_iteration_e iteration,
- haptic_feedback_e feedback,
- haptic_priority_e priority,
- haptic_effect_h *effect_handle)
+ const char *file_path,
+ haptic_iteration_e iteration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle)
{
char *vibe_buffer;
int size, ret;
}
API int haptic_vibrate_buffer_with_detail(haptic_device_h device_handle,
- const unsigned char *vibe_buffer,
- haptic_iteration_e iteration,
- haptic_feedback_e feedback,
- haptic_priority_e priority,
- haptic_effect_h *effect_handle)
+ const unsigned char *vibe_buffer,
+ haptic_iteration_e iteration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle)
{
return haptic_vibrate_buffers_with_detail(device_handle,
vibe_buffer,
}
API int haptic_vibrate_buffers_with_detail(haptic_device_h device_handle,
- const unsigned char *vibe_buffer,
- int size,
- haptic_iteration_e iteration,
- haptic_feedback_e feedback,
- haptic_priority_e priority,
- haptic_effect_h *effect_handle)
+ const unsigned char *vibe_buffer,
+ int size,
+ haptic_iteration_e iteration,
+ haptic_feedback_e feedback,
+ haptic_priority_e priority,
+ haptic_effect_h *effect_handle)
{
char str_handle[32];
char str_iteration[32];
int ret;
/* check if handle is valid */
- if (device_handle < 0) {
- _E("Invalid parameter : device_handle(0)");
+ if (device_handle == NULL) {
+ _E("Invalid parameter : device_handle");
return HAPTIC_ERROR_INVALID_PARAMETER;
}
arr[0] = str_handle;
bytes.size = size;
bytes.data = vibe_buffer;
- arr[2] = (char*)&bytes;
+ arr[2] = (char *)&bytes;
snprintf(str_iteration, sizeof(str_iteration), "%d", iteration);
arr[3] = str_iteration;
snprintf(str_feedback, sizeof(str_feedback), "%d", feedback);
if (ret < 0)
return HAPTIC_ERROR_OPERATION_FAILED;
- if (effect_handle >= 0)
+ if (effect_handle != NULL)
*effect_handle = (haptic_effect_h)ret;
return HAPTIC_ERROR_NONE;
int ret;
/* check if handle is valid */
- if (device_handle < 0) {
- _E("Invalid parameter : device_handle(0)");
+ if (device_handle == NULL) {
+ _E("Invalid parameter : device_handle");
return HAPTIC_ERROR_INVALID_PARAMETER;
}
int ret;
/* check if handle is valid */
- if (device_handle < 0) {
- _E("Invalid parameter : device_handle(0)");
+ if (device_handle == NULL) {
+ _E("Invalid parameter : device_handle");
return HAPTIC_ERROR_INVALID_PARAMETER;
}
}
API int haptic_create_effect(unsigned char *vibe_buffer,
- int max_bufsize,
- haptic_effect_element_s *elem_arr,
- int max_elemcnt)
+ int max_bufsize,
+ haptic_effect_element_s *elem_arr,
+ int max_elemcnt)
{
DBusError err;
DBusMessage *msg;
snprintf(str_bufsize, sizeof(str_bufsize), "%d", max_bufsize);
arr[0] = str_bufsize;
bytes.size = sizeof(haptic_effect_element_s)*max_elemcnt;
- bytes.data = (unsigned char*)elem_arr;
- arr[2] = (char*)&bytes;
+ bytes.data = (unsigned char *)elem_arr;
+ arr[2] = (char *)&bytes;
snprintf(str_elemcnt, sizeof(str_elemcnt), "%d", max_elemcnt);
arr[3] = str_elemcnt;
}
API int haptic_save_effect(const unsigned char *vibe_buffer,
- int max_bufsize,
- const char *file_path)
+ int max_bufsize,
+ const char *file_path)
{
struct stat buf;
int size, ret;
int ret;
/* check if handle is valid */
- if (device_handle < 0) {
- _E("Invalid parameter : device_handle(0)");
+ if (device_handle == NULL) {
+ _E("Invalid parameter : device_handle");
return HAPTIC_ERROR_INVALID_PARAMETER;
}
arr[0] = str_handle;
bytes.size = size;
bytes.data = vibe_buffer;
- arr[2] = (char*)&bytes;
+ arr[2] = (char *)&bytes;
/* request to deviced to open haptic device */
ret = dbus_method_sync(DEVICED_BUS_NAME,
bytes.size = max_bufsize;
bytes.data = vibe_buffer;
- arr[1] = (char*)&bytes;
- arr[2] = (char*)file_path;
+ arr[1] = (char *)&bytes;
+ arr[2] = (char *)file_path;
/* request to deviced to open haptic device */
ret = dbus_method_sync(DEVICED_BUS_NAME,