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