Change use of dedicated memory pool for linked list nodes for node_rx_iq_report to common mem_link_rx. Former solution had a drawback. Released link nodes may be enqueued to wrong memory pool. E.g. link related with nopde_rx_iq_report went to common link memory pool, whereas link nodes from common pool were enqueued to dedicated list. The solution was working because links have the same memory layout, just different memory pools they originated from. The problem may occur if one of those link memory pools is reset. Then the same link may be used by node_rx and node_rx_iq_report at the same time, causing controller failure. Signed-off-by: Piotr Pryga <piotr.pryga@nordicsemi.no>
658 lines
18 KiB
C
658 lines
18 KiB
C
/*
|
|
* Copyright (c) 2020 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <zephyr.h>
|
|
#include <sys/util.h>
|
|
#include <bluetooth/hci.h>
|
|
|
|
#include "hal/cpu.h"
|
|
|
|
#include "util/util.h"
|
|
#include "util/mem.h"
|
|
#include "util/memq.h"
|
|
#include "util/mfifo.h"
|
|
|
|
#include "pdu.h"
|
|
|
|
#include "lll.h"
|
|
#include "lll/lll_adv_types.h"
|
|
#include "lll_adv.h"
|
|
#include "lll/lll_adv_pdu.h"
|
|
#include "lll_scan.h"
|
|
#include "lll/lll_df_types.h"
|
|
#include "lll_sync.h"
|
|
#include "lll_df.h"
|
|
#include "lll/lll_df_internal.h"
|
|
|
|
#include "ull_scan_types.h"
|
|
#include "ull_sync_types.h"
|
|
#include "ull_sync_internal.h"
|
|
#include "ull_adv_types.h"
|
|
#include "ull_df_types.h"
|
|
#include "ull_df_internal.h"
|
|
|
|
#include "ull_adv_internal.h"
|
|
#include "ull_internal.h"
|
|
|
|
#include "ll.h"
|
|
|
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_CTLR_DF_DEBUG_ENABLE)
|
|
#define LOG_MODULE_NAME bt_ctlr_ull_df
|
|
#include "common/log.h"
|
|
#include "hal/debug.h"
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
|
|
|
|
#define CTE_LEN_MAX_US 160U
|
|
|
|
#define IQ_REPORT_HEADER_SIZE (offsetof(struct node_rx_iq_report, pdu))
|
|
#define IQ_REPORT_STRUCT_OVERHEAD (IQ_REPORT_HEADER_SIZE)
|
|
#define IQ_SAMPLE_SIZE (sizeof(struct iq_sample))
|
|
|
|
#define IQ_REPORT_RX_NODE_POOL_ELEMENT_SIZE \
|
|
MROUND(IQ_REPORT_STRUCT_OVERHEAD + (IQ_SAMPLE_TOTAL_CNT * IQ_SAMPLE_SIZE))
|
|
#define IQ_REPORT_POOL_SIZE (IQ_REPORT_RX_NODE_POOL_ELEMENT_SIZE * IQ_REPORT_CNT)
|
|
|
|
/* Memory pool to store IQ reports data */
|
|
static struct {
|
|
void *free;
|
|
uint8_t pool[IQ_REPORT_POOL_SIZE];
|
|
} mem_iq_report;
|
|
|
|
/* FIFO to store free IQ report norde_rx objects. */
|
|
static MFIFO_DEFINE(iq_report_free, sizeof(void *), IQ_REPORT_CNT);
|
|
|
|
/* Number of available instance of linked list to be used for node_rx_iq_reports. */
|
|
static uint8_t mem_link_iq_report_quota_pdu;
|
|
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
|
|
|
|
/* ToDo:
|
|
* - Add release of df_adv_cfg when adv_sync is released.
|
|
* Open question, should df_adv_cfg be released when Adv. CTE is disabled?
|
|
* If yes that would mean, end user must always run ll_df_set_cl_cte_tx_params
|
|
* before consecutive Adv CTE enable.
|
|
*/
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
|
static struct lll_df_adv_cfg lll_df_adv_cfg_pool[CONFIG_BT_CTLR_ADV_AUX_SET];
|
|
static void *df_adv_cfg_free;
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
/* @brief Function performs common steps for initialization and reset
|
|
* of Direction Finding ULL module.
|
|
*
|
|
* @return Zero in case of success, other value in case of failure.
|
|
*/
|
|
static int init_reset(void);
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
|
/* @brief Function acquires memory for DF advertising configuration.
|
|
*
|
|
* The memory is acquired from private @ref lll_df_adv_cfg_pool memory store.
|
|
*
|
|
* @return Pointer to lll_df_adv_cfg or NULL if there is no more free memory.
|
|
*/
|
|
static struct lll_df_adv_cfg *df_adv_cfg_acquire(void);
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
/* @brief Function performs ULL Direction Finding initialization
|
|
*
|
|
* @return Zero in case of success, other value in case of failure.
|
|
*/
|
|
int ull_df_init(void)
|
|
{
|
|
int err;
|
|
|
|
err = init_reset();
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* @brief Function performs ULL Direction Finding reset
|
|
*
|
|
* @return Zero in case of success, other value in case of failure.
|
|
*/
|
|
int ull_df_reset(void)
|
|
{
|
|
int err;
|
|
|
|
err = init_reset();
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int init_reset(void)
|
|
{
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
|
/* Initialize advertising DF memory configuration pool. */
|
|
mem_init(lll_df_adv_cfg_pool, sizeof(struct lll_df_adv_cfg),
|
|
sizeof(lll_df_adv_cfg_pool) / sizeof(struct lll_df_adv_cfg),
|
|
&df_adv_cfg_free);
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
|
|
/* Re-initialize the free IQ report mfifo */
|
|
MFIFO_INIT(iq_report_free);
|
|
|
|
/* Initialize IQ report memory pool. */
|
|
mem_init(mem_iq_report.pool, (IQ_REPORT_RX_NODE_POOL_ELEMENT_SIZE),
|
|
sizeof(mem_iq_report.pool) / (IQ_REPORT_RX_NODE_POOL_ELEMENT_SIZE),
|
|
&mem_iq_report.free);
|
|
|
|
/* Allocate free IQ report node rx */
|
|
mem_link_iq_report_quota_pdu = IQ_REPORT_CNT;
|
|
ull_df_rx_iq_report_alloc(UINT8_MAX);
|
|
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
|
/* @brief Function sets CTE transmission parameters for periodic advertising.
|
|
*
|
|
* @param[in]adv_handle Handle of advertising set.
|
|
* @param[in]cte_len Length of CTE in 8us units.
|
|
* @param[in]cte_type Type of CTE to be used for transmission.
|
|
* @param[in]cte_count Number of CTE that should be transmitted
|
|
* during each periodic advertising
|
|
* interval.
|
|
* @param[in]num_ant_ids Number of antenna IDs in switching
|
|
* pattern. May be zero if CTE type is
|
|
* AoA.
|
|
* @param[in]ant_ids Array of antenna IDs in a switching
|
|
* pattern. May be NULL if CTE type is AoA.
|
|
*
|
|
* @return Status of command completion.
|
|
*/
|
|
uint8_t ll_df_set_cl_cte_tx_params(uint8_t adv_handle, uint8_t cte_len,
|
|
uint8_t cte_type, uint8_t cte_count,
|
|
uint8_t num_ant_ids, uint8_t *ant_ids)
|
|
{
|
|
struct lll_df_adv_cfg *cfg;
|
|
struct ll_adv_set *adv;
|
|
|
|
/* Get the advertising set instance */
|
|
adv = ull_adv_is_created_get(adv_handle);
|
|
if (!adv) {
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
|
}
|
|
|
|
if (cte_len < BT_HCI_LE_CTE_LEN_MIN ||
|
|
cte_len > BT_HCI_LE_CTE_LEN_MAX) {
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
|
}
|
|
|
|
/* ToDo: Check if there is a limit of per. adv. pdu that may be
|
|
* sent. This affects number of CTE that may be requested.
|
|
*/
|
|
if (cte_count < BT_HCI_LE_CTE_COUNT_MIN ||
|
|
cte_count > BT_HCI_LE_CTE_COUNT_MAX) {
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
|
}
|
|
|
|
if (!(IS_ENABLED(CONFIG_BT_CTLR_DF_ADV_CTE_TX) &&
|
|
((cte_type == BT_HCI_LE_AOA_CTE) ||
|
|
(IS_ENABLED(CONFIG_BT_CTLR_DF_ANT_SWITCH_TX) &&
|
|
((cte_type == BT_HCI_LE_AOD_CTE_2US) ||
|
|
(IS_ENABLED(CONFIG_BT_CTLR_DF_ANT_SWITCH_1US) &&
|
|
cte_type == BT_HCI_LE_AOD_CTE_1US)))))) {
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
|
}
|
|
|
|
if ((cte_type == BT_HCI_LE_AOD_CTE_1US ||
|
|
cte_type == BT_HCI_LE_AOD_CTE_2US) &&
|
|
(num_ant_ids < LLL_DF_MIN_ANT_PATTERN_LEN ||
|
|
num_ant_ids > BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN ||
|
|
!ant_ids)) {
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
|
}
|
|
|
|
if (!adv->df_cfg) {
|
|
adv->df_cfg = df_adv_cfg_acquire();
|
|
}
|
|
|
|
cfg = adv->df_cfg;
|
|
|
|
if (cfg->is_enabled) {
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
}
|
|
|
|
cfg->cte_count = cte_count;
|
|
cfg->cte_length = cte_len;
|
|
cfg->cte_type = cte_type;
|
|
|
|
if (cte_type == BT_HCI_LE_AOD_CTE_1US ||
|
|
cte_type == BT_HCI_LE_AOD_CTE_2US) {
|
|
/* Note:
|
|
* Are we going to check antenna identifiers if they are valid?
|
|
* BT 5.2 Core spec. Vol. 4 Part E Section 7.8.80 says
|
|
* that not all controller may be able to do that.
|
|
*/
|
|
memcpy(cfg->ant_ids, ant_ids, num_ant_ids);
|
|
cfg->ant_sw_len = num_ant_ids;
|
|
} else {
|
|
cfg->ant_sw_len = 0;
|
|
}
|
|
|
|
return BT_HCI_ERR_SUCCESS;
|
|
}
|
|
|
|
/* @brief Function enables or disables CTE TX for periodic advertising.
|
|
*
|
|
* @param[in] handle Advertising set handle.
|
|
* @param[in] cte_enable Enable or disable CTE TX
|
|
*
|
|
* @return Status of command completion.
|
|
*/
|
|
uint8_t ll_df_set_cl_cte_tx_enable(uint8_t adv_handle, uint8_t cte_enable)
|
|
{
|
|
struct lll_adv_sync *lll_sync;
|
|
struct lll_df_adv_cfg *df_cfg;
|
|
struct ll_adv_sync_set *sync;
|
|
struct ll_adv_set *adv;
|
|
uint8_t err, ter_idx;
|
|
|
|
/* Get the advertising set instance */
|
|
adv = ull_adv_is_created_get(adv_handle);
|
|
if (!adv) {
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
|
}
|
|
|
|
lll_sync = adv->lll.sync;
|
|
/* If there is no sync in advertising set, then the HCI_LE_Set_-
|
|
* Periodic_Advertising_Parameters command was not issued before.
|
|
*/
|
|
if (!lll_sync) {
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
}
|
|
|
|
sync = HDR_LLL2ULL(lll_sync);
|
|
|
|
/* If df_cfg is NULL, then the HCI_LE_Set_Connectionless_CTE_Transmit_-
|
|
* Parameters command was not issued before.
|
|
*/
|
|
df_cfg = adv->df_cfg;
|
|
if (!df_cfg) {
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
}
|
|
|
|
if (adv->lll.phy_s == PHY_CODED) {
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
}
|
|
|
|
if (!cte_enable) {
|
|
if (!df_cfg->is_enabled) {
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
}
|
|
|
|
err = ull_adv_sync_pdu_set_clear(adv, 0,
|
|
ULL_ADV_PDU_HDR_FIELD_CTE_INFO,
|
|
NULL, &ter_idx);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
if (sync->is_started) {
|
|
/* If CTE is disabled when advertising is pending,
|
|
* decrease advertising event length
|
|
*/
|
|
ull_adv_sync_update(sync, 0, df_cfg->cte_length);
|
|
/* ToDo decrease number of chain PDUs in pending
|
|
* advertising if there are added empty chain PDUs
|
|
* to sent requested number of CTEs in a chain
|
|
*/
|
|
}
|
|
|
|
df_cfg->is_enabled = 0U;
|
|
} else {
|
|
struct pdu_cte_info cte_info;
|
|
struct adv_pdu_field_data pdu_data;
|
|
|
|
if (df_cfg->is_enabled) {
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
}
|
|
|
|
cte_info.type = df_cfg->cte_type;
|
|
cte_info.time = df_cfg->cte_length;
|
|
pdu_data.field_data = (uint8_t *)&cte_info;
|
|
pdu_data.extra_data = df_cfg;
|
|
err = ull_adv_sync_pdu_set_clear(adv,
|
|
ULL_ADV_PDU_HDR_FIELD_CTE_INFO,
|
|
0, &pdu_data, &ter_idx);
|
|
if (err) {
|
|
return err;
|
|
}
|
|
|
|
if (sync->is_started) {
|
|
/* If CTE is enabled when advertising is pending,
|
|
* increase advertising event length
|
|
*/
|
|
ull_adv_sync_update(sync, df_cfg->cte_length, 0);
|
|
/* ToDo increase number of chain PDUs in pending
|
|
* advertising if requested more CTEs than available
|
|
* PDU with advertising data.
|
|
*/
|
|
}
|
|
|
|
df_cfg->is_enabled = 1U;
|
|
}
|
|
|
|
lll_adv_sync_data_enqueue(adv->lll.sync, ter_idx);
|
|
|
|
return BT_HCI_ERR_SUCCESS;
|
|
}
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
/* @brief Function sets CTE transmission parameters for a connection.
|
|
*
|
|
* @param[in]handle Connection handle.
|
|
* @param[in]cte_types Bitfield holding information about
|
|
* allowed CTE types.
|
|
* @param[in]switch_pattern_len Number of antenna ids in switch pattern.
|
|
* @param[in]ant_id Array of antenna identifiers.
|
|
*
|
|
* @return Status of command completion.
|
|
*/
|
|
uint8_t ll_df_set_conn_cte_tx_params(uint16_t handle, uint8_t cte_types,
|
|
uint8_t switch_pattern_len,
|
|
uint8_t *ant_id)
|
|
{
|
|
if (cte_types & BT_HCI_LE_AOD_CTE_RSP_1US ||
|
|
cte_types & BT_HCI_LE_AOD_CTE_RSP_2US) {
|
|
|
|
if (!IS_ENABLED(CONFIG_BT_CTLR_DF_ANT_SWITCH_TX)) {
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
|
}
|
|
|
|
if (switch_pattern_len < BT_HCI_LE_SWITCH_PATTERN_LEN_MIN ||
|
|
switch_pattern_len > BT_HCI_LE_SWITCH_PATTERN_LEN_MAX ||
|
|
!ant_id) {
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
|
}
|
|
}
|
|
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
}
|
|
|
|
/* @brief Function provides information about Direction Finding
|
|
* antennas switching and sampling related settings.
|
|
*
|
|
* @param[out]switch_sample_rates Pointer to store available antennas
|
|
* switch-sampling configurations.
|
|
* @param[out]num_ant Pointer to store number of available
|
|
* antennas.
|
|
* @param[out]max_switch_pattern_len Pointer to store maximum number of
|
|
* antennas ids in switch pattern.
|
|
* @param[out]max_cte_len Pointer to store maximum length of CTE
|
|
* in [8us] units.
|
|
*/
|
|
void ll_df_read_ant_inf(uint8_t *switch_sample_rates,
|
|
uint8_t *num_ant,
|
|
uint8_t *max_switch_pattern_len,
|
|
uint8_t *max_cte_len)
|
|
{
|
|
*switch_sample_rates = 0;
|
|
if (IS_ENABLED(CONFIG_BT_CTLR_DF_ANT_SWITCH_TX) &&
|
|
IS_ENABLED(CONFIG_BT_CTLR_DF_ANT_SWITCH_1US)) {
|
|
*switch_sample_rates |= DF_AOD_1US_TX;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_CTLR_DF_CTE_RX) &&
|
|
IS_ENABLED(CONFIG_BT_CTLR_DF_CTE_RX_SAMPLE_1US)) {
|
|
*switch_sample_rates |= DF_AOD_1US_RX;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_BT_CTLR_DF_ANT_SWITCH_RX) &&
|
|
IS_ENABLED(CONFIG_BT_CTLR_DF_CTE_RX_SAMPLE_1US)) {
|
|
*switch_sample_rates |= DF_AOA_1US;
|
|
}
|
|
|
|
*max_switch_pattern_len = BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN;
|
|
*num_ant = lll_df_ant_num_get();
|
|
*max_cte_len = LLL_DF_MAX_CTE_LEN;
|
|
}
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
|
|
/* @brief Function sets IQ sampling enabled or disabled.
|
|
*
|
|
* Set IQ sampling enable for received PDUs that has attached CTE.
|
|
*
|
|
* @param[in]handle Connection handle.
|
|
* @param[in]sampling_enable Enable or disable CTE RX
|
|
* @param[in]slot_durations Switching and samplig slot durations for
|
|
* AoA mode.
|
|
* @param[in]max_cte_count Maximum number of sampled CTEs in single
|
|
* periodic advertising event.
|
|
* @param[in]switch_pattern_len Number of antenna ids in switch pattern.
|
|
* @param[in]ant_ids Array of antenna identifiers.
|
|
*
|
|
* @return Status of command completion.
|
|
*
|
|
* @Note This function may put TX thread into wait state. This may lead to a
|
|
* situation that ll_sync_set instnace is relased (RX thread has higher
|
|
* priority than TX thread). l_sync_set instance may not be accessed after
|
|
* call to ull_sync_slot_update.
|
|
* This is related with possible race condition with RX thread handling
|
|
* periodic sync lost event.
|
|
*/
|
|
uint8_t ll_df_set_cl_iq_sampling_enable(uint16_t handle,
|
|
uint8_t sampling_enable,
|
|
uint8_t slot_durations,
|
|
uint8_t max_cte_count,
|
|
uint8_t switch_pattern_len,
|
|
uint8_t *ant_ids)
|
|
{
|
|
struct lll_df_sync_cfg *cfg, *cfg_prev;
|
|
uint32_t slot_minus_us = 0;
|
|
uint32_t slot_plus_us = 0;
|
|
struct ll_sync_set *sync;
|
|
struct lll_sync *lll;
|
|
uint8_t cfg_idx;
|
|
|
|
/* After this call and before ull_sync_slot_update the function may not
|
|
* call any kernel API that may put the thread into wait state. It may
|
|
* cause race condition with RX thread and lead to use of released memory.
|
|
*/
|
|
sync = ull_sync_is_enabled_get(handle);
|
|
if (!sync) {
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
|
}
|
|
|
|
lll = &sync->lll;
|
|
|
|
/* CTE is not supported for CODED Phy */
|
|
if (lll->phy == PHY_CODED) {
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
}
|
|
|
|
cfg_prev = lll_df_sync_cfg_curr_get(&lll->df_cfg);
|
|
cfg = lll_df_sync_cfg_alloc(&lll->df_cfg, &cfg_idx);
|
|
|
|
if (!sampling_enable) {
|
|
if (!cfg_prev->is_enabled) {
|
|
/* Disable already disabled CTE Rx */
|
|
return BT_HCI_ERR_SUCCESS;
|
|
}
|
|
slot_minus_us = CTE_LEN_MAX_US;
|
|
cfg->is_enabled = 0U;
|
|
} else {
|
|
/* Enable of already enabled CTE updates AoA configuration */
|
|
if (!((IS_ENABLED(CONFIG_BT_CTLR_DF_ANT_SWITCH_1US) &&
|
|
slot_durations == BT_HCI_LE_ANTENNA_SWITCHING_SLOT_1US) ||
|
|
slot_durations == BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US)) {
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
|
}
|
|
|
|
/* max_cte_count equal to 0x0 has special meaning - sample and
|
|
* report continuously until there are CTEs received.
|
|
*/
|
|
if (max_cte_count > BT_HCI_LE_SAMPLE_CTE_COUNT_MAX) {
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
|
}
|
|
|
|
if (switch_pattern_len < BT_HCI_LE_SWITCH_PATTERN_LEN_MIN ||
|
|
switch_pattern_len > BT_CTLR_DF_MAX_ANT_SW_PATTERN_LEN ||
|
|
!ant_ids) {
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
|
}
|
|
|
|
cfg->slot_durations = slot_durations;
|
|
cfg->max_cte_count = max_cte_count;
|
|
memcpy(cfg->ant_ids, ant_ids, switch_pattern_len);
|
|
cfg->ant_sw_len = switch_pattern_len;
|
|
|
|
cfg->is_enabled = 1U;
|
|
|
|
if (!cfg_prev->is_enabled) {
|
|
/* Extend sync event by maximum CTE duration.
|
|
* CTE duration denepnds on transmitter configuration
|
|
* so it is unknown for receiver upfront.
|
|
*/
|
|
slot_plus_us = BT_HCI_LE_CTE_LEN_MAX;
|
|
}
|
|
}
|
|
|
|
lll_df_sync_cfg_enqueue(&lll->df_cfg, cfg_idx);
|
|
|
|
if (slot_plus_us || slot_minus_us) {
|
|
int err;
|
|
/* Update of sync slot may fail due to race condition.
|
|
* If periodic sync is lost, the ticker event will be stopped.
|
|
* The stop operation may preempt call to this functions.
|
|
* So update may be called after that. Accept this failure
|
|
* (-ENOENT) gracefully.
|
|
* Periodic sync lost event also disables the CTE sampling.
|
|
*/
|
|
err = ull_sync_slot_update(sync, 0, CTE_LEN_MAX_US);
|
|
LL_ASSERT(err == 0 || err == -ENOENT);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *ull_df_iq_report_alloc_peek(uint8_t count)
|
|
{
|
|
if (count > MFIFO_AVAIL_COUNT_GET(iq_report_free)) {
|
|
return NULL;
|
|
}
|
|
|
|
return MFIFO_DEQUEUE_PEEK(iq_report_free);
|
|
}
|
|
|
|
void *ull_df_iq_report_alloc_peek_iter(uint8_t *idx)
|
|
{
|
|
return *(void **)MFIFO_DEQUEUE_ITER_GET(iq_report_free, idx);
|
|
}
|
|
|
|
void *ull_df_iq_report_alloc(void)
|
|
{
|
|
return MFIFO_DEQUEUE(iq_report_free);
|
|
}
|
|
|
|
void ull_df_iq_report_mem_release(struct node_rx_hdr *rx)
|
|
{
|
|
mem_release(rx, &mem_iq_report.free);
|
|
}
|
|
|
|
void ull_iq_report_link_inc_quota(int8_t delta)
|
|
{
|
|
LL_ASSERT(delta <= 0 || mem_link_iq_report_quota_pdu < IQ_REPORT_CNT);
|
|
mem_link_iq_report_quota_pdu += delta;
|
|
}
|
|
|
|
void ull_df_rx_iq_report_alloc(uint8_t max)
|
|
{
|
|
uint8_t idx;
|
|
|
|
if (max > mem_link_iq_report_quota_pdu) {
|
|
max = mem_link_iq_report_quota_pdu;
|
|
}
|
|
|
|
while ((max--) && MFIFO_ENQUEUE_IDX_GET(iq_report_free, &idx)) {
|
|
memq_link_t *link;
|
|
struct node_rx_hdr *rx;
|
|
|
|
link = ll_rx_link_alloc();
|
|
if (!link) {
|
|
return;
|
|
}
|
|
|
|
rx = mem_acquire(&mem_iq_report.free);
|
|
if (!rx) {
|
|
ll_rx_link_release(link);
|
|
return;
|
|
}
|
|
|
|
rx->link = link;
|
|
|
|
MFIFO_BY_IDX_ENQUEUE(iq_report_free, idx, rx);
|
|
|
|
ull_iq_report_link_inc_quota(-1);
|
|
}
|
|
}
|
|
|
|
void ull_df_sync_cfg_init(struct lll_df_sync *cfg)
|
|
{
|
|
memset(&cfg->cfg[0], 0, DOUBLE_BUFFER_SIZE * sizeof(cfg->cfg[0]));
|
|
cfg->first = 0U;
|
|
cfg->last = 0U;
|
|
}
|
|
|
|
uint8_t ull_df_sync_cfg_is_disabled_or_requested_to_disable(struct lll_df_sync *df_cfg)
|
|
{
|
|
struct lll_df_sync_cfg *cfg;
|
|
|
|
/* If new CTE sampling configuration was enqueued, get reference to
|
|
* latest congiruation without swapping buffers. Buffer should be
|
|
* swapped only at the beginning of the radio event.
|
|
*
|
|
* We may not get here if CTE sampling is not enabled in current
|
|
* configuration.
|
|
*/
|
|
if (lll_df_sync_cfg_is_modified(df_cfg)) {
|
|
cfg = lll_df_sync_cfg_peek(df_cfg);
|
|
} else {
|
|
cfg = lll_df_sync_cfg_curr_get(df_cfg);
|
|
}
|
|
|
|
return !cfg->is_enabled;
|
|
}
|
|
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
|
/* @brief Function releases unused memory for DF advertising configuration.
|
|
*
|
|
* The memory is released to private @ref lll_df_adv_cfg_pool memory store.
|
|
*
|
|
* @param[in] df_adv_cfg Pointer to lll_df_adv_cfg memory to be released.
|
|
*/
|
|
void ull_df_adv_cfg_release(struct lll_df_adv_cfg *df_adv_cfg)
|
|
{
|
|
mem_release(df_adv_cfg, &df_adv_cfg_free);
|
|
}
|
|
|
|
static struct lll_df_adv_cfg *df_adv_cfg_acquire(void)
|
|
{
|
|
struct lll_df_adv_cfg *df_adv_cfg;
|
|
|
|
df_adv_cfg = mem_acquire(&df_adv_cfg_free);
|
|
if (!df_adv_cfg) {
|
|
return NULL;
|
|
}
|
|
|
|
df_adv_cfg->is_enabled = 0U;
|
|
|
|
return df_adv_cfg;
|
|
}
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|