Skip to content

Commit

Permalink
bluetooth: services: ras: Implement Ranging Responder role of RAS
Browse files Browse the repository at this point in the history
Implement the ranging responder (RRSP) server role of the
Ranging Service draft specification.
This allows a ranging requestor (RREQ) to retrieve channel sounding
ranging data from the local device.

This implementation contains support for all mandatory features,
as well as using notifications for data transfer.

Signed-off-by: Aleksandar Stanoev <[email protected]>
  • Loading branch information
alexstanoev-nordic authored and rlubos committed Nov 12, 2024
1 parent e4172b8 commit 27bf358
Show file tree
Hide file tree
Showing 8 changed files with 1,249 additions and 16 deletions.
184 changes: 183 additions & 1 deletion include/bluetooth/services/ras.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/hci_types.h>

/** @file
* @defgroup bt_ras Ranging Service API
Expand Down Expand Up @@ -54,7 +55,38 @@ extern "C" {
#define BT_RAS_RANGING_HEADER_LEN 4
#define BT_RAS_SUBEVENT_HEADER_LEN 8
#define BT_RAS_STEP_MODE_LEN 1
#define BT_RAS_MAX_STEP_DATA_LEN 35

#define BT_RAS_MAX_SUBEVENTS_PER_PROCEDURE 32
#define BT_RAS_MAX_STEPS_PER_PROCEDURE 256

#define BT_RAS_STEP_MODE_2_3_ANT_DEPENDENT_LEN(antenna_paths) \
((antenna_paths + 1) * sizeof(struct bt_hci_le_cs_step_data_tone_info))

#define BT_RAS_STEP_MODE_0_MAX_LEN \
MAX(sizeof(struct bt_hci_le_cs_step_data_mode_0_initiator), \
sizeof(struct bt_hci_le_cs_step_data_mode_0_reflector))
#define BT_RAS_STEP_MODE_1_MAX_LEN (sizeof(struct bt_hci_le_cs_step_data_mode_1))
#define BT_RAS_STEP_MODE_2_MAX_LEN \
(sizeof(struct bt_hci_le_cs_step_data_mode_2) + \
BT_RAS_STEP_MODE_2_3_ANT_DEPENDENT_LEN(CONFIG_BT_RAS_MAX_ANTENNA_PATHS))
#define BT_RAS_STEP_MODE_3_MAX_LEN \
(sizeof(struct bt_hci_le_cs_step_data_mode_3) + \
BT_RAS_STEP_MODE_2_3_ANT_DEPENDENT_LEN(CONFIG_BT_RAS_MAX_ANTENNA_PATHS))

#define BT_RAS_STEP_MODE_0_1_MAX_LEN MAX(BT_RAS_STEP_MODE_0_MAX_LEN, BT_RAS_STEP_MODE_1_MAX_LEN)
#define BT_RAS_STEP_MODE_0_1_2_MAX_LEN MAX(BT_RAS_STEP_MODE_0_1_MAX_LEN, BT_RAS_STEP_MODE_2_MAX_LEN)

#if defined(CONFIG_BT_RAS_MODE_3_SUPPORTED)
#define BT_RAS_MAX_STEP_DATA_LEN MAX(BT_RAS_STEP_MODE_0_1_2_MAX_LEN, BT_RAS_STEP_MODE_3_MAX_LEN)
#else
#define BT_RAS_MAX_STEP_DATA_LEN BT_RAS_STEP_MODE_0_1_2_MAX_LEN
#endif

#define BT_RAS_PROCEDURE_MEM \
(BT_RAS_RANGING_HEADER_LEN + \
(BT_RAS_MAX_SUBEVENTS_PER_PROCEDURE * BT_RAS_SUBEVENT_HEADER_LEN) + \
(BT_RAS_MAX_STEPS_PER_PROCEDURE * BT_RAS_STEP_MODE_LEN) + \
(BT_RAS_MAX_STEPS_PER_PROCEDURE * BT_RAS_MAX_STEP_DATA_LEN))

/** @brief Ranging Header structure as defined in RAS Specification, Table 3.7. */
struct ras_ranging_header {
Expand Down Expand Up @@ -130,6 +162,156 @@ struct ras_subevent_header {
} __packed;
BUILD_ASSERT(sizeof(struct ras_subevent_header) == BT_RAS_SUBEVENT_HEADER_LEN);

/** @brief RAS Ranging Data Buffer callback structure. */
struct bt_ras_rd_buffer_cb {
/** @brief New ranging data has been received from the local controller.
*
* This callback notifies the application that the ranging data buffer
* has reassembled a complete ranging procedure from the local controller.
*
* @param conn Connection object.
* @param ranging_counter Ranging counter of the stored procedure.
*/
void (*new_ranging_data_received)(struct bt_conn *conn, uint16_t ranging_counter);

/** @brief Ranging data has been overwritten.
*
* This callback notifies the application that the ranging data buffer
* has overwritten a stored procedure due to running out of buffers
* to store a newer procedure from the local controller.
*
* @param conn Connection object.
* @param ranging_counter Ranging counter of the overwritten procedure.
*/
void (*ranging_data_overwritten)(struct bt_conn *conn, uint16_t ranging_counter);

sys_snode_t node;
};

/** @brief RAS Ranging Data buffer structure.
*
* Provides storage and metadata to store a complete Ranging Data body
* as defined in RAS Specification, Section 3.2.1.2.
* Buffers can be accessed by the application and RRSP concurrently, and will not
* be overwritten while any references are held via @ref bt_ras_rd_buffer_claim.
*
* @note The following CS subevent fields are not included by specification:
* subevent count, step channel, step length.
*/
struct ras_rd_buffer {
/** Connection with an RRSP instance owning this buffer. */
struct bt_conn *conn;
/** CS Procedure Ranging Counter stored in this buffer. */
uint16_t ranging_counter;
/** Write cursor into the procedure subevent buffer. */
uint16_t subevent_cursor;
/** Reference counter for buffer.
* The buffer will not be overwritten with active references.
*/
atomic_t refcount;
/** All ranging data has been written, buffer is ready to send. */
bool ready;
/** Ranging data is being written to this buffer. */
bool busy;
/** The peer has ACKed this buffer, the overwritten callback will not be called. */
bool acked;
/** Complete ranging data procedure buffer. */
union {
uint8_t buf[BT_RAS_PROCEDURE_MEM];
struct {
struct ras_ranging_header ranging_header;
uint8_t subevents[];
} __packed;
} procedure;
};

/** @brief Allocate Ranging Responder instance for connection.
*
* This will allocate an instance of the Ranging Responder service for the given connection.
*
* @note This method must not be called if CONFIG_BT_RAS_RRSP_AUTO_ALLOC_INSTANCE is enabled.
* @note The number of supported instances can be set using CONFIG_BT_RAS_RRSP_MAX_ACTIVE_CONN.
*
* @param conn Connection instance.
*
* @return Zero in case of success and error code in case of error.
*/
int bt_ras_rrsp_alloc(struct bt_conn *conn);

/** @brief Free Ranging Responder instance for connection.
*
* This will free an allocated instance of the Ranging Responder service for
* the given connection, if one has been allocated.
* If the connection has no instance allocated, this method has no effect.
*
* @note This method must not be called if CONFIG_BT_RAS_RRSP_AUTO_ALLOC_INSTANCE is enabled.
*
* @param conn Connection instance.
*/
void bt_ras_rrsp_free(struct bt_conn *conn);

/** @brief Register ranging data buffer callbacks.
*
* Register callbacks to monitor ranging data buffer state.
*
* @param cb Callback struct. Must point to memory that remains valid.
*/
void bt_ras_rd_buffer_cb_register(struct bt_ras_rd_buffer_cb *cb);

/** @brief Check if a given ranging counter is available.
*
* Checks if the given ranging counter is stored in the buffer and
* has a valid complete ranging data body stored.
*
* @param conn Connection instance.
* @param ranging_counter CS procedure ranging counter.
*
* @retval true A buffer storing this ranging counter exists and can be claimed.
* @retval false A buffer storing this ranging counter does not exist.
*/
bool bt_ras_rd_buffer_ready_check(struct bt_conn *conn, uint16_t ranging_counter);

/** @brief Claim a buffer with a given ranging counter.
*
* Returns a pointer to a buffer storing a valid complete ranging data body with
* the requested procedure counter, and increments its reference counter.
*
* @param conn Connection instance.
* @param ranging_counter CS procedure ranging counter.
*
* @return Pointer to ranging data buffer structure or NULL if no such buffer exists.
*/
struct ras_rd_buffer *bt_ras_rd_buffer_claim(struct bt_conn *conn, uint16_t ranging_counter);

/** @brief Release a claimed ranging data buffer.
*
* Returns a buffer and decrements its reference counter.
* The buffer will stay available until overwritten by newer ranging data, if
* it has no remaining references.
*
* @param buf Pointer to claimed ranging data buffer.
*
* @retval 0 Success.
* @retval -EINVAL Invalid buffer provided.
*/
int bt_ras_rd_buffer_release(struct ras_rd_buffer *buf);

/** @brief Pull bytes from a ranging data buffer.
*
* Utility method to consume up to max_data_len bytes from a buffer.
* The provided read_cursor will be used as the initial offset and updated.
*
* @param buf Pointer to claimed ranging data buffer.
* @param out_buf Destination to copy up to max_data_len bytes to.
* @param max_data_len Maximum amount of bytes to copy from the buffer.
* @param read_cursor Current offset into procedure subevent buffer, will be read and written to.
* @param empty Set to true if all data has been read from the ranging data buffer.
*
* @return Number of bytes written into out_buf.
*/
int bt_ras_rd_buffer_bytes_pull(struct ras_rd_buffer *buf, uint8_t *out_buf, uint16_t max_data_len,
uint16_t *read_cursor, bool *empty);

#ifdef __cplusplus
}
#endif
Expand Down
30 changes: 27 additions & 3 deletions subsys/bluetooth/services/ras/Kconfig.ras
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,34 @@
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

config BT_RAS
bool
menuconfig BT_RAS
bool "Ranging Service [EXPERIMENTAL]"
depends on BT_CHANNEL_SOUNDING
select BT_NRF_SERVICES
select EXPERIMENTAL
help
Common Bluetooth GATT Ranging Service modules.
Bluetooth GATT Ranging Service modules - RREQ and RRSP.

if BT_RAS

rsource "rreq/Kconfig.ras_rreq"
rsource "rrsp/Kconfig.ras_rrsp"

config BT_RAS_MAX_ANTENNA_PATHS
int "Maximum number of antenna paths supported"
default 4
range 1 4
help
The number of antenna paths per step that can be stored inside RAS.
Must match the supported CS capabilities of the local device.
This affects the per-instance memory usage of RAS.

config BT_RAS_MODE_3_SUPPORTED
bool "Support storing Mode 3 CS steps"
default y
help
If enabled, RAS will allocate memory for storing Mode 3 CS steps.
Must match the supported CS capabilities of the local device.
This affects the per-instance memory usage of RAS.

endif # BT_RAS
1 change: 1 addition & 0 deletions subsys/bluetooth/services/ras/ras_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extern "C" {
#define RASCP_CMD_PARAMS_OFFSET RASCP_CMD_OPCODE_LEN
#define RASCP_CMD_PARAMS_MAX_LEN 4
#define RASCP_WRITE_MAX_LEN (RASCP_CMD_OPCODE_LEN + RASCP_CMD_PARAMS_MAX_LEN)
#define RASCP_ACK_DATA_TIMEOUT K_SECONDS(5)

/** @brief RAS Control Point opcodes as defined in RAS Specification, Table 3.10. */
enum rascp_opcode {
Expand Down
5 changes: 1 addition & 4 deletions subsys/bluetooth/services/ras/rreq/Kconfig.ras_rreq
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@
#

menuconfig BT_RAS_RREQ
bool "Enable GATT Ranging Requester Client [EXPERIMENTAL]"
depends on BT_CHANNEL_SOUNDING
bool "GATT Ranging Requester Client [EXPERIMENTAL]"
select EXPERIMENTAL
select BT_NRF_SERVICES
select BT_RAS

if BT_RAS_RREQ

Expand Down
3 changes: 2 additions & 1 deletion subsys/bluetooth/services/ras/rrsp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@

zephyr_library_sources_ifdef(
CONFIG_BT_RAS_RRSP
ras_rrsp.c)
ras_rrsp.c
ras_rd_buffer.c)
23 changes: 19 additions & 4 deletions subsys/bluetooth/services/ras/rrsp/Kconfig.ras_rrsp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,29 @@
#

menuconfig BT_RAS_RRSP
bool "Enable GATT Ranging Responder Server [EXPERIMENTAL]"
depends on BT_CHANNEL_SOUNDING
bool "GATT Ranging Responder Server [EXPERIMENTAL]"
select EXPERIMENTAL
select BT_NRF_SERVICES
select BT_RAS

if BT_RAS_RRSP

config BT_RAS_RRSP_AUTO_ALLOC_INSTANCE
bool "Automatically allocate RRSP instances to new connections"
default y

config BT_RAS_RRSP_MAX_ACTIVE_CONN
int "Number of simultaneously supported RRSP instances"
default BT_MAX_CONN
range 1 BT_MAX_CONN
help
The number of simultaneous connections with an instance of RAS RRSP

config BT_RAS_RRSP_RD_BUFFERS_PER_CONN
int "Number of ranging data buffers per connection"
default 1
range 1 10
help
The number of ranging procedures that can be stored inside RRSP.

module = BT_RAS_RRSP
module-str = RAS_RRSP
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
Expand Down
Loading

0 comments on commit 27bf358

Please sign in to comment.