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