1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <zephyr/console/console.h>
10 #include <zephyr/bluetooth/bluetooth.h>
11 #include <zephyr/bluetooth/iso.h>
12 #include <zephyr/sys/byteorder.h>
13 
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(iso_broadcast_broadcaster, LOG_LEVEL_DBG);
16 
17 #define DEFAULT_BIS_RTN         2
18 #define DEFAULT_BIS_INTERVAL_US 7500
19 #define DEFAULT_BIS_LATENCY_MS  10
20 #define DEFAULT_BIS_PHY         BT_GAP_LE_PHY_2M
21 #define DEFAULT_BIS_SDU         CONFIG_BT_ISO_TX_MTU
22 #define DEFAULT_BIS_PACKING     0
23 #define DEFAULT_BIS_FRAMING     0
24 #define DEFAULT_BIS_COUNT       CONFIG_BT_ISO_MAX_CHAN
25 
26 NET_BUF_POOL_FIXED_DEFINE(bis_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT,
27 			  BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
28 			  CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
29 
30 static K_SEM_DEFINE(sem_big_complete, 0, 1);
31 static K_SEM_DEFINE(sem_big_term, 0, 1);
32 static struct k_work_delayable iso_send_work;
33 static uint32_t iso_send_count;
34 static uint8_t iso_data[CONFIG_BT_ISO_TX_MTU];
35 static uint8_t connected_bis;
36 
37 static struct bt_iso_chan bis_iso_chans[CONFIG_BT_ISO_MAX_CHAN];
38 static struct bt_iso_chan *bis[CONFIG_BT_ISO_MAX_CHAN];
39 /* We use a single seq_num for all the BIS as they share the same SDU interval */
40 static uint16_t seq_num;
41 static struct bt_iso_big_create_param big_create_param = {
42 	.num_bis = DEFAULT_BIS_COUNT,
43 	.bis_channels = bis,
44 	.packing = DEFAULT_BIS_PACKING, /* 0 - sequential, 1 - interleaved */
45 	.framing = DEFAULT_BIS_FRAMING, /* 0 - unframed, 1 - framed */
46 	.interval = DEFAULT_BIS_INTERVAL_US, /* in microseconds */
47 	.latency = DEFAULT_BIS_LATENCY_MS, /* milliseconds */
48 };
49 
iso_connected(struct bt_iso_chan * chan)50 static void iso_connected(struct bt_iso_chan *chan)
51 {
52 	LOG_INF("ISO Channel %p connected", chan);
53 
54 	connected_bis++;
55 	if (connected_bis == big_create_param.num_bis) {
56 		seq_num = 0U;
57 		k_sem_give(&sem_big_complete);
58 	}
59 }
60 
iso_disconnected(struct bt_iso_chan * chan,uint8_t reason)61 static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
62 {
63 	LOG_INF("ISO Channel %p disconnected with reason 0x%02x",
64 	       chan, reason);
65 
66 	connected_bis--;
67 	if (connected_bis == big_create_param.num_bis) {
68 		k_sem_give(&sem_big_term);
69 	}
70 }
71 
72 static struct bt_iso_chan_ops iso_ops = {
73 	.connected	= iso_connected,
74 	.disconnected	= iso_disconnected,
75 };
76 
77 static struct bt_iso_chan_io_qos iso_tx_qos = {
78 	.sdu = DEFAULT_BIS_SDU, /* bytes */
79 	.rtn = DEFAULT_BIS_RTN,
80 	.phy = DEFAULT_BIS_PHY,
81 };
82 
83 static struct bt_iso_chan_qos bis_iso_qos = {
84 	.tx = &iso_tx_qos,
85 };
86 
get_chars(char * buffer,size_t max_size)87 static size_t get_chars(char *buffer, size_t max_size)
88 {
89 	size_t pos = 0;
90 
91 	while (pos < max_size) {
92 		char c = tolower(console_getchar());
93 
94 		if (c == '\n' || c == '\r') {
95 			break;
96 		}
97 		printk("%c", c);
98 		buffer[pos++] = c;
99 	}
100 	printk("\n");
101 	buffer[pos] = '\0';
102 
103 	return pos;
104 }
105 
parse_rtn_arg(void)106 static int parse_rtn_arg(void)
107 {
108 	char buffer[4];
109 	size_t char_count;
110 	uint64_t rtn;
111 
112 	printk("Set RTN (current %u, default %u)\n",
113 	       iso_tx_qos.rtn, DEFAULT_BIS_RTN);
114 
115 	char_count = get_chars(buffer, sizeof(buffer) - 1);
116 	if (char_count == 0) {
117 		return DEFAULT_BIS_RTN;
118 	}
119 
120 	rtn = strtoul(buffer, NULL, 0);
121 	if (rtn > BT_ISO_BROADCAST_RTN_MAX) {
122 		printk("Invalid RTN %llu", rtn);
123 		return -EINVAL;
124 	}
125 
126 	return (int)rtn;
127 }
128 
parse_interval_arg(void)129 static int parse_interval_arg(void)
130 {
131 	char buffer[9];
132 	size_t char_count;
133 	uint64_t interval;
134 
135 	printk("Set interval (us) (current %u, default %u)\n",
136 	       big_create_param.interval, DEFAULT_BIS_INTERVAL_US);
137 
138 	char_count = get_chars(buffer, sizeof(buffer) - 1);
139 	if (char_count == 0) {
140 		return DEFAULT_BIS_INTERVAL_US;
141 	}
142 
143 	interval = strtoul(buffer, NULL, 0);
144 	if (interval < BT_ISO_SDU_INTERVAL_MIN || interval > BT_ISO_SDU_INTERVAL_MAX) {
145 		printk("Invalid interval %llu", interval);
146 		return -EINVAL;
147 	}
148 
149 	return (int)interval;
150 }
151 
parse_latency_arg(void)152 static int parse_latency_arg(void)
153 {
154 	char buffer[6];
155 	size_t char_count;
156 	uint64_t latency;
157 
158 	printk("Set latency (ms) (current %u, default %u)\n",
159 	       big_create_param.latency, DEFAULT_BIS_LATENCY_MS);
160 
161 	char_count = get_chars(buffer, sizeof(buffer) - 1);
162 	if (char_count == 0) {
163 		return DEFAULT_BIS_LATENCY_MS;
164 	}
165 
166 	latency = strtoul(buffer, NULL, 0);
167 	if (latency < BT_ISO_LATENCY_MIN || latency > BT_ISO_LATENCY_MAX) {
168 		printk("Invalid latency %llu", latency);
169 		return -EINVAL;
170 	}
171 
172 	return (int)latency;
173 }
174 
parse_phy_arg(void)175 static int parse_phy_arg(void)
176 {
177 	char buffer[3];
178 	size_t char_count;
179 	uint64_t phy;
180 
181 	printk("Set PHY (current %u, default %u) - %u = 1M, %u = 2M, %u = Coded\n",
182 	       iso_tx_qos.phy, DEFAULT_BIS_PHY, BT_GAP_LE_PHY_1M,
183 	       BT_GAP_LE_PHY_2M, BT_GAP_LE_PHY_CODED);
184 
185 	char_count = get_chars(buffer, sizeof(buffer) - 1);
186 	if (char_count == 0) {
187 		return DEFAULT_BIS_PHY;
188 	}
189 
190 	phy = strtoul(buffer, NULL, 0);
191 	if (phy != BT_GAP_LE_PHY_1M &&
192 	    phy != BT_GAP_LE_PHY_2M &&
193 	    phy != BT_GAP_LE_PHY_CODED) {
194 		printk("Invalid PHY %llu", phy);
195 		return -EINVAL;
196 	}
197 
198 	return (int)phy;
199 }
200 
parse_sdu_arg(void)201 static int parse_sdu_arg(void)
202 {
203 	char buffer[6];
204 	size_t char_count;
205 	uint64_t sdu;
206 
207 	printk("Set SDU (current %u, default %u)\n",
208 	       iso_tx_qos.sdu, DEFAULT_BIS_SDU);
209 
210 	char_count = get_chars(buffer, sizeof(buffer) - 1);
211 	if (char_count == 0) {
212 		return DEFAULT_BIS_SDU;
213 	}
214 
215 	sdu = strtoul(buffer, NULL, 0);
216 	if (sdu > MIN(BT_ISO_MAX_SDU, sizeof(iso_data))) {
217 		printk("Invalid SDU %llu", sdu);
218 		return -EINVAL;
219 	}
220 
221 	return (int)sdu;
222 }
223 
parse_packing_arg(void)224 static int parse_packing_arg(void)
225 {
226 	char buffer[3];
227 	size_t char_count;
228 	uint64_t packing;
229 
230 	printk("Set packing (current %u, default %u)\n",
231 	       big_create_param.packing, DEFAULT_BIS_PACKING);
232 
233 	char_count = get_chars(buffer, sizeof(buffer) - 1);
234 	if (char_count == 0) {
235 		return DEFAULT_BIS_PACKING;
236 	}
237 
238 	packing = strtoul(buffer, NULL, 0);
239 	if (packing != BT_ISO_PACKING_SEQUENTIAL &&
240 	    packing != BT_ISO_PACKING_INTERLEAVED) {
241 		printk("Invalid packing %llu", packing);
242 		return -EINVAL;
243 	}
244 
245 	return (int)packing;
246 }
247 
parse_framing_arg(void)248 static int parse_framing_arg(void)
249 {
250 	char buffer[3];
251 	size_t char_count;
252 	uint64_t framing;
253 
254 	printk("Set framing (current %u, default %u)\n",
255 	       big_create_param.framing, DEFAULT_BIS_FRAMING);
256 
257 	char_count = get_chars(buffer, sizeof(buffer) - 1);
258 	if (char_count == 0) {
259 		return DEFAULT_BIS_FRAMING;
260 	}
261 
262 	framing = strtoul(buffer, NULL, 0);
263 	if (framing != BT_ISO_FRAMING_UNFRAMED &&
264 	    framing != BT_ISO_FRAMING_FRAMED) {
265 		printk("Invalid framing %llu", framing);
266 		return -EINVAL;
267 	}
268 
269 	return (int)framing;
270 }
271 
parse_bis_count_arg(void)272 static int parse_bis_count_arg(void)
273 {
274 	char buffer[4];
275 	size_t char_count;
276 	uint64_t bis_count;
277 
278 	printk("Set BIS count (current %u, default %u)\n",
279 	       big_create_param.num_bis, DEFAULT_BIS_COUNT);
280 
281 	char_count = get_chars(buffer, sizeof(buffer) - 1);
282 	if (char_count == 0) {
283 		return DEFAULT_BIS_COUNT;
284 	}
285 
286 	bis_count = strtoul(buffer, NULL, 0);
287 	if (bis_count > MAX(BT_ISO_MAX_GROUP_ISO_COUNT, CONFIG_BT_ISO_MAX_CHAN)) {
288 		printk("Invalid BIS count %llu", bis_count);
289 		return -EINVAL;
290 	}
291 
292 	return (int)bis_count;
293 }
294 
parse_args(void)295 static int parse_args(void)
296 {
297 	int rtn;
298 	int interval;
299 	int latency;
300 	int phy;
301 	int sdu;
302 	int packing;
303 	int framing;
304 	int bis_count;
305 
306 	printk("Follow the prompts. Press enter to use default values.\n");
307 
308 	rtn = parse_rtn_arg();
309 	if (rtn < 0) {
310 		return -EINVAL;
311 	}
312 
313 	interval = parse_interval_arg();
314 	if (interval < 0) {
315 		return -EINVAL;
316 	}
317 
318 	latency = parse_latency_arg();
319 	if (latency < 0) {
320 		return -EINVAL;
321 	}
322 
323 	phy = parse_phy_arg();
324 	if (phy < 0) {
325 		return -EINVAL;
326 	}
327 
328 	sdu = parse_sdu_arg();
329 	if (sdu < 0) {
330 		return -EINVAL;
331 	}
332 
333 	packing = parse_packing_arg();
334 	if (packing < 0) {
335 		return -EINVAL;
336 	}
337 
338 	framing = parse_framing_arg();
339 	if (framing < 0) {
340 		return -EINVAL;
341 	}
342 
343 	bis_count = parse_bis_count_arg();
344 	if (bis_count < 0) {
345 		return -EINVAL;
346 	}
347 
348 	iso_tx_qos.rtn = rtn;
349 	iso_tx_qos.phy = phy;
350 	iso_tx_qos.sdu = sdu;
351 	big_create_param.interval = interval;
352 	big_create_param.latency = latency;
353 	big_create_param.packing = packing;
354 	big_create_param.framing = framing;
355 	big_create_param.num_bis = bis_count;
356 
357 	return 0;
358 }
359 
iso_timer_timeout(struct k_work * work)360 static void iso_timer_timeout(struct k_work *work)
361 {
362 	int ret;
363 	struct net_buf *buf;
364 
365 	/* Reschedule as early as possible to reduce time skewing
366 	 * Use the ISO interval minus a few microseconds to keep the buffer
367 	 * full. This might occasionally skip a transmit, i.e. where the host
368 	 * calls `bt_iso_chan_send` but the controller only sending a single
369 	 * ISO packet.
370 	 */
371 	k_work_reschedule(&iso_send_work, K_USEC(big_create_param.interval - 100));
372 
373 	for (int i = 0; i < big_create_param.num_bis; i++) {
374 		buf = net_buf_alloc(&bis_tx_pool, K_FOREVER);
375 		if (buf == NULL) {
376 			LOG_ERR("Could not allocate buffer");
377 			return;
378 		}
379 
380 		net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
381 		net_buf_add_mem(buf, iso_data, iso_tx_qos.sdu);
382 		ret = bt_iso_chan_send(&bis_iso_chans[i], buf, seq_num,
383 				       BT_ISO_TIMESTAMP_NONE);
384 		if (ret < 0) {
385 			LOG_ERR("Unable to broadcast data: %d", ret);
386 			net_buf_unref(buf);
387 			return;
388 		}
389 		iso_send_count++;
390 
391 		if ((iso_send_count % 100) == 0) {
392 			LOG_INF("Sent %u packets", iso_send_count);
393 		}
394 	}
395 
396 	seq_num++;
397 }
398 
create_big(struct bt_le_ext_adv ** adv,struct bt_iso_big ** big)399 static int create_big(struct bt_le_ext_adv **adv, struct bt_iso_big **big)
400 {
401 	int err;
402 
403 	/* Create a non-connectable non-scannable advertising set */
404 	LOG_INF("Creating Extended Advertising set");
405 	err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv);
406 	if (err != 0) {
407 		LOG_ERR("Failed to create advertising set (err %d)", err);
408 		return err;
409 	}
410 
411 	LOG_INF("Setting Periodic Advertising parameters");
412 	/* Set periodic advertising parameters */
413 	err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT);
414 	if (err != 0) {
415 		LOG_ERR("Failed to set periodic advertising parameters (err %d)",
416 			err);
417 		return err;
418 	}
419 
420 	/* Enable Periodic Advertising */
421 	LOG_INF("Starting Periodic Advertising");
422 	err = bt_le_per_adv_start(*adv);
423 	if (err != 0) {
424 		LOG_ERR("Failed to enable periodic advertising (err %d)", err);
425 		return err;
426 	}
427 
428 	/* Start extended advertising */
429 	LOG_INF("Starting Extended Advertising set");
430 	err = bt_le_ext_adv_start(*adv, BT_LE_EXT_ADV_START_DEFAULT);
431 	if (err != 0) {
432 		LOG_ERR("Failed to start extended advertising (err %d)", err);
433 		return err;
434 	}
435 
436 	/* Prepare BIG */
437 	for (int i = 0; i < ARRAY_SIZE(bis_iso_chans); i++) {
438 		bis_iso_chans[i].ops = &iso_ops;
439 		bis_iso_chans[i].qos = &bis_iso_qos;
440 		bis[i] = &bis_iso_chans[i];
441 	}
442 
443 	/* Create BIG */
444 	LOG_INF("Creating BIG");
445 	err = bt_iso_big_create(*adv, &big_create_param, big);
446 	if (err != 0) {
447 		LOG_ERR("Failed to create BIG (err %d)", err);
448 		return err;
449 	}
450 
451 	LOG_INF("Waiting for BIG complete");
452 	err = k_sem_take(&sem_big_complete, K_FOREVER);
453 	if (err != 0) {
454 		LOG_ERR("failed to take sem_big_complete (err %d)", err);
455 		return err;
456 	}
457 	LOG_INF("BIG created");
458 
459 	return 0;
460 }
461 
delete_big(struct bt_le_ext_adv ** adv,struct bt_iso_big ** big)462 static int delete_big(struct bt_le_ext_adv **adv, struct bt_iso_big **big)
463 {
464 	int err;
465 
466 	err = bt_iso_big_terminate(*big);
467 	if (err != 0) {
468 		LOG_ERR("Failed to terminate BIG (err %d)", err);
469 		return err;
470 	}
471 	*big = NULL;
472 
473 	err = bt_le_per_adv_stop(*adv);
474 	if (err != 0) {
475 		LOG_ERR("Failed to stop periodic advertising (err %d)", err);
476 		return err;
477 	}
478 
479 	err = bt_le_ext_adv_stop(*adv);
480 	if (err != 0) {
481 		LOG_ERR("Failed to stop advertising (err %d)", err);
482 		return err;
483 	}
484 
485 	err = bt_le_ext_adv_delete(*adv);
486 	if (err != 0) {
487 		LOG_ERR("Failed to delete advertiser (err %d)", err);
488 		return err;
489 	}
490 
491 	*adv = NULL;
492 
493 	return 0;
494 }
495 
reset_sems(void)496 static void reset_sems(void)
497 {
498 	(void)k_sem_reset(&sem_big_complete);
499 	(void)k_sem_reset(&sem_big_term);
500 }
501 
test_run_broadcaster(void)502 int test_run_broadcaster(void)
503 {
504 	struct bt_le_ext_adv *adv;
505 	struct bt_iso_big *big;
506 	int err;
507 	char c;
508 	static bool data_initialized;
509 
510 	reset_sems();
511 
512 	printk("Change settings (y/N)? (Current settings: rtn=%u, interval=%u, "
513 	       "latency=%u, phy=%u, sdu=%u, packing=%u, framing=%u, "
514 	       "bis_count=%u)\n", iso_tx_qos.rtn, big_create_param.interval,
515 	       big_create_param.latency, iso_tx_qos.phy, iso_tx_qos.sdu,
516 	       big_create_param.packing, big_create_param.framing,
517 	       big_create_param.num_bis);
518 
519 	c = tolower(console_getchar());
520 	if (c == 'y') {
521 		err = parse_args();
522 		if (err != 0) {
523 			LOG_ERR("Could not parse args: %d", err);
524 			return err;
525 		}
526 
527 		printk("New settings: rtn=%u, interval=%u, latency=%u, "
528 		       "phy=%u, sdu=%u, packing=%u, framing=%u, bis_count=%u\n",
529 		       iso_tx_qos.rtn, big_create_param.interval,
530 		       big_create_param.latency, iso_tx_qos.phy, iso_tx_qos.sdu,
531 		       big_create_param.packing, big_create_param.framing,
532 		       big_create_param.num_bis);
533 	}
534 
535 	err = create_big(&adv, &big);
536 	if (err) {
537 		LOG_ERR("Could not create BIG: %d", err);
538 		return err;
539 	}
540 
541 	iso_send_count = 0;
542 
543 	if (!data_initialized) {
544 		/* Init data */
545 		for (int i = 0; i < iso_tx_qos.sdu; i++) {
546 			iso_data[i] = (uint8_t)i;
547 		}
548 
549 		data_initialized = true;
550 	}
551 
552 	k_work_init_delayable(&iso_send_work, iso_timer_timeout);
553 	k_work_schedule(&iso_send_work, K_MSEC(0));
554 
555 	while (true) {
556 		printk("Press 'q' to end the broadcast\n");
557 		c = tolower(console_getchar());
558 		if (c == 'q') {
559 			break;
560 		}
561 	}
562 
563 	LOG_INF("Ending broadcast");
564 	(void)k_work_cancel_delayable(&iso_send_work);
565 
566 	err = delete_big(&adv, &big);
567 	if (err) {
568 		LOG_ERR("Could not delete BIG: %d", err);
569 		return err;
570 	}
571 
572 	return 0;
573 }
574