bluetooth: host: CS support for remote capabilities and FAE table

Adds HCI support for:
- LE CS Read Remote Supported Capabilities
- LE CS Read Remote FAE Table

Callbacks have been added to the conn object to allow upper layers to
make use of the cache commands, with which it will be possible to store
this information and provide it again in the case of a disconnect
and reconnect to the same device.

Signed-off-by: Olivier Lesage <olivier.lesage@nordicsemi.no>
This commit is contained in:
Olivier Lesage 2024-09-15 23:55:33 +02:00 committed by Fabio Baltieri
commit 947a294d36
10 changed files with 680 additions and 0 deletions

View file

@ -262,6 +262,157 @@ enum __packed bt_conn_type {
BT_CONN_TYPE_SCO | BT_CONN_TYPE_ISO,
};
/** Supported AA-Only RTT precision. */
enum bt_conn_le_cs_capability_rtt_aa_only {
/** AA-Only RTT variant is not supported. */
BT_CONN_LE_CS_RTT_AA_ONLY_NOT_SUPP = 0,
/** 10ns time-of-flight accuracy. */
BT_CONN_LE_CS_RTT_AA_ONLY_10NS,
/** 150ns time-of-flight accuracy. */
BT_CONN_LE_CS_RTT_AA_ONLY_150NS,
};
/** Supported Sounding Sequence RTT precision. */
enum bt_conn_le_cs_capability_rtt_sounding {
/** Sounding Sequence RTT variant is not supported. */
BT_CONN_LE_CS_RTT_SOUNDING_NOT_SUPP = 0,
/** 10ns time-of-flight accuracy. */
BT_CONN_LE_CS_RTT_SOUNDING_10NS,
/** 150ns time-of-flight accuracy. */
BT_CONN_LE_CS_RTT_SOUNDING_150NS,
};
/** Supported Random Payload RTT precision. */
enum bt_conn_le_cs_capability_rtt_random_payload {
/** Random Payload RTT variant is not supported. */
BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_NOT_SUPP = 0,
/** 10ns time-of-flight accuracy. */
BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_10NS,
/** 150ns time-of-flight accuracy. */
BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_150NS,
};
/** Remote channel sounding capabilities for LE connections supporting CS */
struct bt_conn_le_cs_capabilities {
/** Number of CS configurations */
uint8_t num_config_supported;
/** Maximum number of consecutive CS procedures.
*
* When set to zero, indicates support for both fixed and indefinite
* numbers of CS procedures before termination.
*/
uint16_t max_consecutive_procedures_supported;
/** Number of antennas. */
uint8_t num_antennas_supported;
/** Maximum number of antenna paths. */
uint8_t max_antenna_paths_supported;
/** Initiator role. */
bool initiator_supported;
/** Reflector role. */
bool reflector_supported;
/** Mode-3 */
bool mode_3_supported;
/** RTT AA-Only */
enum bt_conn_le_cs_capability_rtt_aa_only rtt_aa_only_precision;
/** RTT Sounding */
enum bt_conn_le_cs_capability_rtt_sounding rtt_sounding_precision;
/** RTT Random Payload */
enum bt_conn_le_cs_capability_rtt_random_payload rtt_random_payload_precision;
/** Number of CS steps needed to achieve the
* accuracy requirements for RTT AA Only.
*
* Set to 0 if RTT AA Only isn't supported.
*/
uint8_t rtt_aa_only_n;
/** Number of CS steps needed to achieve the
* accuracy requirements for RTT Sounding.
*
* Set to 0 if RTT Sounding isn't supported
*/
uint8_t rtt_sounding_n;
/** Number of CS steps needed to achieve the
* accuracy requirements for RTT Random Payload.
*
* Set to 0 if RTT Random Payload isn't supported.
*/
uint8_t rtt_random_payload_n;
/** Phase-based normalized attack detector metric
* when a CS_SYNC with sounding sequence is received.
*/
bool phase_based_nadm_sounding_supported;
/** Phase-based normalized attack detector metric
* when a CS_SYNC with random sequence is received.
*/
bool phase_based_nadm_random_supported;
/** CS_SYNC LE 2M PHY. */
bool cs_sync_2m_phy_supported;
/** CS_SYNC LE 2M 2BT PHY. */
bool cs_sync_2m_2bt_phy_supported;
/** Subfeature: CS with no Frequency Actuation Error. */
bool cs_without_fae_supported;
/** Subfeature: Channel Selection Algorithm #3c */
bool chsel_alg_3c_supported;
/** Subfeature: Phase-based Ranging from RTT sounding sequence. */
bool pbr_from_rtt_sounding_seq_supported;
/** Optional T_IP1 time durations during CS steps.
*
* - Bit 0: 10 us
* - Bit 1: 20 us
* - Bit 2: 30 us
* - Bit 3: 40 us
* - Bit 4: 50 us
* - Bit 5: 60 us
* - Bit 6: 80 us
*/
uint16_t t_ip1_times_supported;
/** Optional T_IP2 time durations during CS steps.
*
* - Bit 0: 10 us
* - Bit 1: 20 us
* - Bit 2: 30 us
* - Bit 3: 40 us
* - Bit 4: 50 us
* - Bit 5: 60 us
* - Bit 6: 80 us
*/
uint16_t t_ip2_times_supported;
/** Optional T_FCS time durations during CS steps.
*
* - Bit 0: 15 us
* - Bit 1: 20 us
* - Bit 2: 30 us
* - Bit 3: 40 us
* - Bit 4: 50 us
* - Bit 5: 60 us
* - Bit 6: 80 us
* - Bit 7: 100 us
* - Bit 8: 120 us
*/
uint16_t t_fcs_times_supported;
/** Optional T_PM time durations during CS steps.
*
* - Bit 0: 10 us
* - Bit 1: 20 us
*/
uint16_t t_pm_times_supported;
/** Time in microseconds for the antenna switch period of the CS tones. */
uint8_t t_sw_time;
/** Supported SNR levels used in RTT packets.
*
* - Bit 0: 18dB
* - Bit 1: 21dB
* - Bit 2: 24dB
* - Bit 3: 27dB
* - Bit 4: 30dB
*/
uint8_t tx_snr_capability;
};
/** Remote FAE Table for LE connections supporting CS */
struct bt_conn_le_cs_fae_table {
uint8_t *remote_fae_table;
};
/** @brief Increment a connection's reference count.
*
* Increment the reference count of a connection object.
@ -1359,6 +1510,30 @@ struct bt_conn_cb {
const struct bt_conn_le_subrate_changed *params);
#endif /* CONFIG_BT_SUBRATING */
#if defined(CONFIG_BT_CHANNEL_SOUNDING)
/** @brief LE CS Read Remote Supported Capabilities Complete event.
*
* This callback notifies the application that the remote channel
* sounding capabilities have been received from the peer.
*
* @param conn Connection object.
* @param remote_cs_capabilities Remote Channel Sounding Capabilities.
*/
void (*remote_cs_capabilities_available)(struct bt_conn *conn,
struct bt_conn_le_cs_capabilities *params);
/** @brief LE CS Read Remote FAE Table Complete event.
*
* This callback notifies the application that the remote mode-0
* FAE Table has been received from the peer.
*
* @param conn Connection object.
* @param params FAE Table.
*/
void (*remote_cs_fae_table_available)(struct bt_conn *conn,
struct bt_conn_le_cs_fae_table *params);
#endif
/** @internal Internally used field for list handling */
sys_snode_t _node;
};

View file

@ -60,6 +60,20 @@ struct bt_cs_set_default_settings_param {
int8_t max_tx_power;
};
/** @brief Read Remote Supported Capabilities
*
* This command is used to query the CS capabilities that are supported
* by the remote controller.
*
* @note To use this API @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set.
*
* @param conn Connection Object.
*
* @return Zero on success or (negative) error code on failure.
*/
int bt_cs_read_remote_supported_capabilities(struct bt_conn *conn);
/** @brief Set Channel Sounding default settings.
*
* This command is used to set default Channel Sounding settings for this
@ -75,6 +89,19 @@ struct bt_cs_set_default_settings_param {
int bt_cs_set_default_settings(struct bt_conn *conn,
const struct bt_cs_set_default_settings_param *params);
/** @brief Read Remote FAE Table
*
* This command is used to read the per-channel mode-0 Frequency Actuation Error
* table of the remote Controller.
*
* @note To use this API @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set.
*
* @param conn Connection Object.
*
* @return Zero on success or (negative) error code on failure.
*/
int bt_cs_read_remote_fae_table(struct bt_conn *conn);
#ifdef __cplusplus
}
#endif

View file

@ -201,6 +201,9 @@ struct bt_hci_cmd_hdr {
#define BT_LE_FEAT_BIT_PAWR_ADVERTISER 43
#define BT_LE_FEAT_BIT_PAWR_SCANNER 44
#define BT_LE_FEAT_BIT_CHANNEL_SOUNDING 46
#define BT_LE_FEAT_BIT_CHANNEL_SOUNDING_HOST 47
#define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \
BIT((n) & 7))
@ -268,6 +271,10 @@ struct bt_hci_cmd_hdr {
BT_LE_FEAT_BIT_PAWR_ADVERTISER)
#define BT_FEAT_LE_PAWR_SCANNER(feat) BT_LE_FEAT_TEST(feat, \
BT_LE_FEAT_BIT_PAWR_SCANNER)
#define BT_FEAT_LE_CHANNEL_SOUNDING(feat) BT_LE_FEAT_TEST(feat, \
BT_LE_FEAT_BIT_CHANNEL_SOUNDING)
#define BT_FEAT_LE_CHANNEL_SOUNDING_HOST(feat) BT_LE_FEAT_TEST(feat, \
BT_LE_FEAT_BIT_CHANNEL_SOUNDING_HOST)
#define BT_FEAT_LE_CIS(feat) (BT_FEAT_LE_CIS_CENTRAL(feat) | \
BT_FEAT_LE_CIS_PERIPHERAL(feat))
@ -2395,6 +2402,12 @@ struct bt_hci_cp_le_tx_test_v4_tx_power {
int8_t tx_power;
} __packed;
#define BT_HCI_OP_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES BT_OP(BT_OGF_LE, 0x008A) /* 0x208A */
struct bt_hci_cp_le_read_remote_supported_capabilities {
uint16_t handle;
} __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)
@ -2417,6 +2430,12 @@ struct bt_hci_cp_le_cs_set_default_settings {
int8_t max_tx_power;
} __packed;
#define BT_HCI_OP_LE_CS_READ_REMOTE_FAE_TABLE BT_OP(BT_OGF_LE, 0x008E) /* 0x208E */
struct bt_hci_cp_le_read_remote_fae_table {
uint16_t handle;
} __packed;
/* Event definitions */
#define BT_HCI_EVT_UNKNOWN 0x00
@ -3151,6 +3170,93 @@ struct bt_hci_evt_le_subrate_change {
uint16_t supervision_timeout;
} __packed;
#define BT_HCI_LE_CS_INITIATOR_ROLE_MASK BIT(0)
#define BT_HCI_LE_CS_REFLECTOR_ROLE_MASK BIT(1)
#define BT_HCI_LE_CS_MODES_SUPPORTED_MODE_3_MASK BIT(0)
#define BT_HCI_LE_CS_RTT_AA_ONLY_N_10NS_MASK BIT(0)
#define BT_HCI_LE_CS_RTT_SOUNDING_N_10NS_MASK BIT(1)
#define BT_HCI_LE_CS_RTT_RANDOM_PAYLOAD_N_10NS_MASK BIT(2)
#define BT_HCI_LE_CS_NADM_SOUNDING_CAPABILITY_PHASE_BASED_MASK BIT(0)
#define BT_HCI_LE_CS_NADM_RANDOM_CAPABILITY_PHASE_BASED_MASK BIT(0)
#define BT_HCI_LE_CS_SYNC_PHYS_2M_MASK BIT(1)
#define BT_HCI_LE_CS_SYNC_PHYS_2M_2BT_MASK BIT(2)
#define BT_HCI_LE_CS_SUBFEATURE_NO_TX_FAE_MASK BIT(1)
#define BT_HCI_LE_CS_SUBFEATURE_CHSEL_ALG_3C_MASK BIT(2)
#define BT_HCI_LE_CS_SUBFEATURE_PBR_FROM_RTT_SOUNDING_SEQ_MASK BIT(3)
#define BT_HCI_LE_CS_T_IP1_TIME_10US_MASK BIT(0)
#define BT_HCI_LE_CS_T_IP1_TIME_20US_MASK BIT(1)
#define BT_HCI_LE_CS_T_IP1_TIME_30US_MASK BIT(2)
#define BT_HCI_LE_CS_T_IP1_TIME_40US_MASK BIT(3)
#define BT_HCI_LE_CS_T_IP1_TIME_50US_MASK BIT(4)
#define BT_HCI_LE_CS_T_IP1_TIME_60US_MASK BIT(5)
#define BT_HCI_LE_CS_T_IP1_TIME_80US_MASK BIT(6)
#define BT_HCI_LE_CS_T_IP2_TIME_10US_MASK BIT(0)
#define BT_HCI_LE_CS_T_IP2_TIME_20US_MASK BIT(1)
#define BT_HCI_LE_CS_T_IP2_TIME_30US_MASK BIT(2)
#define BT_HCI_LE_CS_T_IP2_TIME_40US_MASK BIT(3)
#define BT_HCI_LE_CS_T_IP2_TIME_50US_MASK BIT(4)
#define BT_HCI_LE_CS_T_IP2_TIME_60US_MASK BIT(5)
#define BT_HCI_LE_CS_T_IP2_TIME_80US_MASK BIT(6)
#define BT_HCI_LE_CS_T_FCS_TIME_15US_MASK BIT(0)
#define BT_HCI_LE_CS_T_FCS_TIME_20US_MASK BIT(1)
#define BT_HCI_LE_CS_T_FCS_TIME_30US_MASK BIT(2)
#define BT_HCI_LE_CS_T_FCS_TIME_40US_MASK BIT(3)
#define BT_HCI_LE_CS_T_FCS_TIME_50US_MASK BIT(4)
#define BT_HCI_LE_CS_T_FCS_TIME_60US_MASK BIT(5)
#define BT_HCI_LE_CS_T_FCS_TIME_80US_MASK BIT(6)
#define BT_HCI_LE_CS_T_FCS_TIME_100US_MASK BIT(7)
#define BT_HCI_LE_CS_T_FCS_TIME_1200US_MASK BIT(8)
#define BT_HCI_LE_CS_T_PM_TIME_10US_MASK BIT(0)
#define BT_HCI_LE_CS_T_PM_TIME_20US_MASK BIT(1)
#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_18DB_MASK BIT(0)
#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_21DB_MASK BIT(1)
#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_24DB_MASK BIT(2)
#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_27DB_MASK BIT(3)
#define BT_HCI_LE_CS_TX_SNR_CAPABILITY_30DB_MASK BIT(4)
#define BT_HCI_EVT_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE 0x2C
struct bt_hci_evt_le_cs_read_remote_supported_capabilities_complete {
uint8_t status;
uint16_t conn_handle;
uint8_t num_config_supported;
uint16_t max_consecutive_procedures_supported;
uint8_t num_antennas_supported;
uint8_t max_antenna_paths_supported;
uint8_t roles_supported;
uint8_t modes_supported;
uint8_t rtt_capability;
uint8_t rtt_aa_only_n;
uint8_t rtt_sounding_n;
uint8_t rtt_random_payload_n;
uint16_t nadm_sounding_capability;
uint16_t nadm_random_capability;
uint8_t cs_sync_phys_supported;
uint16_t subfeatures_supported;
uint16_t t_ip1_times_supported;
uint16_t t_ip2_times_supported;
uint16_t t_fcs_times_supported;
uint16_t t_pm_times_supported;
uint8_t t_sw_time_supported;
uint8_t tx_snr_capability;
} __packed;
#define BT_HCI_EVT_LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE 0x2D
struct bt_hci_evt_le_cs_read_remote_fae_table_complete {
uint8_t status;
uint16_t conn_handle;
uint8_t remote_fae_table[72];
} __packed;
/* Event mask bits */
#define BT_EVT_BIT(n) (1ULL << (n))
@ -3240,6 +3346,9 @@ struct bt_hci_evt_le_subrate_change {
#define BT_EVT_MASK_LE_PER_ADV_RESPONSE_REPORT BT_EVT_BIT(39)
#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE_V2 BT_EVT_BIT(40)
#define BT_EVT_MASK_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE BT_EVT_BIT(43)
#define BT_EVT_MASK_LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE BT_EVT_BIT(44)
/** HCI Error Codes, BT Core Spec v5.4 [Vol 1, Part F]. */
#define BT_HCI_ERR_SUCCESS 0x00
#define BT_HCI_ERR_UNKNOWN_CMD 0x01

View file

@ -3320,6 +3320,42 @@ int bt_conn_le_subrate_request(struct bt_conn *conn,
}
#endif /* CONFIG_BT_SUBRATING */
#if defined(CONFIG_BT_CHANNEL_SOUNDING)
void notify_remote_cs_capabilities(struct bt_conn *conn, struct bt_conn_le_cs_capabilities params)
{
struct bt_conn_cb *callback;
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
if (callback->remote_cs_capabilities_available) {
callback->remote_cs_capabilities_available(conn, &params);
}
}
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
if (cb->remote_cs_capabilities_available) {
cb->remote_cs_capabilities_available(conn, &params);
}
}
}
void notify_remote_cs_fae_table(struct bt_conn *conn, struct bt_conn_le_cs_fae_table params)
{
struct bt_conn_cb *callback;
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
if (callback->remote_cs_fae_table_available) {
callback->remote_cs_fae_table_available(conn, &params);
}
}
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
if (cb->remote_cs_fae_table_available) {
cb->remote_cs_fae_table_available(conn, &params);
}
}
}
#endif /* CONFIG_BT_CHANNEL_SOUNDING */
int bt_conn_le_param_update(struct bt_conn *conn,
const struct bt_le_conn_param *param)
{

View file

@ -492,6 +492,12 @@ void notify_path_loss_threshold_report(struct bt_conn *conn,
void notify_subrate_change(struct bt_conn *conn,
struct bt_conn_le_subrate_changed params);
void notify_remote_cs_capabilities(struct bt_conn *conn,
struct bt_conn_le_cs_capabilities params);
void notify_remote_cs_fae_table(struct bt_conn *conn,
struct bt_conn_le_cs_fae_table params);
#if defined(CONFIG_BT_SMP)
/* If role specific LTK is present */
bool bt_conn_ltk_present(const struct bt_conn *conn);

View file

@ -13,7 +13,143 @@
#include "conn_internal.h"
#define LOG_LEVEL CONFIG_BT_HCI_CORE_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_cs);
#if defined(CONFIG_BT_CHANNEL_SOUNDING)
int bt_cs_read_remote_supported_capabilities(struct bt_conn *conn)
{
struct bt_hci_cp_le_read_remote_supported_capabilities *cp;
struct net_buf *buf;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->handle = sys_cpu_to_le16(conn->handle);
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES, buf, NULL);
}
void bt_hci_le_cs_read_remote_supported_capabilities_complete(struct net_buf *buf)
{
struct bt_conn *conn;
struct bt_conn_le_cs_capabilities remote_cs_capabilities;
struct bt_hci_evt_le_cs_read_remote_supported_capabilities_complete *evt;
if (buf->len < sizeof(*evt)) {
LOG_ERR("Unexpected end of buffer");
return;
}
evt = net_buf_pull_mem(buf, sizeof(*evt));
if (evt->status) {
LOG_INF("Read Remote Supported Capabilities failed (status 0x%02X)", evt->status);
return;
}
conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle), BT_CONN_TYPE_LE);
if (!conn) {
LOG_ERR("Could not lookup connection handle when reading remote CS capabilities");
return;
}
remote_cs_capabilities.num_config_supported = evt->num_config_supported;
remote_cs_capabilities.max_consecutive_procedures_supported =
sys_le16_to_cpu(evt->max_consecutive_procedures_supported);
remote_cs_capabilities.num_antennas_supported = evt->num_antennas_supported;
remote_cs_capabilities.max_antenna_paths_supported = evt->max_antenna_paths_supported;
remote_cs_capabilities.initiator_supported =
evt->roles_supported & BT_HCI_LE_CS_INITIATOR_ROLE_MASK;
remote_cs_capabilities.reflector_supported =
evt->roles_supported & BT_HCI_LE_CS_REFLECTOR_ROLE_MASK;
remote_cs_capabilities.mode_3_supported =
evt->modes_supported & BT_HCI_LE_CS_MODES_SUPPORTED_MODE_3_MASK;
remote_cs_capabilities.rtt_aa_only_n = evt->rtt_aa_only_n;
remote_cs_capabilities.rtt_sounding_n = evt->rtt_sounding_n;
remote_cs_capabilities.rtt_random_payload_n = evt->rtt_random_payload_n;
if (evt->rtt_aa_only_n) {
if (evt->rtt_capability & BT_HCI_LE_CS_RTT_AA_ONLY_N_10NS_MASK) {
remote_cs_capabilities.rtt_aa_only_precision =
BT_CONN_LE_CS_RTT_AA_ONLY_10NS;
} else {
remote_cs_capabilities.rtt_aa_only_precision =
BT_CONN_LE_CS_RTT_AA_ONLY_150NS;
}
} else {
remote_cs_capabilities.rtt_aa_only_precision = BT_CONN_LE_CS_RTT_AA_ONLY_NOT_SUPP;
}
if (evt->rtt_sounding_n) {
if (evt->rtt_capability & BT_HCI_LE_CS_RTT_SOUNDING_N_10NS_MASK) {
remote_cs_capabilities.rtt_sounding_precision =
BT_CONN_LE_CS_RTT_SOUNDING_10NS;
} else {
remote_cs_capabilities.rtt_sounding_precision =
BT_CONN_LE_CS_RTT_SOUNDING_150NS;
}
} else {
remote_cs_capabilities.rtt_sounding_precision = BT_CONN_LE_CS_RTT_SOUNDING_NOT_SUPP;
}
if (evt->rtt_random_payload_n) {
if (evt->rtt_capability & BT_HCI_LE_CS_RTT_RANDOM_PAYLOAD_N_10NS_MASK) {
remote_cs_capabilities.rtt_random_payload_precision =
BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_10NS;
} else {
remote_cs_capabilities.rtt_random_payload_precision =
BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_150NS;
}
} else {
remote_cs_capabilities.rtt_random_payload_precision =
BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_NOT_SUPP;
}
remote_cs_capabilities.phase_based_nadm_sounding_supported =
sys_le16_to_cpu(evt->nadm_sounding_capability) &
BT_HCI_LE_CS_NADM_SOUNDING_CAPABILITY_PHASE_BASED_MASK;
remote_cs_capabilities.phase_based_nadm_random_supported =
sys_le16_to_cpu(evt->nadm_random_capability) &
BT_HCI_LE_CS_NADM_RANDOM_CAPABILITY_PHASE_BASED_MASK;
remote_cs_capabilities.cs_sync_2m_phy_supported =
evt->cs_sync_phys_supported & BT_HCI_LE_CS_SYNC_PHYS_2M_MASK;
remote_cs_capabilities.cs_sync_2m_2bt_phy_supported =
evt->cs_sync_phys_supported & BT_HCI_LE_CS_SYNC_PHYS_2M_2BT_MASK;
remote_cs_capabilities.cs_without_fae_supported =
sys_le16_to_cpu(evt->subfeatures_supported) &
BT_HCI_LE_CS_SUBFEATURE_NO_TX_FAE_MASK;
remote_cs_capabilities.chsel_alg_3c_supported =
sys_le16_to_cpu(evt->subfeatures_supported) &
BT_HCI_LE_CS_SUBFEATURE_CHSEL_ALG_3C_MASK;
remote_cs_capabilities.pbr_from_rtt_sounding_seq_supported =
sys_le16_to_cpu(evt->subfeatures_supported) &
BT_HCI_LE_CS_SUBFEATURE_PBR_FROM_RTT_SOUNDING_SEQ_MASK;
remote_cs_capabilities.t_ip1_times_supported = sys_le16_to_cpu(evt->t_ip1_times_supported);
remote_cs_capabilities.t_ip2_times_supported = sys_le16_to_cpu(evt->t_ip2_times_supported);
remote_cs_capabilities.t_fcs_times_supported = sys_le16_to_cpu(evt->t_fcs_times_supported);
remote_cs_capabilities.t_pm_times_supported = sys_le16_to_cpu(evt->t_pm_times_supported);
remote_cs_capabilities.t_sw_time = evt->t_sw_time_supported;
remote_cs_capabilities.tx_snr_capability = evt->tx_snr_capability;
notify_remote_cs_capabilities(conn, remote_cs_capabilities);
bt_conn_unref(conn);
}
int bt_cs_set_default_settings(struct bt_conn *conn,
const struct bt_cs_set_default_settings_param *params)
{
@ -41,4 +177,49 @@ int bt_cs_set_default_settings(struct bt_conn *conn,
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_SET_DEFAULT_SETTINGS, buf, NULL);
}
int bt_cs_read_remote_fae_table(struct bt_conn *conn)
{
struct bt_hci_cp_le_read_remote_fae_table *cp;
struct net_buf *buf;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CS_READ_REMOTE_FAE_TABLE, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->handle = sys_cpu_to_le16(conn->handle);
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_READ_REMOTE_FAE_TABLE, buf, NULL);
}
void bt_hci_le_cs_read_remote_fae_table_complete(struct net_buf *buf)
{
struct bt_conn *conn;
struct bt_conn_le_cs_fae_table fae_table;
struct bt_hci_evt_le_cs_read_remote_fae_table_complete *evt;
if (buf->len < sizeof(*evt)) {
LOG_ERR("Unexpected end of buffer");
return;
}
evt = net_buf_pull_mem(buf, sizeof(*evt));
if (evt->status) {
LOG_INF("Read Remote FAE Table failed with status 0x%02X", evt->status);
return;
}
conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle), BT_CONN_TYPE_LE);
if (!conn) {
LOG_ERR("Could not lookup connection handle when reading remote FAE Table");
return;
}
fae_table.remote_fae_table = evt->remote_fae_table;
notify_remote_cs_fae_table(conn, fae_table);
bt_conn_unref(conn);
}
#endif /* CONFIG_BT_CHANNEL_SOUNDING */

View file

@ -2821,6 +2821,14 @@ static const struct event_handler meta_events[] = {
sizeof(struct bt_hci_evt_le_enh_conn_complete_v2)),
#endif /* CONFIG_BT_PER_ADV_RSP || CONFIG_BT_PER_ADV_SYNC_RSP */
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_CHANNEL_SOUNDING)
EVENT_HANDLER(BT_HCI_EVT_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE,
bt_hci_le_cs_read_remote_supported_capabilities_complete,
sizeof(struct bt_hci_evt_le_cs_read_remote_supported_capabilities_complete)),
EVENT_HANDLER(BT_HCI_EVT_LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE,
bt_hci_le_cs_read_remote_fae_table_complete,
sizeof(struct bt_hci_evt_le_cs_read_remote_fae_table_complete)),
#endif /* CONFIG_BT_CHANNEL_SOUNDING */
};
@ -3391,6 +3399,13 @@ static int le_set_event_mask(void)
mask |= BT_EVT_MASK_LE_ENH_CONN_COMPLETE_V2;
}
if (IS_ENABLED(CONFIG_BT_CHANNEL_SOUNDING) &&
BT_FEAT_LE_CHANNEL_SOUNDING(bt_dev.le.features)) {
mask |= BT_EVT_MASK_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE;
mask |= BT_EVT_MASK_LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE;
}
sys_put_le64(mask, cp_mask->events);
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_EVENT_MASK, buf, NULL);
}
@ -3613,6 +3628,14 @@ static int le_init(void)
}
}
if (IS_ENABLED(CONFIG_BT_CHANNEL_SOUNDING) &&
BT_FEAT_LE_CHANNEL_SOUNDING(bt_dev.le.features)) {
err = le_set_host_feature(BT_LE_FEAT_BIT_CHANNEL_SOUNDING_HOST, 1);
if (err) {
return err;
}
}
return le_set_event_mask();
}

View file

@ -538,6 +538,10 @@ void bt_hci_le_vs_df_connectionless_iq_report(struct net_buf *buf);
void bt_hci_le_past_received(struct net_buf *buf);
void bt_hci_le_past_received_v2(struct net_buf *buf);
/* CS HCI event handlers */
void bt_hci_le_cs_read_remote_supported_capabilities_complete(struct net_buf *buf);
void bt_hci_le_cs_read_remote_fae_table_complete(struct net_buf *buf);
/* Adv HCI event handlers */
void bt_hci_le_adv_set_terminated(struct net_buf *buf);
void bt_hci_le_scan_req_received(struct net_buf *buf);

View file

@ -982,6 +982,78 @@ void subrate_changed(struct bt_conn *conn,
}
#endif
#if defined(CONFIG_BT_CHANNEL_SOUNDING)
void print_remote_cs_capabilities(struct bt_conn *conn, struct bt_conn_le_cs_capabilities *params)
{
shell_print(
ctx_shell,
"Received remote channel sounding capabilities:\n"
"- Num CS configurations: %d\n"
"- Max consecutive CS procedures: %d\n"
"- Num antennas supported: %d\n"
"- Max antenna paths supported: %d\n"
"- Initiator role supported: %s\n"
"- Reflector role supported: %s\n"
"- Mode 3 supported: %s\n"
"- RTT AA only supported: %s\n"
"- RTT AA only is 10ns precise: %s\n"
"- RTT AA only N: %d\n"
"- RTT sounding supported: %s\n"
"- RTT sounding is 10ns precise: %s\n"
"- RTT sounding N: %d\n"
"- RTT random payload supported: %s\n"
"- RTT random payload is 10ns precise: %s\n"
"- RTT random payload N: %d\n"
"- Phase-based NADM with sounding sequences supported: %s\n"
"- Phase-based NADM with random sequences supported: %s\n"
"- CS Sync 2M PHY supported: %s\n"
"- CS Sync 2M 2BT PHY supported: %s\n"
"- CS without transmitter FAE supported: %s\n"
"- Channel selection algorithm #3c supported: %s\n"
"- Phase-based ranging from RTT sounding sequence supported: %s\n"
"- T_IP1 times supported: 0x%04x\n"
"- T_IP2 times supported: 0x%04x\n"
"- T_FCS times supported: 0x%04x\n"
"- T_PM times supported: 0x%04x\n"
"- T_SW time supported: %d us\n"
"- TX SNR capability: 0x%02x",
params->num_config_supported, params->max_consecutive_procedures_supported,
params->num_antennas_supported, params->max_antenna_paths_supported,
params->initiator_supported ? "Yes" : "No",
params->reflector_supported ? "Yes" : "No", params->mode_3_supported ? "Yes" : "No",
params->rtt_aa_only_precision == BT_CONN_LE_CS_RTT_AA_ONLY_NOT_SUPP ? "No" : "Yes",
params->rtt_aa_only_precision == BT_CONN_LE_CS_RTT_AA_ONLY_10NS ? "Yes" : "No",
params->rtt_aa_only_n,
params->rtt_sounding_precision == BT_CONN_LE_CS_RTT_SOUNDING_NOT_SUPP ? "No"
: "Yes",
params->rtt_sounding_precision == BT_CONN_LE_CS_RTT_SOUNDING_10NS ? "Yes" : "No",
params->rtt_sounding_n,
params->rtt_random_payload_precision == BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_NOT_SUPP
? "No"
: "Yes",
params->rtt_random_payload_precision == BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_10NS
? "Yes"
: "No",
params->rtt_random_payload_n,
params->phase_based_nadm_sounding_supported ? "Yes" : "No",
params->phase_based_nadm_random_supported ? "Yes" : "No",
params->cs_sync_2m_phy_supported ? "Yes" : "No",
params->cs_sync_2m_2bt_phy_supported ? "Yes" : "No",
params->cs_without_fae_supported ? "Yes" : "No",
params->chsel_alg_3c_supported ? "Yes" : "No",
params->pbr_from_rtt_sounding_seq_supported ? "Yes" : "No",
params->t_ip1_times_supported, params->t_ip2_times_supported,
params->t_fcs_times_supported, params->t_pm_times_supported, params->t_sw_time,
params->tx_snr_capability);
}
void print_remote_cs_fae_table(struct bt_conn *conn, struct bt_conn_le_cs_fae_table *params)
{
shell_print(ctx_shell, "Received FAE Table: ");
shell_hexdump(ctx_shell, params->remote_fae_table, 72);
}
#endif
static struct bt_conn_cb conn_callbacks = {
.connected = connected,
.disconnected = disconnected,
@ -1011,6 +1083,10 @@ static struct bt_conn_cb conn_callbacks = {
#if defined(CONFIG_BT_SUBRATING)
.subrate_changed = subrate_changed,
#endif
#if defined(CONFIG_BT_CHANNEL_SOUNDING)
.remote_cs_capabilities_available = print_remote_cs_capabilities,
.remote_cs_fae_table_available = print_remote_cs_fae_table,
#endif
};
#endif /* CONFIG_BT_CONN */

View file

@ -39,6 +39,24 @@ static int check_cs_sync_antenna_selection_input(uint16_t input)
return 0;
}
static int cmd_read_remote_supported_capabilities(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;
}
err = bt_cs_read_remote_supported_capabilities(default_conn);
if (err) {
shell_error(sh, "bt_cs_read_remote_supported_capabilities returned error %d", err);
return -ENOEXEC;
}
return 0;
}
static int cmd_set_default_settings(const struct shell *sh, size_t argc, char *argv[])
{
int err = 0;
@ -98,13 +116,38 @@ static int cmd_set_default_settings(const struct shell *sh, size_t argc, char *a
return 0;
}
static int cmd_read_remote_fae_table(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;
}
err = bt_cs_read_remote_fae_table(default_conn);
if (err) {
shell_error(sh, "bt_cs_read_remote_fae_table returned error %d", err);
return -ENOEXEC;
}
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(
cs_cmds,
SHELL_CMD_ARG(
read_remote_supported_capabilities, NULL,
"<None>",
cmd_read_remote_supported_capabilities, 1, 0),
SHELL_CMD_ARG(
set_default_settings, NULL,
"<Enable initiator role: true, false> <Enable reflector role: true, false> "
" <CS_SYNC antenna selection: 0x01 - 0x04, 0xFE, 0xFF> <Max TX power: -127 - 20>",
cmd_set_default_settings, 5, 0),
SHELL_CMD_ARG(
read_remote_fae_table, NULL,
"<None>",
cmd_read_remote_fae_table, 1, 0),
SHELL_SUBCMD_SET_END);
static int cmd_cs(const struct shell *sh, size_t argc, char **argv)