2012-08-22 19:31:53

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 1/4] gatt: Add support for find included services

From: Jefferson Delfes <[email protected]>

Some services like HID over LE can reference another service using
included services.

See Vol 3, Part G, section 2.6.3 of Core specification for more
details.
---
attrib/gatt.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
attrib/gatt.h | 9 +++
2 files changed, 191 insertions(+)

diff --git a/attrib/gatt.c b/attrib/gatt.c
index 6880e2d..2f80b7e 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -45,6 +45,21 @@ struct discover_primary {
void *user_data;
};

+struct find_included {
+ GAttrib *attrib;
+ uint16_t end_handle;
+ GSList *includes;
+ int resolving; /* number of UUID128 resolves pending */
+ gboolean finished;
+ gatt_cb_t cb;
+ void *user_data;
+};
+
+struct included_uuid_resolve {
+ struct find_included *fi;
+ struct gatt_included *included;
+};
+
struct discover_char {
GAttrib *attrib;
bt_uuid_t *uuid;
@@ -61,6 +76,13 @@ static void discover_primary_free(struct discover_primary *dp)
g_free(dp);
}

+static void find_included_free(struct find_included *fi)
+{
+ g_slist_free_full(fi->includes, g_free);
+ g_attrib_unref(fi->attrib);
+ g_free(fi);
+}
+
static void discover_char_free(struct discover_char *dc)
{
g_slist_free_full(dc->characteristics, g_free);
@@ -248,6 +270,166 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
return g_attrib_send(attrib, 0, buf[0], buf, plen, cb, dp, NULL);
}

+static void resolve_included_uuid_cb(uint8_t status, const uint8_t *pdu,
+ uint16_t len, gpointer user_data)
+{
+ struct included_uuid_resolve *resolve = user_data;
+ struct find_included *fi = resolve->fi;
+ struct gatt_included *incl = resolve->included;
+ bt_uuid_t uuid;
+ unsigned int err = status;
+ size_t buflen;
+ uint8_t *buf;
+
+ if (err)
+ goto done;
+
+ buf = g_attrib_get_buffer(fi->attrib, &buflen);
+ if (dec_read_resp(pdu, len, buf, buflen) != 16) {
+ err = ATT_ECODE_IO;
+ goto done;
+ }
+
+ uuid = att_get_uuid128(buf);
+ bt_uuid_to_string(&uuid, incl->uuid, sizeof(incl->uuid));
+ fi->includes = g_slist_append(fi->includes, incl);
+ fi->resolving--;
+
+done:
+ if ((fi->finished && fi->resolving == 0) || err) {
+ fi->cb(fi->includes, err, fi->user_data);
+ find_included_free(fi);
+ }
+
+ if (err)
+ g_free(incl);
+
+ g_free(resolve);
+}
+
+static guint resolve_included_uuid(struct find_included *fi,
+ struct gatt_included *incl)
+{
+ size_t buflen;
+ uint8_t *buf = g_attrib_get_buffer(fi->attrib, &buflen);
+ guint16 oplen = enc_read_req(incl->range.start, buf, buflen);
+ struct included_uuid_resolve *resolve;
+
+ resolve = g_new0(struct included_uuid_resolve, 1);
+ resolve->fi = fi;
+ resolve->included = incl;
+
+ return g_attrib_send(fi->attrib, 0, buf[0], buf, oplen,
+ resolve_included_uuid_cb, resolve, NULL);
+}
+
+static struct gatt_included *included_from_buf(const uint8_t *buf, gsize buflen)
+{
+ struct gatt_included *incl = g_new0(struct gatt_included, 1);
+
+ incl->handle = att_get_u16(&buf[0]);
+ incl->range.start = att_get_u16(&buf[2]);
+ incl->range.end = att_get_u16(&buf[4]);
+
+ if (buflen == 8) {
+ bt_uuid_t uuid128;
+ bt_uuid_t uuid16 = att_get_uuid16(&buf[6]);
+
+ bt_uuid_to_uuid128(&uuid16, &uuid128);
+ bt_uuid_to_string(&uuid128, incl->uuid, sizeof(incl->uuid));
+ }
+
+ return incl;
+}
+
+static void find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
+ gpointer user_data);
+
+static guint call_find_included(struct find_included *fi, uint16_t start)
+{
+ bt_uuid_t uuid;
+ size_t buflen;
+ uint8_t *buf = g_attrib_get_buffer(fi->attrib, &buflen);
+ guint16 oplen;
+
+ bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
+ oplen = enc_read_by_type_req(start, fi->end_handle, &uuid,
+ buf, buflen);
+
+ return g_attrib_send(fi->attrib, 0, buf[0], buf, oplen,
+ find_included_cb, fi, NULL);
+}
+
+static void find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
+ gpointer user_data)
+{
+ struct find_included *fi = user_data;
+ uint16_t last_handle = fi->end_handle;
+ unsigned int err = status;
+ struct att_data_list *list;
+ int i;
+
+ if (err == ATT_ECODE_ATTR_NOT_FOUND)
+ err = 0;
+
+ if (status)
+ goto done;
+
+ list = dec_read_by_type_resp(pdu, len);
+ if (list == NULL) {
+ err = ATT_ECODE_IO;
+ goto done;
+ }
+
+ if (list->len != 6 || list->len != 8) {
+ att_data_list_free(list);
+ goto done;
+ }
+
+ for (i = 0; i < list->num; i++) {
+ struct gatt_included *incl;
+
+ incl = included_from_buf(list->data[i], list->len);
+ /* 128 bit UUID, needs resolving */
+ if (list->len == 6) {
+ fi->resolving++;
+ resolve_included_uuid(fi, incl);
+ continue;
+ }
+
+ fi->includes = g_slist_append(fi->includes, incl);
+ }
+
+ att_data_list_free(list);
+
+ if (last_handle != fi->end_handle) {
+ call_find_included(fi, last_handle + 1);
+ return;
+ }
+
+ fi->finished = TRUE;
+
+done:
+ if (fi->resolving == 0 || err) {
+ fi->cb(fi->includes, err, fi->user_data);
+ find_included_free(fi);
+ }
+}
+
+unsigned int gatt_find_included(GAttrib *attrib, uint16_t start, uint16_t end,
+ gatt_cb_t func, gpointer user_data)
+{
+ struct find_included *fi;
+
+ fi = g_new0(struct find_included, 1);
+ fi->attrib = g_attrib_ref(attrib);
+ fi->end_handle = end;
+ fi->cb = func;
+ fi->user_data = user_data;
+
+ return call_find_included(fi, start);
+}
+
static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
gpointer user_data)
{
diff --git a/attrib/gatt.h b/attrib/gatt.h
index a15e92f..dbec67f 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -61,6 +61,12 @@ struct gatt_primary {
struct att_range range;
};

+struct gatt_included {
+ char uuid[MAX_LEN_UUID_STR + 1];
+ uint16_t handle;
+ struct att_range range;
+};
+
struct gatt_char {
char uuid[MAX_LEN_UUID_STR + 1];
uint16_t handle;
@@ -71,6 +77,9 @@ struct gatt_char {
guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
gpointer user_data);

+unsigned int gatt_find_included(GAttrib *attrib, uint16_t start, uint16_t end,
+ gatt_cb_t func, gpointer user_data);
+
guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
bt_uuid_t *uuid, gatt_cb_t func,
gpointer user_data);
--
1.7.11.4



2012-08-22 19:31:56

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 4/4] attrib: Remove opcode parameter from g_attrib_send()

In all uses of g_attrib_send() the opcode of the command/event is
already clear because of the att.h functions used to build the ATT
PDU.
---
attrib/client.c | 3 +-
attrib/gatt.c | 56 ++++++++++++++++----------------------
attrib/gattrib.c | 9 ++++--
attrib/gattrib.h | 6 ++--
attrib/gatttool.c | 2 +-
attrib/interactive.c | 2 +-
profiles/gatt/gas.c | 2 +-
profiles/thermometer/thermometer.c | 3 +-
src/attrib-server.c | 3 +-
9 files changed, 39 insertions(+), 47 deletions(-)

diff --git a/attrib/client.c b/attrib/client.c
index c438d7c..48b88e6 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -298,8 +298,7 @@ static void events_handler(const uint8_t *pdu, uint16_t len,
case ATT_OP_HANDLE_IND:
opdu = g_attrib_get_buffer(gatt->attrib, &plen);
olen = enc_confirmation(opdu, plen);
- g_attrib_send(gatt->attrib, 0, opdu[0], opdu, olen,
- NULL, NULL, NULL);
+ g_attrib_send(gatt->attrib, 0, opdu, olen, NULL, NULL, NULL);
case ATT_OP_HANDLE_NOTIFY:
if (characteristic_set_value(chr, &pdu[3], len - 3) < 0)
DBG("Can't change Characteristic 0x%02x", handle);
diff --git a/attrib/gatt.c b/attrib/gatt.c
index 2f80b7e..457e798 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -163,8 +163,7 @@ static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
if (oplen == 0)
goto done;

- g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_by_uuid_cb,
- dp, NULL);
+ g_attrib_send(dp->attrib, 0, buf, oplen, primary_by_uuid_cb, dp, NULL);
return;

done:
@@ -229,7 +228,7 @@ static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
guint16 oplen = encode_discover_primary(end + 1, 0xffff, NULL,
buf, buflen);

- g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_all_cb,
+ g_attrib_send(dp->attrib, 0, buf, oplen, primary_all_cb,
dp, NULL);

return;
@@ -267,7 +266,7 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
} else
cb = primary_all_cb;

- return g_attrib_send(attrib, 0, buf[0], buf, plen, cb, dp, NULL);
+ return g_attrib_send(attrib, 0, buf, plen, cb, dp, NULL);
}

static void resolve_included_uuid_cb(uint8_t status, const uint8_t *pdu,
@@ -319,8 +318,8 @@ static guint resolve_included_uuid(struct find_included *fi,
resolve->fi = fi;
resolve->included = incl;

- return g_attrib_send(fi->attrib, 0, buf[0], buf, oplen,
- resolve_included_uuid_cb, resolve, NULL);
+ return g_attrib_send(fi->attrib, 0, buf, oplen,
+ resolve_included_uuid_cb, resolve, NULL);
}

static struct gatt_included *included_from_buf(const uint8_t *buf, gsize buflen)
@@ -356,8 +355,8 @@ static guint call_find_included(struct find_included *fi, uint16_t start)
oplen = enc_read_by_type_req(start, fi->end_handle, &uuid,
buf, buflen);

- return g_attrib_send(fi->attrib, 0, buf[0], buf, oplen,
- find_included_cb, fi, NULL);
+ return g_attrib_send(fi->attrib, 0, buf, oplen, find_included_cb,
+ fi, NULL);
}

static void find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
@@ -496,8 +495,8 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
if (oplen == 0)
return;

- g_attrib_send(dc->attrib, 0, buf[0], buf, oplen,
- char_discovered_cb, dc, NULL);
+ g_attrib_send(dc->attrib, 0, buf, oplen, char_discovered_cb,
+ dc, NULL);

return;
}
@@ -535,7 +534,7 @@ guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
dc->end = end;
dc->uuid = g_memdup(uuid, sizeof(bt_uuid_t));

- return g_attrib_send(attrib, 0, buf[0], buf, plen, char_discovered_cb,
+ return g_attrib_send(attrib, 0, buf, plen, char_discovered_cb,
dc, NULL);
}

@@ -551,8 +550,7 @@ guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
if (plen == 0)
return 0;

- return g_attrib_send(attrib, 0, ATT_OP_READ_BY_TYPE_REQ,
- buf, plen, func, user_data, NULL);
+ return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
}

struct read_long_data {
@@ -611,8 +609,7 @@ static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,

plen = enc_read_blob_req(long_read->handle, long_read->size - 1,
buf, buflen);
- id = g_attrib_send(long_read->attrib, long_read->id,
- ATT_OP_READ_BLOB_REQ, buf, plen,
+ id = g_attrib_send(long_read->attrib, long_read->id, buf, plen,
read_blob_helper, long_read, read_long_destroy);

if (id != 0) {
@@ -648,9 +645,8 @@ static void read_char_helper(guint8 status, const guint8 *rpdu,
long_read->size = rlen;

plen = enc_read_blob_req(long_read->handle, rlen - 1, buf, buflen);
- id = g_attrib_send(long_read->attrib, long_read->id,
- ATT_OP_READ_BLOB_REQ, buf, plen, read_blob_helper,
- long_read, read_long_destroy);
+ id = g_attrib_send(long_read->attrib, long_read->id, buf, plen,
+ read_blob_helper, long_read, read_long_destroy);

if (id != 0) {
g_atomic_int_inc(&long_read->ref);
@@ -686,12 +682,12 @@ guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
if (offset > 0) {
plen = enc_read_blob_req(long_read->handle, offset, buf,
buflen);
- id = g_attrib_send(attrib, 0, ATT_OP_READ_BLOB_REQ, buf, plen,
- read_blob_helper, long_read, read_long_destroy);
+ id = g_attrib_send(attrib, 0, buf, plen, read_blob_helper,
+ long_read, read_long_destroy);
} else {
plen = enc_read_req(handle, buf, buflen);
- id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, buf, plen,
- read_char_helper, long_read, read_long_destroy);
+ id = g_attrib_send(attrib, 0, buf, plen, read_char_helper,
+ long_read, read_long_destroy);
}

if (id == 0)
@@ -726,8 +722,7 @@ static guint execute_write(GAttrib *attrib, uint8_t flags,
if (plen == 0)
return 0;

- return g_attrib_send(attrib, 0, buf[0], buf, plen, func, user_data,
- NULL);
+ return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
}

static guint prepare_write(GAttrib *attrib, uint16_t handle, uint16_t offset,
@@ -776,7 +771,7 @@ static guint prepare_write(GAttrib *attrib, uint16_t handle, uint16_t offset,
if (plen == 0)
return 0;

- return g_attrib_send(attrib, 0, buf[0], buf, plen, prepare_write_cb,
+ return g_attrib_send(attrib, 0, buf, plen, prepare_write_cb,
user_data, NULL);
}

@@ -800,7 +795,7 @@ guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
plen = enc_write_cmd(handle, value, vlen, buf,
buflen);

- return g_attrib_send(attrib, 0, buf[0], buf, plen, func,
+ return g_attrib_send(attrib, 0, buf, plen, func,
user_data, NULL);
}

@@ -829,8 +824,7 @@ guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,

buf = g_attrib_get_buffer(attrib, &buflen);
plen = enc_mtu_req(mtu, buf, buflen);
- return g_attrib_send(attrib, 0, ATT_OP_MTU_REQ, buf, plen, func,
- user_data, NULL);
+ return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
}

guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
@@ -845,8 +839,7 @@ guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
if (plen == 0)
return 0;

- return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, buf, plen, func,
- user_data, NULL);
+ return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
}

guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
@@ -858,8 +851,7 @@ guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,

buf = g_attrib_get_buffer(attrib, &buflen);
plen = enc_write_cmd(handle, value, vlen, buf, buflen);
- return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, buf, plen, NULL,
- user_data, notify);
+ return g_attrib_send(attrib, 0, buf, plen, NULL, user_data, notify);
}

static sdp_data_t *proto_seq_find(sdp_list_t *proto_list)
diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index c91f5e9..f9652b3 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -475,12 +475,13 @@ GAttrib *g_attrib_new(GIOChannel *io)
return g_attrib_ref(attrib);
}

-guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
- const guint8 *pdu, guint16 len, GAttribResultFunc func,
- gpointer user_data, GDestroyNotify notify)
+guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
+ GAttribResultFunc func, gpointer user_data,
+ GDestroyNotify notify)
{
struct command *c;
GQueue *queue;
+ uint8_t opcode;

if (attrib->stale)
return 0;
@@ -489,6 +490,8 @@ guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
if (c == NULL)
return 0;

+ opcode = pdu[0];
+
c->opcode = opcode;
c->expected = opcode2expected(opcode);
c->pdu = g_malloc(len);
diff --git a/attrib/gattrib.h b/attrib/gattrib.h
index bcff039..bca966f 100644
--- a/attrib/gattrib.h
+++ b/attrib/gattrib.h
@@ -50,9 +50,9 @@ GIOChannel *g_attrib_get_channel(GAttrib *attrib);
gboolean g_attrib_set_destroy_function(GAttrib *attrib,
GDestroyNotify destroy, gpointer user_data);

-guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
- const guint8 *pdu, guint16 len, GAttribResultFunc func,
- gpointer user_data, GDestroyNotify notify);
+guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
+ GAttribResultFunc func, gpointer user_data,
+ GDestroyNotify notify);

gboolean g_attrib_cancel(GAttrib *attrib, guint id);
gboolean g_attrib_cancel_all(GAttrib *attrib);
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 416bb71..dea1fc4 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -105,7 +105,7 @@ static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
olen = enc_confirmation(opdu, plen);

if (olen > 0)
- g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
+ g_attrib_send(attrib, 0, opdu, olen, NULL, NULL, NULL);
}

static gboolean listen_start(gpointer user_data)
diff --git a/attrib/interactive.c b/attrib/interactive.c
index 01201ef..34417e0 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -133,7 +133,7 @@ static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
olen = enc_confirmation(opdu, plen);

if (olen > 0)
- g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
+ g_attrib_send(attrib, 0, opdu, olen, NULL, NULL, NULL);
}

static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
index e82513b..7211898 100644
--- a/profiles/gatt/gas.c
+++ b/profiles/gatt/gas.c
@@ -148,7 +148,7 @@ static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
/* Confirming indication received */
opdu = g_attrib_get_buffer(gas->attrib, &plen);
olen = enc_confirmation(opdu, plen);
- g_attrib_send(gas->attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
+ g_attrib_send(gas->attrib, 0, opdu, olen, NULL, NULL, NULL);

if (gas->changed.start == start && gas->changed.end == end)
return;
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
index 6652a41..696693a 100644
--- a/profiles/thermometer/thermometer.c
+++ b/profiles/thermometer/thermometer.c
@@ -1167,8 +1167,7 @@ static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
olen = enc_confirmation(opdu, plen);

if (olen > 0)
- g_attrib_send(t->attrib, 0, opdu[0], opdu, olen, NULL, NULL,
- NULL);
+ g_attrib_send(t->attrib, 0, opdu, olen, NULL, NULL, NULL);
}

static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 145fada..541a430 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -1032,8 +1032,7 @@ done:
length = enc_error_resp(ipdu[0], 0x0000, status, opdu,
channel->mtu);

- g_attrib_send(channel->attrib, 0, opdu[0], opdu, length,
- NULL, NULL, NULL);
+ g_attrib_send(channel->attrib, 0, opdu, length, NULL, NULL, NULL);
}

guint attrib_channel_attach(GAttrib *attrib)
--
1.7.11.4


2012-08-22 19:31:55

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 3/4] core: Add support for included services

Soon after the primary service discovery is complete, we do a included
services discovery for all found services and add each included service
to the 'services' list so they can be probe()'d as a normal profile.

This will also make these services to appear on the D-Bus object tree.
---
src/device.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 96 insertions(+), 13 deletions(-)

diff --git a/src/device.c b/src/device.c
index 7b44e27..360969c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -106,6 +106,12 @@ struct browse_req {
guint listener_id;
};

+struct included_search {
+ struct browse_req *req;
+ GSList *services;
+ GSList *current;
+};
+
struct attio_data {
guint id;
attio_connect_cb cfunc;
@@ -1877,21 +1883,10 @@ static void device_unregister_services(struct btd_device *device)
device->services = NULL;
}

-static void primary_cb(GSList *services, guint8 status, gpointer user_data)
+static void register_all_services(struct browse_req *req, GSList *services)
{
- struct browse_req *req = user_data;
struct btd_device *device = req->device;

- if (status) {
- if (req->msg) {
- DBusMessage *reply;
- reply = btd_error_failed(req->msg,
- att_ecode2str(status));
- g_dbus_send_message(req->conn, reply);
- }
- goto done;
- }
-
device_set_temporary(device, FALSE);

if (device->services)
@@ -1916,11 +1911,99 @@ static void primary_cb(GSList *services, guint8 status, gpointer user_data)

store_services(device);

-done:
device->browse = NULL;
browse_request_free(req);
}

+static int service_by_range_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_primary *prim = a;
+ const struct att_range *range = b;
+
+ return memcmp(&prim->range, range, sizeof(*range));
+}
+
+static void find_included_cb(GSList *includes, uint8_t status,
+ gpointer user_data)
+{
+ struct included_search *search = user_data;
+ struct btd_device *device = search->req->device;
+ struct gatt_primary *prim;
+ GSList *l;
+
+ if (includes == NULL)
+ goto done;
+
+ for (l = includes; l; l = l->next) {
+ struct gatt_included *incl = l->data;
+
+ if (g_slist_find_custom(search->services, &incl->range,
+ service_by_range_cmp))
+ continue;
+
+ prim = g_new0(struct gatt_primary, 1);
+ memcpy(prim->uuid, incl->uuid, sizeof(prim->uuid));
+ memcpy(&prim->range, &incl->range, sizeof(prim->range));
+
+ search->services = g_slist_append(search->services, prim);
+ }
+
+done:
+ search->current = search->current->next;
+ if (search->current == NULL) {
+ register_all_services(search->req, search->services);
+ g_slist_free(search->services);
+ g_free(search);
+ return;
+ }
+
+ prim = search->current->data;
+ gatt_find_included(device->attrib, prim->range.start, prim->range.end,
+ find_included_cb, search);
+}
+
+static void find_included_services(struct browse_req *req, GSList *services)
+{
+ struct btd_device *device = req->device;
+ struct included_search *search;
+ struct gatt_primary *prim;
+
+ if (services == NULL)
+ return;
+
+ search = g_new0(struct included_search, 1);
+ search->req = req;
+ search->services = g_slist_copy(services);
+ search->current = search->services;
+
+ prim = search->current->data;
+ gatt_find_included(device->attrib, prim->range.start, prim->range.end,
+ find_included_cb, search);
+
+}
+
+static void primary_cb(GSList *services, guint8 status, gpointer user_data)
+{
+ struct browse_req *req = user_data;
+
+ if (status) {
+ struct btd_device *device = req->device;
+
+ if (req->msg) {
+ DBusMessage *reply;
+ reply = btd_error_failed(req->msg,
+ att_ecode2str(status));
+ g_dbus_send_message(req->conn, reply);
+ }
+
+ device->browse = NULL;
+ browse_request_free(req);
+ return;
+ }
+
+ find_included_services(req, services);
+}
+
static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
{
struct att_callbacks *attcb = user_data;
--
1.7.11.4


2012-08-22 19:31:54

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 2/4] gatttool: Add "included" command

From: Jefferson Delfes <[email protected]>

New command to find included services in interactive mode.
---
attrib/interactive.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index 3e8a0d9..01201ef 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -209,6 +209,34 @@ static void primary_by_uuid_cb(GSList *ranges, guint8 status,
rl_forced_update_display();
}

+static void included_cb(GSList *includes, guint8 status, gpointer user_data)
+{
+ GSList *l;
+
+ if (status) {
+ printf("Find included services failed: %s\n",
+ att_ecode2str(status));
+ goto done;
+ }
+
+ if (includes == NULL) {
+ printf("No included services found for this range\n");
+ goto done;
+ }
+
+ printf("\n");
+ for (l = includes; l; l = l->next) {
+ struct gatt_included *incl = l->data;
+ printf("handle: 0x%04x, start handle: 0x%04x, "
+ "end handle: 0x%04x uuid: %s\n",
+ incl->handle, incl->range.start,
+ incl->range.end, incl->uuid);
+ }
+
+done:
+ rl_forced_update_display();
+}
+
static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
{
GSList *l;
@@ -426,6 +454,36 @@ static int strtohandle(const char *src)
return dst;
}

+static void cmd_included(int argcp, char **argvp)
+{
+ int start = 0x0001;
+ int end = 0xffff;
+
+ if (conn_state != STATE_CONNECTED) {
+ printf("Command failed: disconnected\n");
+ return;
+ }
+
+ if (argcp > 1) {
+ start = strtohandle(argvp[1]);
+ if (start < 0) {
+ printf("Invalid start handle: %s\n", argvp[1]);
+ return;
+ }
+ end = start;
+ }
+
+ if (argcp > 2) {
+ end = strtohandle(argvp[2]);
+ if (end < 0) {
+ printf("Invalid end handle: %s\n", argvp[2]);
+ return;
+ }
+ }
+
+ gatt_find_included(attrib, start, end, included_cb, NULL);
+}
+
static void cmd_char(int argcp, char **argvp)
{
int start = 0x0001;
@@ -752,6 +810,8 @@ static struct {
"Disconnect from a remote device" },
{ "primary", cmd_primary, "[UUID]",
"Primary Service Discovery" },
+ { "included", cmd_included, "[start hnd [end hnd]]",
+ "Find Included Services" },
{ "characteristics", cmd_char, "[start hnd [end hnd [UUID]]]",
"Characteristics Discovery" },
{ "char-desc", cmd_char_desc, "[start hnd] [end hnd]",
--
1.7.11.4