Implemented enable and disable Gatt watch notification
[platform/core/connectivity/bluetooth-frwk.git] / bt-oal / bluez_hal / src / bt-hal-gatt-client.c
index ec6f955..c30f3f3 100644 (file)
@@ -148,12 +148,12 @@ static int bt_inst_id = 0;
 
 typedef struct {
        int conn_id;
+       int result;
        btgatt_srvc_id_t srvc_id;
        btgatt_gatt_id_t char_id;
        btgatt_gatt_id_t desc_id;
 } hal_gatt_resp_data_t;
 
-
 typedef struct {
        int client_if;
        bt_uuid_t app_uuid;
@@ -175,6 +175,8 @@ static hal_gattc_server_info_t *__bt_find_gatt_conn_info_from_conn_id(int  conn_
 static void _bt_hal_send_search_service_result_event(int conn_id, int is_primary,
                                                const char* uuid_str, int inst_id);
 static void _bt_hal_send_search_service_complete_event(int conn_id, int status);
+static hal_gattc_server_info_t *__bt_find_gatt_conn_info(bt_bdaddr_t *serv_addr);
+static hal_gattc_client_info_t *__bt_find_gatt_client_info(bt_bdaddr_t *serv_addr);
 
 
 /* To send stack event to hal-av handler */
@@ -1373,7 +1375,7 @@ static void __hal_internal_read_char_cb(GObject *source_object,
        value = g_dbus_connection_call_finish(system_gconn, res, &error);
 
        if (error) {
-               ERR("Read Characteristic dbus failed Error:", error->message);
+               ERR("Read Characteristic dbus failed Error:[%s]", error->message);
 
                //send failed event
                result  = BT_STATUS_FAIL;
@@ -1540,7 +1542,7 @@ static void __hal_bluetooth_internal_write_cb(GObject *source_object,
        value = g_dbus_connection_call_finish(system_gconn, res, &error);
 
        if (error) {
-               ERR("write Characteristic dbus failed Error:", error->message);
+               ERR("write Characteristic dbus failed Error:[%s]", error->message);
 
                result  = BT_STATUS_FAIL;
                //send failed event
@@ -1744,7 +1746,7 @@ static void __hal_internal_read_desc_cb(GObject *source_object,
        value = g_dbus_connection_call_finish(system_gconn, res, &error);
 
        if (error) {
-               ERR("Read descriptor dbus failed Error:", error->message);
+               ERR("Read descriptor dbus failed Error:[%s]", error->message);
 
                //send failed event
                result  = BT_STATUS_FAIL;
@@ -1924,7 +1926,7 @@ static void __hal_bluetooth_internal_desc_write_cb(GObject *source_object,
        value = g_dbus_connection_call_finish(system_gconn, res, &error);
 
        if (error) {
-               ERR("write descriptor dbus failed Error:", error->message);
+               ERR("write descriptor dbus failed Error: [%s]", error->message);
 
                //send failed event
                result  = BT_STATUS_FAIL;
@@ -2079,25 +2081,312 @@ bt_status_t execute_write(int conn_id, int execute)
        return BT_STATUS_UNSUPPORTED;
 }
 
+static gboolean _hal_watch_register_notifi_cb(gpointer user_data)
+{
+       struct hal_ev_gatt_client_watch_notification ev;
+       hal_gatt_resp_data_t *resp_data = user_data;
+
+       DBG("sending the watch register notification event");
+       /* send the event */
+       memset(&ev, 0, sizeof(ev));
+       ev.client_if = resp_data->conn_id; /* conn_id is saved with client_if */
+       ev.registered = 1;
+       ev.status = resp_data->result;
+
+       ev.is_primary = resp_data->srvc_id.is_primary;
+       ev.inst_id = resp_data->srvc_id.id.inst_id;
+
+       memcpy(ev.svc_uuid, resp_data->srvc_id.id.uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, resp_data->char_id.uuid.uu, sizeof(ev.char_uuid));
+
+       if (!event_cb)
+               ERR("GATT Callback not registered");
+       else
+               event_cb(HAL_EV_GATT_CLIENT_WATCH_NOTIFICATION, (void *)&ev, sizeof(ev));
+
+       g_free(user_data);
+
+       return FALSE;
+}
+
+static bt_status_t _hal_register_for_notification(int client_if,
+               bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+               btgatt_gatt_id_t *char_id)
+{
+       int result = BT_STATUS_SUCCESS;
+       GError *error = NULL;
+       GDBusConnection *g_conn;
+       hal_gattc_client_info_t *gattc_client = NULL;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_service_t *gattc_service = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       char* char_handle = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+       hal_gatt_resp_data_t *resp_data;
+
+       DBG("+");
+
+       gattc_client = __bt_find_gatt_client_info(bd_addr);
+       if (gattc_client == NULL) {
+               ERR("failed to get the gatt client info");
+               return BT_STATUS_FAIL;
+       }
+
+       if (gattc_client->client_if != client_if) {
+               ERR("could not find the gatt client for client id[%d]", client_if);
+               return BT_STATUS_FAIL;
+       }
+
+        /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info(bd_addr);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info");
+               return BT_STATUS_FAIL;
+       }
+
+       if (conn_info->inst_id != gattc_client->inst_id) {
+               ERR("could not fild the conn_info");
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               DBG("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       DBG("service path [%s]", gattc_service->svc_path);
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+       DBG("service uuid [%s]", svc_uuid_str);
+
+
+       /* find characteristic */
+       gattc_char = _gattc_find_char_from_uuid(gattc_service, &char_id->uuid);
+       if (NULL == gattc_char) {
+               DBG("Failed to get the gatt char");
+               return BT_STATUS_FAIL;
+       }
+
+       DBG("char path [%s]", gattc_char->chr_path);
+       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+       DBG("char uuid [%s]", char_uuid_str);
+
+       char_handle = gattc_char->chr_path;
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (g_conn == NULL) {
+               ERR("conn NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       resp_data = malloc(sizeof(hal_gatt_resp_data_t));
+       if (NULL == resp_data) {
+               ERR("failed to get the memory");
+               return BT_STATUS_FAIL;
+       }
+
+       DBG("#StartNotify");
+       g_dbus_connection_call_sync(g_conn,
+                       BT_HAL_BLUEZ_NAME,
+                       char_handle,
+                       BT_HAL_GATT_CHAR_INTERFACE,
+                       "StartNotify",
+                       NULL,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       BT_HAL_MAX_DBUS_TIMEOUT, NULL, &error);
+
+       if (error) {
+               g_dbus_error_strip_remote_error(error);
+               ERR("### Watch Failed: %s", error->message);
+               if (g_strrstr(error->message, "Already notifying"))
+                       result = BT_STATUS_SUCCESS;
+               else if (g_strrstr(error->message, "In Progress"))
+                       result = BT_STATUS_BUSY;
+               else if (g_strrstr(error->message, "Operation is not supported"))
+                       result = BT_STATUS_UNSUPPORTED;
+               /*failed because of either Insufficient Authorization or Write Not Permitted */
+               else if (g_strrstr(error->message, "Write not permitted") ||
+                               g_strrstr(error->message, "Operation Not Authorized"))
+                       result = BT_STATUS_AUTH_FAILURE;
+               /* failed because of either Insufficient Authentication,
+                  Insufficient Encryption Key Size, or Insufficient Encryption. */
+               else if (g_strrstr(error->message, "Not paired"))
+                       result = BT_STATUS_NOT_READY;
+               else
+                       result = BT_STATUS_FAIL;
+
+               g_clear_error(&error);
+       }
+
+       resp_data->conn_id = gattc_client->client_if; /* saving client_if instead of conn_id */
+       resp_data->result = result;
+       memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+       memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+
+       g_idle_add(_hal_watch_register_notifi_cb, (gpointer)resp_data);
+
+       DBG("-");
+
+       return BT_STATUS_SUCCESS;
+}
+
 /**
  * Register to receive notifications or indications for a given
  * characteristic
  */
-bt_status_t register_for_notification(int client_if,
+bt_status_t btif_register_for_notification(int client_if,
                const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
                btgatt_gatt_id_t *char_id)
 {
        CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+
+       return _hal_register_for_notification(client_if, (bt_bdaddr_t *)bd_addr, srvc_id, char_id);
 }
 
+static gboolean _hal_watch_deregister_notifi_cb(gpointer user_data)
+{
+       struct hal_ev_gatt_client_watch_notification ev;
+       hal_gatt_resp_data_t *resp_data = user_data;
+
+       DBG("sending the watch deregister notification event");
+       /* send the event */
+       memset(&ev, 0, sizeof(ev));
+       ev.client_if = resp_data->conn_id; /* conn_id is saved with client_if */
+       ev.registered = 0;
+       ev.status = resp_data->result;
+
+       ev.is_primary = resp_data->srvc_id.is_primary;
+       ev.inst_id = resp_data->srvc_id.id.inst_id;
+
+       memcpy(ev.svc_uuid, resp_data->srvc_id.id.uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, resp_data->char_id.uuid.uu, sizeof(ev.char_uuid));
+
+       if (!event_cb)
+               ERR("GATT Callback not registered");
+       else
+               event_cb(HAL_EV_GATT_CLIENT_WATCH_NOTIFICATION, (void *)&ev, sizeof(ev));
+
+       g_free(user_data);
+
+       return FALSE;
+}
+
+static bt_status_t _hal_deregister_for_notification(int client_if,
+               bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+               btgatt_gatt_id_t *char_id)
+{
+       int result = BT_STATUS_SUCCESS;
+       GError *error = NULL;
+       GDBusConnection *g_conn;
+       hal_gattc_client_info_t *gattc_client = NULL;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_service_t *gattc_service = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       char* char_handle = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+       hal_gatt_resp_data_t *resp_data;
+
+       DBG("+");
+
+       gattc_client = __bt_find_gatt_client_info(bd_addr);
+       if (gattc_client == NULL) {
+               ERR("failed to get the gatt client info");
+               return BT_STATUS_FAIL;
+       }
+
+       if (gattc_client->client_if != client_if) {
+               ERR("could not find the gatt client for client id[%d]", client_if);
+               return BT_STATUS_FAIL;
+       }
+
+        /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info(bd_addr);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info");
+               return BT_STATUS_FAIL;
+       }
+
+       if (conn_info->inst_id != gattc_client->inst_id) {
+               ERR("could not fild the conn_info");
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               DBG("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       DBG("service path [%s]", gattc_service->svc_path);
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+       DBG("service uuid [%s]", svc_uuid_str);
+
+
+       /* find characteristic */
+       gattc_char = _gattc_find_char_from_uuid(gattc_service, &char_id->uuid);
+       if (NULL == gattc_char) {
+               DBG("Failed to get the gatt char");
+               return BT_STATUS_FAIL;
+       }
+
+       DBG("char path [%s]", gattc_char->chr_path);
+       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+       DBG("char uuid [%s]", char_uuid_str);
+
+       char_handle = gattc_char->chr_path;
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (g_conn == NULL) {
+               ERR("conn NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       resp_data = malloc(sizeof(hal_gatt_resp_data_t));
+       if (NULL == resp_data) {
+               ERR("failed to get the memory");
+               return BT_STATUS_FAIL;
+       }
+
+       DBG("#StartNotify");
+       g_dbus_connection_call_sync(g_conn,
+                       BT_HAL_BLUEZ_NAME,
+                       char_handle,
+                       BT_HAL_GATT_CHAR_INTERFACE,
+                       "StopNotify",
+                       NULL,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       BT_HAL_MAX_DBUS_TIMEOUT, NULL, &error);
+
+       if (error) {
+               ERR("### Watch Failed: %s", error->message);
+               g_clear_error(&error);
+               result = BT_STATUS_FAIL;
+       }
+
+       resp_data->conn_id = gattc_client->client_if; /* saving client_if instead of conn_id */
+       resp_data->result = result;
+       memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+       memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+
+       g_idle_add(_hal_watch_deregister_notifi_cb, (gpointer)resp_data);
+
+       DBG("-");
+
+       return BT_STATUS_SUCCESS;
+}
 /** Deregister a previous request for notifications/indications */
-bt_status_t deregister_for_notification(int client_if,
+bt_status_t btif_deregister_for_notification(int client_if,
                const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
                btgatt_gatt_id_t *char_id)
 {
        CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       return _hal_deregister_for_notification(client_if, (bt_bdaddr_t *)bd_addr, srvc_id, char_id);
 }
 
 /** Request RSSI for a given remote device */
@@ -2313,8 +2602,8 @@ const btgatt_client_interface_t btgatt_client_interface = {
        btif_read_descriptor,
        btif_write_descriptor,
        execute_write,
-       register_for_notification,
-       deregister_for_notification,
+       btif_register_for_notification,
+       btif_deregister_for_notification,
        read_remote_rssi,
        ota_fw_update,
        get_device_type,