blob: 46bdc9bbe5a22a3c2e78ae3b09b7b1f1b5b7face [file] [log] [blame]
/** @file
* @brief Bluetooth Audio shell
*
*/
/*
* Copyright (c) 2020 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <ctype.h>
#include <zephyr.h>
#include <shell/shell.h>
#include <sys/printk.h>
#include <sys/byteorder.h>
#include <sys/util.h>
#include <bluetooth/hci.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/iso.h>
#include "bt.h"
static void iso_recv(struct bt_iso_chan *chan, struct net_buf *buf)
{
printk("Incoming data channel %p len %u\n", chan, buf->len);
}
static void iso_connected(struct bt_iso_chan *chan)
{
printk("ISO Channel %p connected\n", chan);
}
static void iso_disconnected(struct bt_iso_chan *chan)
{
printk("ISO Channel %p disconnected\n", chan);
}
static struct bt_iso_chan_ops iso_ops = {
.recv = iso_recv,
.connected = iso_connected,
.disconnected = iso_disconnected,
};
static struct bt_iso_chan_qos iso_qos = {
.sca = 0x07,
};
static struct bt_iso_chan iso_chan = {
.ops = &iso_ops,
.qos = &iso_qos,
};
static int iso_accept(struct bt_conn *conn, struct bt_iso_chan **chan)
{
printk("Incoming conn %p\n", conn);
if (iso_chan.conn) {
printk("No channels available\n");
return -ENOMEM;
}
*chan = &iso_chan;
return 0;
}
struct bt_iso_server iso_server = {
.sec_level = BT_SECURITY_L1,
.accept = iso_accept,
};
static int cmd_listen(const struct shell *shell, size_t argc, char *argv[])
{
int err;
if (argc > 1) {
iso_server.sec_level = *argv[1] - '0';
}
err = bt_iso_server_register(&iso_server);
if (err) {
shell_error(shell, "Unable to register ISO cap (err %d)",
err);
}
return err;
}
static int cmd_bind(const struct shell *shell, size_t argc, char *argv[])
{
struct bt_conn *conns[1];
struct bt_iso_chan *chans[1];
int err;
if (!default_conn) {
shell_error(shell, "Not connected");
return 0;
}
if (iso_chan.conn) {
shell_error(shell, "Already bound");
return 0;
}
conns[0] = default_conn;
chans[0] = &iso_chan;
if (argc > 1) {
chans[0]->qos->dir = strtol(argv[1], NULL, 0);
}
if (argc > 2) {
chans[0]->qos->interval = strtol(argv[2], NULL, 0);
}
if (argc > 3) {
chans[0]->qos->packing = strtol(argv[3], NULL, 0);
}
if (argc > 4) {
chans[0]->qos->framing = strtol(argv[4], NULL, 0);
}
if (argc > 5) {
chans[0]->qos->latency = strtol(argv[5], NULL, 0);
}
if (argc > 6) {
chans[0]->qos->sdu = strtol(argv[6], NULL, 0);
}
if (argc > 7) {
chans[0]->qos->phy = strtol(argv[7], NULL, 0);
}
if (argc > 8) {
chans[0]->qos->rtn = strtol(argv[8], NULL, 0);
}
err = bt_iso_chan_bind(conns, 1, chans);
if (err) {
shell_error(shell, "Unable to bind (err %d)", err);
return 0;
}
shell_print(shell, "ISO Channel bound");
return 0;
}
static int cmd_connect(const struct shell *shell, size_t argc, char *argv[])
{
struct bt_iso_chan *chans[1];
int err;
if (!iso_chan.conn) {
shell_error(shell, "Not bound");
return 0;
}
chans[0] = &iso_chan;
err = bt_iso_chan_connect(chans, 1);
if (err) {
shell_error(shell, "Unable to connect (err %d)", err);
return 0;
}
shell_print(shell, "ISO Connect pending...");
return 0;
}
#define DATA_MTU CONFIG_BT_ISO_TX_MTU
NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, DATA_MTU, NULL);
static int cmd_send(const struct shell *shell, size_t argc, char *argv[])
{
static uint8_t buf_data[DATA_MTU] = { [0 ... (DATA_MTU - 1)] = 0xff };
int ret, len, count = 1;
struct net_buf *buf;
if (argc > 1) {
count = strtoul(argv[1], NULL, 10);
}
if (!iso_chan.conn) {
shell_error(shell, "Not bound");
return 0;
}
len = MIN(iso_chan.qos->sdu, DATA_MTU - BT_ISO_CHAN_SEND_RESERVE);
while (count--) {
buf = net_buf_alloc(&tx_pool, K_FOREVER);
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
net_buf_add_mem(buf, buf_data, len);
ret = bt_iso_chan_send(&iso_chan, buf);
if (ret < 0) {
shell_print(shell, "Unable to send: %d", -ret);
net_buf_unref(buf);
return -ENOEXEC;
}
}
shell_print(shell, "ISO sending...");
return 0;
}
static int cmd_disconnect(const struct shell *shell, size_t argc,
char *argv[])
{
int err;
err = bt_iso_chan_disconnect(&iso_chan);
if (err) {
shell_error(shell, "Unable to disconnect (err %d)", err);
return 0;
}
shell_print(shell, "ISO Disconnect pending...");
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(iso_cmds,
SHELL_CMD_ARG(bind, NULL, "[dir] [interval] [packing] [framing] "
"[latency] [sdu] [phy] [rtn]", cmd_bind, 1, 8),
SHELL_CMD_ARG(connect, NULL, "Connect ISO Channel", cmd_connect, 1, 0),
SHELL_CMD_ARG(listen, NULL, "[security level]", cmd_listen, 1, 1),
SHELL_CMD_ARG(send, NULL, "Send to ISO Channel", cmd_send, 1, 0),
SHELL_CMD_ARG(disconnect, NULL, "Disconnect ISO Channel",
cmd_disconnect, 1, 0),
SHELL_SUBCMD_SET_END
);
static int cmd_iso(const struct shell *shell, size_t argc, char **argv)
{
if (argc > 1) {
shell_error(shell, "%s unknown parameter: %s",
argv[0], argv[1]);
} else {
shell_error(shell, "%s Missing subcommand", argv[0]);
}
return -ENOEXEC;
}
SHELL_CMD_ARG_REGISTER(iso, &iso_cmds, "Bluetooth ISO shell commands",
cmd_iso, 1, 1);