1
1
/*
2
2
* Copyright (c) 2024 Demant A/S
3
- * Copyright (c) 2024 Nordic Semiconductor ASA
3
+ * Copyright (c) 2024-2025 Nordic Semiconductor ASA
4
4
*
5
5
* SPDX-License-Identifier: Apache-2.0
6
6
*/
7
7
8
8
#include <errno.h>
9
+ #include <stdbool.h>
9
10
#include <stddef.h>
10
11
#include <stdint.h>
11
12
#include <string.h>
24
25
#include <zephyr/bluetooth/uuid.h>
25
26
#include <zephyr/kernel.h>
26
27
#include <zephyr/net_buf.h>
28
+ #include <zephyr/sys/__assert.h>
27
29
#include <zephyr/sys/byteorder.h>
28
30
#include <zephyr/sys/printk.h>
29
31
#include <zephyr/sys/util.h>
33
35
#define PA_SYNC_SKIP 5
34
36
#define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */
35
37
/* 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)
36
40
37
41
static void scan_for_broadcast_sink (void );
38
42
@@ -68,6 +72,7 @@ static K_SEM_DEFINE(sem_sink_disconnected, 0, 1);
68
72
static K_SEM_DEFINE (sem_security_updated , 0 , 1 ) ;
69
73
static K_SEM_DEFINE (sem_bass_discovered , 0 , 1 ) ;
70
74
static K_SEM_DEFINE (sem_pa_synced , 0 , 1 ) ;
75
+ static K_SEM_DEFINE (sem_pa_sync_terminted , 0 , 1 ) ;
71
76
static K_SEM_DEFINE (sem_received_base_subgroups , 0 , 1 ) ;
72
77
73
78
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)
147
152
const struct bt_bap_base * base = bt_bap_base_get_base_from_ad (data );
148
153
int base_size ;
149
154
int base_subgroup_count ;
155
+ int err ;
150
156
151
157
/* Base is NULL if the data does not contain a valid BASE */
152
158
if (base == NULL ) {
@@ -168,13 +174,19 @@ static bool base_store(struct bt_data *data, void *user_data)
168
174
}
169
175
170
176
/* 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
+
172
183
if ((size_t )base_size != received_base_size ||
173
184
memcmp (base , received_base , (size_t )base_size ) != 0 ) {
174
185
(void )memcpy (received_base , base , base_size );
175
186
received_base_size = (size_t )base_size ;
176
187
}
177
- k_mutex_unlock (& base_store_mutex );
188
+ err = k_mutex_unlock (& base_store_mutex );
189
+ __ASSERT_NO_MSG (err == 0 );
178
190
179
191
/* Stop parsing */
180
192
k_sem_give (& sem_received_base_subgroups );
@@ -419,9 +431,7 @@ static void scan_for_broadcast_source(void)
419
431
printk ("Scanning for Broadcast Source successfully started\n" );
420
432
421
433
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 );
425
435
}
426
436
427
437
static void scan_for_broadcast_sink (void )
@@ -439,9 +449,7 @@ static void scan_for_broadcast_sink(void)
439
449
printk ("Scanning for Broadcast Sink successfully started\n" );
440
450
441
451
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 );
445
453
}
446
454
447
455
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,
528
536
k_sem_give (& sem_pa_synced );
529
537
}
530
538
}
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
+ }
531
549
532
550
static struct bt_bap_broadcast_assistant_cb ba_cbs = {
533
551
.discover = bap_broadcast_assistant_discover_cb ,
@@ -536,14 +554,49 @@ static struct bt_bap_broadcast_assistant_cb ba_cbs = {
536
554
537
555
static struct bt_le_per_adv_sync_cb pa_synced_cb = {
538
556
.synced = pa_sync_synced_cb ,
557
+ .term = pa_sync_term_cb ,
539
558
.recv = pa_recv ,
540
559
};
541
560
542
561
static void reset (void )
543
562
{
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
+ }
545
599
546
- broadcast_sink_conn = NULL ;
547
600
selected_broadcast_id = BT_BAP_INVALID_BROADCAST_ID ;
548
601
selected_sid = 0 ;
549
602
selected_pa_interval = 0 ;
@@ -568,7 +621,6 @@ BT_CONN_CB_DEFINE(conn_callbacks) = {
568
621
int main (void )
569
622
{
570
623
int err ;
571
- struct bt_bap_broadcast_assistant_add_src_param param = { 0 };
572
624
573
625
err = bt_enable (NULL );
574
626
if (err ) {
@@ -585,45 +637,33 @@ int main(void)
585
637
k_mutex_init (& base_store_mutex );
586
638
587
639
while (true) {
640
+ struct bt_bap_broadcast_assistant_add_src_param param = {0 };
641
+
642
+ reset ();
643
+
588
644
scan_for_broadcast_sink ();
589
645
590
- err = k_sem_take (& sem_sink_connected , K_FOREVER );
646
+ err = k_sem_take (& sem_sink_connected , SEM_TIMEOUT );
591
647
if (err != 0 ) {
592
648
printk ("Failed to take sem_sink_connected (err %d)\n" , err );
649
+ continue ;
593
650
}
594
651
595
652
err = bt_bap_broadcast_assistant_discover (broadcast_sink_conn );
596
653
if (err != 0 ) {
597
654
printk ("Failed to discover BASS on the sink (err %d)\n" , err );
655
+ continue ;
598
656
}
599
657
600
- err = k_sem_take (& sem_security_updated , K_SECONDS ( 10 ) );
658
+ err = k_sem_take (& sem_security_updated , SEM_TIMEOUT );
601
659
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 );
611
661
continue ;
612
662
}
613
663
614
- err = k_sem_take (& sem_bass_discovered , K_SECONDS ( 10 ) );
664
+ err = k_sem_take (& sem_bass_discovered , SEM_TIMEOUT );
615
665
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 );
627
667
continue ;
628
668
}
629
669
@@ -636,19 +676,19 @@ int main(void)
636
676
637
677
scan_for_broadcast_source ();
638
678
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" ,
640
680
selected_broadcast_id );
641
681
err = pa_sync_create ();
642
682
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 ;
645
685
}
646
686
647
687
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 );
649
689
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 ;
652
692
}
653
693
654
694
memset (bass_subgroups , 0 , sizeof (bass_subgroups ));
@@ -661,42 +701,29 @@ int main(void)
661
701
662
702
/* Wait to receive subgroups */
663
703
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 );
668
705
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 );
670
708
err = bt_bap_base_foreach_subgroup ((const struct bt_bap_base * )received_base ,
671
709
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 );
673
712
674
- if (err < 0 ) {
713
+ if (err != 0 ) {
675
714
printk ("Could not add BASE to params %d\n" , err );
676
715
continue ;
677
716
}
678
717
679
718
err = bt_bap_broadcast_assistant_add_src (broadcast_sink_conn , & param );
680
- if (err ) {
719
+ if (err != 0 ) {
681
720
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 ();
690
721
continue ;
691
722
}
692
723
693
724
/* Reset if the sink disconnects */
694
725
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 );
700
727
}
701
728
702
729
return 0 ;
0 commit comments