1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/types.h>
10 #include <zephyr/sys_clock.h>
11 #include <zephyr/sys/printk.h>
12 #include <zephyr/bluetooth/bluetooth.h>
13 #include <zephyr/bluetooth/hci.h>
14 #include <zephyr/bluetooth/conn.h>
15 #include <zephyr/bluetooth/uuid.h>
16 #include <zephyr/bluetooth/gatt.h>
17 
18 #include "babblekit/testcase.h"
19 #include "babblekit/flags.h"
20 #include "common.h"
21 
22 extern enum bst_result_t bst_result;
23 
24 static struct bt_conn *g_conn;
25 static bt_addr_le_t per_addr;
26 static uint8_t per_sid;
27 
28 DEFINE_FLAG_STATIC(flag_connected);
29 DEFINE_FLAG_STATIC(flag_bonded);
30 DEFINE_FLAG_STATIC(flag_per_adv);
31 DEFINE_FLAG_STATIC(flag_per_adv_sync);
32 DEFINE_FLAG_STATIC(flag_per_adv_sync_lost);
33 DEFINE_FLAG_STATIC(flag_per_adv_recv);
34 
connected(struct bt_conn * conn,uint8_t err)35 static void connected(struct bt_conn *conn, uint8_t err)
36 {
37 	char addr[BT_ADDR_LE_STR_LEN];
38 
39 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
40 
41 	if (err != BT_HCI_ERR_SUCCESS) {
42 		TEST_FAIL("Failed to connect to %s: %u", addr, err);
43 		return;
44 	}
45 
46 	printk("Connected to %s\n", addr);
47 	g_conn = bt_conn_ref(conn);
48 	SET_FLAG(flag_connected);
49 }
50 
disconnected(struct bt_conn * conn,uint8_t reason)51 static void disconnected(struct bt_conn *conn, uint8_t reason)
52 {
53 	char addr[BT_ADDR_LE_STR_LEN];
54 
55 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
56 
57 	printk("Disconnected: %s (reason %u)\n", addr, reason);
58 
59 	bt_conn_unref(g_conn);
60 	g_conn = NULL;
61 }
62 
63 static struct bt_conn_cb conn_cbs = {
64 	.connected = connected,
65 	.disconnected = disconnected,
66 };
67 
pairing_complete_cb(struct bt_conn * conn,bool bonded)68 static void pairing_complete_cb(struct bt_conn *conn, bool bonded)
69 {
70 	if (conn == g_conn && bonded) {
71 		SET_FLAG(flag_bonded);
72 	}
73 }
74 
75 static struct bt_conn_auth_info_cb auto_info_cbs = {
76 	.pairing_complete = pairing_complete_cb,
77 };
78 
scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)79 static void scan_recv(const struct bt_le_scan_recv_info *info,
80 		      struct net_buf_simple *buf)
81 {
82 	if (!IS_FLAG_SET(flag_connected) &&
83 	    info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) {
84 		int err;
85 
86 		printk("Stopping scan\n");
87 		err = bt_le_scan_stop();
88 		if (err != 0) {
89 			TEST_FAIL("Failed to stop scan: %d", err);
90 			return;
91 		}
92 
93 		err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN,
94 					BT_LE_CONN_PARAM_DEFAULT, &g_conn);
95 		if (err != 0) {
96 			TEST_FAIL("Could not connect to peer: %d", err);
97 			return;
98 		}
99 	} else if (!IS_FLAG_SET(flag_per_adv) && info->interval != 0U) {
100 
101 		per_sid = info->sid;
102 		bt_addr_le_copy(&per_addr, info->addr);
103 
104 		SET_FLAG(flag_per_adv);
105 	}
106 }
107 
108 static struct bt_le_scan_cb scan_callbacks = {
109 	.recv = scan_recv,
110 };
111 
sync_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)112 static void sync_cb(struct bt_le_per_adv_sync *sync,
113 		    struct bt_le_per_adv_sync_synced_info *info)
114 {
115 	char le_addr[BT_ADDR_LE_STR_LEN];
116 
117 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
118 
119 	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s synced, "
120 	       "Interval 0x%04x (%u us)\n",
121 	       bt_le_per_adv_sync_get_index(sync), le_addr,
122 	       info->interval, BT_CONN_INTERVAL_TO_US(info->interval));
123 
124 	SET_FLAG(flag_per_adv_sync);
125 }
126 
term_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)127 static void term_cb(struct bt_le_per_adv_sync *sync,
128 		    const struct bt_le_per_adv_sync_term_info *info)
129 {
130 	char le_addr[BT_ADDR_LE_STR_LEN];
131 
132 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
133 
134 	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n",
135 	       bt_le_per_adv_sync_get_index(sync), le_addr);
136 
137 	SET_FLAG(flag_per_adv_sync_lost);
138 }
139 
recv_cb(struct bt_le_per_adv_sync * recv_sync,const struct bt_le_per_adv_sync_recv_info * info,struct net_buf_simple * buf)140 static void recv_cb(struct bt_le_per_adv_sync *recv_sync,
141 		    const struct bt_le_per_adv_sync_recv_info *info,
142 		    struct net_buf_simple *buf)
143 {
144 	char le_addr[BT_ADDR_LE_STR_LEN];
145 	uint8_t buf_data_len;
146 
147 	if (IS_FLAG_SET(flag_per_adv_recv)) {
148 		return;
149 	}
150 
151 	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
152 	printk("PER_ADV_SYNC[%u]: [DEVICE]: %s advertisement received\n",
153 	       bt_le_per_adv_sync_get_index(recv_sync), le_addr);
154 
155 	while (buf->len > 0) {
156 		buf_data_len = (uint8_t)net_buf_simple_pull_le16(buf);
157 		if (buf->data[0] - 1 != sizeof(mfg_data) ||
158 			memcmp(buf->data, mfg_data, sizeof(mfg_data))) {
159 			TEST_FAIL("Unexpected adv data received");
160 		}
161 		net_buf_simple_pull(buf, ARRAY_SIZE(mfg_data));
162 	}
163 
164 	SET_FLAG(flag_per_adv_recv);
165 }
166 
167 static struct bt_le_per_adv_sync_cb sync_callbacks = {
168 	.synced = sync_cb,
169 	.term = term_cb,
170 	.recv = recv_cb,
171 };
172 
common_init(void)173 static void common_init(void)
174 {
175 	int err;
176 
177 	err = bt_enable(NULL);
178 
179 	if (err) {
180 		TEST_FAIL("Bluetooth init failed: %d", err);
181 		return;
182 	}
183 
184 	bt_le_scan_cb_register(&scan_callbacks);
185 	bt_le_per_adv_sync_cb_register(&sync_callbacks);
186 	bt_conn_cb_register(&conn_cbs);
187 	bt_conn_auth_info_cb_register(&auto_info_cbs);
188 }
189 
start_scan(void)190 static void start_scan(void)
191 {
192 	int err;
193 
194 	printk("Start scanning...");
195 
196 	err = bt_le_scan_start(IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED) ?
197 			       BT_LE_SCAN_CODED_ACTIVE : BT_LE_SCAN_ACTIVE,
198 			       NULL);
199 	if (err) {
200 		TEST_FAIL("Failed to start scan: %d", err);
201 		return;
202 	}
203 	printk("done.\n");
204 }
205 
create_pa_sync(struct bt_le_per_adv_sync ** sync)206 static void create_pa_sync(struct bt_le_per_adv_sync **sync)
207 {
208 	struct bt_le_per_adv_sync_param sync_create_param = { 0 };
209 	int err;
210 
211 	printk("Creating periodic advertising sync...");
212 	bt_addr_le_copy(&sync_create_param.addr, &per_addr);
213 	sync_create_param.options = 0;
214 	sync_create_param.sid = per_sid;
215 	sync_create_param.skip = 0;
216 	sync_create_param.timeout = 0x0a;
217 	err = bt_le_per_adv_sync_create(&sync_create_param, sync);
218 	if (err) {
219 		TEST_FAIL("Failed to create periodic advertising sync: %d", err);
220 		return;
221 	}
222 	printk("done.\n");
223 
224 	printk("Waiting for periodic sync...\n");
225 	WAIT_FOR_FLAG(flag_per_adv_sync);
226 	printk("Periodic sync established.\n");
227 }
228 
start_bonding(void)229 static void start_bonding(void)
230 {
231 	int err;
232 
233 	printk("Setting security...");
234 	err = bt_conn_set_security(g_conn, BT_SECURITY_L2);
235 	if (err) {
236 		TEST_FAIL("Failed to set security: %d", err);
237 		return;
238 	}
239 	printk("done.\n");
240 }
241 
main_per_adv_sync(void)242 static void main_per_adv_sync(void)
243 {
244 	struct bt_le_per_adv_sync *sync = NULL;
245 
246 	common_init();
247 	start_scan();
248 
249 	printk("Waiting for periodic advertising...\n");
250 	WAIT_FOR_FLAG(flag_per_adv);
251 	printk("Found periodic advertising.\n");
252 
253 	create_pa_sync(&sync);
254 
255 	printk("Waiting for periodic sync lost...\n");
256 	WAIT_FOR_FLAG(flag_per_adv_sync_lost);
257 
258 	TEST_PASS("Periodic advertising sync passed");
259 }
260 
main_per_adv_sync_app_not_scanning(void)261 static void main_per_adv_sync_app_not_scanning(void)
262 {
263 	int err;
264 	struct bt_le_per_adv_sync *sync = NULL;
265 
266 	common_init();
267 	start_scan();
268 
269 	printk("Waiting for periodic advertising...\n");
270 	WAIT_FOR_FLAG(flag_per_adv);
271 	printk("Found periodic advertising.\n");
272 
273 	printk("Stopping scan\n");
274 	err = bt_le_scan_stop();
275 	if (err != 0) {
276 		TEST_FAIL("Failed to stop scan: %d", err);
277 		return;
278 	}
279 
280 	create_pa_sync(&sync);
281 
282 	printk("Waiting for periodic sync lost...\n");
283 	WAIT_FOR_FLAG(flag_per_adv_sync_lost);
284 
285 	TEST_PASS("Periodic advertising sync passed");
286 }
287 
main_per_adv_conn_sync(void)288 static void main_per_adv_conn_sync(void)
289 {
290 	struct bt_le_per_adv_sync *sync = NULL;
291 
292 	common_init();
293 	start_scan();
294 
295 	printk("Waiting for connection...");
296 	WAIT_FOR_FLAG(flag_connected);
297 	printk("done.\n");
298 
299 	start_scan();
300 
301 	printk("Waiting for periodic advertising...\n");
302 	WAIT_FOR_FLAG(flag_per_adv);
303 	printk("Found periodic advertising.\n");
304 
305 	create_pa_sync(&sync);
306 
307 	printk("Waiting for periodic sync lost...\n");
308 	WAIT_FOR_FLAG(flag_per_adv_sync_lost);
309 
310 	TEST_PASS("Periodic advertising sync passed");
311 }
312 
main_per_adv_conn_privacy_sync(void)313 static void main_per_adv_conn_privacy_sync(void)
314 {
315 	struct bt_le_per_adv_sync *sync = NULL;
316 
317 	common_init();
318 	start_scan();
319 
320 	printk("Waiting for connection...");
321 	WAIT_FOR_FLAG(flag_connected);
322 	printk("done.\n");
323 
324 	start_bonding();
325 
326 	printk("Waiting for bonding...");
327 	WAIT_FOR_FLAG(flag_bonded);
328 	printk("done.\n");
329 
330 	start_scan();
331 
332 	printk("Waiting for periodic advertising...\n");
333 	WAIT_FOR_FLAG(flag_per_adv);
334 	printk("Found periodic advertising.\n");
335 
336 	create_pa_sync(&sync);
337 
338 	printk("Waiting for periodic sync lost...\n");
339 	WAIT_FOR_FLAG(flag_per_adv_sync_lost);
340 
341 	TEST_PASS("Periodic advertising sync passed");
342 }
343 
main_per_adv_long_data_sync(void)344 static void main_per_adv_long_data_sync(void)
345 {
346 #if (CONFIG_BT_PER_ADV_SYNC_BUF_SIZE > 0)
347 	struct bt_le_per_adv_sync *sync = NULL;
348 
349 	common_init();
350 	start_scan();
351 
352 	printk("Waiting for periodic advertising...\n");
353 	WAIT_FOR_FLAG(flag_per_adv);
354 	printk("Found periodic advertising.\n");
355 
356 	create_pa_sync(&sync);
357 
358 	printk("Waiting to receive periodic advertisement...\n");
359 	WAIT_FOR_FLAG(flag_per_adv_recv);
360 
361 	printk("Waiting for periodic sync lost...\n");
362 	WAIT_FOR_FLAG(flag_per_adv_sync_lost);
363 #endif
364 	TEST_PASS("Periodic advertising long data sync passed");
365 }
366 
367 static const struct bst_test_instance per_adv_sync[] = {
368 	{
369 		.test_id = "per_adv_sync",
370 		.test_descr = "Basic periodic advertising sync test. "
371 			      "Will just sync to a periodic advertiser.",
372 		.test_main_f = main_per_adv_sync
373 	},
374 	{
375 		.test_id = "per_adv_sync_app_not_scanning",
376 		.test_descr = "Basic periodic advertising sync test but where "
377 			      "the app stopped scanning before creating sync."
378 			      "Expect the host to start scanning automatically.",
379 		.test_main_f = main_per_adv_sync_app_not_scanning
380 	},
381 	{
382 		.test_id = "per_adv_conn_sync",
383 		.test_descr = "Periodic advertising sync test, but where there "
384 			      "is a connection between the advertiser and the "
385 			      "synchronized device.",
386 		.test_main_f = main_per_adv_conn_sync
387 	},
388 	{
389 		.test_id = "per_adv_conn_privacy_sync",
390 		.test_descr = "Periodic advertising sync test, but where "
391 			      "advertiser and synchronized device are bonded and using  "
392 			      "privacy",
393 		.test_main_f = main_per_adv_conn_privacy_sync
394 	},
395 	{
396 		.test_id = "per_adv_long_data_sync",
397 		.test_descr = "Periodic advertising sync test with larger "
398 			      "data length. Test is used to verify that "
399 			      "reassembly of long data is handeled correctly.",
400 		.test_main_f = main_per_adv_long_data_sync
401 	},
402 	BSTEST_END_MARKER
403 };
404 
test_per_adv_sync(struct bst_test_list * tests)405 struct bst_test_list *test_per_adv_sync(struct bst_test_list *tests)
406 {
407 	return bst_add_tests(tests, per_adv_sync);
408 }
409