4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jiyoung Yun <jy910.yun@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
31 #include <devman_haptic.h>
32 #include <devman_haptic_ext.h>
33 #include <devman_haptic_ext_core.h>
36 #define EXTAPI __attribute__ ((visibility("default")))
40 static long long ms = 0;
42 #define MICROSECONDS(tv) ((tv.tv_sec * 1000000ll) + tv.tv_usec)
44 #define ESTIMATE_PERFORMANCE() \
48 gettimeofday(&tv, NULL); \
49 ms = MICROSECONDS(tv); \
50 fDBG(stderr, "%s start time : %lld\n", __func__, ms); \
52 gettimeofday(&tv, NULL); \
53 fDBG(stderr, "%s elapsed time : %lld\n", __func__, MICROSECONDS(tv) - ms); \
58 #define ESTIMATE_PERFORMANCE()
61 #define MAX_FILE_PATH 256 /* Maximum file path length */
62 #define SAMPLE_INTERVAL 10.0 /* Sample calculation interval in milliseconds */
63 #define IVT_BUFFER_SIZE 4096 /* IVT buffer size */
65 #define FOLDER_MASK 664
75 /* This functions loads the IVT file into memory */
76 static unsigned char *_load_ivt_file(const char *filepath)
80 unsigned char *p_ivt_data = NULL;
81 /* open the IVT file */
82 /* IMPORTANT: open the IVT file as a binary file to avoid translation */
83 pFile = fopen(filepath, "rb");
86 /* handle error, application-specific */
89 /* determine the file size */
90 /* fseek returns zero on success, non-zero on failure */
91 if (fseek(pFile, 0, SEEK_END))
93 /* handle error, application-specific */
97 cbyFileSize = ftell(pFile);
98 if (fseek(pFile, 0, SEEK_SET))
100 /* handle error, application-specific */
104 /* allocate a buffer for the IVT data */
105 p_ivt_data = (unsigned char *)malloc(cbyFileSize);
108 /* handle error, application-specific */
112 /* read the IVT data from the IVT file */
113 if (fread(p_ivt_data, 1, cbyFileSize, pFile) != cbyFileSize)
115 /* handle error, application-specific */
121 /* close the IVT file */
122 if (0 != fclose(pFile))
124 /* handle error, application-specific */
127 /* you can now play effects from the IVT data that was loaded into g_pIVTData */
131 /* converts effect type to string*/
132 static char *_convert_effect_type_to_string(int effect_type)
134 switch (effect_type) {
135 case HAPTIC_EFFECT_TYPE_PERIODIC:
136 return "HAPTIC_EFFECT_TYPE_PERIODIC";
137 case HAPTIC_EFFECT_TYPE_MAGSWEEP:
138 return "HAPTIC_EFFECT_TYPE_MAGSWEEP";
139 case HAPTIC_EFFECT_TYPE_TIMELINE:
140 return "HAPTIC_EFFECT_TYPE_TIMELINE";
141 case HAPTIC_EFFECT_TYPE_STREAMING:
142 return "HAPTIC_EFFECT_TYPE_STREAMING";
143 case HAPTIC_EFFECT_TYPE_WAVEFORM:
144 return "HAPTIC_EFFECT_TYPE_WAVEFORM";
149 /*This functions gets Periodic effect details using devman API*/
150 static int _get_periodic_effect_details(const unsigned char *pivt_data, int index, HapticPeriodic *periodic_effect)
153 result = device_haptic_get_periodic_effect_definition(pivt_data, index,
154 &periodic_effect->duration, &periodic_effect->magnitude,
155 &periodic_effect->period, &periodic_effect->style,
156 &periodic_effect->attacktime, &periodic_effect->attacklevel,
157 &periodic_effect->fadetime, &periodic_effect->fadelevel);
159 DBG("device_haptic_get_periodic_effect_definition() Success");
160 DBG("Duration : %d", periodic_effect->duration);
161 DBG("Magnitude : %d", periodic_effect->magnitude);
162 DBG("Period : %d", periodic_effect->period);
163 DBG("Style & Wave Type : %d", periodic_effect->style);
164 DBG("Attacktime : %d", periodic_effect->attacktime);
165 DBG("Attacklevel : %d", periodic_effect->attacklevel);
166 DBG("Fadetime : %d", periodic_effect->fadetime);
167 DBG("Fadelevel : %d", periodic_effect->fadelevel);
169 DBG("device_haptic_get_periodic_effect_definition() failed. Reason:%d", result);
174 /*This functions gets MagSweep effect details using devman API*/
175 static int _get_magsweep_effect_details(const unsigned char *p_ivt_data, int index, HapticMagSweep *magsweep_effect)
178 result = device_haptic_get_magsweep_effect_definition(p_ivt_data, index,
179 &magsweep_effect->duration, &magsweep_effect->magnitude,
180 &magsweep_effect->style,
181 &magsweep_effect->attacktime, &magsweep_effect->attacklevel,
182 &magsweep_effect->fadetime, &magsweep_effect->fadelevel);
184 DBG("device_haptic_get_magsweep_effect_definition() Success");
185 DBG("Duration : %d", magsweep_effect->duration);
186 DBG("Magnitude : %d", magsweep_effect->magnitude);
187 DBG("Style : %d", magsweep_effect->style);
188 DBG("Attacktime : %d", magsweep_effect->attacktime);
189 DBG("Attacklevel : %d", magsweep_effect->attacklevel);
190 DBG("Fadetime : %d", magsweep_effect->fadetime);
191 DBG("Fadelevel : %d", magsweep_effect->fadelevel);
193 DBG("device_haptic_get_magsweep_effect_definition() failed. Reason:%d", result);
198 /*This functions gets Timeline effect details using devman API*/
199 static int _get_timeline_effect_details(const unsigned char *p_ivt_data, int index, HapticElement *timeline_effect)
201 unsigned char ivt_buffer[IVT_BUFFER_SIZE+1] = {0,};
204 result = device_haptic_initialize_buffer(ivt_buffer, sizeof(ivt_buffer));
206 result = device_haptic_read_element(ivt_buffer, IVT_BUFFER_SIZE, 0, 0, timeline_effect);
208 DBG("Element type:%d", timeline_effect->elementtype);
210 DBG("device_haptic_read_element() failed. Reason :%d", result);
213 DBG("device_haptic_initialize_buffer() failed. Reason:%d", result);
218 /* This function parses the Periodic effect received and generates
219 * corresponding LED pattern for it */
220 static char *_parse_periodic_effect_and_generate_led_pattern(HapticPeriodic periodic, int *buffer_size)
222 char *led_pattern = NULL;
223 int unit = periodic.magnitude/10;
225 int sample_index = 0;
229 int mid = periodic.period/2;
233 int base = BASE*unit;
234 char const_value ='0';
236 led_pattern = (char*)calloc(((periodic.duration/SAMPLE_INTERVAL)+1), sizeof(char));
237 if (led_pattern == NULL) {
238 DBG("Memory allocation failure");
242 if (periodic.magnitude >0)
245 if (periodic.attacktime == 0 && periodic.attacklevel == 0
246 && periodic.fadetime == 0 && periodic.fadelevel == 0) {
247 DBG("Periodic effect");
249 if (periodic.style <=0) {
250 DBG("Unknown periodic effect");
254 /* Extract Style and wave type*/
255 DBG("Style and wave type: %d", periodic.style);
256 style = periodic.style && HAPTIC_STYLE_SUPPORT_MASK;
257 wave_type = periodic.style && HAPTIC_WAVETYPE_SUPPORT_MASK;
258 DBG("Style : %d", style);
259 DBG("Wave type : %d", wave_type);
261 /* Generate pattern based on Wave type. Ignore Style*/
263 case WAVETYPE_SQUARE:
264 case WAVETYPE_SAWTOOTHDOWN:
266 for (i = 0; i<periodic.duration; i =i+periodic.period) {
267 for (j =SAMPLE_INTERVAL; j<=periodic.period; j = j+SAMPLE_INTERVAL) {
269 led_pattern[sample_index++] = '1';
271 led_pattern[sample_index++] = '0';
276 case WAVETYPE_TRIANGLE:
279 step = periodic.magnitude/mid;
280 delta = step * SAMPLE_INTERVAL;
281 for (i = 0; i<periodic.duration; i =i+periodic.period) {
283 for (j =SAMPLE_INTERVAL; j<=periodic.period; j = j+SAMPLE_INTERVAL) {
285 value = value + delta;
287 value = value - delta;
289 led_pattern[sample_index++] = '1';
291 led_pattern[sample_index++] = '0';
296 case WAVETYPE_SAWTOOTHUP:
298 for (i = 0; i<periodic.duration; i =i+periodic.period) {
299 for (j =SAMPLE_INTERVAL; j<=periodic.period; j = j+SAMPLE_INTERVAL) {
301 led_pattern[sample_index++] = '1';
303 led_pattern[sample_index++] = '0';
308 default: DBG("Unknown wave type\n");
314 /* handling periodic effect if attacktime and fade time less than period*/
315 /* Need to keep repeating the pattern with attack and fade effectes within period till duration is reached*/
316 if (periodic.attacktime>periodic.period || periodic.fadetime>periodic.period) {
317 if (periodic.attacktime >0) {
318 DBG("Attack time present\n");
320 if (periodic.attacklevel >periodic.magnitude) { /* Decrementing effect */
321 step = (periodic.attacklevel - periodic.magnitude)/periodic.attacktime;
322 } else if (periodic.attacklevel <periodic.magnitude) { /* Incrementing effect */
323 step = ( periodic.magnitude - periodic.attacklevel)/periodic.attacktime;
325 delta = step * SAMPLE_INTERVAL;
327 for (i=SAMPLE_INTERVAL; i<= periodic.attacktime; i = i+SAMPLE_INTERVAL) {
330 led_pattern[sample_index++] = '1';
332 led_pattern[sample_index++] = '0';
336 for (i = periodic.attacktime+SAMPLE_INTERVAL; i<= (periodic.duration-periodic.fadetime); i = i+ SAMPLE_INTERVAL) {
337 led_pattern[sample_index++] = const_value;
339 if (periodic.fadetime >0) {
340 step = (periodic.magnitude - periodic.fadelevel)/periodic.fadetime;
341 delta = step* SAMPLE_INTERVAL;
342 value = periodic.magnitude;
343 for (i = (periodic.duration-periodic.fadetime+SAMPLE_INTERVAL); i<= periodic.duration; i = i+ SAMPLE_INTERVAL) {
344 value = value - delta;
346 led_pattern[sample_index++] = '1';
348 led_pattern[sample_index++] = '0';
353 /*To mark end of effect*/
354 led_pattern[sample_index++] = '0';
355 *buffer_size = sample_index;
356 DBG("LED Pattern for Periodic effect: %s", led_pattern);
360 /* This function parses the MagSweep effect received and generates
361 * corresponding LED pattern for it */
362 static char *_parse_magsweep_effect_and_generate_led_pattern(HapticMagSweep mag_sweep, int *buffer_size)
364 int unit = mag_sweep.magnitude/10;
366 int sample_index = 0;
370 int base = BASE*unit;
371 char const_value ='0';
372 char *led_pattern = NULL;
374 led_pattern = (char*)calloc(((mag_sweep.duration/SAMPLE_INTERVAL)+1), sizeof(char));
375 if (led_pattern == NULL) {
376 DBG("Memory allocation failure");
380 if (mag_sweep.magnitude >0)
383 if (mag_sweep.attacktime == 0 && mag_sweep.attacklevel == 0
384 && mag_sweep.fadetime == 0 && mag_sweep.fadelevel == 0) {
385 /* Constant effect with maximum magnitude*/
386 DBG("Constant effect");
388 for (i = 0; i<=mag_sweep.duration; i=i+SAMPLE_INTERVAL) {
389 led_pattern[sample_index++] = const_value;
392 DBG("Varying effect");
393 /* Handling Attack effect*/
394 if (mag_sweep.attacktime >0) {
395 DBG("Attack time present");
397 if (mag_sweep.attacklevel >mag_sweep.magnitude) { /* Decrementing effect */
398 step = (mag_sweep.attacklevel - mag_sweep.magnitude)/mag_sweep.attacktime;
399 } else if (mag_sweep.attacklevel <mag_sweep.magnitude) { /* Incrementing effect */
400 step = ( mag_sweep.magnitude - mag_sweep.attacklevel)/mag_sweep.attacktime;
402 delta = step * SAMPLE_INTERVAL;
404 for (i=SAMPLE_INTERVAL; i<= mag_sweep.attacktime; i = i+SAMPLE_INTERVAL) {
407 led_pattern[sample_index++] = '1';
409 led_pattern[sample_index++] = '0';
412 /* For Handling constant effect between attacktime and fade time*/
413 for (i = mag_sweep.attacktime+SAMPLE_INTERVAL; i<= (mag_sweep.duration-mag_sweep.fadetime); i = i+ SAMPLE_INTERVAL) {
414 led_pattern[sample_index++] = const_value;
416 /* Handling fading effect*/
417 if (mag_sweep.fadetime >0) {
418 step = (mag_sweep.magnitude - mag_sweep.fadelevel)/mag_sweep.fadetime;
419 delta = step* SAMPLE_INTERVAL;
420 value = mag_sweep.magnitude;
421 for (i = (mag_sweep.duration-mag_sweep.fadetime+ SAMPLE_INTERVAL); i<= mag_sweep.duration; i = i+ SAMPLE_INTERVAL) {
422 value = value - delta;
424 led_pattern[sample_index++] = '1';
426 led_pattern[sample_index++] = '0';
431 /*To mark end of effect*/
432 led_pattern[sample_index++] = '0';
433 *buffer_size = sample_index;
434 DBG("Appending 0 at the end");
435 DBG("LED Pattern for MagSweep effect: %s", led_pattern);
439 static int _write_pattern_to_file(const char *binary_path, char *pled_dat, int buf_size, int *opened_flag)
441 FILE *ptr_myfile = NULL;
443 DBG("LED file name:%s", binary_path);
444 /* Open file for the FIRST time */
446 ptr_myfile = fopen(binary_path, "wb+");
448 DBG("Unable to open file!");
453 ptr_myfile = fopen(binary_path, "ab+");
455 DBG("Unable to open file!");
460 DBG("Buffer: %s", pled_dat);
461 if (fwrite(pled_dat, 1, buf_size, ptr_myfile) <= 0) {
462 DBG("fwrite() failed");
464 DBG("fwrite() success");
471 static int _convert_ivt_to_binary(const char *haptic_path, const char *binary_path)
473 unsigned char *pivt_dat = NULL;
474 char *pled_dat = NULL;
477 int effect_type = -1;
478 int effect_duration = -1;
480 int opened_flag = 1; // 1 : Not opened, 0 : Opened
481 HapticPeriodic periodic_effect;
482 HapticMagSweep magsweep_effect;
483 HapticElement element;
486 /* Load IVT file into memory */
487 pivt_dat = _load_ivt_file(haptic_path);
489 DBG("Loading IVT failed");
493 /* Get total number of effects in IVT file */
494 effect_cnt = device_haptic_get_effect_count(pivt_dat);
495 DBG("device_haptic_get_effect_count() Return:%d", effect_cnt);
497 /* Parse effects in IVT */
498 for (i = 0; i < effect_cnt; i++) {
500 result = device_haptic_get_effect_type(pivt_dat, i, &effect_type);
502 DBG("EffectNo:%d Getting Effect Type Failed. Reason:%d", (i+1), result);
506 DBG("EffectNo:%d EffectType:%s\n", (i+1), _convert_effect_type_to_string(effect_type));
507 switch (effect_type) {
508 case HAPTIC_EFFECT_TYPE_PERIODIC:
509 memset(&periodic_effect, 0x00, sizeof(HapticPeriodic));
510 if (_get_periodic_effect_details(pivt_dat, i, &periodic_effect) == 0) {
511 /* Parse periodic effect type*/
512 pled_dat = _parse_periodic_effect_and_generate_led_pattern(periodic_effect, &buf_size);
514 _write_pattern_to_file(binary_path, pled_dat, buf_size, &opened_flag);
519 case HAPTIC_EFFECT_TYPE_MAGSWEEP:
520 memset(&magsweep_effect, 0x00, sizeof(HapticMagSweep));
521 if (_get_magsweep_effect_details(pivt_dat, i, &magsweep_effect) == 0) {
522 /* Parse magsweep effect type*/
523 pled_dat = _parse_magsweep_effect_and_generate_led_pattern(magsweep_effect, &buf_size);
525 _write_pattern_to_file(binary_path, pled_dat, buf_size, &opened_flag);
530 case HAPTIC_EFFECT_TYPE_TIMELINE:
531 memset(&element, 0x00, sizeof(HapticElement));
532 if (_get_timeline_effect_details(pivt_dat, i, &element) > 0) {
533 device_haptic_get_effect_duration(pivt_dat, i, &effect_duration);
534 DBG("Timeline effect duration:%d", effect_duration);
537 case HAPTIC_EFFECT_TYPE_STREAMING:
538 case HAPTIC_EFFECT_TYPE_WAVEFORM:
540 DBG("Unsupported effect type");
549 EXTAPI int device_haptic_convert_to_binary(const char *haptic_name)
551 DBG("this api is not implementation yet");