1 /*
2 * Copyright (c) 2024 Nordic Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8 #include "common.h"
9
10 #include <zephyr/bluetooth/bluetooth.h>
11 #include <zephyr/bluetooth/gap.h>
12 #include <zephyr/bluetooth/iso.h>
13 #include <zephyr/logging/log.h>
14 #include <zephyr/sys/util.h>
15
16 #include "babblekit/flags.h"
17 #include "babblekit/sync.h"
18 #include "babblekit/testcase.h"
19
20 LOG_MODULE_REGISTER(bis_receiver, LOG_LEVEL_INF);
21
22 #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 5U /* Set the timeout relative to interval */
23
24 extern enum bst_result_t bst_result;
25
26 static DEFINE_FLAG(flag_broadcaster_found);
27 static DEFINE_FLAG(flag_iso_connected);
28 static DEFINE_FLAG(flag_data_received);
29 static DEFINE_FLAG(flag_pa_synced);
30 static DEFINE_FLAG(flag_biginfo);
31
32 static struct bt_iso_chan iso_chans[CONFIG_BT_ISO_MAX_CHAN];
33 static struct bt_le_scan_recv_info broadcaster_info;
34 static bt_addr_le_t broadcaster_addr;
35 static uint8_t broadcaster_num_bis;
36
37 /** 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
38 *
39 * Examples:
40 * 01
41 * 0102
42 * 010203
43 * 01020304
44 * 0102030405
45 * 010203040506
46 * 010203...050607
47 * 010203...060708
48 * etc.
49 */
iso_log_data(uint8_t * data,size_t data_len)50 static void iso_log_data(uint8_t *data, size_t data_len)
51 {
52 /* Maximum number of octets from each end of the data */
53 const uint8_t max_octets = 3;
54 char data_str[35];
55 size_t str_len;
56
57 str_len = bin2hex(data, MIN(max_octets, data_len), data_str, sizeof(data_str));
58 if (data_len > max_octets) {
59 if (data_len > (max_octets * 2)) {
60 static const char dots[] = "...";
61
62 strcat(&data_str[str_len], dots);
63 str_len += strlen(dots);
64 }
65
66 str_len += bin2hex(data + (data_len - MIN(max_octets, data_len - max_octets)),
67 MIN(max_octets, data_len - max_octets), data_str + str_len,
68 sizeof(data_str) - str_len);
69 }
70
71 LOG_DBG("\t %s", data_str);
72 }
73
iso_recv(struct bt_iso_chan * chan,const struct bt_iso_recv_info * info,struct net_buf * buf)74 static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *info,
75 struct net_buf *buf)
76 {
77 if (info->flags & BT_ISO_FLAGS_VALID) {
78 LOG_DBG("Incoming data channel %p len %u", chan, buf->len);
79 iso_log_data(buf->data, buf->len);
80 SET_FLAG(flag_data_received);
81 }
82 }
83
iso_connected(struct bt_iso_chan * chan)84 static void iso_connected(struct bt_iso_chan *chan)
85 {
86 LOG_INF("ISO Channel %p connected", chan);
87
88 SET_FLAG(flag_iso_connected);
89 }
90
iso_disconnected(struct bt_iso_chan * chan,uint8_t reason)91 static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
92 {
93 LOG_INF("ISO Channel %p disconnected (reason 0x%02x)", chan, reason);
94
95 UNSET_FLAG(flag_iso_connected);
96 }
97
broadcast_scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)98 static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad)
99 {
100 if (IS_FLAG_SET(flag_broadcaster_found)) {
101 /* no-op*/
102 return;
103 }
104
105 LOG_INF("Broadcaster found");
106
107 if (info->interval != 0U) {
108 memcpy(&broadcaster_info, info, sizeof(broadcaster_info));
109 bt_addr_le_copy(&broadcaster_addr, info->addr);
110 SET_FLAG(flag_broadcaster_found);
111 }
112 }
113
pa_synced_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)114 static void pa_synced_cb(struct bt_le_per_adv_sync *sync,
115 struct bt_le_per_adv_sync_synced_info *info)
116 {
117 LOG_INF("PA synced");
118
119 SET_FLAG(flag_pa_synced);
120 }
121
pa_term_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)122 static void pa_term_cb(struct bt_le_per_adv_sync *sync,
123 const struct bt_le_per_adv_sync_term_info *info)
124 {
125 LOG_INF("PA terminated");
126
127 UNSET_FLAG(flag_pa_synced);
128 }
129
pa_biginfo_cb(struct bt_le_per_adv_sync * sync,const struct bt_iso_biginfo * biginfo)130 static void pa_biginfo_cb(struct bt_le_per_adv_sync *sync, const struct bt_iso_biginfo *biginfo)
131 {
132 if (IS_FLAG_SET(flag_biginfo)) {
133 /* no-op*/
134 return;
135 }
136
137 LOG_INF("BIGInfo received");
138
139 broadcaster_num_bis = biginfo->num_bis;
140 SET_FLAG(flag_biginfo);
141 }
142
init(void)143 static void init(void)
144 {
145 static struct bt_le_per_adv_sync_cb pa_sync_cbs = {
146 .biginfo = pa_biginfo_cb,
147 .synced = pa_synced_cb,
148 .term = pa_term_cb,
149 };
150 static struct bt_le_scan_cb bap_scan_cb = {
151 .recv = broadcast_scan_recv,
152 };
153 static struct bt_iso_chan_io_qos iso_rx = {
154 .sdu = CONFIG_BT_ISO_TX_MTU,
155 };
156 static struct bt_iso_chan_ops iso_ops = {
157 .recv = iso_recv,
158 .connected = iso_connected,
159 .disconnected = iso_disconnected,
160 };
161 static struct bt_iso_chan_qos iso_qos = {
162 .rx = &iso_rx,
163 };
164 int err;
165
166 err = bt_enable(NULL);
167 TEST_ASSERT(err == 0, "Bluetooth enable failed (err %d)", err);
168
169 for (size_t i = 0U; i < ARRAY_SIZE(iso_chans); i++) {
170 iso_chans[i].ops = &iso_ops;
171 iso_chans[i].qos = &iso_qos;
172 }
173
174 bt_le_per_adv_sync_cb_register(&pa_sync_cbs);
175 bt_le_scan_cb_register(&bap_scan_cb);
176
177 bk_sync_init();
178 }
179
interval_to_sync_timeout(uint16_t pa_interval)180 static uint16_t interval_to_sync_timeout(uint16_t pa_interval)
181 {
182 uint32_t interval_us;
183 uint32_t timeout;
184
185 /* Add retries and convert to unit in 10's of ms */
186 interval_us = BT_GAP_PER_ADV_INTERVAL_TO_US(pa_interval);
187 timeout =
188 BT_GAP_US_TO_PER_ADV_SYNC_TIMEOUT(interval_us) * PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO;
189
190 /* Enforce restraints */
191 timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT);
192
193 return timeout;
194 }
195
scan_and_sync_pa(struct bt_le_per_adv_sync ** out_sync)196 static void scan_and_sync_pa(struct bt_le_per_adv_sync **out_sync)
197 {
198 struct bt_le_per_adv_sync_param create_params = {0};
199 int err;
200
201 LOG_INF("Starting scan");
202 err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
203 TEST_ASSERT(err == 0, "Failed to start scan: %d", err);
204
205 WAIT_FOR_FLAG(flag_broadcaster_found);
206
207 bt_addr_le_copy(&create_params.addr, &broadcaster_addr);
208 create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE;
209 create_params.sid = broadcaster_info.sid;
210 create_params.skip = 0U;
211 create_params.timeout = interval_to_sync_timeout(broadcaster_info.interval);
212
213 LOG_INF("Creating PA sync");
214 err = bt_le_per_adv_sync_create(&create_params, out_sync);
215 TEST_ASSERT(err == 0, "Failed to sync to PA: %d", err);
216
217 WAIT_FOR_FLAG(flag_pa_synced);
218
219 LOG_INF("Stopping scan");
220 err = bt_le_scan_stop();
221 TEST_ASSERT(err == 0, "Failed to stop scan: %d", err);
222 }
223
sync_big(struct bt_le_per_adv_sync * sync,uint8_t cnt,struct bt_iso_big ** out_big)224 static void sync_big(struct bt_le_per_adv_sync *sync, uint8_t cnt, struct bt_iso_big **out_big)
225 {
226 struct bt_iso_chan *bis_channels[CONFIG_BT_ISO_MAX_CHAN];
227 struct bt_iso_big_sync_param param = {
228 .sync_timeout = interval_to_sync_timeout(broadcaster_info.interval),
229 .bis_bitfield = BIT_MASK(cnt),
230 .bis_channels = bis_channels,
231 .mse = BT_ISO_SYNC_MSE_MIN,
232 .encryption = false,
233 .num_bis = cnt,
234 };
235 int err;
236
237 TEST_ASSERT(cnt <= ARRAY_SIZE(bis_channels));
238 for (size_t i = 0U; i < cnt; i++) {
239 bis_channels[i] = &iso_chans[i];
240 }
241
242 LOG_INF("Creating BIG sync");
243 err = bt_iso_big_sync(sync, ¶m, out_big);
244 TEST_ASSERT(err == 0, "Failed to create BIG sync: %d");
245
246 WAIT_FOR_FLAG(flag_iso_connected);
247 }
248
test_main(void)249 static void test_main(void)
250 {
251 struct bt_le_per_adv_sync *sync;
252 struct bt_iso_big *big;
253
254 init();
255 scan_and_sync_pa(&sync);
256 WAIT_FOR_FLAG(flag_biginfo);
257 sync_big(sync, MIN(broadcaster_num_bis, CONFIG_BT_ISO_MAX_CHAN), &big);
258
259 LOG_INF("Waiting for data");
260 WAIT_FOR_FLAG(flag_data_received);
261 bk_sync_send();
262
263 LOG_INF("Waiting for sync lost");
264 WAIT_FOR_FLAG_UNSET(flag_iso_connected);
265
266 TEST_PASS("Test passed");
267 }
268
269 static const struct bst_test_instance test_def[] = {
270 {
271 .test_id = "receiver",
272 .test_descr = "receiver",
273 .test_pre_init_f = test_init,
274 .test_tick_f = test_tick,
275 .test_main_f = test_main,
276 },
277 BSTEST_END_MARKER,
278 };
279
test_main_bis_receiver_install(struct bst_test_list * tests)280 struct bst_test_list *test_main_bis_receiver_install(struct bst_test_list *tests)
281 {
282 return bst_add_tests(tests, test_def);
283 }
284