98bc613f23264d3c727203f59bd1bac48fd7407d
[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 <errno.h>
23 #include <pthread.h>
24 #include <device-node.h>
25
26 #include "file.h"
27 #include "haptic_module_log.h"
28
29 #define BITPERMS                                50
30 #define MAX_LEVEL                               255.0f
31 #define DEFAULT_EFFECT_HANDLE   0x02
32
33 enum {
34         PLAY_HAPTIC = 0,
35         STOP_HAPTIC,
36         LEVEL_HAPTIC,
37 };
38
39 typedef struct {
40         unsigned char **ppbuffer;
41         int channels;
42         int length;
43         int iteration;
44 } BUFFER;
45
46 static pthread_t tid;
47 static BUFFER gbuffer;
48
49 static int _check_valid_haptic_format(HapticFile *file)
50 {
51         if (file->chunkID != HEADER_ID)
52                 return -1;
53
54         if (file->fmt.chunkID != FMT_ID)
55                 return -1;
56
57         if (file->data.chunkID != DATA_ID)
58                 return -1;
59
60         return 0;
61 }
62
63 static int _create_thread(void* data, void*(*func)(void*))
64 {
65         if (tid) {
66                 MODULE_ERROR("pthread already created");
67                 return -1;
68         }
69
70         if (pthread_create(&tid, NULL, func, data) != 0) {
71                 MODULE_ERROR("pthread_create is failed : %s", strerror(errno));
72                 return -1;
73         }
74
75         return 0;
76 }
77
78 static int _cancel_thread(void)
79 {
80         int *ptr = NULL;
81         int ret = -1;
82
83         if (!tid) {
84                 MODULE_LOG("pthread not initialized");
85                 return 0;
86         }
87
88         if ((ret = pthread_cancel(tid)) < 0) {
89                 MODULE_ERROR("pthread_cancel is failed : %s, ret(%d)", strerror(errno), ret);
90                 return -1;
91         }
92
93         if (pthread_join(tid, (void**)&ptr) < 0) {
94         tid = 0;
95                 MODULE_ERROR("pthread_join is failed : %s", strerror(errno));
96                 return -1;
97         }
98
99     tid = 0;
100         if (ptr == PTHREAD_CANCELED) {
101                 MODULE_LOG("pthread canceled");
102         } else {
103                 MODULE_LOG("pthread already finished");
104         }
105
106         return 0;
107 }
108
109 static void __clean_up(void *arg)
110 {
111         BUFFER *pbuffer = (BUFFER*)arg;
112         int i = 0;
113
114         MODULE_LOG("clean up handler!!! : %d", tid);
115         __haptic_predefine_action(STOP_HAPTIC, NULL);
116
117         for (i = 0; i < pbuffer->channels; ++i) {
118                 free(pbuffer->ppbuffer[i]);
119                 pbuffer->ppbuffer[i] = NULL;
120         }
121
122         free(pbuffer->ppbuffer);
123         pbuffer->ppbuffer = NULL;
124
125         pbuffer->channels = 0;
126         pbuffer->length = 0;
127 }
128
129 static void* __play_cb(void *arg)
130 {
131         BUFFER *pbuffer = (BUFFER*)arg;
132         int i = -1, j = -1, k = -1, value = -1;
133         unsigned char ch;
134         unsigned char prev = -1;
135
136         MODULE_LOG("Start thread");
137
138         pthread_cleanup_push(__clean_up, arg);
139
140         __haptic_predefine_action(PLAY_HAPTIC, NULL);
141
142         /* Copy buffer from source buffer */
143         for (i = 0; i < pbuffer->iteration; i++) {
144                 for (j = 0; j < pbuffer->length; ++j) {
145                         for (k = 0; k < pbuffer->channels; ++k) {
146                                 ch = pbuffer->ppbuffer[k][j];
147                                 if (ch != prev) {
148                                         __haptic_predefine_action(LEVEL_HAPTIC, ch);
149                                         prev = ch;
150                                 }
151                                 usleep(BITPERMS * 1000);
152                         }
153                 }
154         }
155
156         pthread_cleanup_pop(1);
157         pthread_exit((void *)0);
158 }
159
160 int GetHapticLevelMax(int *max)
161 {
162         int status = -1;
163         status = device_get_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_LEVEL_MAX, max);
164         if (status < 0) {
165                 MODULE_ERROR("device_get_property fail : %d", status);
166                 return -1;
167         }
168         return 0;
169 }
170
171 int SetHapticEnable(int value)
172 {
173         int status = -1;
174         status = device_set_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_ENABLE, value);
175         if (status < 0) {
176                 MODULE_ERROR("device_set_property fail : %d", status);
177                 return -1;
178         }
179         return 0;
180 }
181
182 int SetHapticLevel(int value)
183 {
184         int status = -1;
185         status = device_set_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_LEVEL, value);
186         if (status < 0) {
187                 MODULE_ERROR("device_set_property fail : %d", status);
188                 return -1;
189         }
190         return 0;
191 }
192
193 int SetHapticOneshot(int value)
194 {
195         int status = -1;
196         status = device_set_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_ONESHOT, value);
197         if (status < 0) {
198                 MODULE_ERROR("device_set_property fail : %d", status);
199                 return -1;
200         }
201         return 0;
202 }
203
204 int InitializeHapticBuffer(unsigned char *vibe_buffer, int max_bufsize)
205 {
206         HapticFile *pfile = NULL;
207
208         if (max_bufsize < sizeof(HapticFile)) {
209                 MODULE_ERROR("buffer lacks a memory : size(%d) minimum size(%d)", max_bufsize, sizeof(HapticFile));
210                 return -1;
211         }
212
213         MODULE_LOG("FormatChunk : %d, DataChunk : %d, HapticFile : %d", sizeof(FormatChunk), sizeof(DataChunk), sizeof(HapticFile));
214         MODULE_LOG("Bufsize : %d", max_bufsize);
215
216         memset(vibe_buffer, 0, sizeof(char)*max_bufsize);
217
218         pfile = (HapticFile*)vibe_buffer;
219
220         pfile->chunkID = HEADER_ID;
221         pfile->chunkSize = sizeof(HapticFile);
222         pfile->fmt.chunkID = FMT_ID;
223         pfile->fmt.chunkSize = sizeof(FormatChunk);
224         pfile->fmt.wChannels = 1;
225         pfile->fmt.wBlockAlign = 1;     // wChannels*1byte
226         pfile->fmt.dwMagnitude = 99;
227         pfile->fmt.dwDuration = 0;
228         pfile->data.chunkID = DATA_ID;
229         pfile->data.chunkSize = sizeof(DataChunk);
230         return 0;
231 }
232
233 int InsertHapticElement(unsigned char *vibe_buffer, int max_bufsize, HapticElement *element)
234 {
235         HapticFile *pfile = NULL;
236         int databuf = -1;
237         int needbuf = -1;
238         int duration;
239         unsigned char level;
240         int i = -1;
241
242         pfile = (HapticFile*)vibe_buffer;
243         if (_check_valid_haptic_format(pfile) < 0) {
244                 MODULE_ERROR("this buffer is not HapticFormat");
245                 return -1;
246         }
247
248         duration = element->duration/BITPERMS;
249         level = (unsigned char)((unsigned int)element->level*MAX_LEVEL/100);
250
251         databuf = max_bufsize - sizeof(HapticFile);
252         needbuf = (pfile->fmt.dwDuration + duration)*pfile->fmt.wBlockAlign;
253         MODULE_LOG("Need buffer size : %d", needbuf);
254
255         if (databuf < needbuf) {
256                 MODULE_ERROR("buffer lacks a memory : data buf(%d), need buf(%d)", databuf, needbuf);
257                 return -1;
258         }
259
260         for (i = pfile->fmt.dwDuration; i < pfile->fmt.dwDuration+duration; i++) {
261                 pfile->data.pData[i] = level;
262         }
263
264         pfile->chunkSize = sizeof(HapticFile)+needbuf ;
265         pfile->fmt.dwDuration = pfile->fmt.dwDuration+duration;
266         pfile->data.chunkSize = sizeof(DataChunk)+needbuf;
267         return 0;
268 }
269
270 int GetHapticBufferSize(const unsigned char *vibe_buffer, int *size)
271 {
272         HapticFile *pfile = NULL;
273
274         pfile = (HapticFile*)vibe_buffer;
275         if (_check_valid_haptic_format(pfile) < 0) {
276                 MODULE_ERROR("this buffer is not HapticFormat");
277                 return -1;
278         }
279
280         *size = pfile->chunkSize;
281         return 0;
282 }
283
284 int GetHapticBufferDuration(const unsigned char *vibe_buffer, int *duration)
285 {
286         HapticFile *pfile = NULL;
287
288         pfile = (HapticFile*)vibe_buffer;
289         if (_check_valid_haptic_format(pfile) < 0) {
290                 MODULE_ERROR("this buffer is not HapticFormat");
291                 return -1;
292         }
293
294         *duration = pfile->fmt.dwDuration;
295         return 0;
296 }
297
298 int PlayHapticBuffer(const unsigned char *vibe_buffer, int iteration, int level, int *effect_handle)
299 {
300         HapticFile *pfile = NULL;
301         unsigned char **ppbuffer = NULL;
302         unsigned int channels, length, align;
303         unsigned char data;
304         int i = -1, j = -1;
305
306         pfile = (HapticFile*)vibe_buffer;
307         if (_check_valid_haptic_format(pfile) < 0) {
308                 MODULE_ERROR("this buffer is not HapticFormat");
309                 return -1;
310         }
311
312         /* Temporary code
313            This code does not support handle and multi channel concept.
314            Only this code adds to test for playing file. */
315
316         if (_cancel_thread() < 0) {
317                 MODULE_ERROR("_cancel_thread fail");
318                 return -1;
319         }
320
321         channels = pfile->fmt.wChannels;
322         align = pfile->fmt.wBlockAlign;
323         length = (pfile->data.chunkSize-8)/align;
324         MODULE_LOG("channels : %d, length : %d, align : %d, level : %d", channels, length, align, level);
325
326         /* Create buffer */
327         ppbuffer = (unsigned char**)malloc(sizeof(unsigned char*)*channels);
328         for (i = 0; i < channels; ++i) {
329                 ppbuffer[i] = (unsigned char*)malloc(sizeof(unsigned char)*length);
330                 memset(ppbuffer[i], 0, sizeof(unsigned char)*length);
331         }
332
333         /* Copy buffer from source buffer */
334         for (i = 0; i < length; ++i) {
335                 for (j = 0; j < channels; ++j) {
336                         data = (unsigned char)(pfile->data.pData[i*align+j]);
337                         ppbuffer[j][i] = (unsigned char)(data*level/0xFF);
338                         MODULE_LOG("ppbuffer[%2d][%2d] : data(%x) -> (%x)", j, i, data, ppbuffer[j][i]);
339                 }
340         }
341
342         gbuffer.ppbuffer = ppbuffer;
343         gbuffer.channels = channels;
344         gbuffer.length = length;
345         gbuffer.iteration = iteration;
346
347         /* Start thread */
348         if (_create_thread(&gbuffer, __play_cb) < 0) {
349                 MODULE_ERROR("_create_thread fail");
350                 return -1;
351         }
352
353         *effect_handle = DEFAULT_EFFECT_HANDLE;
354         return 0;
355 }
356
357 int CloseHapticDevice(void)
358 {
359         if (_cancel_thread() < 0) {
360                 MODULE_ERROR("_cancel_thread fail");
361                 return -1;
362         }
363         return 0;
364 }