Change zb_enable to async function
authorJiwan Kim <ji-wan.kim@samsung.com>
Tue, 14 Feb 2017 08:35:46 +0000 (17:35 +0900)
committersaerome.kim <saerome.kim@samsung.com>
Thu, 11 May 2017 09:07:20 +0000 (18:07 +0900)
- 'enable' method is used to execute zigbee daemon on demand.
- Its synchronous operation may cause unexpected gvariant crash,
  change this function to act asynchronously.

Change-Id: I0bf03091ed7327d8127f4a6d4aa56ce51cba8d87
Signed-off-by: Jiwan Kim <ji-wan.kim@samsung.com>
common/zb-common.h
include/zdo/zb-zdo-type.h
include/zigbee.h
lib/zbl-dbus.c
lib/zbl-dbus.h
lib/zbl.c
test/main.c

index dc5e5a2..54cc3df 100644 (file)
@@ -33,6 +33,7 @@
 #define ZIGBEE_SERVER_NAME "org.tizen.zigbee"
 #define ZIGBEE_CONTROL_OBJECT_PATH "/org/tizen/zigbee/control"
 
+#define ZIGBEE_MANAGER_INTERFACE "org.tizen.zigbee.manager"
 #define ZIGBEE_SERVICE_INTERFACE "org.tizen.zigbee.service"
 #define ZIGBEE_SERVICE_OBJECT_PATH "/org/tizen/zigbee/service"
 
index 9eb2174..7cd745c 100644 (file)
@@ -44,6 +44,7 @@ typedef enum {
        ZB_ZDP_TABLE_FULL = 0x8C, /**< Table Full */
        ZB_ZDP_NOT_AUTHORIZED = 0x8D, /**< Not Authorized */
        ZB_ZDP_DEVICE_BINDING_TABLE_FULL = 0x8E, /**< Binding Table Full */
+       ZB_ZDP_UNKNOWN = 0xFF /**< Unknown */
 } zb_zdo_status_e;
 
 /**
index c9215c4..2e08a88 100644 (file)
@@ -81,6 +81,44 @@ int zb_create(zigbee_h *handle);
 void zb_destroy(zigbee_h handle);
 
 /**
+ * @brief response of enabling the zigbee service
+ * @details response of enabling the zigbee service
+ *
+ * @since_tizen 3.0
+ *
+ * @param[out] status #ZB_ZDP_SUCCESS \n
+ *                    #ZB_ZDP_NOT_SUPPORTED \n
+ * @param[out] user_data user data
+ *
+ * @see zb_enable()
+ */
+typedef void (*zb_enable_cb)(unsigned char status, void *user_data);
+
+/**
+ * @brief enable the zigbee service.
+ * @details all this function to start zigbee service
+ *
+ * @since_tizen 3.0
+ *
+ * @remarks You must free all resources of the zigbee by calling zb_destroy()
+ * if zigbee service is no longer needed.
+ *
+ * @param[in] handle The handle of zigbee
+ * @param[in] cb zb_enable_cb
+ * @param[in] user_data user data
+ *
+ * @return 0 on success, otherwise a negative error value.
+ * @retval #ZIGBEE_ERROR_NONE Successful
+ * @retval #ZIGBEE_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #ZIGBEE_ERROR_IO_ERROR Unexpected d-bus error
+ *
+ * @see zb_create()
+ * @see zb_destroy()
+ *
+ */
+int zb_enable(zigbee_h handle, zb_enable_cb cb, void *user_data);
+
+/**
  * @brief Specifies the type of function passed to zb_set_event_handler()
  * @details This function can receive events from the devices in the network.
  * ex) join, re-join, leave and attribute change report
@@ -121,8 +159,8 @@ typedef void (*zb_event_cb)(nwk_addr addr16, ieee_addr addr64, zb_event_e event_
                zb_event_data_s lparam);
 
 /**
- * @brief enable the zigbee service.
- * @details all this function to start zigbee service
+ * @brief set event handler for the zigbee service.
+ * @details to set event handler to get events from the zigbee service
  *
  * @since_tizen 3.0
  *
@@ -141,7 +179,7 @@ typedef void (*zb_event_cb)(nwk_addr addr16, ieee_addr addr64, zb_event_e event_
  * @see zb_destroy()
  *
  */
-int zb_enable(zigbee_h handle, zb_event_cb event_handler);
+int zb_set_event_cb(zigbee_h handle, zb_event_cb event_handler);
 
 /**
  * @brief disable the zigbee service.
index 449d4c4..fcf5f37 100644 (file)
@@ -35,6 +35,7 @@
 static int zbl_ref_count;
 
 static GDBusConnection *gdbus_conn = NULL;
+static GDBusProxy *manager_gproxy = NULL;
 static GDBusProxy *service_gproxy = NULL;
 static GDBusProxy *on_off_gproxy = NULL;
 static GDBusProxy *door_lock_gproxy = NULL;
@@ -145,6 +146,21 @@ static GDBusConnection *_zbl_get_connection(void)
        return g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
 }
 
+static GDBusProxy *_zbl_get_manager_proxy(void)
+{
+       GDBusProxy *proxy = NULL;
+       RETVM_IF(NULL == gdbus_conn, NULL, "Connection Object is invalid");
+
+       if (NULL == manager_gproxy) {
+               proxy = g_dbus_proxy_new_sync(gdbus_conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
+                       ZIGBEE_SERVER_NAME, ZIGBEE_DBUS_OBJPATH, ZIGBEE_MANAGER_INTERFACE,
+                       NULL, NULL);
+       } else
+               proxy = manager_gproxy;
+
+       return proxy;
+}
+
 static GDBusProxy *_zbl_get_service_proxy(void)
 {
        GDBusProxy *proxy = NULL;
@@ -2896,37 +2912,99 @@ SCENE_GET_SCENE_MEMBERSHIP_REQ_OUT:
        }
 }
 
+int zbl_set_event_cb(zigbee_h handle, zb_event_cb event_handler)
+{
+       RETV_IF(NULL == handle, ZIGBEE_ERROR_INVALID_PARAMETER);
+       handle->event_handler = event_handler;
+       return ZIGBEE_ERROR_NONE;
+}
 
-int zbl_enable(zigbee_h handle, zb_event_cb event_handler)
+static gboolean _zbl_timeout_enable(gpointer p)
 {
-       char enabled;
-       int result = ZIGBEE_ERROR_NONE;
-       GVariant *variant = NULL;
-       GError *dbus_err = NULL;
+       zbl_req_cb_s *container = NULL;
+       zb_enable_cb cb = NULL;
+
+       DBG("zb_enable_cb()");
+
+       RETVM_IF(NULL == gdbus_conn, G_SOURCE_REMOVE, "gdbus_conn is NULL");
+       container = p;
+       RETVM_IF(NULL == container, G_SOURCE_REMOVE, "cb_container is NULL");
+       cb = container->cb;
+
+       if (false == container->found && container->cb)
+               cb(ZB_ZDP_NOT_SUPPORTED, container->userdata);
+
+       container->tid = 0;
+
+       g_dbus_connection_signal_unsubscribe(gdbus_conn, container->sid);
+       DBG("container->sid=%d unsubscribed");
+       container->sid = 0;
+
+       return G_SOURCE_REMOVE;
+}
+
+static void _zbl_enable_cb(GDBusConnection *connection,
+               const gchar *sender_name, const gchar *object_path, const gchar *interface_name,
+               const gchar *signal_name, GVariant *parameters, gpointer user_data)
+{
+       zbl_req_cb_s *container = user_data;
+       zb_enable_cb cb = container->cb;
+
+       unsigned char ret = ZB_ZDP_SUCCESS;
+       gboolean value = TRUE;
+
+       container->found = true;
+
+       DBG("_zbl_enable_cb");
+
+       g_variant_get(parameters, "(b)", &value);
+       if (!value)
+               ret = ZB_ZDP_UNKNOWN;
+
+       if (cb)
+               cb(ret, container->userdata);
+
+       if (container->sid)
+               g_dbus_connection_signal_unsubscribe(gdbus_conn, container->sid);
+}
+
+
+int zbl_enable(zigbee_h handle, zb_enable_cb cb, void *user_data)
+{
+       int sub_id, to;
+       zbl_req_cb_s *container;
 
        RETV_IF(NULL == gdbus_conn, ZIGBEE_ERROR_IO_ERROR);
        RETV_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR);
        RETV_IF(NULL == handle, ZIGBEE_ERROR_INVALID_PARAMETER);
 
-       handle->event_handler = event_handler;
+       DBG("zbl_enable()");
 
-       variant = g_dbus_proxy_call_sync(service_gproxy, "enable", NULL,
-               G_DBUS_CALL_FLAGS_NONE, -1, NULL, &dbus_err);
+       container = calloc(1, sizeof(zbl_req_cb_s));
+       RETVM_IF(NULL == container, ZIGBEE_ERROR_OUT_OF_MEMORY, "calloc() Fail(%d)", errno);
 
-       if (!variant) {
-               ERR("Failed to get 'enable' [%s]", dbus_err->message);
-               g_error_free(dbus_err);
+       to = zbl_dbus_get_timeout(manager_gproxy);
+       sub_id = g_dbus_connection_signal_subscribe(gdbus_conn, NULL,
+                       ZIGBEE_MANAGER_INTERFACE, "zigbee_state", ZIGBEE_DBUS_OBJPATH,
+                       NULL, G_DBUS_SIGNAL_FLAGS_NONE,
+                       _zbl_enable_cb, container, _zbl_request_cleanup);
+
+       if (0 == sub_id) {
+               ERR("g_dbus_connection_signal_subscribe() Fail");
+               free(container);
                return ZIGBEE_ERROR_IO_ERROR;
        }
 
-       g_variant_get(variant, "(ib)", &result, &enabled);
-       DBG("ret = [0x%x]", result);
-       if (variant) {
-               ERR("variant = %p", variant);
-               g_variant_unref(variant);
-       }
+       container->cb = cb;
+       container->sid = sub_id;
+       container->tid = g_timeout_add_seconds(to, _zbl_timeout_enable, container);
+       container->userdata = user_data;
 
-       return result;
+       g_dbus_proxy_call(manager_gproxy, "enable", NULL,
+               G_DBUS_CALL_FLAGS_NONE, to,
+               NULL, NULL, container);
+
+       return ZIGBEE_ERROR_NONE;
 }
 
 int zbl_disable(void)
@@ -2948,44 +3026,51 @@ int zbl_disable(void)
        }
 
        if (gdbus_conn) {
+               variant = g_dbus_connection_call_sync(gdbus_conn,
+                               ZIGBEE_SERVER_NAME,
+                               ZIGBEE_DBUS_OBJPATH,
+                               ZIGBEE_DBUS_INTERFACE,
+                               "disable",
+                               NULL, NULL,
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               NULL,
+                               &dbus_err);
+
+               if (!variant) {
+                       ERR("Failed to get 'disable' [%s]", dbus_err->message);
+                       g_error_free(dbus_err);
+               }
 
-               if (service_gproxy) {
-                       variant = g_dbus_proxy_call_sync(service_gproxy, "disable", NULL,
-                               G_DBUS_CALL_FLAGS_NONE, -1, NULL, &dbus_err);
-
-                       if (!variant) {
-                               ERR("Failed to get 'disable' [%s]", dbus_err->message);
-                               g_error_free(dbus_err);
-                       }
+               g_variant_get(variant, "(i)", &result);
+               DBG("ret = [0x%x]", result);
+               g_variant_unref(variant);
 
-                       g_variant_get(variant, "(i)", &result);
-                       DBG("ret = [0x%x]", result);
-                       g_variant_unref(variant);
-
-                       g_object_unref(service_gproxy);
-                       service_gproxy = NULL;
-                       g_object_unref(on_off_gproxy);
-                       on_off_gproxy = NULL;
-                       g_object_unref(door_lock_gproxy);
-                       door_lock_gproxy = NULL;
-                       g_object_unref(level_control_gproxy);
-                       level_control_gproxy = NULL;
-                       g_object_unref(thermostat_gproxy);
-                       thermostat_gproxy = NULL;
-                       g_object_unref(alarm_gproxy);
-                       alarm_gproxy = NULL;
-                       g_object_unref(fan_control_gproxy);
-                       fan_control_gproxy = NULL;
-
-                       g_object_unref(mfglib_gproxy);
-                       mfglib_gproxy = NULL;
-                       g_object_unref(zcl_global_proxy);
-                       zcl_global_proxy = NULL;
-                       g_object_unref(zcl_color_control_proxy);
-                       zcl_color_control_proxy = NULL;
-                       g_object_unref(custom_gproxy);
-                       custom_gproxy = NULL;
-               }
+               g_object_unref(manager_gproxy);
+               manager_gproxy = NULL;
+               g_object_unref(service_gproxy);
+               service_gproxy = NULL;
+               g_object_unref(on_off_gproxy);
+               on_off_gproxy = NULL;
+               g_object_unref(door_lock_gproxy);
+               door_lock_gproxy = NULL;
+               g_object_unref(level_control_gproxy);
+               level_control_gproxy = NULL;
+               g_object_unref(thermostat_gproxy);
+               thermostat_gproxy = NULL;
+               g_object_unref(alarm_gproxy);
+               alarm_gproxy = NULL;
+               g_object_unref(fan_control_gproxy);
+               fan_control_gproxy = NULL;
+
+               g_object_unref(mfglib_gproxy);
+               mfglib_gproxy = NULL;
+               g_object_unref(zcl_global_proxy);
+               zcl_global_proxy = NULL;
+               g_object_unref(zcl_color_control_proxy);
+               zcl_color_control_proxy = NULL;
+               g_object_unref(custom_gproxy);
+               custom_gproxy = NULL;
 
                g_object_unref(gdbus_conn);
                gdbus_conn = NULL;
@@ -7731,40 +7816,44 @@ int zbl_dbus_start(zigbee_h handle)
        _zbl_dbus_subscribe_signal(handle);
 
        /* Phase 2. Make proxies */
+       manager_gproxy = _zbl_get_manager_proxy();
+       RETVM_IF(NULL == manager_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get manager_gproxy");
+       g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(manager_gproxy), ZIGBEE_BROADCAST_TIMEOUT);
+
        service_gproxy = _zbl_get_service_proxy();
        RETVM_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get service_gproxy");
        g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(service_gproxy), ZIGBEE_BROADCAST_TIMEOUT);
 
        on_off_gproxy = _zbl_get_on_off_proxy();
-       RETVM_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get on_off_gproxy");
+       RETVM_IF(NULL == on_off_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get on_off_gproxy");
        g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(on_off_gproxy), ZIGBEE_BROADCAST_TIMEOUT);
 
        door_lock_gproxy = _zbl_get_door_lock_proxy();
-       RETVM_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get door_lock_gproxy");
+       RETVM_IF(NULL == door_lock_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get door_lock_gproxy");
        g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(door_lock_gproxy), ZIGBEE_BROADCAST_TIMEOUT);
 
        level_control_gproxy = _zbl_get_level_control_proxy();
-       RETVM_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get level_control_gproxy");
+       RETVM_IF(NULL == level_control_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get level_control_gproxy");
        g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(level_control_gproxy), ZIGBEE_BROADCAST_TIMEOUT);
 
        thermostat_gproxy = _zbl_get_thermostat_proxy();
-       RETVM_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get thermostat_gproxy");
+       RETVM_IF(NULL == thermostat_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get thermostat_gproxy");
        g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(thermostat_gproxy), ZIGBEE_BROADCAST_TIMEOUT);
 
        fan_control_gproxy = _zbl_get_fan_control_proxy();
-       RETVM_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get fan_control_gproxy");
+       RETVM_IF(NULL == fan_control_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get fan_control_gproxy");
        g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(fan_control_gproxy), ZIGBEE_BROADCAST_TIMEOUT);
 
        alarm_gproxy = _zbl_get_alarm_proxy();
-       RETVM_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get alarm_gproxy");
+       RETVM_IF(NULL == alarm_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get alarm_gproxy");
        g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(alarm_gproxy), ZIGBEE_BROADCAST_TIMEOUT);
 
        mfglib_gproxy = _zbl_get_mfglib_proxy();
-       RETVM_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get mfglib_gproxy");
+       RETVM_IF(NULL == mfglib_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get mfglib_gproxy");
        g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(mfglib_gproxy), ZIGBEE_BROADCAST_TIMEOUT);
 
        zcl_global_proxy = _zbl_get_zcl_global_proxy();
-       RETVM_IF(NULL == service_gproxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get zcl_global_proxy");
+       RETVM_IF(NULL == zcl_global_proxy, ZIGBEE_ERROR_IO_ERROR, "Couldn't get zcl_global_proxy");
        g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(zcl_global_proxy), ZIGBEE_BROADCAST_TIMEOUT);
 
        zdo_dev_proxy = _zbl_get_zdo_dev_proxy();
index ea8d8d9..28d4282 100644 (file)
@@ -26,7 +26,8 @@ int zbl_dbus_start(zigbee_h handle);
 void zbl_dbus_stop(void);
 GDBusConnection* zbl_dbus_get_object(void);
 int zbl_dbus_get_timeout(GDBusProxy *proxy);
-int zbl_enable(zigbee_h handle, zb_event_cb event_handler);
+int zbl_enable(zigbee_h handle, zb_enable_cb cb, void *user_data);
+int zbl_set_event_cb(zigbee_h handle, zb_event_cb event_handler);
 int zbl_disable(void);
 int zbl_hw_reset(void);
 int zbl_coex_start(unsigned char channel);
index b9b0f8a..e056467 100644 (file)
--- a/lib/zbl.c
+++ b/lib/zbl.c
@@ -51,15 +51,24 @@ API void zb_destroy(zigbee_h handle)
        zbl_dbus_stop();
 }
 
-API int zb_enable(zigbee_h handle, zb_event_cb event_handler)
+API int zb_enable(zigbee_h handle, zb_enable_cb cb, void *user_data)
 {
        int ret = ZIGBEE_ERROR_NONE;
        RETV_IF(NULL == handle, ZIGBEE_ERROR_INVALID_PARAMETER);
-       ret = zbl_enable(handle, event_handler);
+       ret = zbl_enable(handle, cb, user_data);
        DBG("zbl_enable()=0x%X", ret);
        return ret;
 }
 
+API int zb_set_event_cb(zigbee_h handle, zb_event_cb event_handler)
+{
+       int ret = ZIGBEE_ERROR_NONE;
+       RETV_IF(NULL == handle, ZIGBEE_ERROR_INVALID_PARAMETER);
+       ret = zbl_set_event_cb(handle, event_handler);
+       DBG("zb_set_event_cb()=0x%X", ret);
+       return ret;
+}
+
 API int zb_disable(zigbee_h handle)
 {
        int ret = ZIGBEE_ERROR_NONE;
index 849ce61..09e652a 100644 (file)
@@ -241,14 +241,19 @@ static void _init_endpoints()
        huebulb_ep1.out_clusters[0] = ZB_ZCL_OTA_BOOTLOAD_CLUSTER_ID;
 }
 
+static void zigbee_enable_cb(unsigned char status, void *user_data)
+{
+       msgp("\nenable result received = 0x%02X\n", status);
+}
+
 static void zigbee_form_network_done_cb(nwk_addr panid, void *user_data)
 {
-       msgp("form_network_done received PANID = 0x%04X\n", panid);
+       msgp("\nform_network_done received PANID = 0x%04X\n", panid);
 }
 
 static void zigbee_disable_network_done_cb(unsigned char ret, void *user_data)
 {
-       msgp("disable_network result received = 0x%02X\n", ret);
+       msgp("\ndisable_network result received = 0x%02X\n", ret);
 }
 
 static void zigbee_event_cb(nwk_addr addr16, ieee_addr addr64, zb_event_e e, zb_event_data_s ev)
@@ -489,7 +494,7 @@ static int run_enable(MManager *mm, struct menu_data *menu)
        /* Register event callback */
        int ret = ZIGBEE_ERROR_NONE;
 
-       ret = zb_enable(handle, zigbee_event_cb);
+       ret = zb_enable(handle, zigbee_enable_cb, NULL);
        if (ZIGBEE_ERROR_NONE != ret) {
                msg("zb_enable(0x%X) - FAILED!!!", ret);
                return RET_FAILURE;
@@ -497,6 +502,14 @@ static int run_enable(MManager *mm, struct menu_data *menu)
 
        msg(" - zb_enable() ret: [0x%X]", ret);
 
+       ret = zb_set_event_cb(handle, zigbee_event_cb);
+       if (ZIGBEE_ERROR_NONE != ret) {
+               msg("zb_set_event_cb(0x%X) - FAILED!!!", ret);
+               return RET_FAILURE;
+       }
+
+       msg(" - zb_set_event_cb() ret: [0x%X]", ret);
+
        return RET_SUCCESS;
 }
 
@@ -970,14 +983,22 @@ static int __select_handle_register_event(MManager *mm, struct menu_data *menu)
                msg("zb_create(%d) - SUCCESS!!!. handle [%p]", ret, handle);
        }
 
-       ret = zb_enable(handle, zigbee_event_cb);
+       ret = zb_enable(handle, zigbee_enable_cb, NULL);
        if (ZIGBEE_ERROR_NONE != ret) {
-               msg("zb_enable(%d) - FAILED!!!.", ret);
+               msg("zb_enable(0x%X) - FAILED!!!", ret);
+               return RET_FAILURE;
+       }
+
+       msg(" - zb_enable() ret: [0x%X]", ret);
+
+       ret = zb_set_event_cb(handle, zigbee_event_cb);
+       if (ZIGBEE_ERROR_NONE != ret) {
+               msg("zb_set_event_cb(0x%X) - FAILED!!!", ret);
                return RET_FAILURE;
-       } else {
-               msg("zb_enable(%d) - SUCCESS!!!. handle [%p]", ret, handle);
        }
 
+       msg(" - zb_set_event_cb() ret: [0x%X]", ret);
+
        menu_manager_set_user_data(mm, handle);
 
        return RET_SUCCESS;