3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <device-node.h>
27 #include "haptic_module_log.h"
30 #define MAX_LEVEL 255.0f
31 #define DEFAULT_EFFECT_HANDLE 0x02
40 unsigned char **ppbuffer;
47 static BUFFER gbuffer;
49 static int _check_valid_haptic_format(HapticFile *file)
51 if (file->chunkID != HEADER_ID)
54 if (file->fmt.chunkID != FMT_ID)
57 if (file->data.chunkID != DATA_ID)
63 static int _create_thread(void* data, void*(*func)(void*))
66 MODULE_ERROR("pthread already created");
70 if (pthread_create(&tid, NULL, func, data) != 0) {
71 MODULE_ERROR("pthread_create is failed : %s", strerror(errno));
78 static int _cancel_thread(void)
84 MODULE_LOG("pthread not initialized");
88 if ((ret = pthread_cancel(tid)) < 0) {
89 MODULE_ERROR("pthread_cancel is failed : %s, ret(%d)", strerror(errno), ret);
93 if (pthread_join(tid, (void**)&ptr) < 0) {
95 MODULE_ERROR("pthread_join is failed : %s", strerror(errno));
100 if (ptr == PTHREAD_CANCELED) {
101 MODULE_LOG("pthread canceled");
103 MODULE_LOG("pthread already finished");
109 static void __clean_up(void *arg)
111 BUFFER *pbuffer = (BUFFER*)arg;
114 MODULE_LOG("clean up handler!!! : %d", tid);
115 __haptic_predefine_action(STOP_HAPTIC, NULL);
117 for (i = 0; i < pbuffer->channels; ++i) {
118 free(pbuffer->ppbuffer[i]);
119 pbuffer->ppbuffer[i] = NULL;
122 free(pbuffer->ppbuffer);
123 pbuffer->ppbuffer = NULL;
125 pbuffer->channels = 0;
129 static void* __play_cb(void *arg)
131 BUFFER *pbuffer = (BUFFER*)arg;
132 int i = -1, j = -1, k = -1, value = -1;
134 unsigned char prev = -1;
136 MODULE_LOG("Start thread");
138 pthread_cleanup_push(__clean_up, arg);
140 __haptic_predefine_action(PLAY_HAPTIC, NULL);
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];
148 __haptic_predefine_action(LEVEL_HAPTIC, ch);
151 usleep(BITPERMS * 1000);
156 pthread_cleanup_pop(1);
157 pthread_exit((void *)0);
160 int GetHapticLevelMax(int *max)
163 status = device_get_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_LEVEL_MAX, max);
165 MODULE_ERROR("device_get_property fail : %d", status);
171 int SetHapticEnable(int value)
174 status = device_set_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_ENABLE, value);
176 MODULE_ERROR("device_set_property fail : %d", status);
182 int SetHapticLevel(int value)
185 status = device_set_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_LEVEL, value);
187 MODULE_ERROR("device_set_property fail : %d", status);
193 int SetHapticOneshot(int value)
196 status = device_set_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_ONESHOT, value);
198 MODULE_ERROR("device_set_property fail : %d", status);
204 int InitializeHapticBuffer(unsigned char *vibe_buffer, int max_bufsize)
206 HapticFile *pfile = NULL;
208 if (max_bufsize < sizeof(HapticFile)) {
209 MODULE_ERROR("buffer lacks a memory : size(%d) minimum size(%d)", max_bufsize, sizeof(HapticFile));
213 MODULE_LOG("FormatChunk : %d, DataChunk : %d, HapticFile : %d", sizeof(FormatChunk), sizeof(DataChunk), sizeof(HapticFile));
214 MODULE_LOG("Bufsize : %d", max_bufsize);
216 memset(vibe_buffer, 0, sizeof(char)*max_bufsize);
218 pfile = (HapticFile*)vibe_buffer;
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);
233 int InsertHapticElement(unsigned char *vibe_buffer, int max_bufsize, HapticElement *element)
235 HapticFile *pfile = NULL;
242 pfile = (HapticFile*)vibe_buffer;
243 if (_check_valid_haptic_format(pfile) < 0) {
244 MODULE_ERROR("this buffer is not HapticFormat");
248 duration = element->duration/BITPERMS;
249 level = (unsigned char)((unsigned int)element->level*MAX_LEVEL/100);
251 databuf = max_bufsize - sizeof(HapticFile);
252 needbuf = (pfile->fmt.dwDuration + duration)*pfile->fmt.wBlockAlign;
253 MODULE_LOG("Need buffer size : %d", needbuf);
255 if (databuf < needbuf) {
256 MODULE_ERROR("buffer lacks a memory : data buf(%d), need buf(%d)", databuf, needbuf);
260 for (i = pfile->fmt.dwDuration; i < pfile->fmt.dwDuration+duration; i++) {
261 pfile->data.pData[i] = level;
264 pfile->chunkSize = sizeof(HapticFile)+needbuf ;
265 pfile->fmt.dwDuration = pfile->fmt.dwDuration+duration;
266 pfile->data.chunkSize = sizeof(DataChunk)+needbuf;
270 int GetHapticBufferSize(const unsigned char *vibe_buffer, int *size)
272 HapticFile *pfile = NULL;
274 pfile = (HapticFile*)vibe_buffer;
275 if (_check_valid_haptic_format(pfile) < 0) {
276 MODULE_ERROR("this buffer is not HapticFormat");
280 *size = pfile->chunkSize;
284 int GetHapticBufferDuration(const unsigned char *vibe_buffer, int *duration)
286 HapticFile *pfile = NULL;
288 pfile = (HapticFile*)vibe_buffer;
289 if (_check_valid_haptic_format(pfile) < 0) {
290 MODULE_ERROR("this buffer is not HapticFormat");
294 *duration = pfile->fmt.dwDuration;
298 int PlayHapticBuffer(const unsigned char *vibe_buffer, int iteration, int level, int *effect_handle)
300 HapticFile *pfile = NULL;
301 unsigned char **ppbuffer = NULL;
302 unsigned int channels, length, align;
306 pfile = (HapticFile*)vibe_buffer;
307 if (_check_valid_haptic_format(pfile) < 0) {
308 MODULE_ERROR("this buffer is not HapticFormat");
313 This code does not support handle and multi channel concept.
314 Only this code adds to test for playing file. */
316 if (_cancel_thread() < 0) {
317 MODULE_ERROR("_cancel_thread fail");
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);
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);
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]);
342 gbuffer.ppbuffer = ppbuffer;
343 gbuffer.channels = channels;
344 gbuffer.length = length;
345 gbuffer.iteration = iteration;
348 if (_create_thread(&gbuffer, __play_cb) < 0) {
349 MODULE_ERROR("_create_thread fail");
353 *effect_handle = DEFAULT_EFFECT_HANDLE;
357 int CloseHapticDevice(void)
359 if (_cancel_thread() < 0) {
360 MODULE_ERROR("_cancel_thread fail");