From bb7c08b7219034bc7ea81a71fdfc9f440e9e737d Mon Sep 17 00:00:00 2001 From: Jiwan Kim Date: Tue, 14 Feb 2017 17:35:46 +0900 Subject: [PATCH] Change zb_enable to async function - '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 --- common/zb-common.h | 1 + include/zdo/zb-zdo-type.h | 1 + include/zigbee.h | 44 +++++++++- lib/zbl-dbus.c | 213 ++++++++++++++++++++++++++++++++-------------- lib/zbl-dbus.h | 3 +- lib/zbl.c | 13 ++- test/main.c | 35 ++++++-- 7 files changed, 235 insertions(+), 75 deletions(-) diff --git a/common/zb-common.h b/common/zb-common.h index dc5e5a2..54cc3df 100644 --- a/common/zb-common.h +++ b/common/zb-common.h @@ -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" diff --git a/include/zdo/zb-zdo-type.h b/include/zdo/zb-zdo-type.h index 9eb2174..7cd745c 100644 --- a/include/zdo/zb-zdo-type.h +++ b/include/zdo/zb-zdo-type.h @@ -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; /** diff --git a/include/zigbee.h b/include/zigbee.h index c9215c4..2e08a88 100644 --- a/include/zigbee.h +++ b/include/zigbee.h @@ -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. diff --git a/lib/zbl-dbus.c b/lib/zbl-dbus.c index 449d4c4..fcf5f37 100644 --- a/lib/zbl-dbus.c +++ b/lib/zbl-dbus.c @@ -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(); diff --git a/lib/zbl-dbus.h b/lib/zbl-dbus.h index ea8d8d9..28d4282 100644 --- a/lib/zbl-dbus.h +++ b/lib/zbl-dbus.h @@ -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); diff --git a/lib/zbl.c b/lib/zbl.c index b9b0f8a..e056467 100644 --- 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; diff --git a/test/main.c b/test/main.c index 849ce61..09e652a 100644 --- a/test/main.c +++ b/test/main.c @@ -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; -- 2.7.4