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.
25 #include <device-node.h>
28 #include "haptic_module_log.h"
31 #define MAX_LEVEL 255.0f
32 #define DEFAULT_EFFECT_HANDLE 0x02
37 #define PREDEF_HAPTIC "haptic"
50 unsigned char **ppbuffer;
57 static BUFFER gbuffer;
59 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
61 static int _check_valid_haptic_format(HapticFile *file)
63 if (file->chunkID != HEADER_ID)
66 if (file->fmt.chunkID != FMT_ID)
69 if (file->data.chunkID != DATA_ID)
75 static int __haptic_predefine_action(int handle, int prop, int val)
82 snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
83 snprintf(buf_prop, sizeof(buf_prop), "%d", prop);
84 snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
85 snprintf(buf_val, sizeof(buf_val), "%d", val);
87 MODULE_LOG("pid : %s(%d), prop : %s, handle : %s", buf_pid, pthread_self(), buf_prop, buf_handle);
88 return __haptic_call_predef_action(PREDEF_HAPTIC, 4, buf_pid, buf_prop, buf_handle, buf_val);
91 static int _create_thread(void* data, void*(*func)(void*))
94 MODULE_ERROR("pthread already created");
98 if (pthread_create(&tid, NULL, func, data) != 0) {
99 MODULE_ERROR("pthread_create is failed : %s", strerror(errno));
106 static int _cancel_thread(void)
112 MODULE_LOG("pthread not initialized");
116 MODULE_LOG("cancel thread!!!");
120 while (pthread_mutex_trylock(&mutex) == EBUSY) {
122 MODULE_LOG("Already locked..");
124 __haptic_predefine_action(gbuffer.handle, STOP, NULL);
125 pthread_mutex_unlock(&mutex);
127 if ((ret = pthread_cancel(tid)) < 0) {
128 MODULE_ERROR("pthread_cancel is failed : %s, ret(%d)", strerror(errno), ret);
132 if (pthread_join(tid, (void**)&ptr) < 0) {
133 MODULE_ERROR("pthread_join is failed : %s", strerror(errno));
140 if (ptr == PTHREAD_CANCELED) {
141 MODULE_LOG("pthread canceled");
143 MODULE_LOG("pthread already finished");
149 static void __clean_up(void *arg)
151 BUFFER *pbuffer = (BUFFER*)arg;
154 MODULE_LOG("clean up handler!!! : %d", tid);
156 for (i = 0; i < pbuffer->channels; ++i) {
157 free(pbuffer->ppbuffer[i]);
158 pbuffer->ppbuffer[i] = NULL;
161 free(pbuffer->ppbuffer);
162 pbuffer->ppbuffer = NULL;
164 pbuffer->channels = 0;
168 static void* __play_cb(void *arg)
170 BUFFER *pbuffer = (BUFFER*)arg;
173 unsigned char prev = -1;
175 MODULE_LOG("Start thread");
177 pthread_cleanup_push(__clean_up, arg);
179 /* Copy buffer from source buffer */
180 for (i = 0; i < pbuffer->iteration; i++) {
181 for (j = 0; j < pbuffer->length; ++j) {
182 for (k = 0; k < pbuffer->channels; ++k) {
183 pthread_mutex_lock(&mutex);
185 pthread_mutex_unlock(&mutex);
186 pthread_exit((void*)0);
188 ch = pbuffer->ppbuffer[k][j];
190 __haptic_predefine_action(pbuffer->handle, LEVEL, ch);
193 pthread_mutex_unlock(&mutex);
194 usleep(BITPERMS * 1000);
199 pthread_mutex_lock(&mutex);
200 __haptic_predefine_action(gbuffer.handle, STOP, NULL);
201 pthread_mutex_unlock(&mutex);
203 pthread_cleanup_pop(1);
204 pthread_exit((void *)0);
207 int GetHapticLevelMax(int *max)
210 status = device_get_property(DEVICE_TYPE_VIBRATOR, PROP_VIBRATOR_LEVEL_MAX, max);
212 MODULE_ERROR("device_get_property fail : %d", status);
218 int InitializeBuffer(unsigned char *vibe_buffer, int max_bufsize)
222 if (max_bufsize < sizeof(HapticFile)) {
223 MODULE_ERROR("buffer lacks a memory : size(%d) minimum size(%d)",
224 max_bufsize, sizeof(HapticFile));
228 memset(vibe_buffer, 0, sizeof(char)*max_bufsize);
230 pfile = (HapticFile*)vibe_buffer;
232 pfile->chunkID = HEADER_ID;
233 pfile->chunkSize = sizeof(HapticFile);
234 pfile->fmt.chunkID = FMT_ID;
235 pfile->fmt.chunkSize = sizeof(FormatChunk);
236 pfile->fmt.wChannels = 1;
237 pfile->fmt.wBlockAlign = 1; // wChannels*1byte
238 pfile->fmt.dwMagnitude = 99;
239 pfile->fmt.dwDuration = 0;
240 pfile->data.chunkID = DATA_ID;
241 pfile->data.chunkSize = sizeof(DataChunk);
245 int InsertElement(unsigned char *vibe_buffer, int max_bufsize, HapticElement *element)
254 pfile = (HapticFile*)vibe_buffer;
255 if (_check_valid_haptic_format(pfile) < 0) {
256 MODULE_ERROR("this buffer is not HapticFormat");
260 duration = element->duration/BITPERMS;
261 level = (unsigned char)((unsigned int)element->level*MAX_LEVEL/100);
263 databuf = max_bufsize - sizeof(HapticFile);
264 needbuf = (pfile->fmt.dwDuration + duration)*pfile->fmt.wBlockAlign;
265 MODULE_LOG("Need buffer size : %d", needbuf);
267 if (databuf < needbuf) {
268 MODULE_ERROR("buffer lacks a memory : data buf(%d), need buf(%d)", databuf, needbuf);
272 for (i = pfile->fmt.dwDuration; i < pfile->fmt.dwDuration+duration; i++) {
273 pfile->data.pData[i] = level;
276 pfile->chunkSize = sizeof(HapticFile)+needbuf ;
277 pfile->fmt.dwDuration = pfile->fmt.dwDuration+duration;
278 pfile->data.chunkSize = sizeof(DataChunk)+needbuf;
282 int GetBufferSize(const unsigned char *vibe_buffer, int *size)
286 pfile = (HapticFile*)vibe_buffer;
287 if (_check_valid_haptic_format(pfile) < 0) {
288 MODULE_ERROR("this buffer is not HapticFormat");
292 *size = pfile->chunkSize;
296 int GetBufferDuration(const unsigned char *vibe_buffer, int *duration)
300 pfile = (HapticFile*)vibe_buffer;
301 if (_check_valid_haptic_format(pfile) < 0) {
302 MODULE_ERROR("this buffer is not HapticFormat");
306 *duration = pfile->fmt.dwDuration;
310 int PlayOneshot(int handle, int duration, int level)
315 char buf_duration[32];
318 if (_cancel_thread() < 0) {
319 MODULE_ERROR("_cancel_thread fail");
323 snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
324 snprintf(buf_prop, sizeof(buf_prop), "%d", ONESHOT);
325 snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
326 snprintf(buf_duration, sizeof(buf_duration), "%d", duration);
327 snprintf(buf_level, sizeof(buf_level), "%d", level);
329 MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle);
330 return __haptic_call_predef_action(PREDEF_HAPTIC, 5, buf_pid, buf_prop,
331 buf_handle, buf_duration, buf_level);
334 int PlayBuffer(int handle, const unsigned char *vibe_buffer, int iteration, int level)
337 unsigned char **ppbuffer;
338 unsigned int channels, length, align;
342 pfile = (HapticFile*)vibe_buffer;
343 if (_check_valid_haptic_format(pfile) < 0) {
344 MODULE_ERROR("this buffer is not HapticFormat");
349 This code does not support handle and multi channel concept.
350 Only this code adds to test for playing file. */
352 if (_cancel_thread() < 0) {
353 MODULE_ERROR("_cancel_thread fail");
357 channels = pfile->fmt.wChannels;
358 align = pfile->fmt.wBlockAlign;
359 length = (pfile->data.chunkSize-8)/align;
360 MODULE_LOG("channels : %d, length : %d, align : %d, level : %d", channels, length, align, level);
363 ppbuffer = (unsigned char**)malloc(sizeof(unsigned char*)*channels);
364 for (i = 0; i < channels; ++i) {
365 ppbuffer[i] = (unsigned char*)malloc(sizeof(unsigned char)*length);
366 memset(ppbuffer[i], 0, sizeof(unsigned char)*length);
369 /* Copy buffer from source buffer */
370 for (i = 0; i < length; ++i) {
371 for (j = 0; j < channels; ++j) {
372 data = (unsigned char)(pfile->data.pData[i*align+j]);
373 ppbuffer[j][i] = (unsigned char)(data*level/0xFF);
374 MODULE_LOG("ppbuffer[%2d][%2d] : data(%x) -> (%x)", j, i, data, ppbuffer[j][i]);
378 gbuffer.handle = handle;
379 gbuffer.ppbuffer = ppbuffer;
380 gbuffer.channels = channels;
381 gbuffer.length = length;
382 gbuffer.iteration = iteration;
384 __haptic_predefine_action(gbuffer.handle, PLAY, NULL);
387 if (_create_thread(&gbuffer, __play_cb) < 0) {
388 MODULE_ERROR("_create_thread fail");
401 if (_cancel_thread() < 0) {
402 MODULE_ERROR("_cancel_thread fail");
406 snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
407 snprintf(buf_prop, sizeof(buf_prop), "%d", STOP);
408 snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
410 MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle);
411 return __haptic_call_predef_action(PREDEF_HAPTIC, 3, buf_pid, buf_prop, buf_handle);
414 int OpenDevice(int handle)
420 snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
421 snprintf(buf_prop, sizeof(buf_prop), "%d", OPEN);
422 snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
424 MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle);
425 return __haptic_call_predef_action(PREDEF_HAPTIC, 3, buf_pid, buf_prop, buf_handle);
428 int CloseDevice(int handle)
434 if (_cancel_thread() < 0) {
435 MODULE_ERROR("_cancel_thread fail");
439 snprintf(buf_pid, sizeof(buf_pid), "%d", getpid());
440 snprintf(buf_prop, sizeof(buf_prop), "%d", CLOSE);
441 snprintf(buf_handle, sizeof(buf_handle), "%d", handle);
443 MODULE_LOG("pid : %s, prop : %s, handle : %s", buf_pid, buf_prop, buf_handle);
444 return __haptic_call_predef_action(PREDEF_HAPTIC, 3, buf_pid, buf_prop, buf_handle);
447 int GetState(int handle, int *state)
449 if (gbuffer.handle == handle) {