Parse and vibrate using standard pattern
[platform/core/system/feedbackd.git] / src / haptic / circle.c
1 /*
2  * feedbackd
3  *
4  * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28
29 #include "core/log.h"
30 #include "core/list.h"
31 #include "haptic.h"
32 #include "standard-vibcore.h"
33
34 #define CIRCLE_ON_PATH             "/sys/class/sec/motor/motor_on"
35 #define CIRCLE_OFF_PATH            "/sys/class/sec/motor/motor_off"
36
37 #define BUF_SIZE                   8
38
39 static int fd_play = -1, fd_stop = -1;
40 static dd_list *handle_list;
41 static guint stop_timer;
42 static int unique_number;
43 static bool state = false;
44
45 static int stop_device(int device_handle);
46 static bool find_from_list(int handle)
47 {
48         dd_list *elem;
49
50         elem = DD_LIST_FIND(handle_list, (gpointer)(long)handle);
51         if (elem)
52                 return true;
53
54         return false;
55 }
56
57 static gboolean timer_cb(void *data)
58 {
59         int device_handle = (int)(long)data;
60         int ret;
61         char buf[BUF_SIZE];
62         bool found;
63
64         _I("stop vibration by timer");
65
66         found = find_from_list(device_handle);
67         if (!found)
68                 return G_SOURCE_REMOVE;
69
70         /* stop previous vibration */
71         if (fd_stop < 0) {
72                 fd_stop = open(CIRCLE_OFF_PATH, O_RDONLY);
73                 if (fd_stop < 0)
74                         return G_SOURCE_REMOVE;
75         }
76         ret = read(fd_stop, buf, BUF_SIZE);
77         if (ret < 0) {
78                 _E("failed to stop");
79                 return G_SOURCE_REMOVE;
80         }
81         stop_timer = 0;
82
83         return G_SOURCE_REMOVE;
84 }
85
86 static int get_device_count(int *count)
87 {
88         /* suppose there is just one haptic device */
89         if (count)
90                 *count = 1;
91
92         return 0;
93 }
94
95 static int open_device(int device_index, int *device_handle)
96 {
97         int n;
98         bool found = false;
99         dd_list *elem;
100
101         if (!device_handle)
102                 return -EINVAL;
103
104         /* if it is the first element */
105         n = DD_LIST_LENGTH(handle_list);
106         if (n == 0) {
107                 _I("Open");
108                 if (fd_play < 0) {
109                         fd_play = open(CIRCLE_ON_PATH, O_RDONLY);
110                         if (fd_play < 0) {
111                                 _E("Failed to open %s : %d", CIRCLE_ON_PATH, errno);
112                                 return -errno;
113                         }
114                 }
115                 if (fd_stop < 0) {
116                         fd_stop = open(CIRCLE_OFF_PATH, O_RDONLY);
117                         if (fd_stop < 0) {
118                                 _E("Failed to open %s : %d", CIRCLE_OFF_PATH, errno);
119                                 return -errno;
120                         }
121                 }
122         }
123
124         if (unique_number == INT_MAX)
125                 unique_number = 0;
126
127         while (found != true) {
128                 ++unique_number;
129                 elem = DD_LIST_FIND(handle_list, (gpointer)(long)unique_number);
130                 if (!elem)
131                         found = true;
132         }
133
134         /* add info to local list */
135         DD_LIST_APPEND(handle_list, (gpointer)(long)unique_number);
136
137         *device_handle = unique_number;
138         return 0;
139 }
140
141 static int close_device(int device_handle)
142 {
143         int r, n;
144         bool found;
145
146         found = find_from_list(device_handle);
147         if (!found)
148                 return -EINVAL;
149
150         if (fd_stop < 0) {
151                 fd_stop = open(CIRCLE_OFF_PATH, O_RDONLY);
152                 if (fd_stop < 0)
153                         return -ENODEV;
154         }
155
156         /* stop vibration */
157         r = stop_device(device_handle);
158         if (r < 0)
159                 _I("already stopped or failed to stop effect : %d", r);
160
161         /* unregister existing timer */
162         if (r >= 0) {
163                 _D("device handle %d is closed and timer deleted", device_handle);
164                 if (stop_timer) {
165                         g_source_remove(stop_timer);
166                         stop_timer = 0;
167                 }
168         }
169
170         standard_vibrate_close();
171
172         DD_LIST_REMOVE(handle_list, (gpointer)(long)device_handle);
173
174         /* if it is the last element */
175         n = DD_LIST_LENGTH(handle_list);
176         if (n == 0) {
177                 _I("Close");
178                 if (fd_play > 0) {
179                         close(fd_play);
180                         fd_play = -1;
181                 }
182                 if (fd_stop > 0) {
183                         close(fd_stop);
184                         fd_stop = -1;
185                 }
186         }
187
188         return 0;
189 }
190
191 static int vibrate_monotone(int device_handle, int duration, int feedback, int priority, int *effect_handle)
192 {
193         int ret;
194         char buf[BUF_SIZE];
195         bool found;
196
197         found = find_from_list(device_handle);
198         if (!found)
199                 return -EINVAL;
200
201         if (fd_play < 0) {
202                 fd_play = open(CIRCLE_ON_PATH, O_RDONLY);
203                 if (fd_play < 0)
204                         return -ENODEV;
205         }
206
207         /* Zero(0) is the infinitely vibration value */
208         if (duration == HAPTIC_MODULE_DURATION_UNLIMITED)
209                 duration = 0;
210
211         if (stop_timer)
212                 stop_device(device_handle);
213
214         /* play vibration */
215         ret = read(fd_play, buf, BUF_SIZE);
216         if (ret < 0) {
217                 _E("failed to play");
218                 return -errno;
219         }
220
221         /* register timer */
222         if (duration) {
223                 stop_timer = g_timeout_add(duration, timer_cb, (void *)(long)device_handle);
224
225                 if (!stop_timer)
226                         _E("Failed to add timer callback");
227         }
228
229         _D("device handle %d %dms", device_handle, duration);
230         if (effect_handle)
231                 *effect_handle = device_handle;
232
233         return 0;
234 }
235
236 static int vibrate_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
237 {
238         _E("Not support feature");
239         return -EACCES;
240 }
241
242 static int stop_device(int device_handle)
243 {
244         int ret;
245         char buf[BUF_SIZE];
246         bool found;
247
248         found = find_from_list(device_handle);
249         if (!found)
250                 return -EINVAL;
251
252         if (cur_h_data.handle > 0 && cur_h_data.handle != device_handle) {
253                 _E("Only same handle can stop current vibration");
254                 return -EPERM;
255         }
256
257         /* Remove duration_timer for vibrate_effect */
258         standard_vibrate_close();
259
260         if (fd_stop < 0) {
261                 fd_stop = open(CIRCLE_OFF_PATH, O_RDONLY);
262                 if (fd_stop < 0)
263                         return -ENODEV;
264         }
265         ret = read(fd_stop, buf, BUF_SIZE);
266         if (ret < 0) {
267                 _E("failed to stop");
268                 return -errno;
269         }
270         if (stop_timer) {
271                 g_source_remove(stop_timer);
272                 stop_timer = 0;
273         }
274
275         return 0;
276 }
277
278 static int get_device_state(int device_index, int *effect_state)
279 {
280         if (!effect_state)
281                 return -EINVAL;
282
283         *effect_state = state;
284         return 0;
285 }
286
287 static int create_effect(unsigned char *vibe_buffer, int max_bufsize, const haptic_module_effect_element *elem_arr, int max_elemcnt)
288 {
289         _E("Not support feature");
290         return -EACCES;
291 }
292
293 static int get_buffer_duration(int device_handle, const unsigned char *vibe_buffer, int *buffer_duration)
294 {
295         _E("Not support feature");
296         return -EACCES;
297 }
298
299 static int convert_binary(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path)
300 {
301         _E("Not support feature");
302         return -EACCES;
303 }
304 /* END: Haptic Module APIs */
305
306 static const struct haptic_plugin_ops default_plugin = {
307         .get_device_count    = get_device_count,
308         .open_device         = open_device,
309         .close_device        = close_device,
310         .vibrate_monotone    = vibrate_monotone,
311         .vibrate_buffer      = vibrate_buffer,
312         .vibrate_effect      = standard_vibrate_effect,
313         .is_supported        = standard_is_supported,
314         .stop_device         = stop_device,
315         .get_device_state    = get_device_state,
316         .create_effect       = create_effect,
317         .get_buffer_duration = get_buffer_duration,
318         .convert_binary      = convert_binary,
319 };
320
321 static bool is_valid(void)
322 {
323         if ((access(CIRCLE_ON_PATH, R_OK) != 0) ||
324                 (access(CIRCLE_OFF_PATH, R_OK) != 0)) {
325                 _E("Do not support wearable haptic device");
326                 state = false;
327                 return false;
328         }
329
330         standard_config_parse();
331
332         state = true;
333         _I("Support wearable haptic device");
334         return true;
335 }
336
337 static const struct haptic_plugin_ops *load(void)
338 {
339         standard_set_vib_function(&vibrate_monotone);
340         return &default_plugin;
341 }
342
343 static const struct haptic_ops std_ops = {
344         .type     = HAPTIC_STANDARD,
345         .is_valid = is_valid,
346         .load     = load,
347 };
348
349 HAPTIC_OPS_REGISTER(&std_ops)