1 /** @file
2  *  @brief Bluetooth Audio shell
3  *
4  */
5 
6 /*
7  * Copyright (c) 2020 Intel Corporation
8  * Copyright (c) 2021-2025 Nordic Semiconductor ASA
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 #include <errno.h>
13 #include <stddef.h>
14 #include <stdint.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include <zephyr/bluetooth/gap.h>
19 #include <zephyr/bluetooth/hci.h>
20 #include <zephyr/bluetooth/bluetooth.h>
21 #include <zephyr/bluetooth/conn.h>
22 #include <zephyr/bluetooth/hci_types.h>
23 #include <zephyr/bluetooth/iso.h>
24 #include <zephyr/kernel.h>
25 #include <zephyr/net_buf.h>
26 #include <zephyr/shell/shell.h>
27 #include <zephyr/shell/shell_string_conv.h>
28 #include <zephyr/sys/byteorder.h>
29 #include <zephyr/sys/time_units.h>
30 #include <zephyr/sys/util.h>
31 #include <zephyr/sys/util_macro.h>
32 
33 #include "host/shell/bt.h"
34 #include "common/bt_shell_private.h"
35 
36 #if defined(CONFIG_BT_ISO_TX)
37 #define DEFAULT_IO_QOS                                                                             \
38 	{                                                                                          \
39 		.sdu = 40u, .phy = BT_GAP_LE_PHY_2M, .rtn = 2u,                                    \
40 	}
41 
42 #define TX_BUF_TIMEOUT K_SECONDS(1)
43 
44 static struct bt_iso_chan_io_qos iso_tx_qos = DEFAULT_IO_QOS;
45 static uint32_t cis_sn_last;
46 static uint32_t bis_sn_last;
47 static int64_t cis_sn_last_updated_ticks;
48 static int64_t bis_sn_last_updated_ticks;
49 
50 /**
51  * @brief Get the next sequence number based on the last used values
52  *
53  * @param last_sn     The last sequence number sent.
54  * @param last_ticks  The uptime ticks since the last sequence number increment.
55  * @param interval_us The SDU interval in microseconds.
56  *
57  * @return The next sequence number to use
58  */
get_next_sn(uint32_t last_sn,int64_t * last_ticks,uint32_t interval_us)59 static uint32_t get_next_sn(uint32_t last_sn, int64_t *last_ticks,
60 			    uint32_t interval_us)
61 {
62 	int64_t uptime_ticks, delta_ticks;
63 	uint64_t delta_us;
64 	uint64_t sn_incr;
65 	uint64_t next_sn;
66 
67 	/* Note: This does not handle wrapping of ticks when they go above
68 	 * 2^(62-1)
69 	 */
70 	uptime_ticks = k_uptime_ticks();
71 	delta_ticks = uptime_ticks - *last_ticks;
72 	*last_ticks = uptime_ticks;
73 
74 	delta_us = k_ticks_to_us_near64((uint64_t)delta_ticks);
75 	sn_incr = delta_us / interval_us;
76 	next_sn = (sn_incr + last_sn);
77 
78 	return (uint32_t)next_sn;
79 }
80 #endif /* CONFIG_BT_ISO_TX */
81 
82 #if defined(CONFIG_BT_ISO_RX)
iso_recv(struct bt_iso_chan * chan,const struct bt_iso_recv_info * info,struct net_buf * buf)83 static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *info,
84 		     struct net_buf *buf)
85 {
86 	if (info->flags & BT_ISO_FLAGS_VALID) {
87 		bt_shell_print("Incoming data channel %p len %u, seq: %d, ts: %d",
88 			       chan, buf->len, info->seq_num, info->ts);
89 	}
90 }
91 #endif /* CONFIG_BT_ISO_RX */
92 
iso_connected(struct bt_iso_chan * chan)93 static void iso_connected(struct bt_iso_chan *chan)
94 {
95 	const struct bt_iso_chan_path hci_path = {
96 		.pid = BT_ISO_DATA_PATH_HCI,
97 		.format = BT_HCI_CODING_FORMAT_TRANSPARENT,
98 	};
99 	struct bt_iso_info iso_info;
100 	int err;
101 
102 	bt_shell_print("ISO Channel %p connected", chan);
103 
104 	err = bt_iso_chan_get_info(chan, &iso_info);
105 	if (err != 0) {
106 		bt_shell_error("Failed to get ISO info: %d", err);
107 		return;
108 	}
109 
110 #if defined(CONFIG_BT_ISO_TX)
111 	if (iso_info.type == BT_ISO_CHAN_TYPE_CENTRAL ||
112 	    iso_info.type == BT_ISO_CHAN_TYPE_PERIPHERAL) {
113 		cis_sn_last = 0U;
114 		cis_sn_last_updated_ticks = k_uptime_ticks();
115 	} else {
116 		bis_sn_last = 0U;
117 		bis_sn_last_updated_ticks = k_uptime_ticks();
118 	}
119 #endif /* CONFIG_BT_ISO_TX */
120 
121 	if (iso_info.can_recv) {
122 		err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path);
123 		if (err != 0) {
124 			bt_shell_error("Failed to setup ISO RX data path: %d", err);
125 		}
126 	}
127 
128 	if (iso_info.can_send) {
129 		err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path);
130 		if (err != 0) {
131 			bt_shell_error("Failed to setup ISO TX data path: %d", err);
132 		}
133 	}
134 }
135 
iso_disconnected(struct bt_iso_chan * chan,uint8_t reason)136 static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
137 {
138 	struct bt_iso_info iso_info;
139 	int err;
140 
141 	bt_shell_print("ISO Channel %p disconnected with reason 0x%02x", chan, reason);
142 
143 	err = bt_iso_chan_get_info(chan, &iso_info);
144 	if (err != 0) {
145 		bt_shell_error("Failed to get ISO info: %d", err);
146 	} else if (iso_info.type == BT_ISO_CHAN_TYPE_CENTRAL) {
147 		if (iso_info.can_recv) {
148 			err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST);
149 			if (err != 0) {
150 				bt_shell_error("Failed to remove ISO RX data path: %d", err);
151 			}
152 		}
153 
154 		if (iso_info.can_send) {
155 			err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR);
156 			if (err != 0) {
157 				bt_shell_error("Failed to remove ISO TX data path: %d", err);
158 			}
159 		}
160 	}
161 }
162 
163 static struct bt_iso_chan_ops iso_ops = {
164 #if defined(CONFIG_BT_ISO_RX)
165 	.recv = iso_recv,
166 #endif /* CONFIG_BT_ISO_RX */
167 	.connected = iso_connected,
168 	.disconnected = iso_disconnected,
169 };
170 
171 #if defined(CONFIG_BT_ISO_UNICAST)
172 static uint32_t cis_sdu_interval_us;
173 
174 static struct bt_iso_chan_io_qos iso_rx_qos = DEFAULT_IO_QOS;
175 
176 static struct bt_iso_chan_qos cis_iso_qos = {
177 	.tx = &iso_tx_qos,
178 	.rx = &iso_rx_qos,
179 };
180 
181 #define CIS_ISO_CHAN_COUNT 1
182 
183 struct bt_iso_chan iso_chan = {
184 	.ops = &iso_ops,
185 	.qos = &cis_iso_qos,
186 };
187 
188 NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
189 			  CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
190 
191 #if defined(CONFIG_BT_ISO_CENTRAL)
192 static struct bt_iso_cig *cig;
193 
parse_interval(const struct shell * sh,const char * interval_str)194 static long parse_interval(const struct shell *sh, const char *interval_str)
195 {
196 	unsigned long interval;
197 	int err;
198 
199 	err = 0;
200 	interval = shell_strtoul(interval_str, 0, &err);
201 	if (err != 0) {
202 		shell_error(sh, "Could not parse interval: %d", err);
203 
204 		return -ENOEXEC;
205 	}
206 
207 	if (!IN_RANGE(interval,
208 		      BT_ISO_SDU_INTERVAL_MIN,
209 		      BT_ISO_SDU_INTERVAL_MAX)) {
210 		shell_error(sh, "Invalid interval %lu", interval);
211 
212 		return -ENOEXEC;
213 	}
214 
215 	return interval;
216 }
217 
parse_latency(const struct shell * sh,const char * latency_str)218 static long parse_latency(const struct shell *sh, const char *latency_str)
219 {
220 	unsigned long latency;
221 	int err;
222 
223 	err = 0;
224 	latency = shell_strtoul(latency_str, 0, &err);
225 	if (err != 0) {
226 		shell_error(sh, "Could not parse latency: %d", err);
227 
228 		return -ENOEXEC;
229 	}
230 
231 	if (!IN_RANGE(latency,
232 		      BT_ISO_LATENCY_MIN,
233 		      BT_ISO_LATENCY_MAX)) {
234 		shell_error(sh, "Invalid latency %lu", latency);
235 
236 		return -ENOEXEC;
237 	}
238 
239 	return latency;
240 }
241 
cmd_cig_create(const struct shell * sh,size_t argc,char * argv[])242 static int cmd_cig_create(const struct shell *sh, size_t argc, char *argv[])
243 {
244 	int err;
245 	struct bt_iso_cig_param param = {0};
246 	struct bt_iso_chan *chans[CIS_ISO_CHAN_COUNT];
247 
248 	if (cig != NULL) {
249 		shell_error(sh, "Already created");
250 		return -ENOEXEC;
251 	}
252 
253 	chans[0] = &iso_chan;
254 
255 	if (argc > 1) {
256 		if (!strcmp("tx", argv[1])) {
257 			chans[0]->qos->tx = &iso_tx_qos;
258 			chans[0]->qos->rx = NULL;
259 		} else if (!strcmp("rx", argv[1])) {
260 			chans[0]->qos->tx = NULL;
261 			chans[0]->qos->rx = &iso_rx_qos;
262 		} else if (!strcmp("txrx", argv[1])) {
263 			chans[0]->qos->tx = &iso_tx_qos;
264 			chans[0]->qos->rx = &iso_rx_qos;
265 		}
266 	}
267 
268 	err = 0;
269 	if (argc > 2) {
270 		long interval;
271 
272 		interval = shell_strtoul(argv[2], 0, &err);
273 		interval = parse_interval(sh, argv[2]);
274 		if (interval < 0) {
275 			return interval;
276 		}
277 
278 		param.c_to_p_interval = interval;
279 	} else {
280 		param.c_to_p_interval = 10000;
281 	}
282 
283 	if (argc > 3) {
284 		long interval;
285 
286 		interval = parse_interval(sh, argv[3]);
287 		if (interval < 0) {
288 			return interval;
289 		}
290 
291 		param.p_to_c_interval = interval;
292 	} else {
293 		param.p_to_c_interval = param.c_to_p_interval;
294 	}
295 
296 	/* cis_sdu_interval_us is used to increase the sequence number.
297 	 * cig_create can be called before an ACL is created, so the role
298 	 * information may not be available.
299 	 * Since we are central however we can safely set the cis_sdu_interval
300 	 * to the Central to Peer interval
301 	 */
302 	cis_sdu_interval_us = param.c_to_p_interval;
303 
304 	if (argc > 4) {
305 		unsigned long packing;
306 
307 		packing = shell_strtoul(argv[4], 0, &err);
308 		if (err != 0) {
309 			shell_error(sh, "Could not parse packing: %d", err);
310 
311 			return -ENOEXEC;
312 		}
313 
314 		if (packing != BT_ISO_PACKING_SEQUENTIAL && packing != BT_ISO_PACKING_INTERLEAVED) {
315 			shell_error(sh, "Invalid packing %lu", packing);
316 
317 			return -ENOEXEC;
318 		}
319 
320 		param.packing = packing;
321 	} else {
322 		param.packing = 0;
323 	}
324 
325 	if (argc > 5) {
326 		unsigned long framing;
327 
328 		framing = shell_strtoul(argv[5], 0, &err);
329 		if (err != 0) {
330 			shell_error(sh, "Could not parse framing: %d", err);
331 
332 			return -ENOEXEC;
333 		}
334 
335 		if (framing != BT_ISO_FRAMING_UNFRAMED && framing != BT_ISO_FRAMING_FRAMED) {
336 			shell_error(sh, "Invalid framing %lu", framing);
337 
338 			return -ENOEXEC;
339 		}
340 
341 		param.framing = framing;
342 	} else {
343 		param.framing = 0;
344 	}
345 
346 	if (argc > 6) {
347 		long latency;
348 
349 		latency = parse_latency(sh, argv[6]);
350 
351 		if (latency < 0) {
352 			return latency;
353 		}
354 
355 		param.c_to_p_latency = latency;
356 	} else {
357 		param.c_to_p_latency = 10;
358 	}
359 
360 	if (argc > 7) {
361 		long latency;
362 
363 		latency = parse_latency(sh, argv[7]);
364 
365 		if (latency < 0) {
366 			return latency;
367 		}
368 
369 		param.p_to_c_latency = latency;
370 	} else {
371 		param.p_to_c_latency = param.c_to_p_latency;
372 	}
373 
374 	if (argc > 7) {
375 		unsigned long sdu;
376 
377 		sdu = shell_strtoul(argv[7], 0, &err);
378 		if (err != 0) {
379 			shell_error(sh, "Could not parse sdu: %d", err);
380 
381 			return -ENOEXEC;
382 		}
383 
384 		if (sdu > BT_ISO_MAX_SDU) {
385 			shell_error(sh, "Invalid sdu %lu", sdu);
386 
387 			return -ENOEXEC;
388 		}
389 
390 		if (chans[0]->qos->tx) {
391 			chans[0]->qos->tx->sdu = sdu;
392 		}
393 
394 		if (chans[0]->qos->rx) {
395 			chans[0]->qos->rx->sdu = sdu;
396 		}
397 	}
398 
399 	if (argc > 8) {
400 		unsigned long phy;
401 
402 		phy = shell_strtoul(argv[8], 0, &err);
403 		if (err != 0) {
404 			shell_error(sh, "Could not parse phy: %d", err);
405 
406 			return -ENOEXEC;
407 		}
408 
409 		if (phy != BT_GAP_LE_PHY_1M &&
410 		    phy != BT_GAP_LE_PHY_2M &&
411 		    phy != BT_GAP_LE_PHY_CODED) {
412 			shell_error(sh, "Invalid phy %lu", phy);
413 
414 			return -ENOEXEC;
415 		}
416 
417 		if (chans[0]->qos->tx) {
418 			chans[0]->qos->tx->phy = phy;
419 		}
420 
421 		if (chans[0]->qos->rx) {
422 			chans[0]->qos->rx->phy = phy;
423 		}
424 	}
425 
426 	if (argc > 9) {
427 		unsigned long rtn;
428 
429 		rtn = shell_strtoul(argv[9], 0, &err);
430 		if (err != 0) {
431 			shell_error(sh, "Could not parse rtn: %d", err);
432 
433 			return -ENOEXEC;
434 		}
435 
436 		if (rtn > BT_ISO_CONNECTED_RTN_MAX) {
437 			shell_error(sh, "Invalid rtn %lu", rtn);
438 
439 			return -ENOEXEC;
440 		}
441 
442 		if (chans[0]->qos->tx) {
443 			chans[0]->qos->tx->rtn = rtn;
444 		}
445 
446 		if (chans[0]->qos->rx) {
447 			chans[0]->qos->rx->rtn = rtn;
448 		}
449 	}
450 
451 	param.sca = BT_GAP_SCA_UNKNOWN;
452 	param.cis_channels = chans;
453 	param.num_cis = ARRAY_SIZE(chans);
454 
455 	err = bt_iso_cig_create(&param, &cig);
456 	if (err) {
457 		shell_error(sh, "Unable to create CIG (err %d)", err);
458 		return 0;
459 	}
460 
461 	shell_print(sh, "CIG created");
462 
463 	return 0;
464 }
465 
cmd_cig_term(const struct shell * sh,size_t argc,char * argv[])466 static int cmd_cig_term(const struct shell *sh, size_t argc, char *argv[])
467 {
468 	int err;
469 
470 	if (cig == NULL) {
471 		shell_error(sh, "CIG not created");
472 		return -ENOEXEC;
473 	}
474 
475 	err = bt_iso_cig_terminate(cig);
476 	if (err) {
477 		shell_error(sh, "Unable to terminate CIG (err %d)", err);
478 		return 0;
479 	}
480 
481 	shell_print(sh, "CIG terminated");
482 	cig = NULL;
483 
484 	return 0;
485 }
486 
cmd_connect(const struct shell * sh,size_t argc,char * argv[])487 static int cmd_connect(const struct shell *sh, size_t argc, char *argv[])
488 {
489 	struct bt_iso_connect_param connect_param = {
490 		.acl = default_conn,
491 		.iso_chan = &iso_chan
492 	};
493 	int err;
494 
495 	if (iso_chan.iso == NULL) {
496 		shell_error(sh, "ISO channel not initialized in a CIG");
497 		return 0;
498 	}
499 
500 #if defined(CONFIG_BT_SMP)
501 	if (argc > 1) {
502 		iso_chan.required_sec_level = *argv[1] - '0';
503 	}
504 #endif /* CONFIG_BT_SMP */
505 
506 	err = bt_iso_chan_connect(&connect_param, 1);
507 	if (err) {
508 		shell_error(sh, "Unable to connect (err %d)", err);
509 		return 0;
510 	}
511 
512 	shell_print(sh, "ISO Connect pending...");
513 
514 	return 0;
515 }
516 #endif /* CONFIG_BT_ISO_CENTRAL */
517 
518 #if defined(CONFIG_BT_ISO_PERIPHERAL)
519 
iso_accept(const struct bt_iso_accept_info * info,struct bt_iso_chan ** chan)520 static int iso_accept(const struct bt_iso_accept_info *info,
521 		      struct bt_iso_chan **chan)
522 {
523 	bt_shell_print("Incoming request from %p with CIG ID 0x%02X and CIS ID 0x%02X",
524 		       info->acl, info->cig_id, info->cis_id);
525 
526 	if (iso_chan.iso) {
527 		bt_shell_print("No channels available");
528 		return -ENOMEM;
529 	}
530 
531 	*chan = &iso_chan;
532 
533 	/* As the peripheral host we do not know the SDU interval, and thus we
534 	 * cannot find the proper interval of incrementing the packet
535 	 * sequence number (PSN). The only way to ensure that we correctly
536 	 * increment the PSN, is by incrementing once per the minimum SDU
537 	 * interval. This should be okay as the spec does not specify how much
538 	 * the PSN may be incremented, and it is thus OK for us to increment
539 	 * it faster than the SDU interval.
540 	 */
541 	cis_sdu_interval_us = BT_ISO_SDU_INTERVAL_MIN;
542 
543 	return 0;
544 }
545 
546 struct bt_iso_server iso_server = {
547 #if defined(CONFIG_BT_SMP)
548 	.sec_level = BT_SECURITY_L1,
549 #endif /* CONFIG_BT_SMP */
550 	.accept = iso_accept,
551 };
552 
cmd_listen(const struct shell * sh,size_t argc,char * argv[])553 static int cmd_listen(const struct shell *sh, size_t argc, char *argv[])
554 {
555 	int err;
556 	static struct bt_iso_chan_io_qos *tx_qos, *rx_qos;
557 
558 	if (!strcmp("tx", argv[1])) {
559 		tx_qos = &iso_tx_qos;
560 		rx_qos = NULL;
561 	} else if (!strcmp("rx", argv[1])) {
562 		tx_qos = NULL;
563 		rx_qos = &iso_rx_qos;
564 	} else if (!strcmp("txrx", argv[1])) {
565 		tx_qos = &iso_tx_qos;
566 		rx_qos = &iso_rx_qos;
567 	} else {
568 		shell_error(sh, "Invalid argument - use tx, rx or txrx");
569 		return -ENOEXEC;
570 	}
571 
572 #if defined(CONFIG_BT_SMP)
573 	if (argc > 2) {
574 		iso_server.sec_level = *argv[2] - '0';
575 	}
576 #endif /* CONFIG_BT_SMP */
577 
578 	err = bt_iso_server_register(&iso_server);
579 	if (err) {
580 		shell_error(sh, "Unable to register ISO cap (err %d)", err);
581 		return err;
582 	}
583 
584 	/* Setup peripheral iso data direction only if register is success */
585 	iso_chan.qos->tx = tx_qos;
586 	iso_chan.qos->rx = rx_qos;
587 	return err;
588 }
589 #endif /* CONFIG_BT_ISO_PERIPHERAL */
590 
cmd_send(const struct shell * sh,size_t argc,char * argv[])591 static int cmd_send(const struct shell *sh, size_t argc, char *argv[])
592 {
593 	static uint8_t buf_data[CONFIG_BT_ISO_TX_MTU] = {
594 		[0 ... (CONFIG_BT_ISO_TX_MTU - 1)] = 0xff
595 	};
596 	unsigned long count = 1;
597 	struct net_buf *buf;
598 	int ret = 0;
599 	int len;
600 
601 	if (argc > 1) {
602 		count = shell_strtoul(argv[1], 0, &ret);
603 		if (ret != 0) {
604 			shell_error(sh, "Could not parse count: %d", ret);
605 
606 			return -ENOEXEC;
607 		}
608 
609 		if (count < 1) {
610 			shell_error(sh, "Cannot send 0 times");
611 
612 			return -ENOEXEC;
613 		}
614 	}
615 
616 	if (!iso_chan.iso) {
617 		shell_error(sh, "Not bound");
618 		return 0;
619 	}
620 
621 	if (!iso_chan.qos->tx) {
622 		shell_error(sh, "Transmission QoS disabled");
623 		return -ENOEXEC;
624 	}
625 
626 	len = MIN(iso_chan.qos->tx->sdu, CONFIG_BT_ISO_TX_MTU);
627 	cis_sn_last = get_next_sn(cis_sn_last, &cis_sn_last_updated_ticks,
628 				  cis_sdu_interval_us);
629 
630 	while (count--) {
631 		buf = net_buf_alloc(&tx_pool, TX_BUF_TIMEOUT);
632 		if (buf == NULL) {
633 			shell_error(sh, "Failed to get buffer...");
634 			return -ENOEXEC;
635 		}
636 
637 		net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
638 
639 		net_buf_add_mem(buf, buf_data, len);
640 		shell_info(sh, "send: %d bytes of data with PSN %u", len, cis_sn_last);
641 		ret = bt_iso_chan_send(&iso_chan, buf, cis_sn_last);
642 		if (ret < 0) {
643 			shell_print(sh, "Unable to send: %d", -ret);
644 			net_buf_unref(buf);
645 			return -ENOEXEC;
646 		}
647 	}
648 
649 	shell_print(sh, "ISO sending...");
650 
651 	return 0;
652 }
653 
cmd_disconnect(const struct shell * sh,size_t argc,char * argv[])654 static int cmd_disconnect(const struct shell *sh, size_t argc,
655 			  char *argv[])
656 {
657 	int err;
658 
659 	err = bt_iso_chan_disconnect(&iso_chan);
660 	if (err) {
661 		shell_error(sh, "Unable to disconnect (err %d)", err);
662 		return 0;
663 	}
664 
665 	shell_print(sh, "ISO Disconnect pending...");
666 
667 	return 0;
668 }
669 
cmd_tx_sync_read_cis(const struct shell * sh,size_t argc,char * argv[])670 static int cmd_tx_sync_read_cis(const struct shell *sh, size_t argc, char *argv[])
671 {
672 	struct bt_iso_tx_info tx_info;
673 	int err;
674 
675 	if (!iso_chan.iso) {
676 		shell_error(sh, "Not bound");
677 		return 0;
678 	}
679 
680 	err = bt_iso_chan_get_tx_sync(&iso_chan, &tx_info);
681 	if (err) {
682 		shell_error(sh, "Unable to read sync info (err %d)", err);
683 		return 0;
684 	}
685 
686 	shell_print(sh, "TX sync info:\n\tTimestamp=%u\n\tOffset=%u\n\tSequence number=%u",
687 		    tx_info.ts, tx_info.offset, tx_info.seq_num);
688 
689 	return 0;
690 }
691 #endif /* CONFIG_BT_ISO_UNICAST */
692 
693 #if defined(CONFIG_BT_ISO_BROADCAST)
694 #define BIS_ISO_CHAN_COUNT 1
695 static struct bt_iso_big *big;
696 
697 static struct bt_iso_chan_qos bis_iso_qos;
698 
699 static struct bt_iso_chan bis_iso_chan = {
700 	.ops = &iso_ops,
701 	.qos = &bis_iso_qos,
702 };
703 
704 static struct bt_iso_chan *bis_channels[BIS_ISO_CHAN_COUNT] = { &bis_iso_chan };
705 
706 #if defined(CONFIG_BT_ISO_BROADCASTER)
707 static uint32_t bis_sdu_interval_us;
708 
709 NET_BUF_POOL_FIXED_DEFINE(bis_tx_pool, BIS_ISO_CHAN_COUNT,
710 			  BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
711 			  CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
712 
cmd_broadcast(const struct shell * sh,size_t argc,char * argv[])713 static int cmd_broadcast(const struct shell *sh, size_t argc, char *argv[])
714 {
715 	static uint8_t buf_data[CONFIG_BT_ISO_TX_MTU] = {
716 		[0 ... (CONFIG_BT_ISO_TX_MTU - 1)] = 0xff
717 	};
718 	unsigned long count = 1;
719 	struct net_buf *buf;
720 	int ret = 0;
721 	int len;
722 
723 	if (argc > 1) {
724 		count = shell_strtoul(argv[1], 0, &ret);
725 		if (ret != 0) {
726 			shell_error(sh, "Could not parse count: %d", ret);
727 
728 			return -ENOEXEC;
729 		}
730 
731 		if (count < 1) {
732 			shell_error(sh, "Cannot send 0 times");
733 
734 			return -ENOEXEC;
735 		}
736 	}
737 
738 	if (!bis_iso_chan.iso) {
739 		shell_error(sh, "BIG not created");
740 		return -ENOEXEC;
741 	}
742 
743 	if (!bis_iso_qos.tx) {
744 		shell_error(sh, "BIG not setup as broadcaster");
745 		return -ENOEXEC;
746 	}
747 
748 	len = MIN(bis_iso_chan.qos->tx->sdu, CONFIG_BT_ISO_TX_MTU);
749 	bis_sn_last = get_next_sn(bis_sn_last, &bis_sn_last_updated_ticks,
750 				  bis_sdu_interval_us);
751 
752 	while (count--) {
753 		buf = net_buf_alloc(&bis_tx_pool, TX_BUF_TIMEOUT);
754 		if (buf == NULL) {
755 			shell_error(sh, "Failed to get buffer...");
756 			return -ENOEXEC;
757 		}
758 
759 		net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
760 
761 		net_buf_add_mem(buf, buf_data, len);
762 		shell_info(sh, "send: %d bytes of data with PSN %u", len, bis_sn_last);
763 		ret = bt_iso_chan_send(&bis_iso_chan, buf, bis_sn_last);
764 		if (ret < 0) {
765 			shell_print(sh, "Unable to broadcast: %d", -ret);
766 			net_buf_unref(buf);
767 			return -ENOEXEC;
768 		}
769 	}
770 
771 	shell_print(sh, "ISO broadcasting...");
772 
773 	return 0;
774 }
775 
cmd_big_create(const struct shell * sh,size_t argc,char * argv[])776 static int cmd_big_create(const struct shell *sh, size_t argc, char *argv[])
777 {
778 	int err;
779 	struct bt_iso_big_create_param param = {0};
780 	struct bt_le_ext_adv *adv = adv_sets[selected_adv];
781 
782 	if (!adv) {
783 		shell_error(sh, "No (periodic) advertising set selected");
784 		return -ENOEXEC;
785 	}
786 
787 	/* TODO: Allow setting QOS from shell */
788 	bis_iso_qos.tx = &iso_tx_qos;
789 	bis_iso_qos.tx->phy = BT_GAP_LE_PHY_2M; /* 2 MBit */
790 	bis_iso_qos.tx->rtn = 2;
791 	bis_iso_qos.tx->sdu = CONFIG_BT_ISO_TX_MTU;
792 
793 	bis_sdu_interval_us = param.interval = 10000;      /* us */
794 	param.latency = 20;          /* ms */
795 	param.bis_channels = bis_channels;
796 	param.num_bis = BIS_ISO_CHAN_COUNT;
797 	param.encryption = false;
798 	param.packing = BT_ISO_PACKING_SEQUENTIAL;
799 	param.framing = BT_ISO_FRAMING_UNFRAMED;
800 
801 	if (argc > 1) {
802 		if (!strcmp(argv[1], "enc")) {
803 			uint8_t bcode_len = hex2bin(argv[1], strlen(argv[1]), param.bcode,
804 						    sizeof(param.bcode));
805 			if (!bcode_len || bcode_len != sizeof(param.bcode)) {
806 				shell_error(sh, "Invalid Broadcast Code Length");
807 				return -ENOEXEC;
808 			}
809 			param.encryption = true;
810 		} else {
811 			shell_help(sh);
812 			return SHELL_CMD_HELP_PRINTED;
813 		}
814 	} else {
815 		memset(param.bcode, 0, sizeof(param.bcode));
816 	}
817 
818 	err = bt_iso_big_create(adv, &param, &big);
819 	if (err) {
820 		shell_error(sh, "Unable to create BIG (err %d)", err);
821 		return 0;
822 	}
823 
824 	shell_print(sh, "BIG created");
825 
826 	return 0;
827 }
828 
cmd_tx_sync_read_bis(const struct shell * sh,size_t argc,char * argv[])829 static int cmd_tx_sync_read_bis(const struct shell *sh, size_t argc, char *argv[])
830 {
831 	struct bt_iso_tx_info tx_info;
832 	int err;
833 
834 	if (!bis_iso_chan.iso) {
835 		shell_error(sh, "BIG not created");
836 		return -ENOEXEC;
837 	}
838 
839 	err = bt_iso_chan_get_tx_sync(&bis_iso_chan, &tx_info);
840 	if (err) {
841 		shell_error(sh, "Unable to read sync info (err %d)", err);
842 		return 0;
843 	}
844 
845 	shell_print(sh, "TX sync info:\n\tTimestamp=%u\n\tOffset=%u\n\tSequence number=%u",
846 		    tx_info.ts, tx_info.offset, tx_info.seq_num);
847 
848 	return 0;
849 }
850 #endif /* CONFIG_BT_ISO_BROADCASTER */
851 
852 #if defined(CONFIG_BT_ISO_SYNC_RECEIVER)
cmd_big_sync(const struct shell * sh,size_t argc,char * argv[])853 static int cmd_big_sync(const struct shell *sh, size_t argc, char *argv[])
854 {
855 	int err;
856 	/* TODO: Add support to select which PA sync to BIG sync to */
857 	struct bt_le_per_adv_sync *pa_sync = per_adv_syncs[0];
858 	struct bt_iso_big_sync_param param;
859 	unsigned long bis_bitfield;
860 
861 	if (!pa_sync) {
862 		shell_error(sh, "No PA sync selected");
863 		return -ENOEXEC;
864 	}
865 
866 	err = 0;
867 	bis_bitfield = shell_strtoul(argv[1], 0, &err);
868 	if (err != 0) {
869 		shell_error(sh, "Could not parse bis_bitfield: %d", err);
870 
871 		return -ENOEXEC;
872 	}
873 
874 	if (bis_bitfield == 0U || bis_bitfield > BIT_MASK(BT_ISO_BIS_INDEX_MAX)) {
875 		shell_error(sh, "Invalid bis_bitfield: %lu", bis_bitfield);
876 
877 		return -ENOEXEC;
878 	}
879 
880 	bis_iso_qos.tx = NULL;
881 	bis_iso_qos.rx = &iso_rx_qos;
882 
883 	param.bis_channels = bis_channels;
884 	param.num_bis = BIS_ISO_CHAN_COUNT;
885 	param.encryption = false;
886 	param.bis_bitfield = bis_bitfield;
887 	param.mse = 0;
888 	param.sync_timeout = 0xFF;
889 
890 	for (size_t i = 2U; i < argc; i++) {
891 		if (!strcmp(argv[i], "mse")) {
892 			unsigned long mse;
893 
894 			i++;
895 			if (i == argc) {
896 				shell_help(sh);
897 				return SHELL_CMD_HELP_PRINTED;
898 			}
899 
900 			mse = shell_strtoul(argv[i], 0, &err);
901 			if (err != 0) {
902 				shell_error(sh, "Could not parse mse: %d", err);
903 
904 				return -ENOEXEC;
905 			}
906 
907 			if (mse != BT_ISO_SYNC_MSE_ANY &&
908 			    !IN_RANGE(mse, BT_ISO_SYNC_MSE_MIN, BT_ISO_SYNC_MSE_MAX)) {
909 				shell_error(sh, "Invalid mse %lu", mse);
910 
911 				return -ENOEXEC;
912 			}
913 
914 			param.mse = mse;
915 		} else if (!strcmp(argv[i], "timeout")) {
916 			unsigned long sync_timeout;
917 
918 			i++;
919 			if (i == argc) {
920 				shell_help(sh);
921 				return SHELL_CMD_HELP_PRINTED;
922 			}
923 
924 			sync_timeout = shell_strtoul(argv[i], 0, &err);
925 			if (err != 0) {
926 				shell_error(sh, "Could not parse sync_timeout: %d", err);
927 
928 				return -ENOEXEC;
929 			}
930 
931 			if (!IN_RANGE(sync_timeout,
932 				      BT_ISO_SYNC_TIMEOUT_MIN,
933 				      BT_ISO_SYNC_TIMEOUT_MAX)) {
934 				shell_error(sh, "Invalid sync_timeout %lu", sync_timeout);
935 
936 				return -ENOEXEC;
937 			}
938 
939 			param.sync_timeout = sync_timeout;
940 		} else if (!strcmp(argv[i], "enc")) {
941 			size_t bcode_len;
942 
943 			i++;
944 			if (i == argc) {
945 				shell_help(sh);
946 				return SHELL_CMD_HELP_PRINTED;
947 			}
948 
949 			memset(param.bcode, 0, sizeof(param.bcode));
950 			bcode_len = hex2bin(argv[i], strlen(argv[i]), param.bcode,
951 					    sizeof(param.bcode));
952 
953 			if (bcode_len == 0) {
954 				shell_error(sh, "Invalid Broadcast Code");
955 
956 				return -ENOEXEC;
957 			}
958 
959 			param.encryption = true;
960 		} else {
961 			shell_help(sh);
962 			return SHELL_CMD_HELP_PRINTED;
963 		}
964 	}
965 
966 	err = bt_iso_big_sync(pa_sync, &param, &big);
967 	if (err) {
968 		shell_error(sh, "Unable to sync to BIG (err %d)", err);
969 		return 0;
970 	}
971 
972 	shell_print(sh, "BIG syncing");
973 
974 	return 0;
975 }
976 #endif /* CONFIG_BT_ISO_SYNC_RECEIVER */
977 
cmd_big_term(const struct shell * sh,size_t argc,char * argv[])978 static int cmd_big_term(const struct shell *sh, size_t argc, char *argv[])
979 {
980 	int err;
981 
982 	err = bt_iso_big_terminate(big);
983 	if (err) {
984 		shell_error(sh, "Unable to terminate BIG (err %d)", err);
985 		return 0;
986 	}
987 
988 	shell_print(sh, "BIG terminated");
989 
990 	return 0;
991 }
992 #endif /* CONFIG_BT_ISO_BROADCAST*/
993 
994 SHELL_STATIC_SUBCMD_SET_CREATE(iso_cmds,
995 #if defined(CONFIG_BT_ISO_UNICAST)
996 #if defined(CONFIG_BT_ISO_CENTRAL)
997 	SHELL_CMD_ARG(cig_create, NULL,
998 		      "[dir=tx,rx,txrx] [C to P interval] [P to C interval] "
999 		      "[packing] [framing] [C to P latency] [P to C latency] [sdu] [phy] [rtn]",
1000 		      cmd_cig_create, 1, 10),
1001 	SHELL_CMD_ARG(cig_term, NULL, "Terminate the CIG", cmd_cig_term, 1, 0),
1002 #if defined(CONFIG_BT_SMP)
1003 	SHELL_CMD_ARG(connect, NULL, "Connect ISO Channel [security level]", cmd_connect, 1, 1),
1004 #else /* !CONFIG_BT_SMP */
1005 	SHELL_CMD_ARG(connect, NULL, "Connect ISO Channel", cmd_connect, 1, 0),
1006 #endif /* CONFIG_BT_SMP */
1007 #endif /* CONFIG_BT_ISO_CENTRAL */
1008 #if defined(CONFIG_BT_ISO_PERIPHERAL)
1009 #if defined(CONFIG_BT_SMP)
1010 	SHELL_CMD_ARG(listen, NULL, "<dir=tx,rx,txrx> [security level]", cmd_listen, 2, 1),
1011 #else /* !CONFIG_BT_SMP */
1012 	SHELL_CMD_ARG(listen, NULL, "<dir=tx,rx,txrx>", cmd_listen, 2, 0),
1013 #endif /* CONFIG_BT_SMP */
1014 #endif /* CONFIG_BT_ISO_PERIPHERAL */
1015 #if defined(CONFIG_BT_ISO_TX)
1016 	SHELL_CMD_ARG(send, NULL, "Send to ISO Channel [count]", cmd_send, 1, 1),
1017 #endif /* CONFIG_BT_ISO_TX */
1018 	SHELL_CMD_ARG(disconnect, NULL, "Disconnect ISO Channel", cmd_disconnect, 1, 0),
1019 	SHELL_CMD_ARG(tx_sync_read_cis, NULL, "Read CIS TX sync info", cmd_tx_sync_read_cis, 1, 0),
1020 #endif /* CONFIG_BT_ISO_UNICAST */
1021 #if defined(CONFIG_BT_ISO_BROADCASTER)
1022 	SHELL_CMD_ARG(create-big, NULL, "Create a BIG as a broadcaster [enc <broadcast code>]",
1023 		      cmd_big_create, 1, 2),
1024 	SHELL_CMD_ARG(broadcast, NULL, "Broadcast on ISO channels", cmd_broadcast, 1, 1),
1025 	SHELL_CMD_ARG(tx_sync_read_bis, NULL, "Read BIS TX sync info", cmd_tx_sync_read_bis, 1, 0),
1026 #endif /* CONFIG_BT_ISO_BROADCASTER */
1027 #if defined(CONFIG_BT_ISO_SYNC_RECEIVER)
1028 	SHELL_CMD_ARG(sync-big, NULL,
1029 		      "Synchronize to a BIG as a receiver <BIS bitfield> [mse] "
1030 		      "[timeout] [enc <broadcast code>]",
1031 		      cmd_big_sync, 2, 4),
1032 #endif /* CONFIG_BT_ISO_SYNC_RECEIVER */
1033 #if defined(CONFIG_BT_ISO_BROADCAST)
1034 	SHELL_CMD_ARG(term-big, NULL, "Terminate a BIG", cmd_big_term, 1, 0),
1035 #endif /* CONFIG_BT_ISO_BROADCAST */
1036 	SHELL_SUBCMD_SET_END
1037 );
1038 
cmd_iso(const struct shell * sh,size_t argc,char ** argv)1039 static int cmd_iso(const struct shell *sh, size_t argc, char **argv)
1040 {
1041 	if (argc == 1) {
1042 		shell_help(sh);
1043 
1044 		return SHELL_CMD_HELP_PRINTED;
1045 	}
1046 
1047 	shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
1048 
1049 	return -EINVAL;
1050 }
1051 
1052 SHELL_CMD_ARG_REGISTER(iso, &iso_cmds, "Bluetooth ISO shell commands",
1053 		       cmd_iso, 1, 1);
1054