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, ¶m, 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