Hi Brian, On Tue, Jan 4, 2011 at 9:01 PM, Brian Gix <bgix@xxxxxxxxxxxxxx> wrote: > 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. No tabs here. > --- > Â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; use g_atomic_int_dec_and_test > + > +    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; Maybe using GByteArray will make your code simpler. > + > +    if (rlen < ATT_DEFAULT_MTU) > +        goto done; For now it is fine for testing. But it needs to be fixed later, MTU can change after the MTU negotiation, the new value could be accessed using a getsockopt, passing the value to gatt_* functions or using a GAttrib function. > + > +    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++; Use g_atomic_int_x function > +        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++; same here. Claudio > +        long_read->id = id; > +    } > + > +    return id; > Â} > > Âguint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value, > -- > 1.7.1 > -- > Brian Gix > bgix@xxxxxxxxxxxxxx > Employee of Qualcomm Innovation Center, Inc. > Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum > ÿô.nÇ·®+%˱é¥wÿº{.nÇ·¥{±ý¶â^nr¡öë¨è&£ûz¹Þúzf£¢·h§~Ûÿÿïÿê_èæ+v¨þ)ßø