From b5de5df3191aab48132d83fb7146a8287db39093 Mon Sep 17 00:00:00 2001 From: Graham Wacey Date: Mon, 12 May 2025 15:16:39 +0200 Subject: [PATCH 1/2] samples: Bluetooth: BAP: BA: Reset states and modify error checking Modify the reset function to also reset the connection and PA sync states. Modify and add missing checks for mutex locks to use ASSERT when using K_FOREVER, as they should never fail/timeout. Cleanup some text and error checks. Ensure that the add_src_param is reset for each loop iteration as well. Modify so that we use K_FOREVER fewer places. Signed-off-by: Graham Wacey --- .../bap_broadcast_assistant/src/main.c | 151 +++++++++++------- 1 file changed, 89 insertions(+), 62 deletions(-) diff --git a/samples/bluetooth/bap_broadcast_assistant/src/main.c b/samples/bluetooth/bap_broadcast_assistant/src/main.c index a0471f2ee6f..6458bfe60fe 100644 --- a/samples/bluetooth/bap_broadcast_assistant/src/main.c +++ b/samples/bluetooth/bap_broadcast_assistant/src/main.c @@ -1,11 +1,12 @@ /* * Copyright (c) 2024 Demant A/S - * Copyright (c) 2024 Nordic Semiconductor ASA + * Copyright (c) 2024-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +35,8 @@ #define PA_SYNC_SKIP 5 #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */ /* Broadcast IDs are 24bit, so this is out of valid range */ +/* Default semaphore timeout when waiting for an action */ +#define SEM_TIMEOUT K_SECONDS(10) static void scan_for_broadcast_sink(void); @@ -68,6 +72,7 @@ static K_SEM_DEFINE(sem_sink_disconnected, 0, 1); static K_SEM_DEFINE(sem_security_updated, 0, 1); static K_SEM_DEFINE(sem_bass_discovered, 0, 1); static K_SEM_DEFINE(sem_pa_synced, 0, 1); +static K_SEM_DEFINE(sem_pa_sync_terminted, 0, 1); static K_SEM_DEFINE(sem_received_base_subgroups, 0, 1); static bool device_found(struct bt_data *data, void *user_data) @@ -147,6 +152,7 @@ static bool base_store(struct bt_data *data, void *user_data) const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); int base_size; int base_subgroup_count; + int err; /* Base is NULL if the data does not contain a valid BASE */ if (base == NULL) { @@ -168,13 +174,19 @@ static bool base_store(struct bt_data *data, void *user_data) } /* Compare BASE and copy if different */ - k_mutex_lock(&base_store_mutex, K_FOREVER); + err = k_mutex_lock(&base_store_mutex, K_MSEC(100)); + if (err != 0) { + /* Could not get BASE mutex, wait for new to avoid blocking */ + return false; + } + if ((size_t)base_size != received_base_size || memcmp(base, received_base, (size_t)base_size) != 0) { (void)memcpy(received_base, base, base_size); received_base_size = (size_t)base_size; } - k_mutex_unlock(&base_store_mutex); + err = k_mutex_unlock(&base_store_mutex); + __ASSERT_NO_MSG(err == 0); /* Stop parsing */ k_sem_give(&sem_received_base_subgroups); @@ -419,9 +431,7 @@ static void scan_for_broadcast_source(void) printk("Scanning for Broadcast Source successfully started\n"); err = k_sem_take(&sem_source_discovered, K_FOREVER); - if (err != 0) { - printk("Failed to take sem_source_discovered (err %d)\n", err); - } + __ASSERT_NO_MSG(err == 0); } static void scan_for_broadcast_sink(void) @@ -439,9 +449,7 @@ static void scan_for_broadcast_sink(void) printk("Scanning for Broadcast Sink successfully started\n"); err = k_sem_take(&sem_sink_discovered, K_FOREVER); - if (err != 0) { - printk("Failed to take sem_sink_discovered (err %d)\n", err); - } + __ASSERT_NO_MSG(err == 0); } static void connected(struct bt_conn *conn, uint8_t err) @@ -528,6 +536,16 @@ static void pa_sync_synced_cb(struct bt_le_per_adv_sync *sync, k_sem_give(&sem_pa_synced); } } +static void pa_sync_term_cb(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info) +{ + if (sync == pa_sync) { + printk("PA sync %p terminated with reason %u\n", sync, info->reason); + + k_sem_give(&sem_pa_sync_terminted); + pa_sync = NULL; + } +} static struct bt_bap_broadcast_assistant_cb ba_cbs = { .discover = bap_broadcast_assistant_discover_cb, @@ -536,14 +554,49 @@ static struct bt_bap_broadcast_assistant_cb ba_cbs = { static struct bt_le_per_adv_sync_cb pa_synced_cb = { .synced = pa_sync_synced_cb, + .term = pa_sync_term_cb, .recv = pa_recv, }; static void reset(void) { - printk("\n\nReset...\n\n"); + int err; + + printk("\n\nResetting...\n\n"); + + if (broadcast_sink_conn != NULL) { + err = bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_LOCALHOST_TERM_CONN); + + if (err != 0) { + printk("bt_conn_disconnect failed with %d\n", err); + } else { + if (k_sem_take(&sem_sink_disconnected, SEM_TIMEOUT) != 0) { + /* This should not happen */ + + __ASSERT_NO_MSG(false); + } + } + __ASSERT_NO_MSG(err == 0); + } + + /* Ignore return value as scanning may already be stopped */ + (void)bt_le_scan_stop(); + + if (pa_sync != NULL) { + err = bt_le_per_adv_sync_delete(pa_sync); + + if (err != 0) { + printk("bt_le_per_adv_sync_delete failed with %d\n", err); + } else { + if (k_sem_take(&sem_pa_sync_terminted, SEM_TIMEOUT) != 0) { + /* This should not happen */ + + __ASSERT_NO_MSG(false); + } + } + __ASSERT_NO_MSG(err == 0); + } - broadcast_sink_conn = NULL; selected_broadcast_id = BT_BAP_INVALID_BROADCAST_ID; selected_sid = 0; selected_pa_interval = 0; @@ -568,7 +621,6 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { int main(void) { int err; - struct bt_bap_broadcast_assistant_add_src_param param = { 0 }; err = bt_enable(NULL); if (err) { @@ -585,45 +637,33 @@ int main(void) k_mutex_init(&base_store_mutex); while (true) { + struct bt_bap_broadcast_assistant_add_src_param param = {0}; + + reset(); + scan_for_broadcast_sink(); - err = k_sem_take(&sem_sink_connected, K_FOREVER); + err = k_sem_take(&sem_sink_connected, SEM_TIMEOUT); if (err != 0) { printk("Failed to take sem_sink_connected (err %d)\n", err); + continue; } err = bt_bap_broadcast_assistant_discover(broadcast_sink_conn); if (err != 0) { printk("Failed to discover BASS on the sink (err %d)\n", err); + continue; } - err = k_sem_take(&sem_security_updated, K_SECONDS(10)); + err = k_sem_take(&sem_security_updated, SEM_TIMEOUT); if (err != 0) { - printk("Failed to take sem_security_updated (err %d), resetting\n", err); - bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_AUTH_FAIL); - - if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) { - /* This should not happen */ - return -ETIMEDOUT; - } - - reset(); + printk("Failed to take sem_security_updated (err %d)\n", err); continue; } - err = k_sem_take(&sem_bass_discovered, K_SECONDS(10)); + err = k_sem_take(&sem_bass_discovered, SEM_TIMEOUT); if (err != 0) { - if (err == -EAGAIN) { - printk("Failed to take sem_bass_discovered (err %d)\n", err); - } - bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE); - - if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) { - /* This should not happen */ - return -ETIMEDOUT; - } - - reset(); + printk("Failed to take sem_bass_discovered (err %d)\n", err); continue; } @@ -636,19 +676,19 @@ int main(void) scan_for_broadcast_source(); - printk("Scan stopped, attempting to PA sync to the broadcaster with id 0x%06X\n", + printk("Attempting to PA sync to the broadcaster with id 0x%06X\n", selected_broadcast_id); err = pa_sync_create(); if (err != 0) { - printk("Could not create Broadcast PA sync: %d, resetting\n", err); - return -ETIMEDOUT; + printk("Could not create Broadcast PA sync: %d\n", err); + continue; } printk("Waiting for PA synced\n"); - err = k_sem_take(&sem_pa_synced, K_FOREVER); + err = k_sem_take(&sem_pa_synced, SEM_TIMEOUT); if (err != 0) { - printk("sem_pa_synced timed out, resetting\n"); - return err; + printk("Failed to take sem_pa_synced (err %d)\n", err); + continue; } memset(bass_subgroups, 0, sizeof(bass_subgroups)); @@ -661,42 +701,29 @@ int main(void) /* Wait to receive subgroups */ err = k_sem_take(&sem_received_base_subgroups, K_FOREVER); - if (err != 0) { - printk("Failed to take sem_received_base_subgroups (err %d)\n", err); - return err; - } + __ASSERT_NO_MSG(err == 0); - k_mutex_lock(&base_store_mutex, K_FOREVER); + err = k_mutex_lock(&base_store_mutex, K_FOREVER); + __ASSERT_NO_MSG(err == 0); err = bt_bap_base_foreach_subgroup((const struct bt_bap_base *)received_base, add_pa_sync_base_subgroup_cb, ¶m); - k_mutex_unlock(&base_store_mutex); + err = k_mutex_unlock(&base_store_mutex); + __ASSERT_NO_MSG(err == 0); - if (err < 0) { + if (err != 0) { printk("Could not add BASE to params %d\n", err); continue; } err = bt_bap_broadcast_assistant_add_src(broadcast_sink_conn, ¶m); - if (err) { + if (err != 0) { printk("Failed to add source: %d\n", err); - bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE); - - if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) { - /* This should not happen */ - return -ETIMEDOUT; - } - - reset(); continue; } /* Reset if the sink disconnects */ err = k_sem_take(&sem_sink_disconnected, K_FOREVER); - if (err != 0) { - printk("Failed to take sem_sink_disconnected (err %d)\n", err); - } - - reset(); + __ASSERT_NO_MSG(err == 0); } return 0; From 53e5cc2fe8373624046db8ef6216af210e1d340a Mon Sep 17 00:00:00 2001 From: Graham Wacey Date: Thu, 26 Jun 2025 09:40:24 +0100 Subject: [PATCH 2/2] samples: Bluetooth: BAP: BA: Reset states and modify error checking Modify the reset function to also reset the connection and PA sync states. Modify and add missing checks for mutex locks to use ASSERT when using K_FOREVER, as they should never fail/timeout. Cleanup some text and error checks. Ensure that the add_src_param is reset for each loop iteration as well. Signed-off-by: Graham Wacey --- .../bap_broadcast_assistant/src/main.c | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/samples/bluetooth/bap_broadcast_assistant/src/main.c b/samples/bluetooth/bap_broadcast_assistant/src/main.c index 6458bfe60fe..717c003b5c5 100644 --- a/samples/bluetooth/bap_broadcast_assistant/src/main.c +++ b/samples/bluetooth/bap_broadcast_assistant/src/main.c @@ -31,8 +31,8 @@ #include #include -#define NAME_LEN 30 -#define PA_SYNC_SKIP 5 +#define NAME_LEN 30 +#define PA_SYNC_SKIP 5 #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */ /* Broadcast IDs are 24bit, so this is out of valid range */ /* Default semaphore timeout when waiting for an action */ @@ -59,8 +59,7 @@ static bt_addr_le_t selected_addr; static struct bt_le_per_adv_sync *pa_sync; static uint8_t received_base[UINT8_MAX]; static size_t received_base_size; -static struct bt_bap_bass_subgroup - bass_subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]; +static struct bt_bap_bass_subgroup bass_subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS]; static bool scanning_for_broadcast_source; @@ -194,8 +193,7 @@ static bool base_store(struct bt_data *data, void *user_data) } static void pa_recv(struct bt_le_per_adv_sync *sync, - const struct bt_le_per_adv_sync_recv_info *info, - struct net_buf_simple *buf) + const struct bt_le_per_adv_sync_recv_info *info, struct net_buf_simple *buf) { bt_data_parse(buf, base_store, NULL); } @@ -300,8 +298,7 @@ static int pa_sync_create(void) return bt_le_per_adv_sync_create(&create_params, &pa_sync); } -static void scan_recv_cb(const struct bt_le_scan_recv_info *info, - struct net_buf_simple *ad) +static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad) { int err; struct scan_recv_info sr_info = {0}; @@ -312,8 +309,7 @@ static void scan_recv_cb(const struct bt_le_scan_recv_info *info, sr_info.broadcast_id = BT_BAP_INVALID_BROADCAST_ID; /* We are only interested in non-connectable periodic advertisers */ - if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0 || - info->interval == 0) { + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0 || info->interval == 0) { return; } @@ -494,8 +490,7 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) k_sem_give(&sem_sink_disconnected); } -static void security_changed_cb(struct bt_conn *conn, bt_security_t level, - enum bt_security_err err) +static void security_changed_cb(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { if (err == 0) { printk("Security level changed: %u\n", level); @@ -509,8 +504,7 @@ static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err, uint8_t recv_state_count) { if (err == 0) { - printk("BASS discover done with %u recv states\n", - recv_state_count); + printk("BASS discover done with %u recv states\n", recv_state_count); k_sem_give(&sem_bass_discovered); } else { printk("BASS discover failed (%d)\n", err); @@ -612,11 +606,9 @@ static void reset(void) k_sem_reset(&sem_received_base_subgroups); } -BT_CONN_CB_DEFINE(conn_callbacks) = { - .connected = connected, - .disconnected = disconnected, - .security_changed = security_changed_cb -}; +BT_CONN_CB_DEFINE(conn_callbacks) = {.connected = connected, + .disconnected = disconnected, + .security_changed = security_changed_cb}; int main(void) {