diff --git a/doc/releases/migration-guide-4.4.rst b/doc/releases/migration-guide-4.4.rst index cb99605c9efc5..0f15ff38da9bb 100644 --- a/doc/releases/migration-guide-4.4.rst +++ b/doc/releases/migration-guide-4.4.rst @@ -48,6 +48,9 @@ Bluetooth Host * :kconfig:option:`CONFIG_BT_SIGNING` has been deprecated. * :c:macro:`BT_GATT_CHRC_AUTH` has been deprecated. +* :c:member:`bt_conn_le_info.interval` has been deprecated. Use + :c:member:`bt_conn_le_info.interval_us` instead. Note that the units have changed: ``interval`` + was in units of 1.25 milliseconds, while ``interval_us`` is in microseconds. Networking ********** diff --git a/doc/releases/release-notes-4.4.rst b/doc/releases/release-notes-4.4.rst index 9622d9c5bd388..79a2bbf802e2b 100644 --- a/doc/releases/release-notes-4.4.rst +++ b/doc/releases/release-notes-4.4.rst @@ -62,6 +62,12 @@ Deprecated APIs and options * The callback :c:member:`output_number` in :c:struct:`bt_mesh_prov` structure was deprecated. Applications should use :c:member:`output_numeric` callback instead. + * Host + + * :c:member:`bt_conn_le_info.interval` has been deprecated. Use + :c:member:`bt_conn_le_info.interval_us` instead. Note that the units have changed: + ``interval`` was in units of 1.25 milliseconds, while ``interval_us`` is in microseconds. + New APIs and options ==================== diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index f07e35e315595..14bf2d657f28a 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -252,6 +252,169 @@ struct bt_conn_le_subrate_changed { uint16_t supervision_timeout; }; +/** @brief Maximum Connection Interval Groups possible + * + * The practical maximum is 41 groups based on HCI event size constraints: + * (HCI event max size - cmd_complete overhead - response fields) / sizeof(group) + * (255 - 4 - 3) / 6 = 41 groups max + */ +#define BT_CONN_LE_MAX_CONN_INTERVAL_GROUPS 41 + +/** @brief Minimum supported connection interval group + * + * Each group represents an arithmetic sequence of supported connection intervals: + * min, min + stride, min + 2 * stride, ..., min + n * stride (where min + n * stride <= max) + * + * Example: min = 10 (1250 us), max = 60 (7500 us), stride = 5 (625 us) + * -> Supported: 1250 us, 1875 us, 2500 us, ..., 6875 us, 7500 us + */ +struct bt_conn_le_min_conn_interval_group { + /** @brief Lower bound of group interval range + * + * Unit: 125 microseconds + * + * Range: @ref BT_HCI_LE_SCI_INTERVAL_MIN_125US - @ref BT_HCI_LE_SCI_INTERVAL_MAX_125US + */ + uint16_t min_125us; + /** @brief Upper bound of group interval range + * + * Unit: 125 microseconds + * + * Range: @ref BT_HCI_LE_SCI_INTERVAL_MIN_125US - @ref BT_HCI_LE_SCI_INTERVAL_MAX_125US + */ + uint16_t max_125us; + /** @brief Increment between consecutive supported intervals + * + * Unit: 125 microseconds + * + * Range: @ref BT_HCI_LE_SCI_STRIDE_MIN_125US - @ref BT_HCI_LE_SCI_INTERVAL_MAX_125US + */ + uint16_t stride_125us; +}; + +/** Minimum supported connection interval information */ +struct bt_conn_le_min_conn_interval_info { + /** @brief Minimum supported connection interval + * + * Unit: microseconds + * + * Range: @ref BT_HCI_LE_MIN_SUPP_CONN_INT_MIN_US - @ref BT_HCI_LE_MIN_SUPP_CONN_INT_MAX_US + */ + uint16_t min_supported_conn_interval_us; + /** @brief Number of interval groups. + * + * Range: 0 - @ref BT_CONN_LE_MAX_CONN_INTERVAL_GROUPS + * + * If zero, the controller only supports Rounded ConnInterval Values (RCV). + */ + uint8_t num_groups; + /** @brief Array of supported connection interval groups. + * + * Multiple groups allow representing non-contiguous or differently-strided ranges. + */ + struct bt_conn_le_min_conn_interval_group groups[BT_CONN_LE_MAX_CONN_INTERVAL_GROUPS]; +}; + +/** Connection rate parameters for LE connections */ +struct bt_conn_le_conn_rate_param { + /** @brief Minimum connection interval + * + * Unit: 125 microseconds + * + * Range: @ref BT_HCI_LE_SCI_INTERVAL_MIN_125US - @ref BT_HCI_LE_SCI_INTERVAL_MAX_125US + */ + uint16_t interval_min_125us; + /** @brief Maximum connection interval + * + * Unit: 125 microseconds + * + * Range: @ref BT_HCI_LE_SCI_INTERVAL_MIN_125US - @ref BT_HCI_LE_SCI_INTERVAL_MAX_125US + */ + uint16_t interval_max_125us; + /** @brief Minimum subrate factor + * + * Range: @ref BT_HCI_LE_SUBRATE_FACTOR_MIN - @ref BT_HCI_LE_SUBRATE_FACTOR_MAX + */ + uint16_t subrate_min; + /** @brief Maximum subrate factor + * + * Range: @ref BT_HCI_LE_SUBRATE_FACTOR_MIN - @ref BT_HCI_LE_SUBRATE_FACTOR_MAX + */ + uint16_t subrate_max; + /** @brief Maximum Peripheral latency + * + * Unit: subrated connection intervals @ref bt_conn_le_conn_rate_changed.subrate_factor + * + * Range: @ref BT_HCI_LE_PERIPHERAL_LATENCY_MIN - @ref BT_HCI_LE_PERIPHERAL_LATENCY_MAX + */ + uint16_t max_latency; + /** @brief Minimum number of underlying connection events to remain active + * after a packet containing a Link Layer PDU with a non-zero Length + * field is sent or received. + * + * Range: @ref BT_HCI_LE_CONTINUATION_NUM_MIN - @ref BT_HCI_LE_CONTINUATION_NUM_MAX + */ + uint16_t continuation_number; + /** @brief Connection Supervision timeout + * + * Unit: 10 milliseconds + * + * Range: @ref BT_HCI_LE_SUPERVISON_TIMEOUT_MIN - @ref BT_HCI_LE_SUPERVISON_TIMEOUT_MAX + */ + uint16_t supervision_timeout_10ms; + /** @brief Minimum length of connection event + * + * Unit: 125 microseconds + * + * Range: @ref BT_HCI_LE_SCI_CE_LEN_MIN_125US - @ref BT_HCI_LE_SCI_CE_LEN_MAX_125US + */ + uint16_t min_ce_len_125us; + /** @brief Maximum length of connection event + * + * Unit: 125 microseconds + * + * Range: @ref BT_HCI_LE_SCI_CE_LEN_MIN_125US - @ref BT_HCI_LE_SCI_CE_LEN_MAX_125US + */ + uint16_t max_ce_len_125us; +}; + +/** Updated connection rate parameters */ +struct bt_conn_le_conn_rate_changed { + /** Connection interval + * + * Unit: microseconds + * + * Range: @ref BT_HCI_LE_SCI_INTERVAL_MIN_US - @ref BT_HCI_LE_SCI_INTERVAL_MAX_US + */ + uint32_t interval_us; + /** Connection subrate factor + * + * Range: @ref BT_HCI_LE_SUBRATE_FACTOR_MIN - @ref BT_HCI_LE_SUBRATE_FACTOR_MAX + */ + uint16_t subrate_factor; + /** Peripheral latency + * + * Unit: subrated connection intervals @ref bt_conn_le_conn_rate_changed.subrate_factor + * + * Range: @ref BT_HCI_LE_PERIPHERAL_LATENCY_MIN - @ref BT_HCI_LE_PERIPHERAL_LATENCY_MAX + */ + uint16_t peripheral_latency; + /** Number of underlying connection events to remain active after + * a packet containing a Link Layer PDU with a non-zero Length + * field is sent or received. + * + * Range: @ref BT_HCI_LE_CONTINUATION_NUM_MIN - @ref BT_HCI_LE_CONTINUATION_NUM_MAX + */ + uint16_t continuation_number; + /** Connection Supervision timeout + * + * Unit: 10 milliseconds + * + * Range: @ref BT_HCI_LE_SUPERVISON_TIMEOUT_MIN - @ref BT_HCI_LE_SUPERVISON_TIMEOUT_MAX + */ + uint16_t supervision_timeout_10ms; +}; + /** Read all remote features complete callback params */ struct bt_conn_le_read_all_remote_feat_complete { /** @brief HCI Status from LE Read All Remote Features Complete event. @@ -890,7 +1053,22 @@ struct bt_conn_le_info { const bt_addr_le_t *local; /** Remote device address used during connection setup. */ const bt_addr_le_t *remote; - uint16_t interval; /**< Connection interval */ + /** Connection interval in microseconds */ + uint32_t interval_us; +#if !defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) || defined(__DOXYGEN__) + union { + /** @brief Connection interval in units of 1.25 ms + * + * @deprecated Use @ref bt_conn_le_info.interval_us instead + */ + __deprecated uint16_t interval; + /** @cond INTERNAL_HIDDEN */ + /** Workaround for setting deprecated @ref bt_conn_le_info.interval */ + uint16_t _interval; + /** @endcond */ + }; +#endif /* !CONFIG_BT_SHORTER_CONNECTION_INTERVALS */ + uint16_t latency; /**< Connection peripheral latency */ uint16_t timeout; /**< Connection supervision timeout */ @@ -924,6 +1102,12 @@ struct bt_conn_le_info { */ #define BT_CONN_INTERVAL_TO_US(interval) ((interval) * 1250U) +/** @brief Convert shorter connection interval to microseconds + * + * Multiply by 125 to get microseconds. + */ +#define BT_CONN_SCI_INTERVAL_TO_US(_interval) ((_interval) * BT_HCI_LE_SCI_INTERVAL_UNIT_US) + /** BR/EDR Connection Info Structure */ struct bt_conn_br_info { const bt_addr_t *dst; /**< Destination (Remote) BR/EDR address */ @@ -1329,6 +1513,74 @@ int bt_conn_le_subrate_set_defaults(const struct bt_conn_le_subrate_param *param int bt_conn_le_subrate_request(struct bt_conn *conn, const struct bt_conn_le_subrate_param *params); +/** @brief Read Minimum Supported Connection Interval Groups. + * + * Read the minimum supported connection interval and supported interval + * groups from the local controller. This information describes what the + * local controller supports. + * + * @sa bt_conn_le_read_min_conn_interval if only + * @ref bt_conn_le_min_conn_interval_info.min_supported_conn_interval_us + * is needed. + * + * @kconfig_dep{CONFIG_BT_SHORTER_CONNECTION_INTERVALS} + * + * @param info Pointer to structure to receive the minimum connection interval + * information. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_conn_le_read_min_conn_interval_groups(struct bt_conn_le_min_conn_interval_info *info); + +/** @brief Read Minimum Supported Connection Interval. + * + * Read the minimum supported connection interval from the local controller. + * + * @sa bt_conn_le_read_min_conn_interval_groups if groups are needed. + * + * @kconfig_dep{CONFIG_BT_SHORTER_CONNECTION_INTERVALS} + * + * @param min_interval_us Pointer to variable to receive the minimum connection interval + * in microseconds. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_conn_le_read_min_conn_interval(uint16_t *min_interval_us); + +/** @brief Set Default Connection Rate Parameters. + * + * Set default connection rate parameters to be used for future connections. + * This command does not affect any existing connection. + * Parameters set for specific connection will always have precedence. + * + * @kconfig_dep{CONFIG_BT_SHORTER_CONNECTION_INTERVALS} + * + * @param params Connection rate parameters. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_conn_le_conn_rate_set_defaults(const struct bt_conn_le_conn_rate_param *params); + +/** @brief Request New Connection Rate Parameters. + * + * Request a change to the connection parameters of a connection. This includes + * Subrate parameters. This allows changing the connection interval to below the + * Baseline ConnInterval Values (BCV) and with finer granularity, if supported. + * + * Valid intervals of the local and peer controller should be known. + * See @ref bt_conn_le_read_min_conn_interval_groups + * + * @kconfig_dep{CONFIG_BT_SHORTER_CONNECTION_INTERVALS} + * + * @param conn @ref BT_CONN_TYPE_LE connection object. + * @param params Connection rate parameters. + * + * @return Zero on success or (negative) error code on failure. + * @return -EINVAL @p conn is not a valid @ref BT_CONN_TYPE_LE connection. + */ +int bt_conn_le_conn_rate_request(struct bt_conn *conn, + const struct bt_conn_le_conn_rate_param *params); + /** @brief Read remote feature pages. * * Request remote feature pages, from 0 up to pages_requested or the number @@ -2064,6 +2316,31 @@ struct bt_conn_cb { const struct bt_conn_le_subrate_changed *params); #endif /* CONFIG_BT_SUBRATING */ +#if defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) || defined(__DOXYGEN__) + /** @brief LE Connection Rate Changed event. + * + * This callback notifies the application that the connection rate + * parameters (including both connection interval and subrating) + * of the connection may have changed. + * + * @param conn Connection object. + * @param status HCI Status from LE Connection Rate Change event. + * Possible Status codes: + * - Success (0x00) + * - Unknown Connection Identifier (0x02) + * - Command Disallowed (0x0C) + * - Unsupported Feature or Parameter Value (0x11) + * - Invalid HCI Command Parameters (0x12) + * - Unsupported Remote Feature (0x1A) + * - Unsupported LL Parameter Value (0x20) + * @param params New connection rate parameters. + * The connection rate parameters will be NULL + * if @p status is not @ref BT_HCI_ERR_SUCCESS. + */ + void (*conn_rate_changed)(struct bt_conn *conn, uint8_t status, + const struct bt_conn_le_conn_rate_changed *params); +#endif /* CONFIG_BT_SHORTER_CONNECTION_INTERVALS */ + #if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) /** @brief Read all remote features complete event. * diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 9cbc6778f09ec..71fb29c828aa6 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -210,6 +210,8 @@ struct bt_hci_cmd_hdr { #define BT_LE_FEAT_BIT_CHANNEL_SOUNDING_TONE_QUAL_IND 48 #define BT_LE_FEAT_BIT_EXTENDED_FEAT_SET 63 #define BT_LE_FEAT_BIT_FRAME_SPACE_UPDATE 65 +#define BT_LE_FEAT_BIT_SHORTER_CONN_INTERVALS 72 +#define BT_LE_FEAT_BIT_SHORTER_CONN_INTERVALS_HOST_SUPP 73 #define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ BIT((n) & 7)) @@ -290,6 +292,10 @@ struct bt_hci_cmd_hdr { BT_LE_FEAT_BIT_EXTENDED_FEAT_SET) #define BT_FEAT_LE_FRAME_SPACE_UPDATE_SET(feat) BT_LE_FEAT_TEST(feat, \ BT_LE_FEAT_BIT_FRAME_SPACE_UPDATE) +#define BT_FEAT_LE_SHORTER_CONN_INTERVALS(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_SHORTER_CONN_INTERVALS) +#define BT_FEAT_LE_SHORTER_CONN_INTERVALS_HOST_SUPP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_SHORTER_CONN_INTERVALS_HOST_SUPP) #define BT_FEAT_LE_CIS(feat) (BT_FEAT_LE_CIS_CENTRAL(feat) | \ BT_FEAT_LE_CIS_PERIPHERAL(feat)) @@ -2925,6 +2931,66 @@ struct bt_hci_cp_le_frame_space_update { #define BT_HCI_OP_LE_FRAME_SPACE_UPDATE BT_OP(BT_OGF_LE, 0x009D) /* 0x209D */ +/** All limits according to BT Core spec 6.2 [Vol 4, Part E, 7.8.154]. */ +#define BT_HCI_LE_SCI_INTERVAL_MIN_125US (0x0003U) +#define BT_HCI_LE_SCI_INTERVAL_MAX_125US (0x7D00U) +#define BT_HCI_LE_SCI_INTERVAL_MIN_US (375U) +#define BT_HCI_LE_SCI_INTERVAL_MAX_US (4000000U) +#define BT_HCI_LE_SCI_INTERVAL_UNIT_US (125U) + +#define BT_HCI_LE_SCI_STRIDE_MIN_125US (0x0001U) + +#define BT_HCI_LE_MIN_SUPP_CONN_INT_MIN_US (375U) +#define BT_HCI_LE_MIN_SUPP_CONN_INT_MAX_US (7500U) + +#define BT_HCI_LE_SCI_CE_LEN_MIN_125US (0x0001U) +#define BT_HCI_LE_SCI_CE_LEN_MAX_125US (0x3E7FU) + +struct bt_hci_le_read_min_supported_conn_interval_group { + uint16_t group_min; + uint16_t group_max; + uint16_t group_stride; +} __packed; + +struct bt_hci_op_le_read_min_supported_conn_interval { + uint8_t status; + uint8_t min_supported_conn_interval; + uint8_t num_groups; + struct bt_hci_le_read_min_supported_conn_interval_group groups[]; +} __packed; + +#define BT_HCI_OP_LE_READ_MIN_SUPPORTED_CONN_INTERVAL \ + BT_OP(BT_OGF_LE, 0x00A3) /* 0x20A3 */ + +struct bt_hci_op_le_set_default_rate_parameters { + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t subrate_min; + uint16_t subrate_max; + uint16_t max_latency; + uint16_t continuation_number; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_SET_DEFAULT_RATE_PARAMETERS BT_OP(BT_OGF_LE, 0x00A2) /* 0x20A2 */ + +struct bt_hci_op_le_connection_rate_request { + uint16_t handle; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t subrate_min; + uint16_t subrate_max; + uint16_t max_latency; + uint16_t continuation_number; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_CONNECTION_RATE_REQUEST BT_OP(BT_OGF_LE, 0x00A1) /* 0x20A1 */ + /* Event definitions */ #define BT_HCI_EVT_UNKNOWN 0x00 @@ -3303,10 +3369,13 @@ struct bt_hci_evt_le_advertising_report { /** All limits according to BT Core Spec v5.4 [Vol 4, Part E]. */ #define BT_HCI_LE_INTERVAL_MIN 0x0006 #define BT_HCI_LE_INTERVAL_MAX 0x0c80 +#define BT_HCI_LE_PERIPHERAL_LATENCY_MIN (0x0000U) #define BT_HCI_LE_PERIPHERAL_LATENCY_MAX 0x01f3 #define BT_HCI_LE_SUPERVISON_TIMEOUT_MIN 0x000a #define BT_HCI_LE_SUPERVISON_TIMEOUT_MAX 0x0c80 +#define BT_HCI_LE_INTERVAL_UNIT_US (1250U) + #define BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE 0x03 struct bt_hci_evt_le_conn_update_complete { uint8_t status; @@ -3694,6 +3763,7 @@ struct bt_hci_evt_le_biginfo_adv_report { /** All limits according to BT Core Spec v5.4 [Vol 4, Part E]. */ #define BT_HCI_LE_SUBRATE_FACTOR_MIN 0x0001 #define BT_HCI_LE_SUBRATE_FACTOR_MAX 0x01f4 +#define BT_HCI_LE_CONTINUATION_NUM_MIN (0x0000U) #define BT_HCI_LE_CONTINUATION_NUM_MAX 0x01f3 #define BT_HCI_EVT_LE_SUBRATE_CHANGE 0x23 @@ -4138,6 +4208,17 @@ struct bt_hci_evt_le_frame_space_update_complete { uint16_t spacing_types; } __packed; +#define BT_HCI_EVT_LE_CONN_RATE_CHANGE 0x37 +struct bt_hci_evt_le_conn_rate_change { + uint8_t status; + uint16_t handle; + uint16_t conn_interval; + uint16_t subrate_factor; + uint16_t peripheral_latency; + uint16_t continuation_number; + uint16_t supervision_timeout; +} __packed; + /* Event mask bits */ #define BT_EVT_BIT(n) (1ULL << (n)) @@ -4240,6 +4321,7 @@ struct bt_hci_evt_le_frame_space_update_complete { #define BT_EVT_MASK_LE_CS_TEST_END_COMPLETE BT_EVT_BIT(50) #define BT_EVT_MASK_LE_FRAME_SPACE_UPDATE_COMPLETE BT_EVT_BIT(52) +#define BT_EVT_MASK_LE_CONN_RATE_CHANGE BT_EVT_BIT(54) /** HCI Error Codes, BT Core Spec v5.4 [Vol 1, Part F]. */ #define BT_HCI_ERR_SUCCESS 0x00 diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 7e8fa5dca6ecb..ec5d4fafcc889 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -117,7 +117,7 @@ config BT_CONN_TX config BT_LE_LOCAL_MINIMUM_REQUIRED_FEATURE_PAGE int - default 1 if BT_FRAME_SPACE_UPDATE + default 1 if BT_FRAME_SPACE_UPDATE || BT_SHORTER_CONNECTION_INTERVALS default 0 depends on BT_LE_EXTENDED_FEAT_SET help @@ -260,6 +260,15 @@ config BT_CHANNEL_SOUNDING_REASSEMBLY_BUFFER_CNT results. Each running CS procedure is allocated one buffer and the number of concurrent CS procedures is limited by this value. +config BT_SHORTER_CONNECTION_INTERVALS + bool "Shorter Connection Intervals" + depends on !HAS_BT_CTLR || BT_CTLR_SHORTER_CONNECTION_INTERVALS_SUPPORT + depends on BT_LE_EXTENDED_FEAT_SET + depends on BT_SUBRATING + help + Enable support for the Bluetooth 6.2 Shorter Connection Intervals + feature. + endif # BT_CONN config BT_ISO diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 4636ca605a378..9072c220e5f98 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -525,7 +525,7 @@ static void state_transition_work_handler(struct k_work *work) err = ase_state_notify(ase); if (err == -ENOMEM) { struct bt_conn_info info; - uint32_t retry_delay_ms; + uint32_t retry_delay_us; /* Revert back to old state */ ase->ep.state = old_state; @@ -533,14 +533,14 @@ static void state_transition_work_handler(struct k_work *work) err = bt_conn_get_info(ase->conn, &info); __ASSERT_NO_MSG(err == 0); - retry_delay_ms = BT_CONN_INTERVAL_TO_MS(info.le.interval); + retry_delay_us = info.le.interval_us; /* Reschedule the state transition */ - err = k_work_reschedule(d_work, K_MSEC(retry_delay_ms)); + err = k_work_reschedule(d_work, K_USEC(retry_delay_us)); if (err >= 0) { LOG_DBG("Out of buffers for ase state notification. " - "Will retry in %dms", - retry_delay_ms); + "Will retry in %dus", + retry_delay_us); return; } } diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index fca4bf39d7013..acfef673bf259 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -453,12 +453,12 @@ static void long_bap_read(struct bt_conn *conn, uint16_t handle) if (err != 0) { LOG_DBG("Failed to get conn info, use default interval"); - conn_info.le.interval = BT_GAP_INIT_CONN_INT_MIN; + conn_info.le.interval_us = BT_CONN_INTERVAL_TO_US(BT_GAP_INIT_CONN_INT_MIN); } /* Wait a connection interval to retry */ err = k_work_reschedule(&inst->bap_read_work, - K_USEC(BT_CONN_INTERVAL_TO_US(conn_info.le.interval))); + K_USEC(conn_info.le.interval_us)); if (err < 0) { LOG_DBG("Failed to reschedule read work: %d", err); bap_long_read_reset(inst); diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index b70d9c4d34c7f..860ea8fa56a69 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -239,7 +239,7 @@ static void receive_state_notify_cb(struct bt_conn *conn, void *data) LOG_DBG("Could not notify receive state: %d", err); err = k_work_reschedule(&internal_state->notify_work, - K_USEC(BT_CONN_INTERVAL_TO_US(conn_info.le.interval))); + K_USEC(conn_info.le.interval_us)); __ASSERT(err >= 0, "Failed to reschedule work: %d", err); } } diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 05aa9ca08f218..99ba63c2f42ad 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -1767,12 +1767,12 @@ static void long_ase_read(struct bt_bap_unicast_client_ep *client_ep) if (err != 0) { LOG_DBG("Failed to get conn info, use default interval"); - conn_info.le.interval = BT_GAP_INIT_CONN_INT_MIN; + conn_info.le.interval_us = BT_CONN_INTERVAL_TO_US(BT_GAP_INIT_CONN_INT_MIN); } /* Wait a connection interval to retry */ err = k_work_reschedule(&client_ep->ase_read_work, - K_USEC(BT_CONN_INTERVAL_TO_US(conn_info.le.interval))); + K_USEC(conn_info.le.interval_us)); if (err < 0) { LOG_DBG("Failed to reschedule ASE long read work: %d", err); } diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index 7526c5327e0f2..d7026c63dbe39 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -1005,7 +1005,7 @@ static void notify_handler_cb(struct bt_conn *conn, void *data) LOG_DBG("Notify failed (%d), retrying next connection interval", err); reschedule: err = k_work_reschedule(&inst->notify_work, - K_USEC(BT_CONN_INTERVAL_TO_US(info.le.interval))); + K_USEC(info.le.interval_us)); __ASSERT(err >= 0, "Failed to reschedule work: %d", err); } diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 7fd3c46fe35af..07cdcd2941fde 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -133,6 +133,9 @@ config BT_CTLR_CHANNEL_SOUNDING_SUPPORT config BT_CTLR_EXTENDED_FEAT_SET_SUPPORT bool +config BT_CTLR_SHORTER_CONNECTION_INTERVALS_SUPPORT + bool + # Virtual option that all local LL implementations should select config HAS_BT_CTLR bool @@ -1184,6 +1187,17 @@ config BT_CTLR_EXTENDED_FEAT_SET Enable support for Bluetooth 6.0 LL Extended Feature Set in the Controller. +config BT_CTLR_SHORTER_CONNECTION_INTERVALS + bool "Shorter Connection Intervals" + depends on BT_CTLR_SHORTER_CONNECTION_INTERVALS_SUPPORT + depends on BT_CTLR_EXTENDED_FEAT_SET + depends on BT_CTLR_SUBRATING + select BT_CTLR_SET_HOST_FEATURE + default y if BT_SHORTER_CONNECTION_INTERVALS + help + Enable support for Bluetooth 6.2 Shorter Connection Intervals + in the controller. + rsource "Kconfig.df" rsource "Kconfig.ll_sw_split" rsource "Kconfig.dtm" diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 66833d1cfcc53..6b2586bdda4eb 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -3523,7 +3523,7 @@ static k_timeout_t credit_based_connection_delay(struct bt_conn *conn) * result in an overflow */ const uint32_t calculated_delay_us = - 2 * (conn->le.latency + 1) * BT_CONN_INTERVAL_TO_US(conn->le.interval); + 2 * (conn->le.latency + 1) * conn->le.interval_us; const uint32_t calculated_delay_ms = calculated_delay_us / USEC_PER_MSEC; return K_MSEC(MAX(100, calculated_delay_ms + rand_delay)); diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index ce1a94c58f961..3bb442e3f1859 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -2003,30 +2003,30 @@ void bt_conn_notify_remote_info(struct bt_conn *conn) void bt_conn_notify_le_param_updated(struct bt_conn *conn) { + uint16_t interval_1250us = conn->le.interval_us / BT_HCI_LE_INTERVAL_UNIT_US; + /* If new connection parameters meet requirement of pending * parameters don't send peripheral conn param request anymore on timeout */ if (atomic_test_bit(conn->flags, BT_CONN_PERIPHERAL_PARAM_SET) && - conn->le.interval >= conn->le.interval_min && - conn->le.interval <= conn->le.interval_max && + interval_1250us >= conn->le.interval_min && + interval_1250us <= conn->le.interval_max && conn->le.latency == conn->le.pending_latency && conn->le.timeout == conn->le.pending_timeout) { atomic_clear_bit(conn->flags, BT_CONN_PERIPHERAL_PARAM_SET); } - BT_CONN_CB_DYNAMIC_FOREACH(callback) { if (callback->le_param_updated) { - callback->le_param_updated(conn, conn->le.interval, + callback->le_param_updated(conn, interval_1250us, conn->le.latency, conn->le.timeout); } } STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { if (cb->le_param_updated) { - cb->le_param_updated(conn, conn->le.interval, - conn->le.latency, - conn->le.timeout); + cb->le_param_updated(conn, interval_1250us, + conn->le.latency, conn->le.timeout); } } } @@ -2886,7 +2886,10 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info) info->le.local = &conn->le.resp_addr; info->le.remote = &conn->le.init_addr; } - info->le.interval = conn->le.interval; + info->le.interval_us = conn->le.interval_us; +#if !defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) + info->le._interval = conn->le.interval_us / BT_HCI_LE_INTERVAL_UNIT_US; +#endif info->le.latency = conn->le.latency; info->le.timeout = conn->le.timeout; #if defined(CONFIG_BT_USER_PHY_UPDATE) @@ -3244,6 +3247,24 @@ void bt_conn_notify_subrate_change(struct bt_conn *conn, } } +#if defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) +void bt_conn_notify_conn_rate_change(struct bt_conn *conn, uint8_t status, + const struct bt_conn_le_conn_rate_changed *params) +{ + BT_CONN_CB_DYNAMIC_FOREACH(callback) { + if (callback->conn_rate_changed != NULL) { + callback->conn_rate_changed(conn, status, params); + } + } + + STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->conn_rate_changed != NULL) { + cb->conn_rate_changed(conn, status, params); + } + } +} +#endif /* CONFIG_BT_SHORTER_CONNECTION_INTERVALS */ + static bool le_subrate_common_params_valid(const struct bt_conn_le_subrate_param *param) { /* All limits according to BT Core spec 5.4 [Vol 4, Part E, 7.8.123] */ @@ -3332,6 +3353,182 @@ int bt_conn_le_subrate_request(struct bt_conn *conn, } #endif /* CONFIG_BT_SUBRATING */ +#if defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) +int bt_conn_le_read_min_conn_interval_groups(struct bt_conn_le_min_conn_interval_info *info) +{ + struct net_buf *rsp; + struct bt_hci_op_le_read_min_supported_conn_interval *rp; + int err; + + if (info == NULL) { + return -EINVAL; + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_MIN_SUPPORTED_CONN_INTERVAL, NULL, + &rsp); + if (err != 0) { + return err; + } + + rp = (struct bt_hci_op_le_read_min_supported_conn_interval *)rsp->data; + + if (rp->num_groups > BT_CONN_LE_MAX_CONN_INTERVAL_GROUPS) { + LOG_ERR("Too many groups: %d (max %d)", + rp->num_groups, BT_CONN_LE_MAX_CONN_INTERVAL_GROUPS); + net_buf_unref(rsp); + return -ENOMEM; + } + + info->min_supported_conn_interval_us = + BT_CONN_SCI_INTERVAL_TO_US(rp->min_supported_conn_interval); + info->num_groups = rp->num_groups; + + /* Copy groups up to the number allocated by the application */ + for (uint8_t i = 0; i < rp->num_groups; i++) { + info->groups[i].min_125us = sys_le16_to_cpu(rp->groups[i].group_min); + info->groups[i].max_125us = sys_le16_to_cpu(rp->groups[i].group_max); + info->groups[i].stride_125us = sys_le16_to_cpu(rp->groups[i].group_stride); + } + + net_buf_unref(rsp); + return 0; +} + +int bt_conn_le_read_min_conn_interval(uint16_t *min_interval_us) +{ + int err; + struct net_buf *rsp; + struct bt_hci_op_le_read_min_supported_conn_interval *rp; + + if (min_interval_us == NULL) { + return -EINVAL; + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_MIN_SUPPORTED_CONN_INTERVAL, NULL, + &rsp); + if (err != 0) { + return err; + } + + rp = (struct bt_hci_op_le_read_min_supported_conn_interval *)rsp->data; + *min_interval_us = BT_CONN_SCI_INTERVAL_TO_US(rp->min_supported_conn_interval); + + net_buf_unref(rsp); + return 0; +} + +static bool le_conn_rate_common_params_valid(const struct bt_conn_le_conn_rate_param *param) +{ + /* All limits according to BT Core spec 6.2 [Vol 4, Part E, 7.8.154] */ + + if (!IN_RANGE(param->interval_min_125us, BT_HCI_LE_SCI_INTERVAL_MIN_125US, + BT_HCI_LE_SCI_INTERVAL_MAX_125US) || + !IN_RANGE(param->interval_max_125us, BT_HCI_LE_SCI_INTERVAL_MIN_125US, + BT_HCI_LE_SCI_INTERVAL_MAX_125US) || + param->interval_min_125us > param->interval_max_125us) { + return false; + } + + if (!IN_RANGE(param->subrate_min, BT_HCI_LE_SUBRATE_FACTOR_MIN, + BT_HCI_LE_SUBRATE_FACTOR_MAX) || + !IN_RANGE(param->subrate_max, BT_HCI_LE_SUBRATE_FACTOR_MIN, + BT_HCI_LE_SUBRATE_FACTOR_MAX) || + param->subrate_min > param->subrate_max) { + return false; + } + + if (!IN_RANGE(param->max_latency, 0, BT_HCI_LE_PERIPHERAL_LATENCY_MAX) || + param->subrate_max * (param->max_latency + 1) > 500) { + return false; + } + + if (!IN_RANGE(param->continuation_number, 0, BT_HCI_LE_CONTINUATION_NUM_MAX) || + param->continuation_number >= param->subrate_max) { + return false; + } + + if (!IN_RANGE(param->supervision_timeout_10ms, BT_HCI_LE_SUPERVISON_TIMEOUT_MIN, + BT_HCI_LE_SUPERVISON_TIMEOUT_MAX)) { + return false; + } + + if (!IN_RANGE(param->min_ce_len_125us, BT_HCI_LE_SCI_CE_LEN_MIN_125US, + BT_HCI_LE_SCI_CE_LEN_MAX_125US) || + !IN_RANGE(param->max_ce_len_125us, BT_HCI_LE_SCI_CE_LEN_MIN_125US, + BT_HCI_LE_SCI_CE_LEN_MAX_125US) || + param->max_ce_len_125us < param->min_ce_len_125us) { + return false; + } + + return true; +} + +#if defined(CONFIG_BT_CENTRAL) +int bt_conn_le_conn_rate_set_defaults(const struct bt_conn_le_conn_rate_param *params) +{ + struct bt_hci_op_le_set_default_rate_parameters *cp; + struct net_buf *buf; + + if (params == NULL || !le_conn_rate_common_params_valid(params)) { + return -EINVAL; + } + + buf = bt_hci_cmd_alloc(K_FOREVER); + if (buf == NULL) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->conn_interval_min = sys_cpu_to_le16(params->interval_min_125us); + cp->conn_interval_max = sys_cpu_to_le16(params->interval_max_125us); + cp->subrate_min = sys_cpu_to_le16(params->subrate_min); + cp->subrate_max = sys_cpu_to_le16(params->subrate_max); + cp->max_latency = sys_cpu_to_le16(params->max_latency); + cp->continuation_number = sys_cpu_to_le16(params->continuation_number); + cp->supervision_timeout = sys_cpu_to_le16(params->supervision_timeout_10ms); + cp->min_ce_len = sys_cpu_to_le16(params->min_ce_len_125us); + cp->max_ce_len = sys_cpu_to_le16(params->max_ce_len_125us); + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_DEFAULT_RATE_PARAMETERS, buf, NULL); +} +#endif /* CONFIG_BT_CENTRAL */ + +int bt_conn_le_conn_rate_request(struct bt_conn *conn, + const struct bt_conn_le_conn_rate_param *params) +{ + struct bt_hci_op_le_connection_rate_request *cp; + struct net_buf *buf; + + if (!bt_conn_is_le(conn)) { + LOG_DBG("Invalid connection type: %u for %p", conn->type, conn); + return -EINVAL; + } + + if (params == NULL || !le_conn_rate_common_params_valid(params)) { + return -EINVAL; + } + + buf = bt_hci_cmd_alloc(K_FOREVER); + if (buf == NULL) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + cp->conn_interval_min = sys_cpu_to_le16(params->interval_min_125us); + cp->conn_interval_max = sys_cpu_to_le16(params->interval_max_125us); + cp->subrate_min = sys_cpu_to_le16(params->subrate_min); + cp->subrate_max = sys_cpu_to_le16(params->subrate_max); + cp->max_latency = sys_cpu_to_le16(params->max_latency); + cp->continuation_number = sys_cpu_to_le16(params->continuation_number); + cp->supervision_timeout = sys_cpu_to_le16(params->supervision_timeout_10ms); + cp->min_ce_len = sys_cpu_to_le16(params->min_ce_len_125us); + cp->max_ce_len = sys_cpu_to_le16(params->max_ce_len_125us); + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CONNECTION_RATE_REQUEST, buf, NULL); +} +#endif /* CONFIG_BT_SHORTER_CONNECTION_INTERVALS */ + #if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) void bt_conn_notify_read_all_remote_feat_complete(struct bt_conn *conn, struct bt_conn_le_read_all_remote_feat_complete *params) diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index 06151e21402cb..dd2857079dee0 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -108,7 +108,7 @@ struct bt_conn_le { bt_addr_le_t init_addr; bt_addr_le_t resp_addr; - uint16_t interval; + uint32_t interval_us; uint16_t interval_min; uint16_t interval_max; @@ -538,6 +538,9 @@ void bt_conn_notify_path_loss_threshold_report(struct bt_conn *conn, void bt_conn_notify_subrate_change(struct bt_conn *conn, struct bt_conn_le_subrate_changed params); +void bt_conn_notify_conn_rate_change(struct bt_conn *conn, uint8_t status, + const struct bt_conn_le_conn_rate_changed *params); + void bt_conn_notify_read_all_remote_feat_complete(struct bt_conn *conn, struct bt_conn_le_read_all_remote_feat_complete *params); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 24c7a4c67acc2..f4bc0613ea825 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -1409,7 +1409,7 @@ static void update_conn(struct bt_conn *conn, const bt_addr_le_t *id_addr, { conn->handle = sys_le16_to_cpu(evt->handle); bt_addr_le_copy(&conn->le.dst, id_addr); - conn->le.interval = sys_le16_to_cpu(evt->interval); + conn->le.interval_us = sys_le16_to_cpu(evt->interval) * BT_HCI_LE_INTERVAL_UNIT_US; conn->le.latency = sys_le16_to_cpu(evt->latency); conn->le.timeout = sys_le16_to_cpu(evt->supv_timeout); conn->role = evt->role; @@ -2061,15 +2061,16 @@ static void le_conn_update_complete(struct net_buf *buf) bt_l2cap_update_conn_param(conn, ¶m); } else { if (!evt->status) { - conn->le.interval = sys_le16_to_cpu(evt->interval); + conn->le.interval_us = + sys_le16_to_cpu(evt->interval) * BT_HCI_LE_INTERVAL_UNIT_US; conn->le.latency = sys_le16_to_cpu(evt->latency); conn->le.timeout = sys_le16_to_cpu(evt->supv_timeout); if (!IS_ENABLED(CONFIG_BT_CONN_PARAM_ANY)) { - if (!IN_RANGE(conn->le.interval, BT_HCI_LE_INTERVAL_MIN, - BT_HCI_LE_INTERVAL_MAX)) { - LOG_WRN("interval exceeds the valid range 0x%04x", - conn->le.interval); + if (!IN_RANGE(conn->le.interval_us / BT_HCI_LE_INTERVAL_UNIT_US, + BT_HCI_LE_INTERVAL_MIN, BT_HCI_LE_INTERVAL_MAX)) { + LOG_WRN("interval exceeds the valid range %u us", + conn->le.interval_us); } if (conn->le.latency > BT_HCI_LE_PERIPHERAL_LATENCY_MAX) { LOG_WRN("latency exceeds the valid range 0x%04x", @@ -2808,6 +2809,72 @@ void bt_hci_le_subrate_change_event(struct net_buf *buf) } #endif /* CONFIG_BT_SUBRATING */ +#if defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) +void bt_hci_le_conn_rate_change_event(struct net_buf *buf) +{ + struct bt_hci_evt_le_conn_rate_change *evt; + struct bt_conn_le_conn_rate_changed params; + struct bt_conn *conn; + + evt = net_buf_pull_mem(buf, sizeof(*evt)); + + conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->handle), BT_CONN_TYPE_LE); + if (conn == NULL) { + LOG_ERR("Unknown conn handle 0x%04X for connection rate event", + sys_le16_to_cpu(evt->handle)); + return; + } + + if (evt->status == BT_HCI_ERR_SUCCESS) { + conn->le.interval_us = + BT_CONN_SCI_INTERVAL_TO_US(sys_le16_to_cpu(evt->conn_interval)); + conn->le.subrate.factor = sys_le16_to_cpu(evt->subrate_factor); + conn->le.subrate.continuation_number = sys_le16_to_cpu(evt->continuation_number); + conn->le.latency = sys_le16_to_cpu(evt->peripheral_latency); + conn->le.timeout = sys_le16_to_cpu(evt->supervision_timeout); + + if (!IS_ENABLED(CONFIG_BT_CONN_PARAM_ANY)) { + if (!IN_RANGE(conn->le.interval_us / BT_HCI_LE_SCI_INTERVAL_UNIT_US, + BT_HCI_LE_SCI_INTERVAL_MIN_125US, + BT_HCI_LE_SCI_INTERVAL_MAX_125US)) { + LOG_WRN("interval_us exceeds the valid range %u us", + conn->le.interval_us); + } + if (!IN_RANGE(conn->le.subrate.factor, BT_HCI_LE_SUBRATE_FACTOR_MIN, + BT_HCI_LE_SUBRATE_FACTOR_MAX)) { + LOG_WRN("subrate_factor exceeds the valid range %d", + conn->le.subrate.factor); + } + if (conn->le.latency > BT_HCI_LE_PERIPHERAL_LATENCY_MAX) { + LOG_WRN("peripheral_latency exceeds the valid range 0x%04x", + conn->le.latency); + } + if (conn->le.subrate.continuation_number > BT_HCI_LE_CONTINUATION_NUM_MAX) { + LOG_WRN("continuation_number exceeds the valid range %d", + conn->le.subrate.continuation_number); + } + if (!IN_RANGE(conn->le.timeout, BT_HCI_LE_SUPERVISON_TIMEOUT_MIN, + BT_HCI_LE_SUPERVISON_TIMEOUT_MAX)) { + LOG_WRN("supervision_timeout exceeds the valid range 0x%04x", + conn->le.timeout); + } + } + + params.interval_us = conn->le.interval_us; + params.subrate_factor = conn->le.subrate.factor; + params.continuation_number = conn->le.subrate.continuation_number; + params.peripheral_latency = conn->le.latency; + params.supervision_timeout_10ms = conn->le.timeout; + + bt_conn_notify_conn_rate_change(conn, evt->status, ¶ms); + } else { + bt_conn_notify_conn_rate_change(conn, evt->status, NULL); + } + + bt_conn_unref(conn); +} +#endif /* CONFIG_BT_SHORTER_CONNECTION_INTERVALS */ + static const struct event_handler vs_events[] = { #if defined(CONFIG_BT_DF_VS_CL_IQ_REPORT_16_BITS_IQ_SAMPLES) EVENT_HANDLER(BT_HCI_EVT_VS_LE_CONNECTIONLESS_IQ_REPORT, @@ -2958,7 +3025,11 @@ static const struct event_handler meta_events[] = { #if defined(CONFIG_BT_SUBRATING) EVENT_HANDLER(BT_HCI_EVT_LE_SUBRATE_CHANGE, bt_hci_le_subrate_change_event, sizeof(struct bt_hci_evt_le_subrate_change)), -#endif /* CONFIG_BT_PATH_LOSS_MONITORING */ +#endif /* CONFIG_BT_SUBRATING */ +#if defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) + EVENT_HANDLER(BT_HCI_EVT_LE_CONN_RATE_CHANGE, bt_hci_le_conn_rate_change_event, + sizeof(struct bt_hci_evt_le_conn_rate_change)), +#endif /* CONFIG_BT_SHORTER_CONNECTION_INTERVALS */ #if defined(CONFIG_BT_PER_ADV_SYNC_RSP) EVENT_HANDLER(BT_HCI_EVT_LE_PER_ADVERTISING_REPORT_V2, bt_hci_le_per_adv_report_v2, sizeof(struct bt_hci_evt_le_per_advertising_report_v2)), @@ -3571,6 +3642,11 @@ static int le_set_event_mask(void) mask |= BT_EVT_MASK_LE_SUBRATE_CHANGE; } + if (IS_ENABLED(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) && + BT_FEAT_LE_SHORTER_CONN_INTERVALS(bt_dev.le.features)) { + mask |= BT_EVT_MASK_LE_CONN_RATE_CHANGE; + } + if (IS_ENABLED(CONFIG_BT_LE_EXTENDED_FEAT_SET) && BT_FEAT_LE_EXTENDED_FEAT_SET(bt_dev.le.features)) { mask |= BT_EVT_MASK_LE_READ_ALL_REMOTE_FEAT_COMPLETE; @@ -3885,6 +3961,14 @@ static int le_init(void) } } + if (IS_ENABLED(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) && + BT_FEAT_LE_SHORTER_CONN_INTERVALS(bt_dev.le.features)) { + err = le_set_host_feature(BT_LE_FEAT_BIT_SHORTER_CONN_INTERVALS_HOST_SUPP, 1); + if (err != 0) { + return err; + } + } + return le_set_event_mask(); } diff --git a/subsys/bluetooth/host/shell/bt.c b/subsys/bluetooth/host/shell/bt.c index 816b6549853b0..21302647bdf78 100644 --- a/subsys/bluetooth/host/shell/bt.c +++ b/subsys/bluetooth/host/shell/bt.c @@ -1009,7 +1009,30 @@ void subrate_changed(struct bt_conn *conn, bt_shell_print("Subrate change failed (HCI status 0x%02x)", params->status); } } -#endif + +#if defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) +static void conn_rate_changed(struct bt_conn *conn, uint8_t status, + const struct bt_conn_le_conn_rate_changed *params) +{ + if (status == BT_HCI_ERR_SUCCESS) { + bt_shell_print("Connection rate parameters changed: " + "Connection Interval: %u us " + "Subrate Factor: %d " + "Peripheral latency: 0x%04x " + "Continuation Number: %d " + "Supervision timeout: 0x%04x (%d ms)", + params->interval_us, + params->subrate_factor, + params->peripheral_latency, + params->continuation_number, + params->supervision_timeout_10ms, + params->supervision_timeout_10ms * 10); + } else { + bt_shell_print("Connection rate change failed (HCI status 0x%02x)", status); + } +} +#endif /* CONFIG_BT_SHORTER_CONNECTION_INTERVALS */ +#endif /* CONFIG_BT_SUBRATING */ #if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) void read_all_remote_feat_complete(struct bt_conn *conn, @@ -1255,6 +1278,9 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { #if defined(CONFIG_BT_SUBRATING) .subrate_changed = subrate_changed, #endif +#if defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) + .conn_rate_changed = conn_rate_changed, +#endif #if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) .read_all_remote_feat_complete = read_all_remote_feat_complete, #endif @@ -3361,7 +3387,130 @@ static int cmd_subrate_request(const struct shell *sh, size_t argc, char *argv[] return 0; } -#endif + +#if defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) +static int cmd_read_min_conn_interval_groups(const struct shell *sh, size_t argc, char *argv[]) +{ + int err; + struct bt_conn_le_min_conn_interval_info info; + + err = bt_conn_le_read_min_conn_interval_groups(&info); + if (err != 0) { + shell_error(sh, "bt_conn_le_read_min_conn_interval_groups returned error %d", err); + return -ENOEXEC; + } + + shell_print(sh, "Minimum supported connection interval: %u us", + info.min_supported_conn_interval_us); + shell_print(sh, "Number of groups: %u", info.num_groups); + + for (uint8_t i = 0; i < info.num_groups; i++) { + shell_print( + sh, + " Group %u: min=0x%04x (%u us), max=0x%04x (%u us), stride=0x%04x (%u us)", + i, + info.groups[i].min_125us, + BT_CONN_SCI_INTERVAL_TO_US(info.groups[i].min_125us), + info.groups[i].max_125us, + BT_CONN_SCI_INTERVAL_TO_US(info.groups[i].max_125us), + info.groups[i].stride_125us, + BT_CONN_SCI_INTERVAL_TO_US(info.groups[i].stride_125us)); + } + + return 0; +} + +static int cmd_read_min_conn_interval(const struct shell *sh, size_t argc, char *argv[]) +{ + int err; + uint16_t min_interval_us; + + err = bt_conn_le_read_min_conn_interval(&min_interval_us); + if (err != 0) { + shell_error(sh, "bt_conn_le_read_min_conn_interval returned error %d", err); + return -ENOEXEC; + } + + shell_print(sh, "Minimum supported connection interval: %u us", min_interval_us); + return 0; +} + +static int cmd_conn_rate_set_defaults(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + + for (size_t argn = 1; argn < argc; argn++) { + (void)shell_strtoul(argv[argn], 10, &err); + + if (err != 0) { + shell_help(sh); + shell_error(sh, "Could not parse input number %zu", argn); + return SHELL_CMD_HELP_PRINTED; + } + } + + const struct bt_conn_le_conn_rate_param params = { + .interval_min_125us = shell_strtoul(argv[1], 10, &err), + .interval_max_125us = shell_strtoul(argv[2], 10, &err), + .subrate_min = shell_strtoul(argv[3], 10, &err), + .subrate_max = shell_strtoul(argv[4], 10, &err), + .max_latency = shell_strtoul(argv[5], 10, &err), + .continuation_number = shell_strtoul(argv[6], 10, &err), + .supervision_timeout_10ms = shell_strtoul(argv[7], 10, &err), + .min_ce_len_125us = shell_strtoul(argv[8], 10, &err), + .max_ce_len_125us = shell_strtoul(argv[9], 10, &err), + }; + + err = bt_conn_le_conn_rate_set_defaults(¶ms); + if (err != 0) { + shell_error(sh, "bt_conn_le_conn_rate_set_defaults returned error %d", err); + return -ENOEXEC; + } + + return 0; +} + +static int cmd_conn_rate_request(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + + if (default_conn == NULL) { + shell_error(sh, "Conn handle error, at least one connection is required."); + return -ENOEXEC; + } + + for (size_t argn = 1; argn < argc; argn++) { + (void)shell_strtoul(argv[argn], 10, &err); + + if (err != 0) { + shell_help(sh); + shell_error(sh, "Could not parse input number %zu", argn); + return SHELL_CMD_HELP_PRINTED; + } + } + + const struct bt_conn_le_conn_rate_param params = { + .interval_min_125us = shell_strtoul(argv[1], 10, &err), + .interval_max_125us = shell_strtoul(argv[2], 10, &err), + .subrate_min = shell_strtoul(argv[3], 10, &err), + .subrate_max = shell_strtoul(argv[4], 10, &err), + .max_latency = shell_strtoul(argv[5], 10, &err), + .continuation_number = shell_strtoul(argv[6], 10, &err), + .supervision_timeout_10ms = shell_strtoul(argv[7], 10, &err), + .min_ce_len_125us = shell_strtoul(argv[8], 10, &err), + .max_ce_len_125us = shell_strtoul(argv[9], 10, &err), + }; + + err = bt_conn_le_conn_rate_request(default_conn, ¶ms); + if (err != 0) { + shell_error(sh, "bt_conn_le_conn_rate_request returned error %d", err); + return -ENOEXEC; + } + + return 0; +} +#endif /* CONFIG_BT_SHORTER_CONNECTION_INTERVALS */ +#endif /* CONFIG_BT_SUBRATING */ #if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) static int cmd_read_all_remote_features(const struct shell *sh, size_t argc, char *argv[]) @@ -3714,9 +3863,7 @@ static int cmd_info(const struct shell *sh, size_t argc, char *argv[]) print_le_addr("Remote on-air", info.le.remote); print_le_addr("Local on-air", info.le.local); - shell_print(sh, "Interval: 0x%04x (%u us)", - info.le.interval, - BT_CONN_INTERVAL_TO_US(info.le.interval)); + shell_print(sh, "Interval: %u us", info.le.interval_us); shell_print(sh, "Latency: 0x%04x", info.le.latency); shell_print(sh, "Supervision timeout: 0x%04x (%d ms)", @@ -4138,9 +4285,9 @@ static void connection_info(struct bt_conn *conn, void *user_data) #endif case BT_CONN_TYPE_LE: bt_addr_le_to_str(info.le.dst, addr, sizeof(addr)); - bt_shell_print("%s#%u [LE][%s] %s: Interval %u latency %u timeout %u", selected, - info.id, role_str, addr, info.le.interval, info.le.latency, - info.le.timeout); + bt_shell_print("%s#%u [LE][%s] %s: Interval %u us, latency %u, timeout %u ms", + selected, info.id, role_str, addr, info.le.interval_us, + info.le.latency, info.le.timeout * 10); break; #if defined(CONFIG_BT_ISO) case BT_CONN_TYPE_ISO: @@ -5211,7 +5358,25 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, " " " ", cmd_subrate_request, 6, 0), -#endif +#if defined(CONFIG_BT_SHORTER_CONNECTION_INTERVALS) + SHELL_CMD_ARG(read-min-conn-interval-groups, NULL, + "Read minimum supported connection interval and groups", + cmd_read_min_conn_interval_groups, 1, 0), + SHELL_CMD_ARG(read-min-conn-interval, NULL, + "Read minimum supported connection interval only", + cmd_read_min_conn_interval, 1, 0), + SHELL_CMD_ARG(conn-rate-set-defaults, NULL, + " " + " " + " ", + cmd_conn_rate_set_defaults, 10, 0), + SHELL_CMD_ARG(conn-rate-request, NULL, + " " + " " + " ", + cmd_conn_rate_request, 10, 0), +#endif /* CONFIG_BT_SHORTER_CONNECTION_INTERVALS */ +#endif /* CONFIG_BT_SUBRATING */ #if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) SHELL_CMD_ARG(read-all-remote-features, NULL, "", cmd_read_all_remote_features, 2, 0), diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index a326c7b1495fb..4aca7cee1c110 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -667,7 +667,7 @@ ZTEST_F(ascs_test_suite, test_ase_state_notification_retry) zassert_equal(err, 0); /* Wait for ASE state notification retry */ - k_sleep(K_MSEC(BT_CONN_INTERVAL_TO_MS(info.le.interval))); + k_sleep(K_USEC(info.le.interval_us)); expect_bt_bap_stream_ops_configured_called_once(stream, EMPTY); } diff --git a/tests/bluetooth/audio/ascs/src/test_common.c b/tests/bluetooth/audio/ascs/src/test_common.c index b09677592f46f..f97840fe40acb 100644 --- a/tests/bluetooth/audio/ascs/src/test_common.c +++ b/tests/bluetooth/audio/ascs/src/test_common.c @@ -77,7 +77,7 @@ void test_conn_init(struct bt_conn *conn) conn->info.security.level = BT_SECURITY_L2; conn->info.security.enc_key_size = BT_ENC_KEY_SIZE_MAX; conn->info.security.flags = BT_SECURITY_FLAG_OOB | BT_SECURITY_FLAG_SC; - conn->info.le.interval = BT_GAP_INIT_CONN_INT_MIN; + conn->info.le.interval_us = BT_GAP_INIT_CONN_INT_MIN * BT_HCI_LE_INTERVAL_UNIT_US; } const struct bt_gatt_attr *test_ase_control_point_get(void) diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index 783d3a670e1ee..5e4984e2d509b 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -46,6 +46,13 @@ tests: - CONFIG_BT_LE_EXTENDED_FEAT_SET=y - CONFIG_BT_LL_SW_SPLIT=n build_only: true + bluetooth.shell.shorter_connection_intervals: + extra_configs: + - CONFIG_BT_SHORTER_CONNECTION_INTERVALS=y + - CONFIG_BT_LE_EXTENDED_FEAT_SET=y + - CONFIG_BT_SUBRATING=y + - CONFIG_BT_LL_SW_SPLIT=n + build_only: true bluetooth.shell.channel_sounding: extra_configs: - CONFIG_BT_CHANNEL_SOUNDING=y diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c index bc8de31e1451c..4d0867b5a33f8 100644 --- a/tests/bluetooth/tester/src/btp_gap.c +++ b/tests/bluetooth/tester/src/btp_gap.c @@ -135,7 +135,7 @@ static void le_connected(struct bt_conn *conn, uint8_t err) if (bt_conn_is_type(conn, BT_CONN_TYPE_LE)) { bt_addr_le_copy(&ev.address, info.le.dst); - ev.interval = sys_cpu_to_le16(info.le.interval); + ev.interval = sys_cpu_to_le16(info.le.interval_us / BT_HCI_LE_INTERVAL_UNIT_US); ev.latency = sys_cpu_to_le16(info.le.latency); ev.timeout = sys_cpu_to_le16(info.le.timeout); } else if (IS_ENABLED(CONFIG_BT_CLASSIC) && bt_conn_is_type(conn, BT_CONN_TYPE_BR)) {