1 /*
2 * The goal of this test is to verify the bt_conn_cb_unregister() API works as expected
3 *
4 * Copyright (c) 2024 NXP
5 * Copyright (c) 2022 Nordic Semiconductor ASA
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include "bstests.h"
11 #include <zephyr/bluetooth/bluetooth.h>
12
13 #include <testlib/conn.h>
14
15 #include "common.h"
16
17 CREATE_FLAG(flag_is_connected);
18
19 static struct bt_conn *g_conn;
20
connected(struct bt_conn * conn,uint8_t err)21 static void connected(struct bt_conn *conn, uint8_t err)
22 {
23 char addr[BT_ADDR_LE_STR_LEN];
24
25 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
26
27 if (err != 0) {
28 FAIL("Failed to connect to %s (%u)\n", addr, err);
29 return;
30 }
31
32 printk("conn_callback:Connected to %s\n", addr);
33
34 __ASSERT_NO_MSG(g_conn == NULL);
35 g_conn = bt_conn_ref(conn);
36 SET_FLAG(flag_is_connected);
37 }
38
disconnected(struct bt_conn * conn,uint8_t reason)39 static void disconnected(struct bt_conn *conn, uint8_t reason)
40 {
41 char addr[BT_ADDR_LE_STR_LEN];
42
43 if (conn != g_conn) {
44 return;
45 }
46
47 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
48
49 printk("conn_callback:Disconnected: %s (reason 0x%02x)\n", addr, reason);
50
51 bt_conn_unref(g_conn);
52 g_conn = NULL;
53
54 UNSET_FLAG(flag_is_connected);
55 }
56
57 static struct bt_conn_cb conn_callbacks = {
58 .connected = connected,
59 .disconnected = disconnected,
60 };
61
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)62 void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad)
63 {
64 char addr_str[BT_ADDR_LE_STR_LEN];
65 int err;
66 struct bt_conn *conn;
67
68 if (g_conn != NULL) {
69 printk("g_conn != NULL\n");
70 return;
71 }
72
73 /* We're only interested in connectable events */
74 if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
75 printk("type not connectable\n");
76 return;
77 }
78
79 bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
80 printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
81
82 printk("Stopping scan\n");
83 err = bt_le_scan_stop();
84 if (err != 0) {
85 FAIL("Could not stop scan: %d");
86 return;
87 }
88
89 err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &conn);
90 if (err != 0) {
91 FAIL("Could not connect to peer: %d", err);
92 }
93 printk("%s: connected to found device\n", __func__);
94
95 bt_conn_unref(conn);
96 }
97
connection_info(struct bt_conn * conn,void * user_data)98 static void connection_info(struct bt_conn *conn, void *user_data)
99 {
100 char addr[BT_ADDR_LE_STR_LEN];
101 int *conn_count = user_data;
102 struct bt_conn_info info;
103
104 if (bt_conn_get_info(conn, &info) < 0) {
105 printk("Unable to get info: conn %p", conn);
106 return;
107 }
108
109 switch (info.type) {
110 case BT_CONN_TYPE_LE:
111 (*conn_count)++;
112 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
113 printk("%s: Connected to %s\n", __func__, addr);
114 break;
115 default:
116 break;
117 }
118 }
119
start_adv(void)120 static void start_adv(void)
121 {
122 int err;
123 const struct bt_data ad[] = {
124 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR))};
125
126 err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
127 if (err != 0) {
128 FAIL("Advertising failed to start (err %d)\n", err);
129 return;
130 }
131
132 printk("Advertising successfully started\n");
133 }
134
test_peripheral_main(void)135 static void test_peripheral_main(void)
136 {
137 int err;
138
139 err = bt_enable(NULL);
140 if (err != 0) {
141 FAIL("Bluetooth init failed (err %d)\n", err);
142 return;
143 }
144
145 printk("Bluetooth initialized\n");
146
147 bt_conn_cb_register(&conn_callbacks);
148
149 start_adv();
150
151 WAIT_FOR_FLAG(flag_is_connected);
152
153 WAIT_FOR_FLAG_UNSET(flag_is_connected);
154
155 bt_conn_cb_unregister(&conn_callbacks);
156
157 bt_testlib_conn_wait_free();
158 start_adv();
159
160 k_sleep(K_SECONDS(1));
161
162 err = bt_disable();
163 if (err != 0) {
164 FAIL("Bluetooth disable failed (err %d)\n", err);
165 return;
166 }
167
168 printk("Bluetooth successfully disabled\n");
169
170 PASS("Peripheral device passed\n");
171 }
172
test_central_main(void)173 static void test_central_main(void)
174 {
175 int err;
176 int conn_count = 0;
177
178 err = bt_enable(NULL);
179 if (err != 0) {
180 FAIL("Bluetooth discover failed (err %d)\n", err);
181 }
182 printk("Bluetooth initialized\n");
183 bt_conn_cb_register(&conn_callbacks);
184 /* Connect to peer device after conn_callbacks registered*/
185 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
186 if (err != 0) {
187 FAIL("Scanning failed to start (err %d)\n", err);
188 }
189
190 printk("Scanning successfully started\n");
191
192 WAIT_FOR_FLAG(flag_is_connected);
193
194 err = bt_conn_disconnect(g_conn, 0x13);
195
196 if (err != 0) {
197 FAIL("Disconnect failed (err %d)\n", err);
198 return;
199 }
200
201 WAIT_FOR_FLAG_UNSET(flag_is_connected);
202 bt_conn_cb_unregister(&conn_callbacks);
203 /* Reconnect to the device after conn_callbacks unregistered */
204 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
205 if (err != 0) {
206 FAIL("Scanning failed to start (err %d)\n", err);
207 }
208 printk("Scanning successfully started\n");
209
210 k_sleep(K_SECONDS(1));
211 bt_conn_foreach(BT_CONN_TYPE_LE, connection_info, &conn_count);
212 if (!conn_count) {
213 FAIL("Reconnect to peer device failed!");
214 }
215
216 /* flag_is_connected not set means no conn_callbacks being called */
217 if (flag_is_connected) {
218 FAIL("Unregister conn_callback didn't work");
219 }
220 printk("Unregister connection callbacks succeed!\n");
221
222 err = bt_disable();
223 if (err != 0) {
224 FAIL("Bluetooth disable failed (err %d)\n", err);
225 }
226 printk("Bluetooth successfully disabled\n");
227
228 PASS("Central device passed\n");
229 }
230
231 static const struct bst_test_instance test_def[] = {{.test_id = "peripheral",
232 .test_descr = "Peripheral device",
233 .test_pre_init_f = test_init,
234 .test_tick_f = test_tick,
235 .test_main_f = test_peripheral_main},
236 {.test_id = "central",
237 .test_descr = "Central device",
238 .test_pre_init_f = test_init,
239 .test_tick_f = test_tick,
240 .test_main_f = test_central_main},
241 BSTEST_END_MARKER};
242
test_unregister_conn_cb_install(struct bst_test_list * tests)243 struct bst_test_list *test_unregister_conn_cb_install(struct bst_test_list *tests)
244 {
245 return bst_add_tests(tests, test_def);
246 }
247
248 extern struct bst_test_list *test_unregister_conn_cb_install(struct bst_test_list *tests);
249
250 bst_test_install_t test_installers[] = {test_unregister_conn_cb_install, NULL};
251
main(void)252 int main(void)
253 {
254 bst_main();
255 return 0;
256 }
257