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