1 /*
2  * Copyright (c) 2024-2025 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <string.h>
9 
10 #include <zephyr/autoconf.h>
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/bluetooth/gap.h>
13 #include <zephyr/bluetooth/hci_types.h>
14 #include <zephyr/bluetooth/iso.h>
15 #include <zephyr/logging/log.h>
16 #include <zephyr/sys/util.h>
17 
18 #include "babblekit/flags.h"
19 #include "babblekit/sync.h"
20 #include "babblekit/testcase.h"
21 
22 #include "common.h"
23 
24 LOG_MODULE_REGISTER(bis_receiver, LOG_LEVEL_INF);
25 
26 #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 5U /* Set the timeout relative to interval */
27 /* The broadcaster will send SDUs from 0 to CONFIG_BT_ISO_RX_MTU in the SDU data length. We want to
28  * receive at least 2 of each size to ensure correctness
29  */
30 #define RX_CNT_TO_PASS                    (CONFIG_BT_ISO_RX_MTU * 2)
31 
32 extern enum bst_result_t bst_result;
33 
34 DEFINE_FLAG_STATIC(flag_broadcaster_found);
35 DEFINE_FLAG_STATIC(flag_iso_connected);
36 DEFINE_FLAG_STATIC(flag_data_received);
37 DEFINE_FLAG_STATIC(flag_pa_synced);
38 DEFINE_FLAG_STATIC(flag_biginfo);
39 
40 static struct bt_iso_chan iso_chans[CONFIG_BT_ISO_MAX_CHAN];
41 static struct bt_le_scan_recv_info broadcaster_info;
42 static bt_addr_le_t broadcaster_addr;
43 static uint8_t broadcaster_num_bis;
44 
45 /** Log data as d_0 d_1 d_2 ... d_(n-2) d_(n-1) d_(n) to show the 3 first and 3 last octets
46  *
47  * Examples:
48  * 01
49  * 0102
50  * 010203
51  * 01020304
52  * 0102030405
53  * 010203040506
54  * 010203...050607
55  * 010203...060708
56  * etc.
57  */
iso_log_data(uint8_t * data,size_t data_len)58 static void iso_log_data(uint8_t *data, size_t data_len)
59 {
60 	/* Maximum number of octets from each end of the data */
61 	const uint8_t max_octets = 3;
62 	char data_str[35];
63 	size_t str_len;
64 
65 	str_len = bin2hex(data, MIN(max_octets, data_len), data_str, sizeof(data_str));
66 	if (data_len > max_octets) {
67 		if (data_len > (max_octets * 2)) {
68 			static const char dots[] = "...";
69 
70 			strcat(&data_str[str_len], dots);
71 			str_len += strlen(dots);
72 		}
73 
74 		str_len += bin2hex(data + (data_len - MIN(max_octets, data_len - max_octets)),
75 				   MIN(max_octets, data_len - max_octets), data_str + str_len,
76 				   sizeof(data_str) - str_len);
77 	}
78 
79 	LOG_DBG("\t %s", data_str);
80 }
81 
iso_recv(struct bt_iso_chan * chan,const struct bt_iso_recv_info * info,struct net_buf * buf)82 static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *info,
83 		     struct net_buf *buf)
84 {
85 	if (IS_FLAG_SET(flag_data_received)) {
86 		return;
87 	}
88 
89 	if (info->flags & BT_ISO_FLAGS_VALID) {
90 		static uint16_t last_buf_len;
91 		static uint32_t last_ts;
92 		static size_t rx_cnt;
93 
94 		LOG_DBG("Incoming data channel %p len %u", chan, buf->len);
95 		iso_log_data(buf->data, buf->len);
96 
97 		if (memcmp(buf->data, mock_iso_data, buf->len) != 0) {
98 			TEST_FAIL("Unexpected data received");
99 		} else if (last_buf_len != 0U && buf->len != 1U && buf->len != last_buf_len + 1) {
100 			TEST_FAIL("Unexpected data length (%u) received (expected 1 or %u)",
101 				  buf->len, last_buf_len);
102 		} else if (last_ts != 0U && info->ts > last_ts + 2 * SDU_INTERVAL_US) {
103 			TEST_FAIL("Unexpected timestamp (%u) received (expected %u)", info->ts,
104 				  last_ts + SDU_INTERVAL_US);
105 		} else if (rx_cnt++ > RX_CNT_TO_PASS) {
106 			LOG_INF("Data received");
107 			SET_FLAG(flag_data_received);
108 		}
109 
110 		last_buf_len = buf->len;
111 		last_ts = info->ts;
112 	}
113 }
114 
iso_connected(struct bt_iso_chan * chan)115 static void iso_connected(struct bt_iso_chan *chan)
116 {
117 	const struct bt_iso_chan_path hci_path = {
118 		.pid = BT_ISO_DATA_PATH_HCI,
119 		.format = BT_HCI_CODING_FORMAT_TRANSPARENT,
120 	};
121 	struct bt_iso_info info;
122 	int err;
123 
124 	LOG_INF("ISO Channel %p connected", chan);
125 
126 	err = bt_iso_chan_get_info(chan, &info);
127 	TEST_ASSERT(err == 0, "Failed to get BIS info: %d", err);
128 
129 	TEST_ASSERT(info.can_recv);
130 	TEST_ASSERT(!info.can_send);
131 	TEST_ASSERT(info.type == BT_ISO_CHAN_TYPE_SYNC_RECEIVER);
132 	TEST_ASSERT(IN_RANGE(info.iso_interval, BT_ISO_ISO_INTERVAL_MIN, BT_ISO_ISO_INTERVAL_MAX),
133 		    "Invalid ISO interval 0x%04x", info.iso_interval);
134 	TEST_ASSERT(IN_RANGE(info.max_subevent, BT_ISO_NSE_MIN, BT_ISO_NSE_MAX),
135 		    "Invalid subevent number 0x%02x", info.max_subevent);
136 	TEST_ASSERT(IN_RANGE(info.sync_receiver.latency, BT_HCI_LE_TRANSPORT_LATENCY_BIG_MIN,
137 			     BT_HCI_LE_TRANSPORT_LATENCY_BIG_MAX),
138 		    "Invalid transport latency 0x%06x", info.sync_receiver.latency);
139 	TEST_ASSERT((info.sync_receiver.pto % info.iso_interval) == 0U,
140 		    "PTO in ms %u shall be a multiple of the ISO interval %u",
141 		    info.sync_receiver.pto, info.iso_interval);
142 	TEST_ASSERT(IN_RANGE((info.sync_receiver.pto / info.iso_interval), BT_ISO_PTO_MIN,
143 			     BT_ISO_PTO_MAX),
144 		    "Invalid PTO 0x%x", (info.sync_receiver.pto / info.iso_interval));
145 	TEST_ASSERT(IN_RANGE(info.sync_receiver.bn, BT_ISO_BN_MIN, BT_ISO_BN_MAX),
146 		    "Invalid BN 0x%02x", info.sync_receiver.bn);
147 	TEST_ASSERT(IN_RANGE(info.sync_receiver.irc, BT_ISO_IRC_MIN, BT_ISO_IRC_MAX),
148 		    "Invalid IRC 0x%02x", info.sync_receiver.irc);
149 	TEST_ASSERT(info.sync_receiver.big_handle != 0xFF /* invalid BIG handle */,
150 		    "Invalid BIG handle 0x%02x", info.sync_receiver.big_handle);
151 	TEST_ASSERT(
152 		IN_RANGE(info.sync_receiver.bis_number, BT_ISO_BIS_INDEX_MIN, BT_ISO_BIS_INDEX_MAX),
153 		"Invalid BIS number 0x%02x", info.sync_receiver.bis_number);
154 
155 	SET_FLAG(flag_iso_connected);
156 
157 	err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path);
158 	TEST_ASSERT(err == 0, "Failed to setup ISO RX data path: %d\n", err);
159 }
160 
iso_disconnected(struct bt_iso_chan * chan,uint8_t reason)161 static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
162 {
163 	LOG_INF("ISO Channel %p disconnected (reason 0x%02x)", chan, reason);
164 
165 	UNSET_FLAG(flag_iso_connected);
166 }
167 
broadcast_scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)168 static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad)
169 {
170 	if (IS_FLAG_SET(flag_broadcaster_found)) {
171 		/* no-op*/
172 		return;
173 	}
174 
175 	LOG_INF("Broadcaster found");
176 
177 	if (info->interval != 0U) {
178 		memcpy(&broadcaster_info, info, sizeof(broadcaster_info));
179 		bt_addr_le_copy(&broadcaster_addr, info->addr);
180 		SET_FLAG(flag_broadcaster_found);
181 	}
182 }
183 
pa_synced_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)184 static void pa_synced_cb(struct bt_le_per_adv_sync *sync,
185 			 struct bt_le_per_adv_sync_synced_info *info)
186 {
187 	LOG_INF("PA synced");
188 
189 	SET_FLAG(flag_pa_synced);
190 }
191 
pa_term_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)192 static void pa_term_cb(struct bt_le_per_adv_sync *sync,
193 		       const struct bt_le_per_adv_sync_term_info *info)
194 {
195 	LOG_INF("PA terminated");
196 
197 	UNSET_FLAG(flag_pa_synced);
198 }
199 
pa_biginfo_cb(struct bt_le_per_adv_sync * sync,const struct bt_iso_biginfo * biginfo)200 static void pa_biginfo_cb(struct bt_le_per_adv_sync *sync, const struct bt_iso_biginfo *biginfo)
201 {
202 	if (IS_FLAG_SET(flag_biginfo)) {
203 		/* no-op*/
204 		return;
205 	}
206 
207 	LOG_INF("BIGInfo received");
208 
209 	broadcaster_num_bis = biginfo->num_bis;
210 	SET_FLAG(flag_biginfo);
211 }
212 
init(void)213 static void init(void)
214 {
215 	static struct bt_le_per_adv_sync_cb pa_sync_cbs = {
216 		.biginfo = pa_biginfo_cb,
217 		.synced = pa_synced_cb,
218 		.term = pa_term_cb,
219 	};
220 	static struct bt_le_scan_cb bap_scan_cb = {
221 		.recv = broadcast_scan_recv,
222 	};
223 	static struct bt_iso_chan_io_qos iso_rx = {
224 		.sdu = CONFIG_BT_ISO_TX_MTU,
225 	};
226 	static struct bt_iso_chan_ops iso_ops = {
227 		.recv = iso_recv,
228 		.connected = iso_connected,
229 		.disconnected = iso_disconnected,
230 	};
231 	static struct bt_iso_chan_qos iso_qos = {
232 		.rx = &iso_rx,
233 	};
234 	int err;
235 
236 	err = bt_enable(NULL);
237 	TEST_ASSERT(err == 0, "Bluetooth enable failed (err %d)", err);
238 
239 	for (size_t i = 0U; i < ARRAY_SIZE(iso_chans); i++) {
240 		iso_chans[i].ops = &iso_ops;
241 		iso_chans[i].qos = &iso_qos;
242 	}
243 
244 	bt_le_per_adv_sync_cb_register(&pa_sync_cbs);
245 	bt_le_scan_cb_register(&bap_scan_cb);
246 
247 	bk_sync_init();
248 }
249 
interval_to_sync_timeout(uint16_t pa_interval)250 static uint16_t interval_to_sync_timeout(uint16_t pa_interval)
251 {
252 	uint32_t interval_us;
253 	uint32_t timeout;
254 
255 	/* Add retries and convert to unit in 10's of ms */
256 	interval_us = BT_GAP_PER_ADV_INTERVAL_TO_US(pa_interval);
257 	timeout =
258 		BT_GAP_US_TO_PER_ADV_SYNC_TIMEOUT(interval_us) * PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO;
259 
260 	/* Enforce restraints */
261 	timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT);
262 
263 	return timeout;
264 }
265 
scan_and_sync_pa(struct bt_le_per_adv_sync ** out_sync)266 static void scan_and_sync_pa(struct bt_le_per_adv_sync **out_sync)
267 {
268 	struct bt_le_per_adv_sync_param create_params = {0};
269 	int err;
270 
271 	LOG_INF("Starting scan");
272 	err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
273 	TEST_ASSERT(err == 0, "Failed to start scan: %d", err);
274 
275 	WAIT_FOR_FLAG(flag_broadcaster_found);
276 
277 	bt_addr_le_copy(&create_params.addr, &broadcaster_addr);
278 	create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE;
279 	create_params.sid = broadcaster_info.sid;
280 	create_params.skip = 0U;
281 	create_params.timeout = interval_to_sync_timeout(broadcaster_info.interval);
282 
283 	LOG_INF("Creating PA sync");
284 	err = bt_le_per_adv_sync_create(&create_params, out_sync);
285 	TEST_ASSERT(err == 0, "Failed to sync to PA: %d", err);
286 
287 	WAIT_FOR_FLAG(flag_pa_synced);
288 
289 	LOG_INF("Stopping scan");
290 	err = bt_le_scan_stop();
291 	TEST_ASSERT(err == 0, "Failed to stop scan: %d", err);
292 }
293 
sync_big(struct bt_le_per_adv_sync * sync,uint8_t cnt,struct bt_iso_big ** out_big)294 static void sync_big(struct bt_le_per_adv_sync *sync, uint8_t cnt, struct bt_iso_big **out_big)
295 {
296 	struct bt_iso_chan *bis_channels[CONFIG_BT_ISO_MAX_CHAN];
297 	struct bt_iso_big_sync_param param = {
298 		.sync_timeout = interval_to_sync_timeout(broadcaster_info.interval),
299 		.bis_bitfield = BIT_MASK(cnt),
300 		.bis_channels = bis_channels,
301 		.mse = BT_ISO_SYNC_MSE_MIN,
302 		.encryption = false,
303 		.num_bis = cnt,
304 	};
305 	int err;
306 
307 	TEST_ASSERT(cnt <= ARRAY_SIZE(bis_channels));
308 	for (size_t i = 0U; i < cnt; i++) {
309 		bis_channels[i] = &iso_chans[i];
310 	}
311 
312 	LOG_INF("Creating BIG sync");
313 	err = bt_iso_big_sync(sync, &param, out_big);
314 	TEST_ASSERT(err == 0, "Failed to create BIG sync: %d");
315 
316 	WAIT_FOR_FLAG(flag_iso_connected);
317 }
318 
test_main(void)319 static void test_main(void)
320 {
321 	struct bt_le_per_adv_sync *sync;
322 	struct bt_iso_big *big;
323 
324 	init();
325 	scan_and_sync_pa(&sync);
326 	WAIT_FOR_FLAG(flag_biginfo);
327 	sync_big(sync, MIN(broadcaster_num_bis, CONFIG_BT_ISO_MAX_CHAN), &big);
328 
329 	LOG_INF("Waiting for data");
330 	WAIT_FOR_FLAG(flag_data_received);
331 	bk_sync_send();
332 
333 	LOG_INF("Waiting for sync lost");
334 	WAIT_FOR_FLAG_UNSET(flag_iso_connected);
335 
336 	TEST_PASS("Test passed");
337 }
338 
339 static const struct bst_test_instance test_def[] = {
340 	{
341 		.test_id = "receiver",
342 		.test_descr = "receiver",
343 		.test_main_f = test_main,
344 	},
345 	BSTEST_END_MARKER,
346 };
347 
test_main_bis_receiver_install(struct bst_test_list * tests)348 struct bst_test_list *test_main_bis_receiver_install(struct bst_test_list *tests)
349 {
350 	return bst_add_tests(tests, test_def);
351 }
352