backend: add default_backend initial codes
[platform/core/uifw/libpui.git] / backends / default_backend.c
index f0ca99d..d626c69 100644 (file)
@@ -1,9 +1,29 @@
-#include <PUI.h>
+//#include <PUI.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <PUI_backend.h>
 
+#include <json-c/json.h>
+#include <dirent.h>
+#include <errno.h>
+#include <Eina.h>
+
+#define ANI_COLLECTION_DIR "/run/pui/"
+#define MAX_STR 1024
+
+#define ERROR_CHECK(exp, action, fmt, ...) \
+       do { \
+               if (!(exp)) \
+               { \
+                       printf(fmt, ##__VA_ARGS__);     \
+                       action; \
+               } \
+       } while (0)
+
 pui_backend_ani_func *ani_func = NULL;
+Eina_Hash *_animations_hash = NULL;
 
-enum
+typedef enum
 {
        None,
        Linear,
@@ -13,8 +33,11 @@ enum
        EaseOutQuart
 } pui_effect_func;
 
-typedef struct _default_ani_data default_ani_data;
-struct _default_ani_data
+typedef struct _default_ani_info default_ani_info;
+typedef struct _default_frame_info_t default_frame_info_t;
+typedef struct _default_led_info_t default_led_info_t;
+
+struct _default_ani_info
 {
        pui_id id;
        pui_ani_status status;
@@ -23,35 +46,40 @@ struct _default_ani_data
 
        unsigned int key_frame_idx;
        unsigned int num_key_frames;
-       double interval;
+       default_frame_info_t *frames;
+       int interval;
        pui_effect_func effect_func;
+};
 
-       Eina_Bool (*frame_cb)(void *data);
-
-/*
-       void *frame_cb_data;
-       double expire;
-       Ecore_Timer *frame_cb_timer;
-*/
+struct _default_frame_info_t
+{
+       default_led_info_t *leds;
+       int num_led;
 };
 
-static void
-_start_frame(pui_ani_mgr *ani_mgr)
+struct _default_led_info_t
 {
-       //TODO
-}
+       unsigned int color;
+};
+
+pui_backend_ani_data *g_ani_data = NULL;
 
-static Eina_Bool
-_frame_cb(void *data)
+static pui_bool
+_frame_cb(void *data, int serial)
 {
+       pui_ani_t *ani = (pui_ani_t *)data;
+
        //TODO
+       (void) ani;
        //_get_next_frame();
        //pui_backend_ani_get_buffer();
        //pui_backend_ani_update();
+
+       return (pui_bool)1;
 }
 
 pui_int_error
-get_ani_data_from_collection(default_ani_data *data, pui_id id)
+get_ani_info_from_ani_collection(default_ani_info *info, pui_id id)
 {
        pui_int_error e = PUI_INT_ERROR_NONE;
 
@@ -62,66 +90,193 @@ get_ani_data_from_collection(default_ani_data *data, pui_id id)
        return e;
 }
 
-pui_backend_ani_data *
-_ani_create(pui_ani_mgr *ani_mgr, pui_id id)
+pui_error
+_ani_start(pui_ani_t *ani, int repeat)
 {
-       pui_int_error e = PUI_INT_ERROR_NONE; 
-       default_ani_data *data = (default_ani_data *)calloc(1, sizeof(default_ani_data));
-
-       if (!data)
-       {
-               pui_err("Failed to allocate memory !\n");
-               return NULL;
-       }
+       pui_int_error e = PUI_INT_ERROR_NONE;
+       pui_backend_ani_data *ani_data = NULL;
 
-       e = get_ani_data_from_collection(data, id);
+       ani_data = pui_backend_ani_get_ani_data(ani);
+       default_ani_info *info = (default_ani_info *)ani_data->ani_info;
 
-       if (PUI_INT_ERROR_NONE != e)
-       {
-               pui_err("Failed to get ani data from collection !\n");
-               goto err;
-       }
-       
-       return (pui_backend_ani_data *)default_ani_data;
+       //TODO
+       (void) info;
 
-err:
-       if (data)
-               free(data);
+       pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STARTED);
+       pui_backend_ani_add_frame_cb(ani, _frame_cb, 0.1);
 
-       return NULL;
+       return e;
 }
 
 pui_error
-_ani_start(pui_ani_mgr *ani_mgr, int repeat)
+_ani_stop(pui_ani_t *ani)
 {
        pui_int_error e = PUI_INT_ERROR_NONE;
+       pui_backend_ani_data *ani_data = NULL;
 
-       default_ani_data *data = (default_ani_data *)ani_mgr->ani_data;
+       ani_data = pui_backend_ani_get_ani_data(ani);
+       default_ani_info *info = (default_ani_info *)ani_data->ani_info;
 
        //TODO
-       //start_frame(ani_mgr);
-       //pui_backend_ani_add_frame_cb(data->frame_cb);
+       (void) info;
+
+       pui_backend_ani_remove_frame_cb(ani);
+       pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
 
        return e;
 }
 
-pui_error
-_ani_stop(pui_ani_mgr *ani_mgr)
+static char *
+_read_json_file(const char *path, int *data_size)
 {
-       pui_int_error e = PUI_INT_ERROR_NONE;
+       FILE *fp = fopen(path, "rb");
+       int size;
+       char *buffer;
+       ERROR_CHECK(fp, return NULL, "Failed to open file: %s\n", path);
 
-       default_ani_data *data = (default_ani_data *)ani_mgr->ani_data;
+       fseek(fp, 0, SEEK_END);
+       size = ftell(fp);
+       fseek(fp, 0, SEEK_SET);
 
-       //TODO
-       //pui_backend_ani_remove_frame_cb(data->frame_cb);
+       buffer = (char *)calloc(sizeof(char), size + 1);
 
-       return e;
+       if (fread(buffer, size, 1, fp) < 1) {
+               *data_size = 0;
+               free(buffer);
+               fclose(fp);
+               return NULL;
+       }
+
+       *data_size = size;
+       fclose(fp);
+       return buffer;
+}
+
+static default_ani_info *
+_read_json(const char *path)
+{
+       char *buffer, *type;
+       json_object *root_obj, *data_obj, *frame_obj, *frame_data_obj, *led_obj, *led_data_obj;
+       default_ani_info *ani_info = NULL;
+       int frame_id = 0, frame_len = 0, led_id = 0, led_len = 0;
+       int data_size = 0, i, j;
+
+       buffer = _read_json_file(path, &data_size);
+       ERROR_CHECK(buffer && data_size > 0, return EINA_FALSE, "File %s has no data\n", path);
+       root_obj = json_tokener_parse(buffer);
+       ERROR_CHECK(root_obj, goto error, "Failed to tokenize json object\n");
+
+       ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
+       ERROR_CHECK(ani_info, goto error, "Failed to alloc for animation info\n");
+
+       data_obj = json_object_object_get(root_obj, "type");
+       //printf("type: %s\n", json_object_get_string(data_obj));
+       type = (char *)json_object_get_string(data_obj);
+       ani_info->id = strndup(type, strlen(type));
+
+       data_obj = json_object_object_get(root_obj, "interval");
+       //printf("interval: %d\n", json_object_get_int(data_obj));
+       ani_info->interval = json_object_get_int(data_obj);
+
+       data_obj = json_object_object_get(root_obj, "frame");
+       frame_len = json_object_array_length(data_obj);
+
+       ani_info->num_key_frames = frame_len;
+       ani_info->frames = (default_frame_info_t *)calloc(sizeof(default_frame_info_t), frame_len);
+       ERROR_CHECK(ani_info->frames, goto error, "Failed to alloc for default_frame_info_t\n");
+       
+       for (i = 0; i < frame_len; i++) {
+               frame_obj = json_object_array_get_idx(data_obj, i);
+
+               frame_data_obj = json_object_object_get(frame_obj, "frame_id");
+               //printf("\tframe id: %d\n", json_object_get_int(frame_data_obj));
+               frame_id = json_object_get_int(frame_data_obj);
+
+               frame_data_obj = json_object_object_get(frame_obj, "led");
+               led_len = json_object_array_length(frame_data_obj);
+               
+               ani_info->frames[frame_id - 1].num_led = led_len;
+               ani_info->frames[frame_id - 1].leds = (default_led_info_t *)calloc(sizeof(default_led_info_t), led_len);
+               ERROR_CHECK(ani_info->frames[frame_id - 1].leds, goto error, "Failed to alloc for default_led_info_t\n");
+               
+               for (j = 0; j < led_len; j++) {
+                       led_obj = json_object_array_get_idx(frame_data_obj, j);
+
+                       led_data_obj = json_object_object_get(led_obj, "id");
+                       //printf("\t\tid: %2d  ", json_object_get_int(led_data_obj));
+                       led_id = json_object_get_int(led_data_obj);
+
+                       led_data_obj = json_object_object_get(led_obj, "color");
+                       //printf("color: %s\n", json_object_get_string(led_data_obj));
+                       ani_info->frames[frame_id - 1].leds[led_id - 1].color =
+                               strtol(json_object_get_string(led_data_obj), NULL, 16);
+               }
+       }
+
+       free(buffer);
+       return ani_info;
+
+error:
+       free(buffer);
+       if (ani_info) {
+               if (ani_info->frames) {
+                       for (i = 0; i < ani_info->num_key_frames; i++) {
+                               if (ani_info->frames[i].leds)
+                                       free(ani_info->frames[i].leds);
+                       }
+                       free(ani_info->frames);
+               }
+               free(ani_info->id);
+               free(ani_info);
+       }
+       return NULL;
 }
 
+static int
+_scandir_filter(const struct dirent *dirent)
+{
+       if (!strncmp(dirent->d_name, ".", sizeof(".")) ||
+               !strncmp(dirent->d_name, "..", sizeof("..")))
+               return 0;
+       if (!strstr(dirent->d_name, ".json"))
+               return 0;
+
+       return 1;
+}
+
+
 pui_int_error
 _create_ani_collection(void)
 {
        pui_int_error e = PUI_INT_ERROR_NONE;
+       default_ani_info *ani_info;
+       struct dirent **files;
+       int count, i;
+       char file_path[MAX_STR] = {0, };
+
+       // load and store all of animation data
+
+       if ((count = scandir(ANI_COLLECTION_DIR, &files, _scandir_filter, alphasort)) == -1) {
+               printf("Failed to get %s directory (%s)\n", ANI_COLLECTION_DIR, strerror(errno));
+               e = PUI_INT_ERROR_INVALID_RESOURCES;
+               return e;
+       }
+
+       for (i = 0; i < count; i++) {
+               snprintf(file_path, sizeof(file_path), "%s%s", ANI_COLLECTION_DIR, files[i]->d_name);
+
+               ani_info = _read_json(file_path);
+               if (ani_info) {
+                       eina_hash_add(_animations_hash, ani_info->id, ani_info);
+                       printf("Success to load %s animation\n", files[i]->d_name);
+               }
+               memset(file_path, 0, sizeof(file_path));
+       }
+
+       for (i = 0; i < count; i++) {
+               free(files[i]);
+       }
+       free(files);
 
        //TODO
 
@@ -132,29 +287,62 @@ pui_int_error
 _is_ani_supported(pui_id id)
 {
        pui_int_error e = PUI_INT_ERROR_NONE;
+       default_ani_info *ani_info;
 
        //TODO
        /* if the given id is not supported, return PUI_INT_ERROR_ID_NOT_SUPPORTED. */
+       if (!id) {
+               e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
+               return e;
+       }
+       ani_info = eina_hash_find(_animations_hash, id);
+       if (!ani_info) e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
 
        return e;
 }
 
-pui_backend_ani_func *
-_get_ani_func(pui_id id)
+static void
+_ani_info_cleanup(default_ani_info *ani_info)
 {
-       if (ani_func)
-               return ani_func;
+       int i;
+
+       if (!ani_info) return;
+
+       eina_hash_del(_animations_hash, ani_info->id, ani_info);
+       if (ani_info->frames) {
+               for (i = 0; i < ani_info->num_key_frames; i++) {
+                       if (ani_info->frames[i].leds)
+                               free(ani_info->frames[i].leds);
+               }
+               free(ani_info->frames);
+       }
+       free(ani_info->id);
+       free(ani_info);
+}
 
+pui_backend_ani_data *
+_ani_create(pui_id id)
+{
+       pui_int_error e = PUI_INT_ERROR_NONE;
+
+       pui_backend_ani_data *ani_data = NULL;
+       pui_backend_ani_func *ani_func = NULL;
+
+       /* backend's animation specific info */
+       default_ani_info *ani_info = NULL;
+
+       //TODO : return NULL if the animation correspond to the given id dones't exist.
+
+       /* allocation of the structure of function pointers that will be called from pui_ani_control() */
        ani_func = pui_backend_ani_alloc_ani_func();
 
        if (!ani_func)
        {
-               pui_err("Failed to allocate memory !\n");
+               pui_err("Failed to allocate memory ! (pui backend ani func)\n");
                return NULL;
        }
 
-       /* Assign each function pointer that corresponds to the given id */
-       ani_func->ani_create = _ani_create;
+       /* Assign each function pointer that corresponds to the given id if needed. */
        ani_func->ani_start = _ani_start;
        ani_func->ani_stop = _ani_stop;
 
@@ -169,7 +357,82 @@ _get_ani_func(pui_id id)
        ani_func->reserved9 = NULL;
        ani_func->reserved10 = NULL;
 
-       return ani_func;
+       /* backend's animation specific info */
+       ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
+
+       if (!ani_info)
+       {
+               pui_err("Failed to allocate memory ! (backend's ani specific info)\n");
+               goto err;
+       }
+
+       /* fill animation info associate with the given id from animation collection */
+       e = get_ani_info_from_ani_collection(ani_info, id);
+       
+       if (PUI_INT_ERROR_NONE != e)
+       {
+               pui_err("Failed to get ani info from animation collection !\n");
+               goto err;
+       }
+
+       /* allocate backend ani_data and return it to pui ani core */
+       ani_data = (pui_backend_ani_data *)calloc(1, sizeof(pui_backend_ani_data));
+       
+       if (!ani_data)
+       {
+               pui_err("Failed to allocate memory for pui backend ani data !\n");
+               goto err;
+       }
+       
+       ani_data->ani_func = ani_func;
+       ani_data->ani_info = (pui_backend_ani_info *)ani_info;
+
+       g_ani_data = ani_data;
+
+       return ani_data;
+
+err:
+       if (ani_func)
+       {
+               pui_backend_ani_free_ani_func(ani_func);
+               ani_func = NULL;
+       }
+
+       if (ani_info)
+       {
+               _ani_info_cleanup(ani_info);
+       }
+
+       return NULL;
+}
+
+void
+_ani_destroy(pui_backend_ani_data *ani_data)
+{
+       if (!ani_data)
+               return;
+
+       pui_backend_ani_free_ani_func(ani_data->ani_func);
+
+       //TODO : free if anything needs to be done with ani_info
+       free(ani_data->ani_info);
+
+       ani_data->ani_func = NULL;
+       if (ani_data->ani_info) {
+               _ani_info_cleanup(ani_data->ani_info);
+               ani_data->ani_info = NULL;
+       }
+
+       g_ani_data = NULL;
+}
+
+static void
+_animation_data_free_cb(void *data)
+{
+       int i;
+       default_ani_info *ani_info = (default_ani_info *)data;
+
+       _ani_info_cleanup(ani_info);
 }
 
 static pui_backend_module_data *
@@ -185,27 +448,15 @@ pui_default_backend_init(void)
                return NULL;
        }
 
+       backend_data->create_ani_collection = _create_ani_collection;
+       backend_data->ani_create = _ani_create;
+       backend_data->ani_destroy = _ani_destroy;
+
        /* Allocate backend specific data if needed. Now it will be empty. */
        backend_data->data = NULL;
-
-       backend_data->create_ani_collection = _create_ani_collection;
-       backend_data->is_ani_supported = _is_ani_supported;
-       backend_data->get_ani_func = _get_ani_func;
+       _animations_hash = eina_hash_string_superfast_new(_animation_data_free_cb);
 
        return backend_data;
-
-err:
-       if (backend_data)
-       {
-               if (backend_data->data)
-               {
-                       free(backend_data->data);
-               }
-
-               free(backend_data);
-       }
-
-       return NULL;
 }
 
 static void
@@ -221,22 +472,31 @@ pui_default_backend_deinit(pui_backend_module_data *backend_data)
                free(backend_data->data);
        }
 
-       if (backend_data->get_ani_func && ani_func)
+       if (g_ani_data)
        {
-               pui_backend_ani_free_ani_func(ani_func);
-               ani_func = NULL;
+               if (g_ani_data->ani_func)
+               {
+                       pui_backend_ani_free_ani_func(g_ani_data->ani_func);
+                       g_ani_data->ani_func = NULL;
+               }
+
+               if (g_ani_data->ani_info)
+               {
+                       _ani_info_cleanup(g_ani_data->ani_info);
+                       g_ani_data->ani_info = NULL;
+               }
        }
 
-       backend_data->get_ani_func = NULL;
        backend_data->create_ani_collection = NULL;
-       backend_data->is_ani_supported = NULL;
+       backend_data->ani_create = NULL;
+       backend_data->ani_destroy = NULL;
 
        free(backend_data);
        backend_data = NULL;
 }
 
 pui_backend_module pui_backend_module_info = {
-       "tizen_ref_speaker",
+       "Tizen Reference Speaker Backend",
        "Samsung",
        PUI_BACKEND_SET_ABI_VERSION(1, 0),
        pui_default_backend_init,