#include <errno.h>
#include <string.h>
#include <dlog.h>
+#include <gio/gio.h>
+#include <glib.h>
+
#include "bt-hal-log.h"
#include "bt-hal-msg.h"
#include "bt-hal-adapter-le.h"
#include "bt-hal-gatt-client.h"
+#include "bt-hal-dbus-common-utils.h"
+#include "bt-hal-utils.h"
/************************************************************************************
** Static variables
DBG("%s", __FUNCTION__);\
}
-typedef struct {
- uint32_t client_if;
- bt_uuid_t uuid;
-} hal_registered_client_t;
-
#ifdef TIZEN_BT_HAL
int le_scan_type = BT_GATTC_LE_SCAN_TYPE_PASSIVE;
#endif
static handle_stack_msg event_cb = NULL;
+#define GATT_SERV_INTERFACE "org.bluez.GattService1"
+#define MAX_HAL_OBJECT_PATH_LEN 100
+
+typedef enum {
+ HAL_GATT_CHARACTERISTIC_PROPERTY_BROADCAST = 0x01,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_READ = 0x02,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE = 0x04,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE = 0x08,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY = 0x10,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_INDICATE = 0x20,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE = 0x40,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE = 0x80,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES = 0x100,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ = 0x200,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE = 0x400,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ = 0x800,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE = 0x1000,
+ HAL_GATT_CHARACTERISTIC_PROPERTY_EXTENDED_PROPS = 0xffff,
+} bt_gatt_characteristic_property_t;
+
+
+typedef enum {
+ HAL_GATT_WRITE_TYPE_WRITE_NO_RESPONSE = 1,
+ HAL_GATT_WRITE_TYPE_WRITE ,
+} hal_gatt_write_type_t;
+
+
+typedef enum {
+ HAL_GATT_PROPERTY_BROADCAST = 0x01, /**< Broadcast property */
+ HAL_GATT_PROPERTY_READ = 0x02, /**< Read property */
+ HAL_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE = 0x04, /**< Write without response property */
+ HAL_GATT_PROPERTY_WRITE = 0x08, /**< Write property */
+ HAL_GATT_PROPERTY_NOTIFY = 0x10, /**< Notify property */
+ HAL_GATT_PROPERTY_INDICATE = 0x20, /**< Indicate property */
+ HAL_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES = 0x40, /**< Authenticated signed writes property */
+ HAL_GATT_PROPERTY_EXTENDED_PROPERTIES = 0x80, /**< Extended properties */
+} hal_gatt_property_e;
+
+typedef struct {
+ int client_if;
+ bt_bdaddr_t bd_addr;
+ gboolean auto_connect;
+} bt_pending_le_conn_info_s;
+
+typedef struct {
+ char *desc_path;
+ bt_uuid_t desc_uuid;
+} hal_gattc_desc_t;
+
+typedef struct {
+ char *chr_path;
+ bt_uuid_t chr_uuid;
+ unsigned int permission;
+ GSList *gatt_list_descs;
+} hal_gattc_char_t;
+
+typedef struct {
+ gchar *svc_path;
+ bt_uuid_t svc_uuid;
+ GSList *gatt_list_chars;
+} hal_gattc_service_t;
+
+typedef struct {
+ bt_bdaddr_t bd_addr; /*remote server address*/
+ int inst_id; /*server instance id*/
+ GSList *gatt_list_services;
+} hal_gattc_server_info_t;
+
+/* Linked List of connected GATT server */
+static GSList *hal_gattc_server_info_list = NULL;
+
+typedef struct {
+ int client_if;
+ bt_bdaddr_t bd_addr; /*remote server address*/
+ int conn_id;
+ int inst_id;
+} hal_gattc_client_info_t;
+
+/* Linked list of connected GATT client connection */
+static GSList * hal_gattc_client_info_list = NULL;
+
+
+static bt_pending_le_conn_info_s *pending_le_conn_info = NULL;
+static guint pending_le_conn_timer_id = 0;
+static int bt_conn_id = 0;
+static int bt_inst_id = 0;
+
+#define BT_GATTC_CL_MAX 32
+
+typedef struct {
+ int conn_id;
+ 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;
+} hal_gatt_client_app;
+
+static GSList * hal_gattc_client_app_list = NULL;
+
+static int bt_client_if = 0;
+
+
+static bt_status_t __bt_connect_le_device_internal(int client_if, const bt_bdaddr_t *bd_addr,
+ gboolean auto_connect);
+static bt_status_t _bt_hold_current_advertising();
+static gboolean __bt_hold_current_advertising_timeout_cb(gpointer user_data);
+static gboolean __bt_connect_le_timer_cb(gpointer user_data);
+static void __le_connection_req_cb(GDBusProxy *proxy, GAsyncResult *res,
+ gpointer user_data);
+static hal_gattc_server_info_t *__bt_find_gatt_conn_info_from_conn_id(int conn_id);
+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);
+
+
/* To send stack event to hal-av handler */
void _bt_hal_register_gatt_client_handler_cb(handle_stack_msg cb)
{
static gboolean __bt_hal_register_client_cb(gpointer user_data)
{
struct hal_ev_gatt_client_registered ev;
- hal_registered_client_t *client_info = user_data;
+ hal_gatt_client_app *client_info = user_data;
+ DBG("+");
/* Prepare to send AV connecting event */
memset(&ev, 0, sizeof(ev));
ev.status = BT_STATUS_SUCCESS;
ev.client_if = client_info->client_if;
- memcpy(ev.app_uuid, client_info->uuid.uu, sizeof(ev.app_uuid));
+ memcpy(ev.app_uuid, client_info->app_uuid.uu, sizeof(ev.app_uuid));
if (!event_cb)
ERR("GATT Callback not registered");
return FALSE;
}
+static int __hal_generate_client_id()
+{
+ return ++bt_client_if;
+}
+
+static hal_gatt_client_app *__hal_gattc_add_client_app(bt_uuid_t *app_uuid)
+{
+ GSList *l;
+ hal_gatt_client_app *info = NULL;
+ hal_gatt_client_app *gattc_app = NULL;
+
+ //check if client app is already registered
+ for (l = hal_gattc_client_app_list; l != NULL; l = g_slist_next(l)) {
+ info = (hal_gatt_client_app*)l->data;
+ if (info == NULL)
+ continue;
+
+ if (memcmp(&info->app_uuid, app_uuid, sizeof(bt_uuid_t)) == 0) {
+ DBG("gatt client app already registered");
+ return info;
+ }
+ }
+
+ DBG("adding the gatt client app");
+
+ //add client app
+ gattc_app = g_malloc0(sizeof(hal_gatt_client_app));
+ if (gattc_app == NULL) {
+ DBG("Failed to allocate memory");
+ return NULL;
+ }
+
+ gattc_app->client_if = __hal_generate_client_id();
+ memcpy(&gattc_app->app_uuid, app_uuid, sizeof(bt_uuid_t));
+
+ hal_gattc_client_app_list = g_slist_append(hal_gattc_client_app_list, gattc_app);
+
+ return gattc_app;
+}
+
+static bt_status_t __hal_gattc_register_client_app(bt_uuid_t *app_uuid)
+{
+ hal_gatt_client_app *gattc_app = NULL;
+ hal_gatt_client_app *client_app_info = NULL;
+
+ DBG("+");
+ /* add gatt client in list */
+ gattc_app = __hal_gattc_add_client_app(app_uuid);
+ if (gattc_app == NULL) {
+ ERR("Failed to register gatt client app");
+ return BT_STATUS_FAIL;
+ }
+
+ /*send event */
+ client_app_info = g_malloc0(sizeof(hal_gatt_client_app));
+ if (NULL == client_app_info) {
+ ERR("Failed to allocate memory");
+ return BT_STATUS_FAIL;
+ }
+
+ client_app_info->client_if = gattc_app->client_if;
+ memcpy(&client_app_info->app_uuid, app_uuid, sizeof(bt_uuid_t));
+ g_idle_add(__bt_hal_register_client_cb, (gpointer)client_app_info);
+
+ DBG("registered client client_if [%d]", client_app_info->client_if);
+
+ return BT_STATUS_SUCCESS;
+}
+
/** Registers a GATT client application with the stack */
-bt_status_t register_client(bt_uuid_t *uuid)
+bt_status_t btif_gattc_register_client(bt_uuid_t *uuid)
+{
+ CHECK_BTGATT_INIT();
+ DBG("+");
+
+ return __hal_gattc_register_client_app(uuid);
+}
+
+bt_status_t __hal_gattc_unregister_client(int client_if)
{
- hal_registered_client_t *client_info = NULL;
+ GSList *l;
+ hal_gatt_client_app *info = NULL;
+
+ DBG("registered client count: [%d]", g_slist_length(hal_gattc_client_app_list));
- client_info = g_malloc0(sizeof(hal_registered_client_t));
- /*
- * TODO: Actual client_if will be used here later when GATT register_client
- * is implemented compeltely. For now return 1 as client_if.
- */
- client_info->client_if = 1;
- memcpy(client_info->uuid.uu, uuid->uu, sizeof(bt_uuid_t));
+ /* remove the gatt client app */
+ for (l = hal_gattc_client_app_list; l != NULL; ) {
+ info = (hal_gatt_client_app*)l->data;
+ l = g_slist_next(l);
- /*
- * As we need to provide async callback to user from HAL, simply schedule a
- * callback method which will carry actual result
- */
- g_idle_add(__bt_hal_register_client_cb, (gpointer)client_info);
+ if (info == NULL)
+ continue;
- /* If available, then return success, else return error */
+ if (info->client_if == client_if) {
+ DBG("gatt client app found");
+ hal_gattc_client_app_list = g_slist_remove(hal_gattc_client_app_list, info);
+ g_free(info);
+ }
+ }
+
+ DBG("registered client count: [%d]", g_slist_length(hal_gattc_client_app_list));
return BT_STATUS_SUCCESS;
}
-/* TODO: APIs will be implemented in subsequent patches whenever required */
/** Unregister a client application from the stack */
-bt_status_t unregister_client(int client_if)
+bt_status_t btif_gattc_unregister_client(int client_if)
{
CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+ DBG("+");
+
+ return __hal_gattc_unregister_client(client_if);
}
/** Start or stop LE device scanning */
}
/** Create a connection to a remote LE or dual-mode device */
-bt_status_t connect(int client_if, const bt_bdaddr_t *bd_addr,
+bt_status_t btif_gattc_client_connect(int client_if, const bt_bdaddr_t *bd_addr,
bool is_direct)
{
+ int ret = BT_STATUS_SUCCESS;
+
CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+ DBG("+");
+
+ if (NULL == bd_addr)
+ return BT_STATUS_PARM_INVALID;
+
+ ret = _bt_hold_current_advertising();
+ if (ret == BT_STATUS_SUCCESS) {
+ DBG("Current advertising is held");
+ pending_le_conn_info = g_malloc0(sizeof(bt_pending_le_conn_info_s));
+ pending_le_conn_info->client_if = client_if;
+ memcpy(pending_le_conn_info->bd_addr.address, bd_addr->address,
+ BT_HAL_ADDRESS_LENGTH_MAX);
+ pending_le_conn_info->auto_connect = is_direct;
+
+ pending_le_conn_timer_id =
+ g_timeout_add(1000, __bt_connect_le_timer_cb, NULL);
+
+ return BT_STATUS_SUCCESS;
+ } else {
+ ERR("advertising is not stopped");
+ }
+
+ return __bt_connect_le_device_internal(client_if, bd_addr, is_direct);
+}
+
+
+static void __le_disconnection_req_cb(GDBusProxy *proxy, GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *g_error = NULL;
+ GVariant *reply = NULL;
+ hal_gattc_client_info_t *gatt_conn_info = user_data;
+ int result = BT_STATUS_SUCCESS;
+ struct hal_ev_gatt_client_connected ev;
+
+ DBG("+");
+
+ reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
+ g_object_unref(proxy);
+ if (reply == NULL) {
+ ERR("Connect LE Dbus Call Error");
+ if (g_error) {
+ ERR("Error: %s\n", g_error->message);
+ g_clear_error(&g_error);
+ }
+ result = BT_STATUS_FAIL;
+ }
+ g_variant_unref(reply);
+
+ if (NULL == gatt_conn_info) {
+ ERR("server_data is NULL");
+ return;
+ }
+
+ /*send fail event*/
+ if (result == BT_STATUS_FAIL) {
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = gatt_conn_info->conn_id;
+ ev.status = result;
+ ev.client_if = gatt_conn_info->client_if;
+ memcpy(ev.bdaddr, gatt_conn_info->bd_addr.address,
+ BT_HAL_ADDRESS_LENGTH_MAX);
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ } else {
+ DBG("sending gatt client disconnected event");
+ event_cb(HAL_EV_GATT_CLIENT_DISCONNECTED, (void *)&ev, sizeof(ev));
+ }
+ }
+
+ /*remove conn_info*/
+ if (gatt_conn_info)
+ g_free(gatt_conn_info);
+
+ DBG("-");
+}
+
+bt_status_t _hal_gattc_disconnect(int client_if, const bt_bdaddr_t *bd_addr,
+ int conn_id)
+{
+ char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+ gchar *device_path;
+ GDBusProxy *device_proxy;
+ GDBusConnection *conn;
+ int ret = BT_STATUS_SUCCESS;
+ hal_gattc_client_info_t *gattc_data;
+
+ if (NULL == bd_addr) {
+ ERR("bd_addr is NULL");
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ conn = _bt_hal_get_system_gconn();
+ if (NULL == conn) {
+ ERR("_bt_gdbus_get_system_gconn returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ _bt_hal_convert_addr_type_to_string(device_address,
+ (unsigned char *)bd_addr->address);
+ device_path = _bt_hal_get_device_object_path(device_address);
+ if (device_path == NULL) {
+ DBG("device_path NULL");
+ ret = BT_STATUS_FAIL;
+ return ret;
+ }
+
+ ERR("device_path:%s", device_path);
+
+ device_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, BT_HAL_BLUEZ_NAME,
+ device_path, BT_HAL_DEVICE_INTERFACE, NULL, NULL);
+ g_free(device_path);
+ if (NULL == device_proxy) {
+ ERR("device_proxy returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ gattc_data = g_malloc0(sizeof(hal_gattc_client_info_t));
+ if (NULL == gattc_data) {
+ ERR("Unable to allocate memory");
+ ret = BT_STATUS_FAIL;
+ goto fail;
+ }
+
+ memcpy(gattc_data->bd_addr.address, bd_addr->address,
+ BT_HAL_ADDRESS_LENGTH_MAX);
+ gattc_data->client_if = client_if;
+ gattc_data->conn_id = conn_id;
+
+ DBG("DisconnectLE [%s]", device_address);
+
+ g_dbus_proxy_call(device_proxy, "DisconnectLE",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ BT_HAL_MAX_DBUS_TIMEOUT,
+ NULL,
+ (GAsyncReadyCallback)__le_disconnection_req_cb, gattc_data);
+ return ret;
+fail:
+ if (device_proxy)
+ g_object_unref(device_proxy);
+
+ g_free(gattc_data);
+
+ return ret;
}
/** Disconnect a remote device or cancel a pending connection */
-bt_status_t disconnect(int client_if, const bt_bdaddr_t *bd_addr,
+bt_status_t btif_gattc_client_disconnect(int client_if, const bt_bdaddr_t *bd_addr,
int conn_id)
{
CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+
+ DBG("+");
+
+ return _hal_gattc_disconnect(client_if, bd_addr, conn_id);
}
/** Clear the attribute cache for a given device */
return BT_STATUS_UNSUPPORTED;
}
+static hal_gattc_service_t* _gattc_find_service_from_uuid(hal_gattc_server_info_t *conn_info, bt_uuid_t *svc_uuid)
+{
+ DBG("+");
+
+ GSList *l;
+ hal_gattc_service_t *info = NULL;
+
+ for (l = conn_info->gatt_list_services; l != NULL; l = g_slist_next(l)) {
+ info = (hal_gattc_service_t*)l->data;
+ if (info == NULL)
+ continue;
+
+ if (!memcmp(&info->svc_uuid, svc_uuid, sizeof(bt_uuid_t))) {
+ INFO("Found GATT service uuid");
+ return info;
+ }
+ }
+ return NULL;
+}
+
+
+static hal_gattc_char_t* _gattc_find_char_from_uuid(hal_gattc_service_t *gattc_svc, bt_uuid_t *char_uuid)
+{
+ DBG("+");
+
+ GSList *l;
+ hal_gattc_char_t *info = NULL;
+
+ for (l = gattc_svc->gatt_list_chars; l != NULL; l = g_slist_next(l)) {
+ info = (hal_gattc_char_t*)l->data;
+ if (info == NULL)
+ continue;
+
+ if (!memcmp(&info->chr_uuid, char_uuid, sizeof(bt_uuid_t))) {
+ INFO("Found GATT char uuid");
+ return info;
+ }
+ }
+ return NULL;
+}
+
+static hal_gattc_desc_t* _gattc_find_desc_from_uuid(hal_gattc_char_t *gattc_char, bt_uuid_t *desc_uuid)
+{
+ DBG("+");
+
+ GSList *l;
+ hal_gattc_desc_t *info = NULL;
+
+ for (l = gattc_char->gatt_list_descs; l != NULL; l = g_slist_next(l)) {
+ info = (hal_gattc_desc_t*)l->data;
+ if (info == NULL)
+ continue;
+
+ if (!memcmp(&info->desc_uuid, desc_uuid, sizeof(bt_uuid_t))) {
+ INFO("Found GATT descriptor uuid");
+ return info;
+ }
+ }
+ return NULL;
+}
+
+
+static hal_gattc_service_t* _hal_gatt_client_add_service(hal_gattc_server_info_t *conn_info,
+ const char *uuid_str, char *object_path)
+{
+ DBG("+");
+ hal_gattc_service_t *gattc_service = NULL;
+
+ gattc_service = g_malloc0(sizeof(hal_gattc_service_t));
+ gattc_service->svc_path = g_strdup(object_path);
+ _bt_hal_convert_uuid_string_to_type(gattc_service->svc_uuid.uu, uuid_str);
+
+ DBG("service count[%d]", g_slist_length(conn_info->gatt_list_services));
+
+ conn_info->gatt_list_services = g_slist_append(conn_info->gatt_list_services, gattc_service);
+
+ DBG("svc path {%s] svc uuid [%s]", object_path, uuid_str);
+
+ return gattc_service;
+}
+
+static void _hal_gattc_add_characteristic(hal_gattc_service_t *gatt_svc, char *char_handle)
+{
+ DBG("+");
+ hal_gattc_char_t *gattc_char = NULL;
+
+ gattc_char = g_malloc0(sizeof(hal_gattc_char_t));
+ gattc_char->chr_path = g_strdup(char_handle);
+
+ DBG("svc path: [%s]", gatt_svc->svc_path);
+ DBG("char path: [%s]", gattc_char->chr_path);
+
+ gatt_svc->gatt_list_chars = g_slist_append(gatt_svc->gatt_list_chars, gattc_char);
+}
+
+static void _gattc_create_new_service(hal_gattc_server_info_t *conn_info, gboolean is_primary,
+ const char* uuid_str, char *object_path, GPtrArray *gp_char_array)
+{
+ hal_gattc_service_t* gatt_svc = NULL;
+ int i;
+ gchar *gp_char_path = NULL;
+
+ DBG("+");
+
+ /* add the service */
+ gatt_svc = _hal_gatt_client_add_service(conn_info, uuid_str, object_path);
+ if (gatt_svc == NULL) {
+ ERR("Failed to add service");
+ return;
+ }
+
+ /* add the characteristic */
+ for (i = 0; i < gp_char_array->len; i++) {
+ gp_char_path = g_ptr_array_index(gp_char_array, i);
+ _hal_gattc_add_characteristic(gatt_svc, gp_char_path);
+ }
+
+ g_ptr_array_free(gp_char_array, TRUE);
+}
+
+static void _hal_gattc_add_descriptor(hal_gattc_char_t *gattc_char, char *desc_path)
+{
+ hal_gattc_desc_t *gattc_desc = NULL;
+
+ gattc_desc = g_malloc0(sizeof(hal_gattc_desc_t));
+ gattc_desc->desc_path = g_strdup(desc_path);
+
+ gattc_char->gatt_list_descs = g_slist_append(gattc_char->gatt_list_descs, gattc_desc);
+
+ DBG("char path: [%s]", gattc_char->chr_path);
+ DBG("desc path: [%s]", gattc_desc->desc_path);
+}
+
+static void _hal_gattc_update_char_property(hal_gattc_char_t *gattc_char, const char* char_uuid_str,
+ GPtrArray *gp_desc_array, unsigned int char_permission)
+{
+ gchar *gp_desc_path = NULL;
+ int i;
+
+ DBG("+");
+
+ if (char_uuid_str == NULL) {
+ DBG("char_uuid_str is NULL");
+ return;
+ }
+
+ //update the char uuid
+ DBG("char UUID: [%s] ", char_uuid_str);
+ DBG("char path: [%s]", gattc_char->chr_path);
+
+ _bt_hal_convert_uuid_string_to_type(gattc_char->chr_uuid.uu, char_uuid_str);
+
+ //update char permission
+ gattc_char->permission = char_permission;
+
+ //add the descriptor
+ for (i = 0; i < gp_desc_array->len; i++) {
+ gp_desc_path = g_ptr_array_index(gp_desc_array, i);
+ _hal_gattc_add_descriptor(gattc_char, gp_desc_path);
+ }
+}
+
+static void _hal_gattc_update_desc_property(hal_gattc_desc_t *gattc_desc, const char* desc_uuid_str)
+{
+ DBG("+");
+
+ if (desc_uuid_str == NULL) {
+ DBG("char_uuid_str is NULL");
+ return;
+ }
+
+ //update the descriptor uuid
+ DBG("desc UUID: [%s] ", desc_uuid_str);
+ DBG("desc path: [%s]", gattc_desc->desc_path);
+
+ _bt_hal_convert_uuid_string_to_type(gattc_desc->desc_uuid.uu, desc_uuid_str);
+}
+
+static void browse_service_char(int conn_id)
+{
+ hal_gattc_server_info_t *conn_info = NULL;
+ GSList *l;
+ GSList *k;
+ GSList *m;
+ hal_gattc_service_t *svc_info = NULL;
+ hal_gattc_char_t *char_info = NULL;
+ hal_gattc_desc_t *desc_info = NULL;
+
+ DBG("+");
+
+ conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+ if (conn_info == NULL) {
+ DBG("conn_info is NULL");
+ return;
+ }
+
+ DBG("service count[%d]", g_slist_length(conn_info->gatt_list_services));
+
+ for (l = conn_info->gatt_list_services; l != NULL; l = g_slist_next(l)) {
+ svc_info = (hal_gattc_service_t*)l->data;
+ if (svc_info == NULL)
+ continue;
+
+ DBG("svc path [%s]", svc_info->svc_path);
+
+ /* find characteristic object path */
+ for (k = svc_info->gatt_list_chars; k != NULL; k = g_slist_next(k)) {
+ char_info = (hal_gattc_char_t *)k->data;
+ if (char_info == NULL)
+ continue;
+
+ DBG("char path[%s]", char_info->chr_path);
+
+ /* descriptor */
+ for (m = char_info->gatt_list_descs; m != NULL; m = g_slist_next(m)) {
+ desc_info = (hal_gattc_desc_t *)m->data;
+ if (desc_info == NULL)
+ continue;
+
+ DBG("desc path[%s]", desc_info->desc_path);
+ }
+ }
+ }
+}
+
+
+
/**
* Enumerate all GATT services on a connected device.
* Optionally, the results can be filtered for a given UUID.
*/
-bt_status_t search_service(int conn_id, bt_uuid_t *filter_uuid)
+static bt_status_t _gattc_client_search_service(int conn_id)
{
CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+
+ GVariant *result = NULL;
+ GVariantIter *iter;
+ GVariantIter *svc_iter;
+ GVariantIter *interface_iter;
+ char *object_path = NULL;
+ char *interface_str = NULL;
+ const gchar *key = NULL;
+ GVariant *value = NULL;
+ GPtrArray *gp_array = NULL;
+ char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+ char temp_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+ int ret = BT_STATUS_FAIL;
+ int idx = 0;
+ const gchar *uuid_str = NULL;
+ gsize len = 0;
+ hal_gattc_server_info_t *conn_info = NULL;
+ gboolean is_primary = FALSE;
+ int svc_count = 0;
+
+ char *char_handle = NULL;
+ GVariantIter *char_iter = NULL;
+ GPtrArray *gp_char_array = NULL;
+
+ DBG("+");
+
+ conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+ if (NULL == conn_info) {
+ DBG("Failed to get the conn_info");
+ return BT_STATUS_FAIL;
+ }
+
+ _bt_hal_convert_addr_type_to_string(device_address,
+ (unsigned char *)conn_info->bd_addr.address);
+
+ result = _bt_hal_get_managed_objects();
+ if (result == NULL)
+ return ret;
+
+ gp_array = g_ptr_array_new();
+ g_variant_get(result, "(a{oa{sa{sv}}})", &iter);
+
+ while (g_variant_iter_loop(iter, "{&oa{sa{sv}}}", &object_path,
+ &interface_iter)) {
+ if (object_path == NULL)
+ continue;
+
+ _bt_hal_convert_device_path_to_address(object_path, temp_address);
+
+ if (g_strcmp0(temp_address, device_address) != 0)
+ continue;
+
+ while (g_variant_iter_loop(interface_iter, "{sa{sv}}",
+ &interface_str, &svc_iter)) {
+ if (g_strcmp0(interface_str, GATT_SERV_INTERFACE) != 0)
+ continue;
+
+ DBG("[%d] Object Path : %s", idx++, object_path);
+ /* for characteristic */
+ gp_char_array = g_ptr_array_new();
+ while (g_variant_iter_loop(svc_iter, "{sv}", &key, &value)) {
+ if (g_strcmp0(key, "Primary") == 0) {
+ is_primary = g_variant_get_boolean(value);
+ DBG("primary");
+ if (is_primary) {
+ g_ptr_array_add(gp_array, (gpointer)object_path);
+ svc_count++;
+ }
+ } else if (g_strcmp0(key, "UUID") == 0) {
+ uuid_str = g_variant_get_string(value, &len);
+ DBG(" UUID: [%s]", uuid_str);
+ } else if (g_strcmp0(key, "Characteristics") == 0) {
+ g_variant_get(value, "ao", &char_iter);
+ if (char_iter != NULL) {
+ while (g_variant_iter_loop(char_iter, "&o", &char_handle)) {
+ DBG("char handle : %s", char_handle);
+ g_ptr_array_add(gp_char_array, (gpointer)char_handle);
+ }
+ }
+ }
+ }
+
+ DBG("send search service result event");
+ _bt_hal_send_search_service_result_event(conn_id, is_primary,
+ uuid_str, conn_info->inst_id);
+
+ _gattc_create_new_service(conn_info, is_primary, uuid_str, object_path, gp_char_array);
+ }
+ }
+
+ if (gp_array->len == 0 || svc_count == 0) {
+ ERR("gp_array is NULL");
+ ret = BT_STATUS_FAIL;
+ } else {
+ ret = BT_STATUS_SUCCESS;
+ }
+
+ browse_service_char(conn_id);
+ /* send search service complete event */
+ _bt_hal_send_search_service_complete_event(conn_id, ret);
+
+ g_ptr_array_free(gp_array, TRUE);
+ g_variant_iter_free(iter);
+ g_variant_unref(result);
+ DBG("-");
+ return ret;
}
+bt_status_t btif_gattc_client_search_service(int conn_id, bt_uuid_t *filter_uuid)
+{
+ if (NULL == filter_uuid) {
+ DBG("Browse all the services");
+ return _gattc_client_search_service(conn_id);
+ } else {
+ DBG("TODO implement it");
+ return BT_STATUS_UNSUPPORTED;
+ }
+}
/**
* Enumerate included services for a given service.
* Set start_incl_srvc_id to NULL to get the first included service.
return BT_STATUS_UNSUPPORTED;
}
-/**
- * Enumerate characteristics for a given service.
- * Set start_char_id to NULL to get the first characteristic.
- */
-bt_status_t get_characteristic(int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *start_char_id)
+static void _bt_hal_send_client_char_search_result_event(int conn_id, int status,
+ btgatt_srvc_id_t *svc_id, bt_uuid_t *char_uuid, int char_prop)
{
- CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+ struct hal_ev_gatt_client_char_search_result ev;
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ return;
+ }
+
+ DBG("sending gatt client search char result event conn_id[%d] status[%d]", conn_id, status);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = conn_id;
+ ev.inst_id = svc_id->id.inst_id;
+ ev.is_primary = svc_id->is_primary;
+ ev.status = status;
+ memcpy(ev.svc_uuid, svc_id->id.uuid.uu, sizeof(ev.svc_uuid));
+
+ if (status == BT_STATUS_SUCCESS) {
+ DBG("building char uuid");
+ memcpy(ev.char_uuid, char_uuid->uu, sizeof(ev.char_uuid));
+ ev.char_prop = char_prop;
+ }
+
+ DBG("sending the char search event");
+
+ event_cb(HAL_EV_GATT_CLIENT_CHARAC_SEARCH_RESULT, (void *)&ev, sizeof(ev));
+}
+
+static int _hal_get_permission_flag(char *permission)
+{
+ int ret = 0;
+
+ if (NULL == permission) {
+ ERR("gatt permission is NULL");
+ return ret;
+ }
+
+ if (!g_strcmp0(permission, "broadcast"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_BROADCAST;
+ else if (!g_strcmp0(permission, "read"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_READ;
+ else if (!g_strcmp0(permission, "write-without-response"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE;
+ else if (!g_strcmp0(permission, "write"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE;
+ else if (!g_strcmp0(permission, "notify"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY;
+ else if (!g_strcmp0(permission, "indicate"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_INDICATE;
+ else if (!g_strcmp0(permission, "authenticated-signed-writes"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE;
+ else if (!g_strcmp0(permission, "reliable-write"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE;
+ else if (!g_strcmp0(permission, "writable-auxiliaries"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES;
+ else if (!g_strcmp0(permission, "encrypt-read"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ;
+ else if (!g_strcmp0(permission, "encrypt-write"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE;
+ else if (!g_strcmp0(permission, "encrypt-authenticated-read"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ;
+ else if (!g_strcmp0(permission, "encrypt-authenticated-write"))
+ ret = HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE;
+
+ return ret;
+}
+
+
+static bt_status_t _hal_gattc_get_characteristic_info(hal_gattc_char_t *gattc_char)
+{
+ GDBusProxy *properties_proxy = NULL;
+ GError *error = NULL;
+ GVariant *value = NULL;
+ GVariant *result = NULL;
+ GDBusConnection *g_conn;
+ const gchar *key;
+ char *char_desc_handle = NULL;
+ gsize len;
+ GVariantIter *property_iter;
+ GVariantIter *char_desc_iter;
+ char* char_handle = NULL;
+ const gchar *char_uuid_str = NULL;
+ GPtrArray *gp_desc_array = NULL;
+ GVariantIter *char_perm_iter;
+ gchar* permission;
+ unsigned int char_permission = 0 ;
+
+ DBG("+");
+
+ if (gattc_char->chr_path == NULL) {
+ DBG("char path is NULL");
+ return BT_STATUS_FAIL;
+ }
+ char_handle = gattc_char->chr_path;
+
+ DBG("char path:[%s]", gattc_char->chr_path);
+
+ g_conn = _bt_hal_get_system_gconn();
+ if (NULL == g_conn) {
+ ERR("_bt_gdbus_get_system_gconn returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ properties_proxy = g_dbus_proxy_new_sync(g_conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ BT_HAL_BLUEZ_NAME,
+ char_handle,
+ BT_HAL_PROPERTIES_INTERFACE,
+ NULL, &error);
+
+ if (properties_proxy == NULL) {
+ ERR("properties_proxy returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ result = g_dbus_proxy_call_sync(properties_proxy,
+ "GetAll",
+ g_variant_new("(s)", BT_HAL_GATT_CHAR_INTERFACE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (!result) {
+ if (error != NULL) {
+ ERR("Fail to get properties (Error: %s)", error->message);
+ g_clear_error(&error);
+ } else
+ ERR("Fail to get properties");
+ g_object_unref(properties_proxy);
+ return BT_STATUS_FAIL;
+ }
+
+ gp_desc_array = g_ptr_array_new();
+
+ g_variant_get(result, "(a{sv})", &property_iter);
+
+ while (g_variant_iter_loop(property_iter, "{sv}", &key, &value)) {
+ if (!g_strcmp0(key, "UUID")) {
+ char_uuid_str = g_variant_dup_string(value, &len);
+ DBG("char UUID [%s]", char_uuid_str);
+ } else if (!g_strcmp0(key, "Flags")) {
+ g_variant_get(value, "as", &char_perm_iter);
+ char_permission = 0x00;
+
+ while (g_variant_iter_loop(char_perm_iter, "s", &permission)) {
+ DBG("char permission: [%s]", permission);
+ char_permission |= _hal_get_permission_flag(permission);
+ }
+ } else if (!g_strcmp0(key, "Descriptors")) {
+ g_variant_get(value, "ao", &char_desc_iter);
+ while (g_variant_iter_loop(char_desc_iter, "&o", &char_desc_handle)) {
+ DBG("char descriptor handle : %s", char_desc_handle);
+
+ g_ptr_array_add(gp_desc_array, (gpointer)char_desc_handle);
+ }
+ }
+ }
+
+ _hal_gattc_update_char_property(gattc_char, char_uuid_str, gp_desc_array, char_permission);
+
+ g_variant_iter_free(property_iter);
+ g_variant_unref(result);
+ g_object_unref(properties_proxy);
+ g_ptr_array_free(gp_desc_array, TRUE);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t _gattc_get_all_characteristic(int conn_id,
+ btgatt_srvc_id_t *srvc_id)
+{
+ hal_gattc_server_info_t * conn_info = NULL;
+ hal_gattc_service_t *gattc_service = NULL;
+ GSList *l;
+ hal_gattc_char_t *gattc_char = NULL;
+ char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+ int status = BT_STATUS_FAIL;
+
+ DBG("+");
+ DBG("conn_id[%d]", conn_id);
+
+ conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+ if (NULL == conn_info) {
+ DBG("Failed to get the conn_info for conn_id[%d]", conn_id);
+ 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 object path */
+ for (l = gattc_service->gatt_list_chars; l != NULL; l = g_slist_next(l)) {
+ gattc_char = (hal_gattc_char_t *)l->data;
+ status = _hal_gattc_get_characteristic_info(gattc_char);
+
+ /* send event */
+ if (BT_STATUS_SUCCESS == status) {
+ DBG("Sending the success charateristics event");
+ _bt_hal_send_client_char_search_result_event(conn_id, status, srvc_id,
+ &gattc_char->chr_uuid, gattc_char->permission);
+ }
+ }
+
+ DBG("sending final event");
+
+ status = BT_STATUS_FAIL;
+ _bt_hal_send_client_char_search_result_event(conn_id, status, srvc_id, NULL, 0);
+
+ browse_service_char(conn_id);
+ /* retrive uuid for characteristic and object path for descriptor */
+
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * Enumerate characteristics for a given service.
+ * Set start_char_id to NULL to get the first characteristic.
+ */
+bt_status_t btif_gattc_get_characteristic(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *start_char_id)
+{
+ DBG("+");
+ CHECK_BTGATT_INIT();
+
+ if (start_char_id == NULL) {
+ DBG("Get all the characteristics");
+ return _gattc_get_all_characteristic(conn_id, srvc_id);
+
+ } else {
+ DBG("TBD Get specific characteristics");
+ return BT_STATUS_UNSUPPORTED;
+ }
+}
+
+static bt_status_t _hal_gattc_get_descriptor_info(hal_gattc_desc_t *gattc_desc)
+{
+ GDBusProxy *properties_proxy = NULL;
+ GError *error = NULL;
+ GVariant *value = NULL;
+ GVariant *result = NULL;
+ GDBusConnection *g_conn;
+ const gchar *key;
+ gsize len;
+ GVariantIter *property_iter;
+ char* desc_handle = NULL;
+ const gchar *desc_uuid_str = NULL;
+
+ DBG("+");
+
+ if (gattc_desc->desc_path == NULL) {
+ DBG("desc path is NULL");
+ return BT_STATUS_FAIL;
+ }
+ desc_handle = gattc_desc->desc_path;
+
+ DBG("desc path:[%s]", gattc_desc->desc_path);
+
+ g_conn = _bt_hal_get_system_gconn();
+ if (NULL == g_conn) {
+ ERR("_bt_gdbus_get_system_gconn returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ properties_proxy = g_dbus_proxy_new_sync(g_conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ BT_HAL_BLUEZ_NAME,
+ desc_handle,
+ BT_HAL_PROPERTIES_INTERFACE,
+ NULL, &error);
+
+ if (properties_proxy == NULL) {
+ ERR("properties_proxy returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ result = g_dbus_proxy_call_sync(properties_proxy,
+ "GetAll",
+ g_variant_new("(s)", BT_HAL_GATT_DESC_INTERFACE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (!result) {
+ if (error != NULL) {
+ ERR("Fail to get properties (Error: %s)", error->message);
+ g_clear_error(&error);
+ } else
+ ERR("Fail to get properties");
+ g_object_unref(properties_proxy);
+ return BT_STATUS_FAIL;
+ }
+
+ g_variant_get(result, "(a{sv})", &property_iter);
+
+ while (g_variant_iter_loop(property_iter, "{sv}", &key, &value)) {
+ if (!g_strcmp0(key, "UUID")) {
+ desc_uuid_str = g_variant_dup_string(value, &len);
+ DBG("desc UUID [%s]", desc_uuid_str);
+ }
+ }
+
+ _hal_gattc_update_desc_property(gattc_desc, desc_uuid_str);
+
+ g_variant_iter_free(property_iter);
+ g_variant_unref(result);
+ g_object_unref(properties_proxy);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static void _bt_hal_send_client_desc_search_result_event(int conn_id, int status,
+ btgatt_srvc_id_t *svc_id, btgatt_gatt_id_t *char_id, bt_uuid_t *desc_uuid)
+{
+ struct hal_ev_gatt_client_desc_search_result ev;
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ return;
+ }
+
+ DBG("sending gatt client search desc result event conn_id[%d] status[%d]", conn_id, status);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = conn_id;
+ ev.inst_id = svc_id->id.inst_id;
+ ev.is_primary = svc_id->is_primary;
+ ev.status = status;
+
+ memcpy(ev.svc_uuid, svc_id->id.uuid.uu, sizeof(ev.svc_uuid));
+ memcpy(ev.char_uuid, char_id->uuid.uu, sizeof(ev.char_uuid));
+
+ if (status == BT_STATUS_SUCCESS) {
+ DBG("building desc uuid");
+ memcpy(ev.desc_uuid, desc_uuid->uu, sizeof(ev.desc_uuid));
+ }
+
+ DBG("sending the desc search event");
+
+ event_cb(HAL_EV_GATT_CLIENT_DESC_SEARCH_RESULT, (void *)&ev, sizeof(ev));
+}
+
+static bt_status_t _hal_gattc_get_all_descriptor(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id)
+{
+ hal_gattc_server_info_t * conn_info = NULL;
+ hal_gattc_service_t *gattc_service = NULL;
+ GSList *l;
+ hal_gattc_char_t *gattc_char = NULL;
+ hal_gattc_desc_t *gattc_desc = NULL;
+ char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+ int status = BT_STATUS_FAIL;
+
+ DBG("+");
+
+ conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+ if (NULL == conn_info) {
+ DBG("Failed to get the conn_info for conn_id[%d]", conn_id);
+ 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 characteristics */
+ 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);
+
+ /* get descriptor uuid */
+ for (l = gattc_char->gatt_list_descs; l != NULL; l = g_slist_next(l)) {
+ gattc_desc = (hal_gattc_desc_t *)l->data;
+ status = _hal_gattc_get_descriptor_info(gattc_desc);
+
+ /* send event */
+ if (BT_STATUS_SUCCESS == status) {
+ DBG("Sending the success descriptor event");
+ _bt_hal_send_client_desc_search_result_event(conn_id, status, srvc_id,
+ char_id, &gattc_desc->desc_uuid);
+ }
+ }
+
+ DBG("sending final event");
+
+ status = BT_STATUS_FAIL;
+ _bt_hal_send_client_desc_search_result_event(conn_id, status, srvc_id, char_id, NULL);
+
+ browse_service_char(conn_id);
+ /* retrive uuid for characteristic and object path for descriptor */
+
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * Enumerate descriptors for a given characteristic.
+ * Set start_descr_id to NULL to get the first descriptor.
+ */
+bt_status_t btif_gattc_get_descriptor(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ btgatt_gatt_id_t *start_descr_id)
+{
+ DBG("+");
+ CHECK_BTGATT_INIT();
+
+ if (start_descr_id == NULL) {
+ DBG("Get all the descriptors");
+ return _hal_gattc_get_all_descriptor(conn_id, srvc_id, char_id);
+ } else {
+ DBG("TBD Get specific descriptor");
+ return BT_STATUS_UNSUPPORTED;
+ }
+}
+
+static void __hal_send_char_read_event(hal_gatt_resp_data_t *resp_data, int result, uint8_t *value, int len)
+{
+ struct hal_ev_gatt_client_read_data ev;
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ return;
+ }
+
+ DBG("sending gatt client charac read conn_id[%d] status[%d]", resp_data->conn_id, result);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = resp_data->conn_id;
+ ev.inst_id = resp_data->srvc_id.id.inst_id;
+ ev.is_primary = resp_data->srvc_id.is_primary;
+ ev.status = result;
+
+ 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));
+
+ ev.len = len;
+ if (len > 0) {
+ DBG("building the char read value [%d]", len);
+ memcpy(ev.value, value, len);
+ }
+
+ DBG("sending the gatt client read charac event");
+
+ event_cb(HAL_EV_GATT_CLIENT_READ_CHARAC, (void *)&ev, sizeof(ev));
+}
+
+static void __hal_internal_read_char_cb(GObject *source_object,
+ GAsyncResult *res, gpointer user_data)
+{
+ GError *error = NULL;
+ GDBusConnection *system_gconn = NULL;
+ GVariant *value;
+ GVariantIter *iter;
+ GByteArray *gp_byte_array = NULL;
+ guint8 g_byte;
+ hal_gatt_resp_data_t *resp_data = user_data;
+ int result = BT_STATUS_SUCCESS;
+ int i;
+
+ DBG("+");
+
+ system_gconn = _bt_hal_get_system_gconn();
+ value = g_dbus_connection_call_finish(system_gconn, res, &error);
+
+ if (error) {
+ ERR("Read Characteristic dbus failed Error:", error->message);
+
+ //send failed event
+ result = BT_STATUS_FAIL;
+ __hal_send_char_read_event(resp_data, result, NULL, 0);
+ g_clear_error(&error);
+ g_free(resp_data);
+ return;
+ }
+
+ gp_byte_array = g_byte_array_new();
+ g_variant_get(value, "(ay)", &iter);
+
+ while (g_variant_iter_loop(iter, "y", &g_byte))
+ g_byte_array_append(gp_byte_array, &g_byte, 1);
+
+ //print the value
+ DBG("value is");
+ for (i = 0; i < gp_byte_array->len; i++)
+ DBG("%02x", gp_byte_array->data[i]);
+
+ //send value event
+ __hal_send_char_read_event(resp_data, result, gp_byte_array->data, gp_byte_array->len);
+
+ g_free(resp_data);
+
+ g_byte_array_free(gp_byte_array, TRUE);
+ g_variant_iter_free(iter);
+ g_variant_unref(value);
+
+ DBG("-");
+}
+
+
+static bt_status_t _hal_read_characteristic_value(int conn_id, btgatt_srvc_id_t *srvc_id,
+ btgatt_gatt_id_t *char_id, int auth_req)
+{
+ GDBusConnection *g_conn;
+ hal_gatt_resp_data_t *resp_data;
+ hal_gattc_service_t *gattc_service = NULL;
+ GVariantBuilder *builder = NULL;
+ guint16 offset = 0;
+ hal_gattc_server_info_t * conn_info = NULL;
+ hal_gattc_char_t *gattc_char = NULL;
+ char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char* char_handle = NULL;
+
+ DBG("+");
+
+ /* get the connection info */
+ conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+ if (NULL == conn_info) {
+ DBG("Failed to get the conn_info for conn_id[%d]", conn_id);
+ 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);
+
+ g_conn = _bt_hal_get_system_gconn();
+ if (NULL == g_conn) {
+ ERR("_bt_gdbus_get_system_gconn returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+ if (NULL == resp_data) {
+ ERR("failed to get the memory");
+ return BT_STATUS_FAIL;
+ }
+
+ resp_data->conn_id = conn_id;
+ memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+ memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ /*offset*/
+ g_variant_builder_add(builder, "{sv}", "offset",
+ g_variant_new("q", offset));
+
+ char_handle = gattc_char->chr_path;
+
+ DBG("calling char read value");
+
+ g_dbus_connection_call(g_conn, BT_HAL_BLUEZ_NAME, char_handle, BT_HAL_GATT_CHAR_INTERFACE,
+ "ReadValue", g_variant_new("(a{sv})", builder),
+ G_VARIANT_TYPE("(ay)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+ (GAsyncReadyCallback)__hal_internal_read_char_cb,
+ (gpointer)resp_data);
+ g_variant_builder_unref(builder);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/** Read a characteristic on a remote device */
+bt_status_t btif_read_characteristic(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ int auth_req)
+{
+ CHECK_BTGATT_INIT();
+ DBG("+");
+
+ return _hal_read_characteristic_value(conn_id, srvc_id, char_id, auth_req);
+}
+
+static void __hal_send_char_write_event(hal_gatt_resp_data_t *resp_data, int result)
+{
+ struct hal_ev_gatt_client_write_result ev;
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ return;
+ }
+
+ DBG("sending gatt client charac write conn_id[%d] status[%d]", resp_data->conn_id, result);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = resp_data->conn_id;
+ ev.inst_id = resp_data->srvc_id.id.inst_id;
+ ev.is_primary = resp_data->srvc_id.is_primary;
+ ev.status = result;
+
+ 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));
+
+ DBG("sending the gatt client write charac event");
+
+ event_cb(HAL_EV_GATT_CLIENT_WRITE_CHARAC, (void *)&ev, sizeof(ev));
+}
+
+static void __hal_bluetooth_internal_write_cb(GObject *source_object,
+ GAsyncResult *res, gpointer user_data)
+{
+ GError *error = NULL;
+ GDBusConnection *system_gconn = NULL;
+ GVariant *value;
+ hal_gatt_resp_data_t *resp_data = user_data;
+ int result = BT_STATUS_SUCCESS;
+
+ DBG("+");
+
+ system_gconn = _bt_hal_get_system_gconn();
+ value = g_dbus_connection_call_finish(system_gconn, res, &error);
+
+ if (error) {
+ ERR("write Characteristic dbus failed Error:", error->message);
+
+ result = BT_STATUS_FAIL;
+ //send failed event
+ __hal_send_char_write_event(resp_data, result);
+ g_clear_error(&error);
+ g_free(resp_data);
+ return;
+ }
+
+ //send write value event
+ __hal_send_char_write_event(resp_data, result);
+
+ g_free(resp_data);
+ g_variant_unref(value);
+
+ DBG("-");
+}
+
+static bt_status_t __hal_get_write_prop(hal_gatt_write_type_t type, hal_gatt_property_e *prop)
+{
+ switch (type) {
+ case HAL_GATT_WRITE_TYPE_WRITE:
+ *prop = HAL_GATT_PROPERTY_WRITE;
+ break;
+ case HAL_GATT_WRITE_TYPE_WRITE_NO_RESPONSE:
+ *prop = HAL_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE;
+ break;
+ default:
+ ERR("Unknow write type : %d", type);
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t _hal_write_characteristic_value(int conn_id, btgatt_srvc_id_t *srvc_id,
+ btgatt_gatt_id_t *char_id, int write_type, int length, int auth_req, char* value)
+{
+ GVariant *val, *options;
+ GVariantBuilder *builder1;
+ GVariantBuilder *builder2;
+ GDBusConnection *g_conn;
+ guint16 offset = 0;
+ int i = 0;
+ hal_gatt_resp_data_t *resp_data;
+ hal_gattc_service_t *gattc_service = NULL;
+ hal_gattc_server_info_t * conn_info = NULL;
+ hal_gattc_char_t *gattc_char = NULL;
+ char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char* char_handle = NULL;
+ hal_gatt_property_e write_prop = HAL_GATT_PROPERTY_WRITE;
+ int ret = BT_STATUS_SUCCESS;
+
+ DBG("+");
+
+ ret = __hal_get_write_prop(write_type, &write_prop);
+ if (BT_STATUS_FAIL == ret) {
+ DBG("received invalid write type:[%d] ", write_type);
+ return BT_STATUS_FAIL;
+ }
+
+ /* get the connection info */
+ conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+ if (NULL == conn_info) {
+ DBG("Failed to get the conn_info for conn_id[%d]", conn_id);
+ 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);
+
+ g_conn = _bt_hal_get_system_gconn();
+ if (NULL == g_conn) {
+ ERR("_bt_gdbus_get_system_gconn returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+ if (NULL == resp_data) {
+ ERR("failed to get the memory");
+ return BT_STATUS_FAIL;
+ }
+
+ resp_data->conn_id = conn_id;
+ memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+ memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+
+ char_handle = gattc_char->chr_path;
+
+ builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+
+ for (i = 0; i < length; i++)
+ g_variant_builder_add(builder1, "y", value[i]);
+
+ val = g_variant_new("ay", builder1);
+
+ builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ /*offset*/
+ g_variant_builder_add(builder2, "{sv}", "offset",
+ g_variant_new_uint16(offset));
+
+ options = g_variant_new("a{sv}", builder2);
+
+ g_dbus_connection_call(g_conn, BT_HAL_BLUEZ_NAME, char_handle, BT_HAL_GATT_CHAR_INTERFACE,
+ "WriteValuebyType",
+ g_variant_new("(y@ay@a{sv})", write_prop, val, options),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+ (GAsyncReadyCallback)__hal_bluetooth_internal_write_cb,
+ (gpointer)resp_data);
+
+ g_variant_builder_unref(builder1);
+ g_variant_builder_unref(builder2);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/** Write a remote characteristic */
+bt_status_t btif_write_characteristic(int conn_id,
+ btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+ int write_type, int len, int auth_req,
+ char* p_value)
+{
+ CHECK_BTGATT_INIT();
+
+ DBG("+");
+
+ DBG("svc isntance id:[%d]", srvc_id->id.inst_id);
+ return _hal_write_characteristic_value(conn_id, srvc_id, char_id, write_type,
+ len, auth_req, p_value);
+}
+
+static void __hal_send_desc_read_event(hal_gatt_resp_data_t *resp_data, int result, uint8_t *value, int len)
+{
+ struct hal_ev_gatt_client_read_data ev;
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ return;
+ }
+
+ DBG("sending gatt client desc read conn_id[%d] status[%d]", resp_data->conn_id, result);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = resp_data->conn_id;
+ ev.inst_id = resp_data->srvc_id.id.inst_id;
+ ev.is_primary = resp_data->srvc_id.is_primary;
+ ev.status = result;
+
+ 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));
+ memcpy(ev.desc_uuid, resp_data->desc_id.uuid.uu, sizeof(ev.char_uuid));
+
+ ev.len = len;
+ if (len > 0) {
+ DBG("building the desc read value [%d]", len);
+ memcpy(ev.value, value, len);
+ }
+
+ DBG("sending the gatt client read descriptor event");
+
+ event_cb(HAL_EV_GATT_CLIENT_READ_DESC, (void *)&ev, sizeof(ev));
+}
+
+static void __hal_internal_read_desc_cb(GObject *source_object,
+ GAsyncResult *res, gpointer user_data)
+{
+ GError *error = NULL;
+ GDBusConnection *system_gconn = NULL;
+ GVariant *value;
+ GVariantIter *iter;
+ GByteArray *gp_byte_array = NULL;
+ guint8 g_byte;
+ hal_gatt_resp_data_t *resp_data = user_data;
+ int result = BT_STATUS_SUCCESS;
+ int i;
+
+ DBG("+");
+
+ system_gconn = _bt_hal_get_system_gconn();
+ value = g_dbus_connection_call_finish(system_gconn, res, &error);
+
+ if (error) {
+ ERR("Read descriptor dbus failed Error:", error->message);
+
+ //send failed event
+ result = BT_STATUS_FAIL;
+ __hal_send_desc_read_event(resp_data, result, NULL, 0);
+ g_clear_error(&error);
+ g_free(resp_data);
+ return;
+ }
+
+ gp_byte_array = g_byte_array_new();
+ g_variant_get(value, "(ay)", &iter);
+
+ while (g_variant_iter_loop(iter, "y", &g_byte))
+ g_byte_array_append(gp_byte_array, &g_byte, 1);
+
+ //print the value
+ DBG("value is");
+ for (i = 0; i < gp_byte_array->len; i++)
+ DBG("%02x", gp_byte_array->data[i]);
+
+ //send value event
+ __hal_send_desc_read_event(resp_data, result, gp_byte_array->data, gp_byte_array->len);
+
+ g_free(resp_data);
+
+ g_byte_array_free(gp_byte_array, TRUE);
+ g_variant_iter_free(iter);
+ g_variant_unref(value);
+
+ DBG("-");
+}
+
+static bt_status_t _hal_read_descriptor_value(int conn_id, btgatt_srvc_id_t *srvc_id,
+ btgatt_gatt_id_t *char_id, btgatt_gatt_id_t *desc_id, int auth_req)
+{
+ GDBusConnection *g_conn;
+ hal_gatt_resp_data_t *resp_data;
+ hal_gattc_service_t *gattc_service = NULL;
+ GVariantBuilder *builder = NULL;
+ guint16 offset = 0;
+ hal_gattc_server_info_t * conn_info = NULL;
+ hal_gattc_char_t *gattc_char = NULL;
+ char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char desc_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char* desc_handle = NULL;
+
+ hal_gattc_desc_t *gattc_desc = NULL;
+
+ DBG("+");
+
+ /* get the connection info */
+ conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+ if (NULL == conn_info) {
+ DBG("Failed to get the conn_info for conn_id[%d]", conn_id);
+ 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);
+
+ /* find descriptor */
+ gattc_desc = _gattc_find_desc_from_uuid(gattc_char, &desc_id->uuid);
+ if (NULL == gattc_desc) {
+ DBG("Failed to get the gatt desc");
+ return BT_STATUS_FAIL;
+ }
+
+ DBG("desc path [%s]", gattc_desc->desc_path);
+ _bt_hal_convert_uuid_type_to_string(desc_uuid_str, gattc_desc->desc_uuid.uu);
+ DBG("desc uuid [%s]", desc_uuid_str);
+
+ g_conn = _bt_hal_get_system_gconn();
+ if (NULL == g_conn) {
+ ERR("_bt_gdbus_get_system_gconn returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+ if (NULL == resp_data) {
+ ERR("failed to get the memory");
+ return BT_STATUS_FAIL;
+ }
+
+ resp_data->conn_id = conn_id;
+ memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+ memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+ memcpy(&resp_data->desc_id, desc_id, sizeof(btgatt_gatt_id_t));
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ /*offset*/
+ g_variant_builder_add(builder, "{sv}", "offset",
+ g_variant_new("q", offset));
+
+ desc_handle = gattc_desc->desc_path;
+
+ DBG("calling desc read value");
+
+ g_dbus_connection_call(g_conn, BT_HAL_BLUEZ_NAME, desc_handle, BT_HAL_GATT_DESC_INTERFACE,
+ "ReadValue", g_variant_new("(a{sv})", builder),
+ G_VARIANT_TYPE("(ay)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+ (GAsyncReadyCallback)__hal_internal_read_desc_cb,
+ (gpointer)resp_data);
+ g_variant_builder_unref(builder);
+
+ return BT_STATUS_SUCCESS;
}
-/**
- * Enumerate descriptors for a given characteristic.
- * Set start_descr_id to NULL to get the first descriptor.
- */
-bt_status_t get_descriptor(int conn_id,
+/** Read the descriptor for a given characteristic */
+bt_status_t btif_read_descriptor(int conn_id,
btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
- btgatt_gatt_id_t *start_descr_id)
+ btgatt_gatt_id_t *descr_id, int auth_req)
{
CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+
+ return _hal_read_descriptor_value(conn_id, srvc_id, char_id, descr_id, auth_req);
}
-/** Read a characteristic on a remote device */
-bt_status_t read_characteristic(int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
- int auth_req)
+static void __hal_send_desc_write_event(hal_gatt_resp_data_t *resp_data, int result)
{
- CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+ struct hal_ev_gatt_client_write_result ev;
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ return;
+ }
+
+ DBG("sending gatt client charac write conn_id[%d] status[%d]", resp_data->conn_id, result);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = resp_data->conn_id;
+ ev.inst_id = resp_data->srvc_id.id.inst_id;
+ ev.is_primary = resp_data->srvc_id.is_primary;
+ ev.status = result;
+
+ 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));
+ memcpy(ev.desc_uuid, resp_data->desc_id.uuid.uu, sizeof(ev.desc_uuid));
+
+ DBG("sending the gatt client write charac event");
+
+ event_cb(HAL_EV_GATT_CLIENT_WRITE_DESC, (void *)&ev, sizeof(ev));
}
-/** Write a remote characteristic */
-bt_status_t write_characteristic(int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
- int write_type, int len, int auth_req,
- char* p_value)
+static void __hal_bluetooth_internal_desc_write_cb(GObject *source_object,
+ GAsyncResult *res, gpointer user_data)
{
- CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+ GError *error = NULL;
+ GDBusConnection *system_gconn = NULL;
+ GVariant *value;
+ hal_gatt_resp_data_t *resp_data = user_data;
+ int result = BT_STATUS_SUCCESS;
+
+ DBG("+");
+
+ system_gconn = _bt_hal_get_system_gconn();
+ value = g_dbus_connection_call_finish(system_gconn, res, &error);
+
+ if (error) {
+ ERR("write descriptor dbus failed Error:", error->message);
+
+ //send failed event
+ result = BT_STATUS_FAIL;
+ __hal_send_desc_write_event(resp_data, result);
+ g_clear_error(&error);
+ g_free(resp_data);
+ return;
+ }
+
+ //send write value event
+ __hal_send_desc_write_event(resp_data, result);
+
+ g_free(resp_data);
+ g_variant_unref(value);
+
+ DBG("-");
}
-/** Read the descriptor for a given characteristic */
-bt_status_t read_descriptor(int conn_id,
- btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
- btgatt_gatt_id_t *descr_id, int auth_req)
+static bt_status_t _hal_write_descriptor_value(int conn_id, btgatt_srvc_id_t *srvc_id,
+ btgatt_gatt_id_t *char_id, btgatt_gatt_id_t *descr_id,
+ int write_type, int length, int auth_req, char* value)
{
- CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+ GVariant *val, *options;
+ GVariantBuilder *builder1;
+ GVariantBuilder *builder2;
+ GDBusConnection *g_conn;
+ guint16 offset = 0;
+ int i = 0;
+ hal_gatt_resp_data_t *resp_data;
+ hal_gattc_service_t *gattc_service = NULL;
+ hal_gattc_server_info_t * conn_info = NULL;
+ hal_gattc_char_t *gattc_char = NULL;
+ hal_gattc_desc_t *gattc_desc = NULL;
+ char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char desc_uuid_str[BT_HAL_UUID_STRING_LEN];
+ char* desc_handle = NULL;
+ hal_gatt_property_e write_prop = HAL_GATT_PROPERTY_WRITE;
+ int ret = BT_STATUS_SUCCESS;
+
+ DBG("+");
+
+ ret = __hal_get_write_prop(write_type, &write_prop);
+ if (BT_STATUS_FAIL == ret) {
+ DBG("received invalid write type:[%d] ", write_type);
+ return BT_STATUS_FAIL;
+ }
+
+ /* get the connection info */
+ conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+ if (NULL == conn_info) {
+ DBG("Failed to get the conn_info for conn_id[%d]", conn_id);
+ 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);
+
+ /* find descriptor */
+ gattc_desc = _gattc_find_desc_from_uuid(gattc_char, &descr_id->uuid);
+ if (NULL == gattc_desc) {
+ DBG("Failed to get the gatt char");
+ return BT_STATUS_FAIL;
+ }
+
+ DBG("desc path [%s]", gattc_desc->desc_path);
+ _bt_hal_convert_uuid_type_to_string(desc_uuid_str, gattc_desc->desc_uuid.uu);
+ DBG("char uuid [%s]", desc_uuid_str);
+
+ g_conn = _bt_hal_get_system_gconn();
+ if (NULL == g_conn) {
+ ERR("_bt_gdbus_get_system_gconn returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+ if (NULL == resp_data) {
+ ERR("failed to get the memory");
+ return BT_STATUS_FAIL;
+ }
+
+ resp_data->conn_id = conn_id;
+ memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+ memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+ memcpy(&resp_data->desc_id, descr_id, sizeof(btgatt_gatt_id_t));
+
+ desc_handle = gattc_desc->desc_path;
+
+ builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+
+ for (i = 0; i < length; i++)
+ g_variant_builder_add(builder1, "y", value[i]);
+
+ val = g_variant_new("ay", builder1);
+
+ builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ /*offset*/
+ g_variant_builder_add(builder2, "{sv}", "offset",
+ g_variant_new_uint16(offset));
+
+ options = g_variant_new("a{sv}", builder2);
+
+ g_dbus_connection_call(g_conn, BT_HAL_BLUEZ_NAME, desc_handle, BT_HAL_GATT_DESC_INTERFACE,
+ "WriteValue",
+ g_variant_new("(@ay@a{sv})", val, options),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+ (GAsyncReadyCallback)__hal_bluetooth_internal_desc_write_cb,
+ (gpointer)resp_data);
+
+ g_variant_builder_unref(builder1);
+ g_variant_builder_unref(builder2);
+
+ return BT_STATUS_SUCCESS;
}
+
/** Write a remote descriptor for a given characteristic */
-bt_status_t write_descriptor(int conn_id,
+bt_status_t btif_write_descriptor(int conn_id,
btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
btgatt_gatt_id_t *descr_id, int write_type, int len,
int auth_req, char* p_value)
{
CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+
+ return _hal_write_descriptor_value(conn_id, srvc_id, char_id, descr_id, write_type,
+ len, auth_req, p_value);
}
/** Execute a prepared write operation */
return BT_STATUS_UNSUPPORTED;
}
+static bt_status_t __hal_update_conn_parameter(bt_bdaddr_t *bd_addr,
+ int min_int, int max_int, int latency, int timeout)
+{
+ gchar *device_path = NULL;
+ GError *error = NULL;
+ GDBusProxy *device_proxy = NULL;
+ GDBusConnection *conn;
+ GVariant *reply;
+ int ret = BT_STATUS_SUCCESS;
+ char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+
+ INFO("Min interval: %d, Max interval: %d, Latency: %d, Supervision timeout: %d",
+ min_int, max_int, latency, timeout);
+
+ conn = _bt_hal_get_system_gconn();
+ if (conn == NULL) {
+ ERR("conn NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ _bt_hal_convert_addr_type_to_string(device_address,
+ (unsigned char *)bd_addr->address);
+ device_path = _bt_hal_get_device_object_path(device_address);
+
+ if (device_path == NULL) {
+ ERR("device_path NULL : [%s]", device_address);
+ return BT_STATUS_FAIL;
+ }
+
+ device_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, BT_HAL_BLUEZ_NAME,
+ device_path, BT_HAL_DEVICE_INTERFACE, NULL, NULL);
+
+ g_free(device_path);
+ if (NULL == device_proxy) {
+ ERR("device_proxy returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ INFO("### LeConnUpdate");
+ reply = g_dbus_proxy_call_sync(device_proxy, "LeConnUpdate",
+ g_variant_new("(uuuu)", min_int, max_int, latency, timeout),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ g_object_unref(device_proxy);
+ if (reply == NULL) {
+ if (error) {
+ ERR("Error %s[%s]", error->message, device_address);
+ if (g_strrstr(error->message, "In Progress"))
+ ret = BT_STATUS_SUCCESS;
+ else
+ ret = BT_STATUS_FAIL;
+ g_error_free(error);
+ return ret;
+ }
+ }
+ g_variant_unref(reply);
+
+ INFO("LE Connection parameter Updated");
+ return ret;
+}
+
/** Request a connection parameter update */
-bt_status_t conn_parameter_update(bt_bdaddr_t *bd, int min_int, int max_int, int latency, int timeout)
+bt_status_t btif_gattc_conn_parameter_update(bt_bdaddr_t *bd, int min_int, int max_int, int latency, int timeout)
{
CHECK_BTGATT_INIT();
- return BT_STATUS_UNSUPPORTED;
+
+ DBG("+");
+
+ return __hal_update_conn_parameter(bd, min_int, max_int, latency, timeout);
}
/** Test mode interface */
return BT_STATUS_UNSUPPORTED;
}
-
/** Configure a scan filter condition */
bt_status_t scan_filter_add_remove(int client_if, int action, int filt_type,
int filt_index, int company_id,
}
const btgatt_client_interface_t btgatt_client_interface = {
- register_client,
- unregister_client,
+ btif_gattc_register_client,
+ btif_gattc_unregister_client,
scan,
- connect,
- disconnect,
+ btif_gattc_client_connect,
+ btif_gattc_client_disconnect,
refresh,
- search_service,
+ btif_gattc_client_search_service,
get_included_service,
- get_characteristic,
- get_descriptor,
- read_characteristic,
- write_characteristic,
- read_descriptor,
- write_descriptor,
+ btif_gattc_get_characteristic,
+ btif_gattc_get_descriptor,
+ btif_read_characteristic,
+ btif_write_characteristic,
+ btif_read_descriptor,
+ btif_write_descriptor,
execute_write,
register_for_notification,
deregister_for_notification,
read_remote_rssi,
ota_fw_update,
get_device_type,
- conn_parameter_update,
+ btif_gattc_conn_parameter_update,
test_command,
configure_mtu,
scan_filter_param_setup,
batchscan_dis_batch_scan,
batchscan_read_reports
};
+
+static hal_gattc_server_info_t *__bt_find_gatt_conn_info(bt_bdaddr_t *serv_addr)
+{
+ DBG("+");
+
+ GSList *l;
+ hal_gattc_server_info_t *info = NULL;
+
+ for (l = hal_gattc_server_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (hal_gattc_server_info_t*)l->data;
+ if (info == NULL)
+ continue;
+
+ if (!memcmp(&info->bd_addr, serv_addr, sizeof(bt_bdaddr_t))) {
+ INFO("GATT connection found addr");
+ return info;
+ }
+ }
+ return NULL;
+}
+
+static hal_gattc_client_info_t *__bt_find_gatt_client_info(bt_bdaddr_t *serv_addr)
+{
+ DBG("+");
+
+ GSList *l;
+ hal_gattc_client_info_t *info = NULL;
+
+ for (l = hal_gattc_client_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (hal_gattc_client_info_t*)l->data;
+ if (info == NULL)
+ continue;
+
+ if (!memcmp(&info->bd_addr, serv_addr, sizeof(bt_bdaddr_t))) {
+ INFO("GATT client info found addr");
+ return info;
+ }
+ }
+ return NULL;
+}
+
+static hal_gattc_client_info_t *__bt_find_gatt_client_info_from_conn_id(int conn_id)
+{
+ DBG("+");
+
+ GSList *l;
+ hal_gattc_client_info_t *info = NULL;
+
+ for (l = hal_gattc_client_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (hal_gattc_client_info_t*)l->data;
+ if (info == NULL)
+ continue;
+
+ if (info->conn_id == conn_id) {
+ INFO("GATT client info found for conn_id [%d]", conn_id);
+ return info;
+ }
+ }
+ return NULL;
+}
+
+static hal_gattc_server_info_t *__bt_find_gatt_conn_info_from_conn_id(int conn_id)
+{
+ DBG("+");
+
+ GSList *l;
+ hal_gattc_server_info_t *info = NULL;
+ hal_gattc_client_info_t *gattc_client = NULL;
+
+ gattc_client = __bt_find_gatt_client_info_from_conn_id(conn_id);
+ if (gattc_client == NULL) {
+ INFO("GATT client conn info not found");
+ return NULL;
+ }
+
+ for (l = hal_gattc_server_info_list; l != NULL; l = g_slist_next(l)) {
+ info = (hal_gattc_server_info_t*)l->data;
+ if (info == NULL)
+ continue;
+
+ if ((info->inst_id == gattc_client->inst_id) &&
+ !memcmp(&info->bd_addr, &gattc_client->bd_addr, sizeof(bt_bdaddr_t))) {
+ INFO("GATT connection found for conn_id [%d]", conn_id);
+ return info;
+ }
+ }
+ return NULL;
+}
+
+static bt_status_t __bt_connect_le_device_internal(int client_if, const bt_bdaddr_t *bd_addr,
+ gboolean auto_connect)
+{
+ char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+ gchar *device_path = NULL;
+ GDBusProxy *device_proxy = NULL;
+ GDBusConnection *conn;
+ int ret = BT_STATUS_SUCCESS;
+ hal_gattc_client_info_t *gattc_data;
+
+ DBG("+");
+
+ if (NULL == bd_addr) {
+ ERR("bd_addr is NULL");
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ conn = _bt_hal_get_system_gconn();
+ if (NULL == conn) {
+ ERR("_bt_gdbus_get_system_gconn returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ _bt_hal_convert_addr_type_to_string(device_address,
+ (unsigned char *)bd_addr->address);
+ device_path = _bt_hal_get_device_object_path(device_address);
+ if (device_path == NULL) {
+ ERR("device_path NULL : [%s]", device_address);
+ ret = BT_STATUS_FAIL;
+ return ret;
+ }
+ ERR("device_path:%s", device_path);
+
+ device_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, BT_HAL_BLUEZ_NAME,
+ device_path, BT_HAL_DEVICE_INTERFACE, NULL, NULL);
+ g_free(device_path);
+ if (NULL == device_proxy) {
+ ERR("device_proxy returned NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ gattc_data = g_malloc0(sizeof(hal_gattc_client_info_t));
+ if (gattc_data == NULL) {
+ ERR("Unable to allocate memory");
+ ret = BT_STATUS_NOMEM;
+ goto fail;
+ }
+ memcpy(gattc_data->bd_addr.address, bd_addr->address,
+ BT_HAL_ADDRESS_LENGTH_MAX);
+
+ DBG("Connect LE [%s]", device_address);
+
+ gattc_data->client_if = client_if;
+
+ g_dbus_proxy_call(device_proxy, "ConnectLE",
+ g_variant_new("(b)", auto_connect),
+ G_DBUS_CALL_FLAGS_NONE,
+ BT_HAL_MAX_DBUS_TIMEOUT,
+ NULL,
+ (GAsyncReadyCallback)__le_connection_req_cb, gattc_data);
+
+ return ret;
+
+fail:
+ if (device_proxy)
+ g_object_unref(device_proxy);
+
+ g_free(gattc_data);
+
+ return ret;
+}
+
+static bt_status_t _bt_hold_current_advertising()
+{
+ int ret = BT_STATUS_FAIL;
+ gboolean is_advertising = FALSE;
+ DBG("+");
+
+ is_advertising = _bt_hal_is_advertising_in_slot(0);
+ if (is_advertising) {
+ DBG("+ Stop current advertising");
+
+ ret = _bt_hal_enable_advertising(0, FALSE, FALSE);
+ g_timeout_add(2000, __bt_hold_current_advertising_timeout_cb, NULL);
+ }
+
+ return ret;
+}
+
+static gboolean __bt_hold_current_advertising_timeout_cb(gpointer user_data)
+{
+ DBG("+ start current advertising");
+
+ _bt_hal_enable_advertising(0, TRUE, FALSE);
+
+ return FALSE;
+}
+
+static gboolean __bt_connect_le_timer_cb(gpointer user_data)
+{
+ DBG("Try to initiate pending LE connection");
+
+ pending_le_conn_timer_id = 0;
+
+ __bt_connect_le_device_internal(pending_le_conn_info->client_if,
+ &pending_le_conn_info->bd_addr,
+ pending_le_conn_info->auto_connect);
+
+ g_free(pending_le_conn_info);
+ pending_le_conn_info = NULL;
+
+ return FALSE;
+}
+
+static int __hal_generate_conn_id()
+{
+ return ++bt_conn_id;
+}
+
+static int __hal_generate_server_instance_id()
+{
+ return ++bt_inst_id;
+}
+
+static void __le_connection_req_cb(GDBusProxy *proxy, GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *g_error = NULL;
+ GVariant *reply = NULL;
+ hal_gattc_client_info_t *gattc_data = user_data;
+ int result = BT_STATUS_SUCCESS;
+ struct hal_ev_gatt_client_connected ev;
+ hal_gattc_server_info_t *gatt_conn_info = NULL;
+
+ DBG("+");
+
+ reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
+ g_object_unref(proxy);
+ if (reply == NULL) {
+ ERR("Connect LE Dbus Call Error");
+ if (g_error) {
+ ERR("Error: %s\n", g_error->message);
+ g_clear_error(&g_error);
+ }
+ result = BT_STATUS_FAIL;
+ }
+ g_variant_unref(reply);
+
+ if (NULL == gattc_data) {
+ ERR("server_data is NULL");
+ return;
+ }
+
+ /*send fail event*/
+ if (result == BT_STATUS_FAIL) {
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = -1;
+ ev.status = result;
+ ev.client_if = gattc_data->client_if;
+ memcpy(ev.bdaddr, gattc_data->bd_addr.address,
+ BT_HAL_ADDRESS_LENGTH_MAX);
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ } else {
+ DBG("sending gatt client connected event");
+ event_cb(HAL_EV_GATT_CLIENT_CONNECTED, (void *)&ev, sizeof(ev));
+ }
+
+ goto fail;
+ }
+
+ DBG("adding the server conn info in list");
+ gattc_data->conn_id = __hal_generate_conn_id() ;
+ gattc_data->inst_id = __hal_generate_server_instance_id();
+
+ hal_gattc_client_info_list = g_slist_append(hal_gattc_client_info_list, gattc_data);
+
+ /*add gatt server connection info*/
+ gatt_conn_info = g_malloc0(sizeof(hal_gattc_server_info_t));
+ if (gatt_conn_info == NULL) {
+ ERR("Failed to allocate memory");
+ goto fail;
+ }
+
+ memcpy(gatt_conn_info->bd_addr.address, gattc_data->bd_addr.address, BT_HAL_ADDRESS_LENGTH_MAX);
+ gatt_conn_info->inst_id = gattc_data->inst_id;
+ hal_gattc_server_info_list = g_slist_append(hal_gattc_server_info_list, gatt_conn_info);
+
+ DBG("-");
+ return;
+
+fail:
+ /*remove conn_info*/
+ if (gattc_data)
+ g_free(gattc_data);
+}
+
+void __hal_gattc_free_svc_info(hal_gattc_service_t *svc_info)
+{
+ g_free(svc_info->svc_path);
+ g_free(svc_info);
+}
+
+void __hal_gattc_free_char_info(hal_gattc_char_t *char_info)
+{
+ g_free(char_info->chr_path);
+ g_free(char_info);
+}
+
+void __hal_gattc_free_desc_info(hal_gattc_desc_t *desc_info)
+{
+ g_free(desc_info->desc_path);
+ g_free(desc_info);
+}
+
+void __hal_clean_gattc_server_info(hal_gattc_server_info_t *conn_info)
+{
+ GSList *l;
+ GSList *m;
+ GSList *k;
+ hal_gattc_service_t *svc_info = NULL;
+ hal_gattc_char_t *char_info = NULL;
+ hal_gattc_desc_t *desc_info = NULL;
+
+ DBG("+");
+
+ for (l = conn_info->gatt_list_services; l != NULL;) {
+ svc_info = (hal_gattc_service_t*)l->data;
+ if (svc_info == NULL)
+ continue;
+ l = g_slist_next(l);
+
+ for (m = svc_info->gatt_list_chars; m != NULL; ) {
+ char_info = (hal_gattc_char_t*)m->data;
+ if (char_info == NULL)
+ continue;
+ m = g_slist_next(m);
+
+ for (k = char_info->gatt_list_descs; k != NULL; ) {
+ desc_info = (hal_gattc_desc_t*)k->data;
+ if (desc_info == NULL)
+ continue;
+ k = g_slist_next(k);
+
+ /*remove desc element*/
+ char_info->gatt_list_descs = g_slist_remove(char_info->gatt_list_descs, desc_info);
+ __hal_gattc_free_desc_info(desc_info);
+ }
+
+ /*remove desc list*/
+ g_slist_free(char_info->gatt_list_descs);
+ char_info->gatt_list_descs = NULL;
+
+ /*remove char element*/
+ svc_info->gatt_list_chars = g_slist_remove(svc_info->gatt_list_chars, char_info);
+ __hal_gattc_free_char_info(char_info);
+ }
+
+ /*remove char list*/
+ g_slist_free(svc_info->gatt_list_chars);
+ svc_info->gatt_list_chars = NULL;
+
+ /*remove svc element*/
+ conn_info->gatt_list_services = g_slist_remove(conn_info->gatt_list_services, svc_info);
+ __hal_gattc_free_svc_info(svc_info);
+ }
+
+ /*remove svc list */
+ g_slist_free(conn_info->gatt_list_services);
+ conn_info->gatt_list_services = NULL;
+
+ /*remove conn info*/
+ g_free(conn_info);
+}
+
+void _bt_hal_handle_gattc_connected_event(char* address, gboolean gatt_connected)
+{
+ int result = BT_STATUS_SUCCESS;
+ struct hal_ev_gatt_client_connected ev;
+ hal_gattc_server_info_t *conn_info = NULL;
+ bt_bdaddr_t bd_addr;
+ int event;
+ hal_gattc_client_info_t *gattc_client = NULL;
+ int inst_id = -1;
+
+
+ DBG("+ connected device address [%s]", address);
+
+ event = gatt_connected ? HAL_EV_GATT_CLIENT_CONNECTED :
+ HAL_EV_GATT_CLIENT_DISCONNECTED;
+
+ _bt_hal_convert_addr_string_to_type(bd_addr.address, address);
+ /* find the gatt client info */
+ gattc_client = __bt_find_gatt_client_info(&bd_addr);
+ if (NULL == gattc_client) {
+ ERR("Fail to get gatt client info");
+ return;
+ }
+
+ //send event
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = gattc_client->conn_id;
+ ev.status = result;
+ ev.client_if = gattc_client->client_if;
+ memcpy(ev.bdaddr, gattc_client->bd_addr.address,
+ BT_HAL_ADDRESS_LENGTH_MAX);
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ } else {
+ DBG("sending gatt client connected status event");
+ event_cb(event, (void *)&ev, sizeof(ev));
+ }
+
+ if (!gatt_connected) {
+ inst_id = gattc_client->inst_id;
+
+ /* remove the gatt client info from the client list also*/
+ hal_gattc_client_info_list = g_slist_remove(hal_gattc_client_info_list, gattc_client);
+ g_free(gattc_client);
+
+ //find the connected server info
+ conn_info = __bt_find_gatt_conn_info(&bd_addr);
+ if (NULL == conn_info) {
+ ERR("Fail to get gatt server info");
+ return;
+ }
+
+ if (inst_id != conn_info->inst_id) {
+ ERR("server instance is different");
+ return;
+ }
+
+ //remove gatt conn info from the server list
+ DBG("remove the server conn_info from list after gatt disconnection");
+ hal_gattc_server_info_list = g_slist_remove(hal_gattc_server_info_list, conn_info);
+ __hal_clean_gattc_server_info(conn_info);
+ }
+
+ DBG("-");
+}
+
+static void _bt_hal_send_search_service_result_event(int conn_id, int is_primary,
+ const char* uuid_str, int inst_id)
+{
+ struct hal_ev_gatt_client_search_result ev;
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ return;
+ }
+
+ DBG("sending gatt client search service result event conn_id[%d]", conn_id);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = conn_id;
+ ev.inst_id = inst_id;
+ ev.is_primary = is_primary;
+ _bt_hal_convert_uuid_string_to_type(ev.uuid, uuid_str);
+
+ event_cb(HAL_EV_GATT_CLIENT_SEARCH_RESULT, (void *)&ev, sizeof(ev));
+}
+
+static void _bt_hal_send_search_service_complete_event(int conn_id, int status)
+{
+ struct hal_ev_gatt_client_search_complete ev;
+
+ if (!event_cb) {
+ ERR("gatt client callback not registered");
+ return;
+ }
+
+ DBG("sending gatt client search service complete event conn_id[%d]", conn_id);
+
+
+ memset(&ev, 0, sizeof(ev));
+ ev.conn_id = conn_id;
+ ev.status = status;
+
+ event_cb(HAL_EV_GATT_CLIENT_SEARCH_COMPLETE, (void *)&ev, sizeof(ev));
+}