/* * Copyright (c) 2019 Bose Corporation * Copyright (c) 2020-2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include "bs_tracing.h" #include "bstests.h" #include "common.h" #ifdef CONFIG_BT_CSIP_SET_MEMBER static struct bt_csip_set_member_svc_inst *svc_inst; extern enum bst_result_t bst_result; static volatile bool g_locked; static uint8_t sirk_read_req_rsp = BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT; struct bt_csip_set_member_register_param param = { .lockable = true, /* Using the CSIS test sample SIRK */ .sirk = TEST_SAMPLE_SIRK, }; static void csip_lock_changed_cb(struct bt_conn *conn, struct bt_csip_set_member_svc_inst *svc_inst, bool locked) { printk("Client %p %s the lock\n", conn, locked ? "locked" : "released"); g_locked = locked; } static uint8_t sirk_read_req_cb(struct bt_conn *conn, struct bt_csip_set_member_svc_inst *svc_inst) { return sirk_read_req_rsp; } static struct bt_csip_set_member_cb csip_cbs = { .lock_changed = csip_lock_changed_cb, .sirk_read_req = sirk_read_req_cb, }; static void bt_ready(int err) { struct bt_le_ext_adv *ext_adv; if (err != 0) { FAIL("Bluetooth init failed (err %d)\n", err); return; } printk("Audio Server: Bluetooth initialized\n"); param.cb = &csip_cbs; err = bt_csip_set_member_register(¶m, &svc_inst); if (err != 0) { FAIL("Could not register CSIP (err %d)\n", err); return; } err = bt_csip_set_member_generate_rsi(svc_inst, csip_rsi); if (err != 0) { FAIL("Failed to generate RSI (err %d)\n", err); return; } setup_connectable_adv(&ext_adv); } static void test_sirk(void) { const uint8_t new_sirk[] = {0xff, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce, 0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45}; struct bt_csip_set_member_set_info info; int err; printk("Setting new SIRK\n"); err = bt_csip_set_member_sirk(svc_inst, new_sirk); if (err != 0) { FAIL("Failed to set SIRK: %d\n", err); return; } printk("Getting new SIRK\n"); err = bt_csip_set_member_get_info(svc_inst, &info); if (err != 0) { FAIL("Failed to get SIRK: %d\n", err); return; } if (memcmp(new_sirk, info.sirk, BT_CSIP_SIRK_SIZE) != 0) { FAIL("The SIRK set and the set SIRK were different\n"); return; } printk("New SIRK correctly set and retrieved\n"); } static void update_set_size_and_rank(void) { struct bt_csip_set_member_set_info info; uint8_t old_set_size; uint8_t old_rank; uint8_t new_set_size; uint8_t new_rank; int err; err = bt_csip_set_member_get_info(svc_inst, &info); if (err != 0) { FAIL("Failed to get SIRK: %d\n", err); return; } /* Simulate a new device being added as rank 1 to the set, making the set size increase by 1 * and this device's rank increase by 1 */ old_set_size = info.set_size; old_rank = info.rank; new_set_size = old_set_size + 1U; new_rank = old_rank + 1U; printk("Setting new SIRK\n"); err = bt_csip_set_member_set_size_and_rank(svc_inst, new_set_size, new_rank); if (err != 0) { FAIL("Failed to set new size and rank: %d\n", err); return; } printk("Getting new SIRK\n"); err = bt_csip_set_member_get_info(svc_inst, &info); if (err != 0) { FAIL("Failed to get SIRK: %d\n", err); return; } if (info.set_size != new_set_size) { FAIL("Unexpected set size %u != %u\n", info.set_size, new_set_size); return; } if (info.rank != new_rank) { FAIL("Unexpected rank %u != %u\n", info.rank, new_rank); return; } printk("New size correctly set and retrieved\n"); } static void test_main(void) { int err; err = bt_enable(bt_ready); if (err != 0) { FAIL("Bluetooth init failed (err %d)\n", err); return; } WAIT_FOR_FLAG(flag_connected); if (param.lockable) { /* Waiting for lock */ WAIT_FOR_COND(g_locked); /* Waiting for lock release */ WAIT_FOR_COND(!g_locked); /* Waiting for lock */ WAIT_FOR_COND(g_locked); /* Waiting for lock release */ WAIT_FOR_COND(!g_locked); } WAIT_FOR_UNSET_FLAG(flag_connected); err = bt_csip_set_member_unregister(svc_inst); if (err != 0) { FAIL("Could not unregister CSIP (err %d)\n", err); return; } svc_inst = NULL; PASS("CSIP Set member passed: Client successfully disconnected\n"); } static void test_force_release(void) { int err; err = bt_enable(bt_ready); if (err != 0) { FAIL("Bluetooth init failed (err %d)\n", err); return; } WAIT_FOR_FLAG(flag_connected); WAIT_FOR_COND(g_locked); printk("Force releasing set\n"); bt_csip_set_member_lock(svc_inst, false, true); WAIT_FOR_UNSET_FLAG(flag_connected); err = bt_csip_set_member_unregister(svc_inst); if (err != 0) { FAIL("Could not unregister CSIP (err %d)\n", err); return; } svc_inst = NULL; PASS("CSIP Set member passed: Client successfully disconnected\n"); } static void test_csip_enc(void) { printk("Running %s\n", __func__); sirk_read_req_rsp = BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC; test_main(); } static void test_new_sirk(void) { int err; err = bt_enable(bt_ready); if (err != 0) { FAIL("Bluetooth init failed (err %d)\n", err); return; } WAIT_FOR_FLAG(flag_connected); backchannel_sync_send_all(); backchannel_sync_wait_all(); test_sirk(); WAIT_FOR_UNSET_FLAG(flag_connected); err = bt_csip_set_member_unregister(svc_inst); if (err != 0) { FAIL("Could not unregister CSIP (err %d)\n", err); return; } svc_inst = NULL; PASS("CSIP Set member passed: Client successfully disconnected\n"); } static void test_new_set_size_and_rank(void) { int err; err = bt_enable(bt_ready); if (err != 0) { FAIL("Bluetooth init failed (err %d)\n", err); return; } WAIT_FOR_FLAG(flag_connected); backchannel_sync_send_all(); backchannel_sync_wait_all(); update_set_size_and_rank(); WAIT_FOR_UNSET_FLAG(flag_connected); err = bt_csip_set_member_unregister(svc_inst); if (err != 0) { FAIL("Could not unregister CSIP (err %d)\n", err); return; } svc_inst = NULL; PASS("CSIP Set member passed: Client successfully disconnected\n"); } static void test_register(void) { for (size_t iteration = 1; iteration <= 5; iteration++) { struct bt_csip_set_member_svc_inst *svc_insts[CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT]; int err; printk("Running iteration %zu\n", iteration); ARRAY_FOR_EACH(svc_insts, i) { err = bt_csip_set_member_register(¶m, &svc_insts[i]); if (err != 0) { FAIL("[%zu]: Could not register CSIS (err %d)\n", i, err); return; } } err = bt_csip_set_member_register(¶m, &svc_inst); if (err == 0) { FAIL("Registered more CSIS than expected\n"); return; } ARRAY_FOR_EACH(svc_insts, i) { err = bt_csip_set_member_unregister(svc_insts[i]); if (err != 0) { FAIL("[%zu]: Could not unregister CSIS (err %d)\n", i, err); return; } svc_insts[i] = NULL; } } PASS("CSIP Set member register passed\n"); /* We can terminate the test immediately here as there is no peer devices we keep * communicating with. */ bs_trace_silent_exit(0); } static void test_args(int argc, char *argv[]) { for (size_t argn = 0; argn < argc; argn++) { const char *arg = argv[argn]; if (strcmp(arg, "size") == 0) { param.set_size = strtol(argv[++argn], NULL, 10); } else if (strcmp(arg, "rank") == 0) { param.rank = strtol(argv[++argn], NULL, 10); } else if (strcmp(arg, "not-lockable") == 0) { param.lockable = false; } else if (strcmp(arg, "sirk") == 0) { size_t len; argn++; len = hex2bin(argv[argn], strlen(argv[argn]), param.sirk, sizeof(param.sirk)); if (len == 0) { FAIL("Could not parse SIRK"); return; } } else { FAIL("Invalid arg: %s", arg); } } } static const struct bst_test_instance test_connect[] = { { .test_id = "csip_set_member", .test_pre_init_f = test_init, .test_tick_f = test_tick, .test_main_f = test_main, .test_args_f = test_args, }, { .test_id = "csip_set_member_release", .test_pre_init_f = test_init, .test_tick_f = test_tick, .test_main_f = test_force_release, .test_args_f = test_args, }, { .test_id = "csip_set_member_enc", .test_pre_init_f = test_init, .test_tick_f = test_tick, .test_main_f = test_csip_enc, .test_args_f = test_args, }, { .test_id = "csip_set_member_new_sirk", .test_pre_init_f = test_init, .test_tick_f = test_tick, .test_main_f = test_new_sirk, .test_args_f = test_args, }, { .test_id = "csip_set_member_new_size_and_rank", .test_pre_init_f = test_init, .test_tick_f = test_tick, .test_main_f = test_new_set_size_and_rank, .test_args_f = test_args, }, { .test_id = "csip_set_member_register", .test_pre_init_f = test_init, .test_tick_f = test_tick, .test_main_f = test_register, .test_args_f = test_args, }, BSTEST_END_MARKER, }; struct bst_test_list *test_csip_set_member_install(struct bst_test_list *tests) { return bst_add_tests(tests, test_connect); } #else struct bst_test_list *test_csip_set_member_install(struct bst_test_list *tests) { return tests; } #endif /* CONFIG_BT_CSIP_SET_MEMBER */