Bluetooth: ISO: Support bt_disable

Add support for bt_disable in the ISO implementation.
This involves clearing all information related to states
in the controller, such as the BIGs and CIGs.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2024-05-13 15:57:00 +02:00 committed by Johan Hedberg
commit c40856e5aa
6 changed files with 144 additions and 12 deletions

View file

@ -323,6 +323,8 @@ int bt_conn_iso_init(void);
/* Cleanup ISO references */
void bt_iso_cleanup_acl(struct bt_conn *iso_conn);
void bt_iso_reset(void);
/* Add a new BR/EDR connection */
struct bt_conn *bt_conn_add_br(const bt_addr_t *peer);

View file

@ -4264,6 +4264,10 @@ int bt_disable(void)
k_thread_abort(&bt_workq.thread);
#endif
if (IS_ENABLED(CONFIG_BT_ISO)) {
bt_iso_reset();
}
bt_monitor_send(BT_MONITOR_CLOSE_INDEX, NULL, 0);
/* Clear BT_DEV_ENABLE here to prevent early bt_enable() calls, before disable is

View file

@ -764,25 +764,26 @@ static int validate_send(const struct bt_iso_chan *chan, const struct net_buf *b
BT_ISO_DATA_DBG("chan %p len %zu", chan, net_buf_frags_len(buf));
if (chan->state != BT_ISO_STATE_CONNECTED) {
LOG_DBG("Not connected");
LOG_DBG("Channel %p not connected", chan);
return -ENOTCONN;
}
iso_conn = chan->iso;
if (!iso_conn->iso.info.can_send) {
LOG_DBG("Channel not able to send");
LOG_DBG("Channel %p not able to send", chan);
return -EINVAL;
}
if (buf->size < hdr_size) {
LOG_DBG("Cannot send ISO packet with buffer size %u", buf->size);
LOG_DBG("Channel %p cannot send ISO packet with buffer size %u", chan, buf->size);
return -EMSGSIZE;
}
max_data_len = iso_chan_max_data_len(chan);
if (buf->len > max_data_len) {
LOG_DBG("Cannot send %u octets, maximum %u", buf->len, max_data_len);
LOG_DBG("Channel %p cannot send %u octets, maximum %u", chan, buf->len,
max_data_len);
return -EMSGSIZE;
}
@ -2194,6 +2195,11 @@ void bt_iso_security_changed(struct bt_conn *acl, uint8_t hci_status)
continue;
}
/* Set state to disconnected to indicate that we are no longer waiting for
* encryption.
* TODO: Remove the BT_ISO_STATE_ENCRYPT_PENDING state and replace with a flag to
* avoid these unnecessary state changes
*/
bt_iso_chan_set_state(iso_chan, BT_ISO_STATE_DISCONNECTED);
if (hci_status == BT_HCI_ERR_SUCCESS) {
@ -2528,7 +2534,7 @@ static void big_disconnect(struct bt_iso_big *big, uint8_t reason)
SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) {
bis->iso->err = reason;
bt_iso_disconnected(bis->iso);
bt_iso_chan_disconnected(bis, reason);
}
}
@ -3278,3 +3284,31 @@ int bt_iso_big_sync(struct bt_le_per_adv_sync *sync, struct bt_iso_big_sync_para
}
#endif /* CONFIG_BT_ISO_SYNC_RECEIVER */
#endif /* CONFIG_BT_ISO_BROADCAST */
void bt_iso_reset(void)
{
#if defined(CONFIG_BT_ISO_CENTRAL)
for (size_t i = 0U; i < ARRAY_SIZE(cigs); i++) {
struct bt_iso_cig *cig = &cigs[i];
struct bt_iso_chan *cis, *tmp;
/* Call the disconnected callback for each CIS that is no idle */
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&cig->cis_channels, cis, tmp, node) {
if (cis->state != BT_ISO_STATE_DISCONNECTED) {
bt_iso_chan_disconnected(cis, BT_HCI_ERR_UNSPECIFIED);
}
}
cleanup_cig(cig);
}
#endif /* CONFIG_BT_ISO_CENTRAL */
#if defined(CONFIG_BT_ISO_BROADCAST)
for (size_t i = 0U; i < ARRAY_SIZE(bigs); i++) {
struct bt_iso_big *big = &bigs[i];
big_disconnect(big, BT_HCI_ERR_UNSPECIFIED);
cleanup_big(big);
}
#endif /* CONFIG_BT_ISO_BROADCAST */
}

View file

@ -21,3 +21,4 @@ CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=208
CONFIG_BT_CTLR_ISO_TX_BUFFERS=4
CONFIG_BT_CTLR_ISOAL_SOURCES=2
CONFIG_BT_CTLR_ISOAL_SINKS=2
CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP=4

View file

@ -107,19 +107,23 @@ static void iso_connected(struct bt_iso_chan *chan)
seq_num = 0U;
enqueue_cnt = ENQUEUE_COUNT;
/* Start send timer */
k_work_schedule(&iso_send_work, K_MSEC(0));
if (chan == default_chan) {
/* Start send timer */
k_work_schedule(&iso_send_work, K_MSEC(0));
SET_FLAG(flag_iso_connected);
SET_FLAG(flag_iso_connected);
}
}
static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason)
{
printk("ISO Channel %p disconnected (reason 0x%02x)\n", chan, reason);
k_work_cancel_delayable(&iso_send_work);
if (chan == default_chan) {
k_work_cancel_delayable(&iso_send_work);
UNSET_FLAG(flag_iso_connected);
UNSET_FLAG(flag_iso_connected);
}
}
static void sdu_sent_cb(struct bt_iso_chan *chan)
@ -188,12 +192,19 @@ static void set_cig_defaults(struct bt_iso_cig_param *param)
}
static void create_cig(void)
static void create_cig(size_t iso_channels)
{
struct bt_iso_chan *channels[ARRAY_SIZE(iso_chans)];
struct bt_iso_cig_param param;
int err;
for (size_t i = 0U; i < iso_channels; i++) {
channels[i] = &iso_chans[i];
}
set_cig_defaults(&param);
param.num_cis = iso_channels;
param.cis_channels = channels;
err = bt_iso_cig_create(&param, &cig);
if (err != 0) {
@ -385,10 +396,34 @@ static void terminate_cig(void)
cig = NULL;
}
static void reset_bluetooth(void)
{
int err;
printk("Resetting Bluetooth\n");
err = bt_disable();
if (err != 0) {
FAIL("Failed to disable (%d)\n", err);
return;
}
/* After a disable, all CIGs and BIGs are removed */
cig = NULL;
err = bt_enable(NULL);
if (err != 0) {
FAIL("Failed to re-enable (%d)\n", err);
return;
}
}
static void test_main(void)
{
init();
create_cig();
create_cig(1);
reconfigure_cig();
connect_acl();
connect_cis();
@ -404,6 +439,34 @@ static void test_main(void)
PASS("Test passed\n");
}
static void test_main_disable(void)
{
init();
/* Setup and connect before disabling */
create_cig(ARRAY_SIZE(iso_chans));
connect_acl();
connect_cis();
/* Reset BT to see if we can set it up again */
reset_bluetooth();
/* Set everything up again to see if everything still works as expected */
create_cig(ARRAY_SIZE(iso_chans));
connect_acl();
connect_cis();
while (seq_num < 100U) {
k_sleep(K_USEC(interval_us));
}
disconnect_cis();
disconnect_acl();
terminate_cig();
PASS("Disable test passed\n");
}
static const struct bst_test_instance test_def[] = {
{
.test_id = "central",
@ -412,6 +475,13 @@ static const struct bst_test_instance test_def[] = {
.test_tick_f = test_tick,
.test_main_f = test_main,
},
{
.test_id = "central_disable",
.test_descr = "CIS central that tests bt_disable for ISO",
.test_post_init_f = test_init,
.test_tick_f = test_tick,
.test_main_f = test_main_disable,
},
BSTEST_END_MARKER,
};

View file

@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Copyright (c) 2023 Nordic Semiconductor
# SPDX-License-Identifier: Apache-2.0
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
simulation_id="iso_cis_disable"
verbosity_level=2
cd ${BSIM_OUT_PATH}/bin
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_iso_cis_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central_disable
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_host_iso_cis_prj_conf \
-v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
-D=2 -sim_length=30e6 $@
wait_for_background_jobs