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