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