Skip to content
Permalink
Browse files

Bluetooth: GATT: Add support for static services

This reintroduces support for static service in the form of a new API,
BT_GATT_SERVICE_DEFINE, and changes the internal services (GAP/GATT)
to be defined as const as they are never register/unregistered.

Internal service needed to be renamed in order to keep the same order
as before since the section elements are sorted by name.

The result is the following (make ram_report):

before:
      gatt.c                                    572     0.66%
        cf_cfg                                   32     0.04%
        db                                        8     0.01%
        db_hash                                  16     0.02%
        db_hash_work                             32     0.04%
        gap_attrs				180     0.21%
        gap_svc                                  12     0.01%
        gatt_attrs                              160     0.18%
        gatt_sc                                  80     0.09%
        gatt_svc                                 12     0.01%
        sc_ccc_cfg                               32     0.04%
        subscriptions                             8     0.01%

after:
      gatt.c                                    210     0.24%
        cf_cfg                                   32     0.04%
        db                                        8     0.01%
        db_hash                                  16     0.02%
        db_hash_work                             32     0.04%
        gatt_sc                                  80     0.09%
        last_static_handle                        2     0.00%
        sc_ccc_cfg                               32     0.04%
        subscriptions                             8     0.01%

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  • Loading branch information...
Vudentz authored and jhedberg committed Apr 15, 2019
1 parent 0392ad0 commit e0f3ab6bf20e804fc6ac64fbb6f8397ddbd36a60
Showing with 139 additions and 45 deletions.
  1. +21 −0 include/bluetooth/gatt.h
  2. +7 −0 include/linker/common-rom.ld
  3. +1 −1 scripts/sanitycheck
  4. +110 −44 subsys/bluetooth/host/gatt.c
@@ -152,6 +152,14 @@ struct bt_gatt_attr {
u8_t perm;
};

/** @brief GATT Service structure */
struct bt_gatt_service_static {
/** Service Attributes */
const struct bt_gatt_attr *attrs;
/** Service Attribute count */
size_t attr_count;
};

/** @brief GATT Service structure */
struct bt_gatt_service {
/** Service Attributes */
@@ -391,6 +399,19 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf, u16_t len, u16_t offset);

/** @def BT_GATT_SERVICE_DEFINE
* @brief Statically define and register a service.
*
* Helper macro to statically define and register a service.
*
* @param _name Service name.
*/
#define BT_GATT_SERVICE_DEFINE(_name, ...) \
const struct bt_gatt_attr attr_##_name[] = { __VA_ARGS__ }; \
const struct bt_gatt_service_static _name __aligned(4) \
__in_section(_bt_services, static, _name) = \
BT_GATT_SERVICE(attr_##_name)

/** @def BT_GATT_SERVICE
* @brief Service Structure Declaration Macro.
*
@@ -67,6 +67,13 @@
__net_l2_end = .;
} GROUP_LINK_IN(ROMABLE_REGION)

SECTION_DATA_PROLOGUE(_bt_services_area,,SUBALIGN(4))
{
_bt_services_start = .;
KEEP(*(SORT_BY_NAME("._bt_services.static.*")))
_bt_services_end = .;
} GROUP_LINK_IN(ROMABLE_REGION)

#if defined(CONFIG_BT_SETTINGS)
SECTION_DATA_PROLOGUE(_bt_settings_area,,SUBALIGN(4))
{
@@ -884,7 +884,7 @@ class SizeCalculator:
# These get copied into RAM only on non-XIP
ro_sections = ["text", "ctors", "init_array", "reset", "object_access",
"rodata", "devconfig", "net_l2", "vector", "sw_isr_table",
"_bt_settings_area", "vectors"]
"_bt_settings_area", "_bt_services_area", "vectors"]

def __init__(self, filename, extra_sections):
"""Constructor
@@ -48,6 +48,11 @@

#define DB_HASH_TIMEOUT K_MSEC(10)

/* Linker-defined symbols bound to the bt_gatt_service_static structs */
extern const struct bt_gatt_service_static _bt_services_start[];
extern const struct bt_gatt_service_static _bt_services_end[];
static u16_t last_static_handle;

/* Persistent storage format for GATT CCC */
struct ccc_store {
u16_t handle;
@@ -151,7 +156,7 @@ static ssize_t read_central_addr_res(struct bt_conn *conn,
}
#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_PRIVACY */

static struct bt_gatt_attr gap_attrs[] = {
BT_GATT_SERVICE_DEFINE(_2_gap_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_GAP),
#if defined(CONFIG_BT_DEVICE_NAME_GATT_WRITABLE)
/* Require pairing for writes to device name */
@@ -174,9 +179,7 @@ static struct bt_gatt_attr gap_attrs[] = {
BT_GATT_CHARACTERISTIC(BT_UUID_GAP_PPCP, BT_GATT_CHRC_READ,
BT_GATT_PERM_READ, read_ppcp, NULL, NULL),
#endif
};

static struct bt_gatt_service gap_svc = BT_GATT_SERVICE(gap_attrs);
);

static struct bt_gatt_ccc_cfg sc_ccc_cfg[BT_GATT_CCC_MAX] = {};

@@ -484,7 +487,7 @@ static void remove_cf_cfg(struct bt_conn *conn)
}
#endif /* CONFIG_BT_GATT_CACHING */

static struct bt_gatt_attr gatt_attrs[] = {
BT_GATT_SERVICE_DEFINE(_1_gatt_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_GATT),
/* Bluetooth 5.0, Vol3 Part G:
* The Service Changed characteristic Attribute Handle on the server
@@ -503,10 +506,7 @@ static struct bt_gatt_attr gatt_attrs[] = {
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
db_hash_read, NULL, NULL),
#endif /* COFNIG_BT_GATT_CACHING */

};

static struct bt_gatt_service gatt_svc = BT_GATT_SERVICE(gatt_attrs);
);

static int gatt_register(struct bt_gatt_service *svc)
{
@@ -516,7 +516,7 @@ static int gatt_register(struct bt_gatt_service *svc)
u16_t count = svc->attr_count;

if (sys_slist_is_empty(&db)) {
handle = 0U;
handle = last_static_handle;
goto populate;
}

@@ -613,7 +613,7 @@ static void sc_process(struct k_work *work)
sc->start = 0U;
sc->end = 0U;

sc->params.attr = &gatt_attrs[2];
sc->params.attr = &_1_gatt_svc.attrs[2];
sc->params.func = sc_indicate_rsp;
sc->params.data = &sc_range[0];
sc->params.len = sizeof(sc_range);
@@ -681,13 +681,15 @@ static void ccc_delayed_store(struct k_work *work)

void bt_gatt_init(void)
{
const struct bt_gatt_service_static *svc;

if (!atomic_cas(&init, 0, 1)) {
return;
}

/* Register mandatory services */
gatt_register(&gatt_svc);
gatt_register(&gap_svc);
for (svc = _bt_services_start; svc < _bt_services_end; svc++) {
last_static_handle += svc->attr_count;
}

#if defined(CONFIG_BT_GATT_CACHING)
k_delayed_work_init(&db_hash_work, db_hash_process);
@@ -942,13 +944,60 @@ ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn,
return bt_gatt_attr_read(conn, attr, buf, len, offset, &pdu, value_len);
}

static u8_t gatt_foreach_iter(const struct bt_gatt_attr *attr,
u16_t start_handle, u16_t end_handle,
bt_gatt_attr_func_t func, void *user_data)
{
/* Stop if over the requested range */
if (attr->handle > end_handle) {
return BT_GATT_ITER_STOP;
}

/* Check if attribute handle is within range */
if (attr->handle < start_handle) {
return BT_GATT_ITER_CONTINUE;
}

return func(attr, user_data);
}

void bt_gatt_foreach_attr(u16_t start_handle, u16_t end_handle,
bt_gatt_attr_func_t func, void *user_data)
{
struct bt_gatt_service *svc;
int i;

if (start_handle < last_static_handle) {
const struct bt_gatt_service_static *static_svc;
u16_t handle;

for (static_svc = _bt_services_start, handle = 1;
static_svc < _bt_services_end; static_svc++) {
/* Skip ahead if start is not within service handles */
if (handle + static_svc->attr_count < start_handle) {
handle += static_svc->attr_count;
continue;
}

for (i = 0; i < static_svc->attr_count; i++, handle++) {
struct bt_gatt_attr attr;

memcpy(&attr, &static_svc->attrs[i],
sizeof(attr));

attr.handle = handle;

if (gatt_foreach_iter(&attr, start_handle,
end_handle, func,
user_data) ==
BT_GATT_ITER_STOP) {
return;
}
}
}
}

SYS_SLIST_FOR_EACH_CONTAINER(&db, svc, node) {
int i;
struct bt_gatt_service *next;

next = SYS_SLIST_PEEK_NEXT_CONTAINER(svc, node);
@@ -962,17 +1011,9 @@ void bt_gatt_foreach_attr(u16_t start_handle, u16_t end_handle,
for (i = 0; i < svc->attr_count; i++) {
struct bt_gatt_attr *attr = &svc->attrs[i];

/* Stop if over the requested range */
if (attr->handle > end_handle) {
return;
}

/* Check if attribute handle is within range */
if (attr->handle < start_handle) {
continue;
}

if (func(attr, user_data) == BT_GATT_ITER_STOP) {
if (gatt_foreach_iter(attr, start_handle,
end_handle, func, user_data) ==
BT_GATT_ITER_STOP) {
return;
}
}
@@ -1169,6 +1210,23 @@ ssize_t bt_gatt_attr_read_cpf(struct bt_conn *conn,
sizeof(*value));
}

static u16_t find_static_attr(const struct bt_gatt_attr *attr)
{
const struct bt_gatt_service_static *static_svc;
u16_t handle;

for (static_svc = _bt_services_start, handle = 1;
static_svc < _bt_services_end; static_svc++) {
for (int i = 0; i < static_svc->attr_count; i++, handle++) {
if (attr == &static_svc->attrs[i]) {
return handle;
}
}
}

return 0;
}

struct notify_data {
int err;
u16_t type;
@@ -1247,12 +1305,11 @@ static int gatt_send(struct bt_conn *conn, struct net_buf *buf,
return err;
}

static int gatt_indicate(struct bt_conn *conn,
static int gatt_indicate(struct bt_conn *conn, u16_t handle,
struct bt_gatt_indicate_params *params)
{
struct net_buf *buf;
struct bt_att_indicate *ind;
u16_t value_handle = params->attr->handle;

#if defined(CONFIG_BT_GATT_ENFORCE_CHANGE_UNAWARE)
/* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2350:
@@ -1266,7 +1323,6 @@ static int gatt_indicate(struct bt_conn *conn,
}
#endif


/* Check if attribute is a characteristic then adjust the handle */
if (!bt_uuid_cmp(params->attr->uuid, BT_UUID_GATT_CHRC)) {
struct bt_gatt_chrc *chrc = params->attr->user_data;
@@ -1275,7 +1331,7 @@ static int gatt_indicate(struct bt_conn *conn,
return -EINVAL;
}

value_handle += 1U;
handle++;
}

buf = bt_att_create_pdu(conn, BT_ATT_OP_INDICATE,
@@ -1285,10 +1341,10 @@ static int gatt_indicate(struct bt_conn *conn,
return -ENOMEM;
}

BT_DBG("conn %p handle 0x%04x", conn, value_handle);
BT_DBG("conn %p handle 0x%04x", conn, handle);

ind = net_buf_add(buf, sizeof(*ind));
ind->handle = sys_cpu_to_le16(value_handle);
ind->handle = sys_cpu_to_le16(handle);

net_buf_add(buf, params->len);
memcpy(ind->value, params->data, params->len);
@@ -1382,11 +1438,11 @@ static u8_t notify_cb(const struct bt_gatt_attr *attr, void *user_data)
}

if (data->type == BT_GATT_CCC_INDICATE) {
err = gatt_indicate(conn, data->params);
err = gatt_indicate(conn, attr->handle - 1,
data->params);
} else {
err = gatt_notify(conn, data->attr->handle,
data->data, data->len,
data->func);
err = gatt_notify(conn, attr->handle - 1, data->data,
data->len, data->func);
}

bt_conn_unref(conn);
@@ -1406,9 +1462,14 @@ int bt_gatt_notify_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
bt_gatt_complete_func_t func)
{
struct notify_data nfy;
u16_t handle;

__ASSERT(attr && attr->handle,
"invalid parameters\n");
__ASSERT(attr, "invalid parameters\n");

handle = attr->handle ? : find_static_attr(attr);
if (!handle) {
return -ENOENT;
}

/* Check if attribute is a characteristic then adjust the handle */
if (!bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CHRC)) {
@@ -1418,12 +1479,11 @@ int bt_gatt_notify_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
return -EINVAL;
}

attr++;
handle++;
}

if (conn) {
return gatt_notify(conn, attr->handle, data,
len, func);
return gatt_notify(conn, handle, data, len, func);
}

nfy.err = -ENOTCONN;
@@ -1433,7 +1493,7 @@ int bt_gatt_notify_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr,
nfy.data = data;
nfy.len = len;

bt_gatt_foreach_attr(attr->handle, 0xffff, notify_cb, &nfy);
bt_gatt_foreach_attr(handle, 0xffff, notify_cb, &nfy);

return nfy.err;
}
@@ -1442,12 +1502,18 @@ int bt_gatt_indicate(struct bt_conn *conn,
struct bt_gatt_indicate_params *params)
{
struct notify_data nfy;
u16_t handle;

__ASSERT(params, "invalid parameters\n");
__ASSERT(params->attr && params->attr->handle, "invalid parameters\n");
__ASSERT(params->attr, "invalid parameters\n");

handle = params->attr->handle ? : find_static_attr(params->attr);
if (!handle) {
return -ENOENT;
}

if (conn) {
return gatt_indicate(conn, params);
return gatt_indicate(conn, handle, params);
}

nfy.err = -ENOTCONN;

0 comments on commit e0f3ab6

Please sign in to comment.
You can’t perform that action at this time.