* [PATCH 0/2] Implement Compound GATT Procedures and Long Reads @ 2011-01-05 0:01 Brian Gix 2011-01-05 0:01 ` [PATCH 1/2] Fix g_attrib_send() to include a new ID parameter Brian Gix 2011-01-05 0:01 ` [PATCH 2/2] Fix gatt_read_char() to support long Attrib Values Brian Gix 0 siblings, 2 replies; 6+ messages in thread From: Brian Gix @ 2011-01-05 0:01 UTC (permalink / raw) Cc: claudio.takahasi, padovan, rshaffer, linux-bluetooth These two patches implement Compound GATT procedures, so that they are executed atomically, and in the order that they are invoked, regardless of whether they can be performed in a single or multiple ATT Req/Resp transaction. Patch 1 adds an ID parameter to g_attrib_send which shall be Zero for the first ATT transaction, and shall be the previously returned ID for all subsequent ATT transactions for that GATT procedure. The underlying code will enqueue the requested pkt at the Tail of the queue for Zero ID'd pkts, and at the Head of the queue for non-zero (continuation) pkts. The queue is then only services (next item sent) after the callbacks have been made, to allow any continuation pkts to be created. Patch 2 then uses this new feature of g_attrib_send to implement support for Long Attribute Reads (using READ_BLOB). -- Brian Gix bgix@codeaurora.org Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] Fix g_attrib_send() to include a new ID parameter 2011-01-05 0:01 [PATCH 0/2] Implement Compound GATT Procedures and Long Reads Brian Gix @ 2011-01-05 0:01 ` Brian Gix 2011-01-06 17:17 ` Claudio Takahasi 2011-01-05 0:01 ` [PATCH 2/2] Fix gatt_read_char() to support long Attrib Values Brian Gix 1 sibling, 1 reply; 6+ messages in thread From: Brian Gix @ 2011-01-05 0:01 UTC (permalink / raw) Cc: claudio.takahasi, padovan, rshaffer, linux-bluetooth, Brian Gix 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 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) { 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); + 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 bgix@codeaurora.org Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] Fix g_attrib_send() to include a new ID parameter 2011-01-05 0:01 ` [PATCH 1/2] Fix g_attrib_send() to include a new ID parameter Brian Gix @ 2011-01-06 17:17 ` Claudio Takahasi 0 siblings, 0 replies; 6+ messages in thread From: Claudio Takahasi @ 2011-01-06 17:17 UTC (permalink / raw) To: Brian Gix; +Cc: padovan, rshaffer, linux-bluetooth Hi Brian, On Tue, Jan 4, 2011 at 9:01 PM, Brian Gix <bgix@codeaurora.org> 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 > bgix@codeaurora.org > 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. ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] Fix gatt_read_char() to support long Attrib Values 2011-01-05 0:01 [PATCH 0/2] Implement Compound GATT Procedures and Long Reads Brian Gix 2011-01-05 0:01 ` [PATCH 1/2] Fix g_attrib_send() to include a new ID parameter Brian Gix @ 2011-01-05 0:01 ` Brian Gix 2011-01-06 17:31 ` Claudio Takahasi 1 sibling, 1 reply; 6+ messages in thread From: Brian Gix @ 2011-01-05 0:01 UTC (permalink / raw) Cc: claudio.takahasi, padovan, rshaffer, linux-bluetooth, Brian Gix 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 | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 132 insertions(+), 2 deletions(-) diff --git a/attrib/gatt.c b/attrib/gatt.c index 320759f..304c2b1 100644 --- a/attrib/gatt.c +++ b/attrib/gatt.c @@ -97,15 +97,145 @@ 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; + guint8 ref; +}; + +static void read_long_destroy(gpointer user_data) +{ + struct read_long_data *long_read = user_data; + + if (--long_read->ref) + 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 == ATT_ECODE_ATTR_NOT_LONG || + status == ATT_ECODE_INVALID_OFFSET) { + status = 0; + goto done; + } + + if (status != 0 || rlen == 1) + 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) { + 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) { + 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 { + 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 bgix@codeaurora.org Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] Fix gatt_read_char() to support long Attrib Values 2011-01-05 0:01 ` [PATCH 2/2] Fix gatt_read_char() to support long Attrib Values Brian Gix @ 2011-01-06 17:31 ` Claudio Takahasi 0 siblings, 0 replies; 6+ messages in thread From: Claudio Takahasi @ 2011-01-06 17:31 UTC (permalink / raw) To: Brian Gix; +Cc: padovan, rshaffer, linux-bluetooth 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== ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 0/2] Implement Compound GATT procedures, Long Reads @ 2011-01-07 0:39 Brian Gix 2011-01-07 0:39 ` [PATCH 2/2] Fix gatt_read_char() to support long Attrib Values Brian Gix 0 siblings, 1 reply; 6+ messages in thread From: Brian Gix @ 2011-01-07 0:39 UTC (permalink / raw) Cc: vinicius.gomes, claudio.takahasi, johan.hedberg, padovan, linux-bluetooth These patches address the concerns raised by Vinicius and Claudio. They are based on a rebase as of: commit 3fd5fa3890e3db3857f212ef6a187f7744d07cba Author: Claudio Takahasi <claudio.takahasi@openbossa.org> Date: Mon Jan 3 18:45:54 2011 -0300 -- Brian Gix bgix@codeaurora.org Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] Fix gatt_read_char() to support long Attrib Values 2011-01-07 0:39 [PATCH 0/2] Implement Compound GATT procedures, Long Reads Brian Gix @ 2011-01-07 0:39 ` Brian Gix 0 siblings, 0 replies; 6+ messages in thread From: Brian Gix @ 2011-01-07 0:39 UTC (permalink / raw) Cc: vinicius.gomes, claudio.takahasi, johan.hedberg, padovan, linux-bluetooth, Brian Gix 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 bgix@codeaurora.org Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-01-07 0:39 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2011-01-05 0:01 [PATCH 0/2] Implement Compound GATT Procedures and Long Reads Brian Gix 2011-01-05 0:01 ` [PATCH 1/2] Fix g_attrib_send() to include a new ID parameter Brian Gix 2011-01-06 17:17 ` Claudio Takahasi 2011-01-05 0:01 ` [PATCH 2/2] Fix gatt_read_char() to support long Attrib Values Brian Gix 2011-01-06 17:31 ` Claudio Takahasi -- strict thread matches above, loose matches on Subject: below -- 2011-01-07 0:39 [PATCH 0/2] Implement Compound GATT procedures, Long Reads Brian Gix 2011-01-07 0:39 ` [PATCH 2/2] Fix gatt_read_char() to support long Attrib Values Brian Gix
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox