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 28d343b850
commit a201924ee8
6 changed files with 303 additions and 4 deletions

View File

@ -701,6 +701,19 @@ menuconfig BT_NIMBLE_GATT_CACHING
select BT_NIMBLE_DYNAMIC_SERVICE select BT_NIMBLE_DYNAMIC_SERVICE
help help
Enable GATT caching 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 config BT_NIMBLE_GATT_CACHING_MAX_CONNS
int "Maximum connections to be cached" int "Maximum connections to be cached"
depends on BT_NIMBLE_GATT_CACHING depends on BT_NIMBLE_GATT_CACHING
@ -713,6 +726,12 @@ config BT_NIMBLE_GATT_CACHING_MAX_SVCS
default 64 default 64
help help
Set this option to set the upper limit on number of services per connection to be cached. 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 config BT_NIMBLE_GATT_CACHING_MAX_CHRS
int "Maximum number of characteristics per connection" int "Maximum number of characteristics per connection"
depends on BT_NIMBLE_GATT_CACHING 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) #define MYNEWT_VAL_BLE_MAX_PERIODIC_ADVERTISER_LIST (CONFIG_BT_NIMBLE_MAX_PERIODIC_ADVERTISER_LIST)
#endif #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 #ifndef CONFIG_BT_NIMBLE_GATT_CACHING
#define MYNEWT_VAL_BLE_GATT_CACHING (0) #define MYNEWT_VAL_BLE_GATT_CACHING (0)
#else #else
#define MYNEWT_VAL_BLE_GATT_CACHING (CONFIG_BT_NIMBLE_GATT_CACHING) #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 #ifdef CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CONNS
#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CONNS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CONNS) #define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CONNS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CONNS)
#else #else
@ -146,6 +162,14 @@
#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_SVCS (0) #define MYNEWT_VAL_BLE_GATT_CACHING_MAX_SVCS (0)
#endif #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 #ifdef CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CHRS
#define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CHRS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CHRS) #define MYNEWT_VAL_BLE_GATT_CACHING_MAX_CHRS (CONFIG_BT_NIMBLE_GATT_CACHING_MAX_CHRS)
#else #else

View File

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

View File

@ -38,14 +38,24 @@ struct peer_chr {
struct peer_dsc_list dscs; struct peer_dsc_list dscs;
}; };
SLIST_HEAD(peer_chr_list, peer_chr); 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 { struct peer_svc {
SLIST_ENTRY(peer_svc) next; SLIST_ENTRY(peer_svc) next;
struct ble_gatt_svc svc; 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; struct peer_chr_list chrs;
}; };
SLIST_HEAD(peer_svc_list, peer_svc);
struct peer; struct peer;
typedef void peer_disc_fn(const struct peer *peer, int status, void *arg); 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); peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid);
int peer_delete(uint16_t conn_handle); int peer_delete(uint16_t conn_handle);
int peer_add(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); int peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs);
#endif
struct peer * struct peer *
peer_find(uint16_t conn_handle); peer_find(uint16_t conn_handle);
#if MYNEWT_VAL(ENC_ADV_DATA) #if MYNEWT_VAL(ENC_ADV_DATA)

View File

@ -12,6 +12,10 @@
static void *peer_svc_mem; static void *peer_svc_mem;
static struct os_mempool peer_svc_pool; 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 void *peer_chr_mem;
static struct os_mempool peer_chr_pool; 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, peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc, uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
void *arg); 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 * struct peer *
peer_find(uint16_t conn_handle) peer_find(uint16_t conn_handle)
@ -419,6 +430,189 @@ peer_disc_chrs(struct peer *peer)
peer_disc_dscs(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 int
peer_svc_is_empty(const struct peer_svc *svc) peer_svc_is_empty(const struct peer_svc *svc)
{ {
@ -575,6 +769,14 @@ peer_svc_delete(struct peer_svc *svc)
{ {
struct peer_chr *chr; 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) { while ((chr = SLIST_FIRST(&svc->chrs)) != NULL) {
SLIST_REMOVE_HEAD(&svc->chrs, next); SLIST_REMOVE_HEAD(&svc->chrs, next);
peer_chr_delete(chr); peer_chr_delete(chr);
@ -599,10 +801,16 @@ peer_svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error,
break; break;
case BLE_HS_EDONE: 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. */ /* All services discovered; start discovering characteristics. */
if (peer->disc_prev_chr_val > 0) { if (peer->disc_prev_chr_val > 0) {
peer_disc_chrs(peer); peer_disc_chrs(peer);
} }
#endif
rc = 0; rc = 0;
break; break;
@ -773,6 +981,10 @@ peer_free_mem(void)
free(peer_svc_mem); free(peer_svc_mem);
peer_svc_mem = NULL; 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); free(peer_chr_mem);
peer_chr_mem = NULL; peer_chr_mem = NULL;
@ -780,8 +992,13 @@ peer_free_mem(void)
peer_dsc_mem = NULL; 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 int
peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs) peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs)
#endif
{ {
int rc; int rc;
@ -818,8 +1035,26 @@ peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs)
goto err; 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( peer_chr_mem = malloc(
OS_MEMPOOL_BYTES(max_chrs, sizeof (struct peer_chr))); OS_MEMPOOL_BYTES(max_chrs, sizeof (struct peer_chr)));
if (peer_chr_mem == NULL) { if (peer_chr_mem == NULL) {
rc = BLE_HS_ENOMEM; rc = BLE_HS_ENOMEM;
goto err; goto err;