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