mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-12-04 01:24:42 +08:00
gatt: Add support to GATT Write Long Characteristic
Extending the function gatt_write_char for support GATT Write Long Characteristics. MTU is checked and if the payload does not fit, the prepare and execute write are used to do the transaction.
This commit is contained in:
parent
f5cf20bb06
commit
7040dc92fc
@ -92,6 +92,10 @@
|
||||
#define ATT_CID 4
|
||||
#define ATT_PSM 31
|
||||
|
||||
/* Flags for Execute Write Request Operation */
|
||||
#define ATT_CANCEL_ALL_PREP_WRITES 0x00
|
||||
#define ATT_WRITE_ALL_PREP_WRITES 0x01
|
||||
|
||||
struct att_data_list {
|
||||
uint16_t num;
|
||||
uint16_t len;
|
||||
|
113
attrib/gatt.c
113
attrib/gatt.c
@ -520,23 +520,122 @@ guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
|
||||
return id;
|
||||
}
|
||||
|
||||
guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
|
||||
int vlen, GAttribResultFunc func, gpointer user_data)
|
||||
struct write_long_data {
|
||||
GAttrib *attrib;
|
||||
GAttribResultFunc func;
|
||||
gpointer user_data;
|
||||
guint16 handle;
|
||||
uint16_t offset;
|
||||
uint8_t *value;
|
||||
int vlen;
|
||||
};
|
||||
|
||||
static guint execute_write(GAttrib *attrib, uint8_t flags,
|
||||
GAttribResultFunc func, gpointer user_data)
|
||||
{
|
||||
uint8_t *buf;
|
||||
int buflen;
|
||||
guint16 plen;
|
||||
|
||||
buf = g_attrib_get_buffer(attrib, &buflen);
|
||||
if (func)
|
||||
plen = enc_write_req(handle, value, vlen, buf, buflen);
|
||||
else
|
||||
plen = enc_write_cmd(handle, value, vlen, buf, buflen);
|
||||
plen = enc_exec_write_req(flags, buf, buflen);
|
||||
if (plen == 0)
|
||||
return 0;
|
||||
|
||||
return g_attrib_send(attrib, 0, buf[0], buf, plen, func,
|
||||
return g_attrib_send(attrib, 0, buf[0], buf, plen, func, user_data,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static guint prepare_write(GAttrib *attrib, uint16_t handle, uint16_t offset,
|
||||
uint8_t *value, int vlen, GAttribResultFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
static void prepare_write_cb(guint8 status, const guint8 *rpdu,
|
||||
guint16 rlen, gpointer user_data)
|
||||
{
|
||||
struct write_long_data *long_write = user_data;
|
||||
|
||||
if (status != 0) {
|
||||
long_write->func(status, rpdu, rlen, long_write->user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip Prepare Write Response PDU header (5 bytes) */
|
||||
long_write->offset += rlen - 5;
|
||||
|
||||
if (long_write->offset == long_write->vlen){
|
||||
execute_write(long_write->attrib, ATT_WRITE_ALL_PREP_WRITES,
|
||||
long_write->func, long_write->user_data);
|
||||
g_free(long_write->value);
|
||||
g_free(long_write);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
prepare_write(long_write->attrib, long_write->handle,
|
||||
long_write->offset, long_write->value, long_write->vlen,
|
||||
long_write->func, long_write);
|
||||
}
|
||||
|
||||
static guint prepare_write(GAttrib *attrib, uint16_t handle, uint16_t offset,
|
||||
uint8_t *value, int vlen, GAttribResultFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
guint16 plen;
|
||||
int buflen;
|
||||
uint8_t *buf;
|
||||
|
||||
buf = g_attrib_get_buffer(attrib, &buflen);
|
||||
|
||||
plen = enc_prep_write_req(handle, offset, &value[offset], vlen - offset,
|
||||
buf, buflen);
|
||||
if (plen == 0)
|
||||
return 0;
|
||||
|
||||
return g_attrib_send(attrib, 0, buf[0], buf, plen, prepare_write_cb,
|
||||
user_data, NULL);
|
||||
}
|
||||
|
||||
guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
|
||||
int vlen, GAttribResultFunc func, gpointer user_data)
|
||||
{
|
||||
uint8_t *buf;
|
||||
int buflen;
|
||||
guint16 plen;
|
||||
struct write_long_data *long_write;
|
||||
|
||||
buf = g_attrib_get_buffer(attrib, &buflen);
|
||||
|
||||
/* Only use Write Request/Command if payload fits on a single transfer,
|
||||
* including 3 bytes for the header. */
|
||||
if (vlen <= buflen - 3) {
|
||||
if (func)
|
||||
plen = enc_write_req(handle, value, vlen, buf,
|
||||
buflen);
|
||||
else
|
||||
plen = enc_write_cmd(handle, value, vlen, buf,
|
||||
buflen);
|
||||
|
||||
return g_attrib_send(attrib, 0, buf[0], buf, plen, func,
|
||||
user_data, NULL);
|
||||
}
|
||||
|
||||
/* Write Long Characteristic Values */
|
||||
long_write = g_try_new0(struct write_long_data, 1);
|
||||
if (long_write == NULL)
|
||||
return 0;
|
||||
|
||||
long_write->attrib = attrib;
|
||||
long_write->func = func;
|
||||
long_write->user_data = user_data;
|
||||
long_write->handle = handle;
|
||||
long_write->value = g_memdup(value,vlen);
|
||||
long_write->vlen = vlen;
|
||||
|
||||
return prepare_write(attrib, handle, long_write->offset, value, vlen,
|
||||
func, long_write);
|
||||
}
|
||||
|
||||
guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
|
@ -371,7 +371,7 @@ static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!dec_write_resp(pdu, plen)) {
|
||||
if (!dec_write_resp(pdu, plen) && !dec_exec_write_resp(pdu, plen)) {
|
||||
g_printerr("Protocol error\n");
|
||||
goto done;
|
||||
}
|
||||
|
@ -588,7 +588,7 @@ static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dec_write_resp(pdu, plen)) {
|
||||
if (!dec_write_resp(pdu, plen) && !dec_exec_write_resp(pdu, plen)) {
|
||||
printf("Protocol error\n");
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user