ADD CAPI: 50/26850/2
authorGu Chaojie <chao.jie.gu@intel.com>
Wed, 3 Sep 2014 11:43:29 +0000 (19:43 +0800)
committerGu Chaojie <chao.jie.gu@intel.com>
Wed, 3 Sep 2014 11:43:29 +0000 (19:43 +0800)
Gatt discover characteristic
Gatt Set/unset changed callback
Gatt get characteristic declaration
Gatt write characteristic value
Gatt read characteristic value
Signed-off-by: Gu Chaojie <chao.jie.gu@intel.com>
Change-Id: Ief7feee73f15e2e94840e105f1ef9fd1cb0867ec

capi/bluetooth.c
include/bluetooth.h
include/bluez.h
include/common.h
lib/bluez.c
lib/common.c
test/bluez-capi-test.c

index 76c983a..ba60fdc 100644 (file)
@@ -47,6 +47,8 @@
 #define AGENT_INTERFACE "org.bluez.Agent1"
 #define AGENT_OBJECT_PATH "/org/bluezlib/agent"
 
+#define WRITE_REQUEST "write"
+#define WRITE_COMMAND "write-without-response"
 static bool initialized;
 static bool bt_service_init;
 
@@ -204,6 +206,22 @@ struct nap_connection_state_changed_cb_node {
        void *user_data;
 };
 
+struct char_read_value_cb_node {
+       bt_gatt_characteristic_read_cb cb;
+       void *user_data;
+};
+
+struct char_write_value_cb_node {
+       bt_gatt_characteristic_write_cb cb;
+       void *user_data;
+};
+
+struct char_changed_cb_node {
+       bt_gatt_characteristic_changed_cb cb;
+       char *object_path;
+       void *user_data;
+};
+
 static struct device_connect_cb_node *device_connect_node;
 static struct device_disconnect_cb_node *device_disconnect_node;
 static struct avrcp_repeat_mode_changed_node *avrcp_repeat_node;
@@ -237,9 +255,22 @@ static struct socket_connection_state_changed_cb_node
 static struct hid_host_connection_state_changed_cb_node *hid_host_state_node;
 static struct nap_connection_state_changed_cb_node
                                *nap_connection_state_changed_node;
+static struct char_read_value_cb_node *char_read_value_node;
+static struct char_write_value_cb_node *char_write_value_node;
 
 static gboolean generic_device_removed_set;
 
+static GList *char_changed_node_list;
+
+static int service_by_path_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct char_changed_cb_node *node_data = a;
+       const char *service_path = b;
+       const char *object_path = node_data->object_path;
+
+       return strcmp(service_path, object_path);
+}
+
 static void divide_device_class(bt_class_s *bt_class, unsigned int class)
 {
        bt_class->major_device_class =
@@ -492,6 +523,55 @@ static void bluez_nap_connection_changed(gboolean connected,
                        interface_name, data->user_data);
 }
 
+static void bluez_char_read_received_changed(
+                               struct _bluez_gatt_char *characteristic,
+                               unsigned char *value_array,
+                               int value_length,
+                               void *user_data)
+{
+       struct char_read_value_cb_node *data = user_data;
+
+       if (data->cb)
+               data->cb(value_array, value_length,
+                       data->user_data);
+
+       g_free(char_read_value_node);
+       char_read_value_node = NULL;
+}
+
+static void bluez_char_write_received_changed(
+                               struct _bluez_gatt_char *characteristic,
+                               void *user_data)
+{
+       struct char_write_value_cb_node *data = user_data;
+       char *gatt_char_path;
+
+       gatt_char_path = bluez_gatt_char_get_object_path(characteristic);
+
+       if (data->cb)
+               data->cb(gatt_char_path);
+
+       g_free(char_write_value_node);
+       char_write_value_node = NULL;
+}
+
+static void bluez_char_value_changed(
+                               struct _bluez_gatt_char *characteristic,
+                               unsigned char *value_array,
+                               int value_length,
+                               void *user_data)
+{
+       struct char_changed_cb_node *data = user_data;
+       char *gatt_char_path;
+
+       gatt_char_path = bluez_gatt_char_get_object_path(characteristic);
+
+       if (data->cb)
+               data->cb(gatt_char_path,
+                       value_array, value_length,
+                       data->user_data);
+}
+
 static void bluez_set_data_received_changed(
                                unsigned int channel,
                                const char *data,
@@ -742,6 +822,30 @@ static void foreach_device_property_callback(GList *list, unsigned int flag)
        }
 }
 
+static void foreach_characteristic_property_callback(GList *list,
+                                               void *user_data)
+{
+       struct char_changed_cb_node *node_data = user_data;
+       bluez_gatt_char_t *characteristic;
+       GList *iter, *next;
+
+       DBG("");
+
+       for (iter = g_list_first(list); iter; iter = next) {
+               next = g_list_next(iter);
+
+               characteristic = iter->data;
+
+               if (node_data)
+                       bluez_set_char_value_changed_cb(characteristic,
+                                               bluez_char_value_changed,
+                                               node_data);
+               else
+                       bluez_unset_char_value_changed_cb(characteristic);
+       }
+
+}
+
 static void bluez_device_created(bluez_device_t *device, void *user_data)
 {
        bt_adapter_device_discovery_info_s *discovery_device_info;
@@ -993,8 +1097,18 @@ static void _bt_update_bluetooth_callbacks(void)
 
        if (nap_connection_state_changed_node)
                bluez_set_nap_connection_state_cb(
-                               bluez_nap_connection_changed,
-                               nap_connection_state_changed_node);
+                                       bluez_nap_connection_changed,
+                                       nap_connection_state_changed_node);
+
+       if (char_read_value_node)
+               bluez_set_char_read_value_cb(
+                                       bluez_char_read_received_changed,
+                                       char_read_value_node);
+
+       if (char_write_value_node)
+               bluez_set_char_write_value_cb(
+                                       bluez_char_write_received_changed,
+                                       char_write_value_node);
 }
 
 static void setup_bluez_lib(void)
@@ -1058,6 +1172,8 @@ int bt_initialize(void)
 
        bt_service_init = TRUE;
 
+       char_changed_node_list = NULL;
+
        setup_bluez_lib();
 
        return BT_SUCCESS;
@@ -2203,7 +2319,7 @@ int bt_device_set_authorization_changed_cb(
 
        node = g_new0(struct device_auth_cb_node, 1);
        if (node == NULL) {
-               ERROR("no memeroy");
+               ERROR("no memory");
                return BT_ERROR_OPERATION_FAILED;
        }
 
@@ -5309,7 +5425,6 @@ int bt_gatt_foreach_primary_services(const char *remote_address,
                return BT_ERROR_OPERATION_FAILED;
 
        primary_services = bluez_device_get_primary_services(device);
-
        if (primary_services == NULL)
                return BT_ERROR_OPERATION_FAILED;
 
@@ -5327,10 +5442,16 @@ int bt_gatt_foreach_primary_services(const char *remote_address,
        return BT_SUCCESS;
 }
 
-int bt_gatt_get_service_uuid(bt_gatt_attribute_h service, char **uuid)
+int bt_gatt_discover_characteristics(bt_gatt_attribute_h service,
+                               bt_gatt_characteristics_discovered_cb callback,
+                               void *user_data)
 {
        bluez_gatt_service_t *gatt_service;
+       GList *characteristics, *list, *next;
+       guint total;
        const char *service_path = service;
+       char *gatt_char_path;
+       int index = 0;
 
        DBG("");
 
@@ -5344,7 +5465,50 @@ int bt_gatt_get_service_uuid(bt_gatt_attribute_h service, char **uuid)
                return BT_ERROR_INVALID_PARAMETER;
 
        gatt_service = bluez_gatt_get_service_by_path(service_path);
+       if (gatt_service == NULL)
+               return BT_ERROR_OPERATION_FAILED;
+
+       characteristics = bluez_gatt_service_get_char_paths(gatt_service);
+       if (characteristics == NULL)
+               return BT_ERROR_OPERATION_FAILED;
+
+       total = g_list_length(characteristics);
 
+       for (list = g_list_first(characteristics); list; list = next) {
+               gatt_char_path = list->data;
+
+               next = g_list_next(list);
+
+               if (!callback(0, index, (int)total,
+                       (bt_gatt_attribute_h)gatt_char_path, user_data))
+                       break;
+
+               index++;
+       }
+
+       g_list_free(characteristics);
+
+       return BT_SUCCESS;
+
+}
+
+int bt_gatt_get_service_uuid(bt_gatt_attribute_h service, char **uuid)
+{
+       bluez_gatt_service_t *gatt_service;
+       const char *service_path = service;
+
+       DBG("");
+
+       if (initialized == false)
+               return BT_ERROR_NOT_INITIALIZED;
+
+       if (default_adapter == NULL)
+               return BT_ERROR_ADAPTER_NOT_FOUND;
+
+       if (service_path == NULL)
+               return BT_ERROR_INVALID_PARAMETER;
+
+       gatt_service = bluez_gatt_get_service_by_path(service_path);
        if (gatt_service == NULL)
                return BT_ERROR_OPERATION_FAILED;
 
@@ -5374,14 +5538,12 @@ int bt_gatt_foreach_included_services(bt_gatt_attribute_h service,
                return BT_ERROR_INVALID_PARAMETER;
 
        gatt_service = bluez_gatt_get_service_by_path(service_path);
-
        if (gatt_service == NULL)
                return BT_ERROR_OPERATION_FAILED;
 
        includes = bluez_gatt_service_get_property_includes(gatt_service);
-
        if (includes == NULL) {
-               DBG("No include services found in service handle");
+               DBG("No include services found in this service handle");
                return BT_SUCCESS;
        }
 
@@ -5392,9 +5554,234 @@ int bt_gatt_foreach_included_services(bt_gatt_attribute_h service,
                        break;
        }
 
+       for (index = 0; index < length; index++)
+               g_free(includes[index]);
+
+       g_free(includes);
+
        return BT_SUCCESS;
 }
 
+int bt_gatt_set_characteristic_changed_cb(bt_gatt_attribute_h service,
+                               bt_gatt_characteristic_changed_cb callback,
+                               void *user_data)
+{
+       bluez_gatt_service_t *gatt_service;
+       const char *service_path = service;
+       struct char_changed_cb_node *node_data;
+       GList *characteristics;
+
+       DBG("");
+
+       if (initialized == false)
+               return BT_ERROR_NOT_INITIALIZED;
+
+       if (default_adapter == NULL)
+               return BT_ERROR_ADAPTER_NOT_FOUND;
+
+       if (service_path == NULL)
+               return BT_ERROR_INVALID_PARAMETER;
+
+       if (char_changed_node_list) {
+               if (g_list_find_custom(char_changed_node_list,
+                                       service_path,
+                                       service_by_path_cmp)){
+                       DBG("changed callback already set in this service.");
+                       return BT_ERROR_ALREADY_DONE;
+               }
+       }
+
+       gatt_service = bluez_gatt_get_service_by_path(service_path);
+       if (gatt_service == NULL)
+               return BT_ERROR_OPERATION_FAILED;
+
+       characteristics = bluez_gatt_service_get_chars(gatt_service);
+       if (characteristics == NULL)
+               return BT_ERROR_OPERATION_FAILED;
+
+       node_data = g_new0(struct char_changed_cb_node, 1);
+       if (node_data == NULL) {
+               ERROR("no memory");
+               return BT_ERROR_OUT_OF_MEMORY;
+       }
+
+       node_data->cb = callback;
+       node_data->user_data = user_data;
+       node_data->object_path =
+               bluez_gatt_service_get_object_path(gatt_service);
+
+       char_changed_node_list =
+               g_list_append(char_changed_node_list, node_data);
+
+       foreach_characteristic_property_callback(characteristics, node_data);
+
+       return BT_SUCCESS;
+}
+
+int bt_gatt_unset_characteristic_changed_cb(bt_gatt_attribute_h service)
+{
+       bluez_gatt_service_t *gatt_service;
+       const char *service_path = service;
+       struct char_changed_cb_node *node_data;
+       GList *found, *characteristics;
+
+       DBG("");
+
+       if (initialized == false)
+               return BT_ERROR_NOT_INITIALIZED;
+
+       if (default_adapter == NULL)
+               return BT_ERROR_ADAPTER_NOT_FOUND;
+
+       if (service_path == NULL)
+               return BT_ERROR_INVALID_PARAMETER;
+
+       if (char_changed_node_list) {
+               found = g_list_find_custom(char_changed_node_list,
+                                       service_path,
+                                       service_by_path_cmp);
+               if (found)
+                       node_data = found->data;
+               else {
+                       DBG("changed callback already unset in this service.");
+                       return BT_ERROR_ALREADY_DONE;
+               }
+
+       } else
+               return BT_ERROR_OPERATION_FAILED;
+
+       gatt_service = bluez_gatt_get_service_by_path(service_path);
+       if (gatt_service == NULL)
+               return BT_ERROR_OPERATION_FAILED;
+
+       characteristics = bluez_gatt_service_get_chars(gatt_service);
+       if (characteristics == NULL)
+               return BT_ERROR_OPERATION_FAILED;
+
+       char_changed_node_list =
+                       g_list_remove(char_changed_node_list, found);
+
+       g_free(node_data);
+
+       foreach_characteristic_property_callback(characteristics, NULL);
+
+       return BT_SUCCESS;
+}
+
+int bt_gatt_get_characteristic_declaration(bt_gatt_attribute_h characteristic,
+                               char **uuid, unsigned char **value,
+                               int *value_length)
+{
+       bluez_gatt_char_t *gatt_char;
+       const char *gatt_char_path = characteristic;
+       GByteArray *gb_array;
+
+       DBG("");
+
+       if (initialized == false)
+               return BT_ERROR_NOT_INITIALIZED;
+
+       if (default_adapter == NULL)
+               return BT_ERROR_ADAPTER_NOT_FOUND;
+
+       if (gatt_char_path == NULL)
+               return BT_ERROR_INVALID_PARAMETER;
+
+       gatt_char = bluez_gatt_get_char_by_path(gatt_char_path);
+       if (gatt_char == NULL)
+               return BT_ERROR_OPERATION_FAILED;
+
+       *uuid = bluez_gatt_char_get_property_uuid(gatt_char);
+
+       gb_array = bluez_gatt_char_get_property_value(gatt_char);
+       if (gb_array == NULL) {
+               DBG("Characterisitc is not sync with remote device,"
+                       " please read value");
+               *value_length = 0;
+
+               return BT_SUCCESS;
+       }
+
+       *value = g_malloc0(gb_array->len * sizeof(unsigned char));
+
+       memcpy(*value, gb_array->data, gb_array->len);
+
+       *value_length = gb_array->len;
+
+       g_byte_array_unref(gb_array);
+
+       return BT_SUCCESS;
+}
+
+int bt_gatt_set_characteristic_value_request(bt_gatt_attribute_h characteristic,
+                               const unsigned char *value,
+                               int value_length,
+                               unsigned char request,
+                               bt_gatt_characteristic_write_cb callback)
+{
+       bluez_gatt_char_t *gatt_char;
+       const char *gatt_char_path = characteristic;
+       struct char_write_value_cb_node *node_data;
+       guint length, index;
+       char **flags;
+
+       DBG("");
+
+       if (initialized == false)
+               return BT_ERROR_NOT_INITIALIZED;
+
+       if (default_adapter == NULL)
+               return BT_ERROR_ADAPTER_NOT_FOUND;
+
+       if (gatt_char_path == NULL)
+               return BT_ERROR_INVALID_PARAMETER;
+
+       gatt_char = bluez_gatt_get_char_by_path(gatt_char_path);
+       if (gatt_char == NULL)
+               return BT_ERROR_OPERATION_FAILED;
+
+       flags = bluez_gatt_char_property_get_flags(gatt_char);
+       length = g_strv_length(flags);
+
+       for (index = 0; index < length; ++index) {
+               if (((strcmp(flags[index], WRITE_REQUEST) == 0) &&
+                       request) ||
+                       ((strcmp(flags[index], WRITE_COMMAND) == 0) &&
+                       !request))
+                       break;
+
+               if (index == length - 1)
+                       return BT_ERROR_OPERATION_FAILED;
+       }
+
+       if (request) {
+               if (char_write_value_node) {
+                       DBG("characteristic write callback already set.");
+                       return BT_ERROR_ALREADY_DONE;
+               }
+
+               node_data = g_new0(struct char_write_value_cb_node, 1);
+               if (node_data == NULL) {
+                       ERROR("no memory");
+                       return BT_ERROR_OUT_OF_MEMORY;
+               }
+
+               node_data->cb = callback;
+               node_data->user_data = NULL;
+
+               char_write_value_node = node_data;
+
+               _bt_update_bluetooth_callbacks();
+       }
+
+       bluez_gatt_write_char_value(gatt_char, value, value_length, request);
+
+       g_strfreev(flags);
+
+       return BT_SUCCESS;
+
+}
+
 int bt_gatt_clone_attribute_handle(bt_gatt_attribute_h *clone,
                                bt_gatt_attribute_h origin)
 {
@@ -5431,3 +5818,49 @@ int bt_gatt_destroy_attribute_handle(bt_gatt_attribute_h handle)
 
        return BT_SUCCESS;
 }
+
+int bt_gatt_read_characteristic_value(bt_gatt_attribute_h characteristic,
+               bt_gatt_characteristic_read_cb callback)
+{
+       bluez_gatt_char_t *gatt_char;
+       const char *gatt_char_path = characteristic;
+       struct char_read_value_cb_node *node_data;
+
+       DBG("");
+
+       if (initialized == false)
+               return BT_ERROR_NOT_INITIALIZED;
+
+       if (default_adapter == NULL)
+               return BT_ERROR_ADAPTER_NOT_FOUND;
+
+       if (gatt_char_path == NULL)
+               return BT_ERROR_INVALID_PARAMETER;
+
+       gatt_char = bluez_gatt_get_char_by_path(gatt_char_path);
+       if (gatt_char == NULL)
+               return BT_ERROR_OPERATION_FAILED;
+
+       if (char_read_value_node) {
+               DBG("characteristic read callback already set.");
+               return BT_ERROR_ALREADY_DONE;
+       }
+
+       node_data = g_new0(struct char_read_value_cb_node, 1);
+       if (node_data == NULL) {
+               ERROR("no memory");
+               return BT_ERROR_OUT_OF_MEMORY;
+       }
+
+       node_data->cb = callback;
+       node_data->user_data = NULL;
+
+       char_read_value_node = node_data;
+
+       _bt_update_bluetooth_callbacks();
+
+       bluez_gatt_read_char_value(gatt_char);
+
+       return BT_SUCCESS;
+}
+
index 49e1249..acde62b 100644 (file)
@@ -3922,10 +3922,20 @@ int bt_gatt_get_characteristic_declaration(bt_gatt_attribute_h characteristic, c
 
 /**
  * @ingroup  CAPI_NETWORK_BLUETOOTH_GATT_MODULE
+ * @brief  Called when a characteristic value is written.
+ * @param[in]  characteristic  The attribute handle of characteristic
+ * @see bt_gatt_set_characteristic_value_request()
+ */
+typedef void (*bt_gatt_characteristic_write_cb) (bt_gatt_attribute_h handle);
+
+/**
+ * @ingroup  CAPI_NETWORK_BLUETOOTH_GATT_MODULE
  * @brief  Sets the value of characteristic.
  * @param[in]  characteristic  The attribute handle of characteristic
  * @param[in]  value  The value of characteristic (byte array)
  * @param[in]  value_length  The length of value
+ * @param[in]  request  Request type or command type
+ * @param[in]  callback  The result callback
  * @return  0 on success, otherwise a negative error value.
  * @retval  #BT_ERROR_NONE  Successful
  * @retval  #BT_ERROR_NOT_INITIALIZED  Not initialized
@@ -3935,7 +3945,8 @@ int bt_gatt_get_characteristic_declaration(bt_gatt_attribute_h characteristic, c
  * @see  bt_adapter_enable()
  * @see  bt_gatt_get_characteristic_declaration()
  */
-int bt_gatt_set_characteristic_value(bt_gatt_attribute_h characteristic, const unsigned char *value, int value_length);
+int bt_gatt_set_characteristic_value_request(bt_gatt_attribute_h characteristic, const unsigned char *value,
+                               int value_length, unsigned char request, bt_gatt_characteristic_write_cb callback);
 
 /**
 * @ingroup  CAPI_NETWORK_BLUETOOTH_GATT_MODULE
@@ -3963,6 +3974,34 @@ int bt_gatt_clone_attribute_handle(bt_gatt_attribute_h* clone, bt_gatt_attribute
 int bt_gatt_destroy_attribute_handle(bt_gatt_attribute_h handle);
 
 /**
+ * @ingroup  CAPI_NETWORK_BLUETOOTH_GATT_MODULE
+ * @brief  Called when a characteristic value is read.
+ * @param[in]  value  The value of characteristic (byte array)
+ * @param[in]  value_length  The length of value
+ * @param[in]  user_data  The user data passed from the foreach function
+ * @see bt_gatt_read_characteristic_value()
+ */
+typedef void (*bt_gatt_characteristic_read_cb) (unsigned char *value,
+                       int value_length, void *user_data);
+
+/**
+ * @ingroup  CAPI_NETWORK_BLUETOOTH_GATT_MODULE
+ * @brief  Reads the value of characteristic from remote device
+ * @param[in]  characteristic  The attribute handle of characteristic
+ * @param[in]  callback  The result callback
+ * @return     0 on success, otherwise a negative error value.
+ * @retval     #BT_ERROR_NONE  Successful
+ * @retval     #BT_ERROR_NOT_INITIALIZED  Not initialized
+ * @retval     #BT_ERROR_INVALID_PARAMETER  Invalid parameter
+ * @retval     #BT_ERROR_OPERATION_FAILED      Operation failed
+ * @pre  The state of local Bluetooth must be #BT_ADAPTER_ENABLED.
+ * @see  bt_adapter_enable()
+ * @see  bt_gatt_get_characteristic_declaration()
+ */
+int bt_gatt_read_characteristic_value(bt_gatt_attribute_h char_handle,
+               bt_gatt_characteristic_read_cb callback);
+
+/**
  * @ingroup  CAPI_NETWORK_BLUETOOTH_AGENT_MODULE
  * @brief  Register bluez agent.
  *
index 8b979a5..6953a51 100644 (file)
@@ -259,15 +259,80 @@ char **bluez_adapter_get_property_uuids(
 char *bluez_gatt_service_get_property_uuid(
                                struct _bluez_gatt_service *service);
 
+char *bluez_gatt_char_get_property_uuid(
+                               struct _bluez_gatt_char *characteristic);
+
+char *bluez_gatt_service_get_object_path(
+                               struct _bluez_gatt_service *service);
+
+char *bluez_gatt_char_get_object_path(
+                               struct _bluez_gatt_char *characteristic);
+
+char **bluez_gatt_char_property_get_flags(
+                               struct _bluez_gatt_char *characteristic);
+
+int bluez_gatt_char_get_property_notifying(
+                               struct _bluez_gatt_char *characteristic,
+                               gboolean *notifying);
+
+GByteArray *bluez_gatt_char_get_property_value(
+                               struct _bluez_gatt_char *characteristic);
+
 struct _bluez_gatt_service *bluez_gatt_get_service_by_path(
                                const char *service_path);
 
+struct _bluez_gatt_char *bluez_gatt_get_char_by_path(
+                               const char *gatt_char_path);
+
 GList *bluez_device_get_primary_services(
                                struct _bluez_device *device);
 
 char **bluez_gatt_service_get_property_includes(
                                struct _bluez_gatt_service *service);
 
+GList *bluez_gatt_service_get_chars(
+                               struct _bluez_gatt_service *service);
+
+GList *bluez_gatt_service_get_char_paths(
+                               struct _bluez_gatt_service *service);
+typedef void (*char_read_value_cb_t)(
+                               struct _bluez_gatt_char *characteristic,
+                               unsigned char *value_array,
+                               int value_length,
+                               gpointer user_data);
+
+void bluez_set_char_read_value_cb(char_read_value_cb_t cb,
+                                       gpointer user_data);
+
+void bluez_gatt_read_char_value(struct _bluez_gatt_char *characteristic);
+
+typedef void (*bluez_gatt_char_value_changed_cb_t)(
+                               bluez_gatt_char_t *characteristic,
+                               unsigned char *value_array,
+                               int value_length,
+                               gpointer user_data);
+
+void bluez_set_char_value_changed_cb(
+                               struct _bluez_gatt_char *characteristic,
+                               bluez_gatt_char_value_changed_cb_t cb,
+                               gpointer user_data);
+
+void bluez_unset_char_value_changed_cb(
+                               struct _bluez_gatt_char *characteristic);
+
+void bluez_gatt_write_char_value(struct _bluez_gatt_char *characteristic,
+                               const unsigned char *value,
+                               int value_length,
+                               unsigned char request);
+
+typedef void (*char_write_value_cb_t)(
+                               struct _bluez_gatt_char *characteristic,
+                               gpointer user_data);
+
+void bluez_set_char_write_value_cb(char_write_value_cb_t cb,
+                                       gpointer user_data);
+
+
 /* Returned Glist should not be freed and modified */
 const GList *bluez_adapter_get_devices_path(
                                struct _bluez_adapter *adapter);
index f7fbfcb..f79e0d8 100644 (file)
@@ -102,6 +102,10 @@ char **property_get_object_list(GDBusProxy *proxy,
                                const char *interface_name,
                                const char *property);
 
+GByteArray *property_get_bytestring(GDBusProxy *proxy,
+                                       const char *interface_name,
+                                       const char *property);
+
 void property_set_string(GDBusProxy *proxy,
                                const char *interface_name,
                                const char *property,
index 035dc7b..cb8ebd9 100644 (file)
@@ -207,6 +207,8 @@ struct _bluez_gatt_char {
        struct _bluez_object *parent;
        struct _gatt_char_head *head;
        struct _gatt_desc_head *desc_head;
+       bluez_gatt_char_value_changed_cb_t value_changed_cb;
+       gpointer value_changed_cb_data;
 };
 
 struct _bluez_gatt_desc {
@@ -251,7 +253,20 @@ static device_connect_cb_t dev_connect_cb;
 static gpointer dev_connect_data;
 static device_disconnect_cb_t dev_disconnect_cb;
 static gpointer dev_disconnect_data;
+static char_read_value_cb_t char_read_calue_cb;
+static gpointer char_read_data;
+static char_write_value_cb_t char_write_calue_cb;
+static gpointer char_write_data;
 
+struct gatt_char_read_notify {
+       struct _bluez_gatt_char *characteristic;
+       char_read_value_cb_t cb;
+};
+
+struct gatt_char_write_notify {
+       struct _bluez_gatt_char *characteristic;
+       char_write_value_cb_t cb;
+};
 static void free_discovery_device_info(
                adapter_device_discovery_info_t *discovery_device_info)
 {
@@ -842,15 +857,58 @@ static void gatt_service_properties_changed(GDBusProxy *proxy,
        g_free(properties);
 }
 
+static void handle_gatt_char_value_changed(GVariant *changed_properties,
+                               struct _bluez_gatt_char *charateristic)
+{
+       GVariant *variant_found;
+       GByteArray *gb_array = NULL;
+       GVariantIter *iter;
+       guchar g_value;
+       unsigned char *value_array;
+       int value_length;
+
+       DBG("");
+
+       variant_found = g_variant_lookup_value(changed_properties,
+                                               "Value",
+                                               G_VARIANT_TYPE_BYTESTRING);
+       if (!variant_found)
+               return;
+
+       g_variant_get(variant_found, "ay", &iter);
+
+       gb_array = g_byte_array_new();
+
+       while (g_variant_iter_loop(iter, "y", &g_value)) {
+               g_byte_array_append(gb_array, &g_value,
+                                       sizeof(unsigned char));
+       }
+
+       value_array = g_malloc0(gb_array->len * sizeof(unsigned char));
+
+       memcpy(value_array, gb_array->data, gb_array->len);
+       value_length = gb_array->len;
+
+       charateristic->value_changed_cb(charateristic,
+                               value_array, value_length,
+                               charateristic->value_changed_cb_data);
+
+       g_byte_array_unref(gb_array);
+}
+
 static void gatt_char_properties_changed(GDBusProxy *proxy,
                                        GVariant *changed_properties,
                                        GStrv *invalidated_properties,
                                        gpointer user_data)
 {
+       struct _bluez_gatt_char *charateristic = user_data;
        gchar *properties = g_variant_print(changed_properties, TRUE);
 
        DBG("properties %s", properties);
 
+       if (charateristic->value_changed_cb)
+               handle_gatt_char_value_changed(changed_properties, user_data);
+
        g_free(properties);
 }
 
@@ -1333,6 +1391,29 @@ char *bluez_gatt_service_get_property_uuid(
                                        GATT_SERVICE_IFACE, "UUID");
 }
 
+char *bluez_gatt_char_get_property_uuid(
+                               struct _bluez_gatt_char *characteristic)
+{
+       return property_get_string(characteristic->property_proxy,
+                                       GATT_CHR_IFACE, "UUID");
+}
+
+int bluez_gatt_char_get_property_notifying(
+                               struct _bluez_gatt_char *characteristic,
+                               gboolean *notifying)
+{
+       return property_get_boolean(characteristic->property_proxy,
+                                       GATT_CHR_IFACE,
+                                       "Notifying", notifying);
+}
+
+GByteArray *bluez_gatt_char_get_property_value(
+                               struct _bluez_gatt_char *characteristic)
+{
+       return property_get_bytestring(characteristic->property_proxy,
+                                       GATT_CHR_IFACE, "Value");
+}
+
 char *bluez_gatt_char_property_get_service(
                                struct _bluez_gatt_char *characteristic)
 {
@@ -1340,6 +1421,13 @@ char *bluez_gatt_char_property_get_service(
                                        GATT_CHR_IFACE, "Service");
 }
 
+char **bluez_gatt_char_property_get_flags(
+                               struct _bluez_gatt_char *characteristic)
+{
+       return property_get_string_list(characteristic->property_proxy,
+                                       GATT_CHR_IFACE, "Flags");
+}
+
 char *bluez_gatt_desc_property_get_char(
                                struct _bluez_gatt_desc *descriptor)
 {
@@ -1347,6 +1435,18 @@ char *bluez_gatt_desc_property_get_char(
                                GATT_DESCRIPTOR_IFACE, "Characteristic");
 }
 
+char *bluez_gatt_service_get_object_path(
+                               struct _bluez_gatt_service *service)
+{
+       return service->object_path;
+}
+
+char *bluez_gatt_char_get_object_path(
+                               struct _bluez_gatt_char *characteristic)
+{
+       return characteristic->object_path;
+}
+
 struct _bluez_gatt_service *bluez_gatt_get_service_by_path(
                                const char *service_path)
 {
@@ -1369,6 +1469,186 @@ struct _bluez_gatt_service *bluez_gatt_get_service_by_path(
        return service;
 }
 
+GList *bluez_gatt_service_get_char_paths(struct _bluez_gatt_service *service)
+{
+       struct _gatt_char_head *char_head = service->char_head;
+       GList *characteristics = NULL;
+
+       characteristics = g_hash_table_get_keys(char_head->gatt_char_hash);
+
+       return characteristics;
+}
+
+GList *bluez_gatt_service_get_chars(struct _bluez_gatt_service *service)
+{
+       struct _gatt_char_head *char_head = service->char_head;
+       GList *characteristics = NULL;
+
+       characteristics = g_hash_table_get_values(char_head->gatt_char_hash);
+
+       return characteristics;
+}
+
+struct _bluez_gatt_char *bluez_gatt_get_char_by_path(
+                               const char *gatt_char_path)
+{
+       struct _gatt_char_head *head = NULL;
+       struct _bluez_gatt_char *characteristic = NULL;
+       GList *list, *next;
+
+       for (list = g_list_first(gatt_char_head_list); list; list = next) {
+               head = list->data;
+
+               next = g_list_next(list);
+
+               characteristic = g_hash_table_lookup(head->gatt_char_hash,
+                                       (gconstpointer) gatt_char_path);
+
+               if (characteristic != NULL)
+                       break;
+       }
+
+       return characteristic;
+}
+
+static void char_read_value_callback(GObject *source_object,
+                                               GAsyncResult *res,
+                                               gpointer user_data)
+{
+       struct gatt_char_read_notify *notify = user_data;
+       struct _bluez_gatt_char *characteristic;
+       GVariant *ret;
+       GByteArray *gb_array = NULL;
+       GError *error = NULL;
+       GVariantIter *iter;
+       guchar g_value;
+       unsigned char *value_array;
+       int value_length;
+
+       DBG("");
+
+       characteristic = notify->characteristic;
+
+       ret = g_dbus_proxy_call_finish(characteristic->proxy,
+                                       res, &error);
+
+       if (ret == NULL)
+               DBG("error: %s", error->message);
+       else {
+               g_variant_get(ret, "(ay)", &iter);
+
+               gb_array = g_byte_array_new();
+
+               while (g_variant_iter_loop(iter, "y", &g_value)) {
+                       g_byte_array_append(gb_array, &g_value,
+                                               sizeof(unsigned char));
+               }
+
+               value_array = g_malloc0(gb_array->len * sizeof(unsigned char));
+
+               memcpy(value_array, gb_array->data, gb_array->len);
+               value_length = gb_array->len;
+
+               notify->cb(characteristic, value_array,
+                               value_length, char_read_data);
+
+               g_byte_array_unref(gb_array);
+               g_variant_unref(ret);
+       }
+
+       g_free(notify);
+}
+
+void bluez_gatt_read_char_value(struct _bluez_gatt_char *characteristic)
+{
+       struct gatt_char_read_notify *notify;
+
+       notify = g_try_new0(struct gatt_char_read_notify, 1);
+       if (notify == NULL) {
+               ERROR("no memory");
+               return;
+       }
+
+       notify->characteristic = characteristic;
+       notify->cb = char_read_calue_cb;
+
+       g_dbus_proxy_call(characteristic->proxy,
+                       "ReadValue", NULL,
+                       0, -1, NULL,
+                       char_read_value_callback, notify);
+}
+
+static void char_write_value_callback(GObject *source_object,
+                                               GAsyncResult *res,
+                                               gpointer user_data)
+{
+       struct gatt_char_write_notify *notify = user_data;
+       struct _bluez_gatt_char *characteristic;
+       GVariant *ret;
+       GError *error = NULL;
+
+       DBG("");
+
+       characteristic = notify->characteristic;
+
+       ret = g_dbus_proxy_call_finish(characteristic->proxy,
+                                       res, &error);
+
+       if (ret == NULL)
+               DBG("error: %s", error->message);
+       else {
+               notify->cb(characteristic, char_write_data);
+
+               g_variant_unref(ret);
+       }
+
+       g_free(notify);
+}
+
+void bluez_gatt_write_char_value(struct _bluez_gatt_char *characteristic,
+                               const unsigned char *value,
+                               int value_length,
+                               unsigned char request)
+{
+       GVariantBuilder *builder;
+       GVariant *parameters;
+       GError *error = NULL;
+       int i;
+
+       DBG("");
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+
+       for (i = 0; i < value_length; i++)
+               g_variant_builder_add(builder, "y", value[i]);
+
+       parameters = g_variant_new("(ay)", builder);
+
+       if (request) {
+               struct gatt_char_write_notify *notify;
+
+               notify = g_try_new0(struct gatt_char_write_notify, 1);
+               if (notify == NULL) {
+                       ERROR("no memory");
+                       return;
+               }
+
+               notify->characteristic = characteristic;
+               notify->cb = char_write_calue_cb;
+
+               g_dbus_proxy_call(characteristic->proxy,
+                               "WriteValue", parameters,
+                               0, -1, NULL,
+                               char_write_value_callback, notify);
+
+       } else {
+               g_dbus_proxy_call_sync(characteristic->proxy,
+                               "WriteValue", parameters,
+                               0, -1, NULL, &error);
+       }
+
+       g_variant_builder_unref(builder);
+}
 
 static void destruct_bluez_device(gpointer data)
 {
@@ -2033,6 +2313,40 @@ void bluez_set_device_disconnect_changed_cb(device_disconnect_cb_t cb,
        dev_disconnect_data = user_data;
 }
 
+void bluez_set_char_read_value_cb(char_read_value_cb_t cb,
+                                       gpointer user_data)
+{
+       char_read_calue_cb = cb;
+       char_read_data = user_data;
+}
+
+void bluez_set_char_write_value_cb(char_write_value_cb_t cb,
+                                       gpointer user_data)
+{
+       char_write_calue_cb = cb;
+       char_write_data = user_data;
+}
+
+void bluez_set_char_value_changed_cb(
+                               struct _bluez_gatt_char *characteristic,
+                               bluez_gatt_char_value_changed_cb_t cb,
+                               gpointer user_data)
+{
+       DBG("");
+
+       characteristic->value_changed_cb = cb;
+       characteristic->value_changed_cb_data = user_data;
+}
+
+void bluez_unset_char_value_changed_cb(
+                               struct _bluez_gatt_char *characteristic)
+{
+       DBG("");
+
+       characteristic->value_changed_cb = NULL;
+       characteristic->value_changed_cb_data = NULL;
+}
+
 void bluez_set_avrcp_target_cb(bluez_avrcp_target_cb_t cb,
                                                gpointer user_data)
 {
@@ -2242,7 +2556,9 @@ static void destruct_bluez_adapter(gpointer data)
        g_free(adapter->interface_name);
        g_free(adapter->object_path);
        g_object_unref(adapter->interface);
+       g_object_unref(adapter->media_proxy);
        g_object_unref(adapter->media_interface);
+       g_object_unref(adapter->netserver_proxy);
        g_object_unref(adapter->netserver_interface);
        g_object_unref(adapter->property_proxy);
        g_object_unref(adapter->proxy);
index 9da37f7..617a3fe 100644 (file)
@@ -241,6 +241,40 @@ char **property_get_object_list(GDBusProxy *proxy,
        return objv;
 }
 
+GByteArray *property_get_bytestring(GDBusProxy *proxy,
+                                       const char *interface_name,
+                                       const char *property)
+{
+       GVariant *bytv_v, *bytv_vv;
+       GByteArray *gb_array = NULL;
+       GError *error = NULL;
+       GVariantIter *byt_iter;
+       guchar g_value;
+
+       bytv_vv = g_dbus_proxy_call_sync(
+                       proxy, "Get",
+                       g_variant_new("(ss)", interface_name, property),
+                       0, -1, NULL, &error);
+
+       if (bytv_vv == NULL) {
+               WARN("no cached property %s", property);
+               return NULL;
+       }
+
+       g_variant_get(bytv_vv, "(v)", &bytv_v);
+
+       g_variant_get(bytv_v, "ay", &byt_iter);
+
+       gb_array = g_byte_array_new();
+
+       while (g_variant_iter_loop(byt_iter, "y", &g_value)) {
+               g_byte_array_append(gb_array, &g_value,
+                                       sizeof(unsigned char));
+       }
+
+       return gb_array;
+}
+
 void property_set_string(GDBusProxy *proxy,
                                        const char *interface_name,
                                        const char *property,
index 909fb2a..f7ea831 100644 (file)
@@ -2242,6 +2242,41 @@ static int gatt_foreach_primary_services(const char *p1, const char *p2)
        return 0;
 }
 
+
+static bool gatt_characteristics_callback(int result, int index, int total,
+                                       bt_gatt_attribute_h characteristic,
+                                       void *user_data)
+{
+       const char *gatt_char_handle = characteristic;
+
+       DBG("CAPI Result is %d", result);
+
+       DBG("The index %d Characteristic found", index);
+
+       DBG("Total characteristic is %d", total);
+
+       DBG("Characteristic found %s", gatt_char_handle);
+
+       return TRUE;
+}
+
+static int gatt_discover_characteristics(const char *p1, const char *p2)
+{
+       int ret;
+
+       if (p1 == NULL) {
+               ERROR("gatt characteristics must give the service_handle");
+               return 0;
+       }
+
+       ret = bt_gatt_discover_characteristics((bt_gatt_attribute_h)p1,
+                               gatt_characteristics_callback, NULL);
+
+       DBG("ret = %d", ret);
+
+       return 0;
+}
+
 static int gatt_get_service_uuid(const char *p1, const char *p2)
 {
        int ret;
@@ -2288,6 +2323,110 @@ static int gatt_foreach_included_services(const char *p1, const char *p2)
        return 0;
 }
 
+
+static void bt_gatt_char_changed_cb_test(bt_gatt_attribute_h characteristic,
+                                       unsigned char *value,
+                                       int value_length,
+                                       void *user_data)
+{
+       char *gatt_char_path = characteristic;
+       int i;
+
+       DBG("Characteristic handle %s", gatt_char_path);
+
+       for (i = 0; i < value_length; i++)
+               DBG("value %c", value[i]);
+
+       DBG("Value length %d", value_length);
+}
+
+static int gatt_set_characteristic_changed_cb(const char *p1, const char *p2)
+{
+       int ret;
+
+       if (p1 == NULL) {
+               ERROR("gatt set changed cb must give the service handle");
+               return 0;
+       }
+
+       ret = bt_gatt_set_characteristic_changed_cb(
+                               (bt_gatt_attribute_h)p1,
+                               bt_gatt_char_changed_cb_test,
+                               NULL);
+
+       DBG("ret = %d", ret);
+
+       return 0;
+}
+
+static int gatt_unset_characteristic_changed_cb(const char *p1, const char *p2)
+{
+       int ret;
+
+       if (p1 == NULL) {
+               ERROR("gatt unset changed cb must give the service handle");
+               return 0;
+       }
+
+       ret = bt_gatt_unset_characteristic_changed_cb((bt_gatt_attribute_h)p1);
+
+       DBG("ret = %d", ret);
+
+       return 0;
+}
+
+static int gatt_get_characteristic_declaration(const char *p1, const char *p2)
+{
+       int ret;
+       char *uuid = NULL;
+       unsigned char *value = NULL;
+       int value_length, i;
+
+       if (p1 == NULL) {
+               ERROR("gatt declaration must give the charateristic handle");
+               return 0;
+       }
+
+       ret = bt_gatt_get_characteristic_declaration((bt_gatt_attribute_h)p1,
+                               &uuid, &value, &value_length);
+
+       DBG("Characteristic uuid %s", uuid);
+
+       for (i = 0; i < value_length; i++)
+               DBG("value %c", value[i]);
+
+       DBG("Value length %d", value_length);
+
+       DBG("ret = %d", ret);
+
+       return 0;
+}
+
+void gatt_characteristic_write_callback(bt_gatt_attribute_h handle)
+{
+       char *gatt_char_path = handle;
+
+       DBG("Characteristic handle %s written successfully", gatt_char_path);
+}
+
+static int gatt_set_characteristic_value_request(const char *p1, const char *p2)
+{
+       unsigned char value[4] = { 0, 1, 2, 4};
+       int ret;
+
+       if (p1 == NULL) {
+               ERROR("gatt set value must give the charateristic handle");
+               return 0;
+       }
+
+       ret = bt_gatt_set_characteristic_value_request((bt_gatt_attribute_h)p1,
+                       value, 4, 1, gatt_characteristic_write_callback);
+
+       DBG("ret = %d", ret);
+
+       return 0;
+}
+
 static int gatt_clone_and_destroy_attribute_handle(const char *p1, const char *p2)
 {
        int ret;
@@ -2304,7 +2443,37 @@ static int gatt_clone_and_destroy_attribute_handle(const char *p1, const char *p
 
        ret = bt_gatt_destroy_attribute_handle(clone);
 
-       DBG("destroy handle ret = %d", ret);
+       DBG("destroy handle %s", p1);
+
+       DBG("ret = %d", ret);
+
+       return 0;
+}
+
+static void gatt_characteristic_read_callback(unsigned char *value,
+                       int value_length, void *user_data)
+{
+       int i;
+
+       for (i = 0; i < value_length; i++)
+               DBG("value %c", value[i]);
+
+       DBG("Value length %d", value_length);
+}
+
+static int gatt_read_characteristic_value(const char *p1, const char *p2)
+{
+       int ret;
+
+       if (p1 == NULL) {
+               ERROR("gatt read must give the charateristic handle");
+               return 0;
+       }
+
+       ret = bt_gatt_read_characteristic_value((bt_gatt_attribute_h)p1,
+                               gatt_characteristic_read_callback);
+
+       DBG("ret = %d", ret);
 
        return 0;
 }
@@ -2630,15 +2799,33 @@ struct {
        {"gatt_foreach_primary_services", gatt_foreach_primary_services,
                "Usage: gatt_foreach_primary_services\n\tgatt foreach primary services"},
 
+       {"gatt_discover_characteristics", gatt_discover_characteristics,
+               "Usage: gatt_discover_characteristics\n\tgatt_discover_characteristics"},
+
        {"gatt_get_service_uuid", gatt_get_service_uuid,
                "Usage: gatt_get_service_uuid\n\tgatt get service uuid"},
 
        {"gatt_foreach_included_services", gatt_foreach_included_services,
                "Usage: gatt_foreach_included_services\n\tgatt foreach included services"},
 
+       {"gatt_set_characteristic_changed_cb", gatt_set_characteristic_changed_cb,
+               "Usage: gatt_set_characteristic_changed_cb\n\tgatt set characteristic changed cb"},
+
+       {"gatt_unset_characteristic_changed_cb", gatt_unset_characteristic_changed_cb,
+               "Usage: gatt_unset_characteristic_changed_cb\n\tgatt unset characteristic changed cb"},
+
+       {"gatt_get_characteristic_declaration", gatt_get_characteristic_declaration,
+               "Usage: gatt_get_characteristic_declaration\n\tgatt get characteristic declaration"},
+
+       {"gatt_set_characteristic_value_request", gatt_set_characteristic_value_request,
+               "Usage: gatt_set_characteristic_value_request\n\tgatt set characteristic value request"},
+
        {"gatt_clone_and_destroy_attribute_handle", gatt_clone_and_destroy_attribute_handle,
                "Usage: gatt_clone_and_destroy_attribute_handle\n\tgatt clone and destroy attribute handle"},
 
+       {"gatt_read_characteristic_value", gatt_read_characteristic_value,
+               "Usage: gatt_read_characteristic_value\n\tgatt read characteristic value"},
+
        {"q", quit,
                "Usage: q\n\tQuit"},