default_backend: add test example for getting/updating buffer
[platform/core/uifw/libpui.git] / backends / default_backend.c
1 /*
2  * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <PUI_backend.h>
29
30 #include <json-c/json.h>
31 #include <dirent.h>
32 #include <errno.h>
33 #include <Eina.h>
34 #include <config.h>
35
36 #define ANI_COLLECTION_DIR "/usr/share/pui/"
37 #define MAX_STR 1024
38
39 #define ERROR_CHECK(exp, action, fmt, ...) \
40         do { \
41                 if (!(exp)) \
42                 { \
43                         printf(fmt, ##__VA_ARGS__);     \
44                         action; \
45                 } \
46         } while (0)
47
48 pui_backend_ani_func *ani_func = NULL;
49 Eina_Hash *_animations_hash = NULL;
50
51 typedef enum
52 {
53         None,
54         Linear,
55         EaseInSine,
56         EaseOutSine,
57         EaseInQuart,
58         EaseOutQuart
59 } pui_effect_func;
60
61 typedef struct _default_ani_info default_ani_info;
62 typedef struct _default_frame_info_t default_frame_info_t;
63 typedef struct _default_led_info_t default_led_info_t;
64
65 struct _default_ani_info
66 {
67         pui_id id;
68         pui_ani_status status;
69         pui_ani_control_buffer *buffer;
70         unsigned int repeat;
71
72         unsigned int key_frame_idx;
73         unsigned int num_key_frames;
74         default_frame_info_t *frames;
75         int interval;
76         pui_effect_func effect_func;
77 };
78
79 struct _default_frame_info_t
80 {
81         default_led_info_t *leds;
82         int num_led;
83 };
84
85 struct _default_led_info_t
86 {
87         unsigned int color;
88 };
89
90 pui_backend_ani_data *g_ani_data = NULL;
91
92 static pui_bool
93 _ani_backend_frame_cb(void *data, int serial)
94 {
95         pui_int_error e = PUI_INT_ERROR_NONE;
96         pui_ani_t *ani = (pui_ani_t *)data;
97         pui_backend_ani_data *ani_data = NULL;
98         pui_ani_control_buffer *buffer = NULL;
99
100         ani_data = pui_backend_ani_get_ani_data(ani);
101         default_ani_info *ani_info = (default_ani_info *)ani_data->ani_info;
102
103         pui_info("... serial=%d\n", serial);
104
105         /* TODO : make use of ani_info */
106         (void) ani_info;
107
108         buffer = pui_backend_ani_get_buffer(ani);
109
110         /* test example */
111         for(int i = 0; i<12; i++)
112         {
113                 buffer->ptr[4*i] = 0;
114                 buffer->ptr[4*i + 1] = (((serial%3) == 0) ? 0xFF:0); /* BLUE */
115                 buffer->ptr[4*i + 2] = (((serial%3) == 1) ? 0xFF:0); /* GREEN */
116                 buffer->ptr[4*i + 3] = (((serial%3) == 2) ? 0xFF:0); /* RED */
117         }
118
119         e = pui_backend_ani_set_buffer(ani, buffer);
120
121         if (e != PUI_INT_ERROR_NONE)
122         {
123                 pui_err("Failed on setting buffer on animation !(e=%d)\n", e);
124                 return (pui_bool)0;
125         }
126
127         e = pui_backend_ani_update(ani);
128
129         if (e != PUI_INT_ERROR_NONE)
130         {
131                 pui_err("Failed on updating animation !(e=%d)\n", e);
132                 return (pui_bool)0;
133         }
134
135         pui_info("... update (serial=%d)\n", serial);
136
137         return (pui_bool)1;
138 }
139
140 default_ani_info *
141 get_ani_info_from_ani_collection(pui_id id)
142 {
143         default_ani_info *ani_info = NULL;
144
145         //TODO
146         //ex> data->id = id;
147         //ex> data->interval = 30;
148
149         if (!_animations_hash)
150                 return NULL;
151
152         pui_info("... id: %s\n", id);
153
154         ani_info = eina_hash_find(_animations_hash, id);
155
156         if (!ani_info)
157         {
158                 pui_err("ani_info has NOT been found ! (id:%s)\n", id);
159                 return NULL;
160         }
161
162         pui_info("ani_info has been found ! (id:%s)\n", id);
163
164         return ani_info;
165 }
166
167 pui_error
168 _ani_start(pui_ani_t *ani, int repeat)
169 {
170         pui_bool ret = 0;
171         pui_int_error e = PUI_INT_ERROR_NONE;
172         pui_backend_ani_data *ani_data = NULL;
173
174         ani_data = pui_backend_ani_get_ani_data(ani);
175         default_ani_info *info = (default_ani_info *)ani_data->ani_info;
176
177         //TODO
178         (void) info;
179
180         pui_info("... info->id: %s, repeat : %d\n", info->id, repeat);
181
182         pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STARTED);
183         ret = pui_backend_ani_add_frame_cb(ani, _ani_backend_frame_cb, 0.1);
184
185         if (!ret)
186         {
187                 pui_err("Failed to add frame callback !\n");
188                 e = PUI_INT_ERROR_INVALID_RESOURCES;
189         }
190
191         return e;
192 }
193
194 pui_error
195 _ani_stop(pui_ani_t *ani)
196 {
197         pui_int_error e = PUI_INT_ERROR_NONE;
198         pui_backend_ani_data *ani_data = NULL;
199
200         ani_data = pui_backend_ani_get_ani_data(ani);
201         default_ani_info *info = (default_ani_info *)ani_data->ani_info;
202
203         //TODO
204         (void) info;
205
206         pui_info("... info->id: %s\n", info->id);
207
208         pui_backend_ani_remove_frame_cb(ani);
209         pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
210
211         return e;
212 }
213
214 static char *
215 _read_json_file(const char *path, int *data_size)
216 {
217         FILE *fp = fopen(path, "rb");
218         int size;
219         char *buffer;
220         ERROR_CHECK(fp, return NULL, "Failed to open file: %s\n", path);
221
222         fseek(fp, 0, SEEK_END);
223         size = ftell(fp);
224         fseek(fp, 0, SEEK_SET);
225
226         buffer = (char *)calloc(sizeof(char), size + 1);
227
228         if (fread(buffer, size, 1, fp) < 1) {
229                 *data_size = 0;
230                 free(buffer);
231                 fclose(fp);
232                 return NULL;
233         }
234
235         *data_size = size;
236         fclose(fp);
237         return buffer;
238 }
239
240 static default_ani_info *
241 _read_json(const char *path)
242 {
243         char *buffer, *type;
244         json_object *root_obj, *data_obj, *frame_obj, *frame_data_obj, *led_obj, *led_data_obj;
245         default_ani_info *ani_info = NULL;
246         int frame_id = 0, frame_len = 0, led_id = 0, led_len = 0;
247         int data_size = 0, i, j;
248
249         buffer = _read_json_file(path, &data_size);
250         ERROR_CHECK(buffer && data_size > 0, return EINA_FALSE, "File %s has no data\n", path);
251         root_obj = json_tokener_parse(buffer);
252         ERROR_CHECK(root_obj, goto error, "Failed to tokenize json object\n");
253
254         ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
255         ERROR_CHECK(ani_info, goto error, "Failed to alloc for animation info\n");
256
257         data_obj = json_object_object_get(root_obj, "type");
258         //printf("type: %s\n", json_object_get_string(data_obj));
259         type = (char *)json_object_get_string(data_obj);
260         ani_info->id = strndup(type, strlen(type));
261
262         data_obj = json_object_object_get(root_obj, "interval");
263         //printf("interval: %d\n", json_object_get_int(data_obj));
264         ani_info->interval = json_object_get_int(data_obj);
265
266         data_obj = json_object_object_get(root_obj, "frame");
267         frame_len = json_object_array_length(data_obj);
268
269         ani_info->num_key_frames = frame_len;
270         ani_info->frames = (default_frame_info_t *)calloc(sizeof(default_frame_info_t), frame_len);
271         ERROR_CHECK(ani_info->frames, goto error, "Failed to alloc for default_frame_info_t\n");
272         
273         for (i = 0; i < frame_len; i++) {
274                 frame_obj = json_object_array_get_idx(data_obj, i);
275
276                 frame_data_obj = json_object_object_get(frame_obj, "frame_id");
277                 //printf("\tframe id: %d\n", json_object_get_int(frame_data_obj));
278                 frame_id = json_object_get_int(frame_data_obj);
279
280                 frame_data_obj = json_object_object_get(frame_obj, "led");
281                 led_len = json_object_array_length(frame_data_obj);
282                 
283                 ani_info->frames[frame_id - 1].num_led = led_len;
284                 ani_info->frames[frame_id - 1].leds = (default_led_info_t *)calloc(sizeof(default_led_info_t), led_len);
285                 ERROR_CHECK(ani_info->frames[frame_id - 1].leds, goto error, "Failed to alloc for default_led_info_t\n");
286                 
287                 for (j = 0; j < led_len; j++) {
288                         led_obj = json_object_array_get_idx(frame_data_obj, j);
289
290                         led_data_obj = json_object_object_get(led_obj, "id");
291                         //printf("\t\tid: %2d  ", json_object_get_int(led_data_obj));
292                         led_id = json_object_get_int(led_data_obj);
293
294                         led_data_obj = json_object_object_get(led_obj, "color");
295                         //printf("color: %s\n", json_object_get_string(led_data_obj));
296                         ani_info->frames[frame_id - 1].leds[led_id - 1].color =
297                                 strtol(json_object_get_string(led_data_obj), NULL, 16);
298                 }
299         }
300
301         free(buffer);
302         return ani_info;
303
304 error:
305         free(buffer);
306         if (ani_info) {
307                 if (ani_info->frames) {
308                         for (i = 0; i < ani_info->num_key_frames; i++) {
309                                 if (ani_info->frames[i].leds)
310                                         free(ani_info->frames[i].leds);
311                         }
312                         free(ani_info->frames);
313                 }
314                 free(ani_info->id);
315                 free(ani_info);
316         }
317         return NULL;
318 }
319
320 static int
321 _scandir_filter(const struct dirent *dirent)
322 {
323         if (!strncmp(dirent->d_name, ".", sizeof(".")) ||
324                 !strncmp(dirent->d_name, "..", sizeof("..")))
325                 return 0;
326         if (!strstr(dirent->d_name, ".json"))
327                 return 0;
328
329         return 1;
330 }
331
332
333 pui_int_error
334 _create_ani_collection(void)
335 {
336         pui_int_error e = PUI_INT_ERROR_NONE;
337         default_ani_info *ani_info;
338         struct dirent **files;
339         int count, i;
340         char file_path[MAX_STR] = {0, };
341
342         // load and store all of animation data
343
344         if ((count = scandir(ANI_COLLECTION_DIR, &files, _scandir_filter, alphasort)) == -1) {
345                 printf("Failed to get %s directory (%s)\n", ANI_COLLECTION_DIR, strerror(errno));
346                 e = PUI_INT_ERROR_INVALID_RESOURCES;
347                 return e;
348         }
349
350         for (i = 0; i < count; i++) {
351                 snprintf(file_path, sizeof(file_path), "%s%s", ANI_COLLECTION_DIR, files[i]->d_name);
352
353                 ani_info = _read_json(file_path);
354                 if (ani_info) {
355                         eina_hash_add(_animations_hash, ani_info->id, ani_info);
356                         printf("Success to load %s animation\n", files[i]->d_name);
357                 }
358         }
359
360         for (i = 0; i < count; i++) {
361                 free(files[i]);
362         }
363         free(files);
364
365         //TODO
366
367         return e;
368 }
369
370 pui_int_error
371 _is_ani_supported(pui_id id)
372 {
373         pui_int_error e = PUI_INT_ERROR_NONE;
374         default_ani_info *ani_info;
375
376         //TODO
377         /* if the given id is not supported, return PUI_INT_ERROR_ID_NOT_SUPPORTED. */
378         if (!id) {
379                 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
380                 return e;
381         }
382         ani_info = eina_hash_find(_animations_hash, id);
383
384         if (!ani_info)
385                 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
386
387         return e;
388 }
389
390 static void
391 _ani_info_cleanup(default_ani_info *ani_info)
392 {
393         int i;
394
395         if (!ani_info)
396                 return;
397
398         if (ani_info->frames)
399         {
400                 for (i = 0; i < ani_info->num_key_frames; i++)
401                 {
402                         if (ani_info->frames[i].leds)
403                                 free(ani_info->frames[i].leds);
404                 }
405
406                 free(ani_info->frames);
407         }
408
409         free(ani_info->id);
410 }
411
412 pui_backend_ani_data *
413 _ani_create(pui_id id)
414 {
415         pui_backend_ani_data *ani_data = NULL;
416         pui_backend_ani_func *ani_func = NULL;
417
418         /* backend's animation specific info */
419         default_ani_info *ani_info = NULL;
420
421         //TODO : return NULL if the animation correspond to the given id dones't exist.
422         if (PUI_INT_ERROR_NONE != _is_ani_supported(id))
423         {
424                 pui_err("The animation(%s) doesn't supported !\n", id);
425                 return NULL;
426         }
427
428         /* allocation of the structure of function pointers that will be called from pui_ani_control() */
429         ani_func = pui_backend_ani_alloc_ani_func();
430
431         if (!ani_func)
432         {
433                 pui_err("Failed to allocate memory ! (pui backend ani func)\n");
434                 return NULL;
435         }
436
437         /* Assign each function pointer that corresponds to the given id if needed. */
438         ani_func->ani_start = _ani_start;
439         ani_func->ani_stop = _ani_stop;
440
441         /* get animation info associate with the given id from animation collection */
442         ani_info = get_ani_info_from_ani_collection(id);
443         
444         if (!ani_info)
445         {
446                 pui_err("Failed to get ani info from animation collection !\n");
447                 goto err;
448         }
449
450         /* allocate backend ani_data and return it to pui ani core */
451         ani_data = (pui_backend_ani_data *)calloc(1, sizeof(pui_backend_ani_data));
452         
453         if (!ani_data)
454         {
455                 pui_err("Failed to allocate memory for pui backend ani data !\n");
456                 goto err;
457         }
458         
459         ani_data->ani_func = ani_func;
460         ani_data->ani_info = (pui_backend_ani_info *)ani_info;
461
462         g_ani_data = ani_data;
463
464         return ani_data;
465
466 err:
467         if (ani_func)
468         {
469                 pui_backend_ani_free_ani_func(ani_func);
470                 ani_func = NULL;
471         }
472
473         return NULL;
474 }
475
476 void
477 _ani_destroy(pui_backend_ani_data *ani_data)
478 {
479         if (!ani_data)
480                 return;
481
482         if (ani_data->ani_func)
483         {
484                 pui_backend_ani_free_ani_func(ani_data->ani_func);
485                 ani_data->ani_func = NULL;
486         }
487
488         ani_data->ani_info = NULL;
489         g_ani_data = NULL;
490 }
491
492 static void
493 _animation_data_free_cb(void *data)
494 {
495         default_ani_info *ani_info = (default_ani_info *)data;
496
497         _ani_info_cleanup(ani_info);
498 }
499
500 static pui_backend_module_data *
501 pui_default_backend_init(void)
502 {
503         pui_backend_module_data *backend_data = NULL;
504
505         backend_data = (pui_backend_module_data *)calloc(1, sizeof(pui_backend_module_data));
506
507         if (!backend_data)
508         {
509                 pui_err("Failed to allocate memory for pui backend module data !\n");
510                 return NULL;
511         }
512
513         backend_data->create_ani_collection = _create_ani_collection;
514         backend_data->ani_create = _ani_create;
515         backend_data->ani_destroy = _ani_destroy;
516
517         /* Allocate backend specific data if needed. Now it will be empty. */
518         backend_data->data = NULL;
519         _animations_hash = eina_hash_string_superfast_new(NULL);
520
521         return backend_data;
522 }
523
524 static void
525 pui_default_backend_deinit(pui_backend_module_data *backend_data)
526 {
527         Eina_Iterator *it;
528         default_ani_info *ani_info = NULL;
529
530         if (!backend_data)
531                 return;
532
533         if (backend_data->data)
534         {
535                 //TODO : free variables of backend_data
536
537                 free(backend_data->data);
538         }
539
540         if (g_ani_data)
541         {
542                 if (g_ani_data->ani_func)
543                 {
544                         pui_backend_ani_free_ani_func(g_ani_data->ani_func);
545                         g_ani_data->ani_func = NULL;
546                 }
547
548                 g_ani_data->ani_info = NULL;
549         }
550
551         if (_animations_hash)
552         {
553                 it = eina_hash_iterator_data_new(_animations_hash);
554
555                 EINA_ITERATOR_FOREACH(it, ani_info)
556                 {
557                         _animation_data_free_cb(ani_info);
558                         free(ani_info);
559                 }
560
561                 eina_iterator_free(it);
562
563                 eina_hash_free(_animations_hash);
564                 _animations_hash = NULL;
565         }
566
567         backend_data->create_ani_collection = NULL;
568         backend_data->ani_create = NULL;
569         backend_data->ani_destroy = NULL;
570
571         free(backend_data);
572         backend_data = NULL;
573 }
574
575 pui_backend_module pui_backend_module_info = {
576         "Tizen Reference Speaker Backend",
577         "Samsung",
578         PUI_BACKEND_SET_ABI_VERSION(1, 0),
579         pui_default_backend_init,
580         pui_default_backend_deinit
581 };
582