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