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