#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;
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;
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 =
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,
}
}
+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;
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)
bt_service_init = TRUE;
+ char_changed_node_list = NULL;
+
setup_bluez_lib();
return BT_SUCCESS;
node = g_new0(struct device_auth_cb_node, 1);
if (node == NULL) {
- ERROR("no memeroy");
+ ERROR("no memory");
return BT_ERROR_OPERATION_FAILED;
}
return BT_ERROR_OPERATION_FAILED;
primary_services = bluez_device_get_primary_services(device);
-
if (primary_services == NULL)
return BT_ERROR_OPERATION_FAILED;
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("");
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;
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;
}
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)
{
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;
+}
+
/**
* @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
* @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
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.
*
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);
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,
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 {
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)
{
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);
}
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)
{
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)
{
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)
{
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)
{
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)
{
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);
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,
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;
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;
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;
}
{"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"},