942cca80f3542799d3b5fb8f2d9fb233f84efcc2
[platform/core/system/libsvi.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 #include <system_info.h>
29
30 #include "feedback.h"
31 #include "profiles.h"
32 #include "parser.h"
33 #include "devices.h"
34 #include "log.h"
35 #include "dbus.h"
36
37 #define HAPTIC_DEVICE                           0
38
39 enum haptic_iteration {
40         HAPTIC_ITERATION_ONCE = 1,
41         HAPTIC_ITERATION_INFINITE = 256,
42 };
43
44 #define METHOD_OPEN                 "OpenDevice"
45 #define METHOD_CLOSE                "CloseDevice"
46 #define METHOD_VIBRATE_PATTERN      "VibratePattern"
47 #define METHOD_STOP                 "StopDevice"
48 #define METHOD_IS_SUPPORTED         "IsSupported"
49 #define METHOD_GET_EFFECT           "GetEffect"
50
51 #define DEFAULT_DURATION            100
52 #define SIP_DURATION                60
53 #define WHITESPACE                  " \t"
54
55 #define VIBRATION_FEATURE              "http://tizen.org/feature/feedback.vibration"
56
57 static int vibstatus;
58 static unsigned int v_handle;
59
60 static inline char *trim_str(char *s)
61 {
62         char *t;
63         /* left trim */
64         s += strspn(s, WHITESPACE);
65
66         /* right trim */
67         for (t = strchr(s, 0); t > s; t--)
68                 if (!strchr(WHITESPACE, t[-1]))
69                         break;
70         *t = 0;
71         return s;
72 }
73
74 inline int is_vibration_mode(void)
75 {
76         return vibstatus;
77 }
78
79 static int haptic_open(void)
80 {
81         char *arr[1];
82         char buf_index[32];
83
84         snprintf(buf_index, sizeof(buf_index), "%d", HAPTIC_DEVICE);
85         arr[0] = buf_index;
86
87         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
88                         VIBRATOR_INTERFACE_HAPTIC, METHOD_OPEN,
89                         "i", arr);
90 }
91
92 static int haptic_close(unsigned int handle)
93 {
94         char *arr[1];
95         char buf_handle[32];
96
97         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
98         arr[0] = buf_handle;
99
100         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
101                         VIBRATOR_INTERFACE_HAPTIC, METHOD_CLOSE,
102                         "u", arr);
103 }
104
105 static int haptic_is_supported(char *pattern)
106 {
107         char *arr[1];
108
109         arr[0] = pattern;
110
111         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
112                         VIBRATOR_INTERFACE_HAPTIC, METHOD_IS_SUPPORTED,
113                         "s", arr);
114 }
115
116 static int haptic_vibrate_effect(unsigned int handle,
117                                                                 char *pattern,
118                                                                 int feedback,
119                                                                 int priority)
120 {
121         char *arr[4];
122         char buf_handle[32];
123         char buf_feedback[32];
124         char buf_priority[32];
125
126         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
127         arr[0] = buf_handle;
128         arr[1] = pattern;
129         snprintf(buf_feedback, sizeof(buf_feedback), "%d", feedback);
130         arr[2] = buf_feedback;
131         snprintf(buf_priority, sizeof(buf_priority), "%d", priority);
132         arr[3] = buf_priority;
133
134         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
135                         VIBRATOR_INTERFACE_HAPTIC, METHOD_VIBRATE_PATTERN,
136                         "usii", arr);
137 }
138
139 static int haptic_vibrate_stop(unsigned int handle)
140 {
141         char *arr[1];
142         char buf_handle[32];
143
144         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
145         arr[0] = buf_handle;
146
147         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
148                         VIBRATOR_INTERFACE_HAPTIC, METHOD_STOP,
149                         "u", arr);
150 }
151
152 static int get_priority(feedback_pattern_e pattern)
153 {
154         if (profile->get_priority)
155                 return profile->get_priority(pattern);
156         return PRIORITY_MIDDLE;
157 }
158
159 static void vibrator_init(void)
160 {
161         int ret;
162         bool haptic_avail;
163
164         ret = system_info_get_platform_bool(VIBRATION_FEATURE, &haptic_avail);
165         if (ret < 0) {
166                 v_handle = -ENOTSUP;
167                 return;
168         } else if (ret == 0 && !haptic_avail) {
169                 v_handle = -ENOTSUP;
170                 return;
171         }
172
173         /* Vibration Init */
174         ret = haptic_open();
175         if (ret == -EACCES || ret == -ECOMM || ret == -EPERM) {
176                 _E("haptic_open ==> FAIL!! : %d", ret); //LCOV_EXCL_LINE
177                 v_handle = -EACCES; //LCOV_EXCL_LINE System Error
178                 return; //LCOV_EXCL_LINE System Error
179         }
180         if (ret < 0) {
181                 _E("haptic_open ==> FAIL!! : %d", ret); //LCOV_EXCL_LINE
182                 v_handle = -ENOTSUP; //LCOV_EXCL_LINE System Error
183                 return; //LCOV_EXCL_LINE System Error
184         }
185
186         /* Set vibration handle */
187         v_handle = (unsigned int)ret;
188 }
189
190 static void vibrator_exit(void)
191 {
192         int ret;
193
194         if ((int)v_handle > 0) {
195                 ret = haptic_close(v_handle);
196                 if (ret < 0)
197                         _E("haptic_close is failed : %d", ret); //LCOV_EXCL_LINE
198                 v_handle = 0;
199         }
200
201 }
202
203 static int vibrator_play(feedback_pattern_e pattern)
204 {
205         char *temp;
206         char *data;
207         int ret;
208         int level;
209
210         if ((int)v_handle <= 0) {
211                 if (v_handle == 0) { //LCOV_EXCL_LINE System Error
212                         _E("Not initialized"); //LCOV_EXCL_LINE
213                         return -ENOENT; //LCOV_EXCL_LINE System Error
214                 }
215                 _E("Not supported vibration"); //LCOV_EXCL_LINE
216                 return v_handle; //LCOV_EXCL_LINE System Error
217         }
218
219         if (vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) < 0) {
220                 _D("fail to get vibration status, will work as turning off"); //LCOV_EXCL_LINE
221                 vibstatus = 0;
222         }
223
224         if (vibstatus == 0 && profile->get_always_alert_case &&
225             !profile->get_always_alert_case(FEEDBACK_TYPE_VIBRATION, pattern))  {
226                 _D("Vibration condition is OFF (vibstatus : %d)", vibstatus); //LCOV_EXCL_LINE
227                 return 0;
228         }
229
230         if (vibstatus && profile->get_always_off_case &&
231             profile->get_always_off_case(FEEDBACK_TYPE_VIBRATION, pattern)) {
232                 _D("Vibration always off condition"); //LCOV_EXCL_LINE
233                 return 0;
234         }
235
236         if (pattern <= FEEDBACK_PATTERN_NONE ||
237             pattern >= profile->max_pattern) {
238                 _E("Not supported vibration pattern"); //LCOV_EXCL_LINE
239                 return -ENOTSUP;
240         }
241
242         if (profile->get_strength_type)
243                 level = profile->get_strength_type(FEEDBACK_TYPE_VIBRATION, pattern);
244         else
245                 level = DEFAULT_VIB_LEVEL * HAPTIC_FEEDBACK_STEP;
246
247         temp = strdup(profile->str_pattern(pattern));
248         data = trim_str(temp);
249         if (!data) {
250                 free(temp);
251                 _E("Not supported vibration pattern"); //LCOV_EXCL_LINE
252                 return -ENOTSUP;
253         }
254
255         _D("pattern : %s", data);
256
257         ret = haptic_vibrate_effect(v_handle, data, level, get_priority(pattern));
258
259         if (ret < 0) {
260                 _E("fail to play vibration"); //LCOV_EXCL_LINE
261                 free(temp);
262                 if (ret == -ECOMM || ret == -ENOTSUP)
263                         return ret; //LCOV_EXCL_LINE System Error
264                 return -EPERM;
265         }
266
267         _D("Play success! Data is %s", data);
268         free(temp);
269         return 0;
270 }
271
272 static int vibrator_stop(void)
273 {
274         int ret;
275
276         if ((int)v_handle <= 0) {
277                 if (v_handle == 0) { //LCOV_EXCL_LINE System Error
278                         _E("Not initialized"); //LCOV_EXCL_LINE
279                         return -ENOENT; //LCOV_EXCL_LINE System Error
280                 }
281                 _E("Not supported vibration"); //LCOV_EXCL_LINE
282                 return v_handle; //LCOV_EXCL_LINE System Error
283         }
284
285         /* stop haptic device */
286         ret = haptic_vibrate_stop(v_handle);
287         if (ret < 0) {
288                 _E("haptic_vibrate_stop is failed"); //LCOV_EXCL_LINE
289                 if (ret == -ECOMM)
290                         return ret; //LCOV_EXCL_LINE System Error
291                 return -EPERM;
292         }
293
294         return 0;
295 }
296
297 static int vibrator_is_supported(int pattern, bool *supported)
298 {
299         char *temp;
300         char *data;
301         int ret = 0;
302
303         if (!supported) {
304                 _E("Invalid parameter : supported(NULL)"); //LCOV_EXCL_LINE
305                 return -EINVAL;
306         }
307
308         if ((int)v_handle <= 0) {
309                 if (v_handle == 0) { //LCOV_EXCL_LINE System Error
310                         _E("Not initialized"); //LCOV_EXCL_LINE
311                         return -ENOENT; //LCOV_EXCL_LINE System Error
312                 }
313                 _E("Not supported vibration"); //LCOV_EXCL_LINE
314                 *supported = false; //LCOV_EXCL_LINE System Error
315                 return v_handle;
316         }
317
318         if (pattern <= FEEDBACK_PATTERN_NONE ||
319             pattern >= profile->max_pattern) {
320                 _E("Not supported vibration pattern"); //LCOV_EXCL_LINE
321                 *supported = false;
322                 return 0;
323         }
324
325         /* get vibration data */
326         temp = strdup(profile->str_pattern(pattern));
327         data = trim_str(temp);
328         if (!data) {
329                 free(temp);
330                 *supported = false;
331                 return 0;
332         }
333
334         ret = haptic_is_supported(data);
335         free(temp);
336         if (ret < 0) {
337                 _E("fail to get support information"); //LCOV_EXCL_LINE
338                 if (ret == -ECOMM)
339                         return ret;
340                 return -EPERM;
341         }
342
343         _D("is_supported : %d", ret);
344         *supported = ret;
345         return 0;
346 }
347
348 //LCOV_EXCL_START Not Supported Feature
349 static int vibrator_get_path(feedback_pattern_e pattern, char *buf, unsigned int buflen)
350 {
351         return 0;
352 }
353
354 static int vibrator_set_path(feedback_pattern_e pattern, char *path)
355 {
356         return 0;
357 }
358 //LCOV_EXCL_STOP
359
360 static const struct device_ops vibrator_device_ops = {
361         .type = FEEDBACK_TYPE_VIBRATION,
362         .name = "Vibrator",
363         .init = vibrator_init,
364         .exit = vibrator_exit,
365         .play = vibrator_play,
366         .stop = vibrator_stop,
367         .is_supported = vibrator_is_supported,
368         .get_path = vibrator_get_path,
369         .set_path = vibrator_set_path,
370 };
371
372 DEVICE_OPS_REGISTER(&vibrator_device_ops);