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; }