From e5e739578711feb62a2a9044f2c826c462adc6f4 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 11 Nov 2024 15:18:35 +0100 Subject: [PATCH] samples: Bluetooth: ISO: Update conn and adv intervals Update the connection and advertising intervals of the broadcast and connected ISO samples (including benchmark samples) to work better with the selected SDU intervals and the resulting ISO intervals. For the ISO connected benchmark the order of CIG and ACl has changed, so that we create the CIG before connecting the ACL for the purpose of providing as much information as possible to the controller. Signed-off-by: Emil Gydesen --- samples/bluetooth/iso_broadcast/src/main.c | 23 +++++++- .../iso_broadcast_benchmark/src/broadcaster.c | 58 ++++++++++++++++++- samples/bluetooth/iso_central/src/main.c | 9 ++- .../iso_connected_benchmark/src/main.c | 40 +++++++++++-- 4 files changed, 116 insertions(+), 14 deletions(-) diff --git a/samples/bluetooth/iso_broadcast/src/main.c b/samples/bluetooth/iso_broadcast/src/main.c index 0086a9786de7c..da06a9c417df7 100644 --- a/samples/bluetooth/iso_broadcast/src/main.c +++ b/samples/bluetooth/iso_broadcast/src/main.c @@ -1,10 +1,13 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ +#include +#include #include +#include #include #include @@ -88,6 +91,20 @@ static const struct bt_data ad[] = { int main(void) { + /* Some controllers work best while Extended Advertising interval to be a multiple + * of the ISO Interval minus 10 ms (max. advertising random delay). This is + * required to place the AUX_ADV_IND PDUs in a non-overlapping interval with the + * Broadcast ISO radio events. + * For 10ms SDU interval a extended advertising interval of 60 - 10 = 50 is suitable + */ + const uint16_t adv_interval_ms = 60U; + const uint16_t ext_adv_interval_ms = adv_interval_ms - 10U; + const struct bt_le_adv_param *ext_adv_param = BT_LE_ADV_PARAM( + BT_LE_ADV_OPT_EXT_ADV, BT_GAP_MS_TO_ADV_INTERVAL(ext_adv_interval_ms), + BT_GAP_MS_TO_ADV_INTERVAL(ext_adv_interval_ms), NULL); + const struct bt_le_per_adv_param *per_adv_param = BT_LE_PER_ADV_PARAM( + BT_GAP_MS_TO_PER_ADV_INTERVAL(adv_interval_ms), + BT_GAP_MS_TO_PER_ADV_INTERVAL(adv_interval_ms), BT_LE_PER_ADV_OPT_NONE); uint32_t timeout_counter = INITIAL_TIMEOUT_COUNTER; struct bt_le_ext_adv *adv; struct bt_iso_big *big; @@ -106,7 +123,7 @@ int main(void) } /* Create a non-connectable advertising set */ - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, NULL, &adv); + err = bt_le_ext_adv_create(ext_adv_param, NULL, &adv); if (err) { printk("Failed to create advertising set (err %d)\n", err); return 0; @@ -120,7 +137,7 @@ int main(void) } /* Set periodic advertising parameters */ - err = bt_le_per_adv_set_param(adv, BT_LE_PER_ADV_DEFAULT); + err = bt_le_per_adv_set_param(adv, per_adv_param); if (err) { printk("Failed to set periodic advertising parameters" " (err %d)\n", err); diff --git a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c index 32d5e86ca5f57..2f03528093fb6 100644 --- a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c +++ b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c @@ -1,17 +1,22 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include +#include + +#include #include #include #include #include #include +#include +#include LOG_MODULE_REGISTER(iso_broadcast_broadcaster, LOG_LEVEL_DBG); #define DEFAULT_BIS_RTN 2 @@ -613,13 +618,60 @@ static void iso_timer_timeout(struct k_work *work) seq_num++; } +static uint16_t calc_adv_interval(uint32_t sdu_interval_us) +{ + /* Default to 6 times the SDU interval and then reduce until we reach a reasonable maximum + * advertising interval (BT_GAP_PER_ADV_SLOW_INT_MAX) + * sdu_interval_us can never be larger than 1048ms (BT_ISO_SDU_INTERVAL_MAX) + * so a multiple of it will always be possible to keep under BT_GAP_PER_ADV_SLOW_INT_MAX + * (1200ms) + */ + + /* Convert from microseconds to advertising interval units (0.625ms)*/ + const uint32_t interval = BT_GAP_US_TO_ADV_INTERVAL(sdu_interval_us); + uint32_t adv_interval = interval * 6U; + + /* Ensure that the adv interval is between BT_GAP_PER_ADV_FAST_INT_MIN_1 and + * BT_GAP_PER_ADV_SLOW_INT_MAX for the sake of interopability + */ + while (adv_interval < BT_GAP_PER_ADV_FAST_INT_MIN_1) { + adv_interval += interval; + } + + while (adv_interval > BT_GAP_PER_ADV_SLOW_INT_MAX) { + adv_interval -= interval; + } + + /* If we cannot convert back then it's not a lossless conversion */ + if (big_create_param.framing == BT_ISO_FRAMING_UNFRAMED && + BT_GAP_ADV_INTERVAL_TO_US(interval) != sdu_interval_us) { + LOG_INF("Advertising interval of 0x04%x is not a multiple of the advertising " + "interval unit (0.625 ms) and may be subpar. Suggest to adjust SDU " + "interval %u to be a multiple of 0.625 ms", + adv_interval, sdu_interval_us); + } + + return adv_interval; +} + static int create_big(struct bt_le_ext_adv **adv, struct bt_iso_big **big) { + /* Some controllers work best when Extended Advertising interval is a multiple + * of the ISO Interval minus 10 ms (max. advertising random delay). This is + * required to place the AUX_ADV_IND PDUs in a non-overlapping interval with the + * Broadcast ISO radio events. + */ + const uint16_t adv_interval = calc_adv_interval(big_create_param.interval); + const uint16_t ext_adv_interval = adv_interval - BT_GAP_MS_TO_ADV_INTERVAL(10U); + const struct bt_le_adv_param *ext_adv_param = + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV, ext_adv_interval, ext_adv_interval, NULL); + const struct bt_le_per_adv_param *per_adv_param = + BT_LE_PER_ADV_PARAM(adv_interval, adv_interval, BT_LE_PER_ADV_OPT_NONE); int err; /* Create a non-connectable advertising set */ LOG_INF("Creating Extended Advertising set"); - err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, NULL, adv); + err = bt_le_ext_adv_create(ext_adv_param, NULL, adv); if (err != 0) { LOG_ERR("Failed to create advertising set (err %d)", err); return err; @@ -634,7 +686,7 @@ static int create_big(struct bt_le_ext_adv **adv, struct bt_iso_big **big) LOG_INF("Setting Periodic Advertising parameters"); /* Set periodic advertising parameters */ - err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); + err = bt_le_per_adv_set_param(*adv, per_adv_param); if (err != 0) { LOG_ERR("Failed to set periodic advertising parameters (err %d)", err); diff --git a/samples/bluetooth/iso_central/src/main.c b/samples/bluetooth/iso_central/src/main.c index 65d1abb4914f7..a9352363714c8 100644 --- a/samples/bluetooth/iso_central/src/main.c +++ b/samples/bluetooth/iso_central/src/main.c @@ -1,9 +1,10 @@ /* - * Copyright (c) 2021 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2024 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -90,6 +91,9 @@ static void iso_timer_timeout(struct k_work *work) static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) { + const struct bt_le_conn_param *conn_param = + BT_LE_CONN_PARAM(BT_GAP_MS_TO_CONN_INTERVAL(60), BT_GAP_MS_TO_CONN_INTERVAL(60), 0, + BT_GAP_MS_TO_CONN_TIMEOUT(4000)); char addr_str[BT_ADDR_LE_STR_LEN]; int err; @@ -115,8 +119,7 @@ static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, return; } - err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, - &default_conn); + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, conn_param, &default_conn); if (err) { printk("Create conn to %s failed (%u)\n", addr_str, err); start_scan(); diff --git a/samples/bluetooth/iso_connected_benchmark/src/main.c b/samples/bluetooth/iso_connected_benchmark/src/main.c index e4c1f7935f2ef..1933033f8442b 100644 --- a/samples/bluetooth/iso_connected_benchmark/src/main.c +++ b/samples/bluetooth/iso_connected_benchmark/src/main.c @@ -5,9 +5,14 @@ */ #include +#include +#include #include #include +#include #include +#include +#include #include @@ -1046,6 +1051,12 @@ static int change_central_settings(void) static int central_create_connection(void) { + /* Give the controller a large range of intervals to pick from. In this benchmark sample we + * want to prioritize ISO over ACL, but will leave the actual choice up to the controller. + */ + const struct bt_le_conn_param *conn_param = + BT_LE_CONN_PARAM(BT_GAP_INIT_CONN_INT_MIN, BT_GAP_MS_TO_CONN_INTERVAL(500U), 0, + BT_GAP_MS_TO_CONN_TIMEOUT(4000)); int err; advertiser_found = false; @@ -1071,8 +1082,7 @@ static int central_create_connection(void) } LOG_INF("Connecting"); - err = bt_conn_le_create(&adv_addr, BT_CONN_LE_CREATE_CONN, - BT_LE_CONN_PARAM_DEFAULT, &default_conn); + err = bt_conn_le_create(&adv_addr, BT_CONN_LE_CREATE_CONN, conn_param, &default_conn); if (err != 0) { LOG_ERR("Create connection failed: %d", err); return err; @@ -1089,7 +1099,6 @@ static int central_create_connection(void) static int central_create_cig(void) { - struct bt_iso_connect_param connect_param[CONFIG_BT_ISO_MAX_CHAN]; int err; iso_conn_start_time = 0; @@ -1102,6 +1111,16 @@ static int central_create_cig(void) return err; } + return 0; +} + +static int central_connect_cis(void) +{ + struct bt_iso_connect_param connect_param[CONFIG_BT_ISO_MAX_CHAN]; + int err; + + iso_conn_start_time = 0; + LOG_INF("Connecting ISO channels"); for (int i = 0; i < cig_create_param.num_cis; i++) { @@ -1205,15 +1224,26 @@ static int run_central(void) } } + /* Creating the CIG before connecting verified that it's possible before establishing a + * connection, while also providing the controller information about our use case before + * creating the connection, which should provide additional information to the controller + * about which connection interval to use + */ + err = central_create_cig(); + if (err != 0) { + LOG_ERR("Failed to create CIG: %d", err); + return err; + } + err = central_create_connection(); if (err != 0) { LOG_ERR("Failed to create connection: %d", err); return err; } - err = central_create_cig(); + err = central_connect_cis(); if (err != 0) { - LOG_ERR("Failed to create CIG or connect CISes: %d", err); + LOG_ERR("Failed to connect CISes: %d", err); return err; }