diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index 8d2ceebf6cb6..1b5576d94669 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -784,6 +784,40 @@ enum { * @note Mutually exclusive with BT_LE_ADV_OPT_USE_IDENTITY. */ BT_LE_ADV_OPT_USE_NRPA = BIT(19), + + /** + * @brief Configures the advertiser to use the S=2 coding scheme for + * LE Coded PHY. + * + * Sets the advertiser's required coding scheme to S=2, which is one + * of the coding options available for LE Coded PHY. The S=2 coding + * scheme offers higher data rates compared to S=8, with a trade-off + * of reduced range. The coding scheme will only be set if both the + * primary and secondary advertising channels indicate LE Coded Phy. + * Additionally, the Controller must support the LE Feature Advertising + * Coding Selection. If these conditions are not met, it will default to + * no required coding scheme. + * + * @note Requires @kconfig{BT_EXT_ADV_CODING_SELECTION} + */ + BT_LE_ADV_OPT_REQUIRE_S2_CODING = BIT(20), + + /** + * @brief Configures the advertiser to use the S=8 coding scheme for + * LE Coded PHY. + * + * Sets the advertiser's required coding scheme to S=8, which is one + * of the coding options available for LE Coded PHY. The S=8 coding + * scheme offers increased range compared to S=2, with a trade-off + * of lower data rates. The coding scheme will only be set if both the + * primary and secondary advertising channels indicate LE Coded Phy. + * Additionally, the Controller must support the LE Feature Advertising + * Coding Selection. If these conditions are not met, it will default to + * no required coding scheme. + * + * @note Requires @kconfig{BT_EXT_ADV_CODING_SELECTION} + */ + BT_LE_ADV_OPT_REQUIRE_S8_CODING = BIT(21), }; /** LE Advertising Parameters. */ diff --git a/include/zephyr/bluetooth/gap.h b/include/zephyr/bluetooth/gap.h index 1b1569e30031..2582d9fb96c2 100644 --- a/include/zephyr/bluetooth/gap.h +++ b/include/zephyr/bluetooth/gap.h @@ -747,8 +747,16 @@ enum { BT_GAP_LE_PHY_1M = BIT(0), /** LE 2M PHY */ BT_GAP_LE_PHY_2M = BIT(1), - /** LE Coded PHY */ + /** LE Coded PHY, coding scheme not specified */ BT_GAP_LE_PHY_CODED = BIT(2), + /** LE Coded S=8 PHY. Only used for advertising reports + * when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled. + */ + BT_GAP_LE_PHY_CODED_S8 = BIT(3), + /** LE Coded S=2 PHY. Only used for advertising reports + * when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled. + */ + BT_GAP_LE_PHY_CODED_S2 = BIT(4), }; /** Advertising PDU types */ diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 9f3120490077..9717e8ed7368 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -198,6 +198,8 @@ struct bt_hci_cmd_hdr { #define BT_LE_FEAT_BIT_CONN_SUBRATING 37 #define BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP 38 #define BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION 39 +#define BT_LE_FEAT_BIT_ADV_CODING_SEL 40 +#define BT_LE_FEAT_BIT_ADV_CODING_SEL_HOST 41 #define BT_LE_FEAT_BIT_PAWR_ADVERTISER 43 #define BT_LE_FEAT_BIT_PAWR_SCANNER 44 @@ -268,6 +270,10 @@ struct bt_hci_cmd_hdr { BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP) #define BT_FEAT_LE_CHANNEL_CLASSIFICATION(feat) BT_LE_FEAT_TEST(feat, \ BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION) +#define BT_FEAT_LE_ADV_CODING_SEL(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ADV_CODING_SEL) +#define BT_FEAT_LE_ADV_CODING_SEL_HOST(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ADV_CODING_SEL_HOST) #define BT_FEAT_LE_PAWR_ADVERTISER(feat) BT_LE_FEAT_TEST(feat, \ BT_LE_FEAT_BIT_PAWR_ADVERTISER) #define BT_FEAT_LE_PAWR_SCANNER(feat) BT_LE_FEAT_TEST(feat, \ @@ -1538,6 +1544,30 @@ struct bt_hci_rp_le_set_ext_adv_param { int8_t tx_power; } __packed; +#define BT_HCI_LE_ADV_PHY_OPTION_NO_REQUIRED 0x00 +#define BT_HCI_LE_ADV_PHY_OPTION_REQUIRE_S2 0x03 +#define BT_HCI_LE_ADV_PHY_OPTION_REQUIRE_S8 0x04 + +#define BT_HCI_OP_LE_SET_EXT_ADV_PARAM_V2 BT_OP(BT_OGF_LE, 0x007F) /* 0x207F */ +struct bt_hci_cp_le_set_ext_adv_param_v2 { + uint8_t handle; + uint16_t props; + uint8_t prim_min_interval[3]; + uint8_t prim_max_interval[3]; + uint8_t prim_channel_map; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t filter_policy; + int8_t tx_power; + uint8_t prim_adv_phy; + uint8_t sec_adv_max_skip; + uint8_t sec_adv_phy; + uint8_t sid; + uint8_t scan_req_notify_enable; + uint8_t prim_adv_phy_opt; + uint8_t sec_adv_phy_opt; +} __packed; + #define BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG 0x00 #define BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG 0x01 #define BT_HCI_LE_EXT_ADV_OP_LAST_FRAG 0x02 @@ -3173,6 +3203,14 @@ struct bt_hci_evt_le_phy_update_complete { #define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 #define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_RX_FAILED 0xFF +/* Advertising Coding Selection extended advertising report PHY values. + * Only used when Kconfig BT_EXT_ADV_CODING_SELECTION is enabled. + */ +#define BT_HCI_LE_ADV_EVT_PHY_1M 0x01 +#define BT_HCI_LE_ADV_EVT_PHY_2M 0x02 +#define BT_HCI_LE_ADV_EVT_PHY_CODED_S8 0x03 +#define BT_HCI_LE_ADV_EVT_PHY_CODED_S2 0x04 + struct bt_hci_evt_le_ext_advertising_info { uint16_t evt_type; bt_addr_le_t addr; diff --git a/subsys/bluetooth/Kconfig.adv b/subsys/bluetooth/Kconfig.adv index 99b40250a949..28e1dea61a24 100644 --- a/subsys/bluetooth/Kconfig.adv +++ b/subsys/bluetooth/Kconfig.adv @@ -68,6 +68,14 @@ config BT_PER_ADV_SYNC_RSP Select this to enable Periodic Advertising with Responses Sync API support. +config BT_EXT_ADV_CODING_SELECTION + bool "Advertising Coding Selection support" + depends on !HAS_BT_CTLR || BT_CTLR_PHY_CODED + help + Select this to enable Advertising Coding Selection API support. + This allows the Host to indicate their strict requirement + concerning coding scheme when using Extended Advertising. + if BT_PER_ADV_SYNC config BT_PER_ADV_SYNC_MAX diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 4953343ba3c9..3360db0abc19 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -45,6 +45,10 @@ config BT_CTLR_PHY_CODED_SUPPORT config BT_CTLR_ADV_EXT_SUPPORT bool +config BT_CTLR_ADV_EXT_CODING_SELECTION_SUPPORT + depends on BT_CTLR_PHY_CODED_SUPPORT + bool + config BT_CTLR_ADV_PERIODIC_SUPPORT depends on BT_CTLR_ADV_EXT_SUPPORT bool @@ -742,6 +746,15 @@ config BT_CTLR_ADV_PERIODIC_RSP Enable support for Bluetooth 5.4 LE Periodic Advertising with Responses in the Controller. +config BT_CTLR_ADV_EXT_CODING_SELECTION + bool "Advertising Coding Selection support" + depends on BT_CTLR_PHY_CODED && BT_CTLR_ADV_EXT_CODING_SELECTION_SUPPORT + select BT_CTLR_SET_HOST_FEATURE if BT_OBSERVER + default y if BT_EXT_ADV_CODING_SELECTION + help + Enable support for Bluetooth 6.0 Advertising Coding Selection + in the Controller. + if BT_CTLR_ADV_PERIODIC config BT_CTLR_ADV_PERIODIC_ADI_SUPPORT diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index db71858f8f22..d99144a420de 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -1121,20 +1121,32 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, const struct bt_le_adv_param *param, bool has_scan_data) { - struct bt_hci_cp_le_set_ext_adv_param *cp; + struct bt_hci_cp_le_set_ext_adv_param_v2 *cp; + + uint16_t opcode; + uint16_t size; bool dir_adv = param->peer != NULL, scannable; struct net_buf *buf, *rsp; int err; enum adv_name_type name_type; uint16_t props = 0; - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_EXT_ADV_PARAM, sizeof(*cp)); + if (IS_ENABLED(CONFIG_BT_EXT_ADV_CODING_SELECTION) && + BT_FEAT_LE_ADV_CODING_SEL(bt_dev.le.features)) { + opcode = BT_HCI_OP_LE_SET_EXT_ADV_PARAM_V2; + size = sizeof(struct bt_hci_cp_le_set_ext_adv_param_v2); + } else { + opcode = BT_HCI_OP_LE_SET_EXT_ADV_PARAM; + size = sizeof(struct bt_hci_cp_le_set_ext_adv_param); + } + + buf = bt_hci_cmd_create(opcode, size); if (!buf) { return -ENOBUFS; } - cp = net_buf_add(buf, sizeof(*cp)); - (void)memset(cp, 0, sizeof(*cp)); + cp = net_buf_add(buf, size); + (void)memset(cp, 0, size); adv->options = param->options; @@ -1171,6 +1183,22 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, if (param->options & BT_LE_ADV_OPT_CODED) { cp->prim_adv_phy = BT_HCI_LE_PHY_CODED; cp->sec_adv_phy = BT_HCI_LE_PHY_CODED; + + if (IS_ENABLED(CONFIG_BT_EXT_ADV_CODING_SELECTION) && + opcode == BT_HCI_OP_LE_SET_EXT_ADV_PARAM_V2) { + uint8_t adv_phy_opt; + + if (param->options & BT_LE_ADV_OPT_REQUIRE_S8_CODING) { + adv_phy_opt = BT_HCI_LE_ADV_PHY_OPTION_REQUIRE_S8; + } else if (param->options & BT_LE_ADV_OPT_REQUIRE_S2_CODING) { + adv_phy_opt = BT_HCI_LE_ADV_PHY_OPTION_REQUIRE_S2; + } else { + adv_phy_opt = BT_HCI_LE_ADV_PHY_OPTION_NO_REQUIRED; + } + + cp->prim_adv_phy_opt = adv_phy_opt; + cp->sec_adv_phy_opt = adv_phy_opt; + } } if (!(param->options & BT_LE_ADV_OPT_EXT_ADV)) { @@ -1222,7 +1250,7 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, cp->sec_adv_max_skip = param->secondary_max_skip; cp->props = sys_cpu_to_le16(props); - err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_EXT_ADV_PARAM, buf, &rsp); + err = bt_hci_cmd_send_sync(opcode, buf, &rsp); if (err) { return err; } diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 4701a69b0d54..7c1d1376d065 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -3682,6 +3682,14 @@ static int le_init(void) } } + if (IS_ENABLED(CONFIG_BT_EXT_ADV_CODING_SELECTION) && + BT_FEAT_LE_ADV_CODING_SEL(bt_dev.le.features)) { + err = le_set_host_feature(BT_LE_FEAT_BIT_ADV_CODING_SEL_HOST, 1); + if (err) { + return err; + } + } + return le_set_event_mask(); } diff --git a/subsys/bluetooth/host/scan.c b/subsys/bluetooth/host/scan.c index 05ad120fb38c..c3551c2ef078 100644 --- a/subsys/bluetooth/host/scan.c +++ b/subsys/bluetooth/host/scan.c @@ -741,6 +741,28 @@ static uint8_t get_adv_type(uint8_t evt_type) } } +/* Convert Extended adv report PHY to GAP PHY */ +static uint8_t get_ext_adv_coding_sel_phy(uint8_t hci_phy) +{ + /* Converts from Extended adv report PHY to BT_GAP_LE_PHY_* + * When Advertising Coding Selection (Host Support) is enabled + * the controller will return the advertising coding scheme which + * can be S=2 or S=8 data coding. + */ + switch (hci_phy) { + case BT_HCI_LE_ADV_EVT_PHY_1M: + return BT_GAP_LE_PHY_1M; + case BT_HCI_LE_ADV_EVT_PHY_2M: + return BT_GAP_LE_PHY_2M; + case BT_HCI_LE_ADV_EVT_PHY_CODED_S8: + return BT_GAP_LE_PHY_CODED_S8; + case BT_HCI_LE_ADV_EVT_PHY_CODED_S2: + return BT_GAP_LE_PHY_CODED_S2; + default: + return 0; + } +} + /* Convert extended adv report evt_type field to adv props */ static uint16_t get_adv_props_extended(uint16_t evt_type) { @@ -755,8 +777,15 @@ static uint16_t get_adv_props_extended(uint16_t evt_type) static void create_ext_adv_info(struct bt_hci_evt_le_ext_advertising_info const *const evt, struct bt_le_scan_recv_info *const scan_info) { - scan_info->primary_phy = bt_get_phy(evt->prim_phy); - scan_info->secondary_phy = bt_get_phy(evt->sec_phy); + if (IS_ENABLED(CONFIG_BT_EXT_ADV_CODING_SELECTION) && + BT_FEAT_LE_ADV_CODING_SEL(bt_dev.le.features)) { + scan_info->primary_phy = get_ext_adv_coding_sel_phy(evt->prim_phy); + scan_info->secondary_phy = get_ext_adv_coding_sel_phy(evt->sec_phy); + } else { + scan_info->primary_phy = bt_get_phy(evt->prim_phy); + scan_info->secondary_phy = bt_get_phy(evt->sec_phy); + } + scan_info->tx_power = evt->tx_power; scan_info->rssi = evt->rssi; scan_info->sid = evt->sid; diff --git a/tests/bluetooth/init/prj_host_6_x.conf b/tests/bluetooth/init/prj_host_6_x.conf new file mode 100644 index 000000000000..033794e2b362 --- /dev/null +++ b/tests/bluetooth/init/prj_host_6_x.conf @@ -0,0 +1,9 @@ +CONFIG_BT=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_EXT_ADV=y +CONFIG_BT_CTLR_PHY_CODED=y +CONFIG_BT_EXT_ADV_CODING_SELECTION=y +CONFIG_ZTEST=y diff --git a/tests/bluetooth/init/testcase.yaml b/tests/bluetooth/init/testcase.yaml index 778049c511a9..a5cc40cd39e7 100644 --- a/tests/bluetooth/init/testcase.yaml +++ b/tests/bluetooth/init/testcase.yaml @@ -402,3 +402,10 @@ tests: - SNIPPET="bt-ll-sw-split" platform_allow: - nrf52840dk/nrf52840 + bluetooth.init.test_host_6_x: + extra_args: CONF_FILE=prj_host_6_x.conf + platform_allow: + - qemu_cortex_m3 + - nrf52840dk/nrf52840 + integration_platforms: + - nrf52840dk/nrf52840