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