mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-09-03 15:50:01 +00:00
host/gatt_srv: Implement sending Multiple Handle Notifications
It is mandatory to support sending them if receiving is supported. Implemented functionality and added public API.
This commit is contained in:
committed by
Krzysztof Kopyściński
parent
4340db0c5c
commit
f07a77489f
@@ -246,6 +246,16 @@ struct ble_gatt_dsc {
|
||||
ble_uuid_any_t uuid;
|
||||
};
|
||||
|
||||
|
||||
/** Represents a handle-value tuple for multiple handle notifications. */
|
||||
struct ble_gatt_notif {
|
||||
/** The handle of the GATT characteristic */
|
||||
uint16_t handle;
|
||||
|
||||
/** The buffer with GATT characteristic value */
|
||||
struct os_mbuf *value;
|
||||
};
|
||||
|
||||
/** Function prototype for the GATT MTU exchange callback. */
|
||||
typedef int ble_gatt_mtu_fn(uint16_t conn_handle,
|
||||
const struct ble_gatt_error *error,
|
||||
@@ -634,6 +644,33 @@ int ble_gattc_write_reliable(uint16_t conn_handle,
|
||||
int ble_gatts_notify_custom(uint16_t conn_handle, uint16_t att_handle,
|
||||
struct os_mbuf *om);
|
||||
|
||||
/**
|
||||
* Sends a "free-form" multiple handle variable length characteristic
|
||||
* notification. This function consumes supplied mbufs regardless of the
|
||||
* outcome. Notifications are sent in order of supplied entries.
|
||||
* Function tries to send minimum amount of PDUs. If PDU can't contain all
|
||||
* of the characteristic values, multiple notifications are sent. If only one
|
||||
* handle-value pair fits into PDU, or only one characteristic remains in the
|
||||
* list, regular characteristic notification is sent.
|
||||
*
|
||||
* If GATT client doesn't support receiving multiple handle notifications,
|
||||
* this will use GATT notification for each characteristic, separately.
|
||||
*
|
||||
* If value of characteristic is not specified it will be read from local
|
||||
* GATT database.
|
||||
*
|
||||
* @param conn_handle The connection over which to execute the
|
||||
* procedure.
|
||||
* @param chr_count Number of characteristics to notify about.
|
||||
* @param tuples Handle-value pairs in form of `ble_gatt_notif`
|
||||
* structures.
|
||||
*
|
||||
* @return 0 on success; nonzero on failure.
|
||||
*/
|
||||
int ble_gatts_notify_multiple_custom(uint16_t conn_handle,
|
||||
uint16_t chr_count,
|
||||
struct ble_gatt_notif *tuples);
|
||||
|
||||
/**
|
||||
* Deprecated. Should not be used. Use ble_gatts_notify_custom instead.
|
||||
*/
|
||||
@@ -659,6 +696,32 @@ int ble_gatts_notify(uint16_t conn_handle, uint16_t chr_val_handle);
|
||||
*/
|
||||
int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle);
|
||||
|
||||
/**
|
||||
* Sends a multiple handle variable length characteristic notification. The
|
||||
* content of the message is read from the specified characteristics.
|
||||
* Notifications are sent in order of supplied handles. Function tries to
|
||||
* send minimum amount of PDUs. If PDU can't contain all of the
|
||||
* characteristic values, multiple notifications are sent. If only one
|
||||
* handle-value pair fits into PDU, or only one characteristic remains in the
|
||||
* list, regular characteristic notification is sent.
|
||||
*
|
||||
* If GATT client doesn't support receiving multiple handle notifications,
|
||||
* this will use GATT notification for each characteristic, separately.
|
||||
*
|
||||
* @param conn_handle The connection over which to execute the
|
||||
* procedure.
|
||||
* @param num_handles The number of entries in the "chr_val_handles"
|
||||
* array.
|
||||
* @param chr_val_handles Array of attribute handles of the
|
||||
* characteristics to include in the outgoing
|
||||
* notification.
|
||||
*
|
||||
* @return 0 on success; nonzero on failure.
|
||||
*/
|
||||
int ble_gatts_notify_multiple(uint16_t conn_handle,
|
||||
uint8_t num_handles,
|
||||
const uint16_t *chr_val_handles);
|
||||
|
||||
/**
|
||||
* Sends a "free-form" characteristic indication. The provided mbuf contains
|
||||
* the indication payload. This function consumes the supplied mbuf regardless
|
||||
|
||||
@@ -986,3 +986,35 @@ ble_att_clt_rx_indicate(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxo
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* $multiple handle value notification *
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
ble_att_clt_tx_notify_mult(uint16_t conn_handle, struct os_mbuf *txom)
|
||||
{
|
||||
#if !NIMBLE_BLE_ATT_CLT_NOTIFY_MULT
|
||||
return BLE_HS_ENOTSUP;
|
||||
#endif
|
||||
|
||||
struct os_mbuf *txom2;
|
||||
uint16_t cid;
|
||||
int rc;
|
||||
|
||||
if (ble_att_cmd_get(BLE_ATT_OP_NOTIFY_MULTI_REQ, 0, &txom2) == NULL) {
|
||||
rc = BLE_HS_ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
os_mbuf_concat(txom2, txom);
|
||||
|
||||
cid = ble_eatt_get_available_chan_cid(conn_handle, BLE_GATT_OP_DUMMY);
|
||||
rc = ble_att_tx(conn_handle, cid, txom2);
|
||||
if (cid != BLE_L2CAP_CID_ATT) {
|
||||
ble_eatt_release_chan(conn_handle, BLE_GATT_OP_DUMMY);
|
||||
}
|
||||
|
||||
err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -302,6 +302,7 @@ int ble_att_clt_tx_notify(uint16_t conn_handle, uint16_t handle,
|
||||
int ble_att_clt_tx_indicate(uint16_t conn_handle, uint16_t cid,
|
||||
uint16_t handle, struct os_mbuf *txom);
|
||||
int ble_att_clt_rx_indicate(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom);
|
||||
int ble_att_clt_tx_notify_mult(uint16_t conn_handle, struct os_mbuf *txom);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -4413,6 +4413,139 @@ ble_gatts_notify(uint16_t conn_handle, uint16_t chr_val_handle)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
ble_gatts_notify_multiple_custom(uint16_t conn_handle,
|
||||
uint16_t chr_count,
|
||||
struct ble_gatt_notif *tuples)
|
||||
{
|
||||
#if !MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE)
|
||||
return BLE_HS_ENOTSUP;
|
||||
#endif
|
||||
|
||||
int rc;
|
||||
int i = 0;
|
||||
uint16_t cur_chr_cnt = 0;
|
||||
/* mtu = MTU - 1 octet (OP code) */
|
||||
uint16_t mtu = ble_att_mtu(conn_handle) - 1;
|
||||
struct os_mbuf *txom;
|
||||
struct ble_hs_conn *conn;
|
||||
|
||||
txom = ble_hs_mbuf_att_pkt();
|
||||
if (txom == NULL) {
|
||||
return BLE_HS_ENOMEM;
|
||||
}
|
||||
|
||||
conn = ble_hs_conn_find(conn_handle);
|
||||
if (conn == NULL) {
|
||||
return ENOTCONN;
|
||||
}
|
||||
|
||||
/* Read missing values */
|
||||
for (i = 0; i < chr_count; i++) {
|
||||
if (tuples->handle == 0) {
|
||||
rc = BLE_HS_EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (tuples[i].value == NULL) {
|
||||
rc = ble_att_svr_read_local(tuples[i].handle, &tuples[i].value);
|
||||
if (rc != 0) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If peer does not support fall back to multiple single value
|
||||
* Notifications */
|
||||
if ((conn->bhc_gatt_svr.peer_cl_sup_feat[0] & 0x04) == 0) {
|
||||
for (i = 0; i < chr_count; i++) {
|
||||
rc = ble_att_clt_tx_notify(conn_handle, tuples[chr_count].handle,
|
||||
tuples[chr_count].value);
|
||||
if (rc != 0) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < chr_count; i++) {
|
||||
if (txom->om_len + tuples[i].value->om_len > mtu && cur_chr_cnt < 2) {
|
||||
rc = ble_att_clt_tx_notify(conn_handle, tuples[i].handle,
|
||||
tuples[i].value);
|
||||
if (rc != 0) {
|
||||
goto done;
|
||||
}
|
||||
continue;
|
||||
} else if (txom->om_len + tuples[i].value->om_len > mtu) {
|
||||
rc = ble_att_clt_tx_notify_mult(conn_handle, txom);
|
||||
if (rc != 0) {
|
||||
goto done;
|
||||
}
|
||||
cur_chr_cnt = 0;
|
||||
/* buffer was consumed, allocate new one */
|
||||
txom = ble_hs_mbuf_att_pkt();
|
||||
if (txom == NULL) {
|
||||
return BLE_HS_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
os_mbuf_append(txom, &tuples[i].handle, sizeof(uint16_t));
|
||||
os_mbuf_append(txom, &tuples[i].value->om_len,
|
||||
sizeof(uint16_t));
|
||||
os_mbuf_concat(txom, tuples[i].value);
|
||||
cur_chr_cnt++;
|
||||
}
|
||||
|
||||
if (cur_chr_cnt == 1) {
|
||||
rc = ble_att_clt_tx_notify(conn_handle, tuples[chr_count].handle,
|
||||
tuples[chr_count].value);
|
||||
} else {
|
||||
rc = ble_att_clt_tx_notify_mult(conn_handle, txom);
|
||||
}
|
||||
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
ble_gatts_notify_multiple(uint16_t conn_handle,
|
||||
uint8_t num_handles,
|
||||
const uint16_t *chr_val_handles)
|
||||
{
|
||||
#if !MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE)
|
||||
return BLE_HS_ENOTSUP;
|
||||
#endif
|
||||
int rc, i;
|
||||
struct ble_gatt_notif tuples[num_handles];
|
||||
struct ble_hs_conn *conn;
|
||||
|
||||
BLE_HS_LOG_DEBUG("conn_handle %d\n", conn_handle);
|
||||
conn = ble_hs_conn_find(conn_handle);
|
||||
if (conn == NULL) {
|
||||
return ENOTCONN;
|
||||
}
|
||||
|
||||
/** Skip sending to client that doesn't support this feature */
|
||||
BLE_HS_LOG_DEBUG("ble_gatts_notify_multiple: peer_cl_sup_feat %d\n",
|
||||
conn->bhc_gatt_svr.peer_cl_sup_feat[0]);
|
||||
if ((conn->bhc_gatt_svr.peer_cl_sup_feat[0] & 0x04) == 0) {
|
||||
for (i = 0; i < num_handles; i++) {
|
||||
rc = ble_gatts_notify(conn_handle, chr_val_handles[i]);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_handles; i++) {
|
||||
tuples[i].handle = chr_val_handles[i];
|
||||
tuples[i].value = NULL;
|
||||
BLE_HS_LOG(DEBUG, "handle 0x%02x\n", tuples[i].handle);
|
||||
}
|
||||
|
||||
rc = ble_gatts_notify_multiple_custom(conn_handle, num_handles, tuples);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. Should not be used. Use ble_gatts_notify instead.
|
||||
*/
|
||||
|
||||
@@ -282,6 +282,12 @@ syscfg.defs:
|
||||
description: >
|
||||
Enables sending and receiving of GATT indications. (0/1)
|
||||
value: 1
|
||||
BLE_GATT_NOTIFY_MULTIPLE:
|
||||
description: >
|
||||
Enables sending and receiving of GATT multiple handle notifications. (0/1)
|
||||
value: (MYNEWT_VAL_BLE_VERSION >= 52)
|
||||
restrictions:
|
||||
- '(BLE_VERSION >= 52) if 1'
|
||||
|
||||
# GATT options.
|
||||
BLE_GATT_READ_MAX_ATTRS:
|
||||
@@ -309,6 +315,7 @@ syscfg.defs:
|
||||
description: >
|
||||
Number of CoC channels allocated to EATT
|
||||
value: 0
|
||||
restrictions: BLE_GATT_NOTIFY_MULTIPLE
|
||||
|
||||
BLE_EATT_MTU:
|
||||
description: >
|
||||
|
||||
@@ -109,6 +109,9 @@ extern "C" {
|
||||
#define NIMBLE_BLE_ATT_CLT_INDICATE \
|
||||
(MYNEWT_VAL(BLE_GATT_INDICATE))
|
||||
|
||||
#undef NIMBLE_BLE_ATT_CLT_NOTIFY_MULT
|
||||
#define NIMBLE_BLE_ATT_CLT_NOTIFY_MULT \
|
||||
(MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE))
|
||||
/** Security manager settings. */
|
||||
|
||||
#undef NIMBLE_BLE_SM
|
||||
|
||||
Reference in New Issue
Block a user