Bluetooth: Controller: Implement PAST support in ULL

Implement PAST support in ULL and fixed test after changed
dependencies in ull_sync_internal.c

Signed-off-by: Lucas Mathias Balling <lutb@demant.com>
This commit is contained in:
Lucas Mathias Balling 2024-10-04 13:30:20 +02:00 committed by Carles Cufí
commit cb0e3a7646
23 changed files with 1204 additions and 207 deletions

View file

@ -1036,6 +1036,19 @@ static void read_supported_commands(struct net_buf *buf, struct net_buf **evt)
#endif /* CONFIG_BT_CTLR_DF */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
/* LE Periodic Advertising Sync Transfer */
rp->commands[40] |= BIT(6);
/* LE Periodic Advertising Set Info Transfer */
rp->commands[40] |= BIT(7);
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
/* LE Set Periodic Advertising Sync Transfer Parameters */
rp->commands[41] |= BIT(0);
/* LE Set Default Periodic Advertising Sync Transfer Parameters */
rp->commands[41] |= BIT(1);
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
#if defined(CONFIG_BT_HCI_RAW) && defined(CONFIG_BT_TINYCRYPT_ECC)
bt_hci_ecc_supported_commands(rp->commands);
#endif /* CONFIG_BT_HCI_RAW && CONFIG_BT_TINYCRYPT_ECC */
@ -4081,6 +4094,110 @@ static void le_read_pal_size(struct net_buf *buf, struct net_buf **evt)
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
#endif /* CONFIG_BT_OBSERVER */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
static void le_per_adv_sync_transfer(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_le_per_adv_sync_transfer *cmd = (void *)buf->data;
struct bt_hci_rp_le_per_adv_sync_transfer *rp;
uint16_t conn_handle, conn_handle_le16;
uint16_t service_data;
uint16_t sync_handle;
uint8_t status;
conn_handle_le16 = cmd->conn_handle;
conn_handle = sys_le16_to_cpu(cmd->conn_handle);
service_data = sys_le16_to_cpu(cmd->service_data);
sync_handle = sys_le16_to_cpu(cmd->sync_handle);
status = ll_sync_transfer(conn_handle, service_data, sync_handle);
rp = hci_cmd_complete(evt, sizeof(*rp));
rp->conn_handle = conn_handle_le16;
rp->status = status;
}
static void le_per_adv_set_info_transfer(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_le_per_adv_set_info_transfer *cmd = (void *)buf->data;
struct bt_hci_rp_le_per_adv_set_info_transfer *rp;
uint16_t conn_handle, conn_handle_le16;
uint16_t service_data;
uint8_t adv_handle;
uint8_t status;
conn_handle_le16 = cmd->conn_handle;
conn_handle = sys_le16_to_cpu(cmd->conn_handle);
service_data = sys_le16_to_cpu(cmd->service_data);
adv_handle = cmd->adv_handle;
status = ll_adv_sync_set_info_transfer(conn_handle, service_data, adv_handle);
rp = hci_cmd_complete(evt, sizeof(*rp));
rp->conn_handle = conn_handle_le16;
rp->status = status;
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
static void le_past_param(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_le_past_param *cmd = (void *)buf->data;
struct bt_hci_rp_le_past_param *rp;
uint16_t conn_handle_le16;
uint16_t conn_handle;
uint16_t timeout;
uint8_t cte_type;
uint8_t status;
uint16_t skip;
uint8_t mode;
if (adv_cmds_ext_check(evt)) {
return;
}
conn_handle_le16 = cmd->conn_handle;
conn_handle = sys_le16_to_cpu(cmd->conn_handle);
mode = cmd->mode;
skip = sys_le16_to_cpu(cmd->skip);
timeout = sys_le16_to_cpu(cmd->timeout);
cte_type = cmd->cte_type;
status = ll_past_param(conn_handle, mode, skip, timeout, cte_type);
rp = hci_cmd_complete(evt, sizeof(*rp));
rp->conn_handle = conn_handle_le16;
rp->status = status;
}
static void le_default_past_param(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_le_default_past_param *cmd = (void *)buf->data;
struct bt_hci_rp_le_default_past_param *rp;
uint16_t timeout;
uint8_t cte_type;
uint8_t status;
uint16_t skip;
uint8_t mode;
if (adv_cmds_ext_check(evt)) {
return;
}
mode = cmd->mode;
skip = sys_le16_to_cpu(cmd->skip);
timeout = sys_le16_to_cpu(cmd->timeout);
cte_type = cmd->cte_type;
status = ll_default_past_param(mode, skip, timeout, cte_type);
rp = hci_cmd_complete(evt, sizeof(*rp));
rp->status = status;
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
#if defined(CONFIG_BT_CENTRAL)
static void le_ext_create_connection(struct net_buf *buf, struct net_buf **evt)
{
@ -4297,6 +4414,51 @@ static void le_cis_established(struct pdu_data *pdu_data,
}
#endif /* CONFIG_BT_CTLR_CONN_ISO */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
static void le_per_adv_sync_transfer_received(struct pdu_data *pdu_data_rx,
struct node_rx_pdu *node_rx, struct net_buf *buf)
{
struct bt_hci_evt_le_past_received *sep;
struct node_rx_past_received *se;
struct ll_sync_set *sync;
void *node;
if (!(event_mask & BT_EVT_MASK_LE_META_EVENT) ||
!(le_event_mask & BT_EVT_MASK_LE_PAST_RECEIVED)) {
return;
}
sep = meta_evt(buf, BT_HCI_EVT_LE_PAST_RECEIVED, sizeof(*sep));
/* Check for pdu field being aligned before accessing PAST received
* event.
*/
node = pdu_data_rx;
LL_ASSERT(IS_PTR_ALIGNED(node, struct node_rx_past_received));
se = node;
sep->status = se->rx_sync.status;
sync = node_rx->rx_ftr.param;
/* Resolved address, if private, has been populated in ULL */
sep->addr.type = sync->peer_id_addr_type;
if (sync->peer_addr_resolved) {
/* Mark it as identity address from RPA (0x02, 0x03) */
MARK_AS_IDENTITY_ADDR(sep->addr.type);
}
(void)memcpy(sep->addr.a.val, sync->peer_id_addr, BDADDR_SIZE);
sep->adv_sid = sync->sid;
sep->phy = find_lsb_set(se->rx_sync.phy);
sep->interval = sys_cpu_to_le16(se->rx_sync.interval);
sep->clock_accuracy = se->rx_sync.sca;
sep->conn_handle = sys_cpu_to_le16(se->conn_handle);
sep->service_data = sys_cpu_to_le16(se->service_data);
sep->sync_handle = sys_cpu_to_le16(node_rx->hdr.handle);
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
static int controller_cmd_handle(uint16_t ocf, struct net_buf *cmd,
struct net_buf **evt, void **node_rx)
{
@ -4671,6 +4833,26 @@ static int controller_cmd_handle(uint16_t ocf, struct net_buf *cmd,
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
#endif /* CONFIG_BT_OBSERVER */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
case BT_OCF(BT_HCI_OP_LE_PER_ADV_SYNC_TRANSFER):
le_per_adv_sync_transfer(cmd, evt);
break;
case BT_OCF(BT_HCI_OP_LE_PER_ADV_SET_INFO_TRANSFER):
le_per_adv_set_info_transfer(cmd, evt);
break;
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
case BT_OCF(BT_HCI_OP_LE_PAST_PARAM):
le_past_param(cmd, evt);
break;
case BT_OCF(BT_HCI_OP_LE_DEFAULT_PAST_PARAM):
le_default_past_param(cmd, evt);
break;
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
#if defined(CONFIG_BT_CONN)
#if defined(CONFIG_BT_CENTRAL)
case BT_OCF(BT_HCI_OP_LE_EXT_CREATE_CONN):
@ -6306,7 +6488,7 @@ static inline void le_dir_adv_report(struct pdu_adv *adv, struct net_buf *buf,
ll_rl_id_addr_get(rl_idx, &dir_info->addr.type,
&dir_info->addr.a.val[0]);
/* Mark it as identity address from RPA (0x02, 0x03) */
dir_info->addr.type += 2U;
MARK_AS_IDENTITY_ADDR(dir_info->addr.type);
} else {
#else
if (1) {
@ -6466,7 +6648,7 @@ static void le_advertising_report(struct pdu_data *pdu_data,
ll_rl_id_addr_get(rl_idx, &adv_info->addr.type,
&adv_info->addr.a.val[0]);
/* Mark it as identity address from RPA (0x02, 0x03) */
adv_info->addr.type += 2U;
MARK_AS_IDENTITY_ADDR(adv_info->addr.type);
} else {
#else
if (1) {
@ -6571,7 +6753,7 @@ static void le_ext_adv_legacy_report(struct pdu_data *pdu_data,
ll_rl_id_addr_get(rl_idx, &adv_info->addr.type,
&adv_info->addr.a.val[0]);
/* Mark it as identity address from RPA (0x02, 0x03) */
adv_info->addr.type += 2U;
MARK_AS_IDENTITY_ADDR(adv_info->addr.type);
} else
#endif /* CONFIG_BT_CTLR_PRIVACY */
{
@ -6763,7 +6945,7 @@ static void ext_adv_info_fill(uint8_t evt_type, uint8_t phy, uint8_t sec_phy,
ll_rl_id_addr_get(rl_idx, &adv_info->addr.type,
adv_info->addr.a.val);
/* Mark it as identity address from RPA (0x02, 0x03) */
adv_info->addr.type += 2U;
MARK_AS_IDENTITY_ADDR(adv_info->addr.type);
#else /* !CONFIG_BT_CTLR_PRIVACY */
ARG_UNUSED(rl_idx);
#endif /* !CONFIG_BT_CTLR_PRIVACY */
@ -7438,7 +7620,7 @@ static void le_per_adv_sync_established(struct pdu_data *pdu_data,
struct net_buf *buf)
{
struct bt_hci_evt_le_per_adv_sync_established *sep;
struct ll_scan_set *scan;
struct ll_sync_set *sync;
struct node_rx_sync *se;
void *node;
@ -7463,13 +7645,11 @@ static void le_per_adv_sync_established(struct pdu_data *pdu_data,
return;
}
scan = node_rx->rx_ftr.param;
sync = node_rx->rx_ftr.param;
#if (CONFIG_BT_CTLR_DUP_FILTER_LEN > 0) && \
defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
dup_periodic_adv_reset(scan->periodic.adv_addr_type,
scan->periodic.adv_addr,
scan->periodic.sid);
dup_periodic_adv_reset(sync->peer_id_addr_type, sync->peer_id_addr, sync->sid);
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 &&
* CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT
*/
@ -7477,10 +7657,14 @@ static void le_per_adv_sync_established(struct pdu_data *pdu_data,
sep->handle = sys_cpu_to_le16(node_rx->hdr.handle);
/* Resolved address, if private, has been populated in ULL */
sep->adv_addr.type = scan->periodic.adv_addr_type;
(void)memcpy(sep->adv_addr.a.val, scan->periodic.adv_addr, BDADDR_SIZE);
sep->adv_addr.type = sync->peer_id_addr_type;
if (sync->peer_addr_resolved) {
/* Mark it as identity address from RPA (0x02, 0x03) */
MARK_AS_IDENTITY_ADDR(sep->adv_addr.type);
}
(void)memcpy(sep->adv_addr.a.val, sync->peer_id_addr, BDADDR_SIZE);
sep->sid = scan->periodic.sid;
sep->sid = sync->sid;
sep->phy = find_lsb_set(se->phy);
sep->interval = sys_cpu_to_le16(se->interval);
sep->clock_accuracy = se->sca;
@ -8077,7 +8261,7 @@ static void le_scan_req_received(struct pdu_data *pdu_data,
ll_rl_id_addr_get(rl_idx, &sep->addr.type,
&sep->addr.a.val[0]);
/* Mark it as identity address from RPA (0x02, 0x03) */
sep->addr.type += 2U;
MARK_AS_IDENTITY_ADDR(sep->addr.type);
} else {
#else
if (1) {
@ -8117,7 +8301,7 @@ static void le_vs_scan_req_received(struct pdu_data *pdu,
ll_rl_id_addr_get(rl_idx, &sep->addr.type,
&sep->addr.a.val[0]);
/* Mark it as identity address from RPA (0x02, 0x03) */
sep->addr.type += 2U;
MARK_AS_IDENTITY_ADDR(sep->addr.type);
} else {
#else
if (1) {
@ -8465,6 +8649,12 @@ static void encode_control(struct node_rx_pdu *node_rx,
le_per_adv_sync_lost(pdu_data, node_rx, buf);
break;
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
case NODE_RX_TYPE_SYNC_TRANSFER_RECEIVED:
le_per_adv_sync_transfer_received(pdu_data, node_rx, buf);
return;
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
case NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT:
#if defined(CONFIG_BT_CTLR_DF_VS_CL_IQ_REPORT_16_BITS_IQ_SAMPLES)
@ -9009,6 +9199,10 @@ uint8_t hci_get_class(struct node_rx_pdu *node_rx)
case NODE_RX_TYPE_SYNC_REPORT:
case NODE_RX_TYPE_SYNC_LOST:
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
case NODE_RX_TYPE_SYNC_TRANSFER_RECEIVED:
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
case NODE_RX_TYPE_SYNC_IQ_SAMPLE_REPORT:
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */

View file

@ -135,6 +135,12 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
uint8_t ll_sync_create_cancel(void **rx);
uint8_t ll_sync_terminate(uint16_t handle);
uint8_t ll_sync_recv_enable(uint16_t handle, uint8_t enable);
uint8_t ll_sync_transfer(uint16_t conn_handle, uint16_t service_data, uint16_t sync_handle);
uint8_t ll_adv_sync_set_info_transfer(uint16_t conn_handle, uint16_t service_data,
uint8_t adv_handle);
uint8_t ll_past_param(uint16_t conn_handle, uint8_t mode, uint16_t skip, uint16_t timeout,
uint8_t cte_type);
uint8_t ll_default_past_param(uint8_t mode, uint16_t skip, uint16_t timeout, uint8_t cte_type);
uint8_t ll_big_sync_create(uint8_t big_handle, uint16_t sync_handle,
uint8_t encryption, uint8_t *bcode, uint8_t mse,
uint16_t sync_timeout, uint8_t num_bis,

View file

@ -33,6 +33,7 @@
#include "lll_iso_tx.h"
#include "isoal.h"
#include "ull_iso_types.h"
#include "ull_internal.h"
#include <zephyr/logging/log.h>
@ -134,12 +135,7 @@ isoal_status_t isoal_reset(void)
*/
uint32_t isoal_get_wrapped_time_us(uint32_t time_now_us, int32_t time_diff_us)
{
LL_ASSERT(time_now_us <= ISOAL_TIME_WRAPPING_POINT_US);
uint32_t result = ((uint64_t)time_now_us + ISOAL_TIME_SPAN_FULL_US + time_diff_us) %
((uint64_t)ISOAL_TIME_SPAN_FULL_US);
return result;
return ull_get_wrapped_time_us(time_now_us, time_diff_us);
}
/**

View file

@ -319,6 +319,7 @@ enum node_rx_type {
NODE_RX_TYPE_DTM_IQ_SAMPLE_REPORT,
NODE_RX_TYPE_IQ_SAMPLE_REPORT_ULL_RELEASE,
NODE_RX_TYPE_IQ_SAMPLE_REPORT_LLL_RELEASE,
NODE_RX_TYPE_SYNC_TRANSFER_RECEIVED,
/* Signals retention (ie non-release) of rx node */
NODE_RX_TYPE_RETAIN,

View file

@ -100,6 +100,7 @@ extern uint8_t ull_filter_lll_fal_match(struct lll_filter const *const filter,
uint8_t *devmatch_id);
extern bool ull_filter_lll_lrpa_used(uint8_t rl_idx);
extern bt_addr_t *ull_filter_lll_lrpa_get(uint8_t rl_idx);
extern bt_addr_t *ull_filter_lll_id_addr_get(uint8_t rl_idx, uint8_t *id_addr_type);
extern uint8_t *ull_filter_lll_irks_get(uint8_t *count);
extern uint8_t ull_filter_lll_rl_idx(bool fal, uint8_t devmatch_id);
extern uint8_t ull_filter_lll_rl_irk_idx(uint8_t irkmatch_id);

View file

@ -195,6 +195,11 @@ lll_adv_sync_data_latest_peek(const struct lll_adv_sync *const lll)
return lll_adv_pdu_latest_peek(&lll->data);
}
static inline struct pdu_adv *lll_adv_sync_data_curr_get(struct lll_adv_sync *lll)
{
return (void *)lll->data.pdu[lll->data.first];
}
#if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY)
static inline void *lll_adv_sync_extra_data_peek(struct lll_adv_sync *lll)
{

View file

@ -506,6 +506,16 @@ static struct {
static MEMQ_DECLARE(ull_rx);
static MEMQ_DECLARE(ll_rx);
#if defined(CONFIG_BT_CTLR_ISO) || \
defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER) || \
defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
#define ULL_TIME_WRAPPING_POINT_US (HAL_TICKER_TICKS_TO_US_64BIT(HAL_TICKER_CNTR_MASK))
#define ULL_TIME_SPAN_FULL_US (ULL_TIME_WRAPPING_POINT_US + 1)
#endif /* CONFIG_BT_CTLR_ISO ||
* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER ||
* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER
*/
#if defined(CONFIG_BT_CONN)
static MFIFO_DEFINE(ll_pdu_rx_free, sizeof(void *), LL_PDU_RX_CNT);
@ -1267,6 +1277,10 @@ void ll_rx_dequeue(void)
/* fall through */
case NODE_RX_TYPE_SYNC:
case NODE_RX_TYPE_SYNC_LOST:
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
/* fall through */
case NODE_RX_TYPE_SYNC_TRANSFER_RECEIVED:
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
#if defined(CONFIG_BT_CTLR_SYNC_ISO)
/* fall through */
case NODE_RX_TYPE_SYNC_ISO:
@ -1544,6 +1558,9 @@ void ll_rx_mem_release(void **node_rx)
break;
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC)
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
case NODE_RX_TYPE_SYNC_TRANSFER_RECEIVED:
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
case NODE_RX_TYPE_SYNC:
{
struct node_rx_sync *se =
@ -1558,21 +1575,15 @@ void ll_rx_mem_release(void **node_rx)
(status == BT_HCI_ERR_UNSUPP_REMOTE_FEATURE) ||
(status == BT_HCI_ERR_CONN_FAIL_TO_ESTAB)) {
struct ll_sync_set *sync;
struct ll_scan_set *scan;
/* pick the scan context before node_rx
/* pick the sync context before node_rx
* release.
*/
scan = (void *)rx_free->rx_ftr.param;
sync = (void *)rx_free->rx_ftr.param;
ll_rx_release(rx_free);
/* pick the sync context before scan context
* is cleanup of sync context association.
*/
sync = scan->periodic.sync;
ull_sync_setup_reset(scan);
ull_sync_setup_reset(sync);
if (status != BT_HCI_ERR_SUCCESS) {
memq_link_t *link_sync_lost;
@ -2812,6 +2823,14 @@ static inline void rx_demux_rx(memq_link_t *link, struct node_rx_hdr *rx)
ull_sync_established_report(link, (struct node_rx_pdu *)rx);
}
break;
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
case NODE_RX_TYPE_SYNC_TRANSFER_RECEIVED:
{
(void)memq_dequeue(memq_ull_rx.tail, &memq_ull_rx.head, NULL);
ll_rx_put_sched(link, rx);
}
break;
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
#endif /* CONFIG_BT_CTLR_ADV_EXT */
#endif /* CONFIG_BT_OBSERVER */
@ -3114,3 +3133,26 @@ void *ull_rxfifo_release(uint8_t s, uint8_t n, uint8_t f, uint8_t *l, uint8_t *m
return rx;
}
#if defined(CONFIG_BT_CTLR_ISO) || \
defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER) || \
defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
/**
* @brief Wraps given time within the range of 0 to ULL_TIME_WRAPPING_POINT_US
* @param time_now Current time value
* @param time_diff Time difference (signed)
* @return Wrapped time after difference
*/
uint32_t ull_get_wrapped_time_us(uint32_t time_now_us, int32_t time_diff_us)
{
LL_ASSERT(time_now_us <= ULL_TIME_WRAPPING_POINT_US);
uint32_t result = ((uint64_t)time_now_us + ULL_TIME_SPAN_FULL_US + time_diff_us) %
((uint64_t)ULL_TIME_SPAN_FULL_US);
return result;
}
#endif /* CONFIG_BT_CTLR_ISO ||
* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER ||
* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER
*/

View file

@ -43,6 +43,14 @@
#include "ull_sched_internal.h"
#include "ull_adv_internal.h"
#include "ull_conn_internal.h"
#include "isoal.h"
#include "ull_iso_types.h"
#include "lll_conn_iso.h"
#include "ull_conn_iso_types.h"
#include "ull_llcp.h"
#include "ll.h"
#include "hal/debug.h"
@ -621,6 +629,51 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable)
return 0;
}
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
/* @brief Link Layer interface function corresponding to HCI LE Periodic
* Advertising Set Info Transfer command.
*
* @param[in] conn_handle Connection_Handle identifying the connected device
* Range: 0x0000 to 0x0EFF.
* @param[in] service_data Service_Data value provided by the Host for use by the
* Host of the peer device.
* @param[in] adv_handle Advertising_Handle identifying the advertising
* set. Range: 0x00 to 0xEF.
*
* @return HCI error codes as documented in Bluetooth Core Specification v5.4.
*/
uint8_t ll_adv_sync_set_info_transfer(uint16_t conn_handle, uint16_t service_data,
uint8_t adv_handle)
{
struct ll_adv_sync_set *sync;
struct ll_adv_set *adv;
struct ll_conn *conn;
conn = ll_connected_get(conn_handle);
if (!conn) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
/* Verify that adv_handle is valid and periodic advertising is enabled */
adv = ull_adv_is_created_get(adv_handle);
if (!adv) {
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
}
if (!adv->lll.sync) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
sync = HDR_LLL2ULL(adv->lll.sync);
if (!sync->is_enabled) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
/* Call llcp to start LLCP_PERIODIC_SYNC_IND */
return ull_cp_periodic_sync(conn, NULL, sync, service_data);
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
int ull_adv_sync_init(void)
{
int err;
@ -945,8 +998,10 @@ void ull_adv_sync_pdu_init(struct pdu_adv *pdu, uint8_t ext_hdr_flags,
{
struct pdu_adv_com_ext_adv *com_hdr;
struct pdu_adv_ext_hdr *ext_hdr;
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
struct pdu_adv_aux_ptr *aux_ptr;
uint32_t cte_len_us;
#endif
uint8_t *dptr;
uint8_t len;
@ -971,6 +1026,7 @@ void ull_adv_sync_pdu_init(struct pdu_adv *pdu, uint8_t ext_hdr_flags,
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
ULL_ADV_PDU_HDR_FIELD_SYNC_INFO)));
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
if (IS_ENABLED(CONFIG_BT_CTLR_DF_ADV_CTE_TX) &&
(ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_CTE_INFO)) {
(void)memcpy(dptr, cte_info, sizeof(*cte_info));
@ -979,15 +1035,18 @@ void ull_adv_sync_pdu_init(struct pdu_adv *pdu, uint8_t ext_hdr_flags,
} else {
cte_len_us = 0U;
}
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
(ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_ADI)) {
dptr += sizeof(struct pdu_adv_adi);
}
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) &&
(ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR)) {
aux_ptr = (void *)dptr;
dptr += sizeof(struct pdu_adv_aux_ptr);
}
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_TX_POWER) {
dptr += sizeof(uint8_t);
}

View file

@ -722,7 +722,7 @@ void ull_central_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr,
ll_rl_id_addr_get(rl_idx, &cc->peer_addr_type,
&cc->peer_addr[0]);
/* Mark it as identity address from RPA (0x02, 0x03) */
cc->peer_addr_type += 2;
MARK_AS_IDENTITY_ADDR(cc->peer_addr_type);
/* Store peer RPA */
memcpy(&cc->peer_rpa[0], &peer_addr[0], BDADDR_SIZE);
@ -749,6 +749,11 @@ void ull_central_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr,
/* Set LLCP as connection-wise connected */
ull_cp_state_set(conn, ULL_CP_CONNECTED);
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
/* Set default PAST parameters */
conn->past = ull_conn_default_past_param_get();
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
lll->tx_pwr_lvl = RADIO_TXP_DEFAULT;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */

View file

@ -57,7 +57,16 @@
#include "ull_iso_internal.h"
#include "ull_conn_iso_internal.h"
#include "ull_peripheral_iso_internal.h"
#include "lll/lll_adv_types.h"
#include "lll_adv.h"
#include "ull_adv_types.h"
#include "ull_adv_internal.h"
#include "lll_sync.h"
#include "lll_sync_iso.h"
#include "ull_sync_types.h"
#include "lll_scan.h"
#include "ull_scan_types.h"
#include "ull_sync_internal.h"
#include "ll.h"
#include "ll_feat.h"
@ -147,6 +156,10 @@ static uint8_t default_phy_tx;
static uint8_t default_phy_rx;
#endif /* CONFIG_BT_CTLR_PHY */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
static struct past_params default_past_params;
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
static struct ll_conn conn_pool[CONFIG_BT_MAX_CONN];
static void *conn_free;
@ -795,6 +808,22 @@ uint8_t ull_conn_default_phy_rx_get(void)
}
#endif /* CONFIG_BT_CTLR_PHY */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
void ull_conn_default_past_param_set(uint8_t mode, uint16_t skip, uint16_t timeout,
uint8_t cte_type)
{
default_past_params.mode = mode;
default_past_params.skip = skip;
default_past_params.timeout = timeout;
default_past_params.cte_type = cte_type;
}
struct past_params ull_conn_default_past_param_get(void)
{
return default_past_params;
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN)
bool ull_conn_peer_connected(uint8_t const own_id_addr_type,
uint8_t const *const own_id_addr,
@ -958,6 +987,10 @@ void ull_conn_done(struct node_rx_event_done *done)
ull_cp_tx_ntf(conn);
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
ull_lp_past_conn_evt_done(conn, done);
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
#if defined(CONFIG_BT_CTLR_LE_ENC)
/* Check authenticated payload expiry or MIC failure */
switch (done->extra.mic_state) {
@ -1625,6 +1658,10 @@ static int init_reset(void)
#endif /* CONFIG_BT_CTLR_PHY_CODED */
#endif /* CONFIG_BT_CTLR_PHY */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
memset(&default_past_params, 0, sizeof(struct past_params));
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
return 0;
}
@ -2563,6 +2600,153 @@ void ull_conn_default_tx_time_set(uint16_t tx_time)
}
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
static bool ticker_op_id_match_func(uint8_t ticker_id, uint32_t ticks_slot,
uint32_t ticks_to_expire, void *op_context)
{
ARG_UNUSED(ticks_slot);
ARG_UNUSED(ticks_to_expire);
uint8_t match_id = *(uint8_t *)op_context;
return ticker_id == match_id;
}
static void ticker_get_offset_op_cb(uint32_t status, void *param)
{
*((uint32_t volatile *)param) = status;
}
static uint32_t get_ticker_offset(uint8_t ticker_id, uint16_t *lazy)
{
uint32_t volatile ret_cb;
uint32_t ticks_to_expire;
uint32_t ticks_current;
uint32_t sync_remainder_us;
uint32_t remainder;
uint32_t start_us;
uint32_t ret;
uint8_t id;
id = TICKER_NULL;
ticks_to_expire = 0U;
ticks_current = 0U;
ret_cb = TICKER_STATUS_BUSY;
ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_LOW,
&id, &ticks_current, &ticks_to_expire, &remainder,
lazy, ticker_op_id_match_func, &ticker_id,
ticker_get_offset_op_cb, (void *)&ret_cb);
if (ret == TICKER_STATUS_BUSY) {
while (ret_cb == TICKER_STATUS_BUSY) {
ticker_job_sched(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_LOW);
}
}
LL_ASSERT(ret_cb == TICKER_STATUS_SUCCESS);
/* Reduced a tick for negative remainder and return positive remainder
* value.
*/
hal_ticker_remove_jitter(&ticks_to_expire, &remainder);
sync_remainder_us = remainder;
/* Add a tick for negative remainder and return positive remainder
* value.
*/
hal_ticker_add_jitter(&ticks_to_expire, &remainder);
start_us = remainder;
return ull_get_wrapped_time_us(HAL_TICKER_TICKS_TO_US(ticks_to_expire),
(sync_remainder_us - start_us));
}
static void mfy_past_sender_offset_get(void *param)
{
uint16_t last_pa_event_counter;
uint32_t ticker_offset_us;
uint16_t pa_event_counter;
uint8_t adv_sync_handle;
uint16_t sync_handle;
struct ll_conn *conn;
uint16_t lazy;
conn = param;
/* Get handle to look for */
ull_lp_past_offset_get_calc_params(conn, &adv_sync_handle, &sync_handle);
if (adv_sync_handle == BT_HCI_ADV_HANDLE_INVALID &&
sync_handle == BT_HCI_SYNC_HANDLE_INVALID) {
/* Procedure must have been aborted, do nothing */
return;
}
if (adv_sync_handle != BT_HCI_ADV_HANDLE_INVALID) {
const struct ll_adv_sync_set *adv_sync = ull_adv_sync_get(adv_sync_handle);
LL_ASSERT(adv_sync);
ticker_offset_us = get_ticker_offset(TICKER_ID_ADV_SYNC_BASE + adv_sync_handle,
&lazy);
pa_event_counter = adv_sync->lll.event_counter;
last_pa_event_counter = pa_event_counter - 1;
} else {
const struct ll_sync_set *sync = ull_sync_is_enabled_get(sync_handle);
uint32_t interval_us = sync->interval * PERIODIC_INT_UNIT_US;
uint32_t window_widening_event_us;
LL_ASSERT(sync);
ticker_offset_us = get_ticker_offset(TICKER_ID_SCAN_SYNC_BASE + sync_handle,
&lazy);
if (lazy && ticker_offset_us > interval_us) {
/* Figure out how many events we have actually skipped */
lazy = lazy - (ticker_offset_us / interval_us);
/* Correct offset to point to next event */
ticker_offset_us = ticker_offset_us % interval_us;
}
/* Calculate window widening for next event */
window_widening_event_us = sync->lll.window_widening_event_us +
sync->lll.window_widening_periodic_us * (lazy + 1U);
/* Correct for window widening */
ticker_offset_us += window_widening_event_us;
pa_event_counter = sync->lll.event_counter + lazy;
last_pa_event_counter = pa_event_counter - 1 - lazy;
/* Handle unsuccessful events */
if (sync->timeout_expire) {
last_pa_event_counter -= sync->timeout_reload - sync->timeout_expire;
}
}
ull_lp_past_offset_calc_reply(conn, ticker_offset_us, pa_event_counter,
last_pa_event_counter);
}
void ull_conn_past_sender_offset_request(struct ll_conn *conn)
{
static memq_link_t link;
static struct mayfly mfy = {0, 0, &link, NULL, mfy_past_sender_offset_get};
uint32_t ret;
mfy.param = conn;
ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1,
&mfy);
LL_ASSERT(!ret);
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
uint8_t ull_conn_lll_phy_active(struct ll_conn *conn, uint8_t phys)
{
#if defined(CONFIG_BT_CTLR_PHY)

View file

@ -17,6 +17,9 @@ uint16_t ull_conn_default_tx_octets_get(void);
uint16_t ull_conn_default_tx_time_get(void);
uint8_t ull_conn_default_phy_tx_get(void);
uint8_t ull_conn_default_phy_rx_get(void);
void ull_conn_default_past_param_set(uint8_t mode, uint16_t skip, uint16_t timeout,
uint8_t cte_type);
struct past_params ull_conn_default_past_param_get(void);
bool ull_conn_peer_connected(uint8_t const own_id_addr_type,
uint8_t const *const own_id_addr,
uint8_t const peer_id_addr_type,
@ -77,6 +80,10 @@ static inline void cpr_active_reset(void)
}
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
void ull_conn_past_sender_offset_request(struct ll_conn *conn);
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
uint16_t ull_conn_event_counter(struct ll_conn *conn);
void ull_conn_update_parameters(struct ll_conn *conn, uint8_t is_cu_proc,

View file

@ -154,10 +154,23 @@ struct llcp_struct {
}; /* struct llcp_struct */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
struct past_params {
uint8_t mode;
uint8_t cte_type;
uint16_t skip;
uint16_t timeout;
}; /* struct past_params */
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
struct ll_conn {
struct ull_hdr ull;
struct lll_conn lll;
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
struct past_params past;
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
struct ull_tx_q tx_q;
struct llcp_struct llcp;

View file

@ -859,6 +859,20 @@ bt_addr_t *ull_filter_lll_lrpa_get(uint8_t rl_idx)
return rl[rl_idx].local_rpa;
}
bt_addr_t *ull_filter_lll_id_addr_get(uint8_t rl_idx, uint8_t *id_addr_type)
{
struct lll_resolve_list *rl_entry;
if (rl_idx >= ARRAY_SIZE(rl)) {
return NULL;
}
rl_entry = &rl[rl_idx];
*id_addr_type = rl_entry->id_addr_type;
return &rl_entry->id_addr;
}
uint8_t *ull_filter_lll_irks_get(uint8_t *count)
{
*count = peer_irk_count;

View file

@ -45,6 +45,9 @@ extern bool ull_handle_cpr_anchor_point_move(struct ll_conn *conn, uint16_t *off
/* Macro to convert time in us to periodic advertising interval units */
#define RADIO_SYNC_EVENTS(x, y) ((uint16_t)DIV_ROUND_UP(x, y))
/* Macro to mark address type as identity address from RPA (0x02, 0x03) */
#define MARK_AS_IDENTITY_ADDR(addr_type) ((addr_type) += 2U)
static inline uint8_t ull_ref_get(struct ull_hdr *hdr)
{
return hdr->ref;
@ -170,3 +173,4 @@ void ull_rxfifo_alloc(uint8_t s, uint8_t n, uint8_t f, uint8_t *l, uint8_t *m,
void *mem_free, void *link_free, uint8_t max);
void *ull_rxfifo_release(uint8_t s, uint8_t n, uint8_t f, uint8_t *l, uint8_t *m,
memq_link_t *link, struct node_rx_hdr *rx);
uint32_t ull_get_wrapped_time_us(uint32_t time_now_us, int32_t time_diff_us);

View file

@ -1520,7 +1520,7 @@ void ull_lp_past_conn_evt_done(struct ll_conn *conn, struct node_rx_event_done *
if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL && done->extra.trx_cnt) {
uint32_t start_to_actual_us;
start_to_actual_us = isoal_get_wrapped_time_us(
start_to_actual_us = ull_get_wrapped_time_us(
done->extra.drift.start_to_address_actual_us,
(-done->extra.drift.preamble_to_addr_us));

View file

@ -109,7 +109,7 @@ void ull_periph_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr,
/* Get identity address */
ll_rl_id_addr_get(rl_idx, &peer_addr_type, peer_id_addr);
/* Mark it as identity address from RPA (0x02, 0x03) */
peer_addr_type += 2;
MARK_AS_IDENTITY_ADDR(peer_addr_type);
} else {
#else /* CONFIG_BT_CTLR_PRIVACY */
if (1) {
@ -144,6 +144,11 @@ void ull_periph_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr,
sizeof(conn->own_id_addr));
#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_CONN */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
/* Set default PAST parameters */
conn->past = ull_conn_default_past_param_get();
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
memcpy(&lll->crc_init[0], &pdu_adv->connect_ind.crc_init[0], 3);
memcpy(&lll->access_addr[0], &pdu_adv->connect_ind.access_addr[0], 4);
memcpy(&lll->data_chan_map[0], &pdu_adv->connect_ind.chan_map[0],

View file

@ -5,6 +5,7 @@
*/
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/slist.h>
#include <zephyr/sys/util.h>
#include "util/mem.h"
@ -28,14 +29,27 @@
#include "lll_scan_aux.h"
#include "lll/lll_df_types.h"
#include "lll_conn.h"
#include "lll_conn_iso.h"
#include "lll_sync.h"
#include "lll_sync_iso.h"
#include "lll/lll_adv_types.h"
#include "lll_adv.h"
#include "lll/lll_adv_pdu.h"
#include "ll_sw/ull_tx_queue.h"
#include "isoal.h"
#include "ull_scan_types.h"
#include "ull_conn_types.h"
#include "ull_iso_types.h"
#include "ull_conn_iso_types.h"
#include "ull_sync_types.h"
#include "ull_adv_types.h"
#include "ull_adv_internal.h"
#include "ull_internal.h"
#include "ull_scan_internal.h"
#include "ull_conn_internal.h"
#include "ull_sync_internal.h"
#include "ull_sync_iso_internal.h"
#include "ull_df_internal.h"
@ -377,10 +391,10 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_pdu *rx)
if (sync && (scan->periodic.state != LL_SYNC_STATE_CREATED)) {
/* Check address and update internal state */
#if defined(CONFIG_BT_CTLR_PRIVACY)
ull_sync_setup_addr_check(scan, pdu->tx_addr, ptr,
ull_sync_setup_addr_check(sync, scan, pdu->tx_addr, ptr,
ftr->rl_idx);
#else /* !CONFIG_BT_CTLR_PRIVACY */
ull_sync_setup_addr_check(scan, pdu->tx_addr, ptr, 0U);
ull_sync_setup_addr_check(sync, scan, pdu->tx_addr, ptr, 0U);
#endif /* !CONFIG_BT_CTLR_PRIVACY */
}
@ -420,7 +434,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_pdu *rx)
* Periodic Advertiser List or with the explicitly supplied.
*/
if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && aux && sync && adi &&
ull_sync_setup_sid_match(scan, PDU_ADV_ADI_SID_GET(adi))) {
ull_sync_setup_sid_match(sync, scan, PDU_ADV_ADI_SID_GET(adi))) {
ull_sync_setup(scan, aux, rx, si);
}
}

View file

@ -22,15 +22,10 @@ struct ll_scan_set {
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC)
struct {
uint8_t sid;
uint8_t adv_addr_type:2;
uint8_t filter_policy:1;
uint8_t cancelled:1;
uint8_t state:2;
uint8_t adv_addr[BDADDR_SIZE];
/* Non-Null when creating sync, reset in ISR context on
* synchronisation state and checked in Thread context when
* cancelling sync create, hence the volatile keyword.

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <zephyr/kernel.h>
#include <soc.h>
#include <zephyr/sys/byteorder.h>
@ -27,25 +28,41 @@
#include "pdu.h"
#include "lll.h"
#include "lll/lll_adv_types.h"
#include "lll_adv.h"
#include "lll/lll_adv_pdu.h"
#include "lll_clock.h"
#include "lll/lll_vendor.h"
#include "lll_chan.h"
#include "lll_scan.h"
#include "lll/lll_df_types.h"
#include "lll_conn.h"
#include "lll_conn_iso.h"
#include "lll_sync.h"
#include "lll_sync_iso.h"
#include "isoal.h"
#include "ull_tx_queue.h"
#include "ull_filter.h"
#include "ull_iso_types.h"
#include "ull_scan_types.h"
#include "ull_sync_types.h"
#include "ull_conn_types.h"
#include "ull_adv_types.h"
#include "ull_conn_iso_types.h"
#include "ull_internal.h"
#include "ull_adv_internal.h"
#include "ull_scan_internal.h"
#include "ull_sync_internal.h"
#include "ull_conn_internal.h"
#include "ull_conn_iso_internal.h"
#include "ull_df_types.h"
#include "ull_df_internal.h"
#include "ull_llcp.h"
#include "ll.h"
#include <soc.h>
@ -59,6 +76,8 @@
*/
MEM_FREE_MEMBER_ACCESS_BUILD_ASSERT(struct ll_sync_set, timeout_reload);
static struct ll_sync_set *ull_sync_create(uint8_t sid, uint16_t timeout, uint16_t skip,
uint8_t cte_type, uint8_t rx_enable, uint8_t nodups);
static int init_reset(void);
static inline struct ll_sync_set *sync_acquire(void);
static void sync_ticker_cleanup(struct ll_sync_set *sync, ticker_op_func stop_op_cb);
@ -98,12 +117,10 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
uint16_t sync_timeout, uint8_t sync_cte_type)
{
struct ll_scan_set *scan_coded;
memq_link_t *link_sync_estab;
memq_link_t *link_sync_lost;
struct node_rx_pdu *node_rx;
struct lll_sync *lll_sync;
struct ll_scan_set *scan;
struct ll_sync_set *sync;
uint8_t rx_enable;
uint8_t nodups;
scan = ull_scan_set_get(SCAN_HANDLE_1M);
if (!scan || scan->periodic.sync) {
@ -125,32 +142,11 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
}
#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC */
link_sync_estab = ll_rx_link_alloc();
if (!link_sync_estab) {
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
rx_enable = !(options & BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED);
nodups = (options & BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE) ? 1U : 0U;
link_sync_lost = ll_rx_link_alloc();
if (!link_sync_lost) {
ll_rx_link_release(link_sync_estab);
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
node_rx = ll_rx_alloc();
if (!node_rx) {
ll_rx_link_release(link_sync_lost);
ll_rx_link_release(link_sync_estab);
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
sync = sync_acquire();
sync = ull_sync_create(sid, sync_timeout, skip, sync_cte_type, rx_enable, nodups);
if (!sync) {
ll_rx_release(node_rx);
ll_rx_link_release(link_sync_lost);
ll_rx_link_release(link_sync_estab);
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
@ -166,55 +162,10 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
}
if (!scan->periodic.filter_policy) {
scan->periodic.sid = sid;
scan->periodic.adv_addr_type = adv_addr_type;
(void)memcpy(scan->periodic.adv_addr, adv_addr, BDADDR_SIZE);
if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) {
scan_coded->periodic.sid = scan->periodic.sid;
scan_coded->periodic.adv_addr_type =
scan->periodic.adv_addr_type;
(void)memcpy(scan_coded->periodic.adv_addr,
scan->periodic.adv_addr, BDADDR_SIZE);
}
sync->peer_id_addr_type = adv_addr_type;
(void)memcpy(sync->peer_id_addr, adv_addr, BDADDR_SIZE);
}
/* Initialize sync context */
node_rx->hdr.link = link_sync_estab;
sync->node_rx_lost.rx.hdr.link = link_sync_lost;
/* Make sure that the node_rx_sync_establ hasn't got anything assigned. It is used to
* mark when sync establishment is in progress.
*/
LL_ASSERT(!sync->node_rx_sync_estab);
sync->node_rx_sync_estab = node_rx;
/* Reporting initially enabled/disabled */
sync->rx_enable =
!(options & BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED);
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
sync->nodups = (options &
BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE) ?
1U : 0U;
#endif
sync->skip = skip;
sync->is_stop = 0U;
#if defined(CONFIG_BT_CTLR_SYNC_ISO)
sync->enc = 0U;
#endif /* CONFIG_BT_CTLR_SYNC_ISO */
/* NOTE: Use timeout not zero to represent sync context used for sync
* create.
*/
sync->timeout = sync_timeout;
/* NOTE: Use timeout_reload not zero to represent sync established. */
sync->timeout_reload = 0U;
sync->timeout_expire = 0U;
#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC)
/* Remember the peer address when periodic advertiser list is not
* used.
* NOTE: Peer address will be filled/overwritten with correct identity
@ -226,42 +177,11 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
sizeof(sync->peer_id_addr));
}
/* Remember the SID */
sync->sid = sid;
#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC */
#if defined(CONFIG_BT_CTLR_SYNC_ISO)
/* Reset Broadcast Isochronous Group Sync Establishment */
sync->iso.sync_iso = NULL;
#endif /* CONFIG_BT_CTLR_SYNC_ISO */
/* Initialize sync LLL context */
lll_sync = &sync->lll;
lll_sync->lll_aux = NULL;
lll_sync->is_rx_enabled = sync->rx_enable;
lll_sync->skip_prepare = 0U;
lll_sync->skip_event = 0U;
lll_sync->window_widening_prepare_us = 0U;
lll_sync->window_widening_event_us = 0U;
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING)
lll_sync->cte_type = sync_cte_type;
lll_sync->filter_policy = scan->periodic.filter_policy;
/* Set filter policy in lll_sync */
sync->lll.filter_policy = scan->periodic.filter_policy;
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
ull_df_sync_cfg_init(&lll_sync->df_cfg);
LL_ASSERT(!lll_sync->node_cte_incomplete);
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
/* Initialise ULL and LLL headers */
ull_hdr_init(&sync->ull);
lll_hdr_init(lll_sync, sync);
#if defined(CONFIG_BT_CTLR_SCAN_AUX_SYNC_RESERVE_MIN)
/* Initialise LLL abort count */
lll_sync->abort_count = 0U;
#endif /* CONFIG_BT_CTLR_SCAN_AUX_SYNC_RESERVE_MIN */
/* Enable scanner to create sync */
scan->periodic.sync = sync;
@ -279,6 +199,243 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
return 0;
}
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
void ull_sync_setup_from_sync_transfer(struct ll_conn *conn, uint16_t service_data,
struct ll_sync_set *sync, struct pdu_adv_sync_info *si,
int16_t conn_evt_offset, uint16_t last_pa_event_counter,
uint16_t sync_conn_event_count, uint8_t sender_sca)
{
struct node_rx_past_received *se_past;
uint32_t ticks_slot_overhead;
uint32_t ticks_slot_offset;
uint32_t conn_interval_us;
uint32_t sync_offset_us;
uint32_t ready_delay_us;
struct node_rx_pdu *rx;
uint8_t *data_chan_map;
struct lll_sync *lll;
uint32_t interval_us;
uint32_t slot_us;
uint32_t ticks_anchor;
uint8_t chm_last;
uint32_t ret;
uint16_t interval;
uint16_t sync_handle;
uint8_t sca;
lll = &sync->lll;
/* Copy channel map from sca_chm field in sync_info structure, and
* clear the SCA bits.
*/
chm_last = lll->chm_first;
lll->chm_last = chm_last;
data_chan_map = lll->chm[chm_last].data_chan_map;
(void)memcpy(data_chan_map, si->sca_chm,
sizeof(lll->chm[chm_last].data_chan_map));
data_chan_map[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &=
~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK;
lll->chm[chm_last].data_chan_count =
util_ones_count_get(data_chan_map,
sizeof(lll->chm[chm_last].data_chan_map));
if (lll->chm[chm_last].data_chan_count < CHM_USED_COUNT_MIN) {
/* Ignore sync setup, invalid available channel count */
return;
}
memcpy(lll->access_addr, si->aa, sizeof(lll->access_addr));
lll->data_chan_id = lll_chan_id(lll->access_addr);
memcpy(lll->crc_init, si->crc_init, sizeof(lll->crc_init));
lll->event_counter = sys_le16_to_cpu(si->evt_cntr);
interval = sys_le16_to_cpu(si->interval);
interval_us = interval * PERIODIC_INT_UNIT_US;
/* Convert fromm 10ms units to interval units */
if (sync->timeout != 0 && interval_us != 0) {
sync->timeout_reload = RADIO_SYNC_EVENTS((sync->timeout * 10U *
USEC_PER_MSEC), interval_us);
}
/* Adjust Skip value so that there is minimum of 6 events that can be
* listened to before Sync_Timeout occurs.
* The adjustment of the skip value is controller implementation
* specific and not specified by the Bluetooth Core Specification v5.3.
* The Controller `may` use the Skip value, and the implementation here
* covers a case where Skip value could lead to less events being
* listened to until Sync_Timeout. Listening to more consecutive events
* before Sync_Timeout increases probability of retaining the Periodic
* Synchronization.
*/
if (sync->timeout_reload > CONN_ESTAB_COUNTDOWN) {
uint16_t skip_max = sync->timeout_reload - CONN_ESTAB_COUNTDOWN;
if (sync->skip > skip_max) {
sync->skip = skip_max;
}
}
sync->sync_expire = CONN_ESTAB_COUNTDOWN;
/* Extract the SCA value from the sca_chm field of the sync_info
* structure.
*/
sca = (si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &
PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK) >>
PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS;
lll->sca = sca;
lll->window_widening_periodic_us =
DIV_ROUND_UP(((lll_clock_ppm_local_get() +
lll_clock_ppm_get(sca)) *
interval_us), USEC_PER_SEC);
lll->window_widening_max_us = (interval_us >> 1) - EVENT_IFS_US;
if (PDU_ADV_SYNC_INFO_OFFS_UNITS_GET(si)) {
lll->window_size_event_us = OFFS_UNIT_300_US;
} else {
lll->window_size_event_us = OFFS_UNIT_30_US;
}
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
lll->node_cte_incomplete = NULL;
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
/* Prepare Periodic Advertising Sync Transfer Received event (dispatched later) */
sync_handle = ull_sync_handle_get(sync);
rx = (void *)sync->node_rx_sync_estab;
rx->hdr.type = NODE_RX_TYPE_SYNC_TRANSFER_RECEIVED;
rx->hdr.handle = sync_handle;
rx->rx_ftr.param = sync;
/* Create node_rx and assign values */
se_past = (void *)rx->pdu;
se_past->rx_sync.status = BT_HCI_ERR_SUCCESS;
se_past->rx_sync.interval = interval;
se_past->rx_sync.phy = sync->lll.phy;
se_past->rx_sync.sca = sca;
se_past->conn_handle = ll_conn_handle_get(conn);
se_past->service_data = service_data;
conn_interval_us = conn->lll.interval * CONN_INT_UNIT_US;
/* Calculate offset and schedule sync radio events */
ready_delay_us = lll_radio_rx_ready_delay_get(lll->phy, PHY_FLAGS_S8);
sync_offset_us = PDU_ADV_SYNC_INFO_OFFSET_GET(si) * lll->window_size_event_us;
/* offs_adjust may be 1 only if sync setup by LL_PERIODIC_SYNC_IND */
sync_offset_us += (PDU_ADV_SYNC_INFO_OFFS_ADJUST_GET(si) ? OFFS_ADJUST_US : 0U);
sync_offset_us -= EVENT_TICKER_RES_MARGIN_US;
sync_offset_us -= EVENT_JITTER_US;
sync_offset_us -= ready_delay_us;
if (conn_evt_offset) {
int64_t conn_offset_us = (int64_t)conn_evt_offset * conn_interval_us;
if ((int64_t)sync_offset_us + conn_offset_us < 0) {
uint32_t total_offset_us = abs((int64_t)sync_offset_us + conn_offset_us);
uint32_t sync_intervals = DIV_ROUND_UP(total_offset_us, interval_us);
lll->event_counter += sync_intervals;
sync_offset_us = (sync_intervals * interval_us) - total_offset_us;
} else {
sync_offset_us += conn_offset_us;
}
}
/* Calculate initial window widening - see Core Spec vol 6, part B, 5.1.13.1 */
{
uint16_t event_delta;
uint32_t drift_us;
uint64_t da;
uint64_t db;
uint64_t d;
const uint32_t local_sca_ppm = lll_clock_ppm_local_get();
event_delta = lll->event_counter - last_pa_event_counter;
da = (uint64_t)(local_sca_ppm + lll_clock_ppm_get(sca)) * interval_us;
da = DIV_ROUND_UP(da * (uint64_t)event_delta, USEC_PER_SEC);
db = (uint64_t)(local_sca_ppm + lll_clock_ppm_get(sender_sca)) * conn_interval_us;
db = DIV_ROUND_UP(db * (uint64_t)(ull_conn_event_counter(conn) -
sync_conn_event_count), USEC_PER_SEC);
d = DIV_ROUND_UP((da + db) * (USEC_PER_SEC + local_sca_ppm +
lll_clock_ppm_get(sca) +
lll_clock_ppm_get(sender_sca)), USEC_PER_SEC);
/* Limit drift compenstion to the maximum window widening */
drift_us = MIN((uint32_t)d, lll->window_widening_max_us);
/* Apply total drift to initial window size */
lll->window_size_event_us += drift_us;
/* Adjust offset if less than the drift compensation */
while (sync_offset_us < drift_us) {
sync_offset_us += interval_us;
lll->event_counter++;
}
sync_offset_us -= drift_us;
}
interval_us -= lll->window_widening_periodic_us;
/* Calculate event time reservation */
slot_us = PDU_AC_MAX_US(PDU_AC_EXT_PAYLOAD_RX_SIZE, lll->phy);
slot_us += ready_delay_us;
/* Add implementation defined radio event overheads */
if (IS_ENABLED(CONFIG_BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX)) {
slot_us += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
}
/* TODO: active_to_start feature port */
sync->ull.ticks_active_to_start = 0U;
sync->ull.ticks_prepare_to_start =
HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US);
sync->ull.ticks_preempt_to_start =
HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US);
sync->ull.ticks_slot = HAL_TICKER_US_TO_TICKS_CEIL(slot_us);
ticks_slot_offset = MAX(sync->ull.ticks_active_to_start,
sync->ull.ticks_prepare_to_start);
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
ticks_slot_overhead = ticks_slot_offset;
} else {
ticks_slot_overhead = 0U;
}
ticks_slot_offset += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
sync->lll_sync_prepare = lll_sync_create_prepare;
ticks_anchor = conn->llcp.prep.ticks_at_expire;
#if defined(CONFIG_BT_PERIPHERAL)
if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL) {
/* Compensate for window widening */
ticks_anchor += HAL_TICKER_US_TO_TICKS(conn->lll.periph.window_widening_event_us);
}
#endif /* CONFIG_BT_PERIPHERAL */
ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH,
(TICKER_ID_SCAN_SYNC_BASE + sync_handle),
ticks_anchor,
HAL_TICKER_US_TO_TICKS(sync_offset_us),
HAL_TICKER_US_TO_TICKS(interval_us),
HAL_TICKER_REMAINDER(interval_us),
TICKER_NULL_LAZY,
(sync->ull.ticks_slot + ticks_slot_overhead),
ticker_cb, sync,
ticker_start_op_cb, (void *)__LINE__);
LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
(ret == TICKER_STATUS_BUSY));
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
uint8_t ll_sync_create_cancel(void **rx)
{
struct ll_scan_set *scan_coded;
@ -353,7 +510,7 @@ uint8_t ll_sync_create_cancel(void **rx)
/* It is safe to remove association with scanner as cancelled flag is
* set, sync is_stop flag was set and sync has not been established.
*/
ull_sync_setup_reset(scan);
ull_sync_setup_reset(sync);
/* Mark the sync context as sync create cancelled */
if (IS_ENABLED(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC)) {
@ -431,6 +588,22 @@ uint8_t ll_sync_terminate(uint16_t handle)
LL_ASSERT(!aux->parent);
}
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
/* Clean up node_rx_sync_estab if still present */
if (sync->node_rx_sync_estab) {
memq_link_t *link_sync_estab;
struct node_rx_pdu *node_rx;
node_rx = (void *)sync->node_rx_sync_estab;
link_sync_estab = node_rx->hdr.link;
ll_rx_link_release(link_sync_estab);
ll_rx_release(node_rx);
sync->node_rx_sync_estab = NULL;
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
link_sync_lost = sync->node_rx_lost.rx.hdr.link;
ll_rx_link_release(link_sync_lost);
@ -474,6 +647,111 @@ uint8_t ll_sync_recv_enable(uint16_t handle, uint8_t enable)
return 0;
}
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
/* @brief Link Layer interface function corresponding to HCI LE Set Periodic
* Advertising Sync Transfer command.
*
* @param[in] conn_handle Connection_Handle identifying the connected device
* Range: 0x0000 to 0x0EFF.
* @param[in] service_data Service_Data value provided by the Host for use by the
* Host of the peer device.
* @param[in] sync_handle Sync_Handle identifying the periodic advertising
* train. Range: 0x0000 to 0x0EFF.
*
* @return HCI error codes as documented in Bluetooth Core Specification v5.4.
*/
uint8_t ll_sync_transfer(uint16_t conn_handle, uint16_t service_data, uint16_t sync_handle)
{
struct ll_sync_set *sync;
struct ll_conn *conn;
conn = ll_connected_get(conn_handle);
if (!conn) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
/* Verify that sync_handle is valid */
sync = ull_sync_is_enabled_get(sync_handle);
if (!sync) {
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
}
/* Call llcp to start LLCP_PERIODIC_SYNC_IND */
return ull_cp_periodic_sync(conn, sync, NULL, service_data);
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
/* @brief Link Layer interface function corresponding to HCI LE Set Periodic
* Advertising Sync Transfer Parameters command.
*
* @param[in] conn_handle Connection_Handle identifying the connected device
* Range: 0x0000 to 0x0EFF.
* @param[in] mode Mode specifies the action to be taken when a periodic advertising
* synchronization is received.
* @param[in] skip Skip specifying the number of consectutive periodic advertising
* packets that the receiver may skip after successfully reciving a
* periodic advertising packet. Range: 0x0000 to 0x01F3.
* @param[in] timeout Sync_timeout specifying the maximum permitted time between
* successful receives. Range: 0x000A to 0x4000.
* @param[in] cte_type CTE_Type specifying whether to only synchronize to periodic
* advertising with certain types of Constant Tone Extension.
*
* @return HCI error codes as documented in Bluetooth Core Specification v5.4.
*/
uint8_t ll_past_param(uint16_t conn_handle, uint8_t mode, uint16_t skip, uint16_t timeout,
uint8_t cte_type)
{
struct ll_conn *conn;
conn = ll_connected_get(conn_handle);
if (!conn) {
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
if (mode == BT_HCI_LE_PAST_MODE_SYNC_FILTER_DUPLICATES &&
!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
/* Set PAST Param for connection instance */
conn->past.mode = mode;
conn->past.skip = skip;
conn->past.timeout = timeout;
conn->past.cte_type = cte_type;
return 0;
}
/* @brief Link Layer interface function corresponding to HCI LE Set Default Periodic
* Advertising Sync Transfer Parameters command.
*
* @param[in] mode Mode specifies the action to be taken when a periodic advertising
* synchronization is received.
* @param[in] skip Skip specifying the number of consectutive periodic advertising
* packets that the receiver may skip after successfully reciving a
* periodic advertising packet. Range: 0x0000 to 0x01F3.
* @param[in] timeout Sync_timeout specifying the maximum permitted time between
* successful receives. Range: 0x000A to 0x4000.
* @param[in] cte_type CTE_Type specifying whether to only synchronize to periodic
* advertising with certain types of Constant Tone Extension.
*
* @return HCI error codes as documented in Bluetooth Core Specification v5.4.
*/
uint8_t ll_default_past_param(uint8_t mode, uint16_t skip, uint16_t timeout, uint8_t cte_type)
{
if (mode == BT_HCI_LE_PAST_MODE_SYNC_FILTER_DUPLICATES &&
!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)) {
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
}
/* Set default past param */
ull_conn_default_past_param_set(mode, skip, timeout, cte_type);
return 0;
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */
int ull_sync_init(void)
{
int err;
@ -594,8 +872,8 @@ void ull_sync_release(struct ll_sync_set *sync)
mem_release(sync, &sync_free);
}
void ull_sync_setup_addr_check(struct ll_scan_set *scan, uint8_t addr_type,
uint8_t *addr, uint8_t rl_idx)
void ull_sync_setup_addr_check(struct ll_sync_set *sync, struct ll_scan_set *scan,
uint8_t addr_type, uint8_t *addr, uint8_t rl_idx)
{
/* Check if Periodic Advertiser list to be used */
if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST) &&
@ -605,8 +883,8 @@ void ull_sync_setup_addr_check(struct ll_scan_set *scan, uint8_t addr_type,
/* Remember the address, to check with
* SID in Sync Info
*/
scan->periodic.adv_addr_type = addr_type;
(void)memcpy(scan->periodic.adv_addr, addr,
sync->peer_id_addr_type = addr_type;
(void)memcpy(sync->peer_id_addr, addr,
BDADDR_SIZE);
/* Address matched */
@ -615,22 +893,22 @@ void ull_sync_setup_addr_check(struct ll_scan_set *scan, uint8_t addr_type,
/* Check in Resolving List */
} else if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY) &&
ull_filter_ull_pal_listed(rl_idx, &addr_type,
scan->periodic.adv_addr)) {
sync->peer_id_addr)) {
/* Remember the address, to check with the
* SID in Sync Info
*/
scan->periodic.adv_addr_type = addr_type;
sync->peer_id_addr_type = addr_type;
/* Mark it as identity address from RPA (0x02, 0x03) */
scan->periodic.adv_addr_type += 2U;
/* Mark it as identity address from RPA */
sync->peer_addr_resolved = 1U;
/* Address matched */
scan->periodic.state = LL_SYNC_STATE_ADDR_MATCH;
}
/* Check with explicitly supplied address */
} else if ((addr_type == scan->periodic.adv_addr_type) &&
!memcmp(addr, scan->periodic.adv_addr, BDADDR_SIZE)) {
} else if ((addr_type == sync->peer_id_addr_type) &&
!memcmp(addr, sync->peer_id_addr, BDADDR_SIZE)) {
/* Address matched */
scan->periodic.state = LL_SYNC_STATE_ADDR_MATCH;
@ -638,10 +916,10 @@ void ull_sync_setup_addr_check(struct ll_scan_set *scan, uint8_t addr_type,
} else if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY) &&
(rl_idx < ll_rl_size_get())) {
ll_rl_id_addr_get(rl_idx, &addr_type, addr);
if ((addr_type == scan->periodic.adv_addr_type) &&
!memcmp(addr, scan->periodic.adv_addr, BDADDR_SIZE)) {
/* Mark it as identity address from RPA (0x02, 0x03) */
scan->periodic.adv_addr_type += 2U;
if ((addr_type == sync->peer_id_addr_type) &&
!memcmp(addr, sync->peer_id_addr, BDADDR_SIZE)) {
/* Mark it as identity address from RPA */
sync->peer_addr_resolved = 1U;
/* Identity address matched */
scan->periodic.state = LL_SYNC_STATE_ADDR_MATCH;
@ -649,15 +927,15 @@ void ull_sync_setup_addr_check(struct ll_scan_set *scan, uint8_t addr_type,
}
}
bool ull_sync_setup_sid_match(struct ll_scan_set *scan, uint8_t sid)
bool ull_sync_setup_sid_match(struct ll_sync_set *sync, struct ll_scan_set *scan, uint8_t sid)
{
return (scan->periodic.state == LL_SYNC_STATE_ADDR_MATCH) &&
((IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST) &&
scan->periodic.filter_policy &&
ull_filter_ull_pal_match(scan->periodic.adv_addr_type,
scan->periodic.adv_addr, sid)) ||
ull_filter_ull_pal_match(sync->peer_id_addr_type,
sync->peer_id_addr, sid)) ||
(!scan->periodic.filter_policy &&
(sid == scan->periodic.sid)));
(sid == sync->sid)));
}
void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
@ -705,18 +983,6 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
return;
}
#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC) || \
defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
/* Remember the peer address.
* NOTE: Peer identity address is copied here when privacy is enable.
*/
sync->peer_id_addr_type = scan->periodic.adv_addr_type & 0x01;
(void)memcpy(sync->peer_id_addr, scan->periodic.adv_addr,
sizeof(sync->peer_id_addr));
#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC ||
* CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT
*/
memcpy(lll->access_addr, si->aa, sizeof(lll->access_addr));
lll->data_chan_id = lll_chan_id(lll->access_addr);
memcpy(lll->crc_init, si->crc_init, sizeof(lll->crc_init));
@ -727,7 +993,12 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
interval = sys_le16_to_cpu(si->interval);
interval_us = interval * PERIODIC_INT_UNIT_US;
/* Convert from 10ms units to interval units */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
/* Save Periodic Advertisement Interval */
sync->interval = interval;
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
/* Convert fromm 10ms units to interval units */
sync->timeout_reload = RADIO_SYNC_EVENTS((sync->timeout * 10U *
USEC_PER_MSEC), interval_us);
@ -803,7 +1074,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
rx = (void *)sync->node_rx_sync_estab;
rx->hdr.type = NODE_RX_TYPE_SYNC;
rx->hdr.handle = sync_handle;
rx->rx_ftr.param = scan;
rx->rx_ftr.param = sync;
se = (void *)rx->pdu;
se->interval = interval;
se->phy = lll->phy;
@ -813,7 +1084,7 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
ftr = &node_rx->rx_ftr;
pdu = (void *)((struct node_rx_pdu *)node_rx)->pdu;
ready_delay_us = lll_radio_rx_ready_delay_get(lll->phy, 1);
ready_delay_us = lll_radio_rx_ready_delay_get(lll->phy, PHY_FLAGS_S8);
sync_offset_us = ftr->radio_end_us;
sync_offset_us += PDU_ADV_SYNC_INFO_OFFSET_GET(si) *
@ -885,9 +1156,13 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
(ret == TICKER_STATUS_BUSY));
}
void ull_sync_setup_reset(struct ll_scan_set *scan)
void ull_sync_setup_reset(struct ll_sync_set *sync)
{
struct ll_scan_set *scan;
/* Remove the sync context from being associated with scan contexts */
scan = ull_scan_set_get(SCAN_HANDLE_1M);
scan->periodic.sync = NULL;
#if defined(CONFIG_BT_CTLR_FILTER_ACCEPT_LIST)
@ -895,14 +1170,7 @@ void ull_sync_setup_reset(struct ll_scan_set *scan)
#endif /* CONFIG_BT_CTLR_FILTER_ACCEPT_LIST */
if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) {
struct ll_scan_set *scan_1m;
scan_1m = ull_scan_set_get(SCAN_HANDLE_1M);
if (scan == scan_1m) {
scan = ull_scan_set_get(SCAN_HANDLE_PHY_CODED);
} else {
scan = scan_1m;
}
scan->periodic.sync = NULL;
@ -965,8 +1233,7 @@ void ull_sync_established_report(memq_link_t *link, struct node_rx_pdu *rx)
#endif /* !CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */
/* Prepare and dispatch sync notification */
rx_establ = sync->node_rx_sync_estab;
rx_establ->hdr.type = NODE_RX_TYPE_SYNC;
rx_establ = (void *)sync->node_rx_sync_estab;
rx_establ->hdr.handle = ull_sync_handle_get(sync);
se = (void *)rx_establ->pdu;
/* Clear the node to mark the sync establish as being completed.
@ -1297,6 +1564,110 @@ static inline struct ll_sync_set *sync_acquire(void)
return mem_acquire(&sync_free);
}
static struct ll_sync_set *ull_sync_create(uint8_t sid, uint16_t timeout, uint16_t skip,
uint8_t cte_type, uint8_t rx_enable, uint8_t nodups)
{
memq_link_t *link_sync_estab;
memq_link_t *link_sync_lost;
struct node_rx_pdu *node_rx;
struct lll_sync *lll;
struct ll_sync_set *sync;
link_sync_estab = ll_rx_link_alloc();
if (!link_sync_estab) {
return NULL;
}
link_sync_lost = ll_rx_link_alloc();
if (!link_sync_lost) {
ll_rx_link_release(link_sync_estab);
return NULL;
}
node_rx = ll_rx_alloc();
if (!node_rx) {
ll_rx_link_release(link_sync_lost);
ll_rx_link_release(link_sync_estab);
return NULL;
}
sync = sync_acquire();
if (!sync) {
ll_rx_release(node_rx);
ll_rx_link_release(link_sync_lost);
ll_rx_link_release(link_sync_estab);
return NULL;
}
sync->peer_addr_resolved = 0U;
/* Initialize sync context */
node_rx->hdr.link = link_sync_estab;
sync->node_rx_lost.rx.hdr.link = link_sync_lost;
/* Make sure that the node_rx_sync_establ hasn't got anything assigned. It is used to
* mark when sync establishment is in progress.
*/
LL_ASSERT(!sync->node_rx_sync_estab);
sync->node_rx_sync_estab = node_rx;
/* Reporting initially enabled/disabled */
sync->rx_enable = rx_enable;
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
sync->nodups = nodups;
#endif
sync->skip = skip;
sync->is_stop = 0U;
#if defined(CONFIG_BT_CTLR_SYNC_ISO)
sync->enc = 0U;
#endif /* CONFIG_BT_CTLR_SYNC_ISO */
/* NOTE: Use timeout not zero to represent sync context used for sync
* create.
*/
sync->timeout = timeout;
/* NOTE: Use timeout_reload not zero to represent sync established. */
sync->timeout_reload = 0U;
sync->timeout_expire = 0U;
/* Remember the SID */
sync->sid = sid;
#if defined(CONFIG_BT_CTLR_SYNC_ISO)
/* Reset Broadcast Isochronous Group Sync Establishment */
sync->iso.sync_iso = NULL;
#endif /* CONFIG_BT_CTLR_SYNC_ISO */
/* Initialize sync LLL context */
lll = &sync->lll;
lll->lll_aux = NULL;
lll->is_rx_enabled = sync->rx_enable;
lll->skip_prepare = 0U;
lll->skip_event = 0U;
lll->window_widening_prepare_us = 0U;
lll->window_widening_event_us = 0U;
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING)
lll->cte_type = cte_type;
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */
#if defined(CONFIG_BT_CTLR_DF_SCAN_CTE_RX)
ull_df_sync_cfg_init(&lll->df_cfg);
LL_ASSERT(!lll->node_cte_incomplete);
#endif /* CONFIG_BT_CTLR_DF_SCAN_CTE_RX */
/* Initialise ULL and LLL headers */
ull_hdr_init(&sync->ull);
lll_hdr_init(lll, sync);
return sync;
}
static void sync_ticker_cleanup(struct ll_sync_set *sync, ticker_op_func stop_op_cb)
{
uint16_t sync_handle = ull_sync_handle_get(sync);
@ -1388,7 +1759,6 @@ static void sync_expire(void *param)
/* Generate Periodic advertising sync failed to establish */
rx = (void *)sync->node_rx_sync_estab;
rx->hdr.type = NODE_RX_TYPE_SYNC;
rx->hdr.handle = LLL_HANDLE_INVALID;
/* Clear the node to mark the sync establish as being completed.
@ -1535,3 +1905,61 @@ static struct pdu_cte_info *pdu_cte_info_get(struct pdu_adv *pdu)
return (struct pdu_cte_info *)hdr->data;
}
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING && !CONFIG_BT_CTLR_CTEINLINE_SUPPORT */
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER)
void ull_sync_transfer_received(struct ll_conn *conn, uint16_t service_data,
struct pdu_adv_sync_info *si, uint16_t conn_event_count,
uint16_t last_pa_event_counter, uint8_t sid,
uint8_t addr_type, uint8_t sca, uint8_t phy,
uint8_t *adv_addr, uint16_t sync_conn_event_count,
uint8_t addr_resolved)
{
struct ll_sync_set *sync;
uint16_t conn_evt_current;
uint8_t rx_enable;
uint8_t nodups;
if (conn->past.mode == BT_HCI_LE_PAST_MODE_NO_SYNC) {
/* Ignore LL_PERIODIC_SYNC_IND - see Bluetooth Core Specification v5.4
* Vol 6, Part E, Section 7.8.91
*/
return;
}
#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC)
/* Do not sync twice to the same peer and same SID */
if (peer_sid_sync_exists(addr_type, adv_addr, sid)) {
return;
}
#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC */
nodups = (conn->past.mode == BT_HCI_LE_PAST_MODE_SYNC_FILTER_DUPLICATES) ? 1U : 0U;
rx_enable = (conn->past.mode == BT_HCI_LE_PAST_MODE_NO_REPORTS) ? 0U : 1U;
sync = ull_sync_create(sid, conn->past.timeout, conn->past.skip, conn->past.cte_type,
rx_enable, nodups);
if (!sync) {
return;
}
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING)
/* Reset filter policy in lll_sync */
sync->lll.filter_policy = 0U;
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING */
sync->peer_id_addr_type = addr_type;
sync->peer_addr_resolved = addr_resolved;
memcpy(sync->peer_id_addr, adv_addr, BDADDR_SIZE);
sync->lll.phy = phy;
conn_evt_current = ull_conn_event_counter(conn);
/* LLCP should have ensured this holds */
LL_ASSERT(sync_conn_event_count != conn_evt_current);
ull_sync_setup_from_sync_transfer(conn, service_data, sync, si,
conn_event_count - conn_evt_current,
last_pa_event_counter, sync_conn_event_count,
sca);
}
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_RECEIVER */

View file

@ -9,15 +9,25 @@ int ull_sync_reset(void);
uint16_t ull_sync_handle_get(struct ll_sync_set *sync);
struct ll_sync_set *ull_sync_is_enabled_get(uint16_t handle);
void ull_sync_release(struct ll_sync_set *sync);
void ull_sync_setup_addr_check(struct ll_scan_set *scan, uint8_t addr_type,
uint8_t *addr, uint8_t rl_idx);
bool ull_sync_setup_sid_match(struct ll_scan_set *scan, uint8_t sid);
void ull_sync_setup_addr_check(struct ll_sync_set *sync, struct ll_scan_set *scan,
uint8_t addr_type, uint8_t *addr, uint8_t rl_idx);
bool ull_sync_setup_sid_match(struct ll_sync_set *sync, struct ll_scan_set *scan, uint8_t sid);
void ull_sync_create_from_sync_transfer(uint16_t conn_handle, uint16_t service_data,
struct ll_sync_set *sync,
struct pdu_adv_sync_info *si,
uint32_t conn_offset_us);
void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
struct node_rx_pdu *node_rx, struct pdu_adv_sync_info *si);
void ull_sync_setup_reset(struct ll_scan_set *scan);
void ull_sync_setup_reset(struct ll_sync_set *sync);
void ull_sync_established_report(memq_link_t *link, struct node_rx_pdu *rx);
void ull_sync_done(struct node_rx_event_done *done);
void ull_sync_chm_update(uint8_t sync_handle, uint8_t *acad, uint8_t acad_len);
int ull_sync_slot_update(struct ll_sync_set *sync, uint32_t slot_plus_us,
uint32_t slot_minus_us);
struct ll_sync_set *ull_sync_is_valid_get(struct ll_sync_set *sync);
void ull_sync_transfer_received(struct ll_conn *conn, uint16_t service_data,
struct pdu_adv_sync_info *si, uint16_t conn_event_count,
uint16_t last_pa_event_counter, uint8_t sid,
uint8_t addr_type, uint8_t sca, uint8_t phy,
uint8_t *adv_addr, uint16_t sync_conn_event_count,
uint8_t addr_resolved);

View file

@ -31,18 +31,26 @@
#include "lll/lll_df_types.h"
#include "lll_sync.h"
#include "lll_sync_iso.h"
#include "lll_conn.h"
#include "lll_conn_iso.h"
#include "isoal.h"
#include "ull_tx_queue.h"
#include "ull_scan_types.h"
#include "ull_sync_types.h"
#include "ull_iso_types.h"
#include "ull_conn_types.h"
#include "ull_conn_iso_types.h"
#include "ull_internal.h"
#include "ull_scan_internal.h"
#include "ull_sync_internal.h"
#include "ull_iso_internal.h"
#include "ull_sync_iso_internal.h"
#include "ull_conn_internal.h"
#include "ull_conn_iso_internal.h"
#include "ll.h"

View file

@ -32,13 +32,9 @@ struct ll_sync_set {
*/
void (*lll_sync_prepare)(void *param);
#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC) || \
defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
uint8_t peer_id_addr[BDADDR_SIZE];
uint8_t peer_id_addr_type:1;
#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC ||
* CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT
*/
uint8_t peer_addr_resolved:1;
uint8_t rx_enable:1;
@ -62,9 +58,7 @@ struct ll_sync_set {
uint8_t num_bis : 5;
#endif /* CONFIG_BT_CTLR_SYNC_ISO */
#if defined(CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC)
uint8_t sid;
#endif /* CONFIG_BT_CTLR_CHECK_SAME_PEER_SYNC */
/* node rx type with memory aligned storage for sync lost reason.
* HCI will reference the value using the pdu member of
@ -94,8 +88,10 @@ struct ll_sync_set {
#endif /* CONFIG_BT_CTLR_SYNC_ISO */
uint16_t data_len;
#if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
uint16_t interval;
#endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
};
struct node_rx_sync {
uint8_t status;
uint8_t phy;
@ -103,6 +99,12 @@ struct node_rx_sync {
uint8_t sca;
};
struct node_rx_past_received {
struct node_rx_sync rx_sync;
uint16_t conn_handle;
uint16_t service_data;
};
#if defined(CONFIG_BT_CTLR_SYNC_ISO)
struct ll_sync_iso_set {
struct ull_hdr ull;

View file

@ -23,8 +23,12 @@
#include <lll_scan.h>
#include <lll/lll_df_types.h>
#include <lll_sync.h>
#include <lll_conn.h>
#include <ull_tx_queue.h>
#include <ull_scan_types.h>
#include <ull_scan_internal.h>
#include <ull_conn_types.h>
#include <ull_conn_internal.h>
#include <ull_sync_types.h>
#include <ull_sync_internal.h>