b640e0cd390b62776cd818b109f19e2e75a91ea0
[platform/core/system/haptic-module-tizen.git] / tizen / DEVICE / src / file.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 <string.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <pthread.h>
25 #include <device-node.h>
26
27 #include "file.h"
28 #include "haptic_module_log.h"
29
30 #define BITPERMS                                50
31 #define MAX_LEVEL                               255.0f
32 #define DEFAULT_EFFECT_HANDLE   0x02
33
34 #define STATE_PLAY      0
35 #define STATE_STOP      1
36
37 #define PREDEF_HAPTIC           "haptic"
38
39 enum {
40         OPEN = 0,
41         CLOSE,
42         PLAY,
43         ONESHOT,
44         STOP,
45         LEVEL,
46 };
47
48 typedef struct {
49         int handle;
50         unsigned char **ppbuffer;
51         int channels;
52         int length;
53         int iteration;
54 } BUFFER;
55
56 static pthread_t tid;
57 static BUFFER gbuffer;
58 static int stop;
59 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
60
61 static int _check_valid_haptic_format(HapticFile *file)
62 {
63         if (file->chunkID != HEADER_ID)
64                 return -1;
65
66         if (file->fmt.chunkID != FMT_ID)
67                 return -1;
68
69         if (file->data.chunkID != DATA_ID)
70                 return -1;
71
72         return 0;
73 }
74
75 static int __haptic_predefine_action(int handle, int prop, int val)
76 {
77         char buf_pid[32];
78         char buf_prop[32];
79         char buf_handle[32];
80         char buf_val[32];
81
82         snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
83         snprintf(buf_prop, sizeof(buf_prop), "%d", prop);
84         snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
85         snprintf(buf_val, sizeof(buf_val), "%d", val);
86
87         MODULE_LOG("pid : %s(%d), prop : %s, handle : %s", buf_pid, pthread_self(), buf_prop, buf_handle);
88         return __haptic_call_predef_action(PREDEF_HAPTIC, 4, buf_pid, buf_prop, buf_handle, buf_val);
89 }
90
91 static int _create_thread(void* data, void*(*func)(void*))
92 {
93         if (tid) {
94                 MODULE_ERROR("pthread already created");
95                 return -1;
96         }
97
98         if (pthread_create(&tid, NULL, func, data) != 0) {
99                 MODULE_ERROR("pthread_create is failed : %s", strerror(errno));
100                 return -1;
101         }
102
103         return 0;
104 }
105
106 static int _cancel_thread(void)
107 {
108         int *ptr;
109         int ret;
110
111         if (!tid) {
112                 MODULE_LOG("pthread not initialized");
113                 return 0;
114         }
115
116         MODULE_LOG("cancel thread!!!");
117
118         stop = 1;
119
120         while (pthread_mutex_trylock(&mutex) == EBUSY) {
121                 usleep(100);
122                 MODULE_LOG("Already locked..");
123         }
124         __haptic_predefine_action(gbuffer.handle, STOP, NULL);
125         pthread_mutex_unlock(&mutex);
126
127         if ((ret = pthread_cancel(tid)) < 0) {
128                 MODULE_ERROR("pthread_cancel is failed : %s, ret(%d)", strerror(errno), ret);
129                 return -1;
130         }
131
132         if (pthread_join(tid, (void**)&ptr) < 0) {
133                 MODULE_ERROR("pthread_join is failed : %s", strerror(errno));
134                 return -1;
135         }
136
137         stop = 0;
138
139     tid = 0;
140         if (ptr == PTHREAD_CANCELED) {
141                 MODULE_LOG("pthread canceled");
142         } else {
143                 MODULE_LOG("pthread already finished");
144         }
145
146         return 0;
147 }
148
149 static void __clean_up(void *arg)
150 {
151         BUFFER *pbuffer = (BUFFER*)arg;
152         int i;
153
154         MODULE_LOG("clean up handler!!! : %d", tid);
155
156         for (i = 0; i < pbuffer->channels; ++i) {
157                 free(pbuffer->ppbuffer[i]);
158                 pbuffer->ppbuffer[i] = NULL;
159         }
160
161         free(pbuffer->ppbuffer);
162         pbuffer->ppbuffer = NULL;
163
164         pbuffer->channels = 0;
165         pbuffer->length = 0;
166 }
167
168 static void* __play_cb(void *arg)
169 {
170         BUFFER *pbuffer = (BUFFER*)arg;
171         int i, j, k;
172         unsigned char ch;
173         unsigned char prev = -1;
174
175         MODULE_LOG("Start thread");
176
177         pthread_cleanup_push(__clean_up, arg);
178
179         /* Copy buffer from source buffer */
180         for (i = 0; i < pbuffer->iteration; i++) {
181                 for (j = 0; j < pbuffer->length; ++j) {
182                         for (k = 0; k < pbuffer->channels; ++k) {
183                                 pthread_mutex_lock(&mutex);
184                                 if (stop) {
185                                         pthread_mutex_unlock(&mutex);
186                                         pthread_exit((void*)0);
187                                 }
188                                 ch = pbuffer->ppbuffer[k][j];
189                                 if (ch != prev) {
190                                         __haptic_predefine_action(pbuffer->handle, LEVEL, ch);
191                                         prev = ch;
192                                 }
193                                 pthread_mutex_unlock(&mutex);
194                                 usleep(BITPERMS * 1000);
195                         }
196                 }
197         }
198
199         pthread_mutex_lock(&mutex);
200         __haptic_predefine_action(gbuffer.handle, STOP, NULL);
201         pthread_mutex_unlock(&mutex);
202
203         pthread_cleanup_pop(1);
204         pthread_exit((void *)0);
205 }
206
207 int GetHapticLevelMax(int *max)
208 {
209         int status;
210         status = device_get_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_LEVEL_MAX, max);
211         if (status < 0) {
212                 MODULE_ERROR("device_get_property fail : %d", status);
213                 return -1;
214         }
215         return 0;
216 }
217
218 int InitializeBuffer(unsigned char *vibe_buffer, int max_bufsize)
219 {
220         HapticFile *pfile;
221
222         if (max_bufsize < sizeof(HapticFile)) {
223                 MODULE_ERROR("buffer lacks a memory : size(%d) minimum size(%d)",
224                                         max_bufsize, sizeof(HapticFile));
225                 return -1;
226         }
227
228         memset(vibe_buffer, 0, sizeof(char)*max_bufsize);
229
230         pfile = (HapticFile*)vibe_buffer;
231
232         pfile->chunkID = HEADER_ID;
233         pfile->chunkSize = sizeof(HapticFile);
234         pfile->fmt.chunkID = FMT_ID;
235         pfile->fmt.chunkSize = sizeof(FormatChunk);
236         pfile->fmt.wChannels = 1;
237         pfile->fmt.wBlockAlign = 1;     // wChannels*1byte
238         pfile->fmt.dwMagnitude = 99;
239         pfile->fmt.dwDuration = 0;
240         pfile->data.chunkID = DATA_ID;
241         pfile->data.chunkSize = sizeof(DataChunk);
242         return 0;
243 }
244
245 int InsertElement(unsigned char *vibe_buffer, int max_bufsize, HapticElement *element)
246 {
247         HapticFile *pfile;
248         int databuf;
249         int needbuf;
250         int duration;
251         unsigned char level;
252         int i;
253
254         pfile = (HapticFile*)vibe_buffer;
255         if (_check_valid_haptic_format(pfile) < 0) {
256                 MODULE_ERROR("this buffer is not HapticFormat");
257                 return -1;
258         }
259
260         duration = element->duration/BITPERMS;
261         level = (unsigned char)((unsigned int)element->level*MAX_LEVEL/100);
262
263         databuf = max_bufsize - sizeof(HapticFile);
264         needbuf = (pfile->fmt.dwDuration + duration)*pfile->fmt.wBlockAlign;
265         MODULE_LOG("Need buffer size : %d", needbuf);
266
267         if (databuf < needbuf) {
268                 MODULE_ERROR("buffer lacks a memory : data buf(%d), need buf(%d)", databuf, needbuf);
269                 return -1;
270         }
271
272         for (i = pfile->fmt.dwDuration; i < pfile->fmt.dwDuration+duration; i++) {
273                 pfile->data.pData[i] = level;
274         }
275
276         pfile->chunkSize = sizeof(HapticFile)+needbuf ;
277         pfile->fmt.dwDuration = pfile->fmt.dwDuration+duration;
278         pfile->data.chunkSize = sizeof(DataChunk)+needbuf;
279         return 0;
280 }
281
282 int GetBufferSize(const unsigned char *vibe_buffer, int *size)
283 {
284         HapticFile *pfile;
285
286         pfile = (HapticFile*)vibe_buffer;
287         if (_check_valid_haptic_format(pfile) < 0) {
288                 MODULE_ERROR("this buffer is not HapticFormat");
289                 return -1;
290         }
291
292         *size = pfile->chunkSize;
293         return 0;
294 }
295
296 int GetBufferDuration(const unsigned char *vibe_buffer, int *duration)
297 {
298         HapticFile *pfile;
299
300         pfile = (HapticFile*)vibe_buffer;
301         if (_check_valid_haptic_format(pfile) < 0) {
302                 MODULE_ERROR("this buffer is not HapticFormat");
303                 return -1;
304         }
305
306         *duration = pfile->fmt.dwDuration;
307         return 0;
308 }
309
310 int PlayOneshot(int handle, int duration, int level)
311 {
312         char buf_pid[32];
313         char buf_prop[32];
314         char buf_handle[32];
315         char buf_duration[32];
316         char buf_level[32];
317
318         if (_cancel_thread() < 0) {
319                 MODULE_ERROR("_cancel_thread fail");
320                 return -1;
321         }
322
323         snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
324         snprintf(buf_prop, sizeof(buf_prop), "%d", ONESHOT);
325         snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
326         snprintf(buf_duration, sizeof(buf_duration), "%d", duration);
327         snprintf(buf_level, sizeof(buf_level), "%d", level);
328
329         MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle);
330         return __haptic_call_predef_action(PREDEF_HAPTIC, 5, buf_pid, buf_prop,
331                                                                                 buf_handle, buf_duration, buf_level);
332 }
333
334 int PlayBuffer(int handle, const unsigned char *vibe_buffer, int iteration, int level)
335 {
336         HapticFile *pfile;
337         unsigned char **ppbuffer;
338         unsigned int channels, length, align;
339         unsigned char data;
340         int i, j;
341
342         pfile = (HapticFile*)vibe_buffer;
343         if (_check_valid_haptic_format(pfile) < 0) {
344                 MODULE_ERROR("this buffer is not HapticFormat");
345                 return -1;
346         }
347
348         /* Temporary code
349            This code does not support handle and multi channel concept.
350            Only this code adds to test for playing file. */
351
352         if (_cancel_thread() < 0) {
353                 MODULE_ERROR("_cancel_thread fail");
354                 return -1;
355         }
356
357         channels = pfile->fmt.wChannels;
358         align = pfile->fmt.wBlockAlign;
359         length = (pfile->data.chunkSize-8)/align;
360         MODULE_LOG("channels : %d, length : %d, align : %d, level : %d", channels, length, align, level);
361
362         /* Create buffer */
363         ppbuffer = (unsigned char**)malloc(sizeof(unsigned char*)*channels);
364         for (i = 0; i < channels; ++i) {
365                 ppbuffer[i] = (unsigned char*)malloc(sizeof(unsigned char)*length);
366                 memset(ppbuffer[i], 0, sizeof(unsigned char)*length);
367         }
368
369         /* Copy buffer from source buffer */
370         for (i = 0; i < length; ++i) {
371                 for (j = 0; j < channels; ++j) {
372                         data = (unsigned char)(pfile->data.pData[i*align+j]);
373                         ppbuffer[j][i] = (unsigned char)(data*level/0xFF);
374                         MODULE_LOG("ppbuffer[%2d][%2d] : data(%x) -> (%x)", j, i, data, ppbuffer[j][i]);
375                 }
376         }
377
378         gbuffer.handle = handle;
379         gbuffer.ppbuffer = ppbuffer;
380         gbuffer.channels = channels;
381         gbuffer.length = length;
382         gbuffer.iteration = iteration;
383
384         __haptic_predefine_action(gbuffer.handle, PLAY, NULL);
385
386         /* Start thread */
387         if (_create_thread(&gbuffer, __play_cb) < 0) {
388                 MODULE_ERROR("_create_thread fail");
389                 return -1;
390         }
391
392         return 0;
393 }
394
395 int Stop(int handle)
396 {
397         char buf_pid[32];
398         char buf_prop[32];
399         char buf_handle[32];
400
401         if (_cancel_thread() < 0) {
402                 MODULE_ERROR("_cancel_thread fail");
403                 return -1;
404         }
405
406         snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
407         snprintf(buf_prop, sizeof(buf_prop), "%d", STOP);
408         snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
409
410         MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle);
411         return __haptic_call_predef_action(PREDEF_HAPTIC, 3, buf_pid, buf_prop, buf_handle);
412 }
413
414 int OpenDevice(int handle)
415 {
416         char buf_pid[32];
417         char buf_prop[32];
418         char buf_handle[32];
419
420         snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
421         snprintf(buf_prop, sizeof(buf_prop), "%d", OPEN);
422         snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
423
424         MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle);
425         return __haptic_call_predef_action(PREDEF_HAPTIC, 3, buf_pid, buf_prop, buf_handle);
426 }
427
428 int CloseDevice(int handle)
429 {
430         char buf_pid[32];
431         char buf_prop[32];
432         char buf_handle[32];
433
434         if (_cancel_thread() < 0) {
435                 MODULE_ERROR("_cancel_thread fail");
436                 return -1;
437         }
438
439         snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
440         snprintf(buf_prop, sizeof(buf_prop), "%d", CLOSE);
441         snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
442
443         MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle);
444         return __haptic_call_predef_action(PREDEF_HAPTIC, 3, buf_pid, buf_prop, buf_handle);
445 }
446
447 int GetState(int handle, int *state)
448 {
449         if (gbuffer.handle == handle) {
450                 *state = STATE_PLAY;
451                 return 0;
452         }
453
454         *state = STATE_STOP;
455         return 0;
456 }