1 /*
2  * Copyright (c) 2023 Demant A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdbool.h>
8 #include <stddef.h>
9 
10 #include <zephyr/bluetooth/audio/cap.h>
11 #include <zephyr/bluetooth/audio/csip.h>
12 #include <zephyr/bluetooth/bluetooth.h>
13 #include <zephyr/bluetooth/conn.h>
14 #include <zephyr/bluetooth/gap.h>
15 #include <zephyr/bluetooth/gatt.h>
16 #include <zephyr/bluetooth/uuid.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/sys/printk.h>
19 #include <zephyr/sys/util.h>
20 
21 #include "bstests.h"
22 #include "common.h"
23 
24 extern enum bst_result_t bst_result;
25 
26 static struct bt_csip_set_member_svc_inst *svc_inst;
27 
is_peer_subscribed(struct bt_conn * conn)28 static bool is_peer_subscribed(struct bt_conn *conn)
29 {
30 	struct bt_gatt_attr *attr;
31 
32 	attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_CSIS_SET_LOCK);
33 	if (!attr) {
34 		printk("No BT_UUID_PACS_SNK attribute found\n");
35 		return false;
36 	}
37 
38 	return bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY);
39 }
40 
csip_set_member_lock_changed_cb(struct bt_conn * conn,struct bt_csip_set_member_svc_inst * svc_inst,bool locked)41 static void csip_set_member_lock_changed_cb(struct bt_conn *conn,
42 					    struct bt_csip_set_member_svc_inst *svc_inst,
43 					    bool locked)
44 {
45 	printk("Client %p %s the lock\n", conn, locked ? "locked" : "released");
46 }
47 
48 static struct bt_csip_set_member_cb csip_cb = {
49 	.lock_changed  = csip_set_member_lock_changed_cb,
50 };
51 
test_main(void)52 static void test_main(void)
53 {
54 	int err;
55 	const struct bt_data ad[] = {
56 		BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
57 	};
58 	struct bt_csip_set_member_register_param csip_params = {
59 		.set_size = 1,
60 		.rank = 1,
61 		.lockable = true,
62 		.cb       = &csip_cb,
63 	};
64 
65 	printk("Enabling Bluetooth\n");
66 	err = bt_enable(NULL);
67 	if (err != 0) {
68 		FAIL("Bluetooth enable failed (err %d)\n", err);
69 		return;
70 	}
71 
72 	printk("Registering CSIP Set Member\n");
73 
74 	err = bt_cap_acceptor_register(&csip_params, &svc_inst);
75 	if (err != 0) {
76 		printk("Failed to register csip\n");
77 		return;
78 	}
79 
80 	printk("Start Advertising\n");
81 	err = bt_le_adv_start(BT_LE_ADV_CONN_ONE_TIME, ad, ARRAY_SIZE(ad), NULL, 0);
82 	if (err != 0) {
83 		FAIL("Advertising failed to start (err %d)\n", err);
84 		return;
85 	}
86 
87 	printk("Waiting to be connected\n");
88 	WAIT_FOR_FLAG(flag_connected);
89 	printk("Connected\n");
90 	printk("Waiting to be subscribed\n");
91 
92 	while (!is_peer_subscribed(default_conn)) {
93 		(void)k_sleep(K_MSEC(10));
94 	}
95 	printk("Subscribed\n");
96 
97 	err = bt_csip_set_member_lock(svc_inst, true, false);
98 	if (err != 0) {
99 		FAIL("Failed to set lock (err %d)\n", err);
100 		return;
101 	}
102 
103 	/* Now wait for client to disconnect, then stop adv so it does not reconnect */
104 	printk("Wait for client disconnect\n");
105 	WAIT_FOR_UNSET_FLAG(flag_connected);
106 	printk("Client disconnected\n");
107 
108 	err = bt_le_adv_stop();
109 	if (err != 0) {
110 		FAIL("Advertising failed to stop (err %d)\n", err);
111 		return;
112 	}
113 
114 	/* Trigger changes while device is disconnected */
115 	err = bt_csip_set_member_lock(svc_inst, false, false);
116 	if (err != 0) {
117 		FAIL("Failed to set lock (err %d)\n", err);
118 		return;
119 	}
120 
121 	printk("Start Advertising\n");
122 	err = bt_le_adv_start(BT_LE_ADV_CONN_ONE_TIME, ad, ARRAY_SIZE(ad), NULL, 0);
123 	if (err != 0) {
124 		FAIL("Advertising failed to start (err %d)\n", err);
125 		return;
126 	}
127 
128 	WAIT_FOR_FLAG(flag_connected);
129 	WAIT_FOR_UNSET_FLAG(flag_connected);
130 
131 	PASS("CSIP Notify Server passed\n");
132 }
133 
134 static const struct bst_test_instance test_csip_notify_server[] = {
135 	{
136 		.test_id = "csip_notify_server",
137 		.test_pre_init_f = test_init,
138 		.test_tick_f = test_tick,
139 		.test_main_f = test_main,
140 	},
141 	BSTEST_END_MARKER,
142 };
143 
test_csip_notify_server_install(struct bst_test_list * tests)144 struct bst_test_list *test_csip_notify_server_install(struct bst_test_list *tests)
145 {
146 	return bst_add_tests(tests, test_csip_notify_server);
147 }
148