Modify feedback operation
[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
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 METHOD_OPEN                 "OpenDevice"
56 #define METHOD_CLOSE                "CloseDevice"
57 #define METHOD_VIBRATE_EFFECT       "VibrateEffect"
58 #define METHOD_STOP                 "StopDevice"
59 #define METHOD_IS_SUPPORTED         "IsSupported"
60 #define METHOD_GET_EFFECT           "GetEffect"
61
62 #define DEFAULT_DURATION            100
63 #define SIP_DURATION                60
64 #define WHITESPACE      " \t"
65
66 static int vibstatus;
67 static unsigned int v_handle;
68
69 static inline char *trim_str(char *s)
70 {
71         char *t;
72         /* left trim */
73         s += strspn(s, WHITESPACE);
74
75         /* right trim */
76         for (t = strchr(s, 0); t > s; t--)
77                 if (!strchr(WHITESPACE, t[-1]))
78                         break;
79         *t = 0;
80         return s;
81 }
82
83 inline int is_vibration_mode(void)
84 {
85         return vibstatus;
86 }
87
88 static int haptic_open(void)
89 {
90         char *arr[1];
91         char buf_index[32];
92
93         snprintf(buf_index, sizeof(buf_index), "%d", HAPTIC_DEVICE);
94         arr[0] = buf_index;
95
96         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
97                         VIBRATOR_INTERFACE_HAPTIC, METHOD_OPEN,
98                         "i", arr);
99 }
100
101 static int haptic_close(unsigned int handle)
102 {
103         char *arr[1];
104         char buf_handle[32];
105
106         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
107         arr[0] = buf_handle;
108
109         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
110                         VIBRATOR_INTERFACE_HAPTIC, METHOD_CLOSE,
111                         "u", arr);
112 }
113
114 static int haptic_is_supported(char *pattern)
115 {
116         char *arr[1];
117
118         arr[0] = pattern;
119
120         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
121                         VIBRATOR_INTERFACE_HAPTIC, METHOD_IS_SUPPORTED,
122                         "s", arr);
123 }
124
125 static int haptic_vibrate_effect(unsigned int handle,
126                                                                 char *pattern,
127                                                                 int feedback,
128                                                                 int priority)
129 {
130         char *arr[4];
131         char buf_handle[32];
132         char buf_feedback[32];
133         char buf_priority[32];
134
135         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
136         arr[0] = buf_handle;
137         arr[1] = pattern;
138         snprintf(buf_feedback, sizeof(buf_feedback), "%d", feedback);
139         arr[2] = buf_feedback;
140         snprintf(buf_priority, sizeof(buf_priority), "%d", priority);
141         arr[3] = buf_priority;
142
143         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
144                         VIBRATOR_INTERFACE_HAPTIC, METHOD_VIBRATE_EFFECT,
145                         "usii", arr);
146 }
147
148 static int haptic_vibrate_stop(unsigned int handle)
149 {
150         char *arr[1];
151         char buf_handle[32];
152
153         snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
154         arr[0] = buf_handle;
155
156         return dbus_method_sync(VIBRATOR_BUS_NAME, VIBRATOR_PATH_HAPTIC,
157                         VIBRATOR_INTERFACE_HAPTIC, METHOD_STOP,
158                         "u", arr);
159 }
160
161 static int get_priority(feedback_pattern_e pattern)
162 {
163         if (pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD)
164                 return HAPTIC_PRIORITY_MIN;
165
166         return HAPTIC_PRIORITY_MIDDLE;
167 }
168
169 static void vibrator_init(void)
170 {
171         int ret;
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) {
212                         _E("Not initialized"); //LCOV_EXCL_LINE
213                         return -ENOENT;
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");
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");
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) {
278                         _E("Not initialized"); //LCOV_EXCL_LINE
279                         return -ENOENT;
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         bool ret = true;
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) {
310                         _E("Not initialized"); //LCOV_EXCL_LINE
311                         return -ENOENT;
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");
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");
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 used function-Internal APIs TODO Will make iUTC
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);