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