Skip to content

Commit

Permalink
Bluetooth: ISO: Make setting ISO data explicit
Browse files Browse the repository at this point in the history
The stack will no longer implicitly set the data path
for ISO channel, and the responsibility for doing that is
now for the upper layers/applications.

This provides additional flexibility for the higher layers
as they can better control the values and timing of the data
path, as well as support removing and even reconfiguring the
data path at will.

Finally this also removes some complexity from the stack.

Signed-off-by: Emil Gydesen <[email protected]>
  • Loading branch information
Thalley committed Jul 7, 2024
1 parent a912bb6 commit 21ab23c
Show file tree
Hide file tree
Showing 23 changed files with 695 additions and 288 deletions.
118 changes: 97 additions & 21 deletions include/zephyr/bluetooth/iso.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

/*
* Copyright (c) 2020 Intel Corporation
* Copyright (c) 2021 Nordic Semiconductor ASA
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -48,7 +48,14 @@ extern "C" {

/** Value to set the ISO data path over HCi. */
#define BT_ISO_DATA_PATH_HCI 0x00

/** The minimum value for vendor specific data path ID */
#define BT_ISO_DATA_PATH_VS_ID_MIN 0x01
/** The maximum value for vendor specific data path ID */
#define BT_ISO_DATA_PATH_VS_ID_MAX 0xFE
/** Minimum controller delay in microseconds (0 s) */
#define BT_ISO_CONTROLLER_DELAY_MIN 0x000000
/** Maximum controller delay in microseconds (4 s) */
#define BT_ISO_CONTROLLER_DELAY_MAX 0x3D0900
/** Minimum interval value in microseconds */
#define BT_ISO_SDU_INTERVAL_MIN 0x0000FFU
/** Maximum interval value in microseconds */
Expand Down Expand Up @@ -188,13 +195,7 @@ struct bt_iso_chan_io_qos {
*
* This value is ignored if any advanced ISO parameters are set.
*/
uint8_t rtn;
/** @brief Channel data path reference
*
* Setting to NULL default to HCI data path (same as setting path.pid
* to BT_ISO_DATA_PATH_HCI).
*/
struct bt_iso_chan_path *path;
uint8_t rtn;

#if defined(CONFIG_BT_ISO_TEST_PARAMS)
/** @brief Maximum PDU size
Expand Down Expand Up @@ -250,20 +251,37 @@ struct bt_iso_chan_qos {

/** @brief ISO Channel Data Path structure. */
struct bt_iso_chan_path {
/** Default path ID */
uint8_t pid;
/** Coding Format */
uint8_t format;
/**
* @brief Default path ID
*
* @ref BT_ISO_DATA_PATH_HCI for HCI or between @ref BT_ISO_DATA_PATH_VS_ID_MIN and @ref
* BT_ISO_DATA_PATH_VS_ID_MAX for vendor specific data path.
*/
uint8_t pid;
/**
* Coding Format
*
* See the BT_HCI_CODING_FORMAT_* values for valid values.
*/
uint8_t format;
/** Company ID */
uint16_t cid;
uint16_t cid;
/** Vendor-defined Codec ID */
uint16_t vid;
/** Controller Delay */
uint32_t delay;
/** Codec Configuration length*/
uint8_t cc_len;
/** Pointer to an array containing the Codec Configuration */
uint8_t *cc;
uint16_t vid;
/**
* Controller Delay in microseconds
*
* Value range from @ref BT_ISO_CONTROLLER_DELAY_MIN to @ref BT_ISO_CONTROLLER_DELAY_MAX.
*/
uint32_t delay;
/** Codec Configuration length */
uint8_t cc_len;
/**
* @brief Pointer to an array containing the Codec Configuration
*
* Shall not be NULL if bt_iso_chan_path.cc_len is non-zero.
*/
uint8_t *cc;
};

/** ISO packet status flag bits */
Expand Down Expand Up @@ -883,6 +901,64 @@ int bt_iso_chan_send(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq
int bt_iso_chan_send_ts(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num,
uint32_t ts);

/**
* @brief Sets up the ISO data path for a connected ISO channel
*
* @param chan The channel to setup the ISO data path for
* @param dir The direction to setup, either @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST or
* @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR. For ISO broadcast channels this can only be
* @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, and for ISO sync receiver channels this can
* only be @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST.
* @param path The data path
*
* @retval 0 on success
* @retval -EINVAL on invalid parameters
* @retval -ENOBUFS if no HCI command buffer could be allocated
* @retval -EIO if the controller rejected the request or response contains invalid data
* @retval -ENODEV if @p chan is not associated with a CIS or BIS handle
* @retval -ENOEXEC if unexpected error occurred
*/
int bt_iso_setup_data_path(const struct bt_iso_chan *chan, uint8_t dir,
const struct bt_iso_chan_path *path);

/**
* @brief Removes the ISO data path for a connected ISO channel
*
* Removes the ISO data path configured by bt_iso_setup_data_path() for the provided @p dir.
*
* As per Bluetooth Core specification 5.4, Vol 4, Part E, Section 7.7.5, the data paths of CIS for
* peripherals are deleted by the controller, and thus it is not necessary (or possible) to remove
* data paths of CIS after they have disconnected for a peripheral.
* The data paths for CIS for a central remain valid, even after a disconnection, and thus a central
* device should call bt_iso_remove_data_path() on disconnect if it no longer wants to use that CIS.
* All data paths created by a central are removed when the CIG is removed with
* bt_iso_cig_terminate().
*
* As per Bluetooth Core specification 5.4, Vol 4, Part E, Section 7.7.65.30 any data paths
* associated with an ISO Sync Receiver BIG are removed by the controller when the BIG sync is lost
* or terminated, and thus it is not necessary (or possible) to remove data paths of ISO channels
* associated with a BIG for a Sync Receiver.
*
* As per Bluetooth Core specification 5.4, Vol 4, Part E, Section 7.8.105 all data paths associated
* with an ISO Broadcaster BIG are removed when the BIG is terminated by bt_iso_big_terminate(),
* and thus it is not necessary (or possible) to remove data paths of ISO channels
* associated with a BIG for a Broadcaster.
*
* @param chan The channel to setup the ISO data path for
* @param dir The direction to setup, either @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST or
* @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR. For ISO broadcast channels this can only be
* @ref BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, and for ISO sync receiver channels this can
* only be @ref BT_HCI_DATAPATH_DIR_CTLR_TO_HOST.
* @retval 0 on success
* @retval -EINVAL on invalid parameters
* @retval -ENOBUFS if no HCI command buffer could be allocated
* @retval -EIO if the controller rejected the request or response contains invalid data
* @retval -ENODEV if @p chan is not associated with a CIS or BIS handle
* @retval -ENOEXEC if unexpected error occurred
*/
int bt_iso_remove_data_path(const struct bt_iso_chan *chan, uint8_t dir);

/** @brief ISO Unicast TX Info Structure */
struct bt_iso_unicast_tx_info {
/** The transport latency in us */
Expand Down
24 changes: 21 additions & 3 deletions samples/bluetooth/central_iso/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h>
#include <zephyr/settings/settings.h>
#include <zephyr/sys/byteorder.h>
Expand Down Expand Up @@ -139,18 +140,36 @@ static void start_scan(void)

static void iso_connected(struct bt_iso_chan *chan)
{
const struct bt_iso_chan_path hci_path = {
.pid = BT_ISO_DATA_PATH_HCI,
.format = BT_HCI_CODING_FORMAT_TRANSPARENT,
};
int err;

printk("ISO Channel %p connected\n", chan);

seq_num = 0U;

/* Start send timer */
k_work_schedule(&iso_send_work, K_MSEC(0));
err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path);
if (err != 0) {
printk("Failed to setup ISO TX data path: %d\n", err);
} else {
/* Start send timer */
k_work_schedule(&iso_send_work, K_NO_WAIT);
}
}

static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
{
int err;

printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason);
k_work_cancel_delayable(&iso_send_work);

err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR);
if (err != 0) {
printk("Failed to setup ISO TX data path: %d\n", err);
}
}

static struct bt_iso_chan_ops iso_ops = {
Expand All @@ -162,7 +181,6 @@ static struct bt_iso_chan_io_qos iso_tx = {
.sdu = CONFIG_BT_ISO_TX_MTU,
.phy = BT_GAP_LE_PHY_2M,
.rtn = 1,
.path = NULL,
};

static struct bt_iso_chan_qos iso_qos = {
Expand Down
14 changes: 13 additions & 1 deletion samples/bluetooth/iso_broadcast/src/main.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h>
#include <zephyr/sys/byteorder.h>

Expand All @@ -28,10 +29,21 @@ static uint16_t seq_num;

static void iso_connected(struct bt_iso_chan *chan)
{
const struct bt_iso_chan_path hci_path = {
.pid = BT_ISO_DATA_PATH_HCI,
.format = BT_HCI_CODING_FORMAT_TRANSPARENT,
};
int err;

printk("ISO Channel %p connected\n", chan);

seq_num = 0U;

err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path);
if (err != 0) {
printk("Failed to setup ISO TX data path: %d\n", err);
}

k_sem_give(&sem_big_cmplt);
}

Expand Down
14 changes: 13 additions & 1 deletion samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <ctype.h>
#include <stdlib.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/console/console.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/iso.h>
Expand Down Expand Up @@ -66,8 +67,19 @@ static const struct bt_data ad[] = {

static void iso_connected(struct bt_iso_chan *chan)
{
const struct bt_iso_chan_path hci_path = {
.pid = BT_ISO_DATA_PATH_HCI,
.format = BT_HCI_CODING_FORMAT_TRANSPARENT,
};
int err;

LOG_INF("ISO Channel %p connected", chan);

err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path);
if (err != 0) {
printk("Failed to setup ISO TX data path: %d\n", err);
}

connected_bis++;
if (connected_bis == big_create_param.num_bis) {
seq_num = 0U;
Expand Down
14 changes: 13 additions & 1 deletion samples/bluetooth/iso_broadcast_benchmark/src/receiver.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
* Copyright (c) 2021-2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <ctype.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/bluetooth/iso.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/console/console.h>
Expand Down Expand Up @@ -229,10 +230,21 @@ static void iso_recv(struct bt_iso_chan *chan,

static void iso_connected(struct bt_iso_chan *chan)
{
const struct bt_iso_chan_path hci_path = {
.pid = BT_ISO_DATA_PATH_HCI,
.format = BT_HCI_CODING_FORMAT_TRANSPARENT,
};
int err;

LOG_INF("ISO Channel %p connected", chan);

big_sync_start_time = k_uptime_get();

err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path);
if (err != 0) {
printk("Failed to setup ISO RX data path: %d\n", err);
}

k_sem_give(&sem_big_sync);
}

Expand Down
42 changes: 42 additions & 0 deletions samples/bluetooth/iso_connected_benchmark/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include <ctype.h>
#include <zephyr/bluetooth/hci_types.h>
#include <zephyr/kernel.h>
#include <string.h>
#include <stdlib.h>
Expand Down Expand Up @@ -300,7 +301,12 @@ static void iso_recv(struct bt_iso_chan *chan,

static void iso_connected(struct bt_iso_chan *chan)
{
const struct bt_iso_chan_path hci_path = {
.pid = BT_ISO_DATA_PATH_HCI,
.format = BT_HCI_CODING_FORMAT_TRANSPARENT,
};
struct iso_chan_work *chan_work;
struct bt_iso_info iso_info;
int err;

LOG_INF("ISO Channel %p connected", chan);
Expand All @@ -319,6 +325,20 @@ static void iso_connected(struct bt_iso_chan *chan)
chan_work = CONTAINER_OF(chan, struct iso_chan_work, chan);
chan_work->seq_num = 0U;

if (iso_info.can_recv) {
err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST, &hci_path);
if (err != 0) {
LOG_ERR("Failed to setup ISO RX data path: %d", err);
}
}

if (iso_info.can_send) {
err = bt_iso_setup_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR, &hci_path);
if (err != 0) {
LOG_ERR("Failed to setup ISO TX data path: %d", err);
}
}

k_sem_give(&sem_iso_connected);
}

Expand All @@ -331,8 +351,10 @@ static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
* of the last created CIS.
*/
static int64_t average_duration;
struct bt_iso_info iso_info;
uint64_t iso_conn_duration;
uint64_t total_duration;
int err;

if (iso_conn_start_time > 0) {
iso_conn_duration = k_uptime_get() - iso_conn_start_time;
Expand All @@ -348,6 +370,26 @@ static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
chan, reason, iso_conn_duration, average_duration);

k_sem_give(&sem_iso_disconnected);

err = bt_iso_chan_get_info(chan, &iso_info);
if (err != 0) {
LOG_ERR("Failed to get ISO info: %d\n", err);
return;
} else {

Check warning on line 378 in samples/bluetooth/iso_connected_benchmark/src/main.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

UNNECESSARY_ELSE

samples/bluetooth/iso_connected_benchmark/src/main.c:378 else is not generally useful after a break or return
if (iso_info.can_recv) {
err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST);
if (err != 0) {
LOG_ERR("Failed to remove ISO RX data path: %d\n", err);
}
}

if (iso_info.can_send) {
err = bt_iso_remove_data_path(chan, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR);
if (err != 0) {
LOG_ERR("Failed to remove ISO TX data path: %d\n", err);
}
}
}
}

static struct bt_iso_chan_ops iso_ops = {
Expand Down
Loading

0 comments on commit 21ab23c

Please sign in to comment.