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>
This commit is contained in:
parent
0392ad0dc8
commit
e0f3ab6bf2
4 changed files with 139 additions and 45 deletions
|
@ -152,6 +152,14 @@ struct bt_gatt_attr {
|
||||||
u8_t perm;
|
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 */
|
/** @brief GATT Service structure */
|
||||||
struct bt_gatt_service {
|
struct bt_gatt_service {
|
||||||
/** Service Attributes */
|
/** Service Attributes */
|
||||||
|
@ -391,6 +399,19 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn,
|
||||||
const struct bt_gatt_attr *attr,
|
const struct bt_gatt_attr *attr,
|
||||||
void *buf, u16_t len, u16_t offset);
|
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
|
/** @def BT_GATT_SERVICE
|
||||||
* @brief Service Structure Declaration Macro.
|
* @brief Service Structure Declaration Macro.
|
||||||
*
|
*
|
||||||
|
|
|
@ -67,6 +67,13 @@
|
||||||
__net_l2_end = .;
|
__net_l2_end = .;
|
||||||
} GROUP_LINK_IN(ROMABLE_REGION)
|
} 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)
|
#if defined(CONFIG_BT_SETTINGS)
|
||||||
SECTION_DATA_PROLOGUE(_bt_settings_area,,SUBALIGN(4))
|
SECTION_DATA_PROLOGUE(_bt_settings_area,,SUBALIGN(4))
|
||||||
{
|
{
|
||||||
|
|
|
@ -884,7 +884,7 @@ class SizeCalculator:
|
||||||
# These get copied into RAM only on non-XIP
|
# These get copied into RAM only on non-XIP
|
||||||
ro_sections = ["text", "ctors", "init_array", "reset", "object_access",
|
ro_sections = ["text", "ctors", "init_array", "reset", "object_access",
|
||||||
"rodata", "devconfig", "net_l2", "vector", "sw_isr_table",
|
"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):
|
def __init__(self, filename, extra_sections):
|
||||||
"""Constructor
|
"""Constructor
|
||||||
|
|
|
@ -48,6 +48,11 @@
|
||||||
|
|
||||||
#define DB_HASH_TIMEOUT K_MSEC(10)
|
#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 */
|
/* Persistent storage format for GATT CCC */
|
||||||
struct ccc_store {
|
struct ccc_store {
|
||||||
u16_t handle;
|
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 */
|
#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),
|
BT_GATT_PRIMARY_SERVICE(BT_UUID_GAP),
|
||||||
#if defined(CONFIG_BT_DEVICE_NAME_GATT_WRITABLE)
|
#if defined(CONFIG_BT_DEVICE_NAME_GATT_WRITABLE)
|
||||||
/* Require pairing for writes to device name */
|
/* 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_CHARACTERISTIC(BT_UUID_GAP_PPCP, BT_GATT_CHRC_READ,
|
||||||
BT_GATT_PERM_READ, read_ppcp, NULL, NULL),
|
BT_GATT_PERM_READ, read_ppcp, NULL, NULL),
|
||||||
#endif
|
#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] = {};
|
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 */
|
#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),
|
BT_GATT_PRIMARY_SERVICE(BT_UUID_GATT),
|
||||||
/* Bluetooth 5.0, Vol3 Part G:
|
/* Bluetooth 5.0, Vol3 Part G:
|
||||||
* The Service Changed characteristic Attribute Handle on the server
|
* 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,
|
BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
|
||||||
db_hash_read, NULL, NULL),
|
db_hash_read, NULL, NULL),
|
||||||
#endif /* COFNIG_BT_GATT_CACHING */
|
#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)
|
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;
|
u16_t count = svc->attr_count;
|
||||||
|
|
||||||
if (sys_slist_is_empty(&db)) {
|
if (sys_slist_is_empty(&db)) {
|
||||||
handle = 0U;
|
handle = last_static_handle;
|
||||||
goto populate;
|
goto populate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,7 +613,7 @@ static void sc_process(struct k_work *work)
|
||||||
sc->start = 0U;
|
sc->start = 0U;
|
||||||
sc->end = 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.func = sc_indicate_rsp;
|
||||||
sc->params.data = &sc_range[0];
|
sc->params.data = &sc_range[0];
|
||||||
sc->params.len = sizeof(sc_range);
|
sc->params.len = sizeof(sc_range);
|
||||||
|
@ -681,13 +681,15 @@ static void ccc_delayed_store(struct k_work *work)
|
||||||
|
|
||||||
void bt_gatt_init(void)
|
void bt_gatt_init(void)
|
||||||
{
|
{
|
||||||
|
const struct bt_gatt_service_static *svc;
|
||||||
|
|
||||||
if (!atomic_cas(&init, 0, 1)) {
|
if (!atomic_cas(&init, 0, 1)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register mandatory services */
|
for (svc = _bt_services_start; svc < _bt_services_end; svc++) {
|
||||||
gatt_register(&gatt_svc);
|
last_static_handle += svc->attr_count;
|
||||||
gatt_register(&gap_svc);
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_BT_GATT_CACHING)
|
#if defined(CONFIG_BT_GATT_CACHING)
|
||||||
k_delayed_work_init(&db_hash_work, db_hash_process);
|
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);
|
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,
|
void bt_gatt_foreach_attr(u16_t start_handle, u16_t end_handle,
|
||||||
bt_gatt_attr_func_t func, void *user_data)
|
bt_gatt_attr_func_t func, void *user_data)
|
||||||
{
|
{
|
||||||
struct bt_gatt_service *svc;
|
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) {
|
SYS_SLIST_FOR_EACH_CONTAINER(&db, svc, node) {
|
||||||
int i;
|
|
||||||
struct bt_gatt_service *next;
|
struct bt_gatt_service *next;
|
||||||
|
|
||||||
next = SYS_SLIST_PEEK_NEXT_CONTAINER(svc, node);
|
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++) {
|
for (i = 0; i < svc->attr_count; i++) {
|
||||||
struct bt_gatt_attr *attr = &svc->attrs[i];
|
struct bt_gatt_attr *attr = &svc->attrs[i];
|
||||||
|
|
||||||
/* Stop if over the requested range */
|
if (gatt_foreach_iter(attr, start_handle,
|
||||||
if (attr->handle > end_handle) {
|
end_handle, func, user_data) ==
|
||||||
return;
|
BT_GATT_ITER_STOP) {
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if attribute handle is within range */
|
|
||||||
if (attr->handle < start_handle) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (func(attr, user_data) == BT_GATT_ITER_STOP) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1169,6 +1210,23 @@ ssize_t bt_gatt_attr_read_cpf(struct bt_conn *conn,
|
||||||
sizeof(*value));
|
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 {
|
struct notify_data {
|
||||||
int err;
|
int err;
|
||||||
u16_t type;
|
u16_t type;
|
||||||
|
@ -1247,12 +1305,11 @@ static int gatt_send(struct bt_conn *conn, struct net_buf *buf,
|
||||||
return err;
|
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 bt_gatt_indicate_params *params)
|
||||||
{
|
{
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
struct bt_att_indicate *ind;
|
struct bt_att_indicate *ind;
|
||||||
u16_t value_handle = params->attr->handle;
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_GATT_ENFORCE_CHANGE_UNAWARE)
|
#if defined(CONFIG_BT_GATT_ENFORCE_CHANGE_UNAWARE)
|
||||||
/* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2350:
|
/* 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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Check if attribute is a characteristic then adjust the handle */
|
/* Check if attribute is a characteristic then adjust the handle */
|
||||||
if (!bt_uuid_cmp(params->attr->uuid, BT_UUID_GATT_CHRC)) {
|
if (!bt_uuid_cmp(params->attr->uuid, BT_UUID_GATT_CHRC)) {
|
||||||
struct bt_gatt_chrc *chrc = params->attr->user_data;
|
struct bt_gatt_chrc *chrc = params->attr->user_data;
|
||||||
|
@ -1275,7 +1331,7 @@ static int gatt_indicate(struct bt_conn *conn,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_handle += 1U;
|
handle++;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = bt_att_create_pdu(conn, BT_ATT_OP_INDICATE,
|
buf = bt_att_create_pdu(conn, BT_ATT_OP_INDICATE,
|
||||||
|
@ -1285,10 +1341,10 @@ static int gatt_indicate(struct bt_conn *conn,
|
||||||
return -ENOMEM;
|
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 = 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);
|
net_buf_add(buf, params->len);
|
||||||
memcpy(ind->value, params->data, 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) {
|
if (data->type == BT_GATT_CCC_INDICATE) {
|
||||||
err = gatt_indicate(conn, data->params);
|
err = gatt_indicate(conn, attr->handle - 1,
|
||||||
|
data->params);
|
||||||
} else {
|
} else {
|
||||||
err = gatt_notify(conn, data->attr->handle,
|
err = gatt_notify(conn, attr->handle - 1, data->data,
|
||||||
data->data, data->len,
|
data->len, data->func);
|
||||||
data->func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_conn_unref(conn);
|
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)
|
bt_gatt_complete_func_t func)
|
||||||
{
|
{
|
||||||
struct notify_data nfy;
|
struct notify_data nfy;
|
||||||
|
u16_t handle;
|
||||||
|
|
||||||
__ASSERT(attr && attr->handle,
|
__ASSERT(attr, "invalid parameters\n");
|
||||||
"invalid parameters\n");
|
|
||||||
|
handle = attr->handle ? : find_static_attr(attr);
|
||||||
|
if (!handle) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if attribute is a characteristic then adjust the handle */
|
/* Check if attribute is a characteristic then adjust the handle */
|
||||||
if (!bt_uuid_cmp(attr->uuid, BT_UUID_GATT_CHRC)) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr++;
|
handle++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn) {
|
if (conn) {
|
||||||
return gatt_notify(conn, attr->handle, data,
|
return gatt_notify(conn, handle, data, len, func);
|
||||||
len, func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nfy.err = -ENOTCONN;
|
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.data = data;
|
||||||
nfy.len = len;
|
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;
|
return nfy.err;
|
||||||
}
|
}
|
||||||
|
@ -1442,12 +1502,18 @@ int bt_gatt_indicate(struct bt_conn *conn,
|
||||||
struct bt_gatt_indicate_params *params)
|
struct bt_gatt_indicate_params *params)
|
||||||
{
|
{
|
||||||
struct notify_data nfy;
|
struct notify_data nfy;
|
||||||
|
u16_t handle;
|
||||||
|
|
||||||
__ASSERT(params, "invalid parameters\n");
|
__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) {
|
if (conn) {
|
||||||
return gatt_indicate(conn, params);
|
return gatt_indicate(conn, handle, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
nfy.err = -ENOTCONN;
|
nfy.err = -ENOTCONN;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue