diff --git a/src/gatt-database.c b/src/gatt-database.c
index afacae7..245d33a 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
if (ccc_cb->callback) {
struct pending_op *op;
- op = pending_ccc_new(att, attrib, get_le16(value),
+ op = pending_ccc_new(att, attrib, val,
bt_att_get_link_type(att));
if (!op) {
ecode = BT_ATT_ERROR_UNLIKELY;
struct btd_gatt_database *database = user_data;
struct device_state *state;
uint8_t bits[] = { BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING,
- BT_GATT_CHRC_CLI_FEAT_EATT };
+ BT_GATT_CHRC_CLI_FEAT_EATT,
+ BT_GATT_CHRC_CLI_FEAT_NFY_MULTI };
uint8_t ecode = 0;
unsigned int i;
DBG("GATT server sending notification");
bt_gatt_server_send_notification(server,
notify->handle, notify->value,
- notify->len);
+ notify->len, device_state->cli_feat[0] &
+ BT_GATT_CHRC_CLI_FEAT_NFY_MULTI);
return;
}
diff --git a/src/shared/att.c b/src/shared/att.c
index 6fa16e4..948a554 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
{ BT_ATT_OP_EXEC_WRITE_REQ, ATT_OP_TYPE_REQ },
{ BT_ATT_OP_EXEC_WRITE_RSP, ATT_OP_TYPE_RSP },
{ BT_ATT_OP_HANDLE_NFY, ATT_OP_TYPE_NFY },
+ { BT_ATT_OP_HANDLE_NFY_MULT, ATT_OP_TYPE_NFY },
{ BT_ATT_OP_HANDLE_IND, ATT_OP_TYPE_IND },
{ BT_ATT_OP_HANDLE_CONF, ATT_OP_TYPE_CONF },
{ }
}
if (op->callback)
- op->callback(BT_ATT_OP_HANDLE_NFY, NULL, 0, op->user_data);
+ op->callback(BT_ATT_OP_HANDLE_CONF, NULL, 0, op->user_data);
destroy_att_send_op(op);
chan->pending_ind = NULL;
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 7381f96..963ad61 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
client->features |= BT_GATT_CHRC_CLI_FEAT_EATT;
}
+ client->features |= BT_GATT_CHRC_CLI_FEAT_NFY_MULTI;
+
util_debug(client->debug_callback, client->debug_data,
"Writing Client Features 0x%02x", client->features);
diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
index 8e81d6e..7e5d652 100644
--- a/src/shared/gatt-server.c
+++ b/src/shared/gatt-server.c
#include "src/shared/gatt-server.h"
#include "src/shared/gatt-helpers.h"
#include "src/shared/util.h"
+#include "src/shared/timeout.h"
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
*/
#define DEFAULT_MAX_PREP_QUEUE_LEN 30
+#define NFY_MULT_TIMEOUT 10
+
struct async_read_op {
struct bt_att_chan *chan;
struct bt_gatt_server *server;
free(data);
}
+struct nfy_mult_data {
+ unsigned int id;
+ uint8_t *pdu;
+ uint16_t offset;
+ uint16_t len;
+};
+
struct bt_gatt_server {
struct gatt_db *db;
struct bt_att *att;
bt_gatt_server_authorize_cb_t authorize;
void *authorize_data;
+
+ struct nfy_mult_data *nfy_mult;
};
static void bt_gatt_server_free(struct bt_gatt_server *server)
return true;
}
+static bool notify_multiple(void *user_data)
+{
+ struct bt_gatt_server *server = user_data;
+
+ bt_att_send(server->att, BT_ATT_OP_HANDLE_NFY_MULT,
+ server->nfy_mult->pdu, server->nfy_mult->offset, NULL,
+ NULL, NULL);
+
+ free(server->nfy_mult->pdu);
+ free(server->nfy_mult);
+ server->nfy_mult = NULL;
+
+ return false;
+}
+
bool bt_gatt_server_send_notification(struct bt_gatt_server *server,
uint16_t handle, const uint8_t *value,
- uint16_t length)
+ uint16_t length, bool multiple)
{
- uint16_t pdu_len;
- uint8_t *pdu;
+ struct nfy_mult_data *data = NULL;
bool result;
if (!server || (length && !value))
return false;
- pdu_len = MIN(bt_att_get_mtu(server->att) - 1, length + 2);
- pdu = malloc(pdu_len);
- if (!pdu)
- return false;
+ if (multiple)
+ data = server->nfy_mult;
- put_le16(handle, pdu);
- memcpy(pdu + 2, value, pdu_len - 2);
+ if (!data) {
+ data = new0(struct nfy_mult_data, 1);
+ data->len = bt_att_get_mtu(server->att) - 1;
+ data->pdu = malloc(data->len);
+ }
- result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_NFY, pdu,
- pdu_len, NULL, NULL, NULL);
- free(pdu);
+ put_le16(handle, data->pdu + data->offset);
+ data->offset += 2;
+
+ length = MIN(data->len - data->offset, length);
+
+ if (multiple) {
+ put_le16(length, data->pdu + data->offset);
+ data->offset += 2;
+ }
+
+ memcpy(data->pdu + data->offset, value, length);
+ data->offset += length;
+
+ if (multiple) {
+ if (!server->nfy_mult)
+ server->nfy_mult = data;
+
+ if (!server->nfy_mult->id)
+ server->nfy_mult->id = timeout_add(NFY_MULT_TIMEOUT,
+ notify_multiple, server,
+ NULL);
+
+ return true;
+ }
+
+ result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_NFY,
+ data->pdu, data->offset, NULL, NULL, NULL);
+ free(data->pdu);
+ free(data);
return result;
}
diff --git a/src/shared/gatt-server.h b/src/shared/gatt-server.h
index c3d83f2..a2492d2 100644
--- a/src/shared/gatt-server.h
+++ b/src/shared/gatt-server.h
bool bt_gatt_server_send_notification(struct bt_gatt_server *server,
uint16_t handle, const uint8_t *value,
- uint16_t length);
+ uint16_t length, bool multiple);
bool bt_gatt_server_send_indication(struct bt_gatt_server *server,
uint16_t handle, const uint8_t *value,
diff --git a/tools/btgatt-server.c b/tools/btgatt-server.c
index d9d96e6..5b7857b 100644
--- a/tools/btgatt-server.c
+++ b/tools/btgatt-server.c
bt_gatt_server_send_notification(server->gatt,
server->hr_msrmt_handle,
- pdu, len);
+ pdu, len, false);
cur_ee = server->hr_energy_expended;
conf_cb, NULL, NULL))
printf("Failed to initiate indication\n");
} else if (!bt_gatt_server_send_notification(server->gatt, handle,
- value, length))
+ value, length, false))
printf("Failed to initiate notification\n");
done:
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index d94993b..36dd284 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
const struct test_step *step = context->data->step;
bt_gatt_server_send_notification(context->server, step->handle,
- step->value, step->length);
+ step->value, step->length, false);
}
static const struct test_step test_notification_server_1 = {