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