diff --git a/include/zephyr/bluetooth/cs.h b/include/zephyr/bluetooth/cs.h new file mode 100644 index 00000000000000..903f32eccb0391 --- /dev/null +++ b/include/zephyr/bluetooth/cs.h @@ -0,0 +1,86 @@ +/** @file + * @brief Bluetooth Channel Sounding handling + */ + +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_CS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_CS_H_ + +/** + * @brief Channel Sounding (CS) + * @defgroup bt_cs Channel Sounding (CS) + * @ingroup bluetooth + * @{ + */ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum bt_cs_sync_antenna_selection_opt { + /** Use antenna identifier 1 for CS_SYNC packets. */ + BT_CS_ANTENNA_SELECTION_OPT_ONE = BT_HCI_OP_LE_CS_ANTENNA_SEL_ONE, + /** Use antenna identifier 2 for CS_SYNC packets. */ + BT_CS_ANTENNA_SELECTION_OPT_TWO = BT_HCI_OP_LE_CS_ANTENNA_SEL_TWO, + /** Use antenna identifier 3 for CS_SYNC packets. */ + BT_CS_ANTENNA_SELECTION_OPT_THREE = BT_HCI_OP_LE_CS_ANTENNA_SEL_THREE, + /** Use antenna identifier 4 for CS_SYNC packets. */ + BT_CS_ANTENNA_SELECTION_OPT_FOUR = BT_HCI_OP_LE_CS_ANTENNA_SEL_FOUR, + /** Use antennas in repetitive order from 1 to 4 for CS_SYNC packets. */ + BT_CS_ANTENNA_SELECTION_OPT_REPETITIVE = BT_HCI_OP_LE_CS_ANTENNA_SEL_REP, + /** No recommendation for local controller antenna selection. */ + BT_CS_ANTENNA_SELECTION_OPT_NO_RECOMMENDATION = BT_HCI_OP_LE_CS_ANTENNA_SEL_NONE, +}; + +/** Default CS settings in the local Controller */ +struct bt_cs_set_default_settings_param { + /** Enable CS initiator role. */ + bool enable_initiator_role; + /** Enable CS reflector role. */ + bool enable_reflector_role; + /** Antenna identifier to be used for CS_SYNC packets by the local controller. + */ + enum bt_cs_sync_antenna_selection_opt cs_sync_antenna_selection; + /** Maximum output power (Effective Isotropic Radiated Power) to be used + * for all CS transmissions. + * + * Value range is @ref BT_HCI_OP_LE_CS_MIN_MAX_TX_POWER to + * @ref BT_HCI_OP_LE_CS_MAX_MAX_TX_POWER. + */ + int8_t max_tx_power; +}; + +/** @brief Set Channel Sounding default settings. + * + * This command is used to set default Channel Sounding settings for this + * connection. + * + * @note To use this API @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set. + * + * @param conn Connection Object. + * @param params Channel sounding default settings parameters. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_cs_set_default_settings(struct bt_conn *conn, + const struct bt_cs_set_default_settings_param *params); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_CS_H_ */ diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 83bd3a55d4c059..afdb03f0ce9bfa 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -2395,6 +2395,28 @@ struct bt_hci_cp_le_tx_test_v4_tx_power { int8_t tx_power; } __packed; +#define BT_HCI_OP_LE_CS_SET_DEFAULT_SETTINGS BT_OP(BT_OGF_LE, 0x008D) /* 0x208D */ + +#define BT_HCI_OP_LE_CS_INITIATOR_ROLE_MASK BIT(0) +#define BT_HCI_OP_LE_CS_REFLECTOR_ROLE_MASK BIT(1) + +#define BT_HCI_OP_LE_CS_MIN_MAX_TX_POWER -127 +#define BT_HCI_OP_LE_CS_MAX_MAX_TX_POWER 20 + +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_ONE 0x01 +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_TWO 0x02 +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_THREE 0x03 +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_FOUR 0x04 +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_REP 0xFE +#define BT_HCI_OP_LE_CS_ANTENNA_SEL_NONE 0xFF + +struct bt_hci_cp_le_cs_set_default_settings { + uint16_t handle; + uint8_t role_enable; + uint8_t cs_sync_antenna_selection; + int8_t max_tx_power; +} __packed; + /* Event definitions */ #define BT_HCI_EVT_UNKNOWN 0x00 diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index fad998375bd808..e8c7d9676d74b6 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -189,6 +189,13 @@ config BT_SUBRATING Enable support for LE Connection Subrating feature that is defined in the Bluetooth Core specification, Version 5.4 | Vol 6, Part B, Section 4.6.35. +config BT_CHANNEL_SOUNDING + bool "Channel Sounding support" + select EXPERIMENTAL + depends on !BT_CTLR || BT_CTLR_CHANNEL_SOUNDING_SUPPORT + help + Enable support for Bluetooth 6.0 Channel Sounding feature. + endif # BT_CONN rsource "Kconfig.iso" diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index f6aaba31fab8c9..78c127c235a9b9 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -118,6 +118,9 @@ config BT_CTLR_LE_PATH_LOSS_MONITORING_SUPPORT config BT_CTLR_SUBRATING_SUPPORT bool +config BT_CTLR_CHANNEL_SOUNDING_SUPPORT + bool + config BT_CTLR bool "Bluetooth Controller" help @@ -1069,6 +1072,15 @@ config BT_CTLR_SUBRATING Enable support for Bluetooth v5.3 LE Connection Subrating in the Controller. +config BT_CTLR_CHANNEL_SOUNDING + bool "Channel Sounding support" + depends on BT_CTLR_CHANNEL_SOUNDING_SUPPORT + select BT_CTLR_SET_HOST_FEATURE + default y if BT_CHANNEL_SOUNDING + help + Enable support for Bluetooth 6.0 Channel Sounding in the + Controller. + rsource "Kconfig.df" rsource "Kconfig.ll_sw_split" rsource "Kconfig.dtm" diff --git a/subsys/bluetooth/host/CMakeLists.txt b/subsys/bluetooth/host/CMakeLists.txt index 1b1b6a58543698..860e9cc7d74609 100644 --- a/subsys/bluetooth/host/CMakeLists.txt +++ b/subsys/bluetooth/host/CMakeLists.txt @@ -68,6 +68,11 @@ if(CONFIG_BT_HCI_HOST) conn.c ) + zephyr_library_sources_ifdef( + CONFIG_BT_CHANNEL_SOUNDING + cs.c + ) + if(CONFIG_BT_DF) zephyr_library_sources( direction.c diff --git a/subsys/bluetooth/host/cs.c b/subsys/bluetooth/host/cs.c new file mode 100644 index 00000000000000..4ec67fd42cea38 --- /dev/null +++ b/subsys/bluetooth/host/cs.c @@ -0,0 +1,44 @@ +/* cs.c - Bluetooth Channel Sounding handling */ + +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "conn_internal.h" + +#if defined(CONFIG_BT_CHANNEL_SOUNDING) +int bt_cs_set_default_settings(struct bt_conn *conn, + const struct bt_cs_set_default_settings_param *params) +{ + struct bt_hci_cp_le_cs_set_default_settings *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CS_SET_DEFAULT_SETTINGS, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + cp->max_tx_power = params->max_tx_power; + cp->cs_sync_antenna_selection = params->cs_sync_antenna_selection; + cp->role_enable = 0; + + if (params->enable_initiator_role) { + cp->role_enable |= BT_HCI_OP_LE_CS_INITIATOR_ROLE_MASK; + } + + if (params->enable_reflector_role) { + cp->role_enable |= BT_HCI_OP_LE_CS_REFLECTOR_ROLE_MASK; + } + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_SET_DEFAULT_SETTINGS, buf, NULL); +} +#endif /* CONFIG_BT_CHANNEL_SOUNDING */ diff --git a/subsys/bluetooth/shell/CMakeLists.txt b/subsys/bluetooth/shell/CMakeLists.txt index 58d3ba5b2d951e..f6cc40e6d4a063 100644 --- a/subsys/bluetooth/shell/CMakeLists.txt +++ b/subsys/bluetooth/shell/CMakeLists.txt @@ -29,6 +29,10 @@ zephyr_library_sources_ifdef( CONFIG_BT_ISO iso.c ) +zephyr_library_sources_ifdef( + CONFIG_BT_CHANNEL_SOUNDING + cs.c + ) zephyr_library_sources_ifdef( CONFIG_BT_IAS ias.c diff --git a/subsys/bluetooth/shell/cs.c b/subsys/bluetooth/shell/cs.c new file mode 100644 index 00000000000000..00a16cb4adb885 --- /dev/null +++ b/subsys/bluetooth/shell/cs.c @@ -0,0 +1,123 @@ +/** @file + * @brief Bluetooth Channel Sounding (CS) shell + * + */ + +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "bt.h" + +static int check_cs_sync_antenna_selection_input(uint16_t input) +{ + if (input != BT_CS_ANTENNA_SELECTION_OPT_ONE && input != BT_CS_ANTENNA_SELECTION_OPT_TWO && + input != BT_CS_ANTENNA_SELECTION_OPT_THREE && + input != BT_CS_ANTENNA_SELECTION_OPT_FOUR && + input != BT_CS_ANTENNA_SELECTION_OPT_REPETITIVE && + input != BT_CS_ANTENNA_SELECTION_OPT_NO_RECOMMENDATION) { + return -EINVAL; + } + + return 0; +} + +static int cmd_set_default_settings(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + struct bt_cs_set_default_settings_param params; + uint16_t antenna_input; + int16_t tx_power_input; + + if (default_conn == NULL) { + shell_error(sh, "Conn handle error, at least one connection is required."); + return -ENOEXEC; + } + + params.enable_initiator_role = shell_strtobool(argv[1], 10, &err); + if (err) { + shell_help(sh); + shell_error(sh, "Could not parse input 1, Enable initiator role"); + return SHELL_CMD_HELP_PRINTED; + } + + params.enable_reflector_role = shell_strtobool(argv[2], 10, &err); + if (err) { + shell_help(sh); + shell_error(sh, "Could not parse input 2, Enable reflector role"); + return SHELL_CMD_HELP_PRINTED; + } + + antenna_input = shell_strtoul(argv[3], 16, &err); + if (err) { + shell_help(sh); + shell_error(sh, "Could not parse input 3, CS_SYNC antenna selection"); + return SHELL_CMD_HELP_PRINTED; + } + + err = check_cs_sync_antenna_selection_input(antenna_input); + if (err) { + shell_help(sh); + shell_error(sh, "CS_SYNC antenna selection input invalid"); + return SHELL_CMD_HELP_PRINTED; + } + + tx_power_input = shell_strtol(argv[4], 10, &err); + if (err) { + shell_help(sh); + shell_error(sh, "Could not parse input 4, Max TX power"); + return SHELL_CMD_HELP_PRINTED; + } + + params.cs_sync_antenna_selection = antenna_input; + params.max_tx_power = tx_power_input; + + err = bt_cs_set_default_settings(default_conn, ¶ms); + if (err) { + shell_error(sh, "bt_cs_set_default_settings returned error %d", err); + return -ENOEXEC; + } + + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE( + cs_cmds, + SHELL_CMD_ARG( + set_default_settings, NULL, + " " + " ", + cmd_set_default_settings, 5, 0), + SHELL_SUBCMD_SET_END); + +static int cmd_cs(const struct shell *sh, size_t argc, char **argv) +{ + if (argc == 1) { + shell_help(sh); + + return SHELL_CMD_HELP_PRINTED; + } + + shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]); + + return -EINVAL; +} + +SHELL_CMD_ARG_REGISTER(cs, &cs_cmds, "Bluetooth CS shell commands", cmd_cs, 1, 1); diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index 4a3bca95fb11bb..58fc762768da79 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -43,6 +43,13 @@ tests: platform_allow: - native_sim build_only: true + bluetooth.shell.channel_sounding: + extra_configs: + - CONFIG_BT_CHANNEL_SOUNDING=y + - CONFIG_BT_CTLR=n + platform_allow: + - native_sim + build_only: true bluetooth.shell.cdc_acm: extra_args: - OVERLAY_CONFIG=cdc_acm.conf