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