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