diff --git a/CODEOWNERS b/CODEOWNERS index 35a62f07f935..b932bdeeb5ca 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -413,6 +413,7 @@ /samples/bluetooth/central_nfc_pairing/ @nrfconnect/ncs-si-muffin /samples/bluetooth/central_smp_client/ @nrfconnect/ncs-si-muffin /samples/bluetooth/central_uart/ @nrfconnect/ncs-si-muffin +/samples/bluetooth/channel_sounding_ras_reflector/ @nrfconnect/ncs-dragoon /samples/bluetooth/conn_time_sync/ @nrfconnect/ncs-dragoon /samples/bluetooth/direction_finding_central/ @nrfconnect/ncs-dragoon /samples/bluetooth/direction_finding_connectionless_rx/ @nrfconnect/ncs-dragoon diff --git a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst index 46cad5485367..cfc5ebd4ef6a 100644 --- a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst +++ b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst @@ -235,7 +235,9 @@ Amazon Sidewalk samples Bluetooth samples ----------------- -|no_changes_yet_note| +* Added: + + * The :ref:`channel_sounding_ras_reflector` sample demonstrating how to implement a Channel Sounding Reflector that exposes the Ranging Responder GATT Service. Bluetooth Fast Pair samples --------------------------- diff --git a/samples/bluetooth/channel_sounding_ras_reflector/CMakeLists.txt b/samples/bluetooth/channel_sounding_ras_reflector/CMakeLists.txt new file mode 100644 index 000000000000..3a43fe30e48d --- /dev/null +++ b/samples/bluetooth/channel_sounding_ras_reflector/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(channel_sounding_ras_reflector) + +# NORDIC SDK APP START +target_sources(app PRIVATE + src/main.c +) +# NORDIC SDK APP END diff --git a/samples/bluetooth/channel_sounding_ras_reflector/README.rst b/samples/bluetooth/channel_sounding_ras_reflector/README.rst new file mode 100644 index 000000000000..3f393107cfae --- /dev/null +++ b/samples/bluetooth/channel_sounding_ras_reflector/README.rst @@ -0,0 +1,81 @@ +.. _channel_sounding_ras_reflector: + +Bluetooth: Channel Sounding Reflector with Ranging Responder +############################################################ + +.. contents:: + :local: + :depth: 2 + +This sample demonstrates how to use the ranging service to provide ranging data to a client. + +Requirements +************ + +The sample supports the following development kits: + +.. table-from-sample-yaml:: + +The sample also requires a device running a Channel Sounding Initiator with Ranging Requestor to connect to. + +Overview +******** + +The sample demonstrates a basic Bluetooth® Low Energy Peripheral role functionality that exposes the GATT Ranging Responder Service and configures the Channel Sounding reflector role. +When Channel Sounding Ranging Data is generated by the controller, it will be automatically stored by the Ranging Service, and can be queried at any time by the Ranging Requestor. +The Channel Sounding Ranging Data can then be used by the peer device to perform distance estimation. + +User interface +************** + +The sample does not require user input and will advertise using the GATT Ranging Service UUID. +The first LED on the development kit will be lit when a connection has been established. + +Building and running +******************** +.. |sample path| replace:: :file:`samples/bluetooth/channel_sounding_ras_reflector` + +.. include:: /includes/build_and_run.txt + +Testing +======= + +After programming the sample to your development kit, you can test it by connecting to another development kit with a Channel Sounding Initiator role with Ranging Requestor. + +1. |connect_terminal_specific| +#. Reset the kit. +#. Program the other kit with the Channel Sounding Initiator with Ranging Requestor sample. +#. Wait until the advertiser is detected by the Central. + In the terminal window, check for information similar to the following:: + + I: Connected to xx.xx.xx.xx.xx.xx (random) (err 0x00) + I: CS capability exchange completed. + I: CS config creation complete. ID: 0 + I: CS security enabled. + I: CS procedures enabled. + +Dependencies +************ + +This sample uses the following |NCS| libraries: + +* :ref:`dk_buttons_and_leds_readme` +* :file:`include/bluetooth/services/ras.h` + +This sample uses the following Zephyr libraries: + +* :ref:`zephyr:logging_api`: + + * :file:`include/logging/log.h` + +* :file:`include/zephyr/types.h` +* :ref:`zephyr:kernel_api`: + + * :file:`include/kernel.h` + +* :ref:`zephyr:bluetooth_api`: + +* :file:`include/bluetooth/bluetooth.h` +* :file:`include/bluetooth/conn.h` +* :file:`include/bluetooth/uuid.h` +* :file:`include/bluetooth/cs.h` diff --git a/samples/bluetooth/channel_sounding_ras_reflector/prj.conf b/samples/bluetooth/channel_sounding_ras_reflector/prj.conf new file mode 100644 index 000000000000..0bd07d44b552 --- /dev/null +++ b/samples/bluetooth/channel_sounding_ras_reflector/prj.conf @@ -0,0 +1,27 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_NCS_SAMPLES_DEFAULTS=y +CONFIG_DK_LIBRARY=y + +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_SMP=y +CONFIG_BT_DEVICE_NAME="Nordic CS Reflector" +CONFIG_BT_MAX_CONN=1 +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n +CONFIG_BT_BONDABLE=n + +# The Ranging Profile recommends a MTU of at least 247 octets. +CONFIG_BT_L2CAP_TX_MTU=498 +CONFIG_BT_BUF_ACL_TX_SIZE=502 +CONFIG_BT_BUF_ACL_RX_SIZE=502 +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 +CONFIG_BT_CTLR_PHY_2M=y + +CONFIG_BT_CHANNEL_SOUNDING=y +CONFIG_BT_RAS=y +CONFIG_BT_RAS_RRSP=y diff --git a/samples/bluetooth/channel_sounding_ras_reflector/sample.yaml b/samples/bluetooth/channel_sounding_ras_reflector/sample.yaml new file mode 100644 index 000000000000..62dfc9e06840 --- /dev/null +++ b/samples/bluetooth/channel_sounding_ras_reflector/sample.yaml @@ -0,0 +1,12 @@ +sample: + description: Bluetooth Low Energy Channel Sounding Reflector with Ranging Service Responder + name: Bluetooth LE Channel Sounding Reflector with RRSP +tests: + sample.bluetooth.channel_sounding_ras_reflector: + sysbuild: true + build_only: true + integration_platforms: + - nrf54l15dk/nrf54l15/cpuapp + platform_allow: + - nrf54l15dk/nrf54l15/cpuapp + tags: bluetooth ci_build sysbuild diff --git a/samples/bluetooth/channel_sounding_ras_reflector/src/main.c b/samples/bluetooth/channel_sounding_ras_reflector/src/main.c new file mode 100644 index 000000000000..41f8171519c9 --- /dev/null +++ b/samples/bluetooth/channel_sounding_ras_reflector/src/main.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/** @file + * @brief Channel Sounding Reflector with Ranging Responder sample + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +LOG_MODULE_REGISTER(app_main, LOG_LEVEL_INF); + +#define CON_STATUS_LED DK_LED1 + +static K_SEM_DEFINE(sem_connected, 0, 1); + +static struct bt_conn *connection; + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_RANGING_SERVICE_VAL)), + BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), +}; + +static void connected_cb(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + (void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + LOG_INF("Connected to %s (err 0x%02X)", addr, err); + + if (err) { + bt_conn_unref(conn); + connection = NULL; + } + + connection = bt_conn_ref(conn); + + k_sem_give(&sem_connected); + + dk_set_led_on(CON_STATUS_LED); +} + +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + LOG_INF("Disconnected (reason 0x%02X)", reason); + + bt_conn_unref(conn); + connection = NULL; + + dk_set_led_off(CON_STATUS_LED); +} + +static void remote_capabilities_cb(struct bt_conn *conn, struct bt_conn_le_cs_capabilities *params) +{ + ARG_UNUSED(conn); + ARG_UNUSED(params); + LOG_INF("CS capability exchange completed."); +} + +static void config_created_cb(struct bt_conn *conn, struct bt_conn_le_cs_config *config) +{ + ARG_UNUSED(conn); + LOG_INF("CS config creation complete. ID: %d", config->id); +} + +static void security_enabled_cb(struct bt_conn *conn) +{ + ARG_UNUSED(conn); + LOG_INF("CS security enabled."); +} + +static void procedure_enabled_cb(struct bt_conn *conn, + struct bt_conn_le_cs_procedure_enable_complete *params) +{ + ARG_UNUSED(conn); + if (params->state == 1) { + LOG_INF("CS procedures enabled."); + } else { + LOG_INF("CS procedures disabled."); + } +} + +BT_CONN_CB_DEFINE(conn_cb) = { + .connected = connected_cb, + .disconnected = disconnected_cb, + .le_cs_remote_capabilities_available = remote_capabilities_cb, + .le_cs_config_created = config_created_cb, + .le_cs_security_enabled = security_enabled_cb, + .le_cs_procedure_enabled = procedure_enabled_cb, +}; + +int main(void) +{ + int err; + + LOG_INF("Starting Channel Sounding Reflector Sample"); + + dk_leds_init(); + + err = bt_enable(NULL); + if (err) { + LOG_ERR("Bluetooth init failed (err %d)", err); + return 0; + } + + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + LOG_ERR("Advertising failed to start (err %d)", err); + return 0; + } + + while (true) { + k_sem_take(&sem_connected, K_FOREVER); + + const struct bt_le_cs_set_default_settings_param default_settings = { + .enable_initiator_role = false, + .enable_reflector_role = true, + .cs_sync_antenna_selection = BT_LE_CS_ANTENNA_SELECTION_OPT_REPETITIVE, + .max_tx_power = BT_HCI_OP_LE_CS_MAX_MAX_TX_POWER, + }; + + err = bt_le_cs_set_default_settings(connection, &default_settings); + if (err) { + LOG_ERR("Failed to configure default CS settings (err %d)", err); + } + } + + return 0; +}