1 /**
2 * Copyright (c) 2024 Croxel, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/kernel.h>
7
8 #include "babblekit/testcase.h"
9 #include "babblekit/flags.h"
10
11 #include <zephyr/types.h>
12 #include <zephyr/sys/printk.h>
13
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/conn.h>
16
17 extern enum bst_result_t bst_result;
18
19 static struct bt_conn *g_conn;
20
21 DEFINE_FLAG_STATIC(flag_ext_adv_seen);
22 DEFINE_FLAG_STATIC(flag_connected);
23 DEFINE_FLAG_STATIC(flag_conn_recycled);
24
connected(struct bt_conn * conn,uint8_t err)25 static void connected(struct bt_conn *conn, uint8_t err)
26 {
27 char addr[BT_ADDR_LE_STR_LEN];
28
29 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
30
31 if (err != BT_HCI_ERR_SUCCESS) {
32 TEST_FAIL("Failed to connect to %s: %u", addr, err);
33 bt_conn_unref(g_conn);
34 g_conn = NULL;
35 return;
36 }
37
38 printk("Connected to %s\n", addr);
39 SET_FLAG(flag_connected);
40 }
41
free_conn_object_work_fn(struct k_work * work)42 static void free_conn_object_work_fn(struct k_work *work)
43 {
44 ARG_UNUSED(work);
45
46 bt_conn_unref(g_conn);
47 g_conn = NULL;
48 }
49
50 static K_WORK_DELAYABLE_DEFINE(free_conn_object_work, free_conn_object_work_fn);
51
disconnected(struct bt_conn * conn,uint8_t reason)52 static void disconnected(struct bt_conn *conn, uint8_t reason)
53 {
54 char addr[BT_ADDR_LE_STR_LEN];
55
56 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
57
58 printk("Disconnected: %s (reason %u)\n", addr, reason);
59
60 /* Schedule to cause de-sync between disconnected and recycled events,
61 * in order to prove the test is relying properly on it.
62 */
63 k_work_schedule(&free_conn_object_work, K_MSEC(500));
64
65 UNSET_FLAG(flag_connected);
66 }
67
recycled(void)68 static void recycled(void)
69 {
70 SET_FLAG(flag_conn_recycled);
71 }
72
73 static struct bt_conn_cb conn_cbs = {
74 .connected = connected,
75 .disconnected = disconnected,
76 .recycled = recycled,
77 };
78
79
scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)80 static void scan_recv(const struct bt_le_scan_recv_info *info,
81 struct net_buf_simple *buf)
82 {
83 printk("Found advertisement. Adv-type: 0x%02x, Adv-prop: 0x%02x\n",
84 info->adv_type, info->adv_props);
85
86 if (info->adv_type == BT_GAP_ADV_TYPE_EXT_ADV &&
87 info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) {
88 printk("Found extended advertisement!\n");
89 SET_FLAG(flag_ext_adv_seen);
90 }
91
92 if (!IS_FLAG_SET(flag_connected) && info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) {
93 int err;
94
95 printk("Stopping scan\n");
96 err = bt_le_scan_stop();
97 if (err) {
98 TEST_FAIL("Failed to stop scan: %d", err);
99 return;
100 }
101
102 err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN,
103 BT_LE_CONN_PARAM_DEFAULT, &g_conn);
104 if (err) {
105 TEST_FAIL("Could not connect to peer: %d", err);
106 return;
107 }
108 }
109 }
110
111 static struct bt_le_scan_cb scan_callbacks = {
112 .recv = scan_recv,
113 };
114
common_init(void)115 static void common_init(void)
116 {
117 int err = 0;
118
119 err = bt_enable(NULL);
120
121 if (err) {
122 TEST_FAIL("Bluetooth init failed: %d", err);
123 return;
124 }
125
126 bt_conn_cb_register(&conn_cbs);
127 bt_le_scan_cb_register(&scan_callbacks);
128
129 printk("Bluetooth initialized\n");
130 }
131
start_scan(void)132 static void start_scan(void)
133 {
134 int err;
135
136 printk("Start scanning...");
137 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
138 if (err) {
139 TEST_FAIL("Failed to start scan: %d", err);
140 return;
141 }
142 printk("done.\n");
143 }
144
main_ext_adv_scanner(void)145 static void main_ext_adv_scanner(void)
146 {
147 common_init();
148 start_scan();
149
150 printk("Waiting for extended advertisements...\n");
151
152 WAIT_FOR_FLAG(flag_ext_adv_seen);
153
154 TEST_PASS("Extended adv scanner passed");
155 }
156
scan_connect_and_disconnect_cycle(void)157 static void scan_connect_and_disconnect_cycle(void)
158 {
159 start_scan();
160
161 printk("Waiting for extended advertisements...\n");
162 WAIT_FOR_FLAG(flag_ext_adv_seen);
163
164 printk("Waiting for connection with device...\n");
165 WAIT_FOR_FLAG(flag_connected);
166
167 printk("Waiting for device disconnection...\n");
168 WAIT_FOR_FLAG_UNSET(flag_connected);
169
170 printk("Waiting for Connection object to be recycled...\n");
171 WAIT_FOR_FLAG(flag_conn_recycled);
172
173 /* Iteration cleanup */
174 printk("Clearing flag for seen extended advertisements...\n");
175 UNSET_FLAG(flag_ext_adv_seen);
176 UNSET_FLAG(flag_conn_recycled);
177 }
178
main_ext_adv_conn_scanner(void)179 static void main_ext_adv_conn_scanner(void)
180 {
181 common_init();
182
183 scan_connect_and_disconnect_cycle();
184
185 start_scan();
186 printk("Waiting to extended advertisements (again)...\n");
187 WAIT_FOR_FLAG(flag_ext_adv_seen);
188
189 TEST_PASS("Extended adv scanner passed");
190 }
191
main_ext_adv_conn_scanner_x5(void)192 static void main_ext_adv_conn_scanner_x5(void)
193 {
194 common_init();
195
196 for (size_t i = 0 ; i < 5 ; i++) {
197 printk("Iteration %d...\n", i);
198 scan_connect_and_disconnect_cycle();
199 }
200
201 start_scan();
202 printk("Waiting to extended advertisements (again)...\n");
203 WAIT_FOR_FLAG(flag_ext_adv_seen);
204
205 TEST_PASS("Extended adv scanner x5 passed");
206 }
207
208 static const struct bst_test_instance ext_adv_scanner[] = {
209 {
210 .test_id = "ext_adv_scanner",
211 .test_descr = "Basic extended advertising scanning test. "
212 "Will just scan an extended advertiser.",
213 .test_main_f = main_ext_adv_scanner
214 },
215 {
216 .test_id = "ext_adv_conn_scanner",
217 .test_descr = "Basic extended advertising scanning test. "
218 "Will scan an extended advertiser, connect "
219 "and verify it's detected after disconnection",
220 .test_main_f = main_ext_adv_conn_scanner
221 },
222 {
223 .test_id = "ext_adv_conn_scanner_x5",
224 .test_descr = "Basic extended advertising scanning test. "
225 "Will scan an extended advertiser, connect "
226 "and verify it's detected after disconnection,"
227 "repeated over 5 times",
228 .test_main_f = main_ext_adv_conn_scanner_x5
229 },
230 BSTEST_END_MARKER
231 };
232
test_ext_adv_scanner(struct bst_test_list * tests)233 struct bst_test_list *test_ext_adv_scanner(struct bst_test_list *tests)
234 {
235 return bst_add_tests(tests, ext_adv_scanner);
236 }
237
238 bst_test_install_t test_installers[] = {
239 test_ext_adv_scanner,
240 NULL
241 };
242
main(void)243 int main(void)
244 {
245 bst_main();
246 return 0;
247 }
248