Skip to content

Commit

Permalink
Bluetooth: audio: has: Add non-volatile settings
Browse files Browse the repository at this point in the history
This adds non-volatile settings for the HAS Server. Those are needed to
restore the client awareness of preset list entries exposed by the
server. Based on the settings, the implementation determines how to
notify the client about the HAS related characteristic value changes.

Signed-off-by: Mariusz Skamra <mariusz.skamra@codecoup.pl>
  • Loading branch information
MariuszSkamra committed Oct 30, 2023
1 parent bc43e89 commit bf22800
Showing 1 changed file with 87 additions and 21 deletions.
108 changes: 87 additions & 21 deletions subsys/bluetooth/audio/has.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <zephyr/sys/slist.h>

#include "../bluetooth/host/hci_core.h"
#include "../bluetooth/host/settings.h"
#include "audio_internal.h"
#include "has_internal.h"

Expand Down Expand Up @@ -298,8 +299,6 @@ static struct has_client *client_alloc(struct bt_conn *conn)
}

LOG_DBG("New client_context for %s", bt_addr_le_str(info.le.dst));
} else {
LOG_DBG("Restored client_context for %s", bt_addr_le_str(info.le.dst));
}

return client;
Expand Down Expand Up @@ -508,26 +507,15 @@ static void bond_deleted_cb(uint8_t id, const bt_addr_le_t *addr)
if (context != NULL) {
context_free(context);
}

if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_settings_delete("has", 0, addr);
}
}

static struct bt_conn_auth_info_cb auth_info_cb = {
.bond_deleted = bond_deleted_cb,
};

static void restore_client_context(const struct bt_bond_info *info, void *user_data)
{
struct client_context *context;

context = context_alloc(&info->addr);
if (context == NULL) {
LOG_ERR("Failed to allocate client_context for %s", bt_addr_le_str(&info->addr));
return;
}

/* Notify all the characteristics values after reboot */
atomic_set(context->flags, BONDED_CLIENT_INIT_FLAGS);
}

#endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */

#if defined(CONFIG_BT_HAS_PRESET_SUPPORT)
Expand Down Expand Up @@ -868,19 +856,97 @@ static int bt_has_cp_generic_update(struct has_client *client, uint8_t prev_inde
}
}

#if defined(CONFIG_BT_SETTINGS)
struct client_context_store {
/* Last notified preset index */
uint8_t last_preset_index_known;
};

static int settings_set_cb(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg)
{
struct client_context_store store;
struct client_context *context;
bt_addr_le_t addr;
ssize_t len;
int err;

if (!name) {
LOG_ERR("Insufficient number of arguments");
return -EINVAL;
}

err = bt_settings_decode_key(name, &addr);
if (err) {
LOG_ERR("Unable to decode address %s", name);
return -EINVAL;
}

context = context_find(&addr);
if (context == NULL) {
/* Find and initialize a free entry */
context = context_alloc(&addr);
if (context == NULL) {
LOG_ERR("Failed to allocate client_context for %s", bt_addr_le_str(&addr));
return -ENOMEM;
}
}

if (len_rd) {
len = read_cb(cb_arg, &store, sizeof(store));
if (len < 0) {
LOG_ERR("Failed to decode value (err %zd)", len);
return len;
}

context->last_preset_index_known = store.last_preset_index_known;
} else {
context->last_preset_index_known = 0x00;
}

/* Notify all the characteristics values after reboot */
atomic_set(context->flags, BONDED_CLIENT_INIT_FLAGS);

return 0;
}

BT_SETTINGS_DEFINE(has, "has", settings_set_cb, NULL);

static void store_client_context(struct client_context *context)
{
struct client_context_store store = {
.last_preset_index_known = context->last_preset_index_known,
};
int err;

LOG_DBG("%s last_preset_index_known 0x%02x",
bt_addr_le_str(&context->addr), store.last_preset_index_known);

err = bt_settings_store("has", 0, &context->addr, &store, sizeof(store));
if (err != 0) {
LOG_ERR("Failed to store err %d", err);
}
}
#else
#define store_client_context(...)
#endif /* CONFIG_BT_SETTINGS */

static void update_last_preset_index_known(struct has_client *client, uint8_t index)
{
if (client != NULL) {
if (client != NULL && client->context != NULL &&
client->context->last_preset_index_known != index) {
client->context->last_preset_index_known = index;
store_client_context(client->context);
return;
}

for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) {
client = &has_client_list[i];

/* For each connected client */
if (client->conn != NULL && client->context != NULL) {
if (client->conn != NULL && client->context != NULL &&
client->context->last_preset_index_known != index) {
client->context->last_preset_index_known = index;
store_client_context(client->context);
}
}
}
Expand Down Expand Up @@ -933,6 +999,8 @@ static int bt_has_cp_preset_record_deleted(struct has_client *client, uint8_t in
NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) +
sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t));

LOG_DBG("client %p index 0x%02x", client, index);

preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_DELETED, BT_HAS_IS_LAST);
net_buf_simple_add_u8(&buf, index);

Expand Down Expand Up @@ -1709,8 +1777,6 @@ int bt_has_register(const struct bt_has_features_param *features)

#if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE)
bt_conn_auth_info_cb_register(&auth_info_cb);

bt_foreach_bond(BT_ID_DEFAULT, restore_client_context, NULL);
#endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */

has.registered = true;
Expand Down

0 comments on commit bf22800

Please sign in to comment.