2.0 alpha
[platform/core/system/devman.git] / src / device_convert.c
1 /*
2  *  devman
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jiyoung Yun <jy910.yun@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20 */
21
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <dirent.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29
30 #include "devlog.h"
31 #include <devman_haptic.h>
32 #include <devman_haptic_ext.h>
33 #include <devman_haptic_ext_core.h>
34
35 #ifndef EXTAPI
36 #define EXTAPI __attribute__ ((visibility("default")))
37 #endif /* EXTAPI */
38
39 #ifdef PERFORM_CHECK
40 static long long ms = 0;
41
42 #define MICROSECONDS(tv)        ((tv.tv_sec * 1000000ll) + tv.tv_usec)
43
44 #define ESTIMATE_PERFORMANCE() \
45         do { \
46                 struct timeval tv; \
47                 if (ms == 0) { \
48                         gettimeofday(&tv, NULL); \
49                         ms = MICROSECONDS(tv); \
50                         fDBG(stderr, "%s start time : %lld\n", __func__, ms); \
51                 } else { \
52                         gettimeofday(&tv, NULL); \
53                         fDBG(stderr, "%s elapsed time : %lld\n", __func__, MICROSECONDS(tv) - ms); \
54                         ms = 0; \
55                 } \
56         } while(0)
57 #else
58 #define ESTIMATE_PERFORMANCE()
59 #endif
60
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 */
64 #define BASE                            5
65 #define FOLDER_MASK                     664
66
67 typedef enum {
68     WAVETYPE_SQUARE = 1,
69     WAVETYPE_TRIANGLE,
70     WAVETYPE_SINE,
71     WAVETYPE_SAWTOOTHUP,
72     WAVETYPE_SAWTOOTHDOWN
73 } effect_wave_type;
74
75 /* This functions loads the IVT file into memory */
76 static unsigned char *_load_ivt_file(const char *filepath)
77 {
78     FILE *pFile;
79     long cbyFileSize;
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");
84     if (!pFile)
85     {
86         /* handle error, application-specific */
87         return p_ivt_data;
88     }
89     /* determine the file size */
90     /* fseek returns zero on success, non-zero on failure */
91     if (fseek(pFile, 0, SEEK_END))
92     {
93         /* handle error, application-specific */
94         fclose(pFile);
95         return p_ivt_data;
96     }
97     cbyFileSize = ftell(pFile);
98     if (fseek(pFile, 0, SEEK_SET))
99     {
100         /* handle error, application-specific */
101         fclose(pFile);
102         return p_ivt_data;
103     }
104     /* allocate a buffer for the IVT data */
105     p_ivt_data = (unsigned char *)malloc(cbyFileSize);
106     if (!p_ivt_data)
107     {
108         /* handle error, application-specific */
109         fclose(pFile);
110         return p_ivt_data;
111     }
112     /* read the IVT data from the IVT file */
113     if (fread(p_ivt_data, 1, cbyFileSize, pFile) != cbyFileSize)
114     {
115         /* handle error, application-specific */
116         free(p_ivt_data);
117         p_ivt_data = 0;
118         fclose(pFile);
119         return p_ivt_data;
120     }
121     /* close the IVT file */
122     if (0 != fclose(pFile))
123     {
124         /* handle error, application-specific */
125         return p_ivt_data;
126     }
127     /* you can now play effects from the IVT data that was loaded into g_pIVTData */
128     return p_ivt_data;
129 }
130
131 /* converts effect type to string*/
132 static char *_convert_effect_type_to_string(int effect_type)
133 {
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";
145     }
146         return NULL;
147 }
148
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)
151 {
152     int result = -1;
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);
158     if (result == 0) {
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);
168     }  else {
169         DBG("device_haptic_get_periodic_effect_definition() failed. Reason:%d", result);
170     }
171     return result;
172 }
173
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)
176 {
177     int result = -1;
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);
183     if (result == 0) {
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);
192     }  else {
193         DBG("device_haptic_get_magsweep_effect_definition() failed. Reason:%d", result);
194     }
195     return result;
196 }
197
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)
200 {
201     unsigned char ivt_buffer[IVT_BUFFER_SIZE+1] = {0,};
202     int result = -1;
203
204         result = device_haptic_initialize_buffer(ivt_buffer, sizeof(ivt_buffer));
205     if (result ==0) {
206         result = device_haptic_read_element(ivt_buffer, IVT_BUFFER_SIZE, 0, 0, timeline_effect);
207         if (result == 0) {
208             DBG("Element type:%d", timeline_effect->elementtype);
209         } else {
210             DBG("device_haptic_read_element() failed. Reason :%d", result);
211         }
212     } else {
213         DBG("device_haptic_initialize_buffer() failed. Reason:%d", result);
214     }
215     return result;
216 }
217
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)
221 {
222         char *led_pattern = NULL;
223     int unit = periodic.magnitude/10;
224     int i = 0;
225     int sample_index = 0;
226     int value = 0;
227     int style = 0;
228     int wave_type = 0;
229     int mid = periodic.period/2;
230     int j = 0;
231     int step = 0;
232     int delta = 0;
233     int base = BASE*unit;
234     char const_value ='0';
235
236         led_pattern = (char*)calloc(((periodic.duration/SAMPLE_INTERVAL)+1), sizeof(char));
237         if (led_pattern == NULL) {
238                 DBG("Memory allocation failure");
239                 return NULL;
240         }
241
242     if (periodic.magnitude >0)
243         const_value = '1';
244
245     if (periodic.attacktime == 0 && periodic.attacklevel == 0
246         && periodic.fadetime == 0 && periodic.fadelevel == 0) {
247         DBG("Periodic effect");
248
249         if (periodic.style <=0) {
250             DBG("Unknown periodic effect");
251             free(led_pattern);
252             return NULL;
253         } else {
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);
260
261             /* Generate pattern based on Wave type. Ignore Style*/
262             switch (wave_type) {
263             case WAVETYPE_SQUARE:
264             case WAVETYPE_SAWTOOTHDOWN:
265             {
266                 for (i = 0; i<periodic.duration; i =i+periodic.period) {
267                     for (j =SAMPLE_INTERVAL; j<=periodic.period; j = j+SAMPLE_INTERVAL) {
268                         if (j <= mid)
269                             led_pattern[sample_index++] = '1';
270                         else
271                             led_pattern[sample_index++] = '0';
272                     }
273                 }
274                 break;
275             }
276             case WAVETYPE_TRIANGLE:
277             case WAVETYPE_SINE:
278             {
279                 step = periodic.magnitude/mid;
280                 delta = step * SAMPLE_INTERVAL;
281                 for (i = 0; i<periodic.duration; i =i+periodic.period) {
282                     value = 0;
283                     for (j =SAMPLE_INTERVAL; j<=periodic.period; j = j+SAMPLE_INTERVAL) {
284                         if (j <= mid)
285                             value = value + delta;
286                         else
287                             value = value - delta;
288                         if (value>= base)
289                             led_pattern[sample_index++] = '1';
290                         else
291                             led_pattern[sample_index++] = '0';
292                     }
293                 }
294                 break;
295             }
296             case WAVETYPE_SAWTOOTHUP:
297             {
298                 for (i = 0; i<periodic.duration; i =i+periodic.period) {
299                     for (j =SAMPLE_INTERVAL; j<=periodic.period; j = j+SAMPLE_INTERVAL) {
300                         if (j > mid)
301                             led_pattern[sample_index++] = '1';
302                         else
303                             led_pattern[sample_index++] = '0';
304                     }
305                 }
306                 break;
307             }
308             default: DBG("Unknown wave type\n");
309                 break;
310             }
311          }
312     } else {
313         /*TODO*/
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");
319
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;
324                 }
325                 delta = step * SAMPLE_INTERVAL;
326
327                 for (i=SAMPLE_INTERVAL; i<= periodic.attacktime; i = i+SAMPLE_INTERVAL) {
328                     value = value+delta;
329                     if (value>base)
330                         led_pattern[sample_index++] = '1';
331                     else
332                         led_pattern[sample_index++] = '0';
333                 }
334             }
335
336             for (i = periodic.attacktime+SAMPLE_INTERVAL; i<= (periodic.duration-periodic.fadetime); i = i+ SAMPLE_INTERVAL) {
337                 led_pattern[sample_index++] = const_value;
338             }
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;
345                     if (value>base)
346                         led_pattern[sample_index++] = '1';
347                     else
348                         led_pattern[sample_index++] = '0';
349                 }
350             }
351         }
352     }
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);
357     return led_pattern;
358 }
359
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)
363 {
364     int unit = mag_sweep.magnitude/10;
365     int i =0;
366     int sample_index = 0;
367     int step = 0;
368     int delta = 0;
369     int value =0;
370     int base = BASE*unit;
371     char const_value ='0';
372     char *led_pattern = NULL;
373
374         led_pattern = (char*)calloc(((mag_sweep.duration/SAMPLE_INTERVAL)+1), sizeof(char));
375     if (led_pattern == NULL) {
376         DBG("Memory allocation failure");
377         return NULL;
378     }
379
380     if (mag_sweep.magnitude >0)
381         const_value = '1';
382
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");
387
388         for (i = 0; i<=mag_sweep.duration; i=i+SAMPLE_INTERVAL) {
389             led_pattern[sample_index++] = const_value;
390         }
391     } else {
392         DBG("Varying effect");
393         /* Handling Attack effect*/
394         if (mag_sweep.attacktime >0) {
395             DBG("Attack time present");
396
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;
401             }
402             delta = step * SAMPLE_INTERVAL;
403
404             for (i=SAMPLE_INTERVAL; i<= mag_sweep.attacktime; i = i+SAMPLE_INTERVAL) {
405                 value = value+delta;
406                 if (value>base)
407                     led_pattern[sample_index++] = '1';
408                 else
409                     led_pattern[sample_index++] = '0';
410             }
411         }
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;
415         }
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;
423                 if (value>base)
424                     led_pattern[sample_index++] = '1';
425                 else
426                     led_pattern[sample_index++] = '0';
427             }
428         }
429
430     }
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);
436     return led_pattern;
437 }
438
439 static int _write_pattern_to_file(const char *binary_path, char *pled_dat, int buf_size, int *opened_flag)
440 {
441         FILE *ptr_myfile = NULL;
442
443     DBG("LED file name:%s", binary_path);
444         /* Open file for the FIRST time */
445         if (*opened_flag) {
446         ptr_myfile = fopen(binary_path, "wb+");
447         if (!ptr_myfile) {
448             DBG("Unable to open file!");
449             return -1;
450         }
451                 *opened_flag = 0;
452     } else {
453         ptr_myfile = fopen(binary_path, "ab+");
454         if (!ptr_myfile) {
455             DBG("Unable to open file!");
456             return -1;
457         }
458     }
459
460     DBG("Buffer: %s", pled_dat);
461     if (fwrite(pled_dat, 1, buf_size, ptr_myfile) <= 0) {
462         DBG("fwrite() failed");
463     } else {
464         DBG("fwrite() success");
465     }
466
467     fclose(ptr_myfile);
468         return 0;
469 }
470
471 static int _convert_ivt_to_binary(const char *haptic_path, const char *binary_path)
472 {
473         unsigned char *pivt_dat = NULL;
474         char *pled_dat = NULL;
475         int result = -1;
476         int effect_cnt = -1;
477         int effect_type = -1;
478         int effect_duration = -1;
479         int buf_size = -1;
480         int opened_flag = 1;    // 1 : Not opened, 0 : Opened
481         HapticPeriodic periodic_effect;
482         HapticMagSweep magsweep_effect;
483         HapticElement element;
484         int i;
485
486         /* Load IVT file into memory */
487         pivt_dat = _load_ivt_file(haptic_path);
488         if (!pivt_dat) {
489                 DBG("Loading IVT failed");
490                 return -1;
491         }
492
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);
496
497     /* Parse effects in IVT */
498         for (i = 0; i < effect_cnt; i++) {
499                 /* Get effect type*/
500                 result = device_haptic_get_effect_type(pivt_dat, i, &effect_type);
501                 if (result < 0) {
502                         DBG("EffectNo:%d Getting Effect Type Failed. Reason:%d", (i+1), result);
503                         continue;
504                 }
505
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);
513                                 if (pled_dat) {
514                                         _write_pattern_to_file(binary_path, pled_dat, buf_size, &opened_flag);
515                                         free(pled_dat);
516                                 }
517                         }
518                         break;
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);
524                                 if (pled_dat) {
525                                         _write_pattern_to_file(binary_path, pled_dat, buf_size, &opened_flag);
526                                         free(pled_dat);
527                                 }
528                         }
529                         break;
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);
535                         }
536                         break;
537                 case HAPTIC_EFFECT_TYPE_STREAMING:
538                 case HAPTIC_EFFECT_TYPE_WAVEFORM:
539                 default:
540                         DBG("Unsupported effect type");
541                         break;
542                 }
543         }
544
545         free(pivt_dat);
546         return 0;
547 }
548
549 EXTAPI int device_haptic_convert_to_binary(const char *haptic_name)
550 {
551         DBG("this api is not implementation yet");
552         return -1;
553 }