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"
28 pui_backend_ani_func *ani_func = NULL;
29 Eina_Hash *_animations_hash = NULL;
30 pui_backend_ani_data *g_ani_data = NULL;
34 _ani_backend_ease_function_get_intensity(pui_effect_func func, double interval)
36 double intensity = interval;
44 intensity = 1 - cos(PI / 2 * interval);
47 intensity = sin(PI / 2 * interval);
50 intensity = interval * interval;
53 intensity = interval * (2 - interval);
63 _ani_backend_get_value(unsigned int end_frame, unsigned int start_frame, double interval)
67 // interval: frame ratio between key frame to key frame
68 // end_frame and start_frame is key frame
70 res = (end_frame - start_frame) * interval + start_frame;
77 _ani_backend_frame_cb(void *data, int serial)
79 pui_int_error e = PUI_INT_ERROR_NONE;
80 pui_ani_t *ani = (pui_ani_t *)data;
81 pui_backend_ani_data *ani_data = NULL;
82 pui_ani_control_buffer *buffer = NULL;
85 ani_data = pui_backend_ani_get_ani_data(ani);
86 default_ani_info *ani_info = (default_ani_info *)ani_data->ani_info;
88 now = ecore_time_unix_get();
90 pui_info("[time:%.3f] serial=%d\n", now, serial);
92 /* TODO : make use of ani_info */
95 buffer = pui_backend_ani_get_buffer(ani);
99 pui_err("Failed to get buffer !\n");
104 for(int i = 0; i<12; i++)
106 buffer->ptr[4*i] = 0;
107 buffer->ptr[4*i + 1] = (ani_info->frames[ani_info->frame_idx].leds[i].color & LED_MASK_RED) >> 16;//R
108 buffer->ptr[4*i + 2] = (ani_info->frames[ani_info->frame_idx].leds[i].color & LED_MASK_GREEN) >> 8;//G
109 buffer->ptr[4*i + 3] = ani_info->frames[ani_info->frame_idx].leds[i].color & LED_MASK_BLUE;//B
112 e = pui_backend_ani_set_buffer(ani, buffer);
114 if (e != PUI_INT_ERROR_NONE)
116 pui_err("Failed on setting buffer on animation !(e=%d)\n", e);
120 e = pui_backend_ani_update(ani);
122 if (e != PUI_INT_ERROR_NONE)
124 pui_err("Failed on updating animation !(e=%d)\n", e);
128 pui_info("... update (serial=%d)\n", serial);
134 get_ani_info_from_ani_collection(pui_id id)
136 default_ani_info *ani_info = NULL;
138 if (!_animations_hash)
141 pui_info("... id: %s\n", id);
143 ani_info = eina_hash_find(_animations_hash, id);
147 pui_err("ani_info has NOT been found ! (id:%s)\n", id);
151 pui_info("ani_info has been found ! (id:%s)\n", id);
157 _ani_start(pui_ani_t *ani, int repeat)
160 pui_int_error e = PUI_INT_ERROR_NONE;
161 pui_backend_ani_data *ani_data = NULL;
163 ani_data = pui_backend_ani_get_ani_data(ani);
164 default_ani_info *ani_info = (default_ani_info *)ani_data->ani_info;
166 pui_info("... info->id: %s, repeat : %d\n", ani_info->id, repeat);
168 pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STARTED);
169 ret = pui_backend_ani_add_frame_cb(ani, _ani_backend_frame_cb, (double)ani_info->interval / 1000);
173 pui_err("Failed to add frame callback !\n");
174 e = PUI_INT_ERROR_INVALID_RESOURCES;
181 _ani_stop(pui_ani_t *ani, pui_bool force)
183 pui_int_error e = PUI_INT_ERROR_NONE;
184 pui_backend_ani_data *ani_data = NULL;
186 ani_data = pui_backend_ani_get_ani_data(ani);
187 default_ani_info *info = (default_ani_info *)ani_data->ani_info;
192 pui_info("... info->id: %s, force=%d\n", info->id, force);
194 pui_backend_ani_remove_frame_cb(ani);
197 pui_backend_ani_status_update(ani, PUI_ANI_STATUS_PAUSED);
199 pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
205 _read_json_file(const char *path, int *data_size)
207 FILE *fp = fopen(path, "rb");
210 ERROR_CHECK(fp, return NULL, "Failed to open file: %s\n", path);
212 fseek(fp, 0, SEEK_END);
214 fseek(fp, 0, SEEK_SET);
216 buffer = (char *)calloc(sizeof(char), size + 1);
218 if (fread(buffer, size, 1, fp) < 1) {
230 static default_ani_info *
231 _read_json(const char *path)
234 json_object *root_obj, *data_obj, *frame_obj, *frame_data_obj, *led_obj, *led_data_obj;
235 default_ani_info *ani_info = NULL;
236 int frame_id = 0, frame_len = 0, led_id = 0, led_len = 0;
237 int data_size = 0, i, j;
239 buffer = _read_json_file(path, &data_size);
240 ERROR_CHECK(buffer && data_size > 0, return EINA_FALSE, "File %s has no data\n", path);
241 root_obj = json_tokener_parse(buffer);
242 ERROR_CHECK(root_obj, goto error, "Failed to tokenize json object\n");
244 ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
245 ERROR_CHECK(ani_info, goto error, "Failed to alloc for animation info\n");
247 data_obj = json_object_object_get(root_obj, "type");
248 //printf("type: %s\n", json_object_get_string(data_obj));
249 type = (char *)json_object_get_string(data_obj);
250 ani_info->id = strndup(type, strlen(type));
252 data_obj = json_object_object_get(root_obj, "interval");
253 //printf("interval: %d\n", json_object_get_int(data_obj));
254 ani_info->interval = json_object_get_int(data_obj);
256 data_obj = json_object_object_get(root_obj, "frame");
257 frame_len = json_object_array_length(data_obj);
259 ani_info->num_key_frames = frame_len;
260 ani_info->frames = (default_frame_info_t *)calloc(sizeof(default_frame_info_t), frame_len);
261 ERROR_CHECK(ani_info->frames, goto error, "Failed to alloc for default_frame_info_t\n");
263 for (i = 0; i < frame_len; i++) {
264 frame_obj = json_object_array_get_idx(data_obj, i);
266 frame_data_obj = json_object_object_get(frame_obj, "frame_id");
267 //printf("\tframe id: %d\n", json_object_get_int(frame_data_obj));
268 frame_id = json_object_get_int(frame_data_obj);
270 frame_data_obj = json_object_object_get(frame_obj, "frame_duration");
272 ani_info->frames[frame_id - 1].frame_duration = json_object_get_int(frame_data_obj);
274 ani_info->frames[frame_id - 1].frame_duration = ani_info->interval;
276 frame_data_obj = json_object_object_get(frame_obj, "led");
277 led_len = json_object_array_length(frame_data_obj);
279 ani_info->frames[frame_id - 1].num_led = led_len;
280 ani_info->frames[frame_id - 1].leds = (default_led_info_t *)calloc(sizeof(default_led_info_t), led_len);
281 ERROR_CHECK(ani_info->frames[frame_id - 1].leds, goto error, "Failed to alloc for default_led_info_t\n");
283 for (j = 0; j < led_len; j++) {
284 led_obj = json_object_array_get_idx(frame_data_obj, j);
286 led_data_obj = json_object_object_get(led_obj, "id");
287 //printf("\t\tid: %2d ", json_object_get_int(led_data_obj));
288 led_id = json_object_get_int(led_data_obj);
290 led_data_obj = json_object_object_get(led_obj, "color");
291 //printf("color: %s\n", json_object_get_string(led_data_obj));
292 ani_info->frames[frame_id - 1].leds[led_id - 1].color =
293 strtol(json_object_get_string(led_data_obj), NULL, 16);
303 if (ani_info->frames) {
304 for (i = 0; i < ani_info->num_key_frames; i++) {
305 if (ani_info->frames[i].leds)
306 free(ani_info->frames[i].leds);
308 free(ani_info->frames);
317 _find_directory(const char *path, Eina_List **json_list)
321 int count = 0, ret_cnt = 0;
326 pui_err("Failed to open %s.\n", path);
330 while ((cur = readdir(dir)) != NULL)
332 char next_path[MAX_STR] = {0, };
333 if (cur->d_type == DT_DIR)
335 if (!strncmp(cur->d_name, ".", sizeof(".")) ||
336 !strncmp(cur->d_name, "..", sizeof("..")))
339 snprintf(next_path, MAX_STR, "%s/%s", path, cur->d_name);
340 ret_cnt = _find_directory(next_path, json_list);
345 if (strstr(cur->d_name, ".json"))
347 snprintf(next_path, MAX_STR, "%s/%s", path, cur->d_name);
348 *json_list = eina_list_append(*json_list, eina_stringshare_add(next_path));
360 _create_ani_collection(void)
362 pui_int_error e = PUI_INT_ERROR_NONE;
363 default_ani_info *ani_info;
364 Eina_List *json_list = NULL;
365 Eina_List *l, *l_next;
366 Eina_Stringshare *path;
368 // load and store all of animation data
370 _find_directory(ANI_COLLECTION_DIR, &json_list);
372 EINA_LIST_FOREACH_SAFE(json_list, l, l_next, path)
374 ani_info = _read_json(path);
376 eina_hash_add(_animations_hash, ani_info->id, ani_info);
377 pui_info("Success to load %s animation (id: %s)\n", path, ani_info->id);
379 eina_stringshare_del(path);
380 json_list = eina_list_remove_list(json_list, l);
389 _is_ani_supported(pui_id id)
391 pui_int_error e = PUI_INT_ERROR_NONE;
392 default_ani_info *ani_info;
395 /* if the given id is not supported, return PUI_INT_ERROR_ID_NOT_SUPPORTED. */
397 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
400 ani_info = eina_hash_find(_animations_hash, id);
403 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
409 _ani_info_cleanup(default_ani_info *ani_info)
416 if (ani_info->frames)
418 for (i = 0; i < ani_info->num_key_frames; i++)
420 if (ani_info->frames[i].leds)
421 free(ani_info->frames[i].leds);
424 free(ani_info->frames);
430 pui_backend_ani_data *
431 _ani_create(pui_id id)
433 pui_backend_ani_data *ani_data = NULL;
434 pui_backend_ani_func *ani_func = NULL;
436 /* backend's animation specific info */
437 default_ani_info *ani_info = NULL;
439 //TODO : return NULL if the animation correspond to the given id dones't exist.
440 if (PUI_INT_ERROR_NONE != _is_ani_supported(id))
442 pui_err("The animation(%s) doesn't supported !\n", id);
446 /* allocation of the structure of function pointers that will be called from pui_ani_control() */
447 ani_func = pui_backend_ani_alloc_ani_func();
451 pui_err("Failed to allocate memory ! (pui backend ani func)\n");
455 /* get animation info associate with the given id from animation collection */
456 ani_info = get_ani_info_from_ani_collection(id);
460 pui_err("Failed to get ani info from animation collection !\n");
464 /* allocate backend ani_data and return it to pui ani core */
465 ani_data = (pui_backend_ani_data *)calloc(1, sizeof(pui_backend_ani_data));
469 pui_err("Failed to allocate memory for pui backend ani data !\n");
473 /* Assign each function pointer that corresponds to the given id if needed. */
474 if (!strncmp(ani_info->id, "system/easy_setup", sizeof("system/easy_setup")))
476 pui_default_backend_ani_easysetup_func_set(ani_func);
478 else if (!strncmp(ani_info->id, "system/processing", sizeof("system/processing")))
480 pui_default_backend_ani_system_processing_func_set(ani_func);
482 else if (!strncmp(ani_info->id, "system/sw_update_done", sizeof("system/sw_update_done")))
484 pui_default_backend_ani_swupdatedone_func_set(ani_func);
486 else if (!strncmp(ani_info->id, "system/mic_off", sizeof("system/mic_off")))
488 pui_default_backend_ani_micoff_func_set(ani_func);
490 else if (!strncmp(ani_info->id, "voice/listening", sizeof("voice/listening")))
492 pui_default_backend_ani_listening_func_set(ani_func);
494 else if (!strncmp(ani_info->id, "voice/streaming", sizeof("voice/streaming")))
496 pui_default_backend_ani_streaming_func_set(ani_func);
498 else if (!strncmp(ani_info->id, "voice/processing", sizeof("voice/processing")))
500 pui_default_backend_ani_processing_func_set(ani_func);
502 else if (!strncmp(ani_info->id, "voice/speaking", sizeof("voice/speaking")))
504 pui_default_backend_ani_speaking_func_set(ani_func);
506 else if (!strncmp(ani_info->id, "voice/timeout", sizeof("voice/timeout")))
508 pui_default_backend_ani_timeout_func_set(ani_func);
510 else if (!strncmp(ani_info->id, "notification/normal", sizeof("notification/normal")))
512 pui_default_backend_ani_normal_func_set(ani_func);
514 else if (!strncmp(ani_info->id, "notification/emergency", sizeof("notification/emergency")))
516 pui_default_backend_ani_emergency_func_set(ani_func);
518 else if (!strncmp(ani_info->id, "notification/network_error", sizeof("notification/network_error")))
520 pui_default_backend_ani_networkerror_func_set(ani_func);
522 else if (!strncmp(ani_info->id, "notification/error", sizeof("notification/error")))
524 pui_default_backend_ani_error_func_set(ani_func);
526 else if (!strncmp(ani_info->id, "notification/alarm", sizeof("notification/alarm")))
528 pui_default_backend_ani_alarm_func_set(ani_func);
530 else if (!strncmp(ani_info->id, "bt/pairing", sizeof("bt/pairing")))
532 pui_default_backend_ani_pairing_func_set(ani_func);
534 else if (!strncmp(ani_info->id, "bt/connected", sizeof("bt/connected")))
536 pui_default_backend_ani_connected_func_set(ani_func);
540 pui_info("%s animation has no animation handler, using default handler\n", ani_info->id);
541 /* Assign each function pointer that corresponds to the given id if needed. */
542 ani_func->ani_start = _ani_start;
543 ani_func->ani_stop = _ani_stop;
546 ani_data->ani_func = ani_func;
547 ani_data->ani_info = (pui_backend_ani_info *)ani_info;
549 g_ani_data = ani_data;
556 pui_backend_ani_free_ani_func(ani_func);
564 _ani_destroy(pui_backend_ani_data *ani_data)
569 if (ani_data->ani_func)
571 pui_backend_ani_free_ani_func(ani_data->ani_func);
572 ani_data->ani_func = NULL;
575 ani_data->ani_info = NULL;
580 _animation_data_free_cb(void *data)
582 default_ani_info *ani_info = (default_ani_info *)data;
584 _ani_info_cleanup(ani_info);
587 static pui_backend_module_data *
588 pui_default_backend_init(void)
590 pui_backend_module_data *backend_data = NULL;
592 backend_data = (pui_backend_module_data *)calloc(1, sizeof(pui_backend_module_data));
596 pui_err("Failed to allocate memory for pui backend module data !\n");
600 backend_data->create_ani_collection = _create_ani_collection;
601 backend_data->ani_create = _ani_create;
602 backend_data->ani_destroy = _ani_destroy;
604 /* Allocate backend specific data if needed. Now it will be empty. */
605 backend_data->data = NULL;
606 _animations_hash = eina_hash_string_superfast_new(NULL);
612 pui_default_backend_deinit(pui_backend_module_data *backend_data)
615 default_ani_info *ani_info = NULL;
620 if (backend_data->data)
622 //TODO : free variables of backend_data
624 free(backend_data->data);
629 if (g_ani_data->ani_func)
631 pui_backend_ani_free_ani_func(g_ani_data->ani_func);
632 g_ani_data->ani_func = NULL;
635 g_ani_data->ani_info = NULL;
638 if (_animations_hash)
640 it = eina_hash_iterator_data_new(_animations_hash);
642 EINA_ITERATOR_FOREACH(it, ani_info)
644 _animation_data_free_cb(ani_info);
648 eina_iterator_free(it);
650 eina_hash_free(_animations_hash);
651 _animations_hash = NULL;
654 backend_data->create_ani_collection = NULL;
655 backend_data->ani_create = NULL;
656 backend_data->ani_destroy = NULL;
662 pui_backend_module pui_backend_module_info = {
663 "Tizen Reference Speaker Backend",
665 PUI_BACKEND_SET_ABI_VERSION(1, 0),
666 pui_default_backend_init,
667 pui_default_backend_deinit