summaryrefslogtreecommitdiff
path: root/src/gatt-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gatt-client.c')
-rw-r--r--src/gatt-client.c231
1 files changed, 209 insertions, 22 deletions
diff --git a/src/gatt-client.c b/src/gatt-client.c
index ab8081cc..08e50220 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -61,6 +61,9 @@ struct btd_gatt_client {
struct queue *services;
struct queue *all_notify_clients;
+#ifdef __TIZEN_PATCH__
+ guint wait_charcs_id;
+#endif
};
struct service {
@@ -381,20 +384,19 @@ static void desc_read_cb(bool success, uint8_t att_ecode,
struct async_dbus_op *op = user_data;
struct descriptor *desc = op->data;
struct service *service = desc->chrc->service;
+ DBusMessage *reply;
- if (!success) {
- DBusMessage *reply = create_gatt_dbus_error(op->msg, att_ecode);
-
- desc->read_id = 0;
- g_dbus_send_message(btd_get_dbus_connection(), reply);
- return;
- }
+ if (!success)
+ goto fail;
if (!op->offset)
gatt_db_attribute_reset(desc->attr);
- gatt_db_attribute_write(desc->attr, op->offset, value, length, 0, NULL,
- write_descriptor_cb, desc);
+ if (!gatt_db_attribute_write(desc->attr, op->offset, value, length, 0,
+ NULL, write_descriptor_cb, desc)) {
+ error("Failed to store attribute");
+ goto fail;
+ }
/*
* If the value length is exactly MTU-1, then we may not have read the
@@ -414,10 +416,21 @@ static void desc_read_cb(bool success, uint8_t att_ecode,
return;
}
+ /* Read the stored data from db */
+ if (!gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_op_cb, op)) {
+ error("Failed to read database");
+ goto fail;
+ }
+
desc->read_id = 0;
- /* Read the stored data from db */
- gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_op_cb, op);
+ return;
+
+fail:
+ reply = create_gatt_dbus_error(op->msg, att_ecode);
+ desc->read_id = 0;
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+ return;
}
static DBusMessage *descriptor_read_value(DBusConnection *conn,
@@ -845,20 +858,19 @@ static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
struct async_dbus_op *op = user_data;
struct characteristic *chrc = op->data;
struct service *service = chrc->service;
+ DBusMessage *reply;
- if (!success) {
- DBusMessage *reply = create_gatt_dbus_error(op->msg, att_ecode);
-
- chrc->read_id = 0;
- g_dbus_send_message(btd_get_dbus_connection(), reply);
- return ;
- }
+ if (!success)
+ goto fail;
if (!op->offset)
gatt_db_attribute_reset(chrc->attr);
- gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0, NULL,
- write_characteristic_cb, chrc);
+ if (!gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0,
+ NULL, write_characteristic_cb, chrc)) {
+ error("Failed to store attribute");
+ goto fail;
+ }
/*
* If the value length is exactly MTU-1, then we may not have read the
@@ -881,7 +893,17 @@ static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
chrc->read_id = 0;
/* Read the stored data from db */
- gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_op_cb, op);
+ if (!gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_op_cb, op)) {
+ error("Failed to read database");
+ goto fail;
+ }
+
+ return;
+
+fail:
+ reply = create_gatt_dbus_error(op->msg, att_ecode);
+ chrc->read_id = 0;
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
}
static DBusMessage *characteristic_read_value(DBusConnection *conn,
@@ -1062,7 +1084,18 @@ static DBusMessage *characteristic_write_value_by_type(DBusConnection *conn,
supported = true;
chrc->write_id = bt_gatt_client_write_without_response(gatt,
chrc->value_handle,
- chrc->props & BT_GATT_CHRC_PROP_AUTH,
+ false,
+ value, value_len);
+ if (chrc->write_id) {
+ chrc->write_id = 0;
+ return dbus_message_new_method_return(msg);
+ }
+ } else if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_AUTH) {
+ DBG("BT_GATT_CHRC_PROP_AUTH");
+ supported = true;
+ chrc->write_id = bt_gatt_client_write_without_response(gatt,
+ chrc->value_handle,
+ true,
value, value_len);
if (chrc->write_id) {
chrc->write_id = 0;
@@ -1190,6 +1223,65 @@ static bool match_notify_sender(const void *a, const void *b)
return strcmp(client->owner, sender) == 0;
}
+#ifdef GATT_NO_RELAY
+struct char_value {
+ uint8_t *data;
+ uint8_t len;
+ char *chrc_path;
+};
+
+static void emit_value_changed_signal_to_dest(gpointer data, gpointer user_data)
+{
+ dbus_int32_t result = 0;
+ struct notify_client *notify_client = data;
+ struct char_value *value = user_data;
+
+ g_dbus_emit_signal_to_dest(btd_get_dbus_connection(),
+ notify_client->owner, value->chrc_path,
+ GATT_CHARACTERISTIC_IFACE, "GattValueChanged",
+ DBUS_TYPE_INT32, &result,
+ DBUS_TYPE_STRING, &value->chrc_path,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &value->data, value->len,
+ DBUS_TYPE_INVALID);
+}
+#endif
+
+#ifdef __TIZEN_PATCH__
+void gatt_characteristic_value_changed(void *data, uint8_t data_len, void *user_data)
+{
+ struct characteristic *chrc = user_data;
+ char *chrc_path = strdup(chrc->path);
+#ifdef GATT_NO_RELAY
+ struct char_value *value;
+
+ value = new0(struct char_value, 1);
+ value->len = data_len;
+ value->data = data;
+ value->chrc_path = chrc_path;
+
+ queue_foreach(chrc->notify_clients,
+ emit_value_changed_signal_to_dest, value);
+
+
+ if (value)
+ g_free(value);
+#else
+ dbus_int32_t result = 0;
+
+ g_dbus_emit_signal(btd_get_dbus_connection(), chrc->path,
+ GATT_CHARACTERISTIC_IFACE, "GattValueChanged",
+ DBUS_TYPE_INT32, &result,
+ DBUS_TYPE_STRING, &chrc_path,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, data_len,
+ DBUS_TYPE_INVALID);
+#endif
+
+ if (chrc_path)
+ free(chrc_path);
+
+}
+#endif
+
static void notify_cb(uint16_t value_handle, const uint8_t *value,
uint16_t length, void *user_data)
{
@@ -1206,6 +1298,8 @@ static void notify_cb(uint16_t value_handle, const uint8_t *value,
#ifdef __TIZEN_PATCH__
gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
notify_characteristic_cb, chrc);
+
+ gatt_characteristic_value_changed(value, length, chrc);
#else
gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
write_characteristic_cb, chrc);
@@ -1448,6 +1542,15 @@ static const GDBusMethodTable characteristic_methods[] = {
#endif
};
+#ifdef __TIZEN_PATCH__
+static const GDBusSignalTable characteristic_signals[] = {
+ { GDBUS_SIGNAL("GattValueChanged",
+ GDBUS_ARGS({ "Result", "i"},
+ { "Characteristic Path","s"},
+ { "GattData", "ay"})) },
+};
+#endif
+
static void characteristic_free(void *data)
{
struct characteristic *chrc = data;
@@ -1486,11 +1589,29 @@ static struct characteristic *characteristic_create(
chrc->service = service;
+#ifndef __TIZEN_PATCH__
gatt_db_attribute_get_char_data(attr, &chrc->handle,
&chrc->value_handle,
&chrc->props, &uuid);
+#else
+ if (!gatt_db_attribute_get_char_data(attr, &chrc->handle,
+ &chrc->value_handle,
+ &chrc->props, &uuid)) {
+ queue_destroy(chrc->descs, NULL);
+ queue_destroy(chrc->notify_clients, NULL);
+ free(chrc);
+ return NULL;
+ }
+#endif
+
chrc->attr = gatt_db_get_attribute(service->client->db,
chrc->value_handle);
+ if (!chrc->attr) {
+ error("Attribute 0x%04x not found", chrc->value_handle);
+ characteristic_free(chrc);
+ return NULL;
+ }
+
bt_uuid_to_uuid128(&uuid, &chrc->uuid);
chrc->path = g_strdup_printf("%s/char%04x", service->path,
@@ -1498,7 +1619,11 @@ static struct characteristic *characteristic_create(
if (!g_dbus_register_interface(btd_get_dbus_connection(), chrc->path,
GATT_CHARACTERISTIC_IFACE,
+#ifdef __TIZEN_PATCH__
+ characteristic_methods, characteristic_signals,
+#else
characteristic_methods, NULL,
+#endif
characteristic_properties,
chrc, characteristic_free)) {
error("Unable to register GATT characteristic with handle "
@@ -1933,6 +2058,10 @@ void btd_gatt_client_destroy(struct btd_gatt_client *client)
if (!client)
return;
+#ifdef __TIZEN_PATCH__
+ if (client->wait_charcs_id)
+ g_source_remove(client->wait_charcs_id);
+#endif
queue_destroy(client->services, unregister_service);
queue_destroy(client->all_notify_clients, NULL);
bt_gatt_client_unref(client->gatt);
@@ -1972,6 +2101,50 @@ fail:
notify_client_free(notify_client);
}
+#ifdef __TIZEN_PATCH__
+static void check_chrcs_ready(void *data, void *user_data)
+{
+ gboolean *chrcs_ready = user_data;
+ struct service *service = data;
+
+ /*
+ * Return FALSE if charcteristics are not ready or if there is
+ * any pending request to read char. extended properties exist.
+ */
+ if (!service->chrcs_ready ||
+ !queue_isempty(service->pending_ext_props))
+ *chrcs_ready = FALSE;
+}
+
+static gboolean check_all_chrcs_ready(gpointer user_data)
+{
+ struct btd_gatt_client *client = user_data;
+ gboolean all_chrcs_ready = TRUE;
+ static int count = 0;
+
+ queue_foreach(client->services, check_chrcs_ready, &all_chrcs_ready);
+
+ /*
+ * By adding below condition, forcing to call check_chrcs_ready()
+ * function to check whether all char./extended properties are ready.
+ * Above function would be called max. for 20 times (Assuming more
+ * no of services). Emit signal only when all characteristics are read.
+ */
+ if (all_chrcs_ready == FALSE && count < 20) {
+ count++;
+ return TRUE;
+ }
+
+ device_set_gatt_connected(client->device, TRUE);
+
+ client->wait_charcs_id = 0;
+
+ count = 0;
+
+ return FALSE;
+}
+#endif
+
void btd_gatt_client_ready(struct btd_gatt_client *client)
{
struct bt_gatt_client *gatt;
@@ -1995,6 +2168,20 @@ void btd_gatt_client_ready(struct btd_gatt_client *client)
if (queue_isempty(client->services)) {
DBG("Exporting services");
create_services(client);
+#ifdef __TIZEN_PATCH__
+ /*
+ * In case of more number of services and services having
+ * characteristics extended properties; GattConnected signal
+ * should be emitted only after all the characteristics are ready.
+ * This piece of code checks all the characteristics periodically and
+ * emit the signal if characteristics are ready.
+ */
+ if (client->wait_charcs_id > 0)
+ g_source_remove(client->wait_charcs_id);
+
+ client->wait_charcs_id = g_timeout_add(100,
+ check_all_chrcs_ready, client);
+#endif
return;
}