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