11/*
22 * Copyright (c) 2024 Demant A/S
3- * Copyright (c) 2024 Nordic Semiconductor ASA
3+ * Copyright (c) 2024-2025 Nordic Semiconductor ASA
44 *
55 * SPDX-License-Identifier: Apache-2.0
66 */
77
88#include <errno.h>
9+ #include <stdbool.h>
910#include <stddef.h>
1011#include <stdint.h>
1112#include <string.h>
2425#include <zephyr/bluetooth/uuid.h>
2526#include <zephyr/kernel.h>
2627#include <zephyr/net_buf.h>
28+ #include <zephyr/sys/__assert.h>
2729#include <zephyr/sys/byteorder.h>
2830#include <zephyr/sys/printk.h>
2931#include <zephyr/sys/util.h>
3335#define PA_SYNC_SKIP 5
3436#define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */
3537/* Broadcast IDs are 24bit, so this is out of valid range */
38+ /* Default semaphore timeout when waiting for an action */
39+ #define SEM_TIMEOUT K_SECONDS(10)
3640
3741static void scan_for_broadcast_sink (void );
3842
@@ -68,6 +72,7 @@ static K_SEM_DEFINE(sem_sink_disconnected, 0, 1);
6872static K_SEM_DEFINE (sem_security_updated , 0 , 1 ) ;
6973static K_SEM_DEFINE (sem_bass_discovered , 0 , 1 ) ;
7074static K_SEM_DEFINE (sem_pa_synced , 0 , 1 ) ;
75+ static K_SEM_DEFINE (sem_pa_sync_terminted , 0 , 1 ) ;
7176static K_SEM_DEFINE (sem_received_base_subgroups , 0 , 1 ) ;
7277
7378static 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)
147152 const struct bt_bap_base * base = bt_bap_base_get_base_from_ad (data );
148153 int base_size ;
149154 int base_subgroup_count ;
155+ int err ;
150156
151157 /* Base is NULL if the data does not contain a valid BASE */
152158 if (base == NULL ) {
@@ -168,13 +174,19 @@ static bool base_store(struct bt_data *data, void *user_data)
168174 }
169175
170176 /* Compare BASE and copy if different */
171- k_mutex_lock (& base_store_mutex , K_FOREVER );
177+ err = k_mutex_lock (& base_store_mutex , K_MSEC (100 ));
178+ if (err != 0 ) {
179+ /* Could not get BASE mutex, wait for new to avoid blocking */
180+ return false;
181+ }
182+
172183 if ((size_t )base_size != received_base_size ||
173184 memcmp (base , received_base , (size_t )base_size ) != 0 ) {
174185 (void )memcpy (received_base , base , base_size );
175186 received_base_size = (size_t )base_size ;
176187 }
177- k_mutex_unlock (& base_store_mutex );
188+ err = k_mutex_unlock (& base_store_mutex );
189+ __ASSERT_NO_MSG (err == 0 );
178190
179191 /* Stop parsing */
180192 k_sem_give (& sem_received_base_subgroups );
@@ -419,9 +431,7 @@ static void scan_for_broadcast_source(void)
419431 printk ("Scanning for Broadcast Source successfully started\n" );
420432
421433 err = k_sem_take (& sem_source_discovered , K_FOREVER );
422- if (err != 0 ) {
423- printk ("Failed to take sem_source_discovered (err %d)\n" , err );
424- }
434+ __ASSERT_NO_MSG (err == 0 );
425435}
426436
427437static void scan_for_broadcast_sink (void )
@@ -439,9 +449,7 @@ static void scan_for_broadcast_sink(void)
439449 printk ("Scanning for Broadcast Sink successfully started\n" );
440450
441451 err = k_sem_take (& sem_sink_discovered , K_FOREVER );
442- if (err != 0 ) {
443- printk ("Failed to take sem_sink_discovered (err %d)\n" , err );
444- }
452+ __ASSERT_NO_MSG (err == 0 );
445453}
446454
447455static 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,
528536 k_sem_give (& sem_pa_synced );
529537 }
530538}
539+ static void pa_sync_term_cb (struct bt_le_per_adv_sync * sync ,
540+ const struct bt_le_per_adv_sync_term_info * info )
541+ {
542+ if (sync == pa_sync ) {
543+ printk ("PA sync %p terminated with reason %u\n" , sync , info -> reason );
544+
545+ k_sem_give (& sem_pa_sync_terminted );
546+ pa_sync = NULL ;
547+ }
548+ }
531549
532550static struct bt_bap_broadcast_assistant_cb ba_cbs = {
533551 .discover = bap_broadcast_assistant_discover_cb ,
@@ -536,14 +554,49 @@ static struct bt_bap_broadcast_assistant_cb ba_cbs = {
536554
537555static struct bt_le_per_adv_sync_cb pa_synced_cb = {
538556 .synced = pa_sync_synced_cb ,
557+ .term = pa_sync_term_cb ,
539558 .recv = pa_recv ,
540559};
541560
542561static void reset (void )
543562{
544- printk ("\n\nReset...\n\n" );
563+ int err ;
564+
565+ printk ("\n\nResetting...\n\n" );
566+
567+ if (broadcast_sink_conn != NULL ) {
568+ err = bt_conn_disconnect (broadcast_sink_conn , BT_HCI_ERR_LOCALHOST_TERM_CONN );
569+
570+ if (err != 0 ) {
571+ printk ("bt_conn_disconnect failed with %d\n" , err );
572+ } else {
573+ if (k_sem_take (& sem_sink_disconnected , SEM_TIMEOUT ) != 0 ) {
574+ /* This should not happen */
575+
576+ __ASSERT_NO_MSG (false);
577+ }
578+ }
579+ __ASSERT_NO_MSG (err == 0 );
580+ }
581+
582+ /* Ignore return value as scanning may already be stopped */
583+ (void )bt_le_scan_stop ();
584+
585+ if (pa_sync != NULL ) {
586+ err = bt_le_per_adv_sync_delete (pa_sync );
587+
588+ if (err != 0 ) {
589+ printk ("bt_le_per_adv_sync_delete failed with %d\n" , err );
590+ } else {
591+ if (k_sem_take (& sem_pa_sync_terminted , SEM_TIMEOUT ) != 0 ) {
592+ /* This should not happen */
593+
594+ __ASSERT_NO_MSG (false);
595+ }
596+ }
597+ __ASSERT_NO_MSG (err == 0 );
598+ }
545599
546- broadcast_sink_conn = NULL ;
547600 selected_broadcast_id = BT_BAP_INVALID_BROADCAST_ID ;
548601 selected_sid = 0 ;
549602 selected_pa_interval = 0 ;
@@ -568,7 +621,6 @@ BT_CONN_CB_DEFINE(conn_callbacks) = {
568621int main (void )
569622{
570623 int err ;
571- struct bt_bap_broadcast_assistant_add_src_param param = { 0 };
572624
573625 err = bt_enable (NULL );
574626 if (err ) {
@@ -585,45 +637,33 @@ int main(void)
585637 k_mutex_init (& base_store_mutex );
586638
587639 while (true) {
640+ struct bt_bap_broadcast_assistant_add_src_param param = {0 };
641+
642+ reset ();
643+
588644 scan_for_broadcast_sink ();
589645
590- err = k_sem_take (& sem_sink_connected , K_FOREVER );
646+ err = k_sem_take (& sem_sink_connected , SEM_TIMEOUT );
591647 if (err != 0 ) {
592648 printk ("Failed to take sem_sink_connected (err %d)\n" , err );
649+ continue ;
593650 }
594651
595652 err = bt_bap_broadcast_assistant_discover (broadcast_sink_conn );
596653 if (err != 0 ) {
597654 printk ("Failed to discover BASS on the sink (err %d)\n" , err );
655+ continue ;
598656 }
599657
600- err = k_sem_take (& sem_security_updated , K_SECONDS ( 10 ) );
658+ err = k_sem_take (& sem_security_updated , SEM_TIMEOUT );
601659 if (err != 0 ) {
602- printk ("Failed to take sem_security_updated (err %d), resetting\n" , err );
603- bt_conn_disconnect (broadcast_sink_conn , BT_HCI_ERR_AUTH_FAIL );
604-
605- if (k_sem_take (& sem_sink_disconnected , K_SECONDS (10 )) != 0 ) {
606- /* This should not happen */
607- return - ETIMEDOUT ;
608- }
609-
610- reset ();
660+ printk ("Failed to take sem_security_updated (err %d)\n" , err );
611661 continue ;
612662 }
613663
614- err = k_sem_take (& sem_bass_discovered , K_SECONDS ( 10 ) );
664+ err = k_sem_take (& sem_bass_discovered , SEM_TIMEOUT );
615665 if (err != 0 ) {
616- if (err == - EAGAIN ) {
617- printk ("Failed to take sem_bass_discovered (err %d)\n" , err );
618- }
619- bt_conn_disconnect (broadcast_sink_conn , BT_HCI_ERR_UNSUPP_REMOTE_FEATURE );
620-
621- if (k_sem_take (& sem_sink_disconnected , K_SECONDS (10 )) != 0 ) {
622- /* This should not happen */
623- return - ETIMEDOUT ;
624- }
625-
626- reset ();
666+ printk ("Failed to take sem_bass_discovered (err %d)\n" , err );
627667 continue ;
628668 }
629669
@@ -636,19 +676,19 @@ int main(void)
636676
637677 scan_for_broadcast_source ();
638678
639- printk ("Scan stopped, attempting to PA sync to the broadcaster with id 0x%06X\n" ,
679+ printk ("Attempting to PA sync to the broadcaster with id 0x%06X\n" ,
640680 selected_broadcast_id );
641681 err = pa_sync_create ();
642682 if (err != 0 ) {
643- printk ("Could not create Broadcast PA sync: %d, resetting \n" , err );
644- return - ETIMEDOUT ;
683+ printk ("Could not create Broadcast PA sync: %d\n" , err );
684+ continue ;
645685 }
646686
647687 printk ("Waiting for PA synced\n" );
648- err = k_sem_take (& sem_pa_synced , K_FOREVER );
688+ err = k_sem_take (& sem_pa_synced , SEM_TIMEOUT );
649689 if (err != 0 ) {
650- printk ("sem_pa_synced timed out, resetting \n" );
651- return err ;
690+ printk ("Failed to take sem_pa_synced (err %d) \n" , err );
691+ continue ;
652692 }
653693
654694 memset (bass_subgroups , 0 , sizeof (bass_subgroups ));
@@ -661,42 +701,29 @@ int main(void)
661701
662702 /* Wait to receive subgroups */
663703 err = k_sem_take (& sem_received_base_subgroups , K_FOREVER );
664- if (err != 0 ) {
665- printk ("Failed to take sem_received_base_subgroups (err %d)\n" , err );
666- return err ;
667- }
704+ __ASSERT_NO_MSG (err == 0 );
668705
669- k_mutex_lock (& base_store_mutex , K_FOREVER );
706+ err = k_mutex_lock (& base_store_mutex , K_FOREVER );
707+ __ASSERT_NO_MSG (err == 0 );
670708 err = bt_bap_base_foreach_subgroup ((const struct bt_bap_base * )received_base ,
671709 add_pa_sync_base_subgroup_cb , & param );
672- k_mutex_unlock (& base_store_mutex );
710+ err = k_mutex_unlock (& base_store_mutex );
711+ __ASSERT_NO_MSG (err == 0 );
673712
674- if (err < 0 ) {
713+ if (err != 0 ) {
675714 printk ("Could not add BASE to params %d\n" , err );
676715 continue ;
677716 }
678717
679718 err = bt_bap_broadcast_assistant_add_src (broadcast_sink_conn , & param );
680- if (err ) {
719+ if (err != 0 ) {
681720 printk ("Failed to add source: %d\n" , err );
682- bt_conn_disconnect (broadcast_sink_conn , BT_HCI_ERR_UNSUPP_REMOTE_FEATURE );
683-
684- if (k_sem_take (& sem_sink_disconnected , K_SECONDS (10 )) != 0 ) {
685- /* This should not happen */
686- return - ETIMEDOUT ;
687- }
688-
689- reset ();
690721 continue ;
691722 }
692723
693724 /* Reset if the sink disconnects */
694725 err = k_sem_take (& sem_sink_disconnected , K_FOREVER );
695- if (err != 0 ) {
696- printk ("Failed to take sem_sink_disconnected (err %d)\n" , err );
697- }
698-
699- reset ();
726+ __ASSERT_NO_MSG (err == 0 );
700727 }
701728
702729 return 0 ;
0 commit comments