Commit 9d0fb5ec authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Anas Nashif
Browse files

Bluetooth: ISO: Remove channel direction



Channel direction was actually a source of confusion since the spec does
actually define the data path direction from controller point of view
meaning input actually means transmit and output receive, also direction
can be configured with different QoS settings.

To make these APIs less confusing and allow QoS to be configured
independently they are now split into RX (receiving) and TX
(transmission) settings including its data path.

Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent 0eb4bfee
Loading
Loading
Loading
Loading
+26 −25
Original line number Diff line number Diff line
@@ -60,31 +60,33 @@ struct bt_iso_chan {
	struct bt_iso_chan_ops		*ops;
	/** Channel QoS reference */
	struct bt_iso_chan_qos		*qos;
	/** Channel data path reference*/
	struct bt_iso_chan_path		*path;
	sys_snode_t			node;
	uint8_t				state;
	bt_security_t			required_sec_level;
};

/** @brief Audio QoS direction */
enum {
	BT_ISO_CHAN_QOS_IN,
	BT_ISO_CHAN_QOS_OUT,
	BT_ISO_CHAN_QOS_INOUT
/** @brief ISO Channel IO QoS structure. */
struct bt_iso_chan_io_qos {
	/** Channel interval in us. Value range 0x0000FF - 0x0FFFFFF. */
	uint32_t			interval;
	/** Channel Latency in ms. Value range 0x0005 - 0x0FA0. */
	uint16_t			latency;
	/** Channel SDU. Value range 0x0000 - 0x0FFF. */
	uint16_t			sdu;
	/** Channel PHY - See BT_GAP_LE_PHY for values.
	 *  Setting BT_GAP_LE_PHY_NONE is invalid.
	 */
	uint8_t				phy;
	/** Channel Retransmission Number. Value range 0x00 - 0x0F. */
	uint8_t				rtn;
	/** Channel data path reference.
	 *  Setting to NULL default to HCI data path.
	 */
	struct bt_iso_chan_path		*path;
};

/** @brief ISO Channel QoS structure. */
struct bt_iso_chan_qos {
	/** @brief Channel direction
	 *
	 *  Possible values: BT_ISO_CHAN_QOS_IN, BT_ISO_CHAN_QOS_OUT or
	 *  BT_ISO_CHAN_QOS_INOUT. Shall be BT_ISO_CHAN_QOS_IN for broadcast
	 *  transmitting, and BT_ISO_CHAN_QOS_OUT for broadcast receiver.
	 */
	uint8_t				dir;
	/** Channel interval in us. Value range 0x0000FF - 0x0FFFFFF. */
	uint32_t			interval;
	/** @brief Channel peripherals sleep clock accuracy Only for CIS
	 *
	 * Shall be worst case sleep clock accuracy of all the peripherals.
@@ -95,14 +97,14 @@ struct bt_iso_chan_qos {
	uint8_t				packing;
	/** Channel framing mode. 0 for unframed, 1 for framed. */
	uint8_t				framing;
	/** Channel Latency in ms. Value range 0x0005 - 0x0FA0. */
	uint16_t			latency;
	/** Channel SDU. Value range 0x0000 0 0x0FFF. */
	uint8_t				sdu;
	/** Channel PHY - See BT_GAP_LE_PHY for values. Shall not be BT_GAP_LE_PHY_NONE. */
	uint8_t				phy;
	/** Channel Retransmission Number. Value range 0x00 - 0x0F. */
	uint8_t				rtn;
	/** Channel Receiving QoS:
	 *  Setting NULL disables data path BT_HCI_DATAPATH_DIR_CTLR_TO_HOST
	 */
	struct bt_iso_chan_io_qos	*rx;
	/** Channel Transmission QoS:
	 *  Setting NULL disables data path BT_HCI_DATAPATH_DIR_HOST_TO_CTRL
	 */
	struct bt_iso_chan_io_qos	*tx;
};

/** @brief ISO Channel Data Path structure. */
@@ -123,7 +125,6 @@ struct bt_iso_chan_path {
	uint8_t				cc[0];
};


/** Opaque type representing an Broadcast Isochronous Group (BIG). */
struct bt_iso_big;

+41 −43
Original line number Diff line number Diff line
@@ -395,40 +395,48 @@ static struct net_buf *hci_le_set_cig_params(struct bt_iso_create_param *param)
	memset(req, 0, sizeof(*req));

	req->cig_id = param->conns[0]->iso.cig_id;
	sys_put_le24(param->chans[0]->qos->interval, req->m_interval);
	sys_put_le24(param->chans[0]->qos->interval, req->s_interval);
	sys_put_le24(param->chans[0]->qos->tx->interval, req->m_interval);
	sys_put_le24(param->chans[0]->qos->rx->interval, req->s_interval);
	req->sca = param->chans[0]->qos->sca;
	req->packing = param->chans[0]->qos->packing;
	req->framing = param->chans[0]->qos->framing;
	req->m_latency = sys_cpu_to_le16(param->chans[0]->qos->latency);
	req->s_latency = sys_cpu_to_le16(param->chans[0]->qos->latency);
	req->m_latency = sys_cpu_to_le16(param->chans[0]->qos->tx->latency);
	req->s_latency = sys_cpu_to_le16(param->chans[0]->qos->rx->latency);
	req->num_cis = param->num_conns;

	/* Program the cis parameters */
	for (i = 0; i < param->num_conns; i++) {
		struct bt_iso_chan_qos *qos = param->chans[i]->qos;

		cis = net_buf_add(buf, sizeof(*cis));

		memset(cis, 0, sizeof(*cis));

		cis->cis_id = param->conns[i]->iso.cis_id;

		switch (param->chans[i]->qos->dir) {
		case BT_ISO_CHAN_QOS_IN:
			cis->s_sdu = param->chans[i]->qos->sdu;
			break;
		case BT_ISO_CHAN_QOS_OUT:
			cis->m_sdu = param->chans[i]->qos->sdu;
			break;
		case BT_ISO_CHAN_QOS_INOUT:
			cis->m_sdu = param->chans[i]->qos->sdu;
			cis->s_sdu = param->chans[i]->qos->sdu;
			break;
		if (!qos->tx && !qos->rx) {
			BT_ERR("Both TX and RX QoS are disabled");
			net_buf_unref(buf);
			return NULL;
		}

		cis->m_phy = param->chans[i]->qos->phy;
		cis->s_phy = param->chans[i]->qos->phy;
		cis->m_rtn = param->chans[i]->qos->rtn;
		cis->s_rtn = param->chans[i]->qos->rtn;
		if (!qos->tx) {
			/* Use RX PHY if TX is not set (disabled) */
			cis->m_phy = qos->rx->phy;
		} else {
			cis->m_sdu = sys_cpu_to_le16(qos->tx->sdu);
			cis->m_phy = qos->tx->phy;
			cis->m_rtn = qos->tx->rtn;
		}

		if (!qos->rx) {
			/* Use TX PHY if RX is not set (disabled) */
			cis->s_phy = qos->tx->phy;
		} else {
			cis->s_sdu = sys_cpu_to_le16(qos->rx->sdu);
			cis->s_phy = qos->rx->phy;
			cis->s_rtn = qos->rx->rtn;
		}
	}

	err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_CIG_PARAMS, buf, &rsp);
@@ -702,24 +710,15 @@ static int bt_iso_setup_data_path(struct bt_conn *conn)
		return -EINVAL;
	}

	in_path.path = chan->path ? chan->path : &path;
	out_path.path = chan->path ? chan->path : &path;
	in_path.path = chan->qos->tx->path ? chan->qos->tx->path : &path;
	out_path.path = chan->qos->rx->path ? chan->qos->rx->path : &path;

	switch (chan->qos->dir) {
	case BT_ISO_CHAN_QOS_IN:
		in_path.pid = in_path.path->pid;
		out_path.pid = BT_ISO_DATA_PATH_DISABLED;
		break;
	case BT_ISO_CHAN_QOS_OUT:
	if (!chan->qos->tx) {
		in_path.pid = BT_ISO_DATA_PATH_DISABLED;
		out_path.pid = out_path.path->pid;
		break;
	case BT_ISO_CHAN_QOS_INOUT:
		in_path.pid = in_path.path->pid;
		out_path.pid = out_path.path->pid;
		break;
	default:
		return -EINVAL;
	}

	if (!chan->qos->rx) {
		out_path.pid = BT_ISO_DATA_PATH_DISABLED;
	}

	err = hci_le_setup_iso_data_path(conn, &in_path);
@@ -1242,8 +1241,7 @@ static int big_init_bis(struct bt_iso_big *big, bool broadcaster)
			return -EALREADY;
		}

		if (!bis->qos ||
		    bis->qos->dir != (broadcaster ? BT_ISO_CHAN_QOS_IN : BT_ISO_CHAN_QOS_OUT)) {
		if (!bis->qos || (!bis->qos->tx && broadcaster)) {
			BT_DBG("BIS QOS was invalid");
			return -EINVAL;
		}
@@ -1286,11 +1284,11 @@ static int hci_le_create_big(struct bt_le_ext_adv *padv, struct bt_iso_big *big,
	req->big_handle = big->handle;
	req->adv_handle = padv->handle;
	req->num_bis = big->num_bis;
	sys_put_le24(qos->interval, req->sdu_interval);
	req->max_sdu = sys_cpu_to_le16(qos->sdu);
	req->max_latency = sys_cpu_to_le16(qos->latency);
	req->rtn = qos->rtn;
	req->phy = qos->phy;
	sys_put_le24(qos->tx->interval, req->sdu_interval);
	req->max_sdu = sys_cpu_to_le16(qos->tx->sdu);
	req->max_latency = sys_cpu_to_le16(qos->tx->latency);
	req->rtn = qos->tx->rtn;
	req->phy = qos->tx->phy;
	req->packing = qos->packing;
	req->framing = qos->framing;
	req->encryption = param->encryption;
@@ -1428,7 +1426,7 @@ int bt_iso_big_terminate(struct bt_iso_big *big)
	}

	/* They all have the same QOS dir so we can just check the first */
	broadcaster = big->bis[0]->qos->dir == BT_ISO_CHAN_QOS_IN;
	broadcaster = big->bis[0]->qos->tx ? true : false;

	if (broadcaster) {
		err = hci_le_terminate_big(big);
+76 −22
Original line number Diff line number Diff line
@@ -45,8 +45,22 @@ static struct bt_iso_chan_ops iso_ops = {
	.disconnected	= iso_disconnected,
};

#define DEFAULT_IO_QOS \
{ \
	.interval	= 10000u, \
	.latency	= 10u, \
	.sdu		= 40u, \
	.phy		= BT_GAP_LE_PHY_2M, \
	.rtn		= 2u, \
}

static struct bt_iso_chan_io_qos iso_tx_qos = DEFAULT_IO_QOS;
static struct bt_iso_chan_io_qos iso_rx_qos = DEFAULT_IO_QOS;

static struct bt_iso_chan_qos iso_qos = {
	.sca		= BT_GAP_SCA_UNKNOWN,
	.tx		= &iso_tx_qos,
	.rx		= &iso_rx_qos,
};

struct bt_iso_chan iso_chan = {
@@ -110,11 +124,26 @@ static int cmd_bind(const struct shell *shell, size_t argc, char *argv[])
	chans[0] = &iso_chan;

	if (argc > 1) {
		chans[0]->qos->dir = strtol(argv[1], NULL, 0);
		if (!strcmp("tx", argv[2])) {
			chans[0]->qos->tx = &iso_tx_qos;
			chans[0]->qos->rx = NULL;
		} else if (!strcmp("rx", argv[2])) {
			chans[0]->qos->tx = NULL;
			chans[0]->qos->rx = &iso_rx_qos;
		} else if (!strcmp("txrx", argv[2])) {
			chans[0]->qos->tx = &iso_tx_qos;
			chans[0]->qos->rx = &iso_rx_qos;
		}
	}

	if (argc > 2) {
		chans[0]->qos->interval = strtol(argv[2], NULL, 0);
		if (chans[0]->qos->tx) {
			chans[0]->qos->tx->interval = strtol(argv[2], NULL, 0);
		}

		if (chans[0]->qos->rx) {
			chans[0]->qos->rx->interval = strtol(argv[2], NULL, 0);
		}
	}

	if (argc > 3) {
@@ -126,19 +155,43 @@ static int cmd_bind(const struct shell *shell, size_t argc, char *argv[])
	}

	if (argc > 5) {
		chans[0]->qos->latency = strtol(argv[5], NULL, 0);
		if (chans[0]->qos->tx) {
			chans[0]->qos->tx->latency = strtol(argv[5], NULL, 0);
		}

		if (chans[0]->qos->rx) {
			chans[0]->qos->rx->latency = strtol(argv[5], NULL, 0);
		}
	}

	if (argc > 6) {
		chans[0]->qos->sdu = strtol(argv[6], NULL, 0);
		if (chans[0]->qos->tx) {
			chans[0]->qos->tx->sdu = strtol(argv[6], NULL, 0);
		}

		if (chans[0]->qos->rx) {
			chans[0]->qos->rx->sdu = strtol(argv[6], NULL, 0);
		}
	}

	if (argc > 7) {
		chans[0]->qos->phy = strtol(argv[7], NULL, 0);
		if (chans[0]->qos->tx) {
			chans[0]->qos->tx->phy = strtol(argv[7], NULL, 0);
		}

		if (chans[0]->qos->rx) {
			chans[0]->qos->rx->phy = strtol(argv[7], NULL, 0);
		}
	}

	if (argc > 8) {
		chans[0]->qos->rtn = strtol(argv[8], NULL, 0);
		if (chans[0]->qos->tx) {
			chans[0]->qos->tx->rtn = strtol(argv[8], NULL, 0);
		}

		if (chans[0]->qos->rx) {
			chans[0]->qos->rx->rtn = strtol(argv[8], NULL, 0);
		}
	}

	err = bt_iso_chan_bind(conns, 1, chans);
@@ -193,7 +246,12 @@ static int cmd_send(const struct shell *shell, size_t argc, char *argv[])
		return 0;
	}

	len = MIN(iso_chan.qos->sdu, DATA_MTU - BT_ISO_CHAN_SEND_RESERVE);
	if (!iso_chan.qos->tx) {
		shell_error(shell, "Transmission QoS disabled");
		return -ENOEXEC;
	}

	len = MIN(iso_chan.qos->tx->sdu, DATA_MTU - BT_ISO_CHAN_SEND_RESERVE);

	while (count--) {
		buf = net_buf_alloc(&tx_pool, K_FOREVER);
@@ -260,12 +318,12 @@ static int cmd_broadcast(const struct shell *shell, size_t argc, char *argv[])
		return -ENOEXEC;
	}

	if (bis_iso_qos.dir != BT_ISO_CHAN_QOS_IN) {
	if (!bis_iso_qos.tx) {
		shell_error(shell, "BIG not setup as broadcaster");
		return -ENOEXEC;
	}

	len = MIN(iso_chan.qos->sdu, DATA_MTU - BT_ISO_CHAN_SEND_RESERVE);
	len = MIN(iso_chan.qos->tx->sdu, DATA_MTU - BT_ISO_CHAN_SEND_RESERVE);

	while (count--) {
		for (int i = 0; i < BIS_ISO_CHAN_COUNT; i++) {
@@ -292,20 +350,19 @@ static int cmd_big_create(const struct shell *shell, size_t argc, char *argv[])
	int err;
	struct bt_iso_big_create_param param;
	struct bt_le_ext_adv *adv = adv_sets[selected_adv];
	uint8_t original_dir = bis_iso_qos.dir;

	if (!adv) {
		shell_error(shell, "No (periodic) advertising set selected");
		return -ENOEXEC;
	}

	bis_iso_qos.dir = BT_ISO_CHAN_QOS_IN;
	/* TODO: Allow setting QOS from shell */
	bis_iso_qos.interval = 10000;      /* us */
	bis_iso_qos.latency = 20;          /* ms */
	bis_iso_qos.phy = BT_GAP_LE_PHY_2M; /* 2 MBit */
	bis_iso_qos.rtn = 2;
	bis_iso_qos.sdu = CONFIG_BT_ISO_TX_MTU;
	bis_iso_qos.tx = &iso_tx_qos;
	bis_iso_qos.tx->interval = 10000;      /* us */
	bis_iso_qos.tx->latency = 20;          /* ms */
	bis_iso_qos.tx->phy = BT_GAP_LE_PHY_2M; /* 2 MBit */
	bis_iso_qos.tx->rtn = 2;
	bis_iso_qos.tx->sdu = CONFIG_BT_ISO_TX_MTU;

	param.bis_channels = bis_channels;
	param.num_bis = BIS_ISO_CHAN_COUNT;
@@ -328,7 +385,6 @@ static int cmd_big_create(const struct shell *shell, size_t argc, char *argv[])

	err = bt_iso_big_create(adv, &param, &big);
	if (err) {
		bis_iso_qos.dir = original_dir;
		shell_error(shell, "Unable to create BIG (err %d)", err);
		return 0;
	}
@@ -344,14 +400,13 @@ static int cmd_big_sync(const struct shell *shell, size_t argc, char *argv[])
	/* TODO: Add support to select which PA sync to BIG sync to */
	struct bt_le_per_adv_sync *pa_sync = per_adv_syncs[0];
	struct bt_iso_big_sync_param param;
	uint8_t original_dir = bis_iso_qos.dir;

	if (!pa_sync) {
		shell_error(shell, "No PA sync selected");
		return -ENOEXEC;
	}

	bis_iso_qos.dir = BT_ISO_CHAN_QOS_OUT;
	bis_iso_qos.tx = NULL;

	param.bis_channels = bis_channels;
	param.num_bis = BIS_ISO_CHAN_COUNT;
@@ -390,7 +445,6 @@ static int cmd_big_sync(const struct shell *shell, size_t argc, char *argv[])

	err = bt_iso_big_sync(pa_sync, &param, &big);
	if (err) {
		bis_iso_qos.dir = original_dir;
		shell_error(shell, "Unable to sync to BIG (err %d)", err);
		return 0;
	}
@@ -417,7 +471,7 @@ static int cmd_big_term(const struct shell *shell, size_t argc, char *argv[])
#endif /* CONFIG_BT_ISO_BROADCAST */

SHELL_STATIC_SUBCMD_SET_CREATE(iso_cmds,
	SHELL_CMD_ARG(bind, NULL, "[dir] [interval] [packing] [framing] "
	SHELL_CMD_ARG(bind, NULL, "[dir=tx,rx,txrx] [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),