Bluetooth: GATT: Allow application to add subscription.

Allow the application to add subscription without resubscribing.
This is needed for persistent bonds that can go to deep sleep and
turn of the RAM or power-cycle.
In this case the application as a GATT client must have a way to add
the subscription callbacks back to the stack before the GATT server
sends notifications.
This should preferable be able to be done before even connecting
since the notifications can arrive immediately after connecting to
the peer.
The stack cannot persist this on it's own since it must remember the
function pointers for the callback functions. Storing these in
persistent storage would not be compatible with a Device Firmware
Upgrade (DFU) solution.

Fixes: #21798

Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
This commit is contained in:
Joakim Andersson 2020-09-03 21:51:45 +02:00 committed by Carles Cufí
commit 76119c526e
2 changed files with 78 additions and 0 deletions

View file

@ -1441,6 +1441,25 @@ struct bt_gatt_subscribe_params {
int bt_gatt_subscribe(struct bt_conn *conn, int bt_gatt_subscribe(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params); struct bt_gatt_subscribe_params *params);
/** @brief Resubscribe Attribute Value Notification subscription
*
* Resubscribe to Attribute Value Notification when already subscribed from a
* previous connection. The GATT server will remember subscription from
* previous connections when bonded, so resubscribing can be done without
* performing a new subscribe procedure after a power cycle.
*
* @note Notifications are asynchronous therefore the parameters need to
* remain valid while subscribed.
*
* @param id Local identity (in most cases BT_ID_DEFAULT).
* @param peer Remote address.
* @param params Subscribe parameters.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_gatt_resubscribe(uint8_t id, const bt_addr_le_t *peer,
struct bt_gatt_subscribe_params *params);
/** @brief Unsubscribe Attribute Value Notification /** @brief Unsubscribe Attribute Value Notification
* *
* This procedure unsubscribe to value notification using the Client * This procedure unsubscribe to value notification using the Client

View file

@ -2522,6 +2522,37 @@ static struct gatt_sub *gatt_sub_add(struct bt_conn *conn)
return sub; return sub;
} }
static struct gatt_sub *gatt_sub_find_by_addr(uint8_t id,
const bt_addr_le_t *addr)
{
for (int i = 0; i < ARRAY_SIZE(subscriptions); i++) {
struct gatt_sub *sub = &subscriptions[i];
if (id == sub->id && !bt_addr_le_cmp(&sub->peer, addr)) {
return sub;
}
}
return NULL;
}
static struct gatt_sub *gatt_sub_add_by_addr(uint8_t id,
const bt_addr_le_t *addr)
{
struct gatt_sub *sub;
sub = gatt_sub_find_by_addr(id, addr);
if (!sub) {
sub = gatt_sub_find(NULL);
if (sub) {
bt_addr_le_copy(&sub->peer, addr);
sub->id = id;
}
}
return sub;
}
void bt_gatt_notification(struct bt_conn *conn, uint16_t handle, void bt_gatt_notification(struct bt_conn *conn, uint16_t handle,
const void *data, uint16_t length) const void *data, uint16_t length)
{ {
@ -4075,6 +4106,34 @@ int bt_gatt_subscribe(struct bt_conn *conn,
return 0; return 0;
} }
int bt_gatt_resubscribe(uint8_t id, const bt_addr_le_t *peer,
struct bt_gatt_subscribe_params *params)
{
struct gatt_sub *sub;
struct bt_gatt_subscribe_params *tmp;
__ASSERT(params && params->notify, "invalid parameters\n");
__ASSERT(params->value, "invalid parameters\n");
__ASSERT(params->ccc_handle, "invalid parameters\n");
sub = gatt_sub_add_by_addr(id, peer);
if (!sub) {
return -ENOMEM;
}
/* Lookup existing subscriptions */
SYS_SLIST_FOR_EACH_CONTAINER(&sub->list, tmp, node) {
/* Fail if entry already exists */
if (tmp == params) {
gatt_sub_remove(NULL, sub, NULL, NULL);
return -EALREADY;
}
}
sys_slist_prepend(&sub->list, &params->node);
return 0;
}
int bt_gatt_unsubscribe(struct bt_conn *conn, int bt_gatt_unsubscribe(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params) struct bt_gatt_subscribe_params *params)
{ {