1 /*
2 * Copyright (c) 2019 Bose Corporation
3 * Copyright (c) 2020-2024 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <string.h>
11
12 #include <zephyr/autoconf.h>
13 #include <zephyr/bluetooth/audio/bap.h>
14 #include <zephyr/bluetooth/audio/csip.h>
15 #include <zephyr/bluetooth/addr.h>
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/conn.h>
18 #include <zephyr/bluetooth/gap.h>
19 #include <zephyr/bluetooth/hci_types.h>
20 #include <zephyr/kernel.h>
21 #include <zephyr/net_buf.h>
22 #include <zephyr/sys/printk.h>
23 #include <zephyr/sys/util.h>
24
25 #include "bstests.h"
26 #include "common.h"
27
28 #ifdef CONFIG_BT_CSIP_SET_COORDINATOR
29
30 static bool expect_rank = true;
31 static bool expect_set_size = true;
32 static bool expect_lockable = true;
33
34 extern enum bst_result_t bst_result;
35 static volatile bool discovered;
36 static volatile bool discover_timed_out;
37 static volatile bool set_locked;
38 static volatile bool set_unlocked;
39 static volatile bool ordered_access_locked;
40 static volatile bool ordered_access_unlocked;
41 static const struct bt_csip_set_coordinator_csis_inst *primary_inst;
42 CREATE_FLAG(flag_sirk_changed);
43 CREATE_FLAG(flag_size_changed);
44
45 static uint8_t connected_member_count;
46 static uint8_t members_found;
47 static struct k_work_delayable discover_members_timer;
48 static bt_addr_le_t addr_found[CONFIG_BT_MAX_CONN];
49 static struct bt_conn *conns[CONFIG_BT_MAX_CONN];
50 static const struct bt_csip_set_coordinator_set_member *set_members[CONFIG_BT_MAX_CONN];
51
52 static void csip_set_coordinator_lock_set_cb(int err);
53
csip_set_coordinator_lock_release_cb(int err)54 static void csip_set_coordinator_lock_release_cb(int err)
55 {
56 printk("%s\n", __func__);
57
58 if (err != 0) {
59 FAIL("Release sets failed (%d)\n", err);
60 return;
61 }
62
63 set_unlocked = true;
64 }
65
csip_set_coordinator_lock_set_cb(int err)66 static void csip_set_coordinator_lock_set_cb(int err)
67 {
68 printk("%s\n", __func__);
69
70 if (err != 0) {
71 FAIL("Lock sets failed (%d)\n", err);
72 return;
73 }
74
75 set_locked = true;
76 }
77
csip_discover_cb(struct bt_conn * conn,const struct bt_csip_set_coordinator_set_member * member,int err,size_t set_count)78 static void csip_discover_cb(struct bt_conn *conn,
79 const struct bt_csip_set_coordinator_set_member *member,
80 int err, size_t set_count)
81 {
82 uint8_t conn_index;
83
84 printk("%s\n", __func__);
85
86 if (err != 0 || set_count == 0U) {
87 FAIL("Discover failed (%d)\n", err);
88 return;
89 }
90
91 conn_index = bt_conn_index(conn);
92
93 for (size_t i = 0U; i < set_count; i++) {
94 const uint8_t rank = member->insts[i].info.rank;
95 const uint8_t set_size = member->insts[i].info.set_size;
96 const uint8_t lockable = member->insts[i].info.lockable;
97
98 printk("CSIS[%zu]: %p\n", i, &member->insts[i]);
99 printk("\tRank: %u\n", rank);
100 printk("\tSet Size: %u\n", set_size);
101 printk("\tLockable: %u\n", lockable);
102
103 if ((expect_rank && rank == 0U) || (!expect_rank && rank != 0U)) {
104 FAIL("Unexpected rank: %u %u", expect_rank, rank);
105
106 return;
107 }
108
109 if ((expect_set_size && set_size == 0U) || (!expect_set_size && set_size != 0U)) {
110 FAIL("Unexpected set_size: %u %u", expect_set_size, set_size);
111
112 return;
113 }
114
115 if (expect_lockable != lockable) {
116 FAIL("Unexpected lockable: %u %u", expect_lockable, lockable);
117
118 return;
119 }
120 }
121
122 if (primary_inst == NULL) {
123 primary_inst = &member->insts[0];
124 }
125
126 set_members[conn_index] = member;
127 discovered = true;
128 }
129
csip_lock_changed_cb(struct bt_csip_set_coordinator_csis_inst * inst,bool locked)130 static void csip_lock_changed_cb(struct bt_csip_set_coordinator_csis_inst *inst,
131 bool locked)
132 {
133 printk("inst %p %s\n", inst, locked ? "locked" : "released");
134 }
135
csip_sirk_changed_cb(struct bt_csip_set_coordinator_csis_inst * inst)136 static void csip_sirk_changed_cb(struct bt_csip_set_coordinator_csis_inst *inst)
137 {
138 printk("Inst %p SIRK changed\n", inst);
139
140 SET_FLAG(flag_sirk_changed);
141 }
142
csip_size_changed_cb(struct bt_conn * conn,const struct bt_csip_set_coordinator_csis_inst * inst)143 static void csip_size_changed_cb(struct bt_conn *conn,
144 const struct bt_csip_set_coordinator_csis_inst *inst)
145 {
146 printk("Inst %p size changed: %u\n", inst, inst->info.set_size);
147
148 SET_FLAG(flag_size_changed);
149 }
150
csip_set_coordinator_ordered_access_cb(const struct bt_csip_set_coordinator_set_info * set_info,int err,bool locked,struct bt_csip_set_coordinator_set_member * member)151 static void csip_set_coordinator_ordered_access_cb(
152 const struct bt_csip_set_coordinator_set_info *set_info, int err,
153 bool locked, struct bt_csip_set_coordinator_set_member *member)
154 {
155 if (err) {
156 FAIL("Ordered access failed with err %d\n", err);
157 } else if (locked) {
158 printk("Ordered access procedure locked member %p\n", member);
159 ordered_access_locked = true;
160 } else {
161 printk("Ordered access procedure finished\n");
162 ordered_access_unlocked = true;
163 }
164 }
165
166 static struct bt_csip_set_coordinator_cb cbs = {
167 .lock_set = csip_set_coordinator_lock_set_cb,
168 .release_set = csip_set_coordinator_lock_release_cb,
169 .discover = csip_discover_cb,
170 .lock_changed = csip_lock_changed_cb,
171 .sirk_changed = csip_sirk_changed_cb,
172 .size_changed = csip_size_changed_cb,
173 .ordered_access = csip_set_coordinator_ordered_access_cb,
174 };
175
csip_set_coordinator_oap_cb(const struct bt_csip_set_coordinator_set_info * set_info,struct bt_csip_set_coordinator_set_member * members[],size_t count)176 static bool csip_set_coordinator_oap_cb(const struct bt_csip_set_coordinator_set_info *set_info,
177 struct bt_csip_set_coordinator_set_member *members[],
178 size_t count)
179 {
180 for (size_t i = 0; i < count; i++) {
181 printk("Ordered access for members[%zu]: %p\n", i, members[i]);
182 }
183
184 return true;
185 }
186
is_discovered(const bt_addr_le_t * addr)187 static bool is_discovered(const bt_addr_le_t *addr)
188 {
189 for (int i = 0; i < members_found; i++) {
190 if (bt_addr_le_eq(addr, &addr_found[i])) {
191 return true;
192 }
193 }
194 return false;
195 }
196
csip_found(struct bt_data * data,void * user_data)197 static bool csip_found(struct bt_data *data, void *user_data)
198 {
199 if (primary_inst == NULL ||
200 bt_csip_set_coordinator_is_set_member(primary_inst->info.sirk, data)) {
201 const bt_addr_le_t *addr = user_data;
202 char addr_str[BT_ADDR_LE_STR_LEN];
203
204 bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
205 printk("Found CSIP advertiser with address %s\n", addr_str);
206
207 if (is_discovered(addr)) {
208 printk("Set member already found\n");
209 /* Stop parsing */
210 return false;
211 }
212
213 bt_addr_le_copy(&addr_found[members_found++], addr);
214
215 if (primary_inst == NULL || primary_inst->info.set_size == 0) {
216 printk("Found member %u\n", members_found);
217 } else {
218 printk("Found member (%u / %u)\n", members_found,
219 primary_inst->info.set_size);
220 }
221
222 /* Stop parsing */
223 return false;
224 }
225 /* Continue parsing */
226 return true;
227 }
228
csip_set_coordinator_scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)229 static void csip_set_coordinator_scan_recv(const struct bt_le_scan_recv_info *info,
230 struct net_buf_simple *ad)
231 {
232 /* We're only interested in connectable events */
233 if ((info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0U &&
234 (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0U) {
235 bt_data_parse(ad, csip_found, (void *)info->addr);
236 }
237 }
238
239 static struct bt_le_scan_cb csip_set_coordinator_scan_callbacks = {
240 .recv = csip_set_coordinator_scan_recv
241 };
242
discover_members_timer_handler(struct k_work * work)243 static void discover_members_timer_handler(struct k_work *work)
244 {
245 if (primary_inst->info.set_size > 0) {
246 FAIL("Could not find all members (%u / %u)\n", members_found,
247 primary_inst->info.set_size);
248 } else {
249 discover_timed_out = true;
250 }
251 }
252
ordered_access(const struct bt_csip_set_coordinator_set_member ** members,size_t count,bool expect_locked)253 static void ordered_access(const struct bt_csip_set_coordinator_set_member **members,
254 size_t count, bool expect_locked)
255 {
256 int err;
257
258 printk("Performing ordered access, expecting %s\n",
259 expect_locked ? "locked" : "unlocked");
260
261 if (expect_locked) {
262 ordered_access_locked = false;
263 } else {
264 ordered_access_unlocked = false;
265 }
266
267 err = bt_csip_set_coordinator_ordered_access(members, count, &primary_inst->info,
268 csip_set_coordinator_oap_cb);
269 if (err != 0) {
270 FAIL("Failed to do CSIP set coordinator ordered access (%d)",
271 err);
272 return;
273 }
274
275 if (expect_locked) {
276 WAIT_FOR_COND(ordered_access_locked);
277 } else {
278 WAIT_FOR_COND(ordered_access_unlocked);
279 }
280 }
281
discover_csis(struct bt_conn * conn)282 static void discover_csis(struct bt_conn *conn)
283 {
284 int err;
285
286 discovered = false;
287
288 err = bt_csip_set_coordinator_discover(conns[bt_conn_index(conn)]);
289 if (err != 0) {
290 FAIL("Failed to initialize set coordinator for connection %d\n", err);
291 return;
292 }
293
294 WAIT_FOR_COND(discovered);
295 }
296
init(void)297 static void init(void)
298 {
299 int err;
300
301 err = bt_enable(NULL);
302 if (err != 0) {
303 FAIL("Bluetooth init failed (err %d)\n", err);
304 return;
305 }
306
307 printk("Audio Client: Bluetooth initialized\n");
308
309 bt_csip_set_coordinator_register_cb(&cbs);
310 k_work_init_delayable(&discover_members_timer,
311 discover_members_timer_handler);
312 bt_le_scan_cb_register(&csip_set_coordinator_scan_callbacks);
313 }
314
connect_set(void)315 static void connect_set(void)
316 {
317 char addr[BT_ADDR_LE_STR_LEN];
318 int err;
319
320 connected_member_count = 0U;
321
322 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
323 if (err != 0) {
324 FAIL("Scanning failed to start (err %d)\n", err);
325
326 return;
327 }
328
329 printk("Scanning successfully started\n");
330
331 WAIT_FOR_COND(members_found == 1U);
332
333 printk("Stopping scan\n");
334 err = bt_le_scan_stop();
335 if (err != 0) {
336 FAIL("Could not stop scan");
337
338 return;
339 }
340
341 bt_addr_le_to_str(&addr_found[0], addr, sizeof(addr));
342 err = bt_conn_le_create(&addr_found[0], BT_CONN_LE_CREATE_CONN, BT_BAP_CONN_PARAM_RELAXED,
343 &conns[0]);
344 if (err != 0) {
345 FAIL("Failed to connect to %s: %d\n", err);
346
347 return;
348 }
349 printk("Connecting to %s\n", addr);
350
351 WAIT_FOR_FLAG(flag_connected);
352 connected_member_count++;
353
354 discover_csis(conns[0]);
355 discover_csis(conns[0]); /* test that we can discover twice */
356
357 err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
358 if (err != 0) {
359 FAIL("Could not start scan: %d", err);
360
361 return;
362 }
363
364 err = k_work_reschedule(&discover_members_timer,
365 BT_CSIP_SET_COORDINATOR_DISCOVER_TIMER_VALUE);
366 if (err < 0) { /* Can return 0, 1 and 2 for success */
367 FAIL("Could not schedule discover_members_timer %d", err);
368
369 return;
370 }
371
372 if (primary_inst->info.set_size > 0U) {
373 WAIT_FOR_COND(members_found == primary_inst->info.set_size);
374
375 (void)k_work_cancel_delayable(&discover_members_timer);
376 } else {
377 WAIT_FOR_COND(discover_timed_out);
378 }
379
380 err = bt_le_scan_stop();
381 if (err != 0) {
382 FAIL("Scanning failed to stop (err %d)\n", err);
383
384 return;
385 }
386
387 for (uint8_t i = 1; i < members_found; i++) {
388 bt_addr_le_to_str(&addr_found[i], addr, sizeof(addr));
389
390 UNSET_FLAG(flag_connected);
391 printk("Connecting to member[%d] (%s)", i, addr);
392 err = bt_conn_le_create(&addr_found[i], BT_CONN_LE_CREATE_CONN,
393 BT_LE_CONN_PARAM_DEFAULT, &conns[i]);
394 if (err != 0) {
395 FAIL("Failed to connect to %s: %d\n", addr, err);
396
397 return;
398 }
399
400 printk("Connected to %s\n", addr);
401 WAIT_FOR_FLAG(flag_connected);
402 connected_member_count++;
403
404 printk("Doing discovery on member[%u]", i);
405 discover_csis(conns[i]);
406 }
407 }
408
disconnect_set(void)409 static void disconnect_set(void)
410 {
411 for (uint8_t i = 0; i < connected_member_count; i++) {
412 char addr[BT_ADDR_LE_STR_LEN];
413 int err;
414
415 bt_addr_le_to_str(&addr_found[i], addr, sizeof(addr));
416
417 printk("Disconnecting member[%u] (%s)", i, addr);
418 err = bt_conn_disconnect(conns[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
419 (void)memset(&set_members[i], 0, sizeof(set_members[i]));
420 if (err != 0) {
421 FAIL("Failed to do disconnect\n", err);
422 return;
423 }
424 }
425 }
426
test_main(void)427 static void test_main(void)
428 {
429 const struct bt_csip_set_coordinator_set_member *locked_members[CONFIG_BT_MAX_CONN];
430 int err;
431
432 init();
433 connect_set();
434
435 for (size_t i = 0; i < ARRAY_SIZE(locked_members); i++) {
436 locked_members[i] = set_members[i];
437 }
438
439 if (primary_inst->info.rank != 0U) {
440 ordered_access(locked_members, connected_member_count, false);
441 }
442
443 if (primary_inst->info.lockable) {
444 printk("Locking set\n");
445 err = bt_csip_set_coordinator_lock(locked_members, connected_member_count,
446 &primary_inst->info);
447 if (err != 0) {
448 FAIL("Failed to do set coordinator lock (%d)", err);
449 return;
450 }
451
452 WAIT_FOR_COND(set_locked);
453 }
454
455 if (primary_inst->info.rank != 0U) {
456 ordered_access(locked_members, connected_member_count, primary_inst->info.lockable);
457 }
458
459 k_sleep(K_MSEC(1000)); /* Simulate doing stuff */
460
461 if (primary_inst->info.lockable) {
462 printk("Releasing set\n");
463 err = bt_csip_set_coordinator_release(locked_members, connected_member_count,
464 &primary_inst->info);
465 if (err != 0) {
466 FAIL("Failed to do set coordinator release (%d)", err);
467 return;
468 }
469
470 WAIT_FOR_COND(set_unlocked);
471 }
472
473 if (primary_inst->info.rank != 0U) {
474 ordered_access(locked_members, connected_member_count, false);
475 }
476
477 if (primary_inst->info.lockable) {
478 /* Lock and unlock again */
479 set_locked = false;
480 set_unlocked = false;
481
482 printk("Locking set\n");
483 err = bt_csip_set_coordinator_lock(locked_members, connected_member_count,
484 &primary_inst->info);
485 if (err != 0) {
486 FAIL("Failed to do set coordinator lock (%d)", err);
487 return;
488 }
489
490 WAIT_FOR_COND(set_locked);
491 }
492
493 k_sleep(K_MSEC(1000)); /* Simulate doing stuff */
494
495 if (primary_inst->info.lockable) {
496 printk("Releasing set\n");
497 err = bt_csip_set_coordinator_release(locked_members, connected_member_count,
498 &primary_inst->info);
499 if (err != 0) {
500 FAIL("Failed to do set coordinator release (%d)", err);
501 return;
502 }
503
504 WAIT_FOR_COND(set_unlocked);
505 }
506
507 disconnect_set();
508
509 PASS("All members disconnected\n");
510 }
511
test_new_sirk(void)512 static void test_new_sirk(void)
513 {
514 init();
515 connect_set();
516
517 backchannel_sync_send_all();
518 backchannel_sync_wait_all();
519
520 WAIT_FOR_FLAG(flag_sirk_changed);
521
522 disconnect_set();
523
524 PASS("All members disconnected\n");
525 }
526
test_new_size_and_rank(void)527 static void test_new_size_and_rank(void)
528 {
529 init();
530 connect_set();
531
532 backchannel_sync_send_all();
533 backchannel_sync_wait_all();
534
535 /* We won't get a new rank in a notification. For this test we only verify that we get a new
536 * size
537 */
538 WAIT_FOR_FLAG(flag_size_changed);
539
540 disconnect_set();
541
542 PASS("All members disconnected\n");
543 }
544
test_args(int argc,char * argv[])545 static void test_args(int argc, char *argv[])
546 {
547 for (int argn = 0; argn < argc; argn++) {
548 const char *arg = argv[argn];
549
550 if (strcmp(arg, "no-size") == 0) {
551 expect_set_size = false;
552 } else if (strcmp(arg, "no-rank") == 0) {
553 expect_rank = false;
554 } else if (strcmp(arg, "no-lock") == 0) {
555 expect_lockable = false;
556 } else {
557 FAIL("Invalid arg: %s", arg);
558 }
559 }
560 }
561
562 static const struct bst_test_instance test_connect[] = {
563 {
564 .test_id = "csip_set_coordinator",
565 .test_pre_init_f = test_init,
566 .test_tick_f = test_tick,
567 .test_main_f = test_main,
568 .test_args_f = test_args,
569 },
570 {
571 .test_id = "csip_set_coordinator_new_sirk",
572 .test_pre_init_f = test_init,
573 .test_tick_f = test_tick,
574 .test_main_f = test_new_sirk,
575 .test_args_f = test_args,
576 },
577 {
578 .test_id = "csip_set_coordinator_new_size_and_rank",
579 .test_pre_init_f = test_init,
580 .test_tick_f = test_tick,
581 .test_main_f = test_new_size_and_rank,
582 .test_args_f = test_args,
583 },
584 BSTEST_END_MARKER,
585 };
586
test_csip_set_coordinator_install(struct bst_test_list * tests)587 struct bst_test_list *test_csip_set_coordinator_install(struct bst_test_list *tests)
588 {
589 return bst_add_tests(tests, test_connect);
590 }
591 #else
test_csip_set_coordinator_install(struct bst_test_list * tests)592 struct bst_test_list *test_csip_set_coordinator_install(struct bst_test_list *tests)
593 {
594 return tests;
595 }
596
597 #endif /* CONFIG_BT_CSIP_SET_COORDINATOR */
598