resolve prevent issue about resource leak of file description
[platform/core/system/haptic-module-tizen.git] / tizen / DEVICE / src / haptic.c
1 /*
2  * haptic-module-tizen
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 <unistd.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <assert.h>
27 #include <time.h>
28 #include <vconf.h>
29
30 #include <haptic_plugin_intf.h>
31 #include "haptic_module_log.h"
32 #include "file.h"
33
34 #ifndef EXTAPI
35 #define EXTAPI __attribute__ ((visibility("default")))
36 #endif
37
38 #define DEFAULT_MOTOR_COUNT             1
39 #define DEFAULT_DEVICE_HANDLE   0x01
40 #define DEFAULT_EFFECT_HANDLE   0x02
41 #define HAPTIC_FEEDBACK_AUTO    101
42 #define HAPTIC_PLAY_FILE_EXT    ".tht"
43
44 /* START of Static Function Section */
45 static int __to_level(int feedback, int *type)
46 {
47         static int max = -1;
48         int t;
49
50         if (max == -1) {
51                 int status = GetHapticLevelMax(&max);
52                 if (status < 0) {
53                         MODULE_ERROR("GetHapticLevelMax fail : %d", status);
54                         return HAPTIC_MODULE_OPERATION_FAILED;
55                 }
56         }
57
58         t = feedback * max / HAPTIC_MODULE_FEEDBACK_MAX;
59         MODULE_LOG("feedback value is changed : %d -> %d", feedback, t);
60
61         if (type)
62                 *type = t;
63
64         return 0;
65 }
66
67 static void __trim_name(const char *file_name, char *vibe_buffer, int size)
68 {
69         int length;
70
71         assert(file_name);
72         assert(vibe_buffer);
73         assert(size > 0);
74
75         snprintf(vibe_buffer, size, "%s", file_name);
76
77         length = strlen(vibe_buffer);
78         while (vibe_buffer[--length] == ' ');
79         vibe_buffer[length + 1] = '\0';
80 }
81
82 static int __check_ext(const char *name)
83 {
84         char *ext;
85
86         assert(name);
87
88         ext = strrchr(name, '.');
89         if (ext && !strcmp(ext, HAPTIC_PLAY_FILE_EXT))
90                 return 1;
91
92         return 0;
93 }
94
95 static int __get_size(FILE *pf, const char *fname)
96 {
97         int status;
98         int size;
99
100         assert(pf);
101
102         status = fseek(pf, 0, SEEK_END);
103         if (status == -1) {
104                 MODULE_ERROR("fseek failed: %s", fname);
105                 return -1;
106         }
107
108         size = ftell(pf);
109
110         status = fseek(pf, 0, SEEK_SET);
111         if (status == -1) {
112                 MODULE_ERROR("fseek failed: %s", fname);
113                 return -1;
114         }
115
116         return size;
117 }
118
119 static unsigned char *__read_file(const char *fname)
120 {
121         int status;
122         FILE *pf;
123         long size;
124         unsigned char *vibe_buffer;
125
126         assert(fname);
127
128         pf = fopen(fname, "rb");
129         if (!pf) {
130                 MODULE_ERROR("fopen failed: %s", fname);
131                 return NULL;
132         }
133
134         size = __get_size(pf, fname);
135         if (size <= 0) {
136                 fclose(pf);
137                 return NULL;
138         }
139
140         vibe_buffer = malloc(size);
141         if (!vibe_buffer) {
142                 fclose(pf);
143                 MODULE_ERROR("buffer alloc failed");
144                 return NULL;
145         }
146
147         status = fread(vibe_buffer, 1, size, pf);
148         if (status != size) {
149                 MODULE_ERROR("fread failed: expect %d read %d", size, status);
150                 free(vibe_buffer);
151                 vibe_buffer = NULL;
152         }
153
154         fclose(pf);
155
156         return vibe_buffer;
157 }
158
159 static unsigned char* __convert_file_to_buffer(const char *file_name)
160 {
161         char fname[FILENAME_MAX];
162         int status;
163
164         __trim_name(file_name, fname, sizeof(fname));
165         status = __check_ext(fname);
166         if (!status) {
167                 MODULE_ERROR("__check_file faild");
168                 return NULL;
169         }
170
171         return __read_file(fname);
172 }
173
174 static int __save_file(const unsigned char *vibe_buferf, int size, const char *file_name)
175 {
176         int status;
177         FILE *pf;
178         int fd;
179
180         pf = fopen(file_name, "wb+");
181         if (pf == NULL) {
182                 MODULE_ERROR("To open file is failed");
183                 return HAPTIC_MODULE_OPERATION_FAILED;
184         }
185
186         status = fwrite(vibe_buferf, 1, size, pf);
187         if (status != size) {
188                 MODULE_ERROR("To write file is failed");
189                 fclose(pf);
190                 return HAPTIC_MODULE_OPERATION_FAILED;
191         }
192
193         fd = fileno(pf);
194         if (fd == -1) {
195                 MODULE_ERROR("To get file descriptor is failed");
196                 fclose(pf);
197                 return HAPTIC_MODULE_OPERATION_FAILED;
198         }
199
200         status = fsync(fd);
201         if (status == -1) {
202                 MODULE_ERROR("To be synchronized with the disk is failed");
203                 fclose(pf);
204                 return HAPTIC_MODULE_OPERATION_FAILED;
205         }
206
207         fclose(pf);
208
209         return 0;
210 }
211
212 static int __vibrate(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority)
213 {
214         int status;
215         int level;
216
217         assert(vibe_buffer);
218
219         status = __to_level(feedback, &level);
220         if (status != HAPTIC_MODULE_ERROR_NONE)
221                 return status;
222
223         status = PlayBuffer(device_handle, vibe_buffer, iteration, level);
224         if (status < 0) {
225                 MODULE_ERROR("PlayHapticBuffer fail : %d", status);
226                 return HAPTIC_MODULE_OPERATION_FAILED;
227         }
228
229         return 0;
230 }
231
232 static void *_create_handle(void)
233 {
234         return ((getpid()<<16)|time(NULL));
235 }
236 /* END of Static Function Section */
237
238
239 static int _get_device_count(int *count)
240 {
241         if (count == NULL)
242                 return HAPTIC_MODULE_INVALID_ARGUMENT;
243
244         *count = DEFAULT_MOTOR_COUNT;
245         return HAPTIC_MODULE_ERROR_NONE;
246 }
247
248 static int _open_device(int device_index, int *device_handle)
249 {
250         int handle;
251         int status;
252
253         if (device_index < HAPTIC_MODULE_DEVICE_0 || device_index > HAPTIC_MODULE_DEVICE_ALL)
254                 return HAPTIC_MODULE_INVALID_ARGUMENT;
255
256         if (device_handle == NULL)
257                 return HAPTIC_MODULE_INVALID_ARGUMENT;
258
259         handle = _create_handle();
260         status = OpenDevice(handle);
261         if (status < 0) {
262                 MODULE_ERROR("OpenHapticDevice fail :%d", status);
263                 return HAPTIC_MODULE_OPERATION_FAILED;
264         }
265
266         *device_handle = handle;
267         return HAPTIC_MODULE_ERROR_NONE;
268 }
269
270 static int _close_device(int device_handle)
271 {
272         int status;
273
274         if (device_handle < 0)
275                 return HAPTIC_MODULE_INVALID_ARGUMENT;
276
277         status = CloseDevice(device_handle);
278         if (status < 0) {
279                 MODULE_ERROR("CloseHapticDevice fail : %d", status);
280                 return HAPTIC_MODULE_OPERATION_FAILED;
281         }
282
283         return HAPTIC_MODULE_ERROR_NONE;
284 }
285
286 static int _vibrate_monotone(int device_handle, int duration, int feedback, int priority, int *effect_handle)
287 {
288         int status;
289         int level;
290
291         if (device_handle < 0)
292                 return HAPTIC_MODULE_INVALID_ARGUMENT;
293
294         if (duration < 0)
295                 return HAPTIC_MODULE_INVALID_ARGUMENT;
296
297         if (feedback < HAPTIC_MODULE_FEEDBACK_MIN || feedback > HAPTIC_MODULE_FEEDBACK_MAX)
298                 return HAPTIC_MODULE_INVALID_ARGUMENT;
299
300         if (priority < HAPTIC_MODULE_PRIORITY_MIN || priority > HAPTIC_MODULE_PRIORITY_HIGH)
301                 return HAPTIC_MODULE_INVALID_ARGUMENT;
302
303         if (effect_handle == NULL)
304                 return HAPTIC_MODULE_INVALID_ARGUMENT;
305
306         if (feedback == HAPTIC_MODULE_FEEDBACK_MIN)
307                 return HAPTIC_MODULE_ERROR_NONE;
308
309         status = __to_level(feedback, &level);
310         if (status != HAPTIC_MODULE_ERROR_NONE)
311                 return status;
312
313         status = PlayOneshot(device_handle, duration, level);
314         if (status < 0) {
315                 MODULE_ERROR("PlayOneshot fail : %d", status);
316                 return HAPTIC_MODULE_OPERATION_FAILED;
317         }
318
319         *effect_handle = DEFAULT_EFFECT_HANDLE;
320         return HAPTIC_MODULE_ERROR_NONE;
321 }
322
323 static int _vibrate_file(int device_handle, const char *file_path, int iteration, int feedback, int priority, int  *effect_handle)
324 {
325         int status;
326         unsigned char *vibe_buffer;
327
328         if (device_handle < 0)
329                 return HAPTIC_MODULE_INVALID_ARGUMENT;
330
331         if (file_path == NULL)
332                 return HAPTIC_MODULE_INVALID_ARGUMENT;
333
334         if (iteration < HAPTIC_MODULE_ITERATION_ONCE || iteration > HAPTIC_MODULE_ITERATION_INFINITE)
335                 return HAPTIC_MODULE_INVALID_ARGUMENT;
336
337         if (feedback < HAPTIC_MODULE_FEEDBACK_MIN || feedback > HAPTIC_MODULE_FEEDBACK_MAX)
338                 return HAPTIC_MODULE_INVALID_ARGUMENT;
339
340         if (priority < HAPTIC_MODULE_PRIORITY_MIN || priority > HAPTIC_MODULE_PRIORITY_HIGH)
341                 return HAPTIC_MODULE_INVALID_ARGUMENT;
342
343         if (effect_handle == NULL)
344                 return HAPTIC_MODULE_INVALID_ARGUMENT;
345
346         if (feedback == HAPTIC_MODULE_FEEDBACK_MIN)
347                 return HAPTIC_MODULE_ERROR_NONE;
348
349         vibe_buffer = __convert_file_to_buffer(file_path);
350         if (!vibe_buffer) {
351                 MODULE_ERROR("File load filed");
352                 return HAPTIC_MODULE_OPERATION_FAILED;
353         }
354
355         status = __vibrate(device_handle, vibe_buffer, iteration, feedback, priority);
356         free(vibe_buffer);
357
358         return status;
359 }
360
361 static int _vibrate_buffer(int device_handle, const unsigned char *vibe_buffer, int iteration, int feedback, int priority, int *effect_handle)
362 {
363         if (device_handle < 0)
364                 return HAPTIC_MODULE_INVALID_ARGUMENT;
365
366         if (vibe_buffer == NULL)
367                 return HAPTIC_MODULE_INVALID_ARGUMENT;
368
369         if (iteration < HAPTIC_MODULE_ITERATION_ONCE || iteration > HAPTIC_MODULE_ITERATION_INFINITE)
370                 return HAPTIC_MODULE_INVALID_ARGUMENT;
371
372         if (feedback < HAPTIC_MODULE_FEEDBACK_MIN || feedback > HAPTIC_MODULE_FEEDBACK_MAX)
373                 return HAPTIC_MODULE_INVALID_ARGUMENT;
374
375         if (priority < HAPTIC_MODULE_PRIORITY_MIN || priority > HAPTIC_MODULE_PRIORITY_HIGH)
376                 return HAPTIC_MODULE_INVALID_ARGUMENT;
377
378         if (effect_handle == NULL)
379                 return HAPTIC_MODULE_INVALID_ARGUMENT;
380
381         if (feedback == HAPTIC_MODULE_FEEDBACK_MIN)
382                 return HAPTIC_MODULE_ERROR_NONE;
383
384         return __vibrate(device_handle, vibe_buffer, iteration, feedback, priority);
385 }
386
387 static int _stop_effect(int device_handle, int effect_handle)
388 {
389         int status;
390
391         if (device_handle < 0)
392                 return HAPTIC_MODULE_INVALID_ARGUMENT;
393
394         if (effect_handle < 0)
395                 return HAPTIC_MODULE_INVALID_ARGUMENT;
396
397         status = Stop(device_handle);
398         if (status < 0) {
399                 MODULE_ERROR("StopHaptic fail : %d", status);
400                 return HAPTIC_MODULE_OPERATION_FAILED;
401         }
402
403         return HAPTIC_MODULE_ERROR_NONE;
404 }
405
406 static int _stop_all_effects(int device_handle)
407 {
408         int status;
409
410         if (device_handle < 0)
411                 return HAPTIC_MODULE_INVALID_ARGUMENT;
412
413         status = Stop(device_handle);
414         if (status < 0) {
415                 MODULE_ERROR("StopHaptic fail : %d", status);
416                 return HAPTIC_MODULE_OPERATION_FAILED;
417         }
418
419         return HAPTIC_MODULE_ERROR_NONE;
420 }
421
422 static int _pause_effect(int device_handle, int effect_handle)
423 {
424         if (device_handle < 0)
425                 return HAPTIC_MODULE_INVALID_ARGUMENT;
426
427         if (effect_handle < 0)
428                 return HAPTIC_MODULE_INVALID_ARGUMENT;
429
430         MODULE_ERROR("This device is not supported this function(%s)", __func__);
431         return HAPTIC_MODULE_NOT_SUPPORTED;
432 }
433
434 static int _resume_effect(int device_handle, int effect_handle)
435 {
436         if (device_handle < 0)
437                 return HAPTIC_MODULE_INVALID_ARGUMENT;
438
439         if (effect_handle < 0)
440                 return HAPTIC_MODULE_INVALID_ARGUMENT;
441
442         MODULE_ERROR("This device is not supported this function(%s)", __func__);
443         return HAPTIC_MODULE_NOT_SUPPORTED;
444 }
445
446 static int _get_effect_state(int device_handle, int effect_handle, int *state)
447 {
448         if (device_handle < 0)
449                 return HAPTIC_MODULE_INVALID_ARGUMENT;
450
451         if (effect_handle < 0)
452                 return HAPTIC_MODULE_INVALID_ARGUMENT;
453
454         if (state == NULL)
455                 return HAPTIC_MODULE_INVALID_ARGUMENT;
456
457         MODULE_ERROR("This device is not supported this function(%s)", __func__);
458         return HAPTIC_MODULE_NOT_SUPPORTED;
459 }
460
461 static int _create_effect(unsigned char *vibe_buffer, int max_bufsize, haptic_module_effect_element *elem_arr, int max_elemcnt)
462 {
463         int status;
464         int i;
465         HapticElement elem;
466
467         if (vibe_buffer == NULL)
468                 return HAPTIC_MODULE_INVALID_ARGUMENT;
469
470         if (max_bufsize < 0)
471                 return HAPTIC_MODULE_INVALID_ARGUMENT;
472
473         if (elem_arr == NULL)
474                 return HAPTIC_MODULE_INVALID_ARGUMENT;
475
476         if (max_elemcnt < 0)
477                 return HAPTIC_MODULE_INVALID_ARGUMENT;
478
479         status = InitializeBuffer(vibe_buffer, max_bufsize);
480         if (status < 0) {
481                 MODULE_ERROR("InitializeHapticBuffer fail: %d", status);
482                 return HAPTIC_MODULE_OPERATION_FAILED;
483         }
484
485         MODULE_LOG("effect count : %d", max_elemcnt);
486         for (i = 0; i < max_elemcnt; ++i) {
487                 elem.duration = elem_arr[i].haptic_duration;
488                 elem.level = elem_arr[i].haptic_level;
489                 MODULE_LOG("%d) duration : %d, level : %d", i, elem_arr[i].haptic_duration, elem_arr[i].haptic_level);
490
491                 status = InsertElement(vibe_buffer, max_bufsize, &elem);
492                 if (status < 0) {
493                         MODULE_ERROR("InsertHapticElement fail: %d", status);
494                         return HAPTIC_MODULE_OPERATION_FAILED;
495                 }
496         }
497
498         return HAPTIC_MODULE_ERROR_NONE;
499 }
500
501 static int _save_effect(const unsigned char *vibe_buffer, int max_bufsize, const char *file_path)
502 {
503         int status;
504         int size;
505
506         if (vibe_buffer == NULL)
507                 return HAPTIC_MODULE_INVALID_ARGUMENT;
508
509         if (max_bufsize < 0)
510                 return HAPTIC_MODULE_INVALID_ARGUMENT;
511
512         if (file_path == NULL)
513                 return HAPTIC_MODULE_INVALID_ARGUMENT;
514
515         status = GetBufferSize(vibe_buffer, &size);
516         if (status < 0) {
517                 MODULE_ERROR("GetHapticBufferSize fail: %d", status);
518                 return HAPTIC_MODULE_OPERATION_FAILED;
519         }
520
521         return __save_file(vibe_buffer, size, file_path);
522 }
523
524 static int _get_file_duration(int device_handle, const char *file_path, int *file_duration)
525 {
526         int status;
527         unsigned char *vibe_buffer;
528         int duration;
529
530         if (device_handle < 0)
531                 return HAPTIC_MODULE_INVALID_ARGUMENT;
532
533         if (file_path == NULL)
534                 return HAPTIC_MODULE_INVALID_ARGUMENT;
535
536         if (file_duration == NULL)
537                 return HAPTIC_MODULE_INVALID_ARGUMENT;
538
539         vibe_buffer = __convert_file_to_buffer(file_path);
540         if (!vibe_buffer) {
541                 MODULE_ERROR("File load filed");
542                 return HAPTIC_MODULE_OPERATION_FAILED;
543         }
544
545         status = GetBufferDuration(vibe_buffer, &duration);
546         free(vibe_buffer);
547         if (status < 0) {
548                 MODULE_ERROR("GetHapticBufferDuration fail: %d", status);
549                 return HAPTIC_MODULE_OPERATION_FAILED;
550         }
551
552         *file_duration = duration;
553         return HAPTIC_MODULE_ERROR_NONE;
554 }
555
556 static int _get_buffer_duration(int device_handle, const unsigned char *vibe_buffer, int *buffer_duration)
557 {
558         int status;
559         int duration;
560
561         if (device_handle < 0)
562                 return HAPTIC_MODULE_INVALID_ARGUMENT;
563
564         if (vibe_buffer == NULL)
565                 return HAPTIC_MODULE_INVALID_ARGUMENT;
566
567         if (buffer_duration == NULL)
568                 return HAPTIC_MODULE_INVALID_ARGUMENT;
569
570         status = GetBufferDuration(vibe_buffer, &duration);
571         if (status < 0) {
572                 MODULE_ERROR("GetHapticBufferDuration fail: %d", status);
573                 return HAPTIC_MODULE_OPERATION_FAILED;
574         }
575
576         *buffer_duration = duration;
577         return HAPTIC_MODULE_ERROR_NONE;
578 }
579
580 static int _convert_binary (void)
581 {
582         MODULE_ERROR("This device is not supported this function(%s)", __func__);
583         return HAPTIC_MODULE_NOT_SUPPORTED;
584 }
585
586 static const haptic_plugin_interface haptic_plugin_tizen = {
587         .haptic_internal_get_device_count               = _get_device_count,
588         .haptic_internal_open_device                    = _open_device,
589         .haptic_internal_close_device                   = _close_device,
590         .haptic_internal_vibrate_monotone               = _vibrate_monotone,
591         .haptic_internal_vibrate_file                   = _vibrate_file,
592         .haptic_internal_vibrate_buffer                 = _vibrate_buffer,
593         .haptic_internal_stop_effect                    = _stop_effect,
594         .haptic_internal_stop_all_effects               = _stop_all_effects,
595         .haptic_internal_pause_effect                   = _pause_effect,
596         .haptic_internal_resume_effect                  = _resume_effect,
597         .haptic_internal_get_effect_state               = _get_effect_state,
598         .haptic_internal_create_effect                  = _create_effect,
599         .haptic_internal_save_effect                    = _save_effect,
600         .haptic_internal_get_file_duration              = _get_file_duration,
601         .haptic_internal_get_buffer_duration    = _get_buffer_duration,
602         .haptic_internal_convert_binary                 = _convert_binary,
603 };
604
605 EXTAPI
606 const haptic_plugin_interface *get_haptic_plugin_interface()
607 {
608         return &haptic_plugin_tizen;
609 }