This is an automated email from the ASF dual-hosted git repository. kopyscinski pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit f07a77489f4f4b20073b257123ec4fd5123c0b05 Author: Krzysztof Kopyściński <[email protected]> AuthorDate: Fri Aug 11 14:17:10 2023 +0200 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. --- nimble/host/include/host/ble_gatt.h | 63 +++++++++++++++ nimble/host/src/ble_att_clt.c | 32 ++++++++ nimble/host/src/ble_att_priv.h | 1 + nimble/host/src/ble_gattc.c | 133 ++++++++++++++++++++++++++++++++ nimble/host/syscfg.yml | 7 ++ nimble/include/nimble/nimble_opt_auto.h | 3 + 6 files changed, 239 insertions(+) diff --git a/nimble/host/include/host/ble_gatt.h b/nimble/host/include/host/ble_gatt.h index b82ab2f40..a38d3c934 100644 --- a/nimble/host/include/host/ble_gatt.h +++ b/nimble/host/include/host/ble_gatt.h @@ -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 diff --git a/nimble/host/src/ble_att_clt.c b/nimble/host/src/ble_att_clt.c index 3423e25e8..2b60f8b53 100644 --- a/nimble/host/src/ble_att_clt.c +++ b/nimble/host/src/ble_att_clt.c @@ -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; +} diff --git a/nimble/host/src/ble_att_priv.h b/nimble/host/src/ble_att_priv.h index ac65250f9..2bc3da361 100644 --- a/nimble/host/src/ble_att_priv.h +++ b/nimble/host/src/ble_att_priv.h @@ -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 } diff --git a/nimble/host/src/ble_gattc.c b/nimble/host/src/ble_gattc.c index 2d42856b8..d40adfd3c 100644 --- a/nimble/host/src/ble_gattc.c +++ b/nimble/host/src/ble_gattc.c @@ -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. */ diff --git a/nimble/host/syscfg.yml b/nimble/host/syscfg.yml index 558e31e8d..79a027d4b 100644 --- a/nimble/host/syscfg.yml +++ b/nimble/host/syscfg.yml @@ -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: > diff --git a/nimble/include/nimble/nimble_opt_auto.h b/nimble/include/nimble/nimble_opt_auto.h index 55f621991..4663ae8c7 100644 --- a/nimble/include/nimble/nimble_opt_auto.h +++ b/nimble/include/nimble/nimble_opt_auto.h @@ -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
