@@ -72,11 +72,12 @@
#define BT_ATT_OP_PREP_WRITE_RSP 0x17
#define BT_ATT_OP_EXEC_WRITE_REQ 0x18
#define BT_ATT_OP_EXEC_WRITE_RSP 0x19
-#define BT_ATT_OP_HANDLE_VAL_NOT 0x1B
-#define BT_ATT_OP_HANDLE_VAL_IND 0x1D
-#define BT_ATT_OP_HANDLE_VAL_CONF 0x1E
+#define BT_ATT_OP_HANDLE_NFY 0x1B
+#define BT_ATT_OP_HANDLE_IND 0x1D
+#define BT_ATT_OP_HANDLE_CONF 0x1E
#define BT_ATT_OP_READ_MULT_VL_REQ 0x20
#define BT_ATT_OP_READ_MULT_VL_RSP 0x21
+#define BT_ATT_OP_HANDLE_NFY_MULT 0x23
/* Packed struct definitions for ATT protocol PDUs */
/* TODO: Complete these definitions for all opcodes */
@@ -110,7 +110,7 @@ enum att_op_type {
ATT_OP_TYPE_RSP,
ATT_OP_TYPE_CMD,
ATT_OP_TYPE_IND,
- ATT_OP_TYPE_NOT,
+ ATT_OP_TYPE_NFY,
ATT_OP_TYPE_CONF,
ATT_OP_TYPE_UNKNOWN,
};
@@ -144,9 +144,9 @@ static const struct {
{ BT_ATT_OP_PREP_WRITE_RSP, ATT_OP_TYPE_RSP },
{ BT_ATT_OP_EXEC_WRITE_REQ, ATT_OP_TYPE_REQ },
{ BT_ATT_OP_EXEC_WRITE_RSP, ATT_OP_TYPE_RSP },
- { BT_ATT_OP_HANDLE_VAL_NOT, ATT_OP_TYPE_NOT },
- { BT_ATT_OP_HANDLE_VAL_IND, ATT_OP_TYPE_IND },
- { BT_ATT_OP_HANDLE_VAL_CONF, ATT_OP_TYPE_CONF },
+ { BT_ATT_OP_HANDLE_NFY, ATT_OP_TYPE_NFY },
+ { BT_ATT_OP_HANDLE_IND, ATT_OP_TYPE_IND },
+ { BT_ATT_OP_HANDLE_CONF, ATT_OP_TYPE_CONF },
{ }
};
@@ -530,7 +530,7 @@ static bool can_write_data(struct io *io, void *user_data)
chan->in_req = false;
/* fall through */
case ATT_OP_TYPE_CMD:
- case ATT_OP_TYPE_NOT:
+ case ATT_OP_TYPE_NFY:
case ATT_OP_TYPE_CONF:
case ATT_OP_TYPE_UNKNOWN:
default:
@@ -842,7 +842,7 @@ static void handle_conf(struct bt_att_chan *chan, uint8_t *pdu, ssize_t pdu_len)
}
if (op->callback)
- op->callback(BT_ATT_OP_HANDLE_VAL_CONF, NULL, 0, op->user_data);
+ op->callback(BT_ATT_OP_HANDLE_NFY, NULL, 0, op->user_data);
destroy_att_send_op(op);
chan->pending_ind = NULL;
@@ -1042,7 +1042,7 @@ static bool can_read_data(struct io *io, void *user_data)
chan->in_req = true;
/* fall through */
case ATT_OP_TYPE_CMD:
- case ATT_OP_TYPE_NOT:
+ case ATT_OP_TYPE_NFY:
case ATT_OP_TYPE_UNKNOWN:
case ATT_OP_TYPE_IND:
/* fall through */
@@ -1492,7 +1492,7 @@ unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
result = queue_push_tail(att->ind_queue, op);
break;
case ATT_OP_TYPE_CMD:
- case ATT_OP_TYPE_NOT:
+ case ATT_OP_TYPE_NFY:
case ATT_OP_TYPE_UNKNOWN:
case ATT_OP_TYPE_RSP:
case ATT_OP_TYPE_CONF:
@@ -95,7 +95,7 @@ struct bt_gatt_client {
struct queue *notify_list;
struct queue *notify_chrcs;
int next_reg_id;
- unsigned int disc_id, notify_id, ind_id;
+ unsigned int disc_id, nfy_id, nfy_mult_id, ind_id;
/*
* Handles of the GATT Service and the Service Changed characteristic
@@ -2072,9 +2072,10 @@ done:
return true;
}
-struct pdu_data {
- const void *pdu;
- uint16_t length;
+struct value_data {
+ uint16_t handle;
+ uint16_t len;
+ const void *data;
};
static void disable_ccc_callback(uint8_t opcode, const void *pdu,
@@ -2125,25 +2126,18 @@ done:
static void notify_handler(void *data, void *user_data)
{
struct notify_data *notify_data = data;
- struct pdu_data *pdu_data = user_data;
- uint16_t value_handle;
- const uint8_t *value = NULL;
-
- value_handle = get_le16(pdu_data->pdu);
+ struct value_data *value_data = user_data;
- if (notify_data->chrc->value_handle != value_handle)
+ if (notify_data->chrc->value_handle != value_data->handle)
return;
- if (pdu_data->length > 2)
- value = pdu_data->pdu + 2;
-
/*
* Even if the notify data has a pending ATT request to write to the
* CCC, there is really no reason not to notify the handlers.
*/
if (notify_data->notify)
- notify_data->notify(value_handle, value, pdu_data->length - 2,
- notify_data->user_data);
+ notify_data->notify(value_data->handle, value_data->data,
+ value_data->len, notify_data->user_data);
}
static void notify_cb(struct bt_att_chan *chan, uint8_t opcode,
@@ -2151,18 +2145,42 @@ static void notify_cb(struct bt_att_chan *chan, uint8_t opcode,
void *user_data)
{
struct bt_gatt_client *client = user_data;
- struct pdu_data pdu_data;
+ struct value_data data;
bt_gatt_client_ref(client);
- memset(&pdu_data, 0, sizeof(pdu_data));
- pdu_data.pdu = pdu;
- pdu_data.length = length;
+ memset(&data, 0, sizeof(data));
+
+ if (opcode == BT_ATT_OP_HANDLE_NFY_MULT) {
+ while (length >= 4) {
+ data.handle = get_le16(pdu);
+ length -= 2;
+ pdu += 2;
+
+ data.len = get_le16(pdu);
+ length -= 2;
+ pdu += 2;
+
+ data.data = pdu;
+
+ queue_foreach(client->notify_list, notify_handler,
+ &data);
- queue_foreach(client->notify_list, notify_handler, &pdu_data);
+ length -= data.len;
+ }
+ } else {
+ data.handle = get_le16(pdu);
+ length -= 2;
+ pdu += 2;
+
+ data.len = length;
+ data.data = pdu;
- if (opcode == BT_ATT_OP_HANDLE_VAL_IND && !client->parent)
- bt_att_chan_send(chan, BT_ATT_OP_HANDLE_VAL_CONF, NULL, 0,
+ queue_foreach(client->notify_list, notify_handler, &data);
+ }
+
+ if (opcode == BT_ATT_OP_HANDLE_IND && !client->parent)
+ bt_att_chan_send(chan, BT_ATT_OP_HANDLE_CONF, NULL, 0,
NULL, NULL, NULL);
bt_gatt_client_unref(client);
@@ -2181,7 +2199,8 @@ static void bt_gatt_client_free(struct bt_gatt_client *client)
if (client->att) {
bt_att_unregister_disconnect(client->att, client->disc_id);
- bt_att_unregister(client->att, client->notify_id);
+ bt_att_unregister(client->att, client->nfy_id);
+ bt_att_unregister(client->att, client->nfy_mult_id);
bt_att_unregister(client->att, client->ind_id);
bt_att_unref(client->att);
}
@@ -2239,12 +2258,17 @@ static struct bt_gatt_client *gatt_client_new(struct gatt_db *db,
client->notify_chrcs = queue_new();
client->pending_requests = queue_new();
- client->notify_id = bt_att_register(att, BT_ATT_OP_HANDLE_VAL_NOT,
+ client->nfy_id = bt_att_register(att, BT_ATT_OP_HANDLE_NFY,
+ notify_cb, client, NULL);
+ if (!client->nfy_id)
+ goto fail;
+
+ client->nfy_mult_id = bt_att_register(att, BT_ATT_OP_HANDLE_NFY_MULT,
notify_cb, client, NULL);
- if (!client->notify_id)
+ if (!client->nfy_mult_id)
goto fail;
- client->ind_id = bt_att_register(att, BT_ATT_OP_HANDLE_VAL_IND,
+ client->ind_id = bt_att_register(att, BT_ATT_OP_HANDLE_IND,
notify_cb, client, NULL);
if (!client->ind_id)
goto fail;
@@ -1745,7 +1745,7 @@ bool bt_gatt_server_send_notification(struct bt_gatt_server *server,
put_le16(handle, pdu);
memcpy(pdu + 2, value, pdu_len - 2);
- result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_VAL_NOT, pdu,
+ result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_NFY, pdu,
pdu_len, NULL, NULL, NULL);
free(pdu);
@@ -1806,7 +1806,7 @@ bool bt_gatt_server_send_indication(struct bt_gatt_server *server,
put_le16(handle, pdu);
memcpy(pdu + 2, value, pdu_len - 2);
- result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_VAL_IND, pdu,
+ result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_IND, pdu,
pdu_len, conf_cb,
data, destroy_ind_data);
if (!result)
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Handle Value Multiple Notification can be used to notify multiple values at once. --- src/shared/att-types.h | 7 ++-- src/shared/att.c | 16 ++++----- src/shared/gatt-client.c | 76 ++++++++++++++++++++++++++-------------- src/shared/gatt-server.c | 4 +-- 4 files changed, 64 insertions(+), 39 deletions(-)