fix(nimble): Added api's for fetching gatt cache data and for discovering included service

This commit is contained in:
Astha Verma
2025-04-14 11:55:11 +05:30
parent 3058e24af9
commit 993bd86ee1
6 changed files with 303 additions and 4 deletions

View File

@ -708,6 +708,19 @@ menuconfig BT_NIMBLE_GATT_CACHING
select BT_NIMBLE_DYNAMIC_SERVICE
help
Enable GATT caching
config BT_NIMBLE_GATT_CACHING_INCLUDE_SERVICES
bool "Include services in GATT caching"
depends on BT_NIMBLE_GATT_CACHING
default n
help
Enable this option to include *included services* (e.g., services referenced by other services)
in the GATT database cache. Disabling this will skip caching of included service entries.
config BT_NIMBLE_INCL_SVC_DISCOVERY
bool "Enable Included service discovery"
default y if BT_NIMBLE_GATT_CACHING_INCLUDE_SERVICES
default n
help
Enable this option to start discovery for included service.
config BT_NIMBLE_GATT_CACHING_MAX_CONNS
int "Maximum connections to be cached"
depends on BT_NIMBLE_GATT_CACHING
@ -720,6 +733,12 @@ config BT_NIMBLE_GATT_CACHING_MAX_SVCS
default 64
help
Set this option to set the upper limit on number of services per connection to be cached.
config BT_NIMBLE_GATT_CACHING_MAX_INCL_SVCS
int "Maximum number of included services per connection"
depends on BT_NIMBLE_GATT_CACHING
default 64
help
Set this option to set the upper limit on number of included services per connection to be cached.
config BT_NIMBLE_GATT_CACHING_MAX_CHRS
int "Maximum number of characteristics per connection"
depends on BT_NIMBLE_GATT_CACHING

View File

@ -129,11 +129,27 @@
#define MYNEWT_VAL_BLE_MAX_PERIODIC_ADVERTISER_LIST (CONFIG_BT_NIMBLE_MAX_PERIODIC_ADVERTISER_LIST)
#endif
#ifndef MYNEWT_VAL_BLE_INCL_SVC_DISCOVERY
#ifdef CONFIG_BT_NIMBLE_INCL_SVC_DISCOVERY
#define MYNEWT_VAL_BLE_INCL_SVC_DISCOVERY (CONFIG_BT_NIMBLE_INCL_SVC_DISCOVERY)
#else
#define MYNEWT_VAL_BLE_INCL_SVC_DISCOVERY (0)
#endif
#endif
#ifndef CONFIG_BT_NIMBLE_GATT_CACHING
#define MYNEWT_VAL_BLE_GATT_CACHING (0)
#else
#define MYNEWT_VAL_BLE_GATT_CACHING (CONFIG_BT_NIMBLE_GATT_CACHING)
#ifndef MYNEWT_VAL_BLE_GATT_CACHING_INCLUDE_SERVICES
#ifdef CONFIG_BT_NIMBLE_GATT_CACHING_INCLUDE_SERVICES
#define MYNEWT_VAL_BLE_GATT_CACHING_INCLUDE_SERVICES (CONFIG_BT_NIMBLE_GATT_CACHING_INCLUDE_SERVICES)
#else
#define MYNEWT_VAL_BLE_GATT_CACHING_INCLUDE_SERVICES (0)
#endif
#endif
#ifdef CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CONNS
#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CONNS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CONNS)
#else
@ -146,6 +162,14 @@
#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_SVCS (0)
#endif
#ifndef MYNEWT_VAL_BLE_GATT_CACHING_MAX_INCL_SVCS
#ifdef CONFIG_BT_NIMBLE_GATT_CACHING_MAX_INCL_SVCS
#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_INCL_SVCS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_INCL_SVCS)
#else
#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_INCL_SVCS (0)
#endif
#endif
#ifdef CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CHRS
#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CHRS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CHRS)
#else

View File

@ -27,6 +27,9 @@
#include "console/console.h"
#include "services/gap/ble_svc_gap.h"
#include "blecent.h"
#if MYNEWT_VAL(BLE_GATT_CACHING)
#include "host/ble_esp_gattc_cache.h"
#endif
#if CONFIG_EXAMPLE_USE_CI_ADDRESS
#ifdef CONFIG_IDF_TARGET_ESP32
@ -1052,9 +1055,13 @@ app_main(void)
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
/* Initialize data structures to track connected peers. */
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64, 64);
assert(rc == 0);
#else
rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
assert(rc == 0);
#endif
/* Set the default device name. */
rc = ble_svc_gap_device_name_set("nimble-blecent");
assert(rc == 0);

View File

@ -38,14 +38,24 @@ struct peer_chr {
struct peer_dsc_list dscs;
};
SLIST_HEAD(peer_chr_list, peer_chr);
SLIST_HEAD(peer_svc_list, peer_svc);
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
struct peer_incl_svc {
SLIST_ENTRY(peer_incl_svc) next;
struct ble_gatt_incl_svc svc;
};
SLIST_HEAD(peer_incl_svc_list, peer_incl_svc);
#endif
struct peer_svc {
SLIST_ENTRY(peer_svc) next;
struct ble_gatt_svc svc;
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
struct peer_incl_svc_list incl_svc;
#endif
struct peer_chr_list chrs;
};
SLIST_HEAD(peer_svc_list, peer_svc);
struct peer;
typedef void peer_disc_fn(const struct peer *peer, int status, void *arg);
@ -95,7 +105,11 @@ const struct peer_svc *
peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid);
int peer_delete(uint16_t conn_handle);
int peer_add(uint16_t conn_handle);
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
int peer_init(int max_peers, int max_svcs, int max_incl_svcs, int max_chrs, int max_dscs);
#else
int peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs);
#endif
struct peer *
peer_find(uint16_t conn_handle);
#if MYNEWT_VAL(ENC_ADV_DATA)

View File

@ -12,6 +12,10 @@
static void *peer_svc_mem;
static struct os_mempool peer_svc_pool;
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
static void *peer_incl_svc_mem;
static struct os_mempool peer_incl_svc_pool;
#endif
static void *peer_chr_mem;
static struct os_mempool peer_chr_pool;
@ -44,6 +48,13 @@ static int
peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
void *arg);
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
static int
peer_inc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
const struct ble_gatt_incl_svc *service, void *arg);
static void
peer_disc_incs(struct peer *peer);
#endif
struct peer *
peer_find(uint16_t conn_handle)
@ -419,6 +430,189 @@ peer_disc_chrs(struct peer *peer)
peer_disc_dscs(peer);
}
#if (MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES))
static struct peer_incl_svc *
peer_incl_svc_find_prev(const struct peer_svc *svc, uint16_t incl_svc_handle)
{
struct peer_incl_svc *prev;
struct peer_incl_svc *incl_svc;
prev = NULL;
SLIST_FOREACH(incl_svc, &svc->incl_svc, next) {
if (incl_svc->svc.handle >= incl_svc_handle) {
break;
}
prev = incl_svc;
}
return prev;
}
static struct peer_incl_svc *
peer_incl_svc_find(const struct peer_svc *svc, uint16_t incl_svc_handle,
struct peer_incl_svc **out_prev)
{
struct peer_incl_svc *prev;
struct peer_incl_svc *incl_svc;
prev = peer_incl_svc_find_prev(svc, incl_svc_handle);
if (prev == NULL) {
incl_svc = SLIST_FIRST(&svc->incl_svc);
} else {
incl_svc = SLIST_NEXT(prev, next);
}
if (incl_svc != NULL && incl_svc->svc.handle != incl_svc_handle) {
incl_svc = NULL;
}
if (out_prev != NULL) {
*out_prev = prev;
}
return incl_svc;
}
static void
peer_incl_svc_delete(struct peer_incl_svc *incl_svc)
{
os_memblock_put(&peer_incl_svc_pool, incl_svc);
}
static int
peer_inc_add(struct peer *peer, uint16_t svc_start_handle,
const struct ble_gatt_incl_svc *gatt_incl_svc)
{
struct peer_incl_svc *incl_svc;
struct peer_incl_svc *incl_svc_prev;
struct peer_svc *cur_svc;
struct peer_svc *svc;
struct peer_svc *prev;
svc = peer_svc_find(peer, gatt_incl_svc->start_handle, &prev);
if (!svc) {
/* secondary service */
svc = os_memblock_get(&peer_svc_pool);
if (svc == NULL) {
/* out of memory */
return BLE_HS_ENOMEM;
}
memset(svc, 0, sizeof *svc);
svc->svc.start_handle = gatt_incl_svc->start_handle;
svc->svc.end_handle = gatt_incl_svc->end_handle;
memcpy(&svc->svc.uuid, &gatt_incl_svc->uuid, sizeof(ble_uuid_any_t));
SLIST_INIT(&svc->chrs);
SLIST_INIT(&svc->incl_svc);
if (prev == NULL) {
SLIST_INSERT_HEAD(&peer->svcs, svc, next);
} else {
SLIST_INSERT_AFTER(prev, svc, next);
}
}
/* Including the services into inlucding list */
cur_svc = peer_svc_find_range(peer, gatt_incl_svc->handle);
if (cur_svc == NULL) {
/* Can't find service for discovered included service; this shouldn't
* happen.
*/
assert(0);
return BLE_HS_EUNKNOWN;
}
incl_svc = peer_incl_svc_find(cur_svc, gatt_incl_svc->handle, &incl_svc_prev);
if (incl_svc != NULL) {
/* Already discovered */
return 0;
}
incl_svc = os_memblock_get(&peer_incl_svc_pool);
if (incl_svc == NULL) {
return BLE_HS_ENOMEM;
}
incl_svc->svc = *gatt_incl_svc;
if (incl_svc_prev == NULL) {
SLIST_INSERT_HEAD(&cur_svc->incl_svc, incl_svc, next);
} else {
SLIST_INSERT_AFTER(incl_svc_prev, incl_svc, next);
}
BLE_HS_LOG(DEBUG, "Inc Service added with handle = %d", gatt_incl_svc->handle);
return 0;
}
static int
peer_inc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
const struct ble_gatt_incl_svc *service, void *arg)
{
struct peer *peer;
int rc;
peer = arg;
assert(peer->conn_handle == conn_handle);
switch (error->status) {
case 0:
rc = peer_inc_add(peer, peer->cur_svc->svc.start_handle, service);
break;
case BLE_HS_EDONE:
peer_disc_incs(peer);
rc = 0;
break;
default:
rc = error->status;
break;
}
if (rc != 0) {
/* Error; abort discovery. */
peer_disc_complete(peer, rc);
}
return rc;
}
static void
peer_disc_incs(struct peer *peer)
{
struct peer_svc *svc;
int rc;
if (peer->cur_svc == NULL) {
peer->cur_svc = SLIST_FIRST(&peer->svcs);
} else {
peer->cur_svc = SLIST_NEXT(peer->cur_svc, next);
if (peer->cur_svc == NULL) {
if (peer->disc_prev_chr_val > 0) {
peer_disc_chrs(peer);
return;
}
}
}
svc = peer->cur_svc;
rc = ble_gattc_find_inc_svcs(peer->conn_handle,
svc->svc.start_handle,
svc->svc.end_handle,
peer_inc_disced, peer);
if (rc != 0) {
peer_disc_chrs(peer);
}
}
#endif
int
peer_svc_is_empty(const struct peer_svc *svc)
{
@ -575,6 +769,14 @@ peer_svc_delete(struct peer_svc *svc)
{
struct peer_chr *chr;
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
struct peer_incl_svc *incl_svc;
while ((incl_svc = SLIST_FIRST(&svc->incl_svc)) != NULL) {
SLIST_REMOVE_HEAD(&svc->incl_svc, next);
peer_incl_svc_delete(incl_svc);
}
#endif
while ((chr = SLIST_FIRST(&svc->chrs)) != NULL) {
SLIST_REMOVE_HEAD(&svc->chrs, next);
peer_chr_delete(chr);
@ -599,10 +801,16 @@ peer_svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
break;
case BLE_HS_EDONE:
/* All services discovered; start discovering incs.*/
#if (MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES))
peer->cur_svc = NULL;
peer_disc_incs(peer);
#else
/* All services discovered; start discovering characteristics. */
if (peer->disc_prev_chr_val > 0) {
peer_disc_chrs(peer);
}
#endif
rc = 0;
break;
@ -773,6 +981,10 @@ peer_free_mem(void)
free(peer_svc_mem);
peer_svc_mem = NULL;
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
free(peer_incl_svc_mem);
peer_incl_svc_mem = NULL;
#endif
free(peer_chr_mem);
peer_chr_mem = NULL;
@ -780,8 +992,13 @@ peer_free_mem(void)
peer_dsc_mem = NULL;
}
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
int
peer_init(int max_peers, int max_svcs, int max_incl_svcs, int max_chrs, int max_dscs)
#else
int
peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs)
#endif
{
int rc;
@ -818,8 +1035,26 @@ peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs)
goto err;
}
#if MYNEWT_VAL(BLE_INCL_SVC_DISCOVERY) || MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
peer_incl_svc_mem = malloc(
OS_MEMPOOL_BYTES(max_incl_svcs, sizeof(struct peer_incl_svc)));
if (peer_incl_svc_mem == NULL) {
rc = BLE_HS_ENOMEM;
goto err;
}
rc = os_mempool_init(&peer_incl_svc_pool, max_incl_svcs,
sizeof(struct peer_incl_svc), peer_incl_svc_mem,
"peer_incl_svc_pool");
if (rc != 0) {
rc = BLE_HS_EOS;
goto err;
}
#endif
peer_chr_mem = malloc(
OS_MEMPOOL_BYTES(max_chrs, sizeof (struct peer_chr)));
if (peer_chr_mem == NULL) {
rc = BLE_HS_ENOMEM;
goto err;