2020-03-13 16:24:01 +05:30
|
|
|
/*
|
2021-06-21 13:55:14 +05:30
|
|
|
* Copyright (c) 2017-2021 Nordic Semiconductor ASA
|
2020-03-13 16:24:01 +05:30
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2020-08-19 10:09:58 +05:30
|
|
|
#include <zephyr.h>
|
|
|
|
#include <soc.h>
|
2020-03-13 16:24:01 +05:30
|
|
|
#include <bluetooth/hci.h>
|
2020-08-19 10:09:58 +05:30
|
|
|
#include <sys/byteorder.h>
|
2020-03-13 16:24:01 +05:30
|
|
|
|
2020-08-19 10:09:58 +05:30
|
|
|
#include "hal/cpu.h"
|
2021-11-15 09:41:12 +01:00
|
|
|
#include "hal/ccm.h"
|
2020-03-13 16:24:01 +05:30
|
|
|
#include "hal/ticker.h"
|
|
|
|
|
|
|
|
#include "util/util.h"
|
|
|
|
#include "util/mem.h"
|
|
|
|
#include "util/memq.h"
|
|
|
|
#include "util/mayfly.h"
|
|
|
|
|
|
|
|
#include "ticker/ticker.h"
|
|
|
|
|
|
|
|
#include "pdu.h"
|
2021-02-24 16:42:02 +05:30
|
|
|
|
2020-03-13 16:24:01 +05:30
|
|
|
#include "lll.h"
|
2021-06-21 13:55:14 +05:30
|
|
|
#include "lll_clock.h"
|
2021-02-24 16:42:02 +05:30
|
|
|
#include "lll/lll_vendor.h"
|
|
|
|
#include "lll/lll_adv_types.h"
|
2020-03-13 16:24:01 +05:30
|
|
|
#include "lll_adv.h"
|
2021-02-24 16:42:02 +05:30
|
|
|
#include "lll/lll_adv_pdu.h"
|
2020-02-06 16:43:46 +05:30
|
|
|
#include "lll_adv_sync.h"
|
2021-02-24 16:42:02 +05:30
|
|
|
#include "lll/lll_df_types.h"
|
2021-11-15 09:41:12 +01:00
|
|
|
#include "lll_conn.h"
|
2021-03-08 12:25:46 +05:30
|
|
|
#include "lll_chan.h"
|
2020-03-13 16:24:01 +05:30
|
|
|
|
|
|
|
#include "ull_adv_types.h"
|
|
|
|
|
|
|
|
#include "ull_internal.h"
|
2020-02-07 18:12:16 +05:30
|
|
|
#include "ull_chan_internal.h"
|
2020-03-13 16:24:01 +05:30
|
|
|
#include "ull_adv_internal.h"
|
|
|
|
|
2021-02-24 16:42:02 +05:30
|
|
|
#include "ll.h"
|
|
|
|
|
2020-03-13 16:24:01 +05:30
|
|
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
|
|
|
#define LOG_MODULE_NAME bt_ctlr_ull_adv_sync
|
|
|
|
#include "common/log.h"
|
|
|
|
#include "hal/debug.h"
|
|
|
|
|
|
|
|
static int init_reset(void);
|
|
|
|
static inline struct ll_adv_sync_set *sync_acquire(void);
|
|
|
|
static inline void sync_release(struct ll_adv_sync_set *sync);
|
|
|
|
static inline uint16_t sync_handle_get(struct ll_adv_sync_set *sync);
|
2020-10-20 17:12:28 +05:30
|
|
|
static inline uint8_t sync_remove(struct ll_adv_sync_set *sync,
|
|
|
|
struct ll_adv_set *adv, uint8_t enable);
|
2021-08-25 20:38:10 +05:30
|
|
|
static uint8_t sync_chm_update(uint8_t handle);
|
2021-10-25 21:38:36 +05:30
|
|
|
static uint32_t sync_time_get(struct ll_adv_sync_set *sync,
|
2021-06-30 12:35:19 +05:30
|
|
|
struct pdu_adv *pdu);
|
2021-01-22 05:38:47 -08:00
|
|
|
|
2020-02-12 08:55:57 +05:30
|
|
|
static void mfy_sync_offset_get(void *param);
|
2020-07-17 15:27:42 +05:30
|
|
|
static inline struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu);
|
|
|
|
static inline void sync_info_offset_fill(struct pdu_adv_sync_info *si,
|
|
|
|
uint32_t ticks_offset,
|
|
|
|
uint32_t start_us);
|
2021-09-15 11:48:21 +05:30
|
|
|
static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
|
|
|
|
uint32_t remainder, uint16_t lazy, uint8_t force,
|
|
|
|
void *param);
|
2020-02-12 08:55:57 +05:30
|
|
|
static void ticker_op_cb(uint32_t status, void *param);
|
2020-03-13 16:24:01 +05:30
|
|
|
|
|
|
|
static struct ll_adv_sync_set ll_adv_sync_pool[CONFIG_BT_CTLR_ADV_SYNC_SET];
|
|
|
|
static void *adv_sync_free;
|
|
|
|
|
2021-06-18 07:13:29 +02:00
|
|
|
void ull_adv_sync_pdu_init(struct pdu_adv *pdu, uint8_t ext_hdr_flags)
|
2021-03-01 15:29:21 +01:00
|
|
|
{
|
|
|
|
struct pdu_adv_com_ext_adv *com_hdr;
|
|
|
|
struct pdu_adv_ext_hdr *ext_hdr;
|
|
|
|
uint8_t *dptr;
|
|
|
|
uint8_t len;
|
|
|
|
|
|
|
|
pdu->type = PDU_ADV_TYPE_AUX_SYNC_IND;
|
|
|
|
pdu->rfu = 0U;
|
|
|
|
pdu->chan_sel = 0U;
|
|
|
|
|
|
|
|
pdu->tx_addr = 0U;
|
|
|
|
pdu->rx_addr = 0U;
|
|
|
|
|
|
|
|
com_hdr = &pdu->adv_ext_ind;
|
|
|
|
/* Non-connectable and Non-scannable adv mode */
|
|
|
|
com_hdr->adv_mode = 0U;
|
|
|
|
|
|
|
|
ext_hdr = &com_hdr->ext_hdr;
|
|
|
|
*(uint8_t *)ext_hdr = ext_hdr_flags;
|
|
|
|
dptr = ext_hdr->data;
|
|
|
|
|
2021-11-10 15:46:45 +01:00
|
|
|
LL_ASSERT(!(ext_hdr_flags & (ULL_ADV_PDU_HDR_FIELD_ADVA | ULL_ADV_PDU_HDR_FIELD_TARGETA |
|
|
|
|
#if !defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
|
2021-03-01 15:29:21 +01:00
|
|
|
ULL_ADV_PDU_HDR_FIELD_ADI |
|
2021-11-10 15:46:45 +01:00
|
|
|
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
|
2021-03-01 15:29:21 +01:00
|
|
|
ULL_ADV_PDU_HDR_FIELD_SYNC_INFO)));
|
|
|
|
|
|
|
|
if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
|
|
|
|
dptr += sizeof(struct pdu_cte_info);
|
|
|
|
}
|
|
|
|
if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) {
|
|
|
|
dptr += sizeof(struct pdu_adv_aux_ptr);
|
|
|
|
}
|
|
|
|
if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_TX_POWER) {
|
|
|
|
dptr += sizeof(uint8_t);
|
|
|
|
}
|
2021-11-10 15:46:45 +01:00
|
|
|
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);
|
|
|
|
}
|
2021-03-01 15:29:21 +01:00
|
|
|
|
|
|
|
/* Calc tertiary PDU len */
|
|
|
|
len = ull_adv_aux_hdr_len_calc(com_hdr, &dptr);
|
|
|
|
ull_adv_aux_hdr_len_fill(com_hdr, len);
|
|
|
|
|
|
|
|
pdu->len = len;
|
|
|
|
}
|
2021-03-01 16:00:53 +01:00
|
|
|
|
|
|
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
|
|
|
static uint8_t adv_sync_pdu_init_from_prev_pdu(struct pdu_adv *pdu,
|
|
|
|
struct pdu_adv *pdu_prev,
|
|
|
|
uint16_t ext_hdr_flags_add,
|
|
|
|
uint16_t ext_hdr_flags_rem)
|
|
|
|
{
|
|
|
|
struct pdu_adv_com_ext_adv *com_hdr_prev;
|
|
|
|
struct pdu_adv_ext_hdr *ext_hdr_prev;
|
|
|
|
struct pdu_adv_com_ext_adv *com_hdr;
|
|
|
|
struct pdu_adv_ext_hdr *ext_hdr;
|
|
|
|
uint8_t ext_hdr_flags_prev;
|
|
|
|
uint8_t ext_hdr_flags;
|
|
|
|
uint8_t *dptr_prev;
|
|
|
|
uint8_t len_prev;
|
|
|
|
uint8_t *dptr;
|
|
|
|
uint8_t len;
|
|
|
|
|
|
|
|
/* Copy complete header, assume it was set properly in old PDU */
|
|
|
|
*(uint8_t *)pdu = *(uint8_t *)pdu_prev;
|
|
|
|
|
|
|
|
com_hdr_prev = &pdu_prev->adv_ext_ind;
|
|
|
|
com_hdr = &pdu->adv_ext_ind;
|
|
|
|
|
|
|
|
com_hdr->adv_mode = 0U;
|
|
|
|
|
|
|
|
ext_hdr_prev = &com_hdr_prev->ext_hdr;
|
|
|
|
ext_hdr = &com_hdr->ext_hdr;
|
|
|
|
|
|
|
|
if (com_hdr_prev->ext_hdr_len) {
|
|
|
|
ext_hdr_flags_prev = *(uint8_t *) ext_hdr_prev;
|
|
|
|
} else {
|
|
|
|
ext_hdr_flags_prev = 0;
|
|
|
|
}
|
|
|
|
ext_hdr_flags = ext_hdr_flags_prev |
|
|
|
|
(ext_hdr_flags_add & (~ext_hdr_flags_rem));
|
|
|
|
|
|
|
|
*(uint8_t *)ext_hdr = ext_hdr_flags;
|
|
|
|
|
|
|
|
LL_ASSERT(!ext_hdr->adv_addr);
|
|
|
|
LL_ASSERT(!ext_hdr->tgt_addr);
|
2021-11-10 15:46:45 +01:00
|
|
|
LL_ASSERT(IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) ||
|
|
|
|
!ext_hdr->adi);
|
2021-03-01 16:00:53 +01:00
|
|
|
LL_ASSERT(!ext_hdr->sync_info);
|
|
|
|
|
|
|
|
dptr = ext_hdr->data;
|
|
|
|
dptr_prev = ext_hdr_prev->data;
|
|
|
|
|
|
|
|
/* Note: skip length verification of ext header writes as we assume that
|
|
|
|
* all PDUs are large enough to store at least complete ext header.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Copy CTEInfo, if applicable */
|
|
|
|
if (ext_hdr->cte_info) {
|
|
|
|
if (ext_hdr_prev->cte_info) {
|
2021-11-10 15:46:45 +01:00
|
|
|
(void)memcpy(dptr, dptr_prev, sizeof(struct pdu_cte_info));
|
2021-03-01 16:00:53 +01:00
|
|
|
}
|
|
|
|
dptr += sizeof(struct pdu_cte_info);
|
|
|
|
}
|
|
|
|
if (ext_hdr_prev->cte_info) {
|
|
|
|
dptr_prev += sizeof(struct pdu_cte_info);
|
|
|
|
}
|
|
|
|
|
2021-11-10 15:46:45 +01:00
|
|
|
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) && ext_hdr->adi != 0) {
|
|
|
|
if (ext_hdr_prev->adi) {
|
|
|
|
memcpy(dptr, dptr_prev, sizeof(struct pdu_adv_adi));
|
|
|
|
}
|
|
|
|
dptr += sizeof(struct pdu_adv_adi);
|
|
|
|
}
|
|
|
|
if (ext_hdr_prev->adi) {
|
|
|
|
dptr_prev += sizeof(struct pdu_adv_adi);
|
|
|
|
}
|
|
|
|
|
2021-03-01 16:00:53 +01:00
|
|
|
/* Add AuxPtr, if applicable. Do not copy since it will be updated later
|
|
|
|
* anyway.
|
|
|
|
*/
|
|
|
|
if (ext_hdr->aux_ptr) {
|
|
|
|
dptr += sizeof(struct pdu_adv_aux_ptr);
|
|
|
|
}
|
|
|
|
if (ext_hdr_prev->aux_ptr) {
|
|
|
|
dptr_prev += sizeof(struct pdu_adv_aux_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy TxPower, if applicable */
|
|
|
|
if (ext_hdr->tx_pwr) {
|
|
|
|
if (ext_hdr_prev->tx_pwr) {
|
|
|
|
memcpy(dptr, dptr_prev, sizeof(uint8_t));
|
|
|
|
}
|
|
|
|
dptr += sizeof(uint8_t);
|
|
|
|
}
|
|
|
|
if (ext_hdr_prev->tx_pwr) {
|
|
|
|
dptr_prev += sizeof(uint8_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
LL_ASSERT(ext_hdr_prev >= 0);
|
|
|
|
|
|
|
|
/* Copy ACAD */
|
|
|
|
len = com_hdr_prev->ext_hdr_len - (dptr_prev - (uint8_t *)ext_hdr_prev);
|
|
|
|
memcpy(dptr, dptr_prev, len);
|
|
|
|
dptr += len;
|
|
|
|
|
|
|
|
/* Check populated ext header length excluding length itself. If 0, then
|
|
|
|
* there was neither field nor ACAD populated and we skip ext header
|
|
|
|
* entirely.
|
|
|
|
*/
|
|
|
|
len = dptr - ext_hdr->data;
|
|
|
|
if (len == 0) {
|
|
|
|
com_hdr->ext_hdr_len = 0;
|
|
|
|
} else {
|
|
|
|
com_hdr->ext_hdr_len = len +
|
|
|
|
offsetof(struct pdu_adv_ext_hdr, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Both PDUs have now ext header length calculated properly, reset
|
|
|
|
* pointers to start of AD.
|
|
|
|
*/
|
|
|
|
dptr = &com_hdr->ext_hdr_adv_data[com_hdr->ext_hdr_len];
|
|
|
|
dptr_prev = &com_hdr_prev->ext_hdr_adv_data[com_hdr_prev->ext_hdr_len];
|
|
|
|
|
|
|
|
/* Calculate length of AD to copy and AD length available in new PDU */
|
|
|
|
len_prev = pdu_prev->len - (dptr_prev - pdu_prev->payload);
|
|
|
|
len = PDU_AC_PAYLOAD_SIZE_MAX - (dptr - pdu->payload);
|
|
|
|
|
|
|
|
/* TODO: we should allow partial copy and let caller refragment data */
|
|
|
|
if (len < len_prev) {
|
|
|
|
return BT_HCI_ERR_PACKET_TOO_LONG;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy AD */
|
|
|
|
if (!(ext_hdr_flags_rem & ULL_ADV_PDU_HDR_FIELD_AD_DATA)) {
|
|
|
|
len = MIN(len, len_prev);
|
|
|
|
memcpy(dptr, dptr_prev, len);
|
|
|
|
dptr += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finalize PDU */
|
|
|
|
pdu->len = dptr - pdu->payload;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-08-05 13:11:35 +02:00
|
|
|
/* Note: Function made global because it is temporarily not used and causes compilation warning.
|
|
|
|
* It will be used when fragmentation of periodic advertising PDU is implemented.
|
|
|
|
*/
|
|
|
|
uint8_t adv_sync_pdu_ad_data_set(struct pdu_adv *pdu, const uint8_t *data, uint8_t len)
|
2021-03-01 16:00:53 +01:00
|
|
|
{
|
|
|
|
struct pdu_adv_com_ext_adv *com_hdr;
|
|
|
|
uint8_t len_max;
|
|
|
|
uint8_t *dptr;
|
|
|
|
|
|
|
|
com_hdr = &pdu->adv_ext_ind;
|
|
|
|
|
|
|
|
dptr = &com_hdr->ext_hdr_adv_data[com_hdr->ext_hdr_len];
|
|
|
|
|
|
|
|
len_max = PDU_AC_PAYLOAD_SIZE_MAX - (dptr - pdu->payload);
|
|
|
|
/* TODO: we should allow partial copy and let caller refragment data */
|
|
|
|
if (len > len_max) {
|
|
|
|
return BT_HCI_ERR_PACKET_TOO_LONG;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(dptr, data, len);
|
|
|
|
dptr += len;
|
|
|
|
|
|
|
|
pdu->len = dptr - pdu->payload;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-18 07:13:29 +02:00
|
|
|
uint8_t ull_adv_sync_pdu_cte_info_set(struct pdu_adv *pdu, const struct pdu_cte_info *cte_info)
|
2021-03-01 16:27:07 +01:00
|
|
|
{
|
|
|
|
struct pdu_adv_com_ext_adv *com_hdr;
|
|
|
|
struct pdu_adv_ext_hdr *ext_hdr;
|
|
|
|
uint8_t *dptr;
|
|
|
|
|
|
|
|
com_hdr = &pdu->adv_ext_ind;
|
|
|
|
ext_hdr = &com_hdr->ext_hdr;
|
|
|
|
dptr = ext_hdr->data;
|
|
|
|
|
|
|
|
/* Periodic adv PDUs do not have AdvA/TargetA */
|
|
|
|
LL_ASSERT(!ext_hdr->adv_addr);
|
|
|
|
LL_ASSERT(!ext_hdr->tgt_addr);
|
|
|
|
|
|
|
|
if (ext_hdr->cte_info) {
|
|
|
|
memcpy(dptr, cte_info, sizeof(*cte_info));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-01 16:00:53 +01:00
|
|
|
static struct pdu_adv *adv_sync_pdu_duplicate_chain(struct pdu_adv *pdu)
|
|
|
|
{
|
|
|
|
struct pdu_adv *pdu_dup = NULL;
|
|
|
|
uint8_t err;
|
|
|
|
|
|
|
|
while (pdu) {
|
|
|
|
struct pdu_adv *pdu_new;
|
|
|
|
|
|
|
|
pdu_new = lll_adv_pdu_alloc_pdu_adv();
|
|
|
|
|
|
|
|
/* We make exact copy of old PDU, there's really nothing that
|
|
|
|
* can go wrong there assuming original PDU was created properly
|
|
|
|
*/
|
|
|
|
err = adv_sync_pdu_init_from_prev_pdu(pdu_new, pdu, 0, 0);
|
|
|
|
LL_ASSERT(err == 0);
|
|
|
|
|
|
|
|
if (pdu_dup) {
|
|
|
|
lll_adv_pdu_linked_append_end(pdu_new, pdu_dup);
|
|
|
|
} else {
|
|
|
|
pdu_dup = pdu_new;
|
|
|
|
}
|
|
|
|
|
|
|
|
pdu = lll_adv_pdu_linked_next_get(pdu);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pdu_dup;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CTLR_ADV_PDU_LINK */
|
|
|
|
|
2020-03-13 16:24:01 +05:30
|
|
|
uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
|
|
|
|
{
|
2021-03-01 16:00:53 +01:00
|
|
|
void *extra_data_prev, *extra_data;
|
|
|
|
struct pdu_adv *pdu_prev, *pdu;
|
2020-02-12 08:55:57 +05:30
|
|
|
struct lll_adv_sync *lll_sync;
|
2020-03-13 16:24:01 +05:30
|
|
|
struct ll_adv_sync_set *sync;
|
|
|
|
struct ll_adv_set *adv;
|
2021-01-22 05:38:47 -08:00
|
|
|
uint8_t err, ter_idx;
|
2020-03-13 16:24:01 +05:30
|
|
|
|
2020-03-13 16:24:01 +05:30
|
|
|
adv = ull_adv_is_created_get(handle);
|
2020-03-13 16:24:01 +05:30
|
|
|
if (!adv) {
|
2020-07-22 01:49:22 +02:00
|
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
2020-03-13 16:24:01 +05:30
|
|
|
}
|
|
|
|
|
2020-02-12 08:55:57 +05:30
|
|
|
lll_sync = adv->lll.sync;
|
|
|
|
if (!lll_sync) {
|
2021-02-16 15:41:34 +05:30
|
|
|
struct pdu_adv *ter_pdu;
|
2020-02-12 08:55:57 +05:30
|
|
|
struct lll_adv *lll;
|
2021-08-25 20:38:10 +05:30
|
|
|
uint8_t chm_last;
|
2020-05-11 15:36:12 +05:30
|
|
|
int err;
|
2020-02-10 18:48:04 +05:30
|
|
|
|
2020-03-13 16:24:01 +05:30
|
|
|
sync = sync_acquire();
|
|
|
|
if (!sync) {
|
|
|
|
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
|
|
|
|
}
|
|
|
|
|
2020-02-12 08:55:57 +05:30
|
|
|
lll = &adv->lll;
|
|
|
|
lll_sync = &sync->lll;
|
|
|
|
lll->sync = lll_sync;
|
|
|
|
lll_sync->adv = lll;
|
2020-03-13 16:24:01 +05:30
|
|
|
|
2020-10-22 18:40:38 +05:30
|
|
|
lll_adv_data_reset(&lll_sync->data);
|
|
|
|
err = lll_adv_data_init(&lll_sync->data);
|
|
|
|
if (err) {
|
|
|
|
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
|
|
|
|
}
|
|
|
|
|
2020-04-27 17:00:09 +05:30
|
|
|
/* NOTE: ull_hdr_init(&sync->ull); is done on start */
|
2020-02-12 08:55:57 +05:30
|
|
|
lll_hdr_init(lll_sync, sync);
|
2020-02-07 18:12:16 +05:30
|
|
|
|
2020-05-11 15:36:12 +05:30
|
|
|
err = util_aa_le32(lll_sync->access_addr);
|
|
|
|
LL_ASSERT(!err);
|
|
|
|
|
2021-03-08 12:25:46 +05:30
|
|
|
lll_sync->data_chan_id = lll_chan_id(lll_sync->access_addr);
|
2021-08-25 20:38:10 +05:30
|
|
|
chm_last = lll_sync->chm_first;
|
|
|
|
lll_sync->chm_last = chm_last;
|
|
|
|
lll_sync->chm[chm_last].data_chan_count =
|
|
|
|
ull_chan_map_get(lll_sync->chm[chm_last].data_chan_map);
|
2021-03-08 12:25:46 +05:30
|
|
|
|
2020-05-21 14:51:16 +02:00
|
|
|
lll_csrand_get(lll_sync->crc_init, sizeof(lll_sync->crc_init));
|
2020-02-07 18:12:16 +05:30
|
|
|
|
2020-02-12 08:55:57 +05:30
|
|
|
lll_sync->latency_prepare = 0;
|
|
|
|
lll_sync->latency_event = 0;
|
|
|
|
lll_sync->event_counter = 0;
|
2020-02-07 18:12:16 +05:30
|
|
|
|
2020-05-21 10:29:49 +05:30
|
|
|
sync->is_enabled = 0U;
|
|
|
|
sync->is_started = 0U;
|
2020-03-13 16:24:01 +05:30
|
|
|
|
2021-01-22 05:38:47 -08:00
|
|
|
ter_pdu = lll_adv_sync_data_peek(lll_sync, NULL);
|
2021-06-18 07:13:29 +02:00
|
|
|
ull_adv_sync_pdu_init(ter_pdu, 0);
|
2021-01-22 05:38:47 -08:00
|
|
|
} else {
|
2021-04-05 12:56:51 +05:30
|
|
|
sync = HDR_LLL2ULL(lll_sync);
|
2020-03-13 16:24:01 +05:30
|
|
|
}
|
|
|
|
|
2021-07-01 17:47:19 +05:30
|
|
|
/* Periodic Advertising is already started */
|
|
|
|
if (sync->is_started) {
|
|
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
|
|
}
|
|
|
|
|
2021-01-22 05:38:47 -08:00
|
|
|
sync->interval = interval;
|
2020-02-10 18:48:04 +05:30
|
|
|
|
2021-07-14 07:47:32 +02:00
|
|
|
err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST, &pdu_prev, &pdu,
|
2021-03-01 16:00:53 +01:00
|
|
|
&extra_data_prev, &extra_data, &ter_idx);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
|
|
|
if (extra_data) {
|
|
|
|
ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data,
|
|
|
|
0, 0, NULL);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
|
|
|
|
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, 0, 0, NULL);
|
2021-01-22 05:38:47 -08:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2020-08-17 12:49:40 +05:30
|
|
|
|
2021-01-22 05:38:47 -08:00
|
|
|
lll_adv_sync_data_enqueue(lll_sync, ter_idx);
|
2020-02-10 18:48:04 +05:30
|
|
|
|
2020-03-13 16:24:01 +05:30
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-20 10:18:39 +05:30
|
|
|
uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len,
|
|
|
|
uint8_t const *const data)
|
2020-03-13 16:24:01 +05:30
|
|
|
{
|
2021-08-27 11:10:22 +05:30
|
|
|
uint8_t hdr_data[ULL_ADV_HDR_DATA_LEN_SIZE +
|
|
|
|
ULL_ADV_HDR_DATA_DATA_PTR_SIZE];
|
2021-03-01 16:00:53 +01:00
|
|
|
void *extra_data_prev, *extra_data;
|
|
|
|
struct pdu_adv *pdu_prev, *pdu;
|
2020-11-04 13:29:27 +05:30
|
|
|
struct lll_adv_sync *lll_sync;
|
2021-06-30 13:33:03 +05:30
|
|
|
struct ll_adv_sync_set *sync;
|
2020-11-04 13:29:27 +05:30
|
|
|
struct ll_adv_set *adv;
|
|
|
|
uint8_t ter_idx;
|
2021-01-22 05:38:47 -08:00
|
|
|
uint8_t err;
|
|
|
|
|
|
|
|
/* TODO: handle other op values */
|
|
|
|
if (op != BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA &&
|
|
|
|
op != BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA) {
|
|
|
|
/* FIXME: error code */
|
|
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
|
|
}
|
2020-11-04 13:29:27 +05:30
|
|
|
|
|
|
|
adv = ull_adv_is_created_get(handle);
|
|
|
|
if (!adv) {
|
|
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
|
|
|
}
|
|
|
|
|
|
|
|
lll_sync = adv->lll.sync;
|
|
|
|
if (!lll_sync) {
|
|
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
|
|
|
}
|
|
|
|
|
2021-08-27 11:10:22 +05:30
|
|
|
hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = len;
|
|
|
|
(void)memcpy((void *)&hdr_data[ULL_ADV_HDR_DATA_DATA_PTR_OFFSET], &data,
|
|
|
|
ULL_ADV_HDR_DATA_DATA_PTR_SIZE);
|
2020-11-04 13:29:27 +05:30
|
|
|
|
2021-07-14 07:47:32 +02:00
|
|
|
err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST, &pdu_prev, &pdu,
|
2021-03-01 16:00:53 +01:00
|
|
|
&extra_data_prev, &extra_data, &ter_idx);
|
2021-01-22 05:38:47 -08:00
|
|
|
if (err) {
|
|
|
|
return err;
|
2020-11-04 13:29:27 +05:30
|
|
|
}
|
|
|
|
|
2021-03-01 16:00:53 +01:00
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
|
|
|
if (extra_data) {
|
|
|
|
ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data,
|
2021-07-15 07:57:04 +02:00
|
|
|
ULL_ADV_PDU_HDR_FIELD_AD_DATA, 0, NULL);
|
2021-03-01 16:00:53 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
2020-11-04 13:29:27 +05:30
|
|
|
|
2021-07-15 07:57:04 +02:00
|
|
|
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, ULL_ADV_PDU_HDR_FIELD_AD_DATA, 0,
|
|
|
|
hdr_data);
|
2021-06-30 13:33:03 +05:30
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2021-03-01 16:00:53 +01:00
|
|
|
|
|
|
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
|
|
|
/* alloc() will return the same PDU as peek() in case there was PDU
|
|
|
|
* queued but not switched to current before alloc() - no need to deal
|
|
|
|
* with chain as it's already there. In other case we need to duplicate
|
|
|
|
* chain from current PDU and append it to new PDU.
|
|
|
|
*/
|
|
|
|
if (pdu != pdu_prev) {
|
|
|
|
struct pdu_adv *next, *next_dup;
|
|
|
|
|
|
|
|
LL_ASSERT(lll_adv_pdu_linked_next_get(pdu) == NULL);
|
|
|
|
|
|
|
|
next = lll_adv_pdu_linked_next_get(pdu_prev);
|
|
|
|
next_dup = adv_sync_pdu_duplicate_chain(next);
|
|
|
|
|
|
|
|
lll_adv_pdu_linked_append(next_dup, pdu);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CTLR_ADV_PDU_LINK */
|
|
|
|
|
2021-06-30 13:33:03 +05:30
|
|
|
sync = HDR_LLL2ULL(lll_sync);
|
|
|
|
if (sync->is_started) {
|
2021-07-16 06:47:15 +05:30
|
|
|
err = ull_adv_sync_time_update(sync, pdu);
|
2021-06-30 13:33:03 +05:30
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
2021-03-01 16:00:53 +01:00
|
|
|
}
|
|
|
|
|
2021-06-30 13:33:03 +05:30
|
|
|
lll_adv_sync_data_enqueue(lll_sync, ter_idx);
|
|
|
|
|
2021-03-01 16:00:53 +01:00
|
|
|
return err;
|
2020-03-13 16:24:01 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable)
|
|
|
|
{
|
2020-02-12 08:55:57 +05:30
|
|
|
struct lll_adv_sync *lll_sync;
|
2020-03-13 16:24:01 +05:30
|
|
|
struct ll_adv_sync_set *sync;
|
2020-10-09 16:44:23 +05:30
|
|
|
uint8_t sync_got_enabled;
|
2020-03-13 16:24:01 +05:30
|
|
|
struct ll_adv_set *adv;
|
2020-10-09 16:44:23 +05:30
|
|
|
uint8_t pri_idx;
|
|
|
|
uint8_t err;
|
2020-03-13 16:24:01 +05:30
|
|
|
|
2020-03-13 16:24:01 +05:30
|
|
|
adv = ull_adv_is_created_get(handle);
|
2020-03-13 16:24:01 +05:30
|
|
|
if (!adv) {
|
2020-07-22 01:49:22 +02:00
|
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
2020-03-13 16:24:01 +05:30
|
|
|
}
|
|
|
|
|
2020-02-12 08:55:57 +05:30
|
|
|
lll_sync = adv->lll.sync;
|
|
|
|
if (!lll_sync) {
|
2021-09-09 15:38:13 +05:30
|
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: Add Periodic Advertising ADI Support feature */
|
|
|
|
if (enable > 1U) {
|
|
|
|
return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
|
2020-03-13 16:24:01 +05:30
|
|
|
}
|
|
|
|
|
2021-04-05 12:56:51 +05:30
|
|
|
sync = HDR_LLL2ULL(lll_sync);
|
2020-03-13 16:24:01 +05:30
|
|
|
|
|
|
|
if (!enable) {
|
2020-05-21 10:29:49 +05:30
|
|
|
if (!sync->is_enabled) {
|
|
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sync->is_started) {
|
|
|
|
sync->is_enabled = 0U;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:12:28 +05:30
|
|
|
err = sync_remove(sync, adv, 0U);
|
|
|
|
return err;
|
2020-03-13 16:24:01 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: Check for periodic data being complete */
|
|
|
|
|
|
|
|
/* TODO: Check packet too long */
|
|
|
|
|
2020-10-09 16:44:23 +05:30
|
|
|
sync_got_enabled = 0U;
|
2020-03-13 16:24:01 +05:30
|
|
|
if (sync->is_enabled) {
|
|
|
|
/* TODO: Enabling an already enabled advertising changes its
|
|
|
|
* random address.
|
|
|
|
*/
|
|
|
|
} else {
|
2020-10-09 16:44:23 +05:30
|
|
|
sync_got_enabled = 1U;
|
2020-03-13 16:24:01 +05:30
|
|
|
}
|
|
|
|
|
2020-05-21 10:29:49 +05:30
|
|
|
if (adv->is_enabled && !sync->is_started) {
|
2021-06-21 13:55:14 +05:30
|
|
|
struct pdu_adv_sync_info *sync_info;
|
|
|
|
uint8_t value[1 + sizeof(sync_info)];
|
2020-10-09 16:44:23 +05:30
|
|
|
uint32_t ticks_slot_overhead_aux;
|
|
|
|
struct lll_adv_aux *lll_aux;
|
|
|
|
struct ll_adv_aux_set *aux;
|
|
|
|
uint32_t ticks_anchor_sync;
|
|
|
|
uint32_t ticks_anchor_aux;
|
|
|
|
uint32_t ret;
|
2020-07-06 15:40:58 +05:30
|
|
|
|
2020-10-09 16:44:23 +05:30
|
|
|
lll_aux = adv->lll.aux;
|
2020-07-06 15:40:58 +05:30
|
|
|
|
|
|
|
/* Add sync_info into auxiliary PDU */
|
|
|
|
err = ull_adv_aux_hdr_set_clear(adv,
|
|
|
|
ULL_ADV_PDU_HDR_FIELD_SYNC_INFO,
|
2021-06-21 13:55:14 +05:30
|
|
|
0, value, NULL, &pri_idx);
|
2020-07-06 15:40:58 +05:30
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-06-21 13:55:14 +05:30
|
|
|
/* First byte in the length-value encoded parameter is size of
|
|
|
|
* sync_info structure, followed by pointer to sync_info in the
|
|
|
|
* PDU.
|
|
|
|
*/
|
|
|
|
memcpy(&sync_info, &value[1], sizeof(sync_info));
|
|
|
|
ull_adv_sync_info_fill(sync, sync_info);
|
|
|
|
|
2020-10-09 16:44:23 +05:30
|
|
|
if (lll_aux) {
|
|
|
|
/* FIXME: Find absolute ticks until after auxiliary PDU
|
|
|
|
* on air to place the periodic advertising PDU.
|
|
|
|
*/
|
|
|
|
ticks_anchor_aux = 0U; /* unused in this path */
|
|
|
|
ticks_slot_overhead_aux = 0U; /* unused in this path */
|
|
|
|
ticks_anchor_sync = ticker_ticks_now_get();
|
|
|
|
aux = NULL;
|
|
|
|
} else {
|
|
|
|
lll_aux = adv->lll.aux;
|
2021-04-05 12:56:51 +05:30
|
|
|
aux = HDR_LLL2ULL(lll_aux);
|
2020-10-09 16:44:23 +05:30
|
|
|
ticks_anchor_aux = ticker_ticks_now_get();
|
|
|
|
ticks_slot_overhead_aux = ull_adv_aux_evt_init(aux);
|
|
|
|
ticks_anchor_sync =
|
|
|
|
ticks_anchor_aux + ticks_slot_overhead_aux +
|
2021-04-05 12:56:51 +05:30
|
|
|
aux->ull.ticks_slot +
|
2020-10-09 16:44:23 +05:30
|
|
|
HAL_TICKER_US_TO_TICKS(EVENT_MAFS_US);
|
|
|
|
}
|
2020-07-06 15:40:58 +05:30
|
|
|
|
2021-01-22 05:38:47 -08:00
|
|
|
ret = ull_adv_sync_start(adv, sync, ticks_anchor_sync);
|
2020-10-09 16:44:23 +05:30
|
|
|
if (ret) {
|
2020-10-20 17:12:28 +05:30
|
|
|
sync_remove(sync, adv, 1U);
|
|
|
|
|
|
|
|
return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
|
2020-07-06 15:40:58 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
sync->is_started = 1U;
|
2020-10-01 19:26:34 +05:30
|
|
|
|
|
|
|
lll_adv_data_enqueue(&adv->lll, pri_idx);
|
2020-10-09 16:44:23 +05:30
|
|
|
|
|
|
|
if (aux) {
|
|
|
|
/* Keep aux interval equal or higher than primary PDU
|
|
|
|
* interval.
|
|
|
|
*/
|
|
|
|
aux->interval = adv->interval +
|
|
|
|
(HAL_TICKER_TICKS_TO_US(
|
2021-01-16 13:38:07 +01:00
|
|
|
ULL_ADV_RANDOM_DELAY) /
|
|
|
|
ADV_INT_UNIT_US);
|
2020-10-09 16:44:23 +05:30
|
|
|
|
|
|
|
ret = ull_adv_aux_start(aux, ticks_anchor_aux,
|
|
|
|
ticks_slot_overhead_aux);
|
|
|
|
if (ret) {
|
2020-10-20 17:12:28 +05:30
|
|
|
sync_remove(sync, adv, 1U);
|
|
|
|
|
|
|
|
return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
|
2020-10-09 16:44:23 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
aux->is_started = 1U;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sync_got_enabled) {
|
|
|
|
sync->is_enabled = sync_got_enabled;
|
2020-03-13 16:24:01 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ull_adv_sync_init(void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = init_reset();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ull_adv_sync_reset(void)
|
2021-07-30 15:20:00 +02:00
|
|
|
{
|
|
|
|
struct lll_adv_sync *lll_sync;
|
|
|
|
struct ll_adv_sync_set *sync;
|
|
|
|
struct ll_adv_set *adv;
|
|
|
|
uint8_t handle;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
for (handle = 0U; handle < BT_CTLR_ADV_SET; handle++) {
|
|
|
|
adv = ull_adv_is_created_get(handle);
|
|
|
|
if (!adv) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
lll_sync = adv->lll.sync;
|
|
|
|
if (!lll_sync) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sync = HDR_LLL2ULL(lll_sync);
|
|
|
|
|
|
|
|
if (!sync->is_started) {
|
|
|
|
sync->is_enabled = 0U;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = sync_remove(sync, adv, 0U);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ull_adv_sync_reset_finalize(void)
|
2020-03-13 16:24:01 +05:30
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = init_reset();
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-02-06 16:43:46 +05:30
|
|
|
uint16_t ull_adv_sync_lll_handle_get(struct lll_adv_sync *lll)
|
|
|
|
{
|
|
|
|
return sync_handle_get((void *)lll->hdr.parent);
|
|
|
|
}
|
|
|
|
|
2021-06-30 13:33:03 +05:30
|
|
|
void ull_adv_sync_release(struct ll_adv_sync_set *sync)
|
|
|
|
{
|
|
|
|
lll_adv_sync_data_release(&sync->lll);
|
|
|
|
sync_release(sync);
|
|
|
|
}
|
|
|
|
|
2021-01-22 05:38:47 -08:00
|
|
|
uint32_t ull_adv_sync_start(struct ll_adv_set *adv,
|
|
|
|
struct ll_adv_sync_set *sync,
|
2020-10-09 16:26:22 +05:30
|
|
|
uint32_t ticks_anchor)
|
2020-03-13 16:24:01 +05:30
|
|
|
{
|
2021-05-20 10:18:44 +05:30
|
|
|
struct lll_adv_sync *lll_sync;
|
2020-02-07 18:12:16 +05:30
|
|
|
uint32_t ticks_slot_overhead;
|
2020-10-09 16:26:22 +05:30
|
|
|
uint32_t volatile ret_cb;
|
2021-05-20 10:18:44 +05:30
|
|
|
struct pdu_adv *ter_pdu;
|
2020-02-12 08:55:57 +05:30
|
|
|
uint32_t interval_us;
|
2020-03-13 16:24:01 +05:30
|
|
|
uint8_t sync_handle;
|
2021-06-30 12:35:19 +05:30
|
|
|
uint32_t time_us;
|
2020-03-13 16:24:01 +05:30
|
|
|
uint32_t ret;
|
|
|
|
|
2020-10-09 16:13:33 +05:30
|
|
|
ull_hdr_init(&sync->ull);
|
|
|
|
|
2021-05-20 10:18:44 +05:30
|
|
|
lll_sync = &sync->lll;
|
|
|
|
ter_pdu = lll_adv_sync_data_peek(lll_sync, NULL);
|
2021-07-15 17:55:26 +05:30
|
|
|
|
|
|
|
/* Calculate the PDU Tx Time and hence the radio event length */
|
2021-06-30 12:35:19 +05:30
|
|
|
time_us = sync_time_get(sync, ter_pdu);
|
2021-01-22 05:38:47 -08:00
|
|
|
|
2020-03-13 16:24:01 +05:30
|
|
|
/* TODO: active_to_start feature port */
|
2021-04-05 12:56:51 +05:30
|
|
|
sync->ull.ticks_active_to_start = 0;
|
|
|
|
sync->ull.ticks_prepare_to_start =
|
2020-02-07 18:12:16 +05:30
|
|
|
HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US);
|
2021-04-05 12:56:51 +05:30
|
|
|
sync->ull.ticks_preempt_to_start =
|
2020-02-07 18:12:16 +05:30
|
|
|
HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US);
|
2021-06-30 12:35:19 +05:30
|
|
|
sync->ull.ticks_slot = HAL_TICKER_US_TO_TICKS(time_us);
|
2020-03-13 16:24:01 +05:30
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
|
2021-04-05 12:56:51 +05:30
|
|
|
ticks_slot_overhead = MAX(sync->ull.ticks_active_to_start,
|
|
|
|
sync->ull.ticks_prepare_to_start);
|
2020-03-13 16:24:01 +05:30
|
|
|
} else {
|
|
|
|
ticks_slot_overhead = 0;
|
|
|
|
}
|
|
|
|
|
2021-01-16 13:38:07 +01:00
|
|
|
interval_us = (uint32_t)sync->interval * CONN_INT_UNIT_US;
|
2020-02-12 08:55:57 +05:30
|
|
|
|
2020-03-13 16:24:01 +05:30
|
|
|
sync_handle = sync_handle_get(sync);
|
|
|
|
|
2020-10-09 16:26:22 +05:30
|
|
|
ret_cb = TICKER_STATUS_BUSY;
|
2020-03-13 16:24:01 +05:30
|
|
|
ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
|
|
|
|
(TICKER_ID_ADV_SYNC_BASE + sync_handle),
|
|
|
|
ticks_anchor, 0,
|
2020-02-12 08:55:57 +05:30
|
|
|
HAL_TICKER_US_TO_TICKS(interval_us),
|
|
|
|
HAL_TICKER_REMAINDER(interval_us), TICKER_NULL_LAZY,
|
2021-04-05 12:56:51 +05:30
|
|
|
(sync->ull.ticks_slot + ticks_slot_overhead),
|
2020-03-13 16:24:01 +05:30
|
|
|
ticker_cb, sync,
|
2020-10-09 16:26:22 +05:30
|
|
|
ull_ticker_status_give, (void *)&ret_cb);
|
|
|
|
ret = ull_ticker_status_take(ret, &ret_cb);
|
2020-03-13 16:24:01 +05:30
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-07-16 06:47:15 +05:30
|
|
|
uint8_t ull_adv_sync_time_update(struct ll_adv_sync_set *sync,
|
|
|
|
struct pdu_adv *pdu)
|
|
|
|
{
|
|
|
|
uint32_t volatile ret_cb;
|
|
|
|
uint32_t ticks_minus;
|
|
|
|
uint32_t ticks_plus;
|
|
|
|
uint32_t time_ticks;
|
2021-10-25 21:38:36 +05:30
|
|
|
uint32_t time_us;
|
2021-07-16 06:47:15 +05:30
|
|
|
uint32_t ret;
|
|
|
|
|
|
|
|
time_us = sync_time_get(sync, pdu);
|
|
|
|
time_ticks = HAL_TICKER_US_TO_TICKS(time_us);
|
|
|
|
if (sync->ull.ticks_slot > time_ticks) {
|
|
|
|
ticks_minus = sync->ull.ticks_slot - time_ticks;
|
|
|
|
ticks_plus = 0U;
|
|
|
|
} else if (sync->ull.ticks_slot < time_ticks) {
|
|
|
|
ticks_minus = 0U;
|
|
|
|
ticks_plus = time_ticks - sync->ull.ticks_slot;
|
|
|
|
} else {
|
|
|
|
return BT_HCI_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret_cb = TICKER_STATUS_BUSY;
|
|
|
|
ret = ticker_update(TICKER_INSTANCE_ID_CTLR,
|
|
|
|
TICKER_USER_ID_THREAD,
|
|
|
|
(TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync)),
|
|
|
|
0, 0, ticks_plus, ticks_minus, 0, 0,
|
|
|
|
ull_ticker_status_give, (void *)&ret_cb);
|
|
|
|
ret = ull_ticker_status_take(ret, &ret_cb);
|
|
|
|
if (ret != TICKER_STATUS_SUCCESS) {
|
|
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
|
|
}
|
|
|
|
|
|
|
|
sync->ull.ticks_slot = time_ticks;
|
|
|
|
|
|
|
|
return BT_HCI_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2021-08-25 20:38:10 +05:30
|
|
|
uint8_t ull_adv_sync_chm_update(void)
|
|
|
|
{
|
|
|
|
uint8_t handle;
|
|
|
|
|
|
|
|
handle = CONFIG_BT_CTLR_ADV_SYNC_SET;
|
|
|
|
while (handle--) {
|
|
|
|
(void)sync_chm_update(handle);
|
|
|
|
}
|
|
|
|
|
2021-08-26 21:46:32 +05:30
|
|
|
/* TODO: Should failure due to Channel Map Update being already in
|
|
|
|
* progress be returned to caller?
|
|
|
|
*/
|
2021-08-25 20:38:10 +05:30
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ull_adv_sync_chm_complete(struct node_rx_hdr *rx)
|
|
|
|
{
|
2021-08-27 11:10:22 +05:30
|
|
|
uint8_t hdr_data[ULL_ADV_HDR_DATA_LEN_SIZE +
|
|
|
|
ULL_ADV_HDR_DATA_ACAD_PTR_SIZE];
|
2021-08-25 20:38:10 +05:30
|
|
|
struct lll_adv_sync *lll_sync;
|
|
|
|
struct pdu_adv *pdu_prev;
|
|
|
|
struct ll_adv_set *adv;
|
|
|
|
struct pdu_adv *pdu;
|
|
|
|
uint8_t others_len;
|
|
|
|
uint8_t acad_len;
|
|
|
|
uint8_t *others;
|
|
|
|
uint8_t ter_idx;
|
|
|
|
uint8_t ad_len;
|
|
|
|
uint8_t *acad;
|
|
|
|
uint8_t *ad;
|
|
|
|
uint8_t len;
|
|
|
|
uint8_t err;
|
|
|
|
|
|
|
|
/* Allocate next Sync PDU */
|
|
|
|
pdu_prev = NULL;
|
|
|
|
pdu = NULL;
|
|
|
|
lll_sync = rx->rx_ftr.param;
|
|
|
|
adv = HDR_LLL2ULL(lll_sync->adv);
|
|
|
|
err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
|
|
|
|
&pdu_prev, &pdu, NULL, NULL, &ter_idx);
|
|
|
|
LL_ASSERT(!err);
|
|
|
|
|
2021-08-27 11:10:22 +05:30
|
|
|
/* Get the size of current ACAD, first octet returns the old length and
|
|
|
|
* followed by pointer to previous offset to ACAD in the PDU.
|
|
|
|
*/
|
|
|
|
hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = 0U;
|
2021-08-25 20:38:10 +05:30
|
|
|
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
|
|
|
|
ULL_ADV_PDU_HDR_FIELD_ACAD, 0U,
|
|
|
|
&hdr_data);
|
|
|
|
LL_ASSERT(!err);
|
|
|
|
|
|
|
|
/* Dev assert if ACAD empty */
|
2021-08-27 11:10:22 +05:30
|
|
|
LL_ASSERT(hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET]);
|
2021-08-25 20:38:10 +05:30
|
|
|
|
|
|
|
/* Get the pointer, prev content and size of current ACAD */
|
|
|
|
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
|
|
|
|
ULL_ADV_PDU_HDR_FIELD_ACAD, 0U,
|
|
|
|
&hdr_data);
|
|
|
|
LL_ASSERT(!err);
|
|
|
|
|
|
|
|
/* Find the Channel Map Update Indication */
|
2021-08-27 11:10:22 +05:30
|
|
|
acad_len = hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET];
|
2021-08-25 20:38:10 +05:30
|
|
|
len = acad_len;
|
2021-08-27 11:10:22 +05:30
|
|
|
(void)memcpy(&acad, &hdr_data[ULL_ADV_HDR_DATA_ACAD_PTR_OFFSET],
|
|
|
|
sizeof(acad));
|
2021-08-25 20:38:10 +05:30
|
|
|
ad = acad;
|
|
|
|
do {
|
|
|
|
ad_len = ad[0];
|
|
|
|
if (ad_len && (ad[1] == BT_DATA_CHANNEL_MAP_UPDATE_IND)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ad_len += 1U;
|
|
|
|
|
|
|
|
LL_ASSERT(ad_len < len);
|
|
|
|
|
|
|
|
ad += ad_len;
|
|
|
|
len -= ad_len;
|
|
|
|
} while (len);
|
|
|
|
|
|
|
|
/* Remove Channel Map Update Indication by moving other AD types that
|
|
|
|
* are after it.
|
|
|
|
*/
|
|
|
|
ad_len += 1U;
|
|
|
|
others = ad + ad_len;
|
|
|
|
acad_len -= ad_len;
|
|
|
|
others_len = acad_len - (ad - acad);
|
|
|
|
(void)memmove(ad, others, others_len);
|
|
|
|
|
|
|
|
/* Adjust the next PDU for ACAD length, this is done by using the next
|
|
|
|
* PDU to copy ACAD into same next PDU.
|
|
|
|
*/
|
2021-08-27 11:10:22 +05:30
|
|
|
hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = acad_len;
|
2021-08-25 20:38:10 +05:30
|
|
|
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu, pdu,
|
|
|
|
ULL_ADV_PDU_HDR_FIELD_ACAD, 0U,
|
|
|
|
&hdr_data);
|
|
|
|
LL_ASSERT(!err);
|
|
|
|
|
|
|
|
lll_adv_sync_data_enqueue(lll_sync, ter_idx);
|
|
|
|
}
|
|
|
|
|
2021-06-21 13:55:14 +05:30
|
|
|
void ull_adv_sync_info_fill(struct ll_adv_sync_set *sync,
|
|
|
|
struct pdu_adv_sync_info *si)
|
|
|
|
{
|
|
|
|
struct lll_adv_sync *lll_sync;
|
|
|
|
|
|
|
|
/* NOTE: sync offset and offset unit filled by secondary prepare.
|
|
|
|
*
|
|
|
|
* If sync_info is part of ADV PDU the offs_adjust field
|
|
|
|
* is always set to 0.
|
|
|
|
*/
|
2021-09-23 22:29:40 +05:30
|
|
|
si->offs_units = OFFS_UNIT_VALUE_30_US;
|
2021-06-21 13:55:14 +05:30
|
|
|
si->offs_adjust = 0U;
|
|
|
|
si->offs = 0U;
|
|
|
|
|
2021-08-25 20:38:10 +05:30
|
|
|
/* Fill the interval, access address and CRC init */
|
2021-06-21 13:55:14 +05:30
|
|
|
si->interval = sys_cpu_to_le16(sync->interval);
|
|
|
|
lll_sync = &sync->lll;
|
|
|
|
memcpy(&si->aa, lll_sync->access_addr, sizeof(si->aa));
|
|
|
|
memcpy(si->crc_init, lll_sync->crc_init, sizeof(si->crc_init));
|
|
|
|
|
|
|
|
/* NOTE: Filled by secondary prepare */
|
|
|
|
si->evt_cntr = 0U;
|
|
|
|
}
|
|
|
|
|
2020-02-12 08:55:57 +05:30
|
|
|
void ull_adv_sync_offset_get(struct ll_adv_set *adv)
|
|
|
|
{
|
|
|
|
static memq_link_t link;
|
|
|
|
static struct mayfly mfy = {0, 0, &link, NULL, mfy_sync_offset_get};
|
|
|
|
uint32_t ret;
|
|
|
|
|
|
|
|
mfy.param = adv;
|
|
|
|
ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1,
|
|
|
|
&mfy);
|
|
|
|
LL_ASSERT(!ret);
|
|
|
|
}
|
|
|
|
|
2021-03-01 16:00:53 +01:00
|
|
|
uint8_t ull_adv_sync_pdu_alloc(struct ll_adv_set *adv,
|
2021-07-14 07:47:32 +02:00
|
|
|
enum ull_adv_pdu_extra_data_flag extra_data_flag,
|
|
|
|
struct pdu_adv **ter_pdu_prev, struct pdu_adv **ter_pdu_new,
|
|
|
|
void **extra_data_prev, void **extra_data_new, uint8_t *ter_idx)
|
2021-02-16 15:39:13 +05:30
|
|
|
{
|
|
|
|
struct pdu_adv *pdu_prev, *pdu_new;
|
|
|
|
struct lll_adv_sync *lll_sync;
|
2021-03-01 16:00:53 +01:00
|
|
|
void *ed_prev;
|
|
|
|
#if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY)
|
|
|
|
void *ed_new;
|
|
|
|
#endif
|
2021-02-16 15:39:13 +05:30
|
|
|
|
|
|
|
lll_sync = adv->lll.sync;
|
|
|
|
if (!lll_sync) {
|
|
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get reference to previous periodic advertising PDU data */
|
2021-03-01 16:00:53 +01:00
|
|
|
pdu_prev = lll_adv_sync_data_peek(lll_sync, &ed_prev);
|
2021-02-16 15:39:13 +05:30
|
|
|
|
2021-02-24 13:57:41 +05:30
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
2021-02-16 15:39:13 +05:30
|
|
|
/* Get reference to new periodic advertising PDU data buffer */
|
2021-07-14 07:47:32 +02:00
|
|
|
if (extra_data_flag == ULL_ADV_PDU_EXTRA_DATA_ALLOC_ALWAYS ||
|
|
|
|
(extra_data_flag == ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST && ed_prev)) {
|
2021-02-16 15:39:13 +05:30
|
|
|
/* If there was an extra data in past PDU data or it is required
|
|
|
|
* by the hdr_add_fields then allocate memmory for it.
|
|
|
|
*/
|
2021-03-01 16:00:53 +01:00
|
|
|
pdu_new = lll_adv_sync_data_alloc(lll_sync, &ed_new,
|
2021-02-16 15:39:13 +05:30
|
|
|
ter_idx);
|
|
|
|
if (!pdu_new) {
|
|
|
|
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-01 16:00:53 +01:00
|
|
|
ed_new = NULL;
|
2021-02-16 15:39:13 +05:30
|
|
|
#else
|
|
|
|
{
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
pdu_new = lll_adv_sync_data_alloc(lll_sync, NULL, ter_idx);
|
|
|
|
if (!pdu_new) {
|
|
|
|
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-01 16:00:53 +01:00
|
|
|
#if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY)
|
|
|
|
if (extra_data_prev) {
|
|
|
|
*extra_data_prev = ed_prev;
|
|
|
|
}
|
|
|
|
if (extra_data_new) {
|
|
|
|
*extra_data_new = ed_new;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY */
|
|
|
|
|
|
|
|
*ter_pdu_prev = pdu_prev;
|
|
|
|
*ter_pdu_new = pdu_new;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* @brief Set or clear fields in extended advertising header and store
|
|
|
|
* extra_data if requested.
|
|
|
|
*
|
2021-07-15 07:57:04 +02:00
|
|
|
* @param[in] lll_sync Reference to periodic advertising sync.
|
|
|
|
* @param[in] ter_pdu_prev Pointer to previous PDU.
|
|
|
|
* @param[in] ter_pdu_ Pointer to PDU to fill fileds.
|
2021-03-01 16:00:53 +01:00
|
|
|
* @param[in] hdr_add_fields Flag with information which fields add.
|
|
|
|
* @param[in] hdr_rem_fields Flag with information which fields remove.
|
2021-07-15 07:57:04 +02:00
|
|
|
* @param[in] hdr_data Pointer to data to be added to header. Content
|
|
|
|
* depends on the value of @p hdr_add_fields.
|
2021-03-01 16:00:53 +01:00
|
|
|
*
|
|
|
|
* @Note
|
2021-07-15 07:57:04 +02:00
|
|
|
* @p hdr_data content depends on the flag provided by @p hdr_add_fields:
|
2021-03-01 16:00:53 +01:00
|
|
|
* - ULL_ADV_PDU_HDR_FIELD_CTE_INFO:
|
2021-07-15 07:57:04 +02:00
|
|
|
* # @p hdr_data points to single byte with CTEInfo field
|
2021-03-01 16:00:53 +01:00
|
|
|
* - ULL_ADV_PDU_HDR_FIELD_AD_DATA:
|
2021-07-15 07:57:04 +02:00
|
|
|
* # @p hdr_data points to memory where first byte
|
2021-03-01 16:00:53 +01:00
|
|
|
* is size of advertising data, following byte is a pointer to actual
|
|
|
|
* advertising data.
|
2021-07-15 07:57:04 +02:00
|
|
|
* - ULL_ADV_PDU_HDR_FIELD_AUX_PTR:
|
|
|
|
* # @p hdr_data parameter is not used
|
|
|
|
* - ULL_ADV_PDU_HDR_FIELD_ACAD:
|
|
|
|
* # @p hdr_data points to memory where first byte is size of ACAD, second
|
|
|
|
* byte is used to return offset to ACAD field.
|
2021-08-27 11:10:22 +05:30
|
|
|
* # @p hdr_data memory returns previous ACAD length back in the first byte
|
|
|
|
* and offset to new ACAD in the next PDU.
|
2021-03-01 16:00:53 +01:00
|
|
|
*
|
|
|
|
* @return Zero in case of success, other value in case of failure.
|
|
|
|
*/
|
|
|
|
uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync,
|
|
|
|
struct pdu_adv *ter_pdu_prev,
|
|
|
|
struct pdu_adv *ter_pdu,
|
|
|
|
uint16_t hdr_add_fields,
|
|
|
|
uint16_t hdr_rem_fields,
|
2021-07-15 07:57:04 +02:00
|
|
|
void *hdr_data)
|
2021-01-22 05:38:47 -08:00
|
|
|
{
|
|
|
|
struct pdu_adv_com_ext_adv *ter_com_hdr, *ter_com_hdr_prev;
|
2021-06-18 07:19:33 +02:00
|
|
|
struct pdu_adv_ext_hdr ter_hdr = { 0 }, ter_hdr_prev = { 0 };
|
2021-01-22 05:38:47 -08:00
|
|
|
uint8_t *ter_dptr, *ter_dptr_prev;
|
2021-01-04 13:05:09 +05:30
|
|
|
uint8_t acad_len_prev;
|
2021-02-23 19:18:23 +05:30
|
|
|
uint8_t ter_len_prev;
|
|
|
|
uint8_t hdr_buf_len;
|
|
|
|
uint16_t ter_len;
|
2021-01-22 05:38:47 -08:00
|
|
|
uint8_t *ad_data;
|
2021-02-24 12:39:57 +05:30
|
|
|
uint8_t acad_len;
|
2021-02-24 13:57:41 +05:30
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
2021-01-22 05:38:47 -08:00
|
|
|
uint8_t cte_info;
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
uint8_t ad_len;
|
|
|
|
|
|
|
|
/* Get common pointers from reference to previous tertiary PDU data */
|
|
|
|
ter_com_hdr_prev = (void *)&ter_pdu_prev->adv_ext_ind;
|
2021-06-18 07:19:33 +02:00
|
|
|
if (ter_com_hdr_prev->ext_hdr_len != 0) {
|
|
|
|
ter_hdr_prev = ter_com_hdr_prev->ext_hdr;
|
2021-05-31 17:08:51 +05:30
|
|
|
}
|
2021-06-18 07:19:33 +02:00
|
|
|
ter_dptr_prev = ter_com_hdr_prev->ext_hdr.data;
|
2021-01-22 05:38:47 -08:00
|
|
|
|
|
|
|
/* Set common fields in reference to new tertiary PDU data buffer */
|
|
|
|
ter_pdu->type = ter_pdu_prev->type;
|
|
|
|
ter_pdu->rfu = 0U;
|
|
|
|
ter_pdu->chan_sel = 0U;
|
|
|
|
|
|
|
|
ter_pdu->tx_addr = ter_pdu_prev->tx_addr;
|
|
|
|
ter_pdu->rx_addr = ter_pdu_prev->rx_addr;
|
|
|
|
|
2021-06-18 07:19:33 +02:00
|
|
|
/* Get common pointers from current tertiary PDU data.
|
|
|
|
* It is possbile that the current tertiary is the same as
|
|
|
|
* previous one. It may happen if update periodic advertising
|
|
|
|
* chain in place.
|
|
|
|
*/
|
2021-01-22 05:38:47 -08:00
|
|
|
ter_com_hdr = (void *)&ter_pdu->adv_ext_ind;
|
|
|
|
ter_com_hdr->adv_mode = ter_com_hdr_prev->adv_mode;
|
2021-06-18 07:19:33 +02:00
|
|
|
ter_dptr = ter_com_hdr->ext_hdr.data;
|
2021-01-22 05:38:47 -08:00
|
|
|
|
|
|
|
/* No AdvA in AUX_SYNC_IND */
|
|
|
|
/* No TargetA in AUX_SYNC_IND */
|
|
|
|
|
2021-02-24 13:57:41 +05:30
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
2021-01-22 05:38:47 -08:00
|
|
|
/* If requested add or update CTEInfo */
|
|
|
|
if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
|
2021-06-18 07:19:33 +02:00
|
|
|
ter_hdr.cte_info = 1;
|
2021-07-15 07:57:04 +02:00
|
|
|
cte_info = *(uint8_t *)hdr_data;
|
|
|
|
hdr_data = (uint8_t *)hdr_data + 1;
|
2021-01-22 05:38:47 -08:00
|
|
|
ter_dptr += sizeof(struct pdu_cte_info);
|
|
|
|
/* If CTEInfo exists in prev and is not requested to be removed */
|
|
|
|
} else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) &&
|
|
|
|
ter_hdr_prev.cte_info) {
|
2021-06-18 07:19:33 +02:00
|
|
|
ter_hdr.cte_info = 1;
|
2021-01-22 05:38:47 -08:00
|
|
|
ter_dptr += sizeof(struct pdu_cte_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If CTEInfo exists in prev PDU */
|
|
|
|
if (ter_hdr_prev.cte_info) {
|
|
|
|
ter_dptr_prev += sizeof(struct pdu_cte_info);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
|
2021-10-28 09:15:51 +05:30
|
|
|
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)) {
|
|
|
|
if (ter_hdr_prev.adi) {
|
|
|
|
ter_dptr_prev += sizeof(struct pdu_adv_adi);
|
|
|
|
}
|
|
|
|
ter_hdr.adi = 1U;
|
|
|
|
ter_dptr += sizeof(struct pdu_adv_adi);
|
|
|
|
}
|
2021-01-22 05:38:47 -08:00
|
|
|
|
|
|
|
/* AuxPtr - will be added if AUX_CHAIN_IND is required */
|
|
|
|
if ((hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) ||
|
|
|
|
(!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) &&
|
|
|
|
ter_hdr_prev.aux_ptr)) {
|
2021-06-18 07:19:33 +02:00
|
|
|
ter_hdr.aux_ptr = 1;
|
2021-01-22 05:38:47 -08:00
|
|
|
}
|
2021-06-18 07:19:33 +02:00
|
|
|
if (ter_hdr.aux_ptr) {
|
2021-01-22 05:38:47 -08:00
|
|
|
ter_dptr += sizeof(struct pdu_adv_aux_ptr);
|
|
|
|
}
|
|
|
|
if (ter_hdr_prev.aux_ptr) {
|
|
|
|
ter_dptr_prev += sizeof(struct pdu_adv_aux_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No SyncInfo in AUX_SYNC_IND */
|
|
|
|
|
|
|
|
/* Tx Power flag */
|
|
|
|
if (ter_hdr_prev.tx_pwr) {
|
|
|
|
ter_dptr_prev++;
|
|
|
|
|
2021-06-18 07:19:33 +02:00
|
|
|
ter_hdr.tx_pwr = 1;
|
2021-01-22 05:38:47 -08:00
|
|
|
ter_dptr++;
|
|
|
|
}
|
|
|
|
|
2021-01-04 13:05:09 +05:30
|
|
|
/* Calc previous ACAD len and update PDU len */
|
|
|
|
ter_len_prev = ter_dptr_prev - (uint8_t *)ter_com_hdr_prev;
|
2021-02-23 19:18:23 +05:30
|
|
|
hdr_buf_len = ter_com_hdr_prev->ext_hdr_len +
|
|
|
|
PDU_AC_EXT_HEADER_SIZE_MIN;
|
|
|
|
if (ter_len_prev <= hdr_buf_len) {
|
2021-06-18 07:19:33 +02:00
|
|
|
/* There are some data, except ACAD, in extended header if ter_len_prev
|
|
|
|
* equals to hdr_buf_len. There is ACAD if the size of ter_len_prev
|
|
|
|
* is smaller than hdr_buf_len.
|
|
|
|
*/
|
2021-02-23 19:18:23 +05:30
|
|
|
acad_len_prev = hdr_buf_len - ter_len_prev;
|
2021-01-04 13:05:09 +05:30
|
|
|
ter_len_prev += acad_len_prev;
|
|
|
|
ter_dptr_prev += acad_len_prev;
|
|
|
|
} else {
|
2021-06-18 07:19:33 +02:00
|
|
|
/* There are no data in extended header, all flags are zeros. */
|
2021-01-04 13:05:09 +05:30
|
|
|
acad_len_prev = 0;
|
|
|
|
/* NOTE: If no flags are set then extended header length will be
|
|
|
|
* zero. Under this condition the current ter_len_prev
|
|
|
|
* value will be greater than extended header length,
|
|
|
|
* hence set ter_len_prev to size of the length/mode
|
|
|
|
* field.
|
|
|
|
*/
|
2021-02-23 19:18:23 +05:30
|
|
|
ter_len_prev = PDU_AC_EXT_HEADER_SIZE_MIN;
|
2021-01-04 13:05:09 +05:30
|
|
|
ter_dptr_prev = (uint8_t *)ter_com_hdr_prev + ter_len_prev;
|
|
|
|
}
|
2021-01-22 05:38:47 -08:00
|
|
|
|
|
|
|
/* Did we parse beyond PDU length? */
|
|
|
|
if (ter_len_prev > ter_pdu_prev->len) {
|
|
|
|
/* we should not encounter invalid length */
|
|
|
|
return BT_HCI_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2021-02-24 12:39:57 +05:30
|
|
|
/* Add/Retain/Remove ACAD */
|
|
|
|
if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_ACAD) {
|
2021-07-15 07:57:04 +02:00
|
|
|
acad_len = *(uint8_t *)hdr_data;
|
2021-08-25 20:38:10 +05:30
|
|
|
/* return prev ACAD length */
|
|
|
|
*(uint8_t *)hdr_data = acad_len_prev;
|
2021-07-15 07:57:04 +02:00
|
|
|
hdr_data = (uint8_t *)hdr_data + 1;
|
2021-02-24 12:39:57 +05:30
|
|
|
/* return the pointer to ACAD offset */
|
2021-07-15 07:57:04 +02:00
|
|
|
memcpy(hdr_data, &ter_dptr, sizeof(ter_dptr));
|
|
|
|
hdr_data = (uint8_t *)hdr_data + sizeof(ter_dptr);
|
2021-02-24 12:39:57 +05:30
|
|
|
ter_dptr += acad_len;
|
|
|
|
} else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_ACAD)) {
|
|
|
|
acad_len = acad_len_prev;
|
|
|
|
ter_dptr += acad_len_prev;
|
|
|
|
} else {
|
|
|
|
acad_len = 0U;
|
|
|
|
}
|
|
|
|
|
2021-01-22 05:38:47 -08:00
|
|
|
/* Calc current tertiary PDU len */
|
|
|
|
ter_len = ull_adv_aux_hdr_len_calc(ter_com_hdr, &ter_dptr);
|
|
|
|
ull_adv_aux_hdr_len_fill(ter_com_hdr, ter_len);
|
|
|
|
|
|
|
|
/* Get Adv data from function parameters */
|
|
|
|
if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_AD_DATA) {
|
2021-07-15 07:57:04 +02:00
|
|
|
ad_data = hdr_data;
|
2021-01-22 05:38:47 -08:00
|
|
|
ad_len = *ad_data;
|
|
|
|
++ad_data;
|
|
|
|
|
|
|
|
ad_data = (void *)sys_get_le32(ad_data);
|
|
|
|
} else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_AD_DATA)) {
|
|
|
|
ad_len = ter_pdu_prev->len - ter_len_prev;
|
|
|
|
ad_data = ter_dptr_prev;
|
|
|
|
} else {
|
|
|
|
ad_len = 0;
|
|
|
|
ad_data = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add AD len to tertiary PDU length */
|
|
|
|
ter_len += ad_len;
|
|
|
|
|
|
|
|
/* Check AdvData overflow */
|
|
|
|
if (ter_len > PDU_AC_PAYLOAD_SIZE_MAX) {
|
|
|
|
return BT_HCI_ERR_PACKET_TOO_LONG;
|
|
|
|
}
|
|
|
|
|
2021-02-24 12:39:57 +05:30
|
|
|
/* set the tertiary PDU len */
|
2021-01-22 05:38:47 -08:00
|
|
|
ter_pdu->len = ter_len;
|
|
|
|
|
|
|
|
/* Start filling tertiary PDU payload based on flags from here
|
|
|
|
* ==============================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Fill AdvData in tertiary PDU */
|
2021-09-23 21:42:28 +05:30
|
|
|
(void)memmove(ter_dptr, ad_data, ad_len);
|
2021-01-22 05:38:47 -08:00
|
|
|
|
2021-05-31 17:08:17 +05:30
|
|
|
/* Early exit if no flags set */
|
|
|
|
if (!ter_com_hdr->ext_hdr_len) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-02-24 12:39:57 +05:30
|
|
|
/* Retain ACAD in tertiary PDU */
|
2021-01-04 13:05:09 +05:30
|
|
|
ter_dptr_prev -= acad_len_prev;
|
2021-02-24 12:39:57 +05:30
|
|
|
if (acad_len) {
|
|
|
|
ter_dptr -= acad_len;
|
2021-09-23 21:42:28 +05:30
|
|
|
(void)memmove(ter_dptr, ter_dptr_prev, acad_len_prev);
|
2021-02-24 12:39:57 +05:30
|
|
|
}
|
2021-01-22 05:38:47 -08:00
|
|
|
|
|
|
|
/* Tx Power */
|
2021-06-18 07:19:33 +02:00
|
|
|
if (ter_hdr.tx_pwr) {
|
2021-01-22 05:38:47 -08:00
|
|
|
*--ter_dptr = *--ter_dptr_prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No SyncInfo in AUX_SYNC_IND */
|
|
|
|
|
|
|
|
/* AuxPtr */
|
2021-06-18 07:19:33 +02:00
|
|
|
if (ter_hdr.aux_ptr) {
|
2021-01-22 05:38:47 -08:00
|
|
|
/* ToDo Update setup of aux_ptr - check documentation */
|
|
|
|
if (ter_hdr_prev.aux_ptr) {
|
|
|
|
ter_dptr_prev -= sizeof(struct pdu_adv_aux_ptr);
|
|
|
|
ter_dptr -= sizeof(struct pdu_adv_aux_ptr);
|
2021-09-23 21:42:28 +05:30
|
|
|
(void)memmove(ter_dptr, ter_dptr_prev,
|
|
|
|
sizeof(struct pdu_adv_aux_ptr));
|
2021-01-22 05:38:47 -08:00
|
|
|
} else {
|
2021-10-12 15:23:56 +05:30
|
|
|
ter_dptr -= sizeof(struct pdu_adv_aux_ptr);
|
|
|
|
ull_adv_aux_ptr_fill((void *)ter_dptr, 0U,
|
|
|
|
lll_sync->adv->phy_s);
|
2021-01-22 05:38:47 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-28 09:15:51 +05:30
|
|
|
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)) {
|
|
|
|
struct pdu_adv_adi *adi;
|
|
|
|
struct ll_adv_set *adv;
|
|
|
|
uint16_t did;
|
|
|
|
|
|
|
|
if (ter_hdr_prev.adi) {
|
|
|
|
ter_dptr_prev -= sizeof(struct pdu_adv_adi);
|
|
|
|
}
|
|
|
|
|
|
|
|
ter_dptr -= sizeof(struct pdu_adv_adi);
|
|
|
|
adi = (void *)ter_dptr;
|
|
|
|
|
|
|
|
adv = HDR_LLL2ULL(lll_sync->adv);
|
|
|
|
|
|
|
|
adi->sid = adv->sid;
|
|
|
|
|
|
|
|
/* The DID for a specific SID shall be unique.
|
|
|
|
*/
|
|
|
|
did = ull_adv_aux_did_next_unique_get(adv->sid);
|
|
|
|
adi->did = sys_cpu_to_le16(did);
|
|
|
|
}
|
2021-01-22 05:38:47 -08:00
|
|
|
|
2021-02-24 13:57:41 +05:30
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
2021-06-18 07:19:33 +02:00
|
|
|
if (ter_hdr.cte_info) {
|
2021-01-22 05:38:47 -08:00
|
|
|
if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
|
|
|
|
*--ter_dptr = cte_info;
|
|
|
|
} else {
|
|
|
|
*--ter_dptr = *--ter_dptr_prev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
|
|
|
|
/* No TargetA in AUX_SYNC_IND */
|
|
|
|
/* No AdvA in AUX_SYNC_IND */
|
|
|
|
|
2021-06-18 07:19:33 +02:00
|
|
|
if (ter_com_hdr->ext_hdr_len != 0) {
|
|
|
|
ter_com_hdr->ext_hdr = ter_hdr;
|
|
|
|
}
|
|
|
|
|
2021-01-22 05:38:47 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-25 12:57:32 +02:00
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
|
|
|
/* @brief Set or clear fields in extended advertising header and store
|
|
|
|
* extra_data if requested.
|
|
|
|
*
|
|
|
|
* @param[in] extra_data_prev Pointer to previous content of extra_data.
|
|
|
|
* @param[in] hdr_add_fields Flag with information which fields add.
|
|
|
|
* @param[in] hdr_rem_fields Flag with information which fields remove.
|
|
|
|
* @param[in] data Pointer to data to be stored in extra_data.
|
|
|
|
* Content depends on the data depends on
|
|
|
|
* @p hdr_add_fields.
|
|
|
|
*
|
|
|
|
* @Note
|
|
|
|
* @p data depends on the flag provided by @p hdr_add_fields.
|
|
|
|
* Information about content of value may be found in description of
|
|
|
|
* @ref ull_adv_sync_pdu_set_clear.
|
|
|
|
*
|
|
|
|
* @return Zero in case of success, other value in case of failure.
|
|
|
|
*/
|
|
|
|
void ull_adv_sync_extra_data_set_clear(void *extra_data_prev,
|
|
|
|
void *extra_data_new,
|
|
|
|
uint16_t hdr_add_fields,
|
|
|
|
uint16_t hdr_rem_fields,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
/* Currently only CTE enable requires extra_data. Due to that fact
|
|
|
|
* CTE additional data are just copied to extra_data memory.
|
|
|
|
*/
|
|
|
|
if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
|
|
|
|
memcpy(extra_data_new, data, sizeof(struct lll_df_adv_cfg));
|
|
|
|
} else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) ||
|
|
|
|
extra_data_prev) {
|
2021-09-23 21:42:28 +05:30
|
|
|
(void)memmove(extra_data_new, extra_data_prev,
|
|
|
|
sizeof(struct lll_df_adv_cfg));
|
2021-06-25 12:57:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
|
|
|
|
static int init_reset(void)
|
|
|
|
{
|
|
|
|
/* Initialize adv sync pool. */
|
|
|
|
mem_init(ll_adv_sync_pool, sizeof(struct ll_adv_sync_set),
|
|
|
|
sizeof(ll_adv_sync_pool) / sizeof(struct ll_adv_sync_set),
|
|
|
|
&adv_sync_free);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct ll_adv_sync_set *sync_acquire(void)
|
|
|
|
{
|
|
|
|
return mem_acquire(&adv_sync_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sync_release(struct ll_adv_sync_set *sync)
|
|
|
|
{
|
|
|
|
mem_release(sync, &adv_sync_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t sync_handle_get(struct ll_adv_sync_set *sync)
|
|
|
|
{
|
|
|
|
return mem_index_get(sync, ll_adv_sync_pool,
|
|
|
|
sizeof(struct ll_adv_sync_set));
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t sync_stop(struct ll_adv_sync_set *sync)
|
|
|
|
{
|
|
|
|
uint8_t sync_handle;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
sync_handle = sync_handle_get(sync);
|
|
|
|
|
|
|
|
err = ull_ticker_stop_with_mark(TICKER_ID_ADV_SYNC_BASE + sync_handle,
|
|
|
|
sync, &sync->lll);
|
|
|
|
LL_ASSERT(err == 0 || err == -EALREADY);
|
|
|
|
if (err) {
|
|
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint8_t sync_remove(struct ll_adv_sync_set *sync,
|
|
|
|
struct ll_adv_set *adv, uint8_t enable)
|
|
|
|
{
|
|
|
|
uint8_t pri_idx;
|
|
|
|
uint8_t err;
|
|
|
|
|
|
|
|
/* Remove sync_info from auxiliary PDU */
|
|
|
|
err = ull_adv_aux_hdr_set_clear(adv, 0,
|
|
|
|
ULL_ADV_PDU_HDR_FIELD_SYNC_INFO,
|
|
|
|
NULL, NULL, &pri_idx);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
lll_adv_data_enqueue(&adv->lll, pri_idx);
|
|
|
|
|
|
|
|
if (sync->is_started) {
|
|
|
|
/* TODO: we removed sync info, but if sync_stop() fails, what do
|
|
|
|
* we do?
|
|
|
|
*/
|
|
|
|
err = sync_stop(sync);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
sync->is_started = 0U;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!enable) {
|
|
|
|
sync->is_enabled = 0U;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0U;
|
|
|
|
}
|
|
|
|
|
2021-08-25 20:38:10 +05:30
|
|
|
static uint8_t sync_chm_update(uint8_t handle)
|
|
|
|
{
|
2021-08-27 11:10:22 +05:30
|
|
|
uint8_t hdr_data[ULL_ADV_HDR_DATA_LEN_SIZE +
|
|
|
|
ULL_ADV_HDR_DATA_ACAD_PTR_SIZE];
|
2021-08-25 20:38:10 +05:30
|
|
|
struct pdu_adv_sync_chm_upd_ind *chm_upd_ind;
|
|
|
|
struct lll_adv_sync *lll_sync;
|
|
|
|
struct pdu_adv *pdu_prev;
|
|
|
|
struct ll_adv_set *adv;
|
|
|
|
uint8_t acad_len_prev;
|
|
|
|
struct pdu_adv *pdu;
|
|
|
|
uint16_t instant;
|
|
|
|
uint8_t chm_last;
|
|
|
|
uint8_t ter_idx;
|
|
|
|
uint8_t *acad;
|
|
|
|
uint8_t err;
|
|
|
|
|
|
|
|
/* Check for valid advertising instance */
|
|
|
|
adv = ull_adv_is_created_get(handle);
|
|
|
|
if (!adv) {
|
|
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for valid periodic advertising */
|
|
|
|
lll_sync = adv->lll.sync;
|
|
|
|
if (!lll_sync) {
|
|
|
|
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fail if already in progress */
|
|
|
|
if (lll_sync->chm_last != lll_sync->chm_first) {
|
|
|
|
return BT_HCI_ERR_CMD_DISALLOWED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate next Sync PDU */
|
|
|
|
err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
|
|
|
|
&pdu_prev, &pdu, NULL, NULL, &ter_idx);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-08-27 11:10:22 +05:30
|
|
|
/* Try to allocate ACAD for channel map update indication, previous
|
|
|
|
* ACAD length with be returned back.
|
|
|
|
*/
|
|
|
|
hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = sizeof(*chm_upd_ind) + 2U;
|
2021-08-25 20:38:10 +05:30
|
|
|
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
|
|
|
|
ULL_ADV_PDU_HDR_FIELD_ACAD, 0U,
|
|
|
|
&hdr_data);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-08-27 11:10:22 +05:30
|
|
|
/* Check if there are other ACAD data previously */
|
|
|
|
acad_len_prev = hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET];
|
2021-08-25 20:38:10 +05:30
|
|
|
if (acad_len_prev) {
|
2021-08-27 11:10:22 +05:30
|
|
|
/* Append to end of other ACAD already present */
|
|
|
|
hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = acad_len_prev +
|
|
|
|
sizeof(*chm_upd_ind) +
|
|
|
|
2U;
|
2021-08-25 20:38:10 +05:30
|
|
|
|
|
|
|
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
|
|
|
|
ULL_ADV_PDU_HDR_FIELD_ACAD, 0U,
|
|
|
|
&hdr_data);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Populate the AD data length and opcode */
|
2021-08-27 11:10:22 +05:30
|
|
|
(void)memcpy(&acad, &hdr_data[ULL_ADV_HDR_DATA_ACAD_PTR_OFFSET],
|
|
|
|
sizeof(acad));
|
2021-08-25 20:38:10 +05:30
|
|
|
acad += acad_len_prev;
|
|
|
|
acad[0] = sizeof(*chm_upd_ind) + 1U;
|
|
|
|
acad[1] = BT_DATA_CHANNEL_MAP_UPDATE_IND;
|
|
|
|
|
|
|
|
/* Populate the Channel Map Indication structure */
|
|
|
|
chm_upd_ind = (void *)&acad[2];
|
|
|
|
(void)ull_chan_map_get(chm_upd_ind->chm);
|
|
|
|
instant = lll_sync->event_counter + 6U;
|
|
|
|
chm_upd_ind->instant = sys_cpu_to_le16(instant);
|
|
|
|
|
|
|
|
/* Update the LLL to reflect the Channel Map and Instant to use */
|
|
|
|
chm_last = lll_sync->chm_last + 1;
|
|
|
|
if (chm_last == DOUBLE_BUFFER_SIZE) {
|
|
|
|
chm_last = 0U;
|
|
|
|
}
|
|
|
|
lll_sync->chm[chm_last].data_chan_count =
|
|
|
|
ull_chan_map_get(lll_sync->chm[chm_last].data_chan_map);
|
|
|
|
lll_sync->chm_instant = instant;
|
|
|
|
|
|
|
|
/* Commit the Channel Map Indication in the ACAD field of Periodic
|
|
|
|
* Advertising
|
|
|
|
*/
|
|
|
|
lll_adv_sync_data_enqueue(lll_sync, ter_idx);
|
|
|
|
|
|
|
|
/* Initiate the Channel Map Indication */
|
|
|
|
lll_sync->chm_last = chm_last;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-10-25 21:38:36 +05:30
|
|
|
static uint32_t sync_time_get(struct ll_adv_sync_set *sync,
|
2021-07-16 06:47:15 +05:30
|
|
|
struct pdu_adv *pdu)
|
|
|
|
{
|
|
|
|
struct lll_adv_sync *lll_sync;
|
|
|
|
struct lll_adv *lll;
|
|
|
|
uint32_t time_us;
|
|
|
|
|
2021-10-25 21:38:36 +05:30
|
|
|
/* NOTE: 16-bit values are sufficient for minimum radio event time
|
|
|
|
* reservation, 32-bit are used here so that reservations for
|
|
|
|
* whole back-to-back chaining of PDUs can be accomodated where
|
|
|
|
* the required microseconds could overflow 16-bits, example,
|
|
|
|
* back-to-back chained Coded PHY PDUs.
|
|
|
|
*/
|
|
|
|
|
2021-07-16 06:47:15 +05:30
|
|
|
lll_sync = &sync->lll;
|
2021-08-18 11:41:13 +05:30
|
|
|
lll = lll_sync->adv;
|
|
|
|
time_us = PDU_AC_US(pdu->len, lll->phy_s, lll->phy_flags) +
|
|
|
|
EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
|
2021-07-16 06:47:15 +05:30
|
|
|
|
|
|
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
|
|
|
struct ll_adv_set *adv = HDR_LLL2ULL(lll);
|
|
|
|
struct lll_df_adv_cfg *df_cfg = adv->df_cfg;
|
|
|
|
|
|
|
|
if (df_cfg && df_cfg->is_enabled) {
|
|
|
|
time_us += CTE_LEN_US(df_cfg->cte_length);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
|
|
|
|
|
|
|
return time_us;
|
|
|
|
}
|
|
|
|
|
2020-02-12 08:55:57 +05:30
|
|
|
static void mfy_sync_offset_get(void *param)
|
|
|
|
{
|
|
|
|
struct ll_adv_set *adv = param;
|
2020-07-17 15:27:42 +05:30
|
|
|
struct lll_adv_sync *lll_sync;
|
2020-02-12 08:55:57 +05:30
|
|
|
struct ll_adv_sync_set *sync;
|
2020-07-17 15:27:42 +05:30
|
|
|
struct pdu_adv_sync_info *si;
|
2020-02-12 08:55:57 +05:30
|
|
|
uint32_t ticks_to_expire;
|
|
|
|
uint32_t ticks_current;
|
|
|
|
struct pdu_adv *pdu;
|
2021-08-25 20:38:10 +05:30
|
|
|
uint8_t chm_first;
|
2020-02-12 08:55:57 +05:30
|
|
|
uint8_t ticker_id;
|
2021-03-15 16:13:22 +05:30
|
|
|
uint16_t lazy;
|
2020-02-12 08:55:57 +05:30
|
|
|
uint8_t retry;
|
|
|
|
uint8_t id;
|
|
|
|
|
2020-07-17 15:27:42 +05:30
|
|
|
lll_sync = adv->lll.sync;
|
2021-04-05 12:56:51 +05:30
|
|
|
sync = HDR_LLL2ULL(lll_sync);
|
2020-02-12 08:55:57 +05:30
|
|
|
ticker_id = TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync);
|
|
|
|
|
|
|
|
id = TICKER_NULL;
|
|
|
|
ticks_to_expire = 0U;
|
|
|
|
ticks_current = 0U;
|
|
|
|
retry = 4U;
|
|
|
|
do {
|
2020-07-16 12:34:23 +05:30
|
|
|
uint32_t volatile ret_cb;
|
2020-02-12 08:55:57 +05:30
|
|
|
uint32_t ticks_previous;
|
|
|
|
uint32_t ret;
|
2021-05-19 07:03:27 +05:30
|
|
|
bool success;
|
2020-02-12 08:55:57 +05:30
|
|
|
|
|
|
|
ticks_previous = ticks_current;
|
|
|
|
|
2020-07-16 12:34:23 +05:30
|
|
|
ret_cb = TICKER_STATUS_BUSY;
|
2021-03-15 16:13:22 +05:30
|
|
|
ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR,
|
|
|
|
TICKER_USER_ID_ULL_LOW,
|
|
|
|
&id, &ticks_current,
|
|
|
|
&ticks_to_expire, &lazy,
|
2021-05-21 09:36:54 +02:00
|
|
|
NULL, NULL,
|
2021-03-15 16:13:22 +05:30
|
|
|
ticker_op_cb, (void *)&ret_cb);
|
2020-02-12 08:55:57 +05:30
|
|
|
if (ret == TICKER_STATUS_BUSY) {
|
|
|
|
while (ret_cb == TICKER_STATUS_BUSY) {
|
|
|
|
ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
|
|
|
|
TICKER_USER_ID_ULL_LOW);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-19 07:03:27 +05:30
|
|
|
success = (ret_cb == TICKER_STATUS_SUCCESS);
|
|
|
|
LL_ASSERT(success);
|
2020-02-12 08:55:57 +05:30
|
|
|
|
|
|
|
LL_ASSERT((ticks_current == ticks_previous) || retry--);
|
|
|
|
|
|
|
|
LL_ASSERT(id != TICKER_NULL);
|
|
|
|
} while (id != ticker_id);
|
|
|
|
|
|
|
|
/* NOTE: as remainder not used in scheduling primary PDU
|
|
|
|
* packet timer starts transmission after 1 tick hence the +1.
|
|
|
|
*/
|
2020-07-17 15:27:42 +05:30
|
|
|
lll_sync->ticks_offset = ticks_to_expire + 1;
|
2020-02-12 08:55:57 +05:30
|
|
|
|
2021-01-18 19:10:46 +05:30
|
|
|
pdu = lll_adv_aux_data_latest_peek(adv->lll.aux);
|
2020-07-17 15:27:42 +05:30
|
|
|
si = sync_info_get(pdu);
|
|
|
|
sync_info_offset_fill(si, ticks_to_expire, 0);
|
2021-03-15 16:13:22 +05:30
|
|
|
si->evt_cntr = lll_sync->event_counter + lll_sync->latency_prepare +
|
|
|
|
lazy;
|
2021-08-25 20:38:10 +05:30
|
|
|
|
|
|
|
/* Fill the correct channel map to use if at or past the instant */
|
|
|
|
if (lll_sync->chm_first != lll_sync->chm_last) {
|
|
|
|
uint16_t instant_latency;
|
|
|
|
|
|
|
|
instant_latency = (si->evt_cntr - lll_sync->chm_instant) &
|
2021-08-27 15:41:50 +05:30
|
|
|
EVENT_INSTANT_MAX;
|
|
|
|
if (instant_latency <= EVENT_INSTANT_LATENCY_MAX) {
|
2021-08-25 20:38:10 +05:30
|
|
|
chm_first = lll_sync->chm_last;
|
|
|
|
} else {
|
|
|
|
chm_first = lll_sync->chm_first;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
chm_first = lll_sync->chm_first;
|
|
|
|
}
|
|
|
|
(void)memcpy(si->sca_chm, lll_sync->chm[chm_first].data_chan_map,
|
|
|
|
sizeof(si->sca_chm));
|
|
|
|
si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &=
|
|
|
|
~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK;
|
|
|
|
si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] |=
|
|
|
|
((lll_clock_sca_local_get() <<
|
|
|
|
PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS) &
|
|
|
|
PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK);
|
2020-07-17 15:27:42 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu)
|
|
|
|
{
|
|
|
|
struct pdu_adv_com_ext_adv *p;
|
2020-11-09 15:02:38 +01:00
|
|
|
struct pdu_adv_ext_hdr *h;
|
2020-07-17 15:27:42 +05:30
|
|
|
uint8_t *ptr;
|
|
|
|
|
|
|
|
p = (void *)&pdu->adv_ext_ind;
|
2020-11-09 14:53:54 +01:00
|
|
|
h = (void *)p->ext_hdr_adv_data;
|
2020-11-09 15:22:49 +01:00
|
|
|
ptr = h->data;
|
2020-07-17 15:27:42 +05:30
|
|
|
|
2021-09-03 07:07:08 +05:30
|
|
|
/* traverse through adv_addr, if present */
|
2020-07-17 15:27:42 +05:30
|
|
|
if (h->adv_addr) {
|
|
|
|
ptr += BDADDR_SIZE;
|
|
|
|
}
|
|
|
|
|
2021-09-03 07:07:08 +05:30
|
|
|
/* traverse through tgt_addr, if present */
|
|
|
|
if (h->tgt_addr) {
|
|
|
|
ptr += BDADDR_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No CTEInfo flag in primary and secondary channel PDU */
|
|
|
|
|
|
|
|
/* traverse through adi, if present */
|
2020-07-17 15:27:42 +05:30
|
|
|
if (h->adi) {
|
|
|
|
ptr += sizeof(struct pdu_adv_adi);
|
|
|
|
}
|
|
|
|
|
2021-09-03 07:07:08 +05:30
|
|
|
/* traverse through aux ptr, if present */
|
2020-07-17 15:27:42 +05:30
|
|
|
if (h->aux_ptr) {
|
|
|
|
ptr += sizeof(struct pdu_adv_aux_ptr);
|
|
|
|
}
|
|
|
|
|
2021-09-03 07:07:08 +05:30
|
|
|
/* return pointer offset to sync_info */
|
2020-07-17 15:27:42 +05:30
|
|
|
return (void *)ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sync_info_offset_fill(struct pdu_adv_sync_info *si,
|
|
|
|
uint32_t ticks_offset,
|
|
|
|
uint32_t start_us)
|
|
|
|
{
|
|
|
|
uint32_t offs;
|
|
|
|
|
|
|
|
offs = HAL_TICKER_TICKS_TO_US(ticks_offset) - start_us;
|
2020-09-30 13:40:13 +05:30
|
|
|
offs = offs / OFFS_UNIT_30_US;
|
2021-10-12 21:53:17 +05:30
|
|
|
if (!!(offs >> OFFS_UNIT_BITS)) {
|
2020-09-30 13:40:13 +05:30
|
|
|
si->offs = offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US);
|
2021-09-23 22:29:40 +05:30
|
|
|
si->offs_units = OFFS_UNIT_VALUE_300_US;
|
2020-07-17 15:27:42 +05:30
|
|
|
} else {
|
2020-09-30 13:40:13 +05:30
|
|
|
si->offs = offs;
|
2021-09-23 22:29:40 +05:30
|
|
|
si->offs_units = OFFS_UNIT_VALUE_30_US;
|
2020-07-17 15:27:42 +05:30
|
|
|
}
|
2020-02-12 08:55:57 +05:30
|
|
|
}
|
|
|
|
|
2021-09-15 11:48:21 +05:30
|
|
|
static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
|
|
|
|
uint32_t remainder, uint16_t lazy, uint8_t force,
|
|
|
|
void *param)
|
2020-03-13 16:24:01 +05:30
|
|
|
{
|
|
|
|
static memq_link_t link;
|
2020-03-13 16:24:01 +05:30
|
|
|
static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_sync_prepare};
|
2020-03-13 16:24:01 +05:30
|
|
|
static struct lll_prepare_param p;
|
|
|
|
struct ll_adv_sync_set *sync = param;
|
|
|
|
struct lll_adv_sync *lll;
|
|
|
|
uint32_t ret;
|
|
|
|
uint8_t ref;
|
|
|
|
|
|
|
|
DEBUG_RADIO_PREPARE_A(1);
|
|
|
|
|
|
|
|
lll = &sync->lll;
|
|
|
|
|
|
|
|
/* Increment prepare reference count */
|
|
|
|
ref = ull_ref_inc(&sync->ull);
|
|
|
|
LL_ASSERT(ref);
|
|
|
|
|
|
|
|
/* Append timing parameters */
|
|
|
|
p.ticks_at_expire = ticks_at_expire;
|
|
|
|
p.remainder = remainder;
|
|
|
|
p.lazy = lazy;
|
2021-03-03 15:41:55 +01:00
|
|
|
p.force = force;
|
2020-03-13 16:24:01 +05:30
|
|
|
p.param = lll;
|
|
|
|
mfy.param = &p;
|
|
|
|
|
|
|
|
/* Kick LLL prepare */
|
|
|
|
ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH,
|
|
|
|
TICKER_USER_ID_LLL, 0, &mfy);
|
|
|
|
LL_ASSERT(!ret);
|
|
|
|
|
|
|
|
DEBUG_RADIO_PREPARE_A(1);
|
|
|
|
}
|
2020-02-12 08:55:57 +05:30
|
|
|
|
|
|
|
static void ticker_op_cb(uint32_t status, void *param)
|
|
|
|
{
|
|
|
|
*((uint32_t volatile *)param) = status;
|
|
|
|
}
|