2 * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
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:
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.
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
26 #include "default_backend.h"
29 static Eina_Hash *_animations_hash = NULL;
30 static pui_backend_ani_data *g_ani_data = NULL;
33 _ani_backend_frame_cb(void *data, int serial)
35 pui_int_error e = PUI_INT_ERROR_NONE;
36 pui_ani_t *ani = (pui_ani_t *)data;
37 pui_backend_ani_data *ani_data = NULL;
38 pui_ani_control_buffer *buffer = NULL;
40 ani_data = pui_backend_ani_get_ani_data(ani);
41 default_ani_info *ani_info = (default_ani_info *)ani_data->ani_info;
43 /* TODO : make use of ani_info */
46 buffer = pui_backend_ani_get_buffer(ani);
50 pui_err("Failed to get buffer !\n");
55 for(int i = 0; i<12; i++)
58 buffer->ptr[4*i + 1] = (ani_info->frames[ani_info->frame_idx].leds[i].color & LED_MASK_RED) >> 16;//R
59 buffer->ptr[4*i + 2] = (ani_info->frames[ani_info->frame_idx].leds[i].color & LED_MASK_GREEN) >> 8;//G
60 buffer->ptr[4*i + 3] = ani_info->frames[ani_info->frame_idx].leds[i].color & LED_MASK_BLUE;//B
63 e = pui_backend_ani_set_buffer(ani, buffer);
65 if (e != PUI_INT_ERROR_NONE)
67 pui_err("Failed on setting buffer on animation !(e=%d)\n", e);
71 e = pui_backend_ani_update(ani);
73 if (e != PUI_INT_ERROR_NONE)
75 pui_err("Failed on updating animation !(e=%d)\n", e);
79 pui_info("... update (serial=%d)\n", serial);
85 get_ani_info_from_ani_collection(pui_id id)
87 default_ani_info *ani_info = NULL;
89 if (!_animations_hash)
92 pui_info("... id: %s\n", id);
94 ani_info = eina_hash_find(_animations_hash, id);
98 pui_err("ani_info has NOT been found ! (id:%s)\n", id);
102 pui_info("ani_info has been found ! (id:%s)\n", id);
108 _ani_start(pui_ani_t *ani, int repeat)
111 pui_int_error e = PUI_INT_ERROR_NONE;
112 pui_backend_ani_data *ani_data = NULL;
114 ani_data = pui_backend_ani_get_ani_data(ani);
115 default_ani_info *ani_info = (default_ani_info *)ani_data->ani_info;
117 pui_info("... info->id: %s, repeat : %d\n", ani_info->id, repeat);
119 pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STARTED);
120 ret = pui_backend_ani_add_frame_cb(ani, _ani_backend_frame_cb, (double)ani_info->interval / 1000);
124 pui_err("Failed to add frame callback !\n");
125 e = PUI_INT_ERROR_INVALID_RESOURCES;
132 _ani_stop(pui_ani_t *ani, pui_bool force)
134 pui_int_error e = PUI_INT_ERROR_NONE;
135 pui_backend_ani_data *ani_data = NULL;
137 ani_data = pui_backend_ani_get_ani_data(ani);
138 default_ani_info *info = (default_ani_info *)ani_data->ani_info;
143 pui_info("... info->id: %s, force=%d\n", info->id, force);
145 pui_backend_ani_remove_frame_cb(ani);
148 pui_backend_ani_status_update(ani, PUI_ANI_STATUS_PAUSED);
150 pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
156 _read_json_file(const char *path, int *data_size)
158 FILE *fp = fopen(path, "rb");
161 ERROR_CHECK(fp, return NULL, "Failed to open file: %s\n", path);
163 ret = fseek(fp, 0, SEEK_END);
164 ERROR_CHECK(ret == 0, goto error, "Failed to seek file. ret: %d\n", ret);
165 size = (long int)ftell(fp);
166 ERROR_CHECK(0 < size && size < INT_MAX, goto error, "Invalid file: %d size\n", size);
167 ret = fseek(fp, 0, SEEK_SET);
168 ERROR_CHECK(ret == 0, goto error, "Failed to seek file. ret: %d\n", ret);
170 buffer = (char *)calloc(sizeof(char), size + 1);
171 ERROR_CHECK(buffer, goto error, "Failed to allocate memory for buffer\n");
173 if (fread(buffer, size, 1, fp) < 1) {
183 if (buffer) free(buffer);
188 static default_ani_info *
189 _read_json(const char *path)
192 json_object *root_obj, *data_obj, *frame_obj, *frame_data_obj, *led_obj, *led_data_obj;
193 default_ani_info *ani_info = NULL;
194 int frame_id = 0, frame_len = 0, led_id = 0, led_len = 0;
195 int data_size = 0, i, j;
197 buffer = _read_json_file(path, &data_size);
198 ERROR_CHECK(buffer && data_size > 0, goto error, "File %s has no data\n", path);
199 root_obj = json_tokener_parse(buffer);
200 ERROR_CHECK(root_obj, goto error, "Failed to tokenize json object\n");
202 ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
203 ERROR_CHECK(ani_info, goto error, "Failed to alloc for animation info\n");
205 data_obj = json_object_object_get(root_obj, "type");
206 //printf("type: %s\n", json_object_get_string(data_obj));
207 type = (char *)json_object_get_string(data_obj);
208 ani_info->id = strndup(type, strlen(type));
210 data_obj = json_object_object_get(root_obj, "interval");
211 //printf("interval: %d\n", json_object_get_int(data_obj));
212 ani_info->interval = json_object_get_int(data_obj);
214 data_obj = json_object_object_get(root_obj, "frame");
215 frame_len = json_object_array_length(data_obj);
217 ani_info->num_key_frames = frame_len;
218 ani_info->frames = (default_frame_info_t *)calloc(sizeof(default_frame_info_t), frame_len);
219 ERROR_CHECK(ani_info->frames, goto error, "Failed to alloc for default_frame_info_t\n");
221 for (i = 0; i < frame_len; i++) {
222 frame_obj = json_object_array_get_idx(data_obj, i);
224 frame_data_obj = json_object_object_get(frame_obj, "frame_id");
225 //printf("\tframe id: %d\n", json_object_get_int(frame_data_obj));
226 frame_id = json_object_get_int(frame_data_obj);
228 frame_data_obj = json_object_object_get(frame_obj, "frame_duration");
230 ani_info->frames[frame_id - 1].frame_duration = json_object_get_int(frame_data_obj);
232 ani_info->frames[frame_id - 1].frame_duration = ani_info->interval;
234 frame_data_obj = json_object_object_get(frame_obj, "led");
235 led_len = json_object_array_length(frame_data_obj);
237 ani_info->frames[frame_id - 1].num_led = led_len;
238 if (ani_info->max_leds < led_len) ani_info->max_leds = led_len;
239 ani_info->frames[frame_id - 1].leds = (default_led_info_t *)calloc(sizeof(default_led_info_t), led_len);
240 ERROR_CHECK(ani_info->frames[frame_id - 1].leds, goto error, "Failed to alloc for default_led_info_t\n");
242 for (j = 0; j < led_len; j++) {
243 led_obj = json_object_array_get_idx(frame_data_obj, j);
245 led_data_obj = json_object_object_get(led_obj, "id");
246 //printf("\t\tid: %2d ", json_object_get_int(led_data_obj));
247 led_id = json_object_get_int(led_data_obj);
249 led_data_obj = json_object_object_get(led_obj, "color");
250 //printf("color: %s\n", json_object_get_string(led_data_obj));
251 ani_info->frames[frame_id - 1].leds[led_id - 1].color =
252 strtol(json_object_get_string(led_data_obj), NULL, 16);
260 if (buffer) free(buffer);
262 if (ani_info->frames) {
263 for (i = 0; i < ani_info->num_key_frames; i++) {
264 if (ani_info->frames[i].leds)
265 free(ani_info->frames[i].leds);
267 free(ani_info->frames);
276 _find_directory(const char *path, Eina_List **json_list)
280 int count = 0, ret_cnt = 0;
285 pui_err("Failed to open %s.\n", path);
289 while ((cur = readdir(dir)) != NULL)
291 char next_path[MAX_STR] = {0, };
292 if (cur->d_type == DT_DIR)
294 if (!strncmp(cur->d_name, ".", sizeof(".")) ||
295 !strncmp(cur->d_name, "..", sizeof("..")))
298 snprintf(next_path, MAX_STR, "%s/%s", path, cur->d_name);
299 ret_cnt = _find_directory(next_path, json_list);
304 if (strstr(cur->d_name, ".json"))
306 snprintf(next_path, MAX_STR, "%s/%s", path, cur->d_name);
307 *json_list = eina_list_append(*json_list, eina_stringshare_add(next_path));
318 _create_default_ani_info(char *type)
320 default_ani_info *ani_info = NULL;
324 ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
325 ERROR_CHECK(ani_info, goto error, "Failed to alloc for animation info\n");
327 ani_info->id = strndup(type, strlen(type));
328 ani_info->interval = 50;
330 ani_info->num_key_frames = frame_len;
331 ani_info->frames = (default_frame_info_t *)calloc(sizeof(default_frame_info_t), frame_len);
332 ERROR_CHECK(ani_info->frames, goto error, "Failed to alloc for default_frame_info_t\n");
334 ani_info->frames[0].frame_duration = 500;
335 ani_info->frames[0].num_led = led_len;
336 ani_info->max_leds = led_len;
337 ani_info->frames[0].leds = (default_led_info_t *)calloc(sizeof(default_led_info_t), led_len);
338 ERROR_CHECK(ani_info->frames[0].leds, goto error, "Failed to alloc for default_led_info_t\n");
344 if (ani_info->frames) {
345 for (int i = 0; i < ani_info->num_key_frames; i++) {
346 if (ani_info->frames[i].leds)
347 free(ani_info->frames[i].leds);
349 free(ani_info->frames);
359 _create_ani_collection(void)
361 pui_int_error e = PUI_INT_ERROR_NONE;
362 default_ani_info *ani_info;
363 Eina_List *json_list = NULL;
364 Eina_List *l, *l_next;
365 Eina_Stringshare *path;
367 // load and store all of animation data
369 _find_directory(ANI_COLLECTION_DIR, &json_list);
371 pui_err("Start create ani collect...\n");
373 EINA_LIST_FOREACH_SAFE(json_list, l, l_next, path)
375 ani_info = _read_json(path);
377 eina_hash_add(_animations_hash, ani_info->id, ani_info);
378 pui_info("Success to load %s animation (id: %s)\n", path, ani_info->id);
380 eina_stringshare_del(path);
381 json_list = eina_list_remove_list(json_list, l);
385 ani_info = _create_default_ani_info("default/clear_fadeout");
387 eina_hash_add(_animations_hash, ani_info->id, ani_info);
388 pui_err("Success to load default animation (id: %s)\n", ani_info->id);
390 ani_info = _create_default_ani_info("default/clear_immediate");
392 eina_hash_add(_animations_hash, ani_info->id, ani_info);
393 pui_err("Success to load default animation (id: %s)\n", ani_info->id);
396 pui_err("End create ani collect...\n");
402 _geometry_get(int *width, int *height)
404 if (!width || !height)
408 *width = DEFAULT_BACKEND_GEOM_WIDTH;
410 *height = DEFAULT_BACKEND_GEOM_HEIGHT;
416 _is_ani_supported(pui_id id)
418 pui_int_error e = PUI_INT_ERROR_NONE;
419 default_ani_info *ani_info;
422 /* if the given id is not supported, return PUI_INT_ERROR_ID_NOT_SUPPORTED. */
424 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
427 ani_info = eina_hash_find(_animations_hash, id);
430 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
436 _ani_info_cleanup(default_ani_info *ani_info)
443 if (ani_info->frames)
445 for (i = 0; i < ani_info->num_key_frames; i++)
447 if (ani_info->frames[i].leds)
448 free(ani_info->frames[i].leds);
451 free(ani_info->frames);
457 pui_backend_ani_data *
458 _ani_create(pui_id id)
460 pui_backend_ani_data *ani_data = NULL;
461 pui_backend_ani_func *ani_func = NULL;
463 /* backend's animation specific info */
464 default_ani_info *ani_info = NULL;
466 //TODO : return NULL if the animation correspond to the given id dones't exist.
467 if (PUI_INT_ERROR_NONE != _is_ani_supported(id))
469 pui_err("The animation(%s) doesn't supported !\n", id);
473 /* allocation of the structure of function pointers that will be called from pui_ani_control() */
474 ani_func = pui_backend_ani_alloc_ani_func();
478 pui_err("Failed to allocate memory ! (pui backend ani func)\n");
482 /* get animation info associate with the given id from animation collection */
483 ani_info = get_ani_info_from_ani_collection(id);
487 pui_err("Failed to get ani info from animation collection !\n");
491 /* allocate backend ani_data and return it to pui ani core */
492 ani_data = (pui_backend_ani_data *)calloc(1, sizeof(pui_backend_ani_data));
496 pui_err("Failed to allocate memory for pui backend ani data !\n");
500 /* Assign each function pointer that corresponds to the given id if needed. */
501 if (!strncmp(ani_info->id, "system/easy_setup", sizeof("system/easy_setup")))
503 pui_default_backend_ani_easysetup_func_set(ani_func);
505 else if (!strncmp(ani_info->id, "system/processing", sizeof("system/processing")))
507 pui_default_backend_ani_system_processing_func_set(ani_func);
509 else if (!strncmp(ani_info->id, "system/sw_update_done", sizeof("system/sw_update_done")))
511 pui_default_backend_ani_swupdatedone_func_set(ani_func);
513 else if (!strncmp(ani_info->id, "system/mic_off", sizeof("system/mic_off")))
515 pui_default_backend_ani_micoff_func_set(ani_func);
517 else if (!strncmp(ani_info->id, "voice/listening", sizeof("voice/listening")))
519 pui_default_backend_ani_listening_func_set(ani_func);
521 else if (!strncmp(ani_info->id, "voice/streaming", sizeof("voice/streaming")))
523 pui_default_backend_ani_streaming_func_set(ani_func);
525 else if (!strncmp(ani_info->id, "voice/processing", sizeof("voice/processing")))
527 pui_default_backend_ani_processing_func_set(ani_func);
529 else if (!strncmp(ani_info->id, "voice/speaking", sizeof("voice/speaking")))
531 pui_default_backend_ani_speaking_func_set(ani_func);
533 else if (!strncmp(ani_info->id, "voice/timeout", sizeof("voice/timeout")))
535 pui_default_backend_ani_timeout_func_set(ani_func);
537 else if (!strncmp(ani_info->id, "notification/normal", sizeof("notification/normal")))
539 pui_default_backend_ani_normal_func_set(ani_func);
541 else if (!strncmp(ani_info->id, "notification/emergency", sizeof("notification/emergency")))
543 pui_default_backend_ani_emergency_func_set(ani_func);
545 else if (!strncmp(ani_info->id, "notification/network_error", sizeof("notification/network_error")))
547 pui_default_backend_ani_networkerror_func_set(ani_func);
549 else if (!strncmp(ani_info->id, "notification/error", sizeof("notification/error")))
551 pui_default_backend_ani_error_func_set(ani_func);
553 else if (!strncmp(ani_info->id, "notification/alarm", sizeof("notification/alarm")))
555 pui_default_backend_ani_alarm_func_set(ani_func);
557 else if (!strncmp(ani_info->id, "bt/pairing", sizeof("bt/pairing")))
559 pui_default_backend_ani_pairing_func_set(ani_func);
561 else if (!strncmp(ani_info->id, "bt/connected", sizeof("bt/connected")))
563 pui_default_backend_ani_connected_func_set(ani_func);
565 else if (!strncmp(ani_info->id, "default/clear_fadeout", sizeof("default/clear_fadeout")))
567 pui_default_backend_ani_clear_fadeout_func_set(ani_func);
569 else if (!strncmp(ani_info->id, "default/clear_immediate", sizeof("default/clear_immediate")))
571 pui_default_backend_ani_clear_immediate_func_set(ani_func);
575 pui_info("%s animation has no animation handler, using default handler\n", ani_info->id);
576 /* Assign each function pointer that corresponds to the given id if needed. */
577 ani_func->ani_start = _ani_start;
578 ani_func->ani_stop = _ani_stop;
581 ani_data->ani_func = ani_func;
582 ani_data->ani_info = (pui_backend_ani_info *)ani_info;
584 g_ani_data = ani_data;
591 pui_backend_ani_free_ani_func(ani_func);
599 _ani_destroy(pui_backend_ani_data *ani_data)
604 if (ani_data->ani_func)
606 pui_backend_ani_free_ani_func(ani_data->ani_func);
607 ani_data->ani_func = NULL;
610 ani_data->ani_info = NULL;
615 _animation_data_free_cb(void *data)
617 default_ani_info *ani_info = (default_ani_info *)data;
619 _ani_info_cleanup(ani_info);
622 default_frame_info_t *
623 backend_util_alloc_frame(default_ani_info *ani_info)
625 default_frame_info_t *frame;
627 frame = (default_frame_info_t *)calloc(sizeof(default_frame_info_t), 1);
628 ERROR_CHECK(frame, return NULL, "Failed to allocate memory for frame\n");
630 frame->leds = (default_led_info_t *)calloc(sizeof(default_led_info_t), ani_info->max_leds);
631 ERROR_CHECK(frame->leds, goto error, "Failed to allocate memory for led\n");
633 frame->num_led = ani_info->max_leds;
643 backend_util_cleanup_frame(default_frame_info_t *frame)
645 ERROR_CHECK(frame, return, "Invalid frame to cleanup\n");
647 for (int i = 0; i < frame->num_led; i++)
649 frame->leds[i].color = 0x0;
651 frame->frame_duration = 0;
655 backend_util_free_frame(default_frame_info_t *frame)
659 if (frame->leds) free(frame->leds);
664 pui_default_backend_ani_get_led_rgb(default_frame_info_t *frame,
671 if (!r || !g || !b) return;
672 if (led_idx > frame->num_led) return;
674 *r = (frame->leds[led_idx].color & LED_MASK_RED) >> 16;
675 *g = (frame->leds[led_idx].color & LED_MASK_GREEN) >> 8;
676 *b = (frame->leds[led_idx].color & LED_MASK_BLUE);
680 pui_default_backend_ani_update_frame(pui_ani_t *ani,
681 pui_backend_ani_data *ani_data,
682 pui_ani_control_buffer *buffer,
683 default_frame_info_t *frame,
686 pui_int_error e = PUI_INT_ERROR_NONE;
687 default_ani_info *ani_info = (default_ani_info *)ani_data->ani_info;
688 unsigned int r = 0x0, g = 0x0, b = 0x0;
690 for(int i = 0; i<12; i++)
692 pui_default_backend_ani_get_led_rgb(frame, i, &r, &g, &b);
693 buffer->ptr[4*i] = 0;
694 buffer->ptr[4*i + 1] = b; /* BLUE */
695 buffer->ptr[4*i + 2] = g; /* GREEN */
696 buffer->ptr[4*i + 3] = r; /* RED */
698 backend_util_cleanup_frame(frame);
700 e = pui_backend_ani_set_buffer(ani, buffer);
702 if (e != PUI_INT_ERROR_NONE)
704 pui_err("Failed on setting buffer on animation !(e=%d)\n", e);
708 e = pui_backend_ani_update(ani);
710 if (e != PUI_INT_ERROR_NONE)
712 pui_err("Failed on updating animation !(e=%d)\n", e);
716 pui_info("... update (serial=%d), (repeat| cur: %d, want: %d)\n",
717 serial, ani_info->repeat_cur, ani_info->repeat);
719 if (ani_info->repeat >= 0 &&
720 ani_info->repeat_cur >= ani_info->repeat)
722 ani_data->ani_func->ani_stop(ani, EINA_FALSE);
728 static pui_backend_module_data *
729 pui_default_backend_init(void)
731 pui_backend_module_data *backend_data = NULL;
733 backend_data = (pui_backend_module_data *)calloc(1, sizeof(pui_backend_module_data));
737 pui_err("Failed to allocate memory for pui backend module data !\n");
741 backend_data->create_ani_collection = _create_ani_collection;
742 backend_data->geometry_get = _geometry_get;
743 backend_data->ani_create = _ani_create;
744 backend_data->ani_destroy = _ani_destroy;
746 /* Allocate backend specific data if needed. Now it will be empty. */
747 backend_data->data = NULL;
748 _animations_hash = eina_hash_string_superfast_new(NULL);
754 pui_default_backend_deinit(pui_backend_module_data *backend_data)
757 default_ani_info *ani_info = NULL;
762 if (backend_data->data)
764 //TODO : free variables of backend_data
766 free(backend_data->data);
771 if (g_ani_data->ani_func)
773 pui_backend_ani_free_ani_func(g_ani_data->ani_func);
774 g_ani_data->ani_func = NULL;
777 g_ani_data->ani_info = NULL;
780 if (_animations_hash)
782 it = eina_hash_iterator_data_new(_animations_hash);
784 EINA_ITERATOR_FOREACH(it, ani_info)
786 _animation_data_free_cb(ani_info);
790 eina_iterator_free(it);
792 eina_hash_free(_animations_hash);
793 _animations_hash = NULL;
796 backend_data->create_ani_collection = NULL;
797 backend_data->geometry_get = NULL;
798 backend_data->ani_create = NULL;
799 backend_data->ani_destroy = NULL;
805 pui_backend_module pui_backend_module_info = {
806 "Tizen Reference Speaker Backend",
808 PUI_BACKEND_SET_ABI_VERSION(1, 0),
809 pui_default_backend_init,
810 pui_default_backend_deinit