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