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(¶m, &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, ¶m, &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, ¶m, &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