These patches address the concerns raised by Vinicius and Claudio.
They are based on a rebase as of:
commit 3fd5fa3890e3db3857f212ef6a187f7744d07cba
Author: Claudio Takahasi <[email protected]>
Date: Mon Jan 3 18:45:54 2011 -0300
--
Brian Gix
[email protected]
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Hi Brian,
On Thu, Jan 06, 2011, Brian Gix wrote:
> These patches address the concerns raised by Vinicius and Claudio.
>
> They are based on a rebase as of:
>
> commit 3fd5fa3890e3db3857f212ef6a187f7744d07cba
> Author: Claudio Takahasi <[email protected]>
> Date: Mon Jan 3 18:45:54 2011 -0300
Thanks. Both patches have been pushed upstream.
Johan
Fix gatt_read_char() to support long Attribute Values by recognizing
that results longer that 21 octets may include data beyond
what has been returned with the first read. Extra data is
obtained by issuing READ_BLOB requests until either a
result is returned shorter than 22 octets, or an error
is recieved indicating that no further data is available.
The API for this function has not changed.
---
attrib/gatt.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 128 insertions(+), 2 deletions(-)
diff --git a/attrib/gatt.c b/attrib/gatt.c
index 320759f..ae33211 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -97,15 +97,141 @@ guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
pdu, plen, func, user_data, NULL);
}
+struct read_long_data {
+ GAttrib *attrib;
+ GAttribResultFunc func;
+ gpointer user_data;
+ guint8 *buffer;
+ guint16 size;
+ guint16 handle;
+ guint id;
+ gint ref;
+};
+
+static void read_long_destroy(gpointer user_data)
+{
+ struct read_long_data *long_read = user_data;
+
+ if (g_atomic_int_dec_and_test(&long_read->ref) == FALSE)
+ return;
+
+ if (long_read->buffer != NULL)
+ g_free(long_read->buffer);
+
+ g_free(long_read);
+}
+
+static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
+ gpointer user_data)
+{
+ struct read_long_data *long_read = user_data;
+ uint8_t pdu[ATT_DEFAULT_MTU];
+ guint8 *tmp;
+ guint16 plen;
+ guint id;
+
+ if (status != 0 || rlen == 1) {
+ status = 0;
+ goto done;
+ }
+
+ tmp = g_try_realloc(long_read->buffer, long_read->size + rlen - 1);
+
+ if (tmp == NULL) {
+ status = ATT_ECODE_INSUFF_RESOURCES;
+ goto done;
+ }
+
+ memcpy(&tmp[long_read->size], &rpdu[1], rlen - 1);
+ long_read->buffer = tmp;
+ long_read->size += rlen - 1;
+
+ if (rlen < ATT_DEFAULT_MTU)
+ goto done;
+
+ plen = enc_read_blob_req(long_read->handle, long_read->size - 1,
+ pdu, sizeof(pdu));
+ id = g_attrib_send(long_read->attrib, long_read->id,
+ ATT_OP_READ_BLOB_REQ, pdu, plen,
+ read_blob_helper, long_read, read_long_destroy);
+
+ if (id != 0) {
+ g_atomic_int_inc(&long_read->ref);
+ return;
+ }
+
+ status = ATT_ECODE_IO;
+
+done:
+ long_read->func(status, long_read->buffer, long_read->size,
+ long_read->user_data);
+}
+
+static void read_char_helper(guint8 status, const guint8 *rpdu,
+ guint16 rlen, gpointer user_data)
+{
+ struct read_long_data *long_read = user_data;
+ uint8_t pdu[ATT_DEFAULT_MTU];
+ guint16 plen;
+ guint id;
+
+ if (status != 0 || rlen < ATT_DEFAULT_MTU)
+ goto done;
+
+ long_read->buffer = g_malloc(rlen);
+
+ if (long_read->buffer == NULL)
+ goto done;
+
+ memcpy(long_read->buffer, rpdu, rlen);
+ long_read->size = rlen;
+
+ plen = enc_read_blob_req(long_read->handle, rlen - 1, pdu, sizeof(pdu));
+ id = g_attrib_send(long_read->attrib, long_read->id,
+ ATT_OP_READ_BLOB_REQ, pdu, plen, read_blob_helper,
+ long_read, read_long_destroy);
+
+ if (id != 0) {
+ g_atomic_int_inc(&long_read->ref);
+ return;
+ }
+
+ status = ATT_ECODE_IO;
+
+done:
+ long_read->func(status, rpdu, rlen, long_read->user_data);
+}
+
guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
gpointer user_data)
{
uint8_t pdu[ATT_DEFAULT_MTU];
guint16 plen;
+ guint id;
+ struct read_long_data *long_read;
+
+ long_read = g_try_new0(struct read_long_data, 1);
+
+ if (long_read == NULL)
+ return 0;
+
+ long_read->attrib = attrib;
+ long_read->func = func;
+ long_read->user_data = user_data;
+ long_read->handle = handle;
plen = enc_read_req(handle, pdu, sizeof(pdu));
- return g_attrib_send(attrib, 0, ATT_OP_READ_REQ, pdu, plen, func,
- user_data, NULL);
+ id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, pdu, plen,
+ read_char_helper, long_read, read_long_destroy);
+
+ if (id == 0)
+ g_free(long_read);
+ else {
+ g_atomic_int_inc(&long_read->ref);
+ long_read->id = id;
+ }
+
+ return id;
}
guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
--
1.7.1
--
Brian Gix
[email protected]
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Overall purpose of change is to enable a GATT procedure to be
executed atomically, even if it requires multiple ATT
request/response transactions.
Fix g_attrib_send() to include an ID parameter, if the pkt to
be sent should be added to the Head of the pkt queue. If the
ID is Zero, legacy functionality is maintained, and the pkt will
be added at the tail of the queuer, and a new ID will be generated,
and returned to the caller. If ID is non-zero, the pkt will be
added to the head of the queue, with the ID value requested, which
will also be returned to the caller.
Fix received_data() to not service the send queue until after the
received data has been processed by calling the cmd->func()
callback, to allow the callback to insert another pkt on the head
of the queue.
Fix all callers of g_attrib_send() to include new parameter.
---
attrib/client.c | 2 +-
attrib/gatt.c | 12 ++++++------
attrib/gattrib.c | 22 +++++++++++++++-------
attrib/gattrib.h | 7 ++++---
attrib/gatttool.c | 2 +-
src/attrib-server.c | 2 +-
6 files changed, 28 insertions(+), 19 deletions(-)
diff --git a/attrib/client.c b/attrib/client.c
index 644cd62..7f72348 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -295,7 +295,7 @@ static void events_handler(const uint8_t *pdu, uint16_t len,
switch (pdu[0]) {
case ATT_OP_HANDLE_IND:
olen = enc_confirmation(opdu, sizeof(opdu));
- g_attrib_send(gatt->attrib, opdu[0], opdu, olen,
+ g_attrib_send(gatt->attrib, 0, opdu[0], opdu, olen,
NULL, NULL, NULL);
case ATT_OP_HANDLE_NOTIFY:
if (characteristic_set_value(chr, &pdu[3], len - 3) < 0)
diff --git a/attrib/gatt.c b/attrib/gatt.c
index bca8b49..320759f 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -68,7 +68,7 @@ guint gatt_discover_primary(GAttrib *attrib, uint16_t start, uint16_t end,
if (plen == 0)
return 0;
- return g_attrib_send(attrib, op, pdu, plen, func, user_data, NULL);
+ return g_attrib_send(attrib, 0, op, pdu, plen, func, user_data, NULL);
}
guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
@@ -93,7 +93,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, ATT_OP_READ_BY_TYPE_REQ,
+ return g_attrib_send(attrib, 0, ATT_OP_READ_BY_TYPE_REQ,
pdu, plen, func, user_data, NULL);
}
@@ -104,7 +104,7 @@ guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
guint16 plen;
plen = enc_read_req(handle, pdu, sizeof(pdu));
- return g_attrib_send(attrib, ATT_OP_READ_REQ, pdu, plen, func,
+ return g_attrib_send(attrib, 0, ATT_OP_READ_REQ, pdu, plen, func,
user_data, NULL);
}
@@ -115,7 +115,7 @@ guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
guint16 plen;
plen = enc_write_req(handle, value, vlen, pdu, sizeof(pdu));
- return g_attrib_send(attrib, ATT_OP_WRITE_REQ, pdu, plen, func,
+ return g_attrib_send(attrib, 0, ATT_OP_WRITE_REQ, pdu, plen, func,
user_data, NULL);
}
@@ -129,7 +129,7 @@ guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
if (plen == 0)
return 0;
- return g_attrib_send(attrib, ATT_OP_FIND_INFO_REQ, pdu, plen, func,
+ return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, pdu, plen, func,
user_data, NULL);
}
@@ -140,6 +140,6 @@ guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
guint16 plen;
plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
- return g_attrib_send(attrib, ATT_OP_WRITE_CMD, pdu, plen, NULL,
+ return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, pdu, plen, NULL,
user_data, notify);
}
diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index dd7b1d7..779a471 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -294,6 +294,7 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
uint8_t buf[512], status;
gsize len;
GIOStatus iostat;
+ gboolean qempty;
if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
attrib->read_watch = 0;
@@ -341,8 +342,7 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
status = 0;
done:
- if (attrib->queue && g_queue_is_empty(attrib->queue) == FALSE)
- wake_up_sender(attrib);
+ qempty = attrib->queue == NULL || g_queue_is_empty(attrib->queue);
if (cmd) {
if (cmd->func)
@@ -351,6 +351,9 @@ done:
command_destroy(cmd);
}
+ if (!qempty)
+ wake_up_sender(attrib);
+
return TRUE;
}
@@ -376,9 +379,9 @@ GAttrib *g_attrib_new(GIOChannel *io)
return g_attrib_ref(attrib);
}
-guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
- guint16 len, GAttribResultFunc func,
- gpointer user_data, GDestroyNotify notify)
+guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
+ const guint8 *pdu, guint16 len, GAttribResultFunc func,
+ gpointer user_data, GDestroyNotify notify)
{
struct command *c;
@@ -394,9 +397,14 @@ guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
c->func = func;
c->user_data = user_data;
c->notify = notify;
- c->id = ++attrib->next_cmd_id;
- g_queue_push_tail(attrib->queue, c);
+ if (id) {
+ c->id = id;
+ g_queue_push_head(attrib->queue, c);
+ } else {
+ c->id = ++attrib->next_cmd_id;
+ g_queue_push_tail(attrib->queue, c);
+ }
if (g_queue_get_length(attrib->queue) == 1)
wake_up_sender(attrib);
diff --git a/attrib/gattrib.h b/attrib/gattrib.h
index 5c50bc9..f25208d 100644
--- a/attrib/gattrib.h
+++ b/attrib/gattrib.h
@@ -52,9 +52,10 @@ gboolean g_attrib_set_disconnect_function(GAttrib *attrib,
gboolean g_attrib_set_destroy_function(GAttrib *attrib,
GDestroyNotify destroy, gpointer user_data);
-guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
- guint16 len, GAttribResultFunc func,
- gpointer user_data, GDestroyNotify notify);
+guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
+ 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 a234e36..a6f92db 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -272,7 +272,7 @@ static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
olen = enc_confirmation(opdu, sizeof(opdu));
if (olen > 0)
- g_attrib_send(attrib, opdu[0], opdu, olen, NULL, NULL, NULL);
+ g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
}
static gboolean listen_start(gpointer user_data)
diff --git a/src/attrib-server.c b/src/attrib-server.c
index cbc01ee..aee2ace 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -694,7 +694,7 @@ done:
if (status)
length = enc_error_resp(ipdu[0], 0x0000, status, opdu, channel->mtu);
- g_attrib_send(channel->attrib, opdu[0], opdu, length,
+ g_attrib_send(channel->attrib, 0, opdu[0], opdu, length,
NULL, NULL, NULL);
}
--
1.7.1
--
Brian Gix
[email protected]
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
SGkgQnJpYW4sCgpPbiBUdWUsIEphbiA0LCAyMDExIGF0IDk6MDEgUE0sIEJyaWFuIEdpeCA8Ymdp
eEBjb2RlYXVyb3JhLm9yZz4gd3JvdGU6Cj4gRml4IGdhdHRfcmVhZF9jaGFyKCkgdG8gc3VwcG9y
dCBsb25nIEF0dHJpYnV0ZSBWYWx1ZXMgYnkgcmVjb2duaXppbmcKPiDCoCDCoCDCoCDCoHRoYXQg
cmVzdWx0cyBsb25nZXIgdGhhdCAyMSBvY3RldHMgbWF5IGluY2x1ZGUgZGF0YSBiZXlvbmQKPiDC
oCDCoCDCoCDCoHdoYXQgaGFzIGJlZW4gcmV0dXJuZWQgd2l0aCB0aGUgZmlyc3QgcmVhZC4gRXh0
cmEgZGF0YSBpcwo+IMKgIMKgIMKgIMKgb2J0YWluZWQgYnkgaXNzdWluZyBSRUFEX0JMT0IgcmVx
dWVzdHMgdW50aWwgZWl0aGVyIGEKPiDCoCDCoCDCoCDCoHJlc3VsdCBpcyByZXR1cm5lZCBzaG9y
dGVyIHRoYW4gMjIgb2N0ZXRzLCBvciBhbiBlcnJvcgo+IMKgIMKgIMKgIMKgaXMgcmVjaWV2ZWQg
aW5kaWNhdGluZyB0aGF0IG5vIGZ1cnRoZXIgZGF0YSBpcyBhdmFpbGFibGUuCj4gwqAgwqAgwqAg
wqBUaGUgQVBJIGZvciB0aGlzIGZ1bmN0aW9uIGhhcyBub3QgY2hhbmdlZC4KTm8gdGFicyBoZXJl
LgoKPiAtLS0KPiDCoGF0dHJpYi9nYXR0LmMgfCDCoDEzNCArKysrKysrKysrKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKy0KPiDCoDEgZmlsZXMgY2hhbmdlZCwg
MTMyIGluc2VydGlvbnMoKyksIDIgZGVsZXRpb25zKC0pCj4KPiBkaWZmIC0tZ2l0IGEvYXR0cmli
L2dhdHQuYyBiL2F0dHJpYi9nYXR0LmMKPiBpbmRleCAzMjA3NTlmLi4zMDRjMmIxIDEwMDY0NAo+
IC0tLSBhL2F0dHJpYi9nYXR0LmMKPiArKysgYi9hdHRyaWIvZ2F0dC5jCj4gQEAgLTk3LDE1ICs5
NywxNDUgQEAgZ3VpbnQgZ2F0dF9yZWFkX2NoYXJfYnlfdXVpZChHQXR0cmliICphdHRyaWIsIHVp
bnQxNl90IHN0YXJ0LCB1aW50MTZfdCBlbmQsCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBwZHUsIHBsZW4sIGZ1bmMsIHVzZXJfZGF0
YSwgTlVMTCk7Cj4gwqB9Cj4KPiArc3RydWN0IHJlYWRfbG9uZ19kYXRhIHsKPiArIMKgIMKgIMKg
IEdBdHRyaWIgKmF0dHJpYjsKPiArIMKgIMKgIMKgIEdBdHRyaWJSZXN1bHRGdW5jIGZ1bmM7Cj4g
KyDCoCDCoCDCoCBncG9pbnRlciB1c2VyX2RhdGE7Cj4gKyDCoCDCoCDCoCBndWludDggKmJ1ZmZl
cjsKPiArIMKgIMKgIMKgIGd1aW50MTYgc2l6ZTsKPiArIMKgIMKgIMKgIGd1aW50MTYgaGFuZGxl
Owo+ICsgwqAgwqAgwqAgZ3VpbnQgaWQ7Cj4gKyDCoCDCoCDCoCBndWludDggcmVmOwo+ICt9Owo+
ICsKPiArc3RhdGljIHZvaWQgcmVhZF9sb25nX2Rlc3Ryb3koZ3BvaW50ZXIgdXNlcl9kYXRhKQo+
ICt7Cj4gKyDCoCDCoCDCoCBzdHJ1Y3QgcmVhZF9sb25nX2RhdGEgKmxvbmdfcmVhZCA9IHVzZXJf
ZGF0YTsKPiArCj4gKyDCoCDCoCDCoCBpZiAoLS1sb25nX3JlYWQtPnJlZikKPiArIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIHJldHVybjsKdXNlIGdfYXRvbWljX2ludF9kZWNfYW5kX3Rlc3QKCj4gKwo+
ICsgwqAgwqAgwqAgaWYgKGxvbmdfcmVhZC0+YnVmZmVyICE9IE5VTEwpCj4gKyDCoCDCoCDCoCDC
oCDCoCDCoCDCoCBnX2ZyZWUobG9uZ19yZWFkLT5idWZmZXIpOwo+ICsKPiArIMKgIMKgIMKgIGdf
ZnJlZShsb25nX3JlYWQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCByZWFkX2Jsb2JfaGVscGVy
KGd1aW50OCBzdGF0dXMsIGNvbnN0IGd1aW50OCAqcnBkdSwgZ3VpbnQxNiBybGVuLAo+ICsgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgZ3BvaW50ZXIgdXNlcl9kYXRhKQo+ICt7Cj4gKyDCoCDCoCDC
oCBzdHJ1Y3QgcmVhZF9sb25nX2RhdGEgKmxvbmdfcmVhZCA9IHVzZXJfZGF0YTsKPiArIMKgIMKg
IMKgIHVpbnQ4X3QgcGR1W0FUVF9ERUZBVUxUX01UVV07Cj4gKyDCoCDCoCDCoCBndWludDggKnRt
cDsKPiArIMKgIMKgIMKgIGd1aW50MTYgcGxlbjsKPiArIMKgIMKgIMKgIGd1aW50IGlkOwo+ICsK
PiArIMKgIMKgIMKgIGlmIChzdGF0dXMgPT0gQVRUX0VDT0RFX0FUVFJfTk9UX0xPTkcgfHwKPiAr
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IHN0YXR1cyA9PSBBVFRfRUNPREVfSU5WQUxJRF9PRkZTRVQpIHsKPiArIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIHN0YXR1cyA9IDA7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBnb3RvIGRvbmU7Cj4g
KyDCoCDCoCDCoCB9Cj4gKwo+ICsgwqAgwqAgwqAgaWYgKHN0YXR1cyAhPSAwIHx8IHJsZW4gPT0g
MSkKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGdvdG8gZG9uZTsKPiArCj4gKyDCoCDCoCDCoCB0
bXAgPSBnX3RyeV9yZWFsbG9jKGxvbmdfcmVhZC0+YnVmZmVyLCBsb25nX3JlYWQtPnNpemUgKyBy
bGVuIC0gMSk7Cj4gKwo+ICsgwqAgwqAgwqAgaWYgKHRtcCA9PSBOVUxMKSB7Cj4gKyDCoCDCoCDC
oCDCoCDCoCDCoCDCoCBzdGF0dXMgPSBBVFRfRUNPREVfSU5TVUZGX1JFU09VUkNFUzsKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIGdvdG8gZG9uZTsKPiArIMKgIMKgIMKgIH0KPiArCj4gKyDCoCDC
oCDCoCBtZW1jcHkoJnRtcFtsb25nX3JlYWQtPnNpemVdLCAmcnBkdVsxXSwgcmxlbiAtIDEpOwo+
ICsgwqAgwqAgwqAgbG9uZ19yZWFkLT5idWZmZXIgPSB0bXA7Cj4gKyDCoCDCoCDCoCBsb25nX3Jl
YWQtPnNpemUgKz0gcmxlbiAtIDE7Ck1heWJlIHVzaW5nIEdCeXRlQXJyYXkgd2lsbCBtYWtlIHlv
dXIgY29kZSBzaW1wbGVyLgoKPiArCj4gKyDCoCDCoCDCoCBpZiAocmxlbiA8IEFUVF9ERUZBVUxU
X01UVSkKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGdvdG8gZG9uZTsKCkZvciBub3cgaXQgaXMg
ZmluZSBmb3IgdGVzdGluZy4gQnV0IGl0IG5lZWRzIHRvIGJlIGZpeGVkIGxhdGVyLCBNVFUKY2Fu
IGNoYW5nZSBhZnRlciB0aGUgTVRVIG5lZ290aWF0aW9uLCB0aGUgbmV3IHZhbHVlIGNvdWxkIGJl
IGFjY2Vzc2VkCnVzaW5nIGEgZ2V0c29ja29wdCwgcGFzc2luZyB0aGUgdmFsdWUgdG8gZ2F0dF8q
IGZ1bmN0aW9ucyBvciB1c2luZyBhCkdBdHRyaWIgZnVuY3Rpb24uCgo+ICsKPiArIMKgIMKgIMKg
IHBsZW4gPSBlbmNfcmVhZF9ibG9iX3JlcShsb25nX3JlYWQtPmhhbmRsZSwgbG9uZ19yZWFkLT5z
aXplIC0gMSwKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHBkdSwgc2l6ZW9mKHBkdSkpOwo+
ICsgwqAgwqAgwqAgaWQgPSBnX2F0dHJpYl9zZW5kKGxvbmdfcmVhZC0+YXR0cmliLCBsb25nX3Jl
YWQtPmlkLAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
QVRUX09QX1JFQURfQkxPQl9SRVEsIHBkdSwgcGxlbiwKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHJlYWRfYmxvYl9oZWxwZXIsIGxvbmdfcmVhZCwgcmVh
ZF9sb25nX2Rlc3Ryb3kpOwo+ICsKPiArIMKgIMKgIMKgIGlmIChpZCAhPSAwKSB7Cj4gKyDCoCDC
oCDCoCDCoCDCoCDCoCDCoCBsb25nX3JlYWQtPnJlZisrOwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgcmV0dXJuOwo+ICsgwqAgwqAgwqAgfQo+ICsKPiArIMKgIMKgIMKgIHN0YXR1cyA9IEFUVF9F
Q09ERV9JTzsKPiArCj4gK2RvbmU6Cj4gKyDCoCDCoCDCoCBsb25nX3JlYWQtPmZ1bmMoc3RhdHVz
LCBsb25nX3JlYWQtPmJ1ZmZlciwgbG9uZ19yZWFkLT5zaXplLAo+ICsgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgbG9uZ19yZWFkLT51c2VyX2RhdGEpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBy
ZWFkX2NoYXJfaGVscGVyKGd1aW50OCBzdGF0dXMsIGNvbnN0IGd1aW50OCAqcnBkdSwKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGd1
aW50MTYgcmxlbiwgZ3BvaW50ZXIgdXNlcl9kYXRhKQo+ICt7Cj4gKyDCoCDCoCDCoCBzdHJ1Y3Qg
cmVhZF9sb25nX2RhdGEgKmxvbmdfcmVhZCA9IHVzZXJfZGF0YTsKPiArIMKgIMKgIMKgIHVpbnQ4
X3QgcGR1W0FUVF9ERUZBVUxUX01UVV07Cj4gKyDCoCDCoCDCoCBndWludDE2IHBsZW47Cj4gKyDC
oCDCoCDCoCBndWludCBpZDsKPiArCj4gKyDCoCDCoCDCoCBpZiAoc3RhdHVzICE9IDAgfHwgcmxl
biA8IEFUVF9ERUZBVUxUX01UVSkKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGdvdG8gZG9uZTsK
PiArCj4gKyDCoCDCoCDCoCBsb25nX3JlYWQtPmJ1ZmZlciA9IGdfbWFsbG9jKHJsZW4pOwo+ICsK
PiArIMKgIMKgIMKgIGlmIChsb25nX3JlYWQtPmJ1ZmZlciA9PSBOVUxMKQo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgZ290byBkb25lOwo+ICsKPiArIMKgIMKgIMKgIG1lbWNweShsb25nX3JlYWQt
PmJ1ZmZlciwgcnBkdSwgcmxlbik7Cj4gKyDCoCDCoCDCoCBsb25nX3JlYWQtPnNpemUgPSBybGVu
Owo+ICsKPiArIMKgIMKgIMKgIHBsZW4gPSBlbmNfcmVhZF9ibG9iX3JlcShsb25nX3JlYWQtPmhh
bmRsZSwgcmxlbiAtIDEsIHBkdSwgc2l6ZW9mKHBkdSkpOwo+ICsgwqAgwqAgwqAgaWQgPSBnX2F0
dHJpYl9zZW5kKGxvbmdfcmVhZC0+YXR0cmliLCBsb25nX3JlYWQtPmlkLAo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgQVRUX09QX1JFQURfQkxPQl9SRVEsIHBkdSwgcGxlbiwg
cmVhZF9ibG9iX2hlbHBlciwKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIGxv
bmdfcmVhZCwgcmVhZF9sb25nX2Rlc3Ryb3kpOwo+ICsKPiArIMKgIMKgIMKgIGlmIChpZCAhPSAw
KSB7Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBsb25nX3JlYWQtPnJlZisrOwpVc2UgZ19hdG9t
aWNfaW50X3ggZnVuY3Rpb24KCgo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgcmV0dXJuOwo+ICsg
wqAgwqAgwqAgfQo+ICsKPiArIMKgIMKgIMKgIHN0YXR1cyA9IEFUVF9FQ09ERV9JTzsKPiArCj4g
K2RvbmU6Cj4gKyDCoCDCoCDCoCBsb25nX3JlYWQtPmZ1bmMoc3RhdHVzLCBycGR1LCBybGVuLCBs
b25nX3JlYWQtPnVzZXJfZGF0YSk7Cj4gK30KPiArCj4gwqBndWludCBnYXR0X3JlYWRfY2hhcihH
QXR0cmliICphdHRyaWIsIHVpbnQxNl90IGhhbmRsZSwgR0F0dHJpYlJlc3VsdEZ1bmMgZnVuYywK
PiDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGdwb2ludGVyIHVzZXJfZGF0YSkKPiDCoHsKPiDC
oCDCoCDCoCDCoHVpbnQ4X3QgcGR1W0FUVF9ERUZBVUxUX01UVV07Cj4gwqAgwqAgwqAgwqBndWlu
dDE2IHBsZW47Cj4gKyDCoCDCoCDCoCBndWludCBpZDsKPiArIMKgIMKgIMKgIHN0cnVjdCByZWFk
X2xvbmdfZGF0YSAqbG9uZ19yZWFkOwo+ICsKPiArIMKgIMKgIMKgIGxvbmdfcmVhZCA9IGdfdHJ5
X25ldzAoc3RydWN0IHJlYWRfbG9uZ19kYXRhLCAxKTsKPiArCj4gKyDCoCDCoCDCoCBpZiAobG9u
Z19yZWFkID09IE5VTEwpCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCByZXR1cm4gMDsKPiArCj4g
KyDCoCDCoCDCoCBsb25nX3JlYWQtPmF0dHJpYiA9IGF0dHJpYjsKPiArIMKgIMKgIMKgIGxvbmdf
cmVhZC0+ZnVuYyA9IGZ1bmM7Cj4gKyDCoCDCoCDCoCBsb25nX3JlYWQtPnVzZXJfZGF0YSA9IHVz
ZXJfZGF0YTsKPiArIMKgIMKgIMKgIGxvbmdfcmVhZC0+aGFuZGxlID0gaGFuZGxlOwo+Cj4gwqAg
wqAgwqAgwqBwbGVuID0gZW5jX3JlYWRfcmVxKGhhbmRsZSwgcGR1LCBzaXplb2YocGR1KSk7Cj4g
LSDCoCDCoCDCoCByZXR1cm4gZ19hdHRyaWJfc2VuZChhdHRyaWIsIDAsIEFUVF9PUF9SRUFEX1JF
USwgcGR1LCBwbGVuLCBmdW5jLAo+IC0gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdXNlcl9kYXRh
LCBOVUxMKTsKPiArIMKgIMKgIMKgIGlkID0gZ19hdHRyaWJfc2VuZChhdHRyaWIsIDAsIEFUVF9P
UF9SRUFEX1JFUSwgcGR1LCBwbGVuLAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgcmVhZF9jaGFyX2hlbHBlciwgbG9uZ19yZWFkLCByZWFkX2xvbmdfZGVz
dHJveSk7Cj4gKwo+ICsgwqAgwqAgwqAgaWYgKGlkID09IDApCj4gKyDCoCDCoCDCoCDCoCDCoCDC
oCDCoCBnX2ZyZWUobG9uZ19yZWFkKTsKPiArIMKgIMKgIMKgIGVsc2Ugewo+ICsgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgbG9uZ19yZWFkLT5yZWYrKzsKc2FtZSBoZXJlLgoKQ2xhdWRpbwo+ICsgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgbG9uZ19yZWFkLT5pZCA9IGlkOwo+ICsgwqAgwqAgwqAgfQo+ICsK
PiArIMKgIMKgIMKgIHJldHVybiBpZDsKPiDCoH0KPgo+IMKgZ3VpbnQgZ2F0dF93cml0ZV9jaGFy
KEdBdHRyaWIgKmF0dHJpYiwgdWludDE2X3QgaGFuZGxlLCB1aW50OF90ICp2YWx1ZSwKPiAtLQo+
IDEuNy4xCj4gLS0KPiBCcmlhbiBHaXgKPiBiZ2l4QGNvZGVhdXJvcmEub3JnCj4gRW1wbG95ZWUg
b2YgUXVhbGNvbW0gSW5ub3ZhdGlvbiBDZW50ZXIsIEluYy4KPiBRdWFsY29tbSBJbm5vdmF0aW9u
IENlbnRlciwgSW5jLiBpcyBhIG1lbWJlciBvZiBDb2RlIEF1cm9yYSBGb3J1bQo+Cg==
Hi Brian,
On Tue, Jan 4, 2011 at 9:01 PM, Brian Gix <[email protected]> wrote:
> Overall purpose of change is to enable a GATT procedure to be
> executed atomically, even if it requires multiple ATT
> request/response transactions.
>
> Fix g_attrib_send() to include an ID parameter, if the pkt to
> be sent should be added to the Head of the pkt queue.
> If the ID is Zero, legacy functionality is maintained,
> and the pkt will be added at the tail of the queuer, and
> a new ID will be generated, and returned to the caller. If
> ID is non-zero, the pkt will be added to the head of the
> queue, with the ID value requested, which will also be
> returned to the caller.
>
> Fix received_data() to not service the send queue until after the
> received data has been processed by calling the cmd->func()
> callback, to allow the callback to insert another pkt on
> the head of the queue.
>
We don't use tabs in the comments.
> Fix all callers of g_attrib_send() to include new parameter.
> ---
> attrib/client.c | 2 +-
> attrib/gatt.c | 12 ++++++------
> attrib/gattrib.c | 22 +++++++++++++++-------
> attrib/gattrib.h | 7 ++++---
> attrib/gatttool.c | 2 +-
> src/attrib-server.c | 2 +-
> 6 files changed, 28 insertions(+), 19 deletions(-)
>
> diff --git a/attrib/client.c b/attrib/client.c
> index 10bbf7d..4301082 100644
> --- a/attrib/client.c
> +++ b/attrib/client.c
> @@ -295,7 +295,7 @@ static void events_handler(const uint8_t *pdu, uint16_t len,
> switch (pdu[0]) {
> case ATT_OP_HANDLE_IND:
> olen = enc_confirmation(opdu, sizeof(opdu));
> - g_attrib_send(gatt->attrib, opdu[0], opdu, olen,
> + g_attrib_send(gatt->attrib, 0, opdu[0], opdu, olen,
> NULL, NULL, NULL);
> case ATT_OP_HANDLE_NOTIFY:
> if (characteristic_set_value(chr, &pdu[3], len - 3) < 0)
> diff --git a/attrib/gatt.c b/attrib/gatt.c
> index bca8b49..320759f 100644
> --- a/attrib/gatt.c
> +++ b/attrib/gatt.c
> @@ -68,7 +68,7 @@ guint gatt_discover_primary(GAttrib *attrib, uint16_t start, uint16_t end,
> if (plen == 0)
> return 0;
>
> - return g_attrib_send(attrib, op, pdu, plen, func, user_data, NULL);
> + return g_attrib_send(attrib, 0, op, pdu, plen, func, user_data, NULL);
> }
>
> guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
> @@ -93,7 +93,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, ATT_OP_READ_BY_TYPE_REQ,
> + return g_attrib_send(attrib, 0, ATT_OP_READ_BY_TYPE_REQ,
> pdu, plen, func, user_data, NULL);
> }
>
> @@ -104,7 +104,7 @@ guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
> guint16 plen;
>
> plen = enc_read_req(handle, pdu, sizeof(pdu));
> - return g_attrib_send(attrib, ATT_OP_READ_REQ, pdu, plen, func,
> + return g_attrib_send(attrib, 0, ATT_OP_READ_REQ, pdu, plen, func,
> user_data, NULL);
> }
>
> @@ -115,7 +115,7 @@ guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
> guint16 plen;
>
> plen = enc_write_req(handle, value, vlen, pdu, sizeof(pdu));
> - return g_attrib_send(attrib, ATT_OP_WRITE_REQ, pdu, plen, func,
> + return g_attrib_send(attrib, 0, ATT_OP_WRITE_REQ, pdu, plen, func,
> user_data, NULL);
> }
>
> @@ -129,7 +129,7 @@ guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
> if (plen == 0)
> return 0;
>
> - return g_attrib_send(attrib, ATT_OP_FIND_INFO_REQ, pdu, plen, func,
> + return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, pdu, plen, func,
> user_data, NULL);
> }
>
> @@ -140,6 +140,6 @@ guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
> guint16 plen;
>
> plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
> - return g_attrib_send(attrib, ATT_OP_WRITE_CMD, pdu, plen, NULL,
> + return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, pdu, plen, NULL,
> user_data, notify);
> }
> diff --git a/attrib/gattrib.c b/attrib/gattrib.c
> index 9268001..79ee2e9 100644
> --- a/attrib/gattrib.c
> +++ b/attrib/gattrib.c
> @@ -286,6 +286,7 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
> uint8_t buf[512], status;
> gsize len;
> GIOStatus iostat;
> + gboolean qempty;
>
> if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
> attrib->read_watch = 0;
> @@ -333,8 +334,7 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
> status = 0;
>
> done:
> - if (attrib->queue && g_queue_is_empty(attrib->queue) == FALSE)
> - wake_up_sender(attrib);
> + qempty = attrib->queue == NULL || g_queue_is_empty(attrib->queue);
>
> if (cmd) {
> if (cmd->func)
> @@ -343,6 +343,9 @@ done:
> command_destroy(cmd);
> }
>
> + if (!qempty)
> + wake_up_sender(attrib);
> +
> return TRUE;
> }
>
> @@ -368,9 +371,9 @@ GAttrib *g_attrib_new(GIOChannel *io)
> return g_attrib_ref(attrib);
> }
>
> -guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
> - guint16 len, GAttribResultFunc func,
> - gpointer user_data, GDestroyNotify notify)
> +guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
> + const guint8 *pdu, guint16 len, GAttribResultFunc func,
> + gpointer user_data, GDestroyNotify notify)
Missing tab here.
> {
> struct command *c;
>
> @@ -386,9 +389,14 @@ guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
> c->func = func;
> c->user_data = user_data;
> c->notify = notify;
> - c->id = ++attrib->next_cmd_id;
>
> - g_queue_push_tail(attrib->queue, c);
> + if (id) {
> + c->id = id;
> + g_queue_push_head(attrib->queue, c);
> + } else {
> + c->id = ++attrib->next_cmd_id;
> + g_queue_push_tail(attrib->queue, c);
> + }
>
> if (g_queue_get_length(attrib->queue) == 1)
> wake_up_sender(attrib);
> diff --git a/attrib/gattrib.h b/attrib/gattrib.h
> index 0940289..1a966a7 100644
> --- a/attrib/gattrib.h
> +++ b/attrib/gattrib.h
> @@ -50,9 +50,10 @@ gboolean g_attrib_set_disconnect_function(GAttrib *attrib,
> gboolean g_attrib_set_destroy_function(GAttrib *attrib,
> GDestroyNotify destroy, gpointer user_data);
>
> -guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
> - guint16 len, GAttribResultFunc func,
> - gpointer user_data, GDestroyNotify notify);
> +guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
> + const guint8 *pdu, guint16 len, GAttribResultFunc func,
> + gpointer user_data, GDestroyNotify notify);
> +
Missing tab here.
> 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 a234e36..a6f92db 100644
> --- a/attrib/gatttool.c
> +++ b/attrib/gatttool.c
> @@ -272,7 +272,7 @@ static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
> olen = enc_confirmation(opdu, sizeof(opdu));
>
> if (olen > 0)
> - g_attrib_send(attrib, opdu[0], opdu, olen, NULL, NULL, NULL);
> + g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
> }
>
> static gboolean listen_start(gpointer user_data)
> diff --git a/src/attrib-server.c b/src/attrib-server.c
> index cbc01ee..aee2ace 100644
> --- a/src/attrib-server.c
> +++ b/src/attrib-server.c
> @@ -694,7 +694,7 @@ done:
> if (status)
> length = enc_error_resp(ipdu[0], 0x0000, status, opdu, channel->mtu);
>
> - g_attrib_send(channel->attrib, opdu[0], opdu, length,
> + g_attrib_send(channel->attrib, 0, opdu[0], opdu, length,
> NULL, NULL, NULL);
> }
>
> --
> 1.7.1
> --
> Brian Gix
> [email protected]
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
>
We need only to avoid calling g_attrib_send outside gatt.c passing id
!=0, otherwise it may break the commands sequence.
Could you please change the the attribute server adding a service with
long attributes?
Regards,
Claudio.