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