aboutsummaryrefslogtreecommitdiffstats
path: root/attrib/client.c
diff options
context:
space:
mode:
authorClaudio Takahasi <claudio.takahasi@openbossa.org>2011-07-12 17:28:40 -0300
committerJohan Hedberg <johan.hedberg@intel.com>2011-07-27 10:32:17 +0300
commita0988557ea6d7c3e2bbf7a6f88dcabe9a25090d5 (patch)
tree6d8d93cb9043f9ddc887c43d026b55960203c583 /attrib/client.c
parent3177d97eeda04adfadc47ddfd6e17277ceafe861 (diff)
downloadbluez-a0988557ea6d7c3e2bbf7a6f88dcabe9a25090d5.tar.gz
bluez-a0988557ea6d7c3e2bbf7a6f88dcabe9a25090d5.tar.xz
bluez-a0988557ea6d7c3e2bbf7a6f88dcabe9a25090d5.zip
On demand connection for characteristics discovery
In the Generic Attribute API, when DiscoverCharacteristics is called ATT connection should be requested if the link is not up. A query list is required to control when the link can be disconnected since the discover finishes after receiving all caracteristic declarations.
Diffstat (limited to 'attrib/client.c')
-rw-r--r--attrib/client.c84
1 files changed, 75 insertions, 9 deletions
diff --git a/attrib/client.c b/attrib/client.c
index 962cdb7b..03d161ed 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -62,6 +62,12 @@ struct format {
guint16 desc;
} __attribute__ ((packed));
+struct query {
+ DBusMessage *msg;
+ guint attioid;
+ GSList *list;
+};
+
struct gatt_service {
struct btd_device *dev;
struct att_primary *prim;
@@ -72,6 +78,7 @@ struct gatt_service {
char *path;
GSList *chars;
GSList *watchers;
+ struct query *query;
};
struct characteristic {
@@ -91,7 +98,6 @@ struct characteristic {
struct query_data {
struct gatt_service *gatt;
struct characteristic *chr;
- DBusMessage *msg;
uint16_t handle;
};
@@ -576,6 +582,27 @@ static void store_attribute(struct gatt_service *gatt, uint16_t handle,
g_free(str);
}
+static void query_list_append(struct gatt_service *gatt, struct query_data *data)
+{
+ struct query *query = gatt->query;
+
+ query->list = g_slist_append(query->list, data);
+}
+
+static void query_list_remove(struct gatt_service *gatt, struct query_data *data)
+{
+ struct query *query = gatt->query;
+
+ query->list = g_slist_remove(query->list, data);
+ if (query->list != NULL)
+ return;
+
+ btd_device_remove_attio_callback(gatt->dev, query->attioid);
+ g_free(query);
+
+ gatt->query = NULL;
+}
+
static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
@@ -606,6 +633,7 @@ static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
}
}
+ query_list_remove(gatt, current);
g_free(current);
}
@@ -631,6 +659,7 @@ static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
(void *) chr->format, sizeof(*chr->format));
done:
+ query_list_remove(gatt, current);
g_free(current);
}
@@ -655,6 +684,7 @@ static void update_char_value(guint8 status, const guint8 *pdu,
}
}
+ query_list_remove(gatt, current);
g_free(current);
}
@@ -708,9 +738,11 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
qfmt->handle = handle;
if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) {
+ query_list_append(gatt, qfmt);
gatt_read_char(gatt->attrib, handle, 0, update_char_desc,
qfmt);
} else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) {
+ query_list_append(gatt, qfmt);
gatt_read_char(gatt->attrib, handle, 0,
update_char_format, qfmt);
} else
@@ -719,6 +751,7 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
att_data_list_free(list);
done:
+ query_list_remove(gatt, current);
g_free(current);
}
@@ -732,6 +765,8 @@ static void update_all_chars(gpointer data, gpointer user_data)
qdesc->gatt = gatt;
qdesc->chr = chr;
+ query_list_append(gatt, qdesc);
+
gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
qdesc);
@@ -739,6 +774,8 @@ static void update_all_chars(gpointer data, gpointer user_data)
qvalue->gatt = gatt;
qvalue->chr = chr;
+ query_list_append(gatt, qvalue);
+
gatt_read_char(gatt->attrib, chr->handle, 0, update_char_value, qvalue);
}
@@ -758,7 +795,7 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
const char *str = att_ecode2str(status);
DBG("Discover all characteristics failed: %s", str);
- reply = btd_error_failed(current->msg, str);
+ reply = btd_error_failed(gatt->query->msg, str);
goto fail;
}
@@ -795,7 +832,7 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
g_slist_foreach(gatt->chars, register_characteristic, gatt->path);
- reply = dbus_message_new_method_return(current->msg);
+ reply = dbus_message_new_method_return(gatt->query->msg);
dbus_message_iter_init_append(reply, &iter);
@@ -815,25 +852,54 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
fail:
g_dbus_send_message(gatt->conn, reply);
+ query_list_remove(gatt, current);
g_free(current);
}
+static void send_discover(GAttrib *attrib, gpointer user_data)
+{
+ struct query_data *qchr = user_data;
+ struct gatt_service *gatt = qchr->gatt;
+ struct att_primary *prim = gatt->prim;
+
+ gatt->attrib = attrib;
+
+ gatt_discover_char(gatt->attrib, prim->start, prim->end, NULL,
+ char_discovered_cb, qchr);
+}
+
+static void cancel_discover(gpointer user_data)
+{
+ struct query_data *qchr = user_data;
+ struct gatt_service *gatt = qchr->gatt;
+
+ gatt->attrib = NULL;
+}
+
static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg,
void *data)
{
struct gatt_service *gatt = data;
- struct att_primary *prim = gatt->prim;
+ struct query *query;
struct query_data *qchr;
- if (gatt->attrib == NULL)
- return btd_error_not_connected(msg);
+ if (gatt->query)
+ return btd_error_busy(msg);
+
+ query = g_new0(struct query, 1);
qchr = g_new0(struct query_data, 1);
qchr->gatt = gatt;
- qchr->msg = dbus_message_ref(msg);
- gatt_discover_char(gatt->attrib, prim->start, prim->end, NULL,
- char_discovered_cb, qchr);
+ query->msg = dbus_message_ref(msg);
+ query->attioid = btd_device_add_attio_callback(gatt->dev,
+ send_discover,
+ cancel_discover,
+ qchr);
+
+ gatt->query = query;
+
+ query_list_append(gatt, qchr);
return NULL;
}