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_connected);
26 CREATE_FLAG(flag_conn_recycled);
27
common_init(void)28 static void common_init(void)
29 {
30 int err;
31
32 err = bt_enable(NULL);
33
34 if (err) {
35 FAIL("Bluetooth init failed: %d\n", err);
36 return;
37 }
38 printk("Bluetooth initialized\n");
39 }
40
create_ext_adv_set(struct bt_le_ext_adv ** adv,bool connectable)41 static void create_ext_adv_set(struct bt_le_ext_adv **adv, bool connectable)
42 {
43 int err;
44
45 printk("Creating extended advertising set...");
46
47 const struct bt_le_adv_param *adv_param = connectable ?
48 BT_LE_EXT_ADV_CONN : BT_LE_EXT_ADV_NCONN;
49
50 err = bt_le_ext_adv_create(adv_param, NULL, adv);
51 if (err) {
52 printk("Failed to create advertising set: %d\n", err);
53 return;
54 }
55 printk("done.\n");
56 }
57
start_ext_adv_set(struct bt_le_ext_adv * adv)58 static void start_ext_adv_set(struct bt_le_ext_adv *adv)
59 {
60 int err;
61
62 printk("Starting Extended Advertising...");
63 err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
64 if (err) {
65 printk("Failed to start extended advertising: %d\n", err);
66 return;
67 }
68 printk("done.\n");
69 }
70
stop_ext_adv_set(struct bt_le_ext_adv * adv)71 static void stop_ext_adv_set(struct bt_le_ext_adv *adv)
72 {
73 int err;
74
75 printk("Stopping Extended Advertising...");
76 err = bt_le_ext_adv_stop(adv);
77 if (err) {
78 printk("Failed to stop extended advertising: %d\n",
79 err);
80 return;
81 }
82 printk("done.\n");
83 }
84
delete_adv_set(struct bt_le_ext_adv * adv)85 static void delete_adv_set(struct bt_le_ext_adv *adv)
86 {
87 int err;
88
89 printk("Delete extended advertising set...");
90 err = bt_le_ext_adv_delete(adv);
91 if (err) {
92 printk("Failed Delete extended advertising set: %d\n", err);
93 return;
94 }
95 printk("done.\n");
96 }
97
disconnect_from_target(void)98 static void disconnect_from_target(void)
99 {
100 int err;
101
102 printk("Disconnecting...\n");
103
104 err = bt_conn_disconnect(g_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
105 if (err) {
106 FAIL("BT Disconnect failed: %d\n", err);
107 return;
108 }
109 }
110
connected(struct bt_conn * conn,uint8_t err)111 static void connected(struct bt_conn *conn, uint8_t err)
112 {
113 char addr[BT_ADDR_LE_STR_LEN];
114
115 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
116
117 if (err != BT_HCI_ERR_SUCCESS) {
118 FAIL("Failed to connect to %s: %u\n", addr, err);
119 return;
120 }
121
122 printk("Connected to %s\n", addr);
123 if (g_conn != NULL) {
124 FAIL("Attempt to override connection object without clean-up\n");
125 return;
126 }
127 g_conn = bt_conn_ref(conn);
128 SET_FLAG(flag_connected);
129 }
130
free_conn_object_work_fn(struct k_work * work)131 static void free_conn_object_work_fn(struct k_work *work)
132 {
133 ARG_UNUSED(work);
134
135 bt_conn_unref(g_conn);
136 g_conn = NULL;
137 }
138
139 static K_WORK_DELAYABLE_DEFINE(free_conn_object_work, free_conn_object_work_fn);
140
disconnected(struct bt_conn * conn,uint8_t reason)141 static void disconnected(struct bt_conn *conn, uint8_t reason)
142 {
143 char addr[BT_ADDR_LE_STR_LEN];
144
145 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
146
147 printk("Disconnected: %s (reason %u)\n", addr, reason);
148
149 /* Schedule to cause de-sync between disconnected and recycled events,
150 * in order to prove the test is relying properly on it.
151 */
152 k_work_schedule(&free_conn_object_work, K_MSEC(100));
153
154 UNSET_FLAG(flag_connected);
155 }
156
recycled(void)157 static void recycled(void)
158 {
159 SET_FLAG(flag_conn_recycled);
160 }
161
162 static struct bt_conn_cb conn_cbs = {
163 .connected = connected,
164 .disconnected = disconnected,
165 .recycled = recycled,
166 };
167
main_ext_adv_advertiser(void)168 static void main_ext_adv_advertiser(void)
169 {
170 struct bt_le_ext_adv *ext_adv;
171
172 common_init();
173
174 create_ext_adv_set(&ext_adv, false);
175 start_ext_adv_set(ext_adv);
176
177 /* Advertise for a bit */
178 k_sleep(K_SECONDS(5));
179
180 stop_ext_adv_set(ext_adv);
181 delete_adv_set(ext_adv);
182
183 ext_adv = NULL;
184
185 PASS("Extended advertiser passed\n");
186 }
187
adv_connect_and_disconnect_cycle(void)188 static void adv_connect_and_disconnect_cycle(void)
189 {
190 struct bt_le_ext_adv *ext_adv;
191
192 create_ext_adv_set(&ext_adv, true);
193 start_ext_adv_set(ext_adv);
194
195 printk("Waiting for connection...\n");
196 WAIT_FOR_FLAG(flag_connected);
197
198 disconnect_from_target();
199 WAIT_FOR_FLAG_UNSET(flag_connected);
200
201 printk("Waiting for Connection object to be recycled...\n");
202 WAIT_FOR_FLAG(flag_conn_recycled);
203
204 /* Iteration Cleanup */
205 UNSET_FLAG(flag_conn_recycled);
206 stop_ext_adv_set(ext_adv);
207 delete_adv_set(ext_adv);
208 }
209
main_ext_conn_adv_advertiser(void)210 static void main_ext_conn_adv_advertiser(void)
211 {
212 struct bt_le_ext_adv *ext_adv;
213
214 common_init();
215
216 bt_conn_cb_register(&conn_cbs);
217
218 adv_connect_and_disconnect_cycle();
219
220 create_ext_adv_set(&ext_adv, false);
221 start_ext_adv_set(ext_adv);
222
223 /* Advertise for a bit */
224 k_sleep(K_SECONDS(5));
225
226 stop_ext_adv_set(ext_adv);
227 delete_adv_set(ext_adv);
228
229 ext_adv = NULL;
230
231 PASS("Extended advertiser passed\n");
232 }
233
main_ext_conn_adv_advertiser_x5(void)234 static void main_ext_conn_adv_advertiser_x5(void)
235 {
236 struct bt_le_ext_adv *ext_adv;
237
238 common_init();
239
240 bt_conn_cb_register(&conn_cbs);
241
242 for (size_t i = 0 ; i < 5 ; i++) {
243 printk("Iteration %d...\n", i);
244 adv_connect_and_disconnect_cycle();
245 }
246
247 /* Advertise for a bit */
248 create_ext_adv_set(&ext_adv, false);
249 start_ext_adv_set(ext_adv);
250 k_sleep(K_SECONDS(5));
251 stop_ext_adv_set(ext_adv);
252 delete_adv_set(ext_adv);
253 ext_adv = NULL;
254
255 PASS("Extended advertiser passed\n");
256 }
257
258 static const struct bst_test_instance ext_adv_advertiser[] = {
259 {
260 .test_id = "ext_adv_advertiser",
261 .test_descr = "Basic extended advertising test. "
262 "Will just start extended advertising.",
263 .test_pre_init_f = test_init,
264 .test_tick_f = test_tick,
265 .test_main_f = main_ext_adv_advertiser
266 },
267 {
268 .test_id = "ext_adv_conn_advertiser",
269 .test_descr = "Basic connectable extended advertising test. "
270 "Starts extended advertising, and restarts it after disconnecting",
271 .test_pre_init_f = test_init,
272 .test_tick_f = test_tick,
273 .test_main_f = main_ext_conn_adv_advertiser
274 },
275 {
276 .test_id = "ext_adv_conn_advertiser_x5",
277 .test_descr = "Basic connectable extended advertising test. "
278 "Starts extended advertising, and restarts it after disconnecting, "
279 "repeated over 5 times",
280 .test_pre_init_f = test_init,
281 .test_tick_f = test_tick,
282 .test_main_f = main_ext_conn_adv_advertiser_x5
283 },
284 BSTEST_END_MARKER
285 };
286
test_ext_adv_advertiser(struct bst_test_list * tests)287 struct bst_test_list *test_ext_adv_advertiser(struct bst_test_list *tests)
288 {
289 return bst_add_tests(tests, ext_adv_advertiser);
290 }
291
292 bst_test_install_t test_installers[] = {
293 test_ext_adv_advertiser,
294 NULL
295 };
296
main(void)297 int main(void)
298 {
299 bst_main();
300 return 0;
301 }
302