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, &param, 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