tizen 2.4 release
[framework/system/libfeedback.git] / src / vibrator.c
1 /*
2  * libfeedback
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <limits.h>
26 #include <vconf.h>
27 #include <sys/stat.h>
28
29 #include "feedback-ids.h"
30 #include "profiles.h"
31 #include "parser.h"
32 #include "devices.h"
33 #include "log.h"
34 #include "dbus.h"
35 #ifdef MOBILE
36 #include "feedback-ids-mobile.h"
37 #endif
38 #ifdef WEARABLE
39 #include "feedback-ids-wearable.h"
40 #endif
41
42 #define HAPTIC_DEVICE                           0
43
44 enum haptic_priority {
45         HAPTIC_PRIORITY_MIN = 0,
46         HAPTIC_PRIORITY_MIDDLE,
47         HAPTIC_PRIORITY_HIGH,
48 };
49
50 enum haptic_iteration {
51         HAPTIC_ITERATION_ONCE = 1,
52         HAPTIC_ITERATION_INFINITE = 256,
53 };
54
55 #define VIBRATION_CONF_FILE         "/usr/share/feedback/vibration.conf"
56
57 #define METHOD_OPEN                 "OpenDevice"
58 #define METHOD_CLOSE                "CloseDevice"
59 #define METHOD_VIBRATE_MONOTONE     "VibrateMonotone"
60 #define METHOD_VIBRATE_BUFFER       "VibrateBuffer"
61 #define METHOD_STOP                 "StopDevice"
62
63 #define DEFAULT_DURATION            100
64 #define SIP_DURATION                60
65
66 static int vibstatus;
67 static unsigned int v_handle;
68 static struct feedback_config_info vib_info = {
69         .name = "Vibration",
70 };
71
72 static char *get_data(feedback_pattern_e pattern)
73 {
74         char *data;
75
76         if (pattern <= FEEDBACK_PATTERN_NONE ||
77             pattern >= profile->max_pattern)
78                 return NULL;
79
80         if (vib_info.data[pattern].changed)
81                 data = vib_info.data[pattern].changed;
82         else
83                 data = vib_info.data[pattern].origin;
84
85         return data;
86 }
87
88 inline int is_vibration_mode(void)
89 {
90         return vibstatus;
91 }
92
93 static int haptic_open(void)
94 {
95         char *arr[1];
96         char buf_index[32];
97
98         snprintf(buf_index, sizeof(buf_index), "%d", HAPTIC_DEVICE);
99         arr[0] = buf_index;
100
101         return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_HAPTIC,
102                         DEVICED_INTERFACE_HAPTIC, METHOD_OPEN,
103                         "i", arr);
104 }
105
106 static int haptic_close(unsigned int handle)
107 {
108         char *arr[1];
109         char buf_handle[32];
110
111         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
112         arr[0] = buf_handle;
113
114         return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_HAPTIC,
115                         DEVICED_INTERFACE_HAPTIC, METHOD_CLOSE,
116                         "u", arr);
117 }
118
119 static int haptic_vibrate_buffer(unsigned int handle,
120                                                                 const unsigned char *buffer,
121                                                                 int size,
122                                                                 int iteration,
123                                                                 int feedback,
124                                                                 int priority)
125 {
126         char *arr[6];
127         char buf_handle[32];
128         char buf_iteration[32];
129         char buf_feedback[32];
130         char buf_priority[32];
131         struct dbus_byte bytes;
132
133         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
134         arr[0] = buf_handle;
135         bytes.size = size;
136         bytes.data = buffer;
137         arr[2] = (char *)&bytes;
138         snprintf(buf_iteration, sizeof(buf_iteration), "%d", iteration);
139         arr[3] = buf_iteration;
140         snprintf(buf_feedback, sizeof(buf_feedback), "%d", feedback);
141         arr[4] = buf_feedback;
142         snprintf(buf_priority, sizeof(buf_priority), "%d", priority);
143         arr[5] = buf_priority;
144
145         return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_HAPTIC,
146                         DEVICED_INTERFACE_HAPTIC, METHOD_VIBRATE_BUFFER,
147                         "uayiii", arr);
148 }
149
150 static int haptic_vibrate_monotone(unsigned int handle,
151                                                                 int duration,
152                                                                 int feedback,
153                                                                 int priority)
154 {
155         char *arr[4];
156         char buf_handle[32];
157         char buf_duration[32];
158         char buf_feedback[32];
159         char buf_priority[32];
160
161         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
162         arr[0] = buf_handle;
163         snprintf(buf_duration, sizeof(buf_duration), "%d", duration);
164         arr[1] = buf_duration;
165         snprintf(buf_feedback, sizeof(buf_feedback), "%d", feedback);
166         arr[2] = buf_feedback;
167         snprintf(buf_priority, sizeof(buf_priority), "%d", priority);
168         arr[3] = buf_priority;
169
170         return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_HAPTIC,
171                         DEVICED_INTERFACE_HAPTIC, METHOD_VIBRATE_MONOTONE,
172                         "uiii", arr);
173 }
174
175 static int haptic_vibrate_stop(unsigned int handle)
176 {
177         char *arr[1];
178         char buf_handle[32];
179
180         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
181         arr[0] = buf_handle;
182
183         return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_HAPTIC,
184                         DEVICED_INTERFACE_HAPTIC, METHOD_STOP,
185                         "u", arr);
186 }
187
188 static unsigned char *convert_file_to_buffer(const char *file_name, int *size)
189 {
190         FILE *pf;
191         long file_size;
192         unsigned char *pdata = NULL;
193
194         if (!file_name)
195                 return NULL;
196
197         /* Get File Stream Pointer */
198         pf = fopen(file_name, "rb");
199         if (!pf) {
200                 _E("fopen failed : %s", strerror(errno));
201                 return NULL;
202         }
203
204         if (fseek(pf, 0, SEEK_END))
205                 goto error;
206
207         file_size = ftell(pf);
208         if (fseek(pf, 0, SEEK_SET))
209                 goto error;
210
211         if (file_size < 0)
212                 goto error;
213
214         pdata = (unsigned char *)malloc(file_size);
215         if (!pdata)
216                 goto error;
217
218         if (fread(pdata, 1, file_size, pf) != file_size)
219                 goto err_free;
220
221         fclose(pf);
222         *size = file_size;
223         return pdata;
224
225 err_free:
226         free(pdata);
227
228 error:
229         fclose(pf);
230
231         _E("failed to convert file to buffer (%s)", strerror(errno));
232         return NULL;
233 }
234
235 static int get_priority(feedback_pattern_e pattern)
236 {
237         if (pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD)
238                 return HAPTIC_PRIORITY_MIN;
239
240         return HAPTIC_PRIORITY_MIDDLE;
241 }
242
243 static int get_duration(feedback_pattern_e pattern)
244 {
245         if (pattern == FEEDBACK_PATTERN_SIP)
246                 return SIP_DURATION;
247 #ifdef MOBILE
248         if (pattern == (feedback_pattern_e)FEEDBACK_PATTERN_MOBILE_SIP_BACKSPACE)
249                 return SIP_DURATION;
250 #endif
251 #ifdef WEARABLE
252         if (pattern == (feedback_pattern_e)FEEDBACK_PATTERN_WEARABLE_SIP_BACKSPACE)
253                 return SIP_DURATION;
254 #endif
255         return DEFAULT_DURATION;
256 }
257
258 static void vibrator_init(void)
259 {
260         int ret;
261
262         /* Vibration Init */
263         ret = haptic_open();
264         if (ret < 0) {
265                 _E("haptic_open ==> FAIL!! : %d", ret);
266                 v_handle = -ENOTSUP;
267                 return;
268         }
269
270         /* Set vibration handle */
271         v_handle = (unsigned int)ret;
272
273         /* get vibration data */
274         feedback_load_config(VIBRATION_CONF_FILE, &vib_info);
275 }
276
277 static void vibrator_exit(void)
278 {
279         int ret;
280
281         if (v_handle > 0) {
282                 ret = haptic_close(v_handle);
283                 if (ret < 0)
284                         _E("haptic_close is failed : %d", ret);
285                 v_handle = 0;
286         }
287
288         /* free vibration data */
289         feedback_free_config(&vib_info);
290 }
291
292 static int vibrator_play(feedback_pattern_e pattern)
293 {
294         struct stat buf;
295         char *data;
296         unsigned char *pbuf;
297         int size;
298         int ret;
299         int level;
300         int duration;
301
302         if (!v_handle) {
303                 _E("Not initialize");
304                 return -EPERM;
305         }
306
307         if (v_handle == -ENOTSUP) {
308                 _E("Not supported vibration");
309                 return -ENOTSUP;
310         }
311
312         if (vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) < 0) {
313                 _D("fail to get vibration status, will work as turning off");
314                 vibstatus = 0;
315         }
316
317         if (vibstatus == 0 && profile->get_always_alert_case &&
318             !profile->get_always_alert_case(FEEDBACK_TYPE_VIBRATION, pattern))  {
319                 _D("Vibration condition is OFF (vibstatus : %d)", vibstatus);
320                 return 0;
321         }
322
323         if (vibstatus && profile->get_always_off_case &&
324             profile->get_always_off_case(FEEDBACK_TYPE_VIBRATION, pattern)) {
325                 _D("Vibration always off condition");
326                 return 0;
327         }
328
329         if (profile->get_strength_type)
330                 level = profile->get_strength_type(FEEDBACK_TYPE_VIBRATION, pattern);
331         else
332                 level = DEFAULT_VIB_LEVEL * HAPTIC_FEEDBACK_STEP;
333
334         /* get vibration data */
335         data = get_data(pattern);
336         if (!data) {
337                 _E("Not supported vibration pattern");
338                 return -ENOTSUP;
339         }
340
341         /* if it has a file path */
342         if (!stat(data, &buf)) {
343                 pbuf = convert_file_to_buffer(data, &size);
344                 if (!pbuf) {
345                         _E("fail to convert file to buffer");
346                         return -EPERM;
347                 }
348
349                 ret = haptic_vibrate_buffer(v_handle, pbuf, size,
350                                 HAPTIC_ITERATION_ONCE,
351                                 level, get_priority(pattern));
352                 free(pbuf);
353         } else {
354                 duration = get_duration(pattern);
355                 ret = haptic_vibrate_monotone(v_handle, duration,
356                                 level, get_priority(pattern));
357         }
358
359         if (ret < 0) {
360                 _E("fail to play vibration");
361                 if (ret == -ECOMM)
362                         return ret;
363                 return -EPERM;
364         }
365
366         _D("Play success! Data is %s", data);
367         return 0;
368 }
369
370 static int vibrator_stop(void)
371 {
372         int ret;
373
374         if (!v_handle) {
375                 _E("Not initialize");
376                 return -EPERM;
377         }
378
379         if (v_handle == -ENOTSUP) {
380                 _E("Not supported vibration");
381                 return -ENOTSUP;
382         }
383
384         /* stop haptic device */
385         ret = haptic_vibrate_stop(v_handle);
386         if (ret < 0) {
387                 _E("haptic_vibrate_stop is failed");
388                 if (ret == -ECOMM)
389                         return ret;
390                 return -EPERM;
391         }
392
393         return 0;
394 }
395
396 static int vibrator_is_supported(int pattern, bool *supported)
397 {
398         char *data;
399         bool ret = true;
400
401         if (!supported) {
402                 _E("Invalid parameter : supported(NULL)");
403                 return -EINVAL;
404         }
405
406         if (!v_handle) {
407                 _E("Not initialize");
408                 return -EPERM;
409         }
410
411         if (v_handle == -ENOTSUP) {
412                 _E("Not supported vibration");
413                 *supported = false;
414                 return 0;
415         }
416
417         /* get vibration data */
418         data = get_data(pattern);
419         if (!data) {
420                 _E("Not supported vibration pattern");
421                 ret = false;
422         }
423
424         *supported = ret;
425         return 0;
426 }
427
428 static int vibrator_get_path(feedback_pattern_e pattern, char *buf, unsigned int buflen)
429 {
430         char *data;
431         int ret = 0;
432
433         if (!buf || buflen <= 0)
434                 return -EINVAL;
435
436         /* get vibration data */
437         data = get_data(pattern);
438         if (!data) {
439                 _E("This pattern(%s) in vibrator type is not supported to play",
440                                 profile->str_pattern[pattern]);
441                 data = "NULL";
442                 ret = -ENOENT;
443         }
444
445         snprintf(buf, buflen, "%s", data);
446         return ret;
447 }
448
449 static int vibrator_set_path(feedback_pattern_e pattern, char *path)
450 {
451         struct stat buf;
452
453         /*
454          * check the path is valid
455          * if path is null, reset vibration path
456          */
457         if (!path) {
458                 if (vib_info.data[pattern].changed) {
459                         free(vib_info.data[pattern].changed);
460                         vib_info.data[pattern].changed = NULL;
461                 }
462                 return 0;
463         }
464
465         if (path && stat(path, &buf)) {
466                 _E("%s is not presents", path);
467                 return -errno;
468         }
469
470         if (vib_info.data[pattern].changed) {
471                 free(vib_info.data[pattern].changed);
472                 vib_info.data[pattern].changed = NULL;
473         }
474
475         /* if path is NULL, this pattern set to default file */
476         if (path)
477                 vib_info.data[pattern].changed = strdup(path);
478
479         _D("The file of pattern(%s) is changed to [%s]",
480                         profile->str_pattern[pattern], path);
481         return 0;
482 }
483
484 static const struct device_ops vibrator_device_ops = {
485         .type = FEEDBACK_TYPE_VIBRATION,
486         .name = "Vibrator",
487         .init = vibrator_init,
488         .exit = vibrator_exit,
489         .play = vibrator_play,
490         .stop = vibrator_stop,
491         .is_supported = vibrator_is_supported,
492         .get_path = vibrator_get_path,
493         .set_path = vibrator_set_path,
494 };
495
496 DEVICE_OPS_REGISTER(&vibrator_device_ops);