1 /* Copyright (c) 2024 Nordic Semiconductor ASA
2 * SPDX-License-Identifier: Apache-2.0
3 */
4
5 #include <zephyr/kernel.h>
6 #include <zephyr/irq.h>
7 #include <string.h>
8
9 #include <zephyr/logging/log.h>
10 #include <zephyr/settings/settings.h>
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/bluetooth/addr.h>
13 #include <zephyr/sys/atomic.h>
14 #include <zephyr/sys/atomic_builtin.h>
15 #include <babblekit/testcase.h>
16 #include <babblekit/sync.h>
17 #include <babblekit/flags.h>
18
19 LOG_MODULE_REGISTER(bt_bsim_scan_start_stop, LOG_LEVEL_DBG);
20
21 static atomic_t flag_adv_report_received;
22 static atomic_t flag_periodic_sync_established;
23 static bt_addr_le_t adv_addr;
24
bt_sync_established_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)25 static void bt_sync_established_cb(struct bt_le_per_adv_sync *sync,
26 struct bt_le_per_adv_sync_synced_info *info)
27 {
28 LOG_DBG("Periodic sync established");
29 atomic_set(&flag_periodic_sync_established, true);
30 }
31
32 static struct bt_le_per_adv_sync_cb sync_callbacks = {
33 .synced = bt_sync_established_cb,
34 };
35
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)36 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
37 struct net_buf_simple *ad)
38 {
39 char addr_str[BT_ADDR_LE_STR_LEN];
40
41 memcpy(&adv_addr, addr, sizeof(adv_addr));
42
43 bt_addr_le_to_str(&adv_addr, addr_str, sizeof(addr_str));
44 LOG_DBG("Device found: %s (RSSI %d), type %u, AD data len %u",
45 addr_str, rssi, type, ad->len);
46 atomic_set(&flag_adv_report_received, true);
47 }
48
run_dut(void)49 void run_dut(void)
50 {
51 /* Test purpose:
52 *
53 * Verifies that the scanner can establish a sync to a device when
54 * it is explicitly enabled and disabled. Disabling the scanner
55 * explicitly should not stop the implicitly started scanner.
56 * Verify that the explicit scanner can be started when the
57 * implicit scanner is already running.
58 *
59 * Two devices:
60 * - `dut`: tries to establish the sync
61 * - `peer`: runs an advertiser / periodic advertiser
62 *
63 * Procedure:
64 * - [dut] start establishing a sync (no peer)
65 * - [peer] starts advertising
66 * - [dut] starts explicit scanning
67 * - [dut] wait for the peer to be found
68 * - [dut] stops explicit scanning
69 * - [dut] stop the periodic sync
70 * - [dut] start establishing a sync to the peer
71 * - [dut] start and stop explicit scanning
72 * - [peer] start periodic advertiser
73 * - [dut] wait until a sync is established
74 *
75 * [verdict]
76 * - dut is able to sync to the peer.
77 */
78
79 LOG_DBG("start");
80 bk_sync_init();
81 int err;
82
83 LOG_DBG("Starting DUT");
84
85 err = bt_enable(NULL);
86 TEST_ASSERT(!err, "Bluetooth init failed (err %d)", err);
87
88 LOG_DBG("Bluetooth initialised");
89
90 /* Try to establish a sync to a periodic advertiser.
91 * This will start the scanner.
92 */
93 memset(&adv_addr, 0x00, sizeof(adv_addr));
94 struct bt_le_per_adv_sync_param per_sync_param = {
95 .addr = adv_addr,
96 .options = 0x0,
97 .sid = 0x0,
98 .skip = 0x0,
99 .timeout = BT_GAP_PER_ADV_MAX_TIMEOUT,
100 };
101 struct bt_le_per_adv_sync *p_per_sync;
102
103 bt_le_per_adv_sync_cb_register(&sync_callbacks);
104
105 err = bt_le_per_adv_sync_create(&per_sync_param, &p_per_sync);
106 TEST_ASSERT(!err, "Periodic sync setup failed (err %d)", err);
107 LOG_DBG("Periodic sync started");
108
109 /* Start scanner. Check that we can start the scanner while it is already
110 * running due to the periodic sync.
111 */
112 struct bt_le_scan_param scan_params = {
113 .type = BT_LE_SCAN_TYPE_ACTIVE,
114 .options = 0x0,
115 .interval = 123,
116 .window = 12,
117 .interval_coded = 222,
118 .window_coded = 32,
119 };
120
121 err = bt_le_scan_start(&scan_params, device_found);
122 TEST_ASSERT(!err, "Scanner setup failed (err %d)", err);
123 LOG_DBG("Explicit scanner started");
124
125 LOG_DBG("Wait for an advertising report");
126 WAIT_FOR_FLAG(flag_adv_report_received);
127
128 /* Stop the scanner. That should not affect the periodic advertising sync. */
129 err = bt_le_scan_stop();
130 TEST_ASSERT(!err, "Scanner stop failed (err %d)", err);
131 LOG_DBG("Explicit scanner stopped");
132
133 /* We should be able to stop the periodic advertising sync. */
134 err = bt_le_per_adv_sync_delete(p_per_sync);
135 TEST_ASSERT(!err, "Periodic sync stop failed (err %d)", err);
136 LOG_DBG("Periodic sync stopped");
137
138 /* Start the periodic advertising sync. This time, provide the address of the advertiser
139 * which it should connect to.
140 */
141 per_sync_param = (struct bt_le_per_adv_sync_param) {
142 .addr = adv_addr,
143 .options = 0x0,
144 .sid = 0x0,
145 .skip = 0x0,
146 .timeout = BT_GAP_PER_ADV_MAX_TIMEOUT
147 };
148 err = bt_le_per_adv_sync_create(&per_sync_param, &p_per_sync);
149 TEST_ASSERT(!err, "Periodic sync setup failed (err %d)", err);
150 LOG_DBG("Periodic sync started");
151
152 /* Start the explicit scanner */
153 err = bt_le_scan_start(&scan_params, device_found);
154 TEST_ASSERT(!err, "Scanner setup failed (err %d)", err);
155 LOG_DBG("Explicit scanner started");
156
157 /* Stop the explicit scanner. This should not stop scanner, since we still try to establish
158 * a sync.
159 */
160 err = bt_le_scan_stop();
161 TEST_ASSERT(!err, "Scanner stop failed (err %d)", err);
162 LOG_DBG("Explicit scanner stopped");
163
164 /* Signal to the tester to start the periodic adv. */
165 bk_sync_send();
166
167 /* Validate that we can still establish a sync */
168 LOG_DBG("Wait for sync to periodic adv");
169 WAIT_FOR_FLAG(flag_periodic_sync_established);
170
171 /* Signal to the tester to end the test. */
172 bk_sync_send();
173
174 TEST_PASS("Test passed (DUT)");
175 }
176
run_tester(void)177 void run_tester(void)
178 {
179 LOG_DBG("start");
180 bk_sync_init();
181
182 int err;
183
184 LOG_DBG("Starting DUT");
185
186 err = bt_enable(NULL);
187 TEST_ASSERT(!err, "Bluetooth init failed (err %d)", err);
188
189 LOG_DBG("Bluetooth initialised");
190
191 struct bt_le_ext_adv *per_adv;
192
193 struct bt_le_adv_param adv_param = BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_EXT_ADV,
194 BT_GAP_ADV_FAST_INT_MIN_2,
195 BT_GAP_ADV_FAST_INT_MAX_2,
196 NULL);
197
198 err = bt_le_ext_adv_create(&adv_param, NULL, &per_adv);
199 TEST_ASSERT(!err, "Failed to create advertising set: %d", err);
200 LOG_DBG("Created extended advertising set.");
201
202 err = bt_le_ext_adv_start(per_adv, BT_LE_EXT_ADV_START_DEFAULT);
203 TEST_ASSERT(!err, "Failed to start extended advertising: %d", err);
204 LOG_DBG("Started extended advertising.");
205
206 /* Wait for the DUT before starting the periodic advertising */
207 bk_sync_wait();
208 err = bt_le_per_adv_set_param(per_adv, BT_LE_PER_ADV_DEFAULT);
209 TEST_ASSERT(!err, "Failed to set periodic advertising parameters: %d", err);
210 LOG_DBG("Periodic advertising parameters set.");
211
212 err = bt_le_per_adv_start(per_adv);
213 TEST_ASSERT(!err, "Failed to start periodic advertising: %d", err);
214 LOG_DBG("Periodic advertising started.");
215
216 /* Wait for the signal from the DUT before finishing the test */
217 bk_sync_wait();
218
219 bt_le_per_adv_stop(per_adv);
220
221 TEST_PASS("Test passed (Tester)");
222 }
223
224 static const struct bst_test_instance test_def[] = {
225 {
226 .test_id = "scanner",
227 .test_descr = "SCANNER",
228 .test_main_f = run_dut,
229 },
230 {
231 .test_id = "periodic_adv",
232 .test_descr = "PER_ADV",
233 .test_main_f = run_tester,
234 },
235 BSTEST_END_MARKER
236 };
237
test_scan_start_stop_install(struct bst_test_list * tests)238 struct bst_test_list *test_scan_start_stop_install(struct bst_test_list *tests)
239 {
240 return bst_add_tests(tests, test_def);
241 }
242
243 bst_test_install_t test_installers[] = {test_scan_start_stop_install, NULL};
244
main(void)245 int main(void)
246 {
247 bst_main();
248 return 0;
249 }
250