X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bt-api%2Fbt-gatt-client.c;h=3a7d8427ab688cf37efe4f8055ca03ae98e3ec4a;hb=d09e1ba26924a3ee146675a426f19dc260514fbe;hp=486513d3cd2e1355e1f7c7c79e88dffa9ac7cc90;hpb=f8cd843634b70ab96c83bd552606c197fcf5decc;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git diff --git a/bt-api/bt-gatt-client.c b/bt-api/bt-gatt-client.c index 486513d..3a7d842 100755 --- a/bt-api/bt-gatt-client.c +++ b/bt-api/bt-gatt-client.c @@ -1,10 +1,5 @@ /* - * Bluetooth-frwk low energy (GATT Client) - * - * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Hocheol Seo - * Chanyeol Park + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,17 +21,22 @@ #include #include #include +#include #include "bt-common.h" +#include "bt-event-handler.h" +#include "bt-gatt-client.h" +#include "bt-internal-types.h" +#include "bt-request-sender.h" + +#ifdef TIZEN_GATT_CLIENT +#include "bluetooth-gatt-client-api.h" +#include +static GSList *gatt_characteristic_notify_list; +static GSList *gatt_characteristic_write_list = NULL;; +#endif -#define GATT_SERV_INTERFACE "org.bluez.GattService1" -#define GATT_CHAR_INTERFACE "org.bluez.GattCharacteristic1" -#define GATT_DESC_INTERFACE "org.bluez.GattDescriptor1" - -#define GATT_USER_DESC_UUID "00002901-0000-1000-8000-00805f9b34fb" -#define GATT_CHAR_CLIENT_CONF "00002902-0000-1000-8000-00805f9b34fb" -#define GATT_CHAR_SERVER_CONF "00002903-0000-1000-8000-00805f9b34fb" -#define GATT_CHAR_FORMAT "00002904-0000-1000-8000-00805f9b34fb" +#define GATT_DEFAULT_TIMEOUT (6 * 1000) // Dependent on supervision timeout 6 sec typedef enum { TYPE_NONE, @@ -44,7 +44,9 @@ typedef enum { CLIENT_CONF, SERVER_CONF, CHAR_FORMAT -}char_descriptor_type_t; +} char_descriptor_type_t; + +static GSList *service_monitor_list = NULL; BT_EXPORT_API int bluetooth_gatt_free_service_property(bt_gatt_service_property_t *svc_pty) { @@ -52,10 +54,14 @@ BT_EXPORT_API int bluetooth_gatt_free_service_property(bt_gatt_service_property_ BT_CHECK_PARAMETER(svc_pty, return); +#ifdef TIZEN_GATT_CLIENT + g_free(svc_pty->uuid); +#else g_free(svc_pty->uuid); g_free(svc_pty->handle); g_strfreev(svc_pty->include_handles.handle); g_strfreev(svc_pty->char_handle.handle); +#endif memset(svc_pty, 0, sizeof(bt_gatt_service_property_t)); @@ -73,8 +79,10 @@ BT_EXPORT_API int bluetooth_gatt_free_char_property(bt_gatt_char_property_t *cha g_free(char_pty->name); g_free(char_pty->description); g_free(char_pty->val); +#ifndef TIZEN_GATT_CLIENT g_free(char_pty->handle); g_strfreev(char_pty->char_desc_handle.handle); +#endif memset(char_pty, 0, sizeof(bt_gatt_char_property_t)); @@ -90,7 +98,9 @@ BT_EXPORT_API int bluetooth_gatt_free_desc_property(bt_gatt_char_descriptor_prop g_free(desc_pty->uuid); g_free(desc_pty->val); +#ifndef TIZEN_GATT_CLIENT g_free(desc_pty->handle); +#endif memset(desc_pty, 0, sizeof(bt_gatt_char_descriptor_property_t)); @@ -112,12 +122,89 @@ static char **__get_string_array_from_gptr_array(GPtrArray *gp) for (i = 0; i < gp->len; i++) { gp_path = g_ptr_array_index(gp, i); path[i] = g_strdup(gp_path); - BT_DBG("path[%d] : [%s]", i, path[i]); + // BT_DBG("path[%d] : [%s]", i, path[i]); } return path; } +gboolean _bluetooth_gatt_check_service_change_watcher_address( + const bluetooth_device_address_t *device_addr) +{ + GSList *l; + char device_address[BT_ADDRESS_STRING_SIZE] = { 0 }; + char secure_address[BT_ADDRESS_STRING_SIZE] = { 0 }; + + _bt_convert_addr_type_to_string(device_address, + (unsigned char *)device_addr->addr); + + for (l = service_monitor_list; l != NULL; l = l->next) { + char device_address2[BT_ADDRESS_STRING_SIZE] = { 0 }; + char secure_address2[BT_ADDRESS_STRING_SIZE] = { 0 }; + bluetooth_device_address_t *addr = l->data; + + _bt_convert_addr_type_to_string(device_address2, + (unsigned char *)addr->addr); + _bt_convert_addr_string_to_secure_string(secure_address, + device_address); + _bt_convert_addr_string_to_secure_string(secure_address2, + device_address2); + BT_INFO("service_monitor_list [%s] - Input [%s]", + secure_address2, secure_address); + + if (!memcmp(device_addr, addr, + sizeof(bluetooth_device_address_t))) + return TRUE; + } + + return FALSE; +} + +BT_EXPORT_API int bluetooth_gatt_set_service_change_watcher( + const bluetooth_device_address_t *address, gboolean enable) +{ + GSList *l; + bluetooth_device_address_t *addr = NULL; + char secure_address[BT_ADDRESS_STRING_SIZE] = { 0 }; + + _bt_convert_addr_type_to_secure_string(secure_address, (unsigned char *)address->addr); + BT_INFO("Set watcher for %s with %d", secure_address, enable); + + if (enable == TRUE) { + if (_bluetooth_gatt_check_service_change_watcher_address(address) + == TRUE) { + BT_INFO("The watcher is already set"); + return BLUETOOTH_ERROR_NONE; + } + + if (service_monitor_list == NULL) + _bt_register_manager_subscribe_signal(TRUE); + + addr = g_malloc0(sizeof(bluetooth_device_address_t)); + memcpy(addr, address, sizeof(bluetooth_device_address_t)); + + service_monitor_list = + g_slist_append(service_monitor_list, addr); + } else { + for (l = service_monitor_list; l != NULL; l = l->next) { + addr = l->data; + + if (!memcmp(address, addr, + sizeof(bluetooth_device_address_t))) { + service_monitor_list = + g_slist_remove(service_monitor_list, addr); + g_free(addr); + break; + } + } + + if (service_monitor_list == NULL) + _bt_register_manager_subscribe_signal(FALSE); + } + + return BLUETOOTH_ERROR_NONE; +} + BT_EXPORT_API int bluetooth_gatt_get_service_property(const char *service_handle, bt_gatt_service_property_t *service) { @@ -125,10 +212,10 @@ BT_EXPORT_API int bluetooth_gatt_get_service_property(const char *service_handle GError *error = NULL; GVariant *result = NULL; GDBusConnection *g_conn; - int len; + gsize len; char *char_handle = NULL; GPtrArray *gp_array = NULL ; - GVariantIter *property_iter, *char_iter; + GVariantIter *property_iter, *char_iter = NULL; const gchar *key; GVariant *value; @@ -171,36 +258,46 @@ BT_EXPORT_API int bluetooth_gatt_get_service_property(const char *service_handle memset(service, 0, sizeof(bt_gatt_service_property_t)); while (g_variant_iter_loop(property_iter, "{sv}", &key, &value)) { - if (!g_strcmp0(key,"UUID")) { - service->uuid = g_variant_dup_string(value,&len); - - } else if(!g_strcmp0(key, "Primary")) { + if (!g_strcmp0(key, "UUID")) { + char *name = NULL; + service->uuid = g_variant_dup_string(value, &len); + bluetooth_get_uuid_name(service->uuid, &name); + BT_INFO("%s %s [%s]", service_handle + 37, service->uuid, name); + g_free(name); + } else if (!g_strcmp0(key, "Primary")) { service->primary = g_variant_get_boolean(value); } else if (!g_strcmp0(key, "Includes")) { g_variant_get(value, "ao", &char_iter); - gp_array = g_ptr_array_new(); - while (g_variant_iter_loop(char_iter, "&o", &char_handle)) { - g_ptr_array_add(gp_array, (gpointer)char_handle); - } - if (gp_array->len != 0) { - service->include_handles.count = gp_array->len; - service->include_handles.handle = - __get_string_array_from_gptr_array(gp_array); + if (char_iter != NULL) { + gp_array = g_ptr_array_new(); + while (g_variant_iter_loop(char_iter, "&o", &char_handle)) + g_ptr_array_add(gp_array, (gpointer)char_handle); + + if (gp_array->len != 0) { + service->include_handles.count = gp_array->len; + service->include_handles.handle = + __get_string_array_from_gptr_array(gp_array); + } + g_ptr_array_free(gp_array, TRUE); + g_variant_iter_free(char_iter); } - g_ptr_array_free(gp_array, TRUE); } else if (!g_strcmp0(key, "Characteristics")) { g_variant_get(value, "ao", &char_iter); - gp_array = g_ptr_array_new(); - while (g_variant_iter_loop(char_iter, "&o", &char_handle)) { - g_ptr_array_add(gp_array, (gpointer)char_handle); - } - if (gp_array->len != 0) { - service->char_handle.count = gp_array->len; - service->char_handle.handle = - __get_string_array_from_gptr_array(gp_array); + if (char_iter != NULL) { + gp_array = g_ptr_array_new(); + while (g_variant_iter_loop(char_iter, "&o", &char_handle)) + g_ptr_array_add(gp_array, (gpointer)char_handle); + + if (gp_array->len != 0) { + service->char_handle.count = gp_array->len; + service->char_handle.handle = + __get_string_array_from_gptr_array(gp_array); + } + g_ptr_array_free(gp_array, TRUE); + g_variant_iter_free(char_iter); } - g_ptr_array_free(gp_array, TRUE); + BT_DBG("Characteristics count : %d", service->char_handle.count); } } @@ -229,8 +326,9 @@ BT_EXPORT_API int bluetooth_gatt_get_primary_services( char device_address[BT_ADDRESS_STRING_SIZE] = { 0 }; char temp_address[BT_ADDRESS_STRING_SIZE] = { 0 }; int ret = BLUETOOTH_ERROR_INTERNAL; + int idx = 0; - BT_INFO("+"); + BT_DBG("+"); BT_CHECK_PARAMETER(address, return); BT_CHECK_PARAMETER(prim_svc, return); BT_CHECK_ENABLED(return); @@ -260,7 +358,7 @@ BT_EXPORT_API int bluetooth_gatt_get_primary_services( if (g_strcmp0(interface_str, GATT_SERV_INTERFACE) != 0) continue; - BT_DBG("Object Path: %s", object_path); + BT_DBG("[%d] Object Path : %s", idx++, object_path); while (g_variant_iter_loop(svc_iter, "{sv}", &key, &value)) { if (g_strcmp0(key, "Primary") == 0) { if (g_variant_get_boolean(value)) @@ -294,7 +392,6 @@ BT_EXPORT_API int bluetooth_gatt_get_service_from_uuid(bluetooth_device_address_ GVariantIter *iter; GVariantIter *svc_iter; GVariantIter *interface_iter; - GError *error = NULL; char *object_path = NULL; char *interface_str = NULL; char device_address[BT_ADDRESS_STRING_SIZE] = { 0 }; @@ -364,7 +461,6 @@ static void __bluetooth_internal_get_char_cb(GDBusProxy *proxy, GVariantIter *char_iter; GPtrArray *gp_array = NULL; bt_gatt_discovered_char_t svc_char = { 0, }; - int i; char *char_handle; GError *error = NULL; bt_user_info_t *user_info; @@ -397,20 +493,16 @@ static void __bluetooth_internal_get_char_cb(GDBusProxy *proxy, g_variant_get(value, "(v)", &char_value); g_variant_get(char_value, "ao", &char_iter); - int len = g_variant_get_size(char_iter); - if (len > 0) { - gp_array = g_ptr_array_new(); - for (i = 0; i < len; i++) { - g_variant_iter_loop(char_iter, "&o", &char_handle); - g_ptr_array_add(gp_array, (gpointer)char_handle); - } - if (gp_array->len != 0) { - svc_char.handle_info.count = gp_array->len; - svc_char.handle_info.handle = - __get_string_array_from_gptr_array(gp_array); - } - g_ptr_array_free(gp_array, TRUE); + gp_array = g_ptr_array_new(); + while (g_variant_iter_loop(char_iter, "&o", &char_handle)) + g_ptr_array_add(gp_array, (gpointer)char_handle); + + if (gp_array->len != 0) { + svc_char.handle_info.count = gp_array->len; + svc_char.handle_info.handle = + __get_string_array_from_gptr_array(gp_array); } + g_ptr_array_free(gp_array, TRUE); if (user_info) { _bt_common_event_cb(BLUETOOTH_EVENT_GATT_SVC_CHAR_DISCOVERED, @@ -421,6 +513,7 @@ static void __bluetooth_internal_get_char_cb(GDBusProxy *proxy, g_strfreev(svc_char.handle_info.handle); g_free(svc_char.service_handle); g_variant_iter_free(char_iter); + g_variant_unref(value); g_object_unref(proxy); } @@ -471,31 +564,71 @@ static int __get_permission_flag(char *permission) retv_if(permission == NULL, ret); - BT_DBG("permission = %s",permission); - - if (!g_strcmp0(permission,"broadcast")) { + if (!g_strcmp0(permission, "broadcast")) ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_BROADCAST; - } else if (!g_strcmp0(permission,"read")) { + else if (!g_strcmp0(permission, "read")) ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ; - } else if (!g_strcmp0(permission,"write-without-response")) { + else if (!g_strcmp0(permission, "write-without-response")) ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE; - } else if (!g_strcmp0(permission,"write")) { + else if (!g_strcmp0(permission, "write")) ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE; - } else if (!g_strcmp0(permission,"notify")) { + else if (!g_strcmp0(permission, "notify")) ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY; - } else if (!g_strcmp0(permission,"indicate")) { + else if (!g_strcmp0(permission, "indicate")) ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE; - } else if (!g_strcmp0(permission,"authenticated-signed-writes")) { + else if (!g_strcmp0(permission, "authenticated-signed-writes")) ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE; - } else if (!g_strcmp0(permission,"reliable-write")) { - ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_EXTENDED_PROPS; - } else if (!g_strcmp0(permission,"writable-auxiliaries")) { - ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_EXTENDED_PROPS; - } + else if (!g_strcmp0(permission, "reliable-write")) + ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE; + else if (!g_strcmp0(permission, "writable-auxiliaries")) + ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES; + else if (!g_strcmp0(permission, "encrypt-read")) + ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ; + else if (!g_strcmp0(permission, "encrypt-write")) + ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE; + else if (!g_strcmp0(permission, "encrypt-authenticated-read")) + ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ; + else if (!g_strcmp0(permission, "encrypt-authenticated-write")) + ret = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE; return ret; } +static void __convert_permission_flag_to_str(unsigned int permission) +{ + char perm[200] = { 0, }; + + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_BROADCAST) + g_strlcat(perm, "broadcast ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ) + g_strlcat(perm, "read ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE) + g_strlcat(perm, "write-without-response ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE) + g_strlcat(perm, "write ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY) + g_strlcat(perm, "notify ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_INDICATE) + g_strlcat(perm, "indicate ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE) + g_strlcat(perm, "authenticated-signed-writes ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE) + g_strlcat(perm, "reliable-write ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES) + g_strlcat(perm, "writable-auxiliaries ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ) + g_strlcat(perm, "encrypt-read ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE) + g_strlcat(perm, "encrypt-write ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ) + g_strlcat(perm, "encrypt-authenticated-read ", sizeof(perm)); + if (permission & BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE) + g_strlcat(perm, "encrypt-authenticated-write ", sizeof(perm)); + + BT_INFO("permission [0x%04x] : %s\n", permission, perm); + return; +} + BT_EXPORT_API int bluetooth_gatt_get_characteristics_property( const char *char_handle, bt_gatt_char_property_t *characteristic) { @@ -510,13 +643,12 @@ BT_EXPORT_API int bluetooth_gatt_get_characteristics_property( const gchar *key; gchar* permission; char *char_desc_handle = NULL; - int len; + gsize len; GVariantIter *property_iter; GVariantIter *char_value_iter; GVariantIter *char_perm_iter; GVariantIter *char_desc_iter; - BT_DBG("+"); BT_CHECK_PARAMETER(char_handle, return); BT_CHECK_PARAMETER(characteristic, return); @@ -558,17 +690,21 @@ BT_EXPORT_API int bluetooth_gatt_get_characteristics_property( characteristic->handle = g_strdup(char_handle); while (g_variant_iter_loop(property_iter, "{sv}", &key, &value)) { - BT_DBG("property"); - if (!g_strcmp0(key,"UUID")) { - characteristic->uuid = g_variant_dup_string(value,&len); - BT_DBG("UUID of the char = %s",characteristic->uuid); - } else if(!g_strcmp0(key, "Value")) { + if (!g_strcmp0(key, "UUID")) { + char *name = NULL; + characteristic->uuid = g_variant_dup_string(value, &len); + bluetooth_get_uuid_name(characteristic->uuid, &name); + BT_INFO("%s %s [%s]", char_handle + 37, characteristic->uuid, name); + g_free(name); + } else if (!g_strcmp0(key, "Value")) { gb_array = g_byte_array_new(); g_variant_get(value, "ay", &char_value_iter); - while(g_variant_iter_loop(char_value_iter, "y", &char_value)) { - BT_DBG("value of char = %d",char_value); + while (g_variant_iter_loop(char_value_iter, "y", &char_value)) { + // BT_DBG("value of char = %d",char_value); g_byte_array_append(gb_array, &char_value, 1); } + g_variant_iter_free(char_value_iter); + if (gb_array->len != 0) { characteristic->val = g_malloc0(gb_array->len * sizeof(unsigned char)); @@ -576,21 +712,22 @@ BT_EXPORT_API int bluetooth_gatt_get_characteristics_property( } characteristic->val_len = gb_array->len; g_byte_array_free(gb_array, TRUE); - } else if(!g_strcmp0(key, "Flags")) { + } else if (!g_strcmp0(key, "Flags")) { g_variant_get(value, "as", &char_perm_iter); characteristic->permission = 0x00; - while (g_variant_iter_loop(char_perm_iter, "s", &permission)) { - BT_DBG("permission = %s",permission); + + while (g_variant_iter_loop(char_perm_iter, "s", &permission)) characteristic->permission |= __get_permission_flag(permission); - BT_DBG("permission check = %d",characteristic->permission); - } + __convert_permission_flag_to_str(characteristic->permission); + g_variant_iter_free(char_perm_iter); } else if (!g_strcmp0(key, "Descriptors")) { g_variant_get(value, "ao", &char_desc_iter); gp_array = g_ptr_array_new(); - while (g_variant_iter_loop(char_desc_iter, "&o", &char_desc_handle)) { + while (g_variant_iter_loop(char_desc_iter, "&o", &char_desc_handle)) g_ptr_array_add(gp_array, (gpointer)char_desc_handle); - } + + g_variant_iter_free(char_desc_iter); if (gp_array->len != 0) { characteristic->char_desc_handle.count = gp_array->len; characteristic->char_desc_handle.handle = @@ -604,7 +741,6 @@ BT_EXPORT_API int bluetooth_gatt_get_characteristics_property( g_variant_unref(result); g_object_unref(properties_proxy); - BT_DBG("-"); return BLUETOOTH_ERROR_NONE; } @@ -613,7 +749,6 @@ void bluetooth_gatt_get_char_from_uuid_cb(GDBusProxy *proxy, { GVariant *value; GVariantIter *char_iter; - int i, len; char *char_handle; GError *error = NULL; bt_user_info_t *user_info; @@ -644,10 +779,7 @@ void bluetooth_gatt_get_char_from_uuid_cb(GDBusProxy *proxy, g_variant_get(value, "(ao)", &char_iter); - len = g_variant_get_size(char_iter); - - for (i = 0; i < len; i++) { - g_variant_iter_loop(char_iter, "o", &char_handle); + while (g_variant_iter_loop(char_iter, "&o", &char_handle)) { if (!char_handle) continue; ret = bluetooth_gatt_get_characteristics_property(char_handle, @@ -671,6 +803,7 @@ void bluetooth_gatt_get_char_from_uuid_cb(GDBusProxy *proxy, bluetooth_gatt_free_char_property(&characteristic); g_variant_iter_free(char_iter); + g_variant_unref(value); g_free(user_data); } @@ -722,12 +855,11 @@ BT_EXPORT_API int bluetooth_gatt_get_char_descriptor_property( GVariantIter *property_iter; const gchar *key; guint8 char_value; - int len; + gsize len; GVariant *value = NULL; GByteArray *gb_array = NULL; GVariantIter *desc_value_iter; - BT_DBG("+"); BT_CHECK_PARAMETER(descriptor_handle, return); BT_CHECK_PARAMETER(descriptor, return); @@ -769,17 +901,21 @@ BT_EXPORT_API int bluetooth_gatt_get_char_descriptor_property( descriptor->handle = g_strdup(descriptor_handle); while (g_variant_iter_loop(property_iter, "{sv}", &key, &value)) { - BT_DBG("property"); - if (!g_strcmp0(key,"UUID")) { - descriptor->uuid = g_variant_dup_string(value,&len); - BT_DBG("UUID of the char_desc = %s",descriptor->uuid); - } else if(!g_strcmp0(key, "Value")) { + if (!g_strcmp0(key, "UUID")) { + char *name = NULL; + descriptor->uuid = g_variant_dup_string(value, &len); + bluetooth_get_uuid_name(descriptor->uuid, &name); + BT_INFO("Descriptor : %s [%s]", descriptor->uuid, name); + g_free(name); + } else if (!g_strcmp0(key, "Value")) { gb_array = g_byte_array_new(); g_variant_get(value, "ay", &desc_value_iter); - while(g_variant_iter_loop(desc_value_iter, "y", &char_value)) { - BT_DBG("value of descriptor = %d",char_value); + while (g_variant_iter_loop(desc_value_iter, "y", &char_value)) { + BT_DBG("value of descriptor = %d", char_value); g_byte_array_append(gb_array, &char_value, 1); } + g_variant_iter_free(desc_value_iter); + if (gb_array->len != 0) { descriptor->val = g_malloc0(gb_array->len * sizeof(unsigned char)); @@ -794,105 +930,215 @@ BT_EXPORT_API int bluetooth_gatt_get_char_descriptor_property( g_variant_unref(result); g_object_unref(properties_proxy); - BT_DBG("-"); return BLUETOOTH_ERROR_NONE; } +static int __bluetooth_get_att_error_code(GError *error, char *handle) +{ + int att_ecode = 0; + int len; + char *str = NULL; + + BT_ERR("Error : %s [%s]", error->message, handle + 15); + str = g_strrstr(error->message, "ATT error: 0x"); + if (str) { + len = strlen(str); + att_ecode = g_ascii_xdigit_value(str[len - 2]) << 4; + att_ecode += g_ascii_xdigit_value(str[len - 1]); + } else + return BLUETOOTH_ATT_ERROR_INTERNAL; + + switch (att_ecode) { + case BLUETOOTH_ATT_ERROR_READ_NOT_PERMITTED: + BT_ERR("Read not permitted"); + break; + case BLUETOOTH_ATT_ERROR_WRITE_NOT_PERMITTED: + BT_ERR("Write not permitted"); + break; + case BLUETOOTH_ATT_ERROR_AUTHENTICATION: + case BLUETOOTH_ATT_ERROR_INSUFFICIENT_ENCRYPTION: + case BLUETOOTH_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE: + BT_ERR("Not paired"); + break; + case BLUETOOTH_ATT_ERROR_INVALID_OFFSET: + BT_ERR("Invalid offset"); + break; + case BLUETOOTH_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN: + BT_ERR("Invalid Length"); + break; + case BLUETOOTH_ATT_ERROR_AUTHORIZATION: + BT_ERR("Operation not Authorized"); + break; + default: + BT_ERR("default ecode"); + break; + } + + if (att_ecode >= 0x80 && att_ecode <= 0x9F) + BT_ERR("Application error"); + + return att_ecode; +} + static void __bluetooth_internal_read_cb(GObject *source_object, - GAsyncResult *res, - gpointer user_data) + GAsyncResult *res, gpointer user_data) { GError *error = NULL; - bt_user_info_t *user_info; - bt_gatt_char_value_t char_value = { 0, }; GDBusConnection *system_gconn = NULL; GVariant *value; - GByteArray *gp_byte_array = NULL; + bt_user_info_t *user_info; GVariantIter *iter; + GByteArray *gp_byte_array = NULL; guint8 g_byte; + int att_ecode = 0; + bt_gatt_resp_data_t *resp_data = user_data; BT_DBG("+"); - user_info = _bt_get_user_data(BT_COMMON); system_gconn = _bt_gdbus_get_system_gconn(); value = g_dbus_connection_call_finish(system_gconn, res, &error); + user_info = _bt_get_user_data(BT_COMMON); + if (!user_info) { + if (error) { + BT_ERR("Error : %s [%s]", error->message, resp_data->handle + 15); + g_clear_error(&error); + g_free(resp_data); + return; + } + g_free(resp_data); + g_variant_unref(value); + return; + } + if (error) { - BT_ERR("Error : %s \n", error->message); + att_ecode = __bluetooth_get_att_error_code(error, resp_data->handle); g_clear_error(&error); - if (user_info) { - _bt_common_event_cb(BLUETOOTH_EVENT_GATT_READ_CHAR, - BLUETOOTH_ERROR_INTERNAL, NULL, - user_info->cb, user_info->user_data); - } - g_free(user_data); + + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_READ_CHAR, + att_ecode, resp_data, + user_info->cb, user_info->user_data); + g_free(resp_data); return; } - char_value.char_handle = user_data; gp_byte_array = g_byte_array_new(); g_variant_get(value, "(ay)", &iter); - while (g_variant_iter_loop(iter, "y", &g_byte)) { + while (g_variant_iter_loop(iter, "y", &g_byte)) g_byte_array_append(gp_byte_array, &g_byte, 1); - } if (gp_byte_array->len != 0) { - char_value.val_len = gp_byte_array->len; - char_value.char_value = gp_byte_array->data; + resp_data->len = gp_byte_array->len; + resp_data->value = gp_byte_array->data; } - if (user_info) { - _bt_common_event_cb(BLUETOOTH_EVENT_GATT_READ_CHAR, - BLUETOOTH_ERROR_NONE, &char_value, - user_info->cb, user_info->user_data); - } + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_READ_CHAR, + BLUETOOTH_ATT_ERROR_NONE, resp_data, + user_info->cb, user_info->user_data); + g_free(resp_data); - g_free(char_value.char_handle); g_byte_array_free(gp_byte_array, TRUE); - g_variant_unref(value); g_variant_iter_free(iter); + g_variant_unref(value); BT_DBG("-"); } -BT_EXPORT_API int bluetooth_gatt_read_characteristic_value(const char *characteristic) +BT_EXPORT_API int bluetooth_gatt_read_characteristic_value(const char *chr, + gpointer user_data) { GDBusConnection *conn; - char *handle; + bt_gatt_resp_data_t *resp_data; + GVariantBuilder *builder = NULL; + guint16 offset = 0; - BT_CHECK_PARAMETER(characteristic, return); + BT_CHECK_PARAMETER(chr, return); BT_CHECK_ENABLED(return); conn = _bt_gdbus_get_system_gconn(); retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); - handle = g_strdup(characteristic); + resp_data = g_malloc0(sizeof(bt_gatt_resp_data_t)); + resp_data->user_data = user_data; + resp_data->handle = (char *)chr; - g_dbus_connection_call(conn, - BT_BLUEZ_NAME, - characteristic, - GATT_CHAR_INTERFACE, - "ReadValue", - NULL, - G_VARIANT_TYPE("(ay)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, + builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + + /*offset*/ + g_variant_builder_add(builder, "{sv}", "offset", + g_variant_new("q", offset)); + + /* Device Object path*/ +// g_variant_builder_add(builder, "{sv}", "device", +// g_variant_new_object("o", NULL)); + + g_dbus_connection_call(conn, BT_BLUEZ_NAME, chr, GATT_CHAR_INTERFACE, + "ReadValue", g_variant_new("(a{sv})", builder), + G_VARIANT_TYPE("(ay)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, (GAsyncReadyCallback)__bluetooth_internal_read_cb, - (gpointer)handle); + (gpointer)resp_data); + g_variant_builder_unref(builder); return BLUETOOTH_ERROR_NONE; } +static void __bluetooth_internal_write_cb(GObject *source_object, + GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + GDBusConnection *system_gconn = NULL; + bt_user_info_t *user_info; + GVariant *value; + int att_ecode = 0; + bt_gatt_resp_data_t *resp_data = user_data; + + system_gconn = _bt_gdbus_get_system_gconn(); + value = g_dbus_connection_call_finish(system_gconn, res, &error); + + user_info = _bt_get_user_data(BT_COMMON); + if (!user_info) { + if (error) { + BT_ERR("Error : %s [%s]", error->message, resp_data->handle + 15); + g_clear_error(&error); + g_free(resp_data); + return; + } + g_free(resp_data); + g_variant_unref(value); + return; + } + + if (error) { + att_ecode = __bluetooth_get_att_error_code(error, resp_data->handle); + g_clear_error(&error); + + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_WRITE_CHAR, + att_ecode, resp_data, + user_info->cb, user_info->user_data); + g_free(resp_data); + return; + } + + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_WRITE_CHAR, + BLUETOOTH_ATT_ERROR_NONE, resp_data, + user_info->cb, user_info->user_data); + g_free(resp_data); + + g_variant_unref(value); + return; +} + BT_EXPORT_API int bluetooth_gatt_set_characteristics_value( const char *char_handle, const guint8 *value, int length) { - GVariant *val; - GVariantBuilder *builder; + GVariant *val, *options; + GVariantBuilder *builder1; + GVariantBuilder *builder2; GError *error = NULL; GDBusConnection *conn; int i = 0; + guint16 offset = 0; BT_DBG("+"); BT_CHECK_PARAMETER(char_handle, return); @@ -903,77 +1149,115 @@ BT_EXPORT_API int bluetooth_gatt_set_characteristics_value( conn = _bt_gdbus_get_system_gconn(); retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); - builder = g_variant_builder_new(G_VARIANT_TYPE("ay")); + builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay")); + for (i = 0; i < length; i++) + g_variant_builder_add(builder1, "y", value[i]); - for (i = 0; i < length; i++) { - g_variant_builder_add(builder, "y", value[i]); - } + val = g_variant_new("ay", builder1); - val = g_variant_new("(ay)", builder); + builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + /*offset*/ + g_variant_builder_add(builder2, "{sv}", "offset", + g_variant_new_uint16(offset)); + + /* Device Object path*/ +// g_variant_builder_add(builder2, "{sv}", "device", +// g_variant_new_object("o", NULL)); + + options = g_variant_new("a{sv}", builder2); + + g_dbus_connection_call(conn, + BT_BLUEZ_NAME, + char_handle, + GATT_CHAR_INTERFACE, + "WriteValue", + g_variant_new("(@ay@a{sv})", + val, options), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, + (GAsyncReadyCallback)__bluetooth_internal_write_cb, + NULL); - g_dbus_connection_call_sync(conn, - BT_BLUEZ_NAME, - char_handle, - GATT_CHAR_INTERFACE, - "WriteValue", - val, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, &error); if (error) { BT_ERR("Set value Failed: %s", error->message); g_clear_error(&error); - g_variant_builder_unref(builder); + g_variant_builder_unref(builder1); return BLUETOOTH_ERROR_INTERNAL; } - - g_variant_builder_unref(builder); + g_variant_builder_unref(builder1); + g_variant_builder_unref(builder2); BT_DBG("-"); return BLUETOOTH_ERROR_NONE; } -static void __bluetooth_internal_write_cb(GObject *source_object, - GAsyncResult *res, - gpointer user_data) +BT_EXPORT_API int bluetooth_gatt_set_characteristics_value_by_type( + const char *chr, const guint8 *value, int length, + guint8 write_type, gpointer user_data) { - BT_DBG("+"); - GError *error = NULL; - bt_user_info_t *user_info; - GDBusConnection *system_gconn = NULL; - GVariant *value; - int result = BLUETOOTH_ERROR_NONE; + GVariant *val, *options; + GVariantBuilder *builder1; + GVariantBuilder *builder2; + GDBusConnection *conn; + guint16 offset = 0; + int i = 0; + int ret = BLUETOOTH_ERROR_NONE; + bt_gatt_resp_data_t *resp_data; - user_info = _bt_get_user_data(BT_COMMON); + BT_CHECK_PARAMETER(chr, return); + BT_CHECK_PARAMETER(value, return); + retv_if(length == 0, BLUETOOTH_ERROR_INVALID_PARAM); + BT_CHECK_ENABLED_INTERNAL(return); - system_gconn = _bt_gdbus_get_system_gconn(); - value = g_dbus_connection_call_finish(system_gconn, res, &error); + conn = _bt_gdbus_get_system_gconn(); + retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); - if (error) { - BT_ERR("Error : %s \n", error->message); - g_clear_error(&error); - result = BLUETOOTH_ERROR_INTERNAL; - } - if (user_info) { - BT_DBG("result = %d", result); - _bt_common_event_cb(BLUETOOTH_EVENT_GATT_WRITE_CHAR, - result, NULL, - user_info->cb, user_info->user_data); - } + builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay")); - if (value) - g_variant_unref(value); - BT_DBG("-"); - return; + 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)); + + /* Device Object path*/ +// g_variant_builder_add(builder2, "{sv}", "device", +// g_variant_new_object("o", NULL)); + + options = g_variant_new("a{sv}", builder2); + + resp_data = g_malloc0(sizeof(bt_gatt_resp_data_t)); + resp_data->user_data = user_data; + resp_data->handle = (char *)chr; + + g_dbus_connection_call(conn, BT_BLUEZ_NAME, chr, GATT_CHAR_INTERFACE, + "WriteValuebyType", + g_variant_new("(y@ay@a{sv})", write_type, val, options), + NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, + (GAsyncReadyCallback)__bluetooth_internal_write_cb, + (gpointer)resp_data); + + g_variant_builder_unref(builder1); + g_variant_builder_unref(builder2); + + return ret; } BT_EXPORT_API int bluetooth_gatt_set_characteristics_value_request( const char *char_handle, const guint8 *value, int length) { - GVariant *val; + GVariant *val, *options; GDBusConnection *conn; - GVariantBuilder *builder; + GVariantBuilder *builder1; + GVariantBuilder *builder2; + guint offset = 0; int i; BT_DBG("+"); @@ -985,28 +1269,41 @@ BT_EXPORT_API int bluetooth_gatt_set_characteristics_value_request( conn = _bt_gdbus_get_system_gconn(); retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); - builder = g_variant_builder_new(G_VARIANT_TYPE("ay")); + builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay")); for (i = 0; i < length; i++) { - g_variant_builder_add(builder, "y", value[i]); + g_variant_builder_add(builder1, "y", value[i]); BT_DBG("value [] = %d", value[i]); } - val = g_variant_new("(ay)", builder); + 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)); + + /* Device Object path*/ +// g_variant_builder_add(builder2, "{sv}", "device", +// g_variant_new_object("o", NULL)); + + options = g_variant_new("a{sv}", builder2); g_dbus_connection_call(conn, BT_BLUEZ_NAME, char_handle, GATT_CHAR_INTERFACE, "WriteValue", - val, + g_variant_new("(@ay@a{sv})", + val, options), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, (GAsyncReadyCallback)__bluetooth_internal_write_cb, NULL); - g_variant_builder_unref(builder); + g_variant_builder_unref(builder1); + g_variant_builder_unref(builder2); BT_DBG("-"); return BLUETOOTH_ERROR_NONE; @@ -1022,8 +1319,8 @@ static int __bluetooth_gatt_descriptor_iter(const char *char_handle, GVariant *result = NULL; GDBusConnection *g_conn; int i, ret = BLUETOOTH_ERROR_NONE; - char *uuid = NULL; - int len = 0; + const char *uuid = NULL; + gsize len = 0; GVariantIter *desc_value_iter, *property_iter; const gchar *key; char_descriptor_type_t desc_type = TYPE_NONE; @@ -1059,7 +1356,7 @@ static int __bluetooth_gatt_descriptor_iter(const char *char_handle, } g_variant_get(result, "(a{sv})", &property_iter); while (g_variant_iter_loop(property_iter, "{sv}", &key, &value)) { - if (!g_strcmp0(key,"UUID")) { + if (!g_strcmp0(key, "UUID")) { uuid = g_variant_get_string(value, &len); if (g_strcmp0(uuid, GATT_USER_DESC_UUID) == 0) { BT_DBG("GATT_USER_DESC_UUID"); @@ -1077,45 +1374,43 @@ static int __bluetooth_gatt_descriptor_iter(const char *char_handle, BT_DBG("descriptor uuid = %s", uuid); } } else if (!g_strcmp0(key, "Value")) { - switch(desc_type) { - case CHAR_FORMAT : - BT_DBG("Format descriptor"); - g_variant_get(value, "(yyqyq)", - &(characteristic->format.format), - &(characteristic->format.exponent), - &(characteristic->format.unit), - &(characteristic->format.name_space), - &(characteristic->format.description)); - break; - case USER_DESC: - BT_DBG("User descriptor"); - g_variant_get(value, "ay", &desc_value_iter); - len = g_variant_get_size(desc_value_iter); - - if (len > 0) { - characteristic->description = (guint8 *)g_malloc0(len + 1); - if (!characteristic->description) { - ret = BLUETOOTH_ERROR_OUT_OF_MEMORY; - goto done; - } - } - for (i = 0; i < len; i++) { - g_variant_iter_loop(desc_value_iter, "y", - &characteristic->description[i]); - BT_DBG("description = %s", characteristic->description); - } - break; - case CLIENT_CONF : - BT_DBG(" CLIENT_CONF"); - break; - case SERVER_CONF : - BT_DBG(" SERVER_CONF"); - break; + switch (desc_type) { + case CHAR_FORMAT: + BT_DBG("Format descriptor"); + g_variant_get(value, "(yyqyq)", + &(characteristic->format.format), + &(characteristic->format.exponent), + &(characteristic->format.unit), + &(characteristic->format.name_space), + &(characteristic->format.description)); + break; + case USER_DESC: + BT_DBG("User descriptor"); + g_variant_get(value, "ay", &desc_value_iter); + len = g_variant_get_size((GVariant *)desc_value_iter); + + if (len > 0) + characteristic->description = (char *)g_malloc0(len + 1); + + for (i = 0; i < len; i++) { + g_variant_iter_loop(desc_value_iter, "y", + &characteristic->description[i]); + BT_DBG("description = %s", characteristic->description); + } + g_variant_iter_free(desc_value_iter); + break; + case CLIENT_CONF: + BT_DBG(" CLIENT_CONF"); + break; + case SERVER_CONF: + BT_DBG(" SERVER_CONF"); + break; + default: + break; } } } -done: g_variant_iter_free(property_iter); g_variant_unref(result); g_object_unref(properties_proxy); @@ -1132,7 +1427,6 @@ static void bluetooth_gatt_get_char_desc_cb(GDBusProxy *proxy, GVariant *value; GVariant *char_value; GVariantIter *char_iter; - int i; char *char_handle; GError *error = NULL; bt_user_info_t *user_info; @@ -1142,6 +1436,7 @@ static void bluetooth_gatt_get_char_desc_cb(GDBusProxy *proxy, user_info = _bt_get_user_data(BT_COMMON); value = g_dbus_proxy_call_finish(proxy, res, &error); + characteristic.handle = user_data; if (value == NULL) { if (error != NULL) { @@ -1156,7 +1451,7 @@ static void bluetooth_gatt_get_char_desc_cb(GDBusProxy *proxy, BLUETOOTH_ERROR_INTERNAL, NULL, user_info->cb, user_info->user_data); } - g_free(user_data); + g_free(characteristic.handle); g_object_unref(proxy); return; } @@ -1164,20 +1459,15 @@ static void bluetooth_gatt_get_char_desc_cb(GDBusProxy *proxy, g_variant_get(value, "(v)", &char_value); g_variant_get(char_value, "ao", &char_iter); - int len = g_variant_get_size(char_iter); - if (len > 0) { - for (i = 0; i < len; i++) { - g_variant_iter_loop(char_iter, "o", &char_handle); - BT_DBG("object path of descriptor = %s",char_handle); - if(char_handle) { - ret = __bluetooth_gatt_descriptor_iter(char_handle, - &characteristic); - BT_DBG("Descriptor read status [%d]",ret); - } + while (g_variant_iter_loop(char_iter, "&o", &char_handle)) { + BT_DBG("object path of descriptor = %s", char_handle); + if (char_handle) { + ret = __bluetooth_gatt_descriptor_iter(char_handle, + &characteristic); + BT_DBG("Descriptor read status [%d]", ret); } } - characteristic.handle = user_data; if (user_info) { _bt_common_event_cb(BLUETOOTH_EVENT_GATT_SVC_CHAR_DESC_DISCOVERED, ret, &characteristic, user_info->cb, user_info->user_data); @@ -1185,6 +1475,7 @@ static void bluetooth_gatt_get_char_desc_cb(GDBusProxy *proxy, bluetooth_gatt_free_char_property(&characteristic); g_variant_iter_free(char_iter); + g_variant_unref(value); BT_DBG("-"); } @@ -1229,133 +1520,171 @@ static void __bluetooth_internal_read_desc_cb(GObject *source_object, gpointer user_data) { GError *error = NULL; - bt_user_info_t *user_info; - bt_gatt_char_property_t char_value = { 0, }; GDBusConnection *system_gconn = NULL; GVariant *value; + bt_user_info_t *user_info; GByteArray *gp_byte_array = NULL; GVariantIter *iter; guint8 g_byte; + int att_ecode = 0; + bt_gatt_resp_data_t *resp_data = user_data; BT_DBG("+"); - user_info = _bt_get_user_data(BT_COMMON); - system_gconn = _bt_gdbus_get_system_gconn(); - char_value.handle = user_data; + system_gconn = _bt_gdbus_get_system_gconn(); value = g_dbus_connection_call_finish(system_gconn, res, &error); - if (error) { - BT_ERR("Error : %s \n", error->message); - g_clear_error(&error); - if (user_info) { - _bt_common_event_cb(BLUETOOTH_EVENT_GATT_READ_DESC, - BLUETOOTH_ERROR_INTERNAL, NULL, - user_info->cb, user_info->user_data); + user_info = _bt_get_user_data(BT_COMMON); + if (!user_info) { + if (error) { + BT_ERR("Error : %s [%s]", error->message, resp_data->handle + 15); + g_clear_error(&error); + g_free(resp_data); + return; } - g_free(char_value.handle); + g_free(resp_data); + g_variant_unref(value); 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); + if (error) { + att_ecode = __bluetooth_get_att_error_code(error, resp_data->handle); + g_clear_error(&error); + + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_READ_DESC, + att_ecode, resp_data, + user_info->cb, user_info->user_data); + 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); + if (gp_byte_array->len != 0) { - char_value.val_len = gp_byte_array->len; - char_value.description= gp_byte_array->data; + resp_data->len = gp_byte_array->len; + resp_data->value = gp_byte_array->data; } - if (user_info) { - _bt_common_event_cb(BLUETOOTH_EVENT_GATT_READ_DESC, - BLUETOOTH_ERROR_NONE, &char_value, - user_info->cb, user_info->user_data); - } + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_READ_DESC, + BLUETOOTH_ATT_ERROR_NONE, resp_data, + user_info->cb, user_info->user_data); + g_free(resp_data); + g_byte_array_free(gp_byte_array, TRUE); - g_free(char_value.handle); - g_variant_unref(value); g_variant_iter_free(iter); + g_variant_unref(value); BT_DBG("-"); } -BT_EXPORT_API int bluetooth_gatt_read_descriptor_value(const char *char_descriptor) +BT_EXPORT_API int bluetooth_gatt_read_descriptor_value(const char *desc, + gpointer user_data) { GDBusConnection *conn; - char *handle; + GVariantBuilder *builder; + guint offset = 0; + bt_gatt_resp_data_t *resp_data; BT_DBG("+"); - BT_CHECK_PARAMETER(char_descriptor, return); + + BT_CHECK_PARAMETER(desc, return); BT_CHECK_ENABLED(return); conn = _bt_gdbus_get_system_gconn(); retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); - handle = g_strdup(char_descriptor); + resp_data = g_malloc0(sizeof(bt_gatt_resp_data_t)); + resp_data->user_data = user_data; + resp_data->handle = (char *)desc; - g_dbus_connection_call(conn, - BT_BLUEZ_NAME, - char_descriptor, - GATT_DESC_INTERFACE, - "ReadValue", - NULL, + builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + + /*offset*/ + g_variant_builder_add(builder, "{sv}", "offset", + g_variant_new("q", offset)); + /* Device Object path*/ +// g_variant_builder_add(builder, "{sv}", "device", +// g_variant_new("o", serv_info->serv_path)); + + g_dbus_connection_call(conn, BT_BLUEZ_NAME, desc, GATT_DESC_INTERFACE, + "ReadValue", g_variant_new("(a{sv})", builder), G_VARIANT_TYPE("(ay)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, (GAsyncReadyCallback)__bluetooth_internal_read_desc_cb, - (gpointer)handle); + (gpointer)resp_data); + g_variant_builder_unref(builder); BT_DBG("-"); return BLUETOOTH_ERROR_NONE; } static void __bluetooth_internal_write_desc_cb(GObject *source_object, - GAsyncResult *res, - gpointer user_data) + GAsyncResult *res, gpointer user_data) { GError *error = NULL; bt_user_info_t *user_info; GDBusConnection *system_gconn = NULL; GVariant *value; - int result = BLUETOOTH_ERROR_NONE; + int att_ecode = BLUETOOTH_ATT_ERROR_NONE; + bt_gatt_resp_data_t *resp_data = user_data; BT_DBG("+"); - user_info = _bt_get_user_data(BT_COMMON); system_gconn = _bt_gdbus_get_system_gconn(); value = g_dbus_connection_call_finish(system_gconn, res, &error); + user_info = _bt_get_user_data(BT_COMMON); + if (!user_info) { + if (error) { + BT_ERR("Error : %s [%s]", error->message, resp_data->handle + 15); + g_clear_error(&error); + g_free(resp_data); + return; + } + g_free(resp_data); + g_variant_unref(value); + return; + } + if (error) { - BT_ERR("Error : %s \n", error->message); + att_ecode = __bluetooth_get_att_error_code(error, resp_data->handle); g_clear_error(&error); - result = BLUETOOTH_ERROR_INTERNAL; - } - if (user_info) { + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_WRITE_DESC, - result, NULL, + att_ecode, resp_data, user_info->cb, user_info->user_data); + g_free(resp_data); + return; } - if(value) - g_variant_unref(value); + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_WRITE_DESC, + BLUETOOTH_ATT_ERROR_NONE, resp_data, + user_info->cb, user_info->user_data); + g_free(resp_data); + g_variant_unref(value); BT_DBG("-"); } -BT_EXPORT_API int bluetooth_gatt_write_descriptor_value( - const char *desc_handle, const guint8 *value, int length) +BT_EXPORT_API int bluetooth_gatt_write_descriptor_value(const char *desc, + const guint8 *value, int length, gpointer user_data) { - GVariant *val; + GVariant *val, *options; GDBusConnection *conn; - GVariantBuilder *builder; + GVariantBuilder *builder1; + GVariantBuilder *builder2; + guint offset = 0; int i; + bt_gatt_resp_data_t *resp_data; BT_DBG("+"); - BT_CHECK_PARAMETER(desc_handle, return); + + BT_CHECK_PARAMETER(desc, return); BT_CHECK_PARAMETER(value, return); retv_if(length == 0, BLUETOOTH_ERROR_INVALID_PARAM); BT_CHECK_ENABLED(return); @@ -1363,46 +1692,52 @@ BT_EXPORT_API int bluetooth_gatt_write_descriptor_value( conn = _bt_gdbus_get_system_gconn(); retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); - builder = g_variant_builder_new(G_VARIANT_TYPE("ay")); + builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay")); - for (i = 0; i < length; i++) { - g_variant_builder_add(builder, "y", value[i]); - } + for (i = 0; i < length; i++) + g_variant_builder_add(builder1, "y", value[i]); - val = g_variant_new("(ay)", builder); + val = g_variant_new("ay", builder1); - g_dbus_connection_call(conn, - BT_BLUEZ_NAME, - desc_handle, - GATT_DESC_INTERFACE, - "WriteValue", - val, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, - (GAsyncReadyCallback)__bluetooth_internal_write_desc_cb, - NULL); + builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + /*offset*/ + g_variant_builder_add(builder2, "{sv}", "offset", + g_variant_new_uint16(offset)); - g_variant_builder_unref(builder); + /* Device Object path*/ +// g_variant_builder_add(builder2, "{sv}", "device", +// g_variant_new_object("o", NULL)); + + options = g_variant_new("a{sv}", builder2); + + resp_data = g_malloc0(sizeof(bt_gatt_resp_data_t)); + resp_data->user_data = user_data; + resp_data->handle = (char *)desc; + + g_dbus_connection_call(conn, BT_BLUEZ_NAME, desc, GATT_DESC_INTERFACE, + "WriteValue", g_variant_new("(@ay@a{sv})", + val, options), NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, + (GAsyncReadyCallback)__bluetooth_internal_write_desc_cb, + (gpointer)resp_data); + + g_variant_builder_unref(builder1); + g_variant_builder_unref(builder2); BT_DBG("-"); return BLUETOOTH_ERROR_NONE; } -BT_EXPORT_API int bluetooth_gatt_watch_characteristics(const char *char_handle) +BT_EXPORT_API int bluetooth_gatt_watch_characteristics(const char *char_handle, const char *svc_name) { - GDBusConnection *conn; GError *error = NULL; int ret = BLUETOOTH_ERROR_NONE; - BT_DBG("+"); -/* Implementation in Bluez is not complete */ -#if 0 - BT_CHECK_PARAMETER(char_handle, return); + BT_CHECK_PARAMETER(char_handle, return); BT_CHECK_ENABLED(return); - BT_DBG("Entered characteristic handle:%s \n ", char_handle); + BT_INFO_C("### Enable CCCD : %s [%s]", char_handle + 15, svc_name); conn = _bt_gdbus_get_system_gconn(); retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); @@ -1415,32 +1750,44 @@ BT_EXPORT_API int bluetooth_gatt_watch_characteristics(const char *char_handle) NULL, NULL, G_DBUS_CALL_FLAGS_NONE, - -1, NULL, &error); + GATT_DEFAULT_TIMEOUT, NULL, &error); if (error) { - BT_ERR("Watch Failed: %s", error->message); + g_dbus_error_strip_remote_error(error); + BT_ERR_C("### Watch Failed: %s", error->message); + if (g_strrstr(error->message, "Already notifying")) + ret = BLUETOOTH_ERROR_NONE; + else if (g_strrstr(error->message, "In Progress")) + ret = BLUETOOTH_ERROR_IN_PROGRESS; + else if (g_strrstr(error->message, "Operation is not supported")) + ret = BLUETOOTH_ERROR_NOT_SUPPORT; +/*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")) + ret = BLUETOOTH_ERROR_PERMISSION_DEINED; +/* failed because of either Insufficient Authentication, + Insufficient Encryption Key Size, or Insufficient Encryption. */ + else if (g_strrstr(error->message, "Not paired")) + ret = BLUETOOTH_ERROR_NOT_PAIRED; + else + ret = BLUETOOTH_ERROR_INTERNAL; + g_clear_error(&error); - ret = BLUETOOTH_ERROR_INTERNAL; } -#endif - BT_DBG("-"); + return ret; } -BT_EXPORT_API int bluetooth_gatt_unwatch_characteristics(const char *service_handle) +BT_EXPORT_API int bluetooth_gatt_unwatch_characteristics(const char *char_handle) { - GDBusConnection *conn; GError *error = NULL; int ret = BLUETOOTH_ERROR_NONE; - BT_DBG("+"); -/* Implementation in Bluez is not complete */ -#if 0 BT_CHECK_PARAMETER(char_handle, return); BT_CHECK_ENABLED(return); - BT_DBG("Entered characteristic handle:%s \n ", char_handle); + BT_INFO("Disable CCCD : %s", char_handle); conn = _bt_gdbus_get_system_gconn(); retv_if(conn == NULL, BLUETOOTH_ERROR_INTERNAL); @@ -1453,14 +1800,1026 @@ BT_EXPORT_API int bluetooth_gatt_unwatch_characteristics(const char *service_han NULL, NULL, G_DBUS_CALL_FLAGS_NONE, - -1, NULL, &error); + GATT_DEFAULT_TIMEOUT, NULL, &error); if (error) { BT_ERR("Watch Failed: %s", error->message); g_clear_error(&error); ret = BLUETOOTH_ERROR_INTERNAL; } -#endif - BT_DBG("-"); + return ret; } + +#ifdef TIZEN_GATT_CLIENT +void __bt_uuid_hex_to_string(unsigned char *uuid, char *str) +{ + uint32_t uuid0, uuid4; + uint16_t uuid1, uuid2, uuid3, uuid5; + + memcpy(&uuid0, &(uuid[0]), 4); + memcpy(&uuid1, &(uuid[4]), 2); + memcpy(&uuid2, &(uuid[6]), 2); + memcpy(&uuid3, &(uuid[8]), 2); + memcpy(&uuid4, &(uuid[10]), 4); + memcpy(&uuid5, &(uuid[14]), 2); + + snprintf((char *)str, BLUETOOTH_UUID_STRING_MAX, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x", + ntohl(uuid0), ntohs(uuid1), + ntohs(uuid2), ntohs(uuid3), + ntohl(uuid4), ntohs(uuid5)); + return; +} + + +static void __bt_fill_service_handle_informations(bt_services_browse_info_t *props, + bt_gatt_handle_info_t *svcs) +{ + int count; + BT_INFO("Total services found [%d]", props->count); + + if (props->count == 0) + return; + + svcs->count = props->count; + + for (count = 0; count < props->count; count++) { + BT_INFO("UUID[%d] = [%s] instance_id [%d] Is Primary [%d]", + count, props->uuids[count], props->inst_id[count], props->primary[count]); + g_strlcpy(svcs->uuids[count], props->uuids[count], + BLUETOOTH_UUID_STRING_MAX); + svcs->inst_id[count] = props->inst_id[count]; + } +} + +static void __bt_fill_char_handle_informations(bt_char_browse_info_t *props, bt_gatt_service_property_t *service) +{ + int count; + char uuid_string[BLUETOOTH_UUID_STRING_MAX]; + BT_INFO("Total number of characteristics found [%d]", + props->count); + + service->char_handle.count = props->count; + + /* Before filling all char handles, fill the service's UUID and instance ID */ + __bt_uuid_hex_to_string(props->svc_uuid, uuid_string); + service->uuid = g_strdup(uuid_string); + service->primary = TRUE; + + /* Now fill all the char handles [UUID and Instance ID's]*/ + for (count = 0; count < props->count; count++) { + BT_INFO("UUID[%d] = [%s] instance_id [%d] properties [%d]", + count, props->uuids[count], props->inst_id[count], props->props[count]); + + g_strlcpy(service->char_handle.uuids[count], + props->uuids[count], + BLUETOOTH_UUID_STRING_MAX); + + service->char_handle.inst_id[count] = props->inst_id[count]; + } +} + +static void __bt_fill_desc_handle_informations(bt_descriptor_browse_info_t *props, + bt_gatt_char_property_t *charc) +{ + int count; + char uuid_string[BLUETOOTH_UUID_STRING_MAX]; + BT_INFO("Total descriptor count found [%d]", props->count); + + charc->char_desc_handle.count = props->count; + + /* Before filling all desc handles, fill the charac's UUID and instance ID */ + __bt_uuid_hex_to_string(props->char_uuid, uuid_string); + charc->uuid = g_strdup(uuid_string); + + /* Now fill all the descriptor handles [UUID and Instance ID's]*/ + for (count = 0; count < props->count; count++) { + BT_INFO("UUID[%d] = [%s] instance_id [%d]", + count, props->uuids[count], props->inst_id[count]); + + g_strlcpy(charc->char_desc_handle.uuids[count], + props->uuids[count], + BLUETOOTH_UUID_STRING_MAX); + + charc->char_desc_handle.inst_id[count] = props->inst_id[count]; + } + charc->permission = props->char_props_map; + BT_INFO("Characteritic property map val [%d]", charc->permission); +} + + +BT_EXPORT_API int bluetooth_gatt_client_init( + int *client_id, + const bluetooth_device_address_t *address, + gatt_client_cb_func_ptr callback_ptr) +{ + int ret = BLUETOOTH_ERROR_NONE; + bt_event_info_t *event_info; + int *count; + + BT_CHECK_PARAMETER(client_id, return); + BT_CHECK_PARAMETER(callback_ptr, return); + BT_CHECK_ENABLED(return); + + BT_INFO("+"); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, address, sizeof(bluetooth_device_address_t)); + + ret = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_CLIENT_REGISTER, + in_param1, in_param2, in_param3, in_param4, &out_param); + + /* App ID -1 is invalid */ + if (ret == BLUETOOTH_ERROR_NONE) { + + *client_id = g_array_index(out_param, int, 0); + + BT_INFO("GATT Client Registered successfully: Client instance ID [%d]", *client_id); + + event_info = _bt_event_get_cb_data(BT_GATT_CLIENT_EVENT); + + if (event_info) { + count = (int*)event_info->user_data; + + BT_INFO("Total num of GATT client instances [%d]", *count); + + /* Increement the count */ + *count += 1; + } else { + BT_INFO("No GATT Client instances found in this application: Set User data"); + count = g_malloc0(sizeof(int)); + *count = 1; + + /* Register event handler for GATT */ + _bt_register_event(BT_GATT_CLIENT_EVENT, + (void *)callback_ptr, + (void *)count); + _bt_set_user_data(BT_GATT_CLIENT, (void *)callback_ptr, NULL); + } + } else + BT_ERR("GATT Client Registration failed!! ret [%d]", ret); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + return ret; +} + + + +/* GATT Client*/ +BT_EXPORT_API int bluetooth_gatt_client_get_primary_services( + const bluetooth_device_address_t *address, /* Remote GATT Server */ + bt_gatt_handle_info_t *prim_svc) /* UUID & instance_id */ +{ + + int result = BLUETOOTH_ERROR_NONE; + bt_services_browse_info_t service_props; + + BT_DBG("+"); + + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(prim_svc, return); + BT_CHECK_ENABLED(return); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + g_array_append_vals(in_param1, address, sizeof(bluetooth_device_address_t)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, + BT_GATT_GET_PRIMARY_SERVICES, + in_param1, in_param2, in_param3, in_param4, &out_param); + + if (BLUETOOTH_ERROR_NONE != result) + goto done; + + memset(&service_props, 0x00, sizeof(bt_services_browse_info_t)); + + service_props = g_array_index( + out_param, bt_services_browse_info_t, 0); + + __bt_fill_service_handle_informations( + &service_props, prim_svc); + +done: + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + BT_DBG("result = %d", result); + return result; +} + +BT_EXPORT_API int bluetooth_gatt_client_get_service_property( + const char *address, + bt_gatt_handle_property_t *service_handle, + bt_gatt_service_property_t *service) +{ + int result = BLUETOOTH_ERROR_NONE; + bluetooth_gatt_client_svc_prop_info_t svc_prop; + bt_char_browse_info_t char_handles_info; + BT_INFO("Remote Address [%s]", address); + + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(service_handle, return); + BT_CHECK_PARAMETER(service, return); + BT_CHECK_ENABLED(return); + + /* Call to bt-service (sync) and send address and service_handle info */ + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + memset(&svc_prop, 0x00, sizeof(bluetooth_gatt_client_svc_prop_info_t)); + /* All characteristics handles are discovered */ + memset(&char_handles_info, 0x00, sizeof(bt_char_browse_info_t)); + + svc_prop.svc.instance_id = service_handle->instance_id; + memcpy(&svc_prop.svc.uuid, &service_handle->uuid, 16); + + _bt_convert_addr_string_to_type(svc_prop.device_address.addr, address); + + g_array_append_vals(in_param1, &svc_prop, sizeof(bluetooth_gatt_client_svc_prop_info_t)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, + BT_GATT_GET_SERVICE_PROPERTIES, + in_param1, in_param2, in_param3, in_param4, &out_param); + + if (BLUETOOTH_ERROR_NONE != result) + goto done; + + char_handles_info = g_array_index( + out_param, bt_char_browse_info_t, 0); + __bt_fill_char_handle_informations(&char_handles_info, + service); + /* TODO Get all Included Services */ + +done: + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + BT_INFO("result = %d", result); + return result; +} + +BT_EXPORT_API int bluetooth_gatt_client_get_characteristics_property( + const char *address, + bt_gatt_handle_property_t *service_handle, + bt_gatt_handle_property_t *char_handle, + bt_gatt_char_property_t *char_property) +{ + int result = BLUETOOTH_ERROR_NONE; + bt_descriptor_browse_info_t desc_handles_info; + bluetooth_gatt_client_char_prop_info_t char_prop; + BT_INFO("Get Properties of characteristics from remote device [%s]", address); + + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(service_handle, return); + BT_CHECK_PARAMETER(char_handle, return); + BT_CHECK_PARAMETER(char_property, return); + BT_CHECK_ENABLED(return); + + + /* Call to bt-service (sync) and send address service_handle info & char handle info */ + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + memset(&char_prop, 0x00, sizeof(bluetooth_gatt_client_char_prop_info_t)); + char_prop.svc.instance_id = service_handle->instance_id; + memcpy(&char_prop.svc.uuid, &service_handle->uuid, 16); + + char_prop.characteristic.instance_id = char_handle->instance_id; + memcpy(&char_prop.characteristic.uuid, &char_handle->uuid, 16); + + _bt_convert_addr_string_to_type(char_prop.device_address.addr, address); + + g_array_append_vals(in_param1, &char_prop, sizeof(bluetooth_gatt_client_char_prop_info_t)); + + result = _bt_send_request(BT_BLUEZ_SERVICE, + BT_GATT_GET_CHARACTERISTIC_PROPERTIES, + in_param1, in_param2, in_param3, in_param4, &out_param); + + BT_INFO("result = [%d]", result); + if (BLUETOOTH_ERROR_NONE != result) + goto done; + + /* All descriptors handles are discovered */ + memset(&desc_handles_info, 0x00, sizeof(bt_descriptor_browse_info_t)); + + desc_handles_info = g_array_index( + out_param, bt_descriptor_browse_info_t, 0); + + __bt_fill_desc_handle_informations(&desc_handles_info, + char_property); + +done: + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + BT_INFO("result = %d", result); + return result; + /* Call to bt-service (sync) and send address, service_handle & char_handle infos */ + + /* After result is fetched, extract descriptor handles (UUID's & instance_id's) */ + + /* Fill the info in *char_prop */ + + /*No: Before returning, call bluetooth_gatt_client_read_characteristic_value as + an asyn function and leave every thing else in the callback */ +} + +BT_EXPORT_API int bluetooth_gatt_client_get_char_descriptor_property( + const char *address, + bt_gatt_handle_property_t *service_handle, + bt_gatt_handle_property_t *char_handle, + bt_gatt_handle_property_t *descriptor_handle, + bt_gatt_char_descriptor_property_t *desc_prop) +{ + char uuid_string[BLUETOOTH_UUID_STRING_MAX]; + BT_DBG("Remote Address [%s]", address); + + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(service_handle, return); + BT_CHECK_PARAMETER(char_handle, return); + BT_CHECK_PARAMETER(descriptor_handle, return); + BT_CHECK_PARAMETER(desc_prop, return); + /* No Need to Call to bt-service (sync) and send address, service_handle, + char_handle & descriptor handle infos */ + /* After result is fetched, extract descriptior handles (UUID's & instance_id's) */ + /* Fill the info in *desc_prop */ + __bt_uuid_hex_to_string(descriptor_handle->uuid, uuid_string); + + /* Before filling all desc handles, fill the charac's UUID and instance ID */ + desc_prop->uuid = g_strdup(uuid_string); + + return BLUETOOTH_ERROR_NONE; + /* No: Before returning, call bluetooth_gatt_client_read_descriptor_value + as an asyn function and leave every thing else in the callback */ +} + + +static gboolean bluetooth_gatt_client_notify_channel_watch_cb(GIOChannel *gio, + GIOCondition cond, gpointer data) +{ + bt_gatt_characteristic_notify_info_t *chr_info = (bt_gatt_characteristic_notify_info_t *)data; + + BT_INFO(" FD io NOTIFICATION recived\n"); + + if (!chr_info) { + BT_ERR("char INFO nort recieved"); + return FALSE; + } + if (cond & G_IO_IN) { + GIOStatus status = G_IO_STATUS_NORMAL; + GError *err = NULL; + char *buffer = NULL; + gsize len = 0; + bt_event_info_t *event_info; + + buffer = g_malloc0(chr_info->mtu + 1); + + status = g_io_channel_read_chars(gio, buffer, + chr_info->mtu, &len, &err); + if (status != G_IO_STATUS_NORMAL) { + BT_ERR("IO Channel read is failed with %d", status); + g_free(buffer); + if (err) { + BT_ERR("IO Channel read error [%s]", err->message); + if (status == G_IO_STATUS_ERROR) { + BT_ERR("cond : %d", cond); + g_error_free(err); + g_io_channel_shutdown(gio, TRUE, NULL); + g_io_channel_unref(gio); + + gatt_characteristic_notify_list = g_slist_remove(gatt_characteristic_notify_list, chr_info); + g_free(chr_info); + return FALSE; + } + g_error_free(err); + } + return FALSE; + } + + if (len > 0 && len < chr_info->mtu) { + + bt_gatt_char_property_t char_val; + BT_INFO("FD io sending value changed %s %d \ni", buffer, len); + + char_val.val = g_malloc0(len + 1); + + memcpy(char_val.prop.uuid, chr_info->UUID, 16); + memcpy(char_val.val, buffer, len); + char_val.val_len = len; + memcpy(char_val.address, chr_info->adress, 18); + + event_info = _bt_event_get_cb_data(BT_GATT_CLIENT_EVENT); + + if (event_info) { + + _bt_common_event_cb(BLUETOOTH_EVENT_GATT_CHAR_VAL_CHANGED, + BLUETOOTH_ERROR_NONE, &char_val, + event_info->cb, event_info->user_data); + } else { + BT_ERR("eventinfo failed"); + } + + g_free(char_val.val); + + } else + BT_ERR("Packet corrupted"); + g_free(buffer); + + return TRUE; + } + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + BT_ERR("Error : GIOCondition %d, [%s]", cond, chr_info->UUID); + g_io_channel_shutdown(gio, TRUE, NULL); + g_io_channel_unref(gio); + + gatt_characteristic_notify_list = g_slist_remove(gatt_characteristic_notify_list, chr_info); + g_free(chr_info); + + return FALSE; + } + + return TRUE; +} + +static bt_gatt_characteristic_notify_info_t * bluetooth_gatt_client_get_characteristic_notify_info(unsigned char *handle , int id) +{ + GSList *l; + + for (l = gatt_characteristic_notify_list; l != NULL; l = l->next) { + bt_gatt_characteristic_notify_info_t *info = l->data; + if (memcmp(info->UUID, handle, 16) == 0 && info->id == id) + return info; + } + return NULL; +} + +static bt_gatt_characteristic_notify_info_t * bluetooth_gatt_client_create_watch_io(int fd, int id, int mtu, char * address, unsigned char *uuid) +{ + GIOChannel *channel; + bt_gatt_characteristic_notify_info_t *chr_info; + + chr_info = g_malloc0(sizeof(bt_gatt_characteristic_notify_info_t)); + chr_info->notify_fd = fd; + chr_info->id = id; + chr_info->mtu = mtu; + g_strlcpy(chr_info->adress, address, 18); + memcpy(chr_info->UUID, uuid, 16); + + channel = g_io_channel_unix_new(fd); + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_set_buffered(channel, FALSE); + g_io_channel_set_close_on_unref(channel, FALSE); + g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch(channel, (G_IO_IN | G_IO_ERR | G_IO_HUP), + bluetooth_gatt_client_notify_channel_watch_cb, chr_info); + + return chr_info; + +} + +BT_EXPORT_API int bluetooth_gatt_client_watch_characteristics( + const char *address, + bt_gatt_handle_property_t *service_handle, + bt_gatt_handle_property_t *char_handle, + int client_id, + gboolean is_notify, + gboolean is_indicate) +{ + int result = BLUETOOTH_ERROR_NONE; + bluetooth_gatt_client_char_prop_info_t param; + bt_gatt_characteristic_notify_info_t *chr_info; + + BT_DBG("+"); + + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(service_handle, return); + BT_CHECK_PARAMETER(char_handle, return); + + chr_info = bluetooth_gatt_client_get_characteristic_notify_info(char_handle->uuid , char_handle->instance_id); + if (chr_info && !is_notify) { + BT_INFO("Already CCCD enabled. fd %d", chr_info->notify_fd); + + close(chr_info->notify_fd); + return result; + } + + /* ASync Function, result expected in callback from bt-service */ + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + BT_INFO("Address [%s]", address); + memset(¶m, 0x00, sizeof(bluetooth_gatt_client_char_prop_info_t)); + + memcpy(¶m.svc.uuid, service_handle->uuid, 16); + param.svc.instance_id = service_handle->instance_id; + + memcpy(¶m.characteristic.uuid, char_handle->uuid, 16); + param.characteristic.instance_id = char_handle->instance_id; + + _bt_convert_addr_string_to_type(param.device_address.addr, address); + + g_array_append_vals(in_param1, ¶m, sizeof(bluetooth_gatt_client_char_prop_info_t)); + g_array_append_vals(in_param2, &client_id, sizeof(int)); + g_array_append_vals(in_param3, &is_notify, sizeof(gboolean)); + g_array_append_vals(in_param4, &is_indicate, sizeof(gboolean)); + + + GUnixFDList *out_fd_list = NULL; + + result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_GATT_WATCH_CHARACTERISTIC, + in_param1, in_param2, in_param3, in_param4, NULL, &out_param, &out_fd_list); + BT_DBG("result: %x", result); + + if (result != BLUETOOTH_ERROR_NONE) { + BT_ERR("Fail to send request"); + return result; + } else if (NULL == out_fd_list) { + BT_ERR("out_fd_list is NULL"); + + } else { + + int *fd_list_array; + int len = 0; + int mtu; + int fd = -1;; + + if (!out_fd_list) + return BLUETOOTH_ERROR_INTERNAL; + + fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len); + BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]); + fd = fd_list_array[0]; + mtu = g_array_index(out_param, int, 0); + + chr_info = bluetooth_gatt_client_create_watch_io(fd, char_handle->instance_id, mtu, (char *)address, char_handle->uuid); + + gatt_characteristic_notify_list = g_slist_append(gatt_characteristic_notify_list, chr_info); + + g_free(fd_list_array); + g_object_unref(out_fd_list); + + } + + /*result = _bt_send_request(BT_BLUEZ_SERVICE, + BT_GATT_WATCH_CHARACTERISTIC, + in_param1, in_param2, in_param3, in_param4, &out_param);*/ + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + BT_INFO("Result [%d]", result); + return result; +} + +BT_EXPORT_API int bluetooth_gatt_client_read_characteristic_value( + const char *address, + bt_gatt_handle_property_t *service_handle, + bt_gatt_handle_property_t *char_handle) +{ + int result = BLUETOOTH_ERROR_NONE; + bt_user_info_t *user_info; + bluetooth_gatt_client_char_prop_info_t param; + BT_DBG("+"); + + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(service_handle, return); + BT_CHECK_PARAMETER(char_handle, return); + + user_info = _bt_get_user_data(BT_GATT_CLIENT); + retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + /* Async Function, result expected in callback from bt-service */ + /* Call to bt-service (sync) and send address service_handle info & char handle info */ + memset(¶m, 0x00, sizeof(bluetooth_gatt_client_char_prop_info_t)); + + memcpy(¶m.svc.uuid, service_handle->uuid, 16); + param.svc.instance_id = service_handle->instance_id; + + memcpy(¶m.characteristic.uuid, char_handle->uuid, 16); + param.characteristic.instance_id = char_handle->instance_id; + + _bt_convert_addr_string_to_type(param.device_address.addr, address); + + g_array_append_vals(in_param1, ¶m, + sizeof(bluetooth_gatt_client_char_prop_info_t)); + + + result = _bt_send_request_async(BT_BLUEZ_SERVICE, BT_GATT_READ_CHARACTERISTIC, + in_param1, in_param2, in_param3, in_param4, + user_info->cb, user_info->user_data); + + + BT_INFO("result = [%d]", result); + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + return result; +} + +BT_EXPORT_API int bluetooth_gatt_client_read_descriptor_value( + const char *address, + bt_gatt_handle_property_t *service_handle, + bt_gatt_handle_property_t *char_handle, + bt_gatt_handle_property_t *descriptor_handle) +{ + int result = BLUETOOTH_ERROR_NONE; + bt_user_info_t *user_info; + bluetooth_gatt_client_desc_prop_info_t param; + BT_DBG("+"); + + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(service_handle, return); + BT_CHECK_PARAMETER(char_handle, return); + BT_CHECK_PARAMETER(descriptor_handle, return); + + user_info = _bt_get_user_data(BT_GATT_CLIENT); + retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + /* Async Function, result expected in callback from bt-service */ + memset(¶m, 0x00, sizeof(bluetooth_gatt_client_desc_prop_info_t)); + + memcpy(¶m.svc.uuid, service_handle->uuid, 16); + param.svc.instance_id = service_handle->instance_id; + + memcpy(¶m.characteristic.uuid, char_handle->uuid, 16); + param.characteristic.instance_id = char_handle->instance_id; + + memcpy(¶m.descriptor.uuid, descriptor_handle->uuid, 16); + param.descriptor.instance_id = descriptor_handle->instance_id; + + _bt_convert_addr_string_to_type(param.device_address.addr, address); + + g_array_append_vals(in_param1, ¶m, + sizeof(bluetooth_gatt_client_desc_prop_info_t)); + + + result = _bt_send_request_async(BT_BLUEZ_SERVICE, BT_GATT_READ_DESCRIPTOR_VALUE, + in_param1, in_param2, in_param3, in_param4, + user_info->cb, user_info->user_data); + + BT_INFO("result = [%d]", result); + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + return result; +} + + +static bt_gatt_characteristic_write_info_t * bluetooth_gatt_client_get_characteristic_fd(unsigned char *handle, int id) +{ + GSList *l; + char str[37]; + _bt_convert_uuid_type_to_string(str, handle); + BT_INFO("request found UUID [%s], sid [ %d]", str, id); + for (l = gatt_characteristic_write_list; l != NULL; l = l->next) { + bt_gatt_characteristic_write_info_t *info = l->data; + _bt_convert_uuid_type_to_string(str, info->UUID); + BT_INFO("UUID [%s], sid [ %d]" , str, info->id); + if (memcmp(info->UUID, handle, 16) == 0 && info->id == id) + return info; + } + return NULL; +} + +static gboolean bluetooth_gatt_client_write_channel_watch_cb(GIOChannel *gio, + GIOCondition cond, gpointer data) +{ + bt_gatt_characteristic_write_info_t *chr_info = (bt_gatt_characteristic_write_info_t *)data; + + if (!chr_info) + return FALSE; + + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + BT_ERR("Error : GIOCondition %d, [%s]", cond, chr_info->UUID); + g_io_channel_shutdown(gio, TRUE, NULL); + g_io_channel_unref(gio); + + gatt_characteristic_write_list = g_slist_remove(gatt_characteristic_write_list, chr_info); + g_free(chr_info); + + return FALSE; + } + + return TRUE; +} + +static int bluetooth_gatt_client_write_characteristics_value_to_fd( + int fd, const guint8 *value, int length, int mtu, + gpointer user_data) +{ + int written; + int att_result = BLUETOOTH_ERROR_NONE; + BT_CHECK_PARAMETER(value, return); + written = write(fd, value, length); + if (written != length) { + att_result = BLUETOOTH_ERROR_INTERNAL; + BT_INFO("write data failed %d is ", written); + } else + BT_INFO("write data %s is sucess ", value); + + return att_result; +} + +static void bluetooth_gatt_client_create_write_io_channel(int fd, unsigned char * uuid, int id, int mtu) +{ + bt_gatt_characteristic_write_info_t *chr_info; + GIOChannel *channel; + + chr_info = g_malloc0(sizeof(bt_gatt_characteristic_write_info_t)); + chr_info->write_fd = fd; + chr_info->id = id; + chr_info->mtu = mtu; + + memcpy(chr_info->UUID, uuid, 16); + channel = g_io_channel_unix_new(fd); + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_set_buffered(channel, FALSE); + g_io_channel_set_close_on_unref(channel, TRUE); + g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch(channel, (G_IO_ERR | G_IO_HUP | G_IO_NVAL), + bluetooth_gatt_client_write_channel_watch_cb, chr_info); + + gatt_characteristic_write_list = g_slist_append(gatt_characteristic_write_list, chr_info); + +} + +BT_EXPORT_API int bluetooth_gatt_client_write_characteristic_value_by_type( + const char *address, + bt_gatt_handle_property_t *service_handle, + bt_gatt_handle_property_t *char_handle, + bluetooth_gatt_att_data_t *data, + bluetooth_gatt_write_type_e write_type) +{ + int result = BLUETOOTH_ERROR_NONE; + bt_user_info_t *user_info; + bluetooth_gatt_client_char_prop_info_t param; + BT_DBG("+"); + + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(service_handle, return); + BT_CHECK_PARAMETER(char_handle, return); + BT_CHECK_PARAMETER(data, return); + + /* ASync Function, result expected in callback from bt-service */ + user_info = _bt_get_user_data(BT_GATT_CLIENT); + retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + memset(¶m, 0x00, sizeof(bluetooth_gatt_client_char_prop_info_t)); + + memcpy(¶m.svc.uuid, service_handle->uuid, 16); + param.svc.instance_id = service_handle->instance_id; + + memcpy(¶m.characteristic.uuid, char_handle->uuid, 16); + param.characteristic.instance_id = char_handle->instance_id; + + _bt_convert_addr_string_to_type(param.device_address.addr, address); + + g_array_append_vals(in_param1, ¶m, sizeof(bluetooth_gatt_client_char_prop_info_t)); + g_array_append_vals(in_param2, data, sizeof(bluetooth_gatt_att_data_t)); + g_array_append_vals(in_param3, &write_type, sizeof(bluetooth_gatt_write_type_e)); + + if (write_type == BLUETOOTH_GATT_TYPE_WRITE_NO_RESPONSE) { + int fd = -1; + int mtu = 0; + bt_gatt_characteristic_write_info_t *info; + info = bluetooth_gatt_client_get_characteristic_fd(char_handle->uuid, service_handle->instance_id); + + if (info) { + fd = info->write_fd; + mtu = info->mtu; + } + + if (fd < 0) { + + GUnixFDList *out_fd_list = NULL; + + result = _bt_send_request_with_unix_fd_list(BT_BLUEZ_SERVICE, BT_GATT_ACQUIRE_WRITE, + in_param1, in_param2, in_param3, in_param4, NULL, &out_param, &out_fd_list); + BT_DBG("result: %x", result); + + mtu = g_array_index(out_param, int, 0); + + if (result != BLUETOOTH_ERROR_NONE) { + BT_ERR("Fail to send request"); + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + return result; + } else if (NULL == out_fd_list) { + BT_ERR("out_fd_list is NULL"); + return BLUETOOTH_ERROR_INTERNAL; + } else { + int *fd_list_array; + int len = 0; + + if (!out_fd_list) { + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + return BLUETOOTH_ERROR_INTERNAL; + } + + fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len); + BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]); + fd = fd_list_array[0]; + + g_free(fd_list_array); + g_object_unref(out_fd_list); + } + BT_INFO("Acquired characteristic fd %d --------------- mtu %d, ", fd, mtu); + + if (fd > -1) { + + bluetooth_gatt_client_create_write_io_channel(fd, char_handle->uuid, service_handle->instance_id, mtu); + + result = bluetooth_gatt_client_write_characteristics_value_to_fd(fd, data->data, data->length, mtu, NULL); + + } else { + BT_INFO(" characteristic info FD is invalid\n"); + goto done; + } + + } else { + BT_INFO("Acquired characteristic fd %d --------------- mtu %d, ", fd, mtu); + result = bluetooth_gatt_client_write_characteristics_value_to_fd(fd, data->data, data->length, mtu, NULL); + } + + } else { +done: + result = _bt_send_request_async(BT_BLUEZ_SERVICE, + BT_GATT_WRITE_CHARACTERISTIC_VALUE_BY_TYPE, + in_param1, in_param2, in_param3, in_param4, + user_info->cb, user_info->user_data); + } + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; +} + +BT_EXPORT_API int bluetooth_gatt_client_write_descriptor_value( + const char *address, + bt_gatt_handle_property_t *service_handle, + bt_gatt_handle_property_t *char_handle, + bt_gatt_handle_property_t *descriptor_handle, + bluetooth_gatt_att_data_t *data, + bluetooth_gatt_write_type_e write_type) +{ + int result = BLUETOOTH_ERROR_NONE; + bt_user_info_t *user_info; + bluetooth_gatt_client_desc_prop_info_t param; + BT_DBG("+"); + + BT_CHECK_PARAMETER(address, return); + BT_CHECK_PARAMETER(service_handle, return); + BT_CHECK_PARAMETER(char_handle, return); + BT_CHECK_PARAMETER(descriptor_handle, return); + BT_CHECK_PARAMETER(data, return); + + /* Async Function, result expected in callback from bt-service */ + user_info = _bt_get_user_data(BT_GATT_CLIENT); + retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + memset(¶m, 0x00, sizeof(bluetooth_gatt_client_desc_prop_info_t)); + + memcpy(¶m.svc.uuid, service_handle->uuid, 16); + param.svc.instance_id = service_handle->instance_id; + + memcpy(¶m.characteristic.uuid, char_handle->uuid, 16); + param.characteristic.instance_id = char_handle->instance_id; + + memcpy(¶m.descriptor.uuid, descriptor_handle->uuid, 16); + param.descriptor.instance_id = descriptor_handle->instance_id; + + _bt_convert_addr_string_to_type(param.device_address.addr, address); + + g_array_append_vals(in_param1, ¶m, sizeof(bluetooth_gatt_client_desc_prop_info_t)); + g_array_append_vals(in_param2, data, sizeof(bluetooth_gatt_att_data_t)); + g_array_append_vals(in_param3, &write_type, sizeof(bluetooth_gatt_write_type_e)); + + result = _bt_send_request_async(BT_BLUEZ_SERVICE, + BT_GATT_WRITE_DESCRIPTOR_VALUE, + in_param1, in_param2, in_param3, in_param4, + user_info->cb, user_info->user_data); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + return result; +} + +BT_EXPORT_API int bluetooth_gatt_client_set_service_change_watcher( + const bluetooth_device_address_t *address, gboolean enable) +{ + GSList *l; + bluetooth_device_address_t *addr = NULL; + char secure_address[BT_ADDRESS_STRING_SIZE] = { 0 }; + int result = BLUETOOTH_ERROR_NONE; + + BT_INFO("+"); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, address, sizeof(bluetooth_device_address_t)); + g_array_append_vals(in_param2, &enable, sizeof(gboolean)); + + + _bt_convert_addr_string_to_secure_string(secure_address, (const char *)address->addr); + BT_INFO("Set watcher for %s with %d", secure_address, enable); + + if (enable == TRUE) { + if (_bluetooth_gatt_check_service_change_watcher_address(address) + == TRUE) { + BT_INFO("The watcher is already set"); + goto done; + } + + if (service_monitor_list == NULL) { + //_bt_register_manager_subscribe_signal(TRUE); + + result = _bt_send_request(BT_BLUEZ_SERVICE, + BT_GATT_WATCH_SERVICE_CHANGED_INDICATION, + in_param1, in_param2, in_param3, in_param4, &out_param); + } + + if (result == BLUETOOTH_ERROR_NONE) { + addr = g_malloc0(sizeof(bluetooth_device_address_t)); + memcpy(addr, address, sizeof(bluetooth_device_address_t)); + + service_monitor_list = + g_slist_append(service_monitor_list, addr); + } + } else { + for (l = service_monitor_list; l != NULL; l = l->next) { + addr = l->data; + + if (!memcmp(address, addr, + sizeof(bluetooth_device_address_t))) { + service_monitor_list = + g_slist_remove(service_monitor_list, addr); + g_free(addr); + break; + } + } + + if (service_monitor_list == NULL) { + //_bt_register_manager_subscribe_signal(FALSE); + result = _bt_send_request(BT_BLUEZ_SERVICE, + BT_GATT_WATCH_SERVICE_CHANGED_INDICATION, + in_param1, in_param2, in_param3, in_param4, &out_param); + + } + } + +done: + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + return result; +} + +BT_EXPORT_API int bluetooth_gatt_client_deinit( + int client_id) +{ + int result; + int *count; + bt_event_info_t *event_info; + + BT_CHECK_ENABLED(return); + + BT_INFO("GATT Client Deinit Client instance ID [%d]", client_id); + + BT_INIT_PARAMS(); + BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + + g_array_append_vals(in_param1, &client_id, sizeof(int)); + + /* Unregistration MUST NOT FAIL */ + result = _bt_send_request(BT_BLUEZ_SERVICE, BT_GATT_CLIENT_UNREGISTER, + in_param1, in_param2, in_param3, in_param4, &out_param); + + if (result != BLUETOOTH_ERROR_NONE) + BT_INFO("GATT Client Unregistration failed result [%d]", result); + else + BT_INFO("GATT Client Unregistration successful"); + + /* Unregister event handler if this is the only instance */ + event_info = _bt_event_get_cb_data(BT_GATT_CLIENT_EVENT); + + if (event_info) { + count = (int*)event_info->user_data; + + BT_INFO("Total num of GATT client instances [%d]", *count); + + if (*count == 1) { + BT_INFO("Currently only one GATT client instance, so remove it and unregister GATT client events"); + _bt_unregister_event(BT_GATT_CLIENT_EVENT); + _bt_set_user_data(BT_GATT_CLIENT, NULL, NULL); + } else + *count -= 1; + } else + BT_ERR("Impossible that client is created, but no event handler is registered!!!"); + + BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param); + return result; +} + +#endif