Bluetooth: controller: split: Implement Aux Sets

Implement use of configurable Auxiliary advertising sets.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2020-02-12 08:55:57 +05:30 committed by Carles Cufí
commit 4d79d43db1
16 changed files with 929 additions and 175 deletions

View file

@ -455,10 +455,20 @@ config BT_CTLR_ADV_EXT
config BT_CTLR_ADV_SET
int "LE Advertising Extensions Sets"
depends on BT_CTLR_ADV_EXT
default 1
range 1 64
help
Maximum supported advertising sets.
config BT_CTLR_ADV_AUX_SET
int "LE Advertising Extensions Auxiliary Sets"
depends on BT_CTLR_ADV_EXT
range 1 BT_CTLR_ADV_SET if BT_CTLR_ADV_PERIODIC
range 0 BT_CTLR_ADV_SET
default 1 if BT_CTLR_ADV_PERIODIC
default 0
help
Maximum supported advertising auxiliary channel sets.
config BT_CTLR_ADV_PERIODIC
bool "LE Periodic Advertising"
depends on BT_CTLR_ADV_EXT
@ -470,7 +480,7 @@ config BT_CTLR_ADV_PERIODIC
config BT_CTLR_ADV_SYNC_SET
int "LE Periodic Advertising Sets"
depends on BT_CTLR_ADV_PERIODIC
default 1
range 1 BT_CTLR_ADV_AUX_SET
help
Maximum supported periodic advertising sets.

View file

@ -39,11 +39,11 @@ enum {
TICKER_ID_ADV_BASE,
#if defined(CONFIG_BT_CTLR_ADV_EXT) || defined(CONFIG_BT_HCI_MESH_EXT)
TICKER_ID_ADV_LAST = ((TICKER_ID_ADV_BASE) + (BT_CTLR_ADV_MAX) - 1),
#if defined(CONFIG_BT_CTLR_ADV_EXT)
#if (CONFIG_BT_CTLR_ADV_AUX_SET > 0)
TICKER_ID_ADV_AUX_BASE,
TICKER_ID_ADV_AUX_LAST = ((TICKER_ID_ADV_AUX_BASE) +
(CONFIG_BT_CTLR_ADV_SET) - 1),
#endif /* CONFIG_BT_CTLR_ADV_EXT */
(CONFIG_BT_CTLR_ADV_AUX_SET) - 1),
#endif /* CONFIG_BT_CTLR_ADV_AUX_SET > 0 */
#endif /* !CONFIG_BT_CTLR_ADV_EXT || !CONFIG_BT_HCI_MESH_EXT */
#endif /* CONFIG_BT_BROADCASTER */

View file

@ -779,7 +779,7 @@ uint32_t radio_tmr_start_now(uint8_t trx)
now = EVENT_TIMER->CC[1];
} while (now > start);
return start;
return start + 1;
}
uint32_t radio_tmr_start_get(void)

View file

@ -55,10 +55,6 @@ static void isr_done(void *param);
static void isr_abort(void *param);
static struct pdu_adv *chan_prepare(struct lll_adv *lll);
#if defined(CONFIG_BT_CTLR_ADV_EXT)
static void aux_ptr_populate(struct pdu_adv *pdu, uint32_t start_us);
#endif /* CONFIG_BT_CTLR_ADV_EXT */
static inline int isr_rx_pdu(struct lll_adv *lll,
uint8_t devmatch_ok, uint8_t devmatch_id,
uint8_t irkmatch_ok, uint8_t irkmatch_id,
@ -214,14 +210,6 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
/* capture end of Tx-ed PDU, used to calculate HCTO. */
radio_tmr_end_capture();
#if defined(CONFIG_BT_CTLR_ADV_EXT)
if (pdu->type == PDU_ADV_TYPE_EXT_IND) {
aux_ptr_populate(pdu, start_us);
}
#else /* !CONFIG_BT_CTLR_ADV_EXT */
ARG_UNUSED(pdu);
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
#if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
radio_gpio_pa_setup();
radio_gpio_pa_lna_enable(start_us + radio_tx_ready_delay_get(0, 0) -
@ -488,8 +476,9 @@ static void isr_done(void *param)
start_us = radio_tmr_start_now(1);
#if defined(CONFIG_BT_CTLR_ADV_EXT)
if (pdu->type == PDU_ADV_TYPE_EXT_IND) {
aux_ptr_populate(pdu, start_us);
if (lll->aux) {
lll_adv_aux_offset_fill(lll->aux->ticks_offset,
start_us + 1, pdu);
}
#else /* !CONFIG_BT_CTLR_ADV_EXT */
ARG_UNUSED(pdu);
@ -512,7 +501,7 @@ static void isr_done(void *param)
return;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
#if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_CTLR_ADV_EXT_PBACK)
} else {
struct pdu_adv_com_ext_adv *p;
struct ext_adv_hdr *h;
@ -525,7 +514,7 @@ static void isr_done(void *param)
if ((pdu->type == PDU_ADV_TYPE_EXT_IND) && h->aux_ptr) {
radio_filter_disable();
lll_adv_aux_prepare(lll);
lll_adv_aux_pback_prepare(lll);
return;
}
@ -627,39 +616,6 @@ static struct pdu_adv *chan_prepare(struct lll_adv *lll)
return pdu;
}
#if defined(CONFIG_BT_CTLR_ADV_EXT)
static void aux_ptr_populate(struct pdu_adv *pdu, uint32_t start_us)
{
struct pdu_adv_com_ext_adv *p;
struct ext_adv_aux_ptr *aux;
struct ext_adv_hdr *h;
uint8_t *ptr;
p = (void *)&pdu->adv_ext_ind;
h = (void *)p->ext_hdr_adi_adv_data;
if (!h->aux_ptr) {
return;
}
ptr = (uint8_t *)h + sizeof(*h);
if (h->adv_addr) {
ptr += BDADDR_SIZE;
}
if (h->adi) {
ptr += sizeof(struct ext_adv_adi);
}
aux = (void *)ptr;
aux->offs = (1000 - start_us) / 30;
if (aux->offs_units) {
aux->offs /= 10;
}
}
#endif /* CONFIG_BT_CTLR_ADV_EXT */
static inline int isr_rx_pdu(struct lll_adv *lll,
uint8_t devmatch_ok, uint8_t devmatch_id,
uint8_t irkmatch_ok, uint8_t irkmatch_id,

View file

@ -13,6 +13,19 @@ struct lll_adv_pdu {
uint8_t pdu[DOUBLE_BUFFER_SIZE][PDU_AC_SIZE_MAX];
};
struct lll_adv_aux {
struct lll_hdr hdr;
struct lll_adv *adv;
uint32_t ticks_offset;
struct lll_adv_pdu data;
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
int8_t tx_pwr_lvl;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
};
struct lll_adv_sync {
struct lll_hdr hdr;
struct lll_adv *adv;
@ -28,7 +41,13 @@ struct lll_adv_sync {
uint8_t data_chan_count:6;
uint16_t data_chan_id;
uint32_t ticks_offset;
struct lll_adv_pdu data;
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
int8_t tx_pwr_lvl;
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
};
struct lll_adv {
@ -61,7 +80,7 @@ struct lll_adv {
struct lll_adv_pdu scan_rsp;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
struct lll_adv_pdu aux_data;
struct lll_adv_aux *aux;
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
struct lll_adv_sync *sync;
@ -134,20 +153,21 @@ static inline struct pdu_adv *lll_adv_scan_rsp_peek(struct lll_adv *lll)
}
#if defined(CONFIG_BT_CTLR_ADV_EXT)
static inline struct pdu_adv *lll_adv_aux_data_alloc(struct lll_adv *lll,
static inline struct pdu_adv *lll_adv_aux_data_alloc(struct lll_adv_aux *lll,
uint8_t *idx)
{
return lll_adv_pdu_alloc(&lll->aux_data, idx);
return lll_adv_pdu_alloc(&lll->data, idx);
}
static inline void lll_adv_aux_data_enqueue(struct lll_adv *lll, uint8_t idx)
static inline void lll_adv_aux_data_enqueue(struct lll_adv_aux *lll,
uint8_t idx)
{
lll_adv_pdu_enqueue(&lll->aux_data, idx);
lll_adv_pdu_enqueue(&lll->data, idx);
}
static inline struct pdu_adv *lll_adv_aux_data_peek(struct lll_adv *lll)
static inline struct pdu_adv *lll_adv_aux_data_peek(struct lll_adv_aux *lll)
{
return (void *)lll->aux_data.pdu[lll->aux_data.last];
return (void *)lll->data.pdu[lll->data.last];
}
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)

View file

@ -8,9 +8,11 @@
#include <toolchain.h>
#include <zephyr/types.h>
#include <sys/byteorder.h>
#include "hal/ccm.h"
#include "hal/radio.h"
#include "hal/ticker.h"
#include "util/util.h"
#include "util/memq.h"
@ -18,9 +20,11 @@
#include "pdu.h"
#include "lll.h"
#include "lll_vendor.h"
#include "lll_clock.h"
#include "lll_adv.h"
#include "lll_chan.h"
#include "lll_adv.h"
#include "lll_adv_aux.h"
#include "lll_internal.h"
#include "lll_adv_internal.h"
@ -31,28 +35,107 @@
#include <soc.h>
#include "hal/debug.h"
void lll_adv_aux_prepare(struct lll_adv *lll)
static int init_reset(void);
static int prepare_cb(struct lll_prepare_param *prepare_param);
static void abort_cb(struct lll_prepare_param *prepare_param, void *param);
int lll_adv_aux_init(void)
{
int err;
err = init_reset();
if (err) {
return err;
}
return 0;
}
int lll_adv_aux_reset(void)
{
int err;
err = init_reset();
if (err) {
return err;
}
return 0;
}
void lll_adv_aux_prepare(void *param)
{
struct lll_prepare_param *p = param;
int err;
err = lll_hfclock_on();
LL_ASSERT(!err || err == -EINPROGRESS);
err = lll_prepare(lll_is_abort_cb, abort_cb, prepare_cb, 0, p);
LL_ASSERT(!err || err == -EINPROGRESS);
}
void lll_adv_aux_offset_fill(uint32_t ticks_offset, uint32_t start_us,
struct pdu_adv *pdu)
{
struct pdu_adv_com_ext_adv *p;
struct ext_adv_aux_ptr *aux;
struct pdu_adv *pri, *sec;
struct ext_adv_hdr *h;
uint32_t start_us;
uint8_t *ptr;
uint8_t upd = 0U;
/* TODO: if coded we use S8? */
radio_phy_set(lll->phy_s, 1);
radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX, (lll->phy_s << 1));
p = (void *)&pdu->adv_ext_ind;
h = (void *)p->ext_hdr_adi_adv_data;
ptr = (uint8_t *)h + sizeof(*h);
if (h->adv_addr) {
ptr += BDADDR_SIZE;
}
if (h->adi) {
ptr += sizeof(struct ext_adv_adi);
}
aux = (void *)ptr;
aux->offs = (HAL_TICKER_TICKS_TO_US(ticks_offset) - start_us) / 30;
if (aux->offs_units) {
aux->offs /= 10;
}
}
void lll_adv_aux_pback_prepare(void *param)
{
}
static int init_reset(void)
{
return 0;
}
static int prepare_cb(struct lll_prepare_param *prepare_param)
{
struct lll_adv_aux *lll = prepare_param->param;
uint32_t aa = sys_cpu_to_le32(PDU_AC_ACCESS_ADDR);
uint32_t ticks_at_event, ticks_at_start;
struct pdu_adv_com_ext_adv *p;
struct ext_adv_aux_ptr *aux;
struct pdu_adv *pri, *sec;
struct lll_adv *lll_adv;
struct ext_adv_hdr *h;
struct evt_hdr *evt;
uint32_t remainder;
uint32_t start_us;
uint8_t phy_s;
uint8_t *ptr;
uint8_t upd;
DEBUG_RADIO_START_A(1);
/* AUX_ADV_IND PDU buffer get */
/* FIXME: get latest only when primary PDU without Aux PDUs */
sec = lll_adv_aux_data_latest_get(lll, &upd);
radio_pkt_tx_set(sec);
/* Get reference to primary PDU aux_ptr */
pri = lll_adv_data_curr_get(lll);
lll_adv = lll->adv;
pri = lll_adv_data_curr_get(lll_adv);
p = (void *)&pri->adv_ext_ind;
h = (void *)p->ext_hdr_adi_adv_data;
ptr = (uint8_t *)h + sizeof(*h);
@ -68,23 +151,109 @@ void lll_adv_aux_prepare(struct lll_adv *lll)
}
aux = (void *)ptr;
#if !defined(CONFIG_BT_CTLR_ADV_EXT_PBACK)
/* Set up Radio H/W */
radio_reset();
#endif /* !CONFIG_BT_CTLR_ADV_EXT_PBACK */
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
radio_tx_power_set(lll->tx_pwr_lvl);
#else
radio_tx_power_set(RADIO_TXP_DEFAULT);
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
phy_s = lll_adv->phy_s;
/* TODO: if coded we use S8? */
radio_phy_set(phy_s, 1);
radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX, (phy_s << 1));
#if !defined(CONFIG_BT_CTLR_ADV_EXT_PBACK)
/* Access address and CRC */
radio_aa_set((uint8_t *)&aa);
radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
0x555555);
#endif /* !CONFIG_BT_CTLR_ADV_EXT_PBACK */
/* Use channel idx in aux_ptr */
lll_chan_set(aux->chan_idx);
/* Set the Radio Tx Packet */
radio_pkt_tx_set(sec);
/* TODO: Based on adv_mode switch to Rx, if needed */
radio_isr_set(lll_isr_done, lll);
radio_switch_complete_and_disable();
#if defined(CONFIG_BT_CTLR_ADV_EXT_PBACK)
start_us = 1000;
radio_tmr_start_us(1, start_us);
#else /* !CONFIG_BT_CTLR_ADV_EXT_PBACK */
ticks_at_event = prepare_param->ticks_at_expire;
evt = HDR_LLL2EVT(lll);
ticks_at_event += lll_evt_offset_get(evt);
ticks_at_start = ticks_at_event;
ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
remainder = prepare_param->remainder;
start_us = radio_tmr_start(1, ticks_at_start, remainder);
#endif /* !CONFIG_BT_CTLR_ADV_EXT_PBACK */
/* capture end of Tx-ed PDU, used to calculate HCTO. */
radio_tmr_end_capture();
#if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
radio_gpio_pa_setup();
radio_gpio_pa_lna_enable(start_us +
radio_tx_ready_delay_get(0, 0) -
radio_gpio_pa_lna_enable(start_us + radio_tx_ready_delay_get(phy_s, 1) -
CONFIG_BT_CTLR_GPIO_PA_OFFSET);
#else /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
ARG_UNUSED(start_us);
#endif /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
#if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
(EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US)
/* check if preempt to start has changed */
if (lll_preempt_calc(evt, (TICKER_ID_ADV_AUX_BASE +
ull_adv_aux_lll_handle_get(lll)),
ticks_at_event)) {
radio_isr_set(lll_isr_abort, lll);
radio_disable();
} else
#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
{
uint32_t ret;
ret = lll_prepare_done(lll);
LL_ASSERT(!ret);
}
DEBUG_RADIO_START_A(1);
return 0;
}
static void abort_cb(struct lll_prepare_param *prepare_param, void *param)
{
int err;
/* NOTE: This is not a prepare being cancelled */
if (!prepare_param) {
/* Perform event abort here.
* After event has been cleanly aborted, clean up resources
* and dispatch event done.
*/
radio_isr_set(lll_isr_done, param);
radio_disable();
return;
}
/* NOTE: Else clean the top half preparations of the aborted event
* currently in preparation pipeline.
*/
err = lll_hfclock_off();
LL_ASSERT(!err || err == -EBUSY);
lll_done(param);
}

View file

@ -4,4 +4,11 @@
* SPDX-License-Identifier: Apache-2.0
*/
void lll_adv_aux_prepare(struct lll_adv *lll);
int lll_adv_aux_init(void);
int lll_adv_aux_reset(void);
void lll_adv_aux_prepare(void *param);
void lll_adv_aux_offset_fill(uint32_t ticks_offset, uint32_t start_us,
struct pdu_adv *pdu);
extern uint16_t ull_adv_aux_lll_handle_get(struct lll_adv_aux *lll);

View file

@ -45,15 +45,15 @@ static inline struct pdu_adv *lll_adv_scan_rsp_curr_get(struct lll_adv *lll)
}
#if defined(CONFIG_BT_CTLR_ADV_EXT)
static inline struct pdu_adv *lll_adv_aux_data_latest_get(struct lll_adv *lll,
uint8_t *is_modified)
static inline struct pdu_adv *
lll_adv_aux_data_latest_get(struct lll_adv_aux *lll, uint8_t *is_modified)
{
return lll_adv_pdu_latest_get(&lll->aux_data, is_modified);
return lll_adv_pdu_latest_get(&lll->data, is_modified);
}
static inline struct pdu_adv *lll_adv_aux_data_curr_get(struct lll_adv *lll)
static inline struct pdu_adv *lll_adv_aux_data_curr_get(struct lll_adv_aux *lll)
{
return (void *)lll->aux_data.pdu[lll->aux_data.first];
return (void *)lll->data.pdu[lll->data.first];
}
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)

View file

@ -76,6 +76,37 @@ void lll_adv_sync_prepare(void *param)
LL_ASSERT(!err || err == -EINPROGRESS);
}
void lll_adv_sync_offset_fill(uint32_t ticks_offset, uint32_t start_us,
struct pdu_adv *pdu)
{
struct pdu_adv_com_ext_adv *p;
struct ext_adv_sync_info *si;
struct ext_adv_hdr *h;
uint8_t *ptr;
p = (void *)&pdu->adv_ext_ind;
h = (void *)p->ext_hdr_adi_adv_data;
ptr = (uint8_t *)h + sizeof(*h);
if (h->adv_addr) {
ptr += BDADDR_SIZE;
}
if (h->adi) {
ptr += sizeof(struct ext_adv_adi);
}
if (h->aux_ptr) {
ptr += sizeof(struct ext_adv_aux_ptr);
}
si = (void *)ptr;
si->offs = (HAL_TICKER_TICKS_TO_US(ticks_offset) - start_us) / 30;
if (si->offs_units) {
si->offs /= 10;
}
}
static int init_reset(void)
{
return 0;
@ -88,9 +119,9 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
struct pdu_adv *pdu;
struct evt_hdr *evt;
uint16_t event_counter;
uint32_t remainder_us;
uint8_t data_chan_use;
uint32_t remainder;
uint32_t start_us;
uint16_t lazy;
uint8_t phy_s;
uint8_t upd;
@ -154,23 +185,15 @@ static int prepare_cb(struct lll_prepare_param *prepare_param)
ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
remainder = prepare_param->remainder;
remainder_us = radio_tmr_start(1, ticks_at_start, remainder);
start_us = radio_tmr_start(1, ticks_at_start, remainder);
#if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
radio_gpio_pa_setup();
#if defined(CONFIG_BT_CTLR_PHY)
radio_gpio_pa_lna_enable(remainder_us +
radio_tx_ready_delay_get(lll->phy_tx,
lll->phy_flags) -
radio_gpio_pa_lna_enable(start_us + radio_tx_ready_delay_get(phy_s, 1) -
CONFIG_BT_CTLR_GPIO_PA_OFFSET);
#else /* !CONFIG_BT_CTLR_PHY */
radio_gpio_pa_lna_enable(remainder_us +
radio_tx_ready_delay_get(0, 0) -
CONFIG_BT_CTLR_GPIO_PA_OFFSET);
#endif /* !CONFIG_BT_CTLR_PHY */
#else /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
ARG_UNUSED(remainder_us);
ARG_UNUSED(start_us);
#endif /* !CONFIG_BT_CTLR_GPIO_PA_PIN */
#if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \

View file

@ -7,5 +7,7 @@
int lll_adv_sync_init(void);
int lll_adv_sync_reset(void);
void lll_adv_sync_prepare(void *param);
void lll_adv_sync_offset_fill(uint32_t ticks_offset, uint32_t start_us,
struct pdu_adv *pdu);
extern uint16_t ull_adv_sync_lll_handle_get(struct lll_adv_sync *lll);

View file

@ -74,9 +74,24 @@
#if defined(CONFIG_BT_BROADCASTER)
#define BT_ADV_TICKER_NODES ((TICKER_ID_ADV_LAST) - (TICKER_ID_ADV_STOP) + 1)
#else
#if defined(CONFIG_BT_CTLR_ADV_EXT) && (CONFIG_BT_CTLR_ADV_AUX_SET > 0)
#define BT_ADV_AUX_TICKER_NODES ((TICKER_ID_ADV_AUX_LAST) - \
(TICKER_ID_ADV_AUX_BASE) + 1)
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
#define BT_ADV_SYNC_TICKER_NODES ((TICKER_ID_ADV_SYNC_LAST) - \
(TICKER_ID_ADV_SYNC_BASE) + 1)
#else /* !CONFIG_BT_CTLR_ADV_PERIODIC */
#define BT_ADV_SYNC_TICKER_NODES 0
#endif /* !CONFIG_BT_CTLR_ADV_PERIODIC */
#else /* (CONFIG_BT_CTLR_ADV_AUX_SET > 0) */
#define BT_ADV_AUX_TICKER_NODES 0
#define BT_ADV_SYNC_TICKER_NODES 0
#endif /* (CONFIG_BT_CTLR_ADV_AUX_SET > 0) */
#else /* !CONFIG_BT_BROADCASTER */
#define BT_ADV_TICKER_NODES 0
#endif
#define BT_ADV_AUX_TICKER_NODES 0
#define BT_ADV_SYNC_TICKER_NODES 0
#endif /* !CONFIG_BT_BROADCASTER */
#if defined(CONFIG_BT_OBSERVER)
#define BT_SCAN_TICKER_NODES ((TICKER_ID_SCAN_LAST) - (TICKER_ID_SCAN_STOP) + 1)
@ -106,6 +121,8 @@
#define TICKER_NODES (TICKER_ID_ULL_BASE + \
BT_ADV_TICKER_NODES + \
BT_ADV_AUX_TICKER_NODES + \
BT_ADV_SYNC_TICKER_NODES + \
BT_SCAN_TICKER_NODES + \
BT_CONN_TICKER_NODES + \
FLASH_TICKER_NODES + \

View file

@ -50,8 +50,6 @@
#include <soc.h>
#include "hal/debug.h"
#define ULL_ADV_RANDOM_DELAY HAL_TICKER_US_TO_TICKS(10000)
inline struct ll_adv_set *ull_adv_set_get(uint8_t handle);
inline uint16_t ull_adv_handle_get(struct ll_adv_set *adv);
@ -469,6 +467,8 @@ uint8_t ll_adv_enable(uint8_t handle, uint8_t enable)
struct ll_adv_sync_set *sync;
uint8_t sync_is_started = 0U;
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
struct ll_adv_aux_set *aux;
uint8_t aux_is_started = 0U;
uint32_t ticks_anchor;
#endif /* !CONFIG_BT_HCI_MESH_EXT */
#else /* !CONFIG_BT_CTLR_ADV_EXT || !CONFIG_BT_HCI_MESH_EXT */
@ -531,7 +531,7 @@ uint8_t ll_adv_enable(uint8_t enable)
struct ext_adv_hdr *hs;
uint8_t *ps;
pdu_aux = lll_adv_aux_data_peek(lll);
pdu_aux = lll_adv_aux_data_peek(lll->aux);
s = (void *)&pdu_aux->adv_ext_ind;
hs = (void *)s->ext_hdr_adi_adv_data;
@ -986,24 +986,48 @@ uint8_t ll_adv_enable(uint8_t enable)
#endif /* CONFIG_BT_TICKER_EXT */
);
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
if (lll->sync) {
struct lll_adv_sync *lll_sync = lll->sync;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
if (lll->aux) {
struct lll_adv_aux *lll_aux = lll->aux;
sync = (void *)HDR_LLL2EVT(lll_sync);
if (sync->is_enabled && !sync->is_started) {
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret != TICKER_STATUS_SUCCESS) {
goto failure_cleanup;
}
ret = ull_adv_sync_start(sync, ticks_anchor,
&ret_cb);
sync_is_started = 1U;
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret != TICKER_STATUS_SUCCESS) {
goto failure_cleanup;
}
aux = (void *)HDR_LLL2EVT(lll_aux);
ull_hdr_init(&aux->ull);
aux->interval =
adv->interval +
(HAL_TICKER_TICKS_TO_US(ULL_ADV_RANDOM_DELAY) /
625U);
ret = ull_adv_aux_start(aux, ticks_anchor, &ret_cb);
aux_is_started = 1U;
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
if (lll->sync) {
struct lll_adv_sync *lll_sync = lll->sync;
sync = (void *)HDR_LLL2EVT(lll_sync);
if (sync->is_enabled && !sync->is_started) {
ret = ull_ticker_status_take(ret,
&ret_cb);
if (ret != TICKER_STATUS_SUCCESS) {
goto failure_cleanup;
}
ret = ull_adv_sync_start(sync,
ticks_anchor,
&ret_cb);
sync_is_started = 1U;
}
}
}
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
}
#endif /* CONFIG_BT_CTLR_ADV_EXT */
}
ret = ull_ticker_status_take(ret, &ret_cb);
@ -1011,11 +1035,17 @@ uint8_t ll_adv_enable(uint8_t enable)
goto failure_cleanup;
}
#if defined(CONFIG_BT_CTLR_ADV_EXT)
if (aux_is_started) {
aux->is_started = aux_is_started;
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
if (sync_is_started) {
sync->is_started = sync_is_started;
}
if (sync_is_started) {
sync->is_started = sync_is_started;
}
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
}
#endif /* CONFIG_BT_CTLR_ADV_EXT */
adv->is_enabled = 1;
@ -1050,10 +1080,21 @@ int ull_adv_init(void)
{
int err;
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC)) {
err = ull_adv_sync_init();
if (err) {
return err;
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT)) {
#if defined(CONFIG_BT_CTLR_ADV_AUX_SET)
if (CONFIG_BT_CTLR_ADV_AUX_SET > 0) {
err = ull_adv_aux_init();
if (err) {
return err;
}
}
#endif
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC)) {
err = ull_adv_sync_init();
if (err) {
return err;
}
}
}
@ -1070,10 +1111,21 @@ int ull_adv_reset(void)
uint8_t handle;
int err;
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC)) {
err = ull_adv_sync_reset();
if (err) {
return err;
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT)) {
#if defined(CONFIG_BT_CTLR_ADV_AUX_SET)
if (CONFIG_BT_CTLR_ADV_AUX_SET > 0) {
err = ull_adv_aux_reset();
if (err) {
return err;
}
}
#endif
if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC)) {
err = ull_adv_sync_reset();
if (err) {
return err;
}
}
}
@ -1232,6 +1284,12 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, uint16_t laz
(ret == TICKER_STATUS_BUSY));
}
#if defined(CONFIG_BT_CTLR_ADV_EXT) && (CONFIG_BT_CTLR_ADV_AUX_SET > 0)
if (adv->lll.aux) {
ull_adv_aux_offset_get(adv);
}
#endif /* CONFIG_BT_CTLR_ADV_EXT && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) */
DEBUG_RADIO_PREPARE_A(1);
}
@ -1380,6 +1438,22 @@ static inline uint8_t disable(uint8_t handle)
return BT_HCI_ERR_CMD_DISALLOWED;
}
#if defined(CONFIG_BT_CTLR_ADV_EXT) && (CONFIG_BT_CTLR_ADV_AUX_SET > 0)
struct lll_adv_aux *lll_aux = adv->lll.aux;
if (lll_aux) {
struct ll_adv_aux_set *aux;
uint8_t err;
aux = (void *)HDR_LLL2EVT(lll_aux);
err = ull_adv_aux_stop(aux);
if (err) {
return err;
}
}
#endif /* CONFIG_BT_CTLR_ADV_EXT && (CONFIG_BT_CTLR_ADV_AUX_SET > 0) */
mark = ull_disable_mark(adv);
LL_ASSERT(mark == adv);

View file

@ -4,24 +4,50 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <zephyr/types.h>
#include <sys/byteorder.h>
#include <bluetooth/hci.h>
#include "hal/ccm.h"
#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"
#include "ll.h"
#include "lll.h"
#include "lll_vendor.h"
#include "lll_adv.h"
#include "lll_conn.h"
#include "ull_internal.h"
#include "lll_adv_aux.h"
#include "lll_adv_internal.h"
#include "ull_adv_types.h"
#include "ull_internal.h"
#include "ull_adv_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
#define LOG_MODULE_NAME bt_ctlr_ull_adv_aux
#include "common/log.h"
#include <soc.h>
#include "hal/debug.h"
static int init_reset(void);
static inline struct ll_adv_aux_set *aux_acquire(void);
static inline void aux_release(struct ll_adv_aux_set *aux);
static inline uint16_t aux_handle_get(struct ll_adv_aux_set *aux);
static void mfy_aux_offset_get(void *param);
static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
uint16_t lazy, void *param);
static void ticker_op_cb(uint32_t status, void *param);
static struct ll_adv_aux_set ll_adv_aux_pool[CONFIG_BT_CTLR_ADV_AUX_SET];
static void *adv_aux_free;
uint8_t ll_adv_aux_random_addr_set(uint8_t handle, uint8_t *addr)
{
/* TODO: store in adv set instance */
@ -41,8 +67,11 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui
uint8_t pri_len, _pri_len, sec_len, _sec_len;
struct pdu_adv *_pri, *pri, *_sec, *sec;
struct ext_adv_hdr *hp, _hp, *hs, _hs;
struct lll_adv_aux *lll_aux;
struct ll_adv_aux_set *aux;
uint8_t *_pp, *pp, *ps, *_ps;
struct ll_adv_set *adv;
struct lll_adv *lll;
uint8_t ip, is;
/* op param definitions:
@ -66,8 +95,29 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui
return BT_HCI_ERR_CMD_DISALLOWED;
}
lll = &adv->lll;
lll_aux = lll->aux;
if (!lll_aux) {
aux = aux_acquire();
if (!aux) {
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
lll_aux = &aux->lll;
lll->aux = lll_aux;
lll_aux->adv = lll;
/* NOTE: ull_hdr_init(&aux->ull); is done on start */
lll_hdr_init(lll_aux, aux);
aux->is_started = 0;
} else {
aux = (void *)HDR_LLL2EVT(lll_aux);
}
/* Do not update data if not extended advertising. */
_pri = lll_adv_data_peek(&adv->lll);
_pri = lll_adv_data_peek(lll);
if (_pri->type != PDU_ADV_TYPE_EXT_IND) {
/* Advertising Handle has not been created using
* Set Extended Advertising Parameter command
@ -82,7 +132,7 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui
_pp = (uint8_t *)hp + sizeof(*hp);
/* Get reference to new primary PDU data buffer */
pri = lll_adv_data_alloc(&adv->lll, &ip);
pri = lll_adv_data_alloc(lll, &ip);
pri->type = _pri->type;
pri->rfu = 0U;
pri->chan_sel = 0U;
@ -93,14 +143,14 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui
*(uint8_t *)hp = 0U;
/* Get reference to previous secondary PDU data */
_sec = lll_adv_aux_data_peek(&adv->lll);
_sec = lll_adv_aux_data_peek(lll_aux);
_s = (void *)&_sec->adv_ext_ind;
hs = (void *)_s->ext_hdr_adi_adv_data;
*(uint8_t *)&_hs = *(uint8_t *)hs;
_ps = (uint8_t *)hs + sizeof(*hs);
/* Get reference to new secondary PDU data buffer */
sec = lll_adv_aux_data_alloc(&adv->lll, &is);
sec = lll_adv_aux_data_alloc(lll_aux, &is);
sec->type = pri->type;
sec->rfu = 0U;
@ -187,7 +237,7 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui
/* C1, Tx Power is optional on the LE 1M PHY, and reserved for
* for future use on the LE Coded PHY.
*/
if (adv->lll.phy_p != BIT(2)) {
if (lll->phy_p != BIT(2)) {
hp->tx_pwr = 1;
pp++;
} else {
@ -265,7 +315,7 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui
aux->chan_idx = 0; /* FIXME: implementation defined */
aux->ca = 0; /* FIXME: implementation defined */
aux->offs_units = 0; /* FIXME: implementation defined */
aux->phy = find_lsb_set(adv->lll.phy_s) - 1;
aux->phy = find_lsb_set(lll->phy_s) - 1;
}
if (_hs.aux_ptr) {
struct ext_adv_aux_ptr *aux;
@ -278,7 +328,7 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui
aux->chan_idx = 0; /* FIXME: implementation defined */
aux->ca = 0; /* FIXME: implementation defined */
aux->offs_units = 0; /* FIXME: implementation defined */
aux->phy = find_lsb_set(adv->lll.phy_s) - 1;
aux->phy = find_lsb_set(lll->phy_s) - 1;
}
/* ADI */
@ -340,8 +390,31 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui
memcpy(ps, bdaddr, BDADDR_SIZE);
}
lll_adv_aux_data_enqueue(&adv->lll, is);
lll_adv_data_enqueue(&adv->lll, ip);
lll_adv_aux_data_enqueue(lll_aux, is);
lll_adv_data_enqueue(lll, ip);
if (adv->is_enabled && !aux->is_started) {
volatile uint32_t ret_cb;
uint32_t ticks_anchor;
uint32_t ret;
ull_hdr_init(&aux->ull);
aux->interval = adv->interval +
(HAL_TICKER_TICKS_TO_US(ULL_ADV_RANDOM_DELAY) /
625U);
ticks_anchor = ticker_ticks_now_get();
ret = ull_adv_aux_start(aux, ticks_anchor, &ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret != TICKER_STATUS_SUCCESS) {
/* FIXME: Use a better error code */
return BT_HCI_ERR_CMD_DISALLOWED;
}
aux->is_started = 1;
}
return 0;
}
@ -378,3 +451,252 @@ uint8_t ll_adv_aux_set_clear(void)
*/
return 0;
}
int ull_adv_aux_init(void)
{
int err;
err = init_reset();
if (err) {
return err;
}
return 0;
}
int ull_adv_aux_reset(void)
{
int err;
err = init_reset();
if (err) {
return err;
}
return 0;
}
uint16_t ull_adv_aux_lll_handle_get(struct lll_adv_aux *lll)
{
return aux_handle_get((void *)lll->hdr.parent);
}
uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor,
uint32_t volatile *ret_cb)
{
uint32_t slot_us = EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
uint32_t ticks_slot_overhead;
uint8_t aux_handle;
uint32_t ret;
/* TODO: Calc AUX_ADV_IND slot_us */
slot_us += 1000;
/* TODO: active_to_start feature port */
aux->evt.ticks_active_to_start = 0;
aux->evt.ticks_xtal_to_start =
HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US);
aux->evt.ticks_preempt_to_start =
HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US);
aux->evt.ticks_slot = HAL_TICKER_US_TO_TICKS(slot_us);
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
ticks_slot_overhead = MAX(aux->evt.ticks_active_to_start,
aux->evt.ticks_xtal_to_start);
} else {
ticks_slot_overhead = 0;
}
aux_handle = aux_handle_get(aux);
*ret_cb = TICKER_STATUS_BUSY;
ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
(TICKER_ID_ADV_AUX_BASE + aux_handle),
ticks_anchor, 0,
HAL_TICKER_US_TO_TICKS((uint64_t)aux->interval *
625),
TICKER_NULL_REMAINDER, TICKER_NULL_LAZY,
(aux->evt.ticks_slot + ticks_slot_overhead),
ticker_cb, aux,
ull_ticker_status_give, (void *)ret_cb);
return ret;
}
uint8_t ull_adv_aux_stop(struct ll_adv_aux_set *aux)
{
volatile uint32_t ret_cb = TICKER_STATUS_BUSY;
uint8_t aux_handle;
void *mark;
uint32_t ret;
mark = ull_disable_mark(aux);
LL_ASSERT(mark == aux);
aux_handle = aux_handle_get(aux);
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
TICKER_ID_ADV_AUX_BASE + aux_handle,
ull_ticker_status_give, (void *)&ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret) {
mark = ull_disable_mark(aux);
LL_ASSERT(mark == aux);
return BT_HCI_ERR_CMD_DISALLOWED;
}
ret = ull_disable(&aux->lll);
LL_ASSERT(!ret);
mark = ull_disable_unmark(aux);
LL_ASSERT(mark == aux);
aux->is_started = 0U;
return 0;
}
void ull_adv_aux_offset_get(struct ll_adv_set *adv)
{
static memq_link_t link;
static struct mayfly mfy = {0, 0, &link, NULL, mfy_aux_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);
}
static int init_reset(void)
{
/* Initialize adv aux pool. */
mem_init(ll_adv_aux_pool, sizeof(struct ll_adv_aux_set),
sizeof(ll_adv_aux_pool) / sizeof(struct ll_adv_aux_set),
&adv_aux_free);
return 0;
}
static inline struct ll_adv_aux_set *aux_acquire(void)
{
return mem_acquire(&adv_aux_free);
}
static inline void aux_release(struct ll_adv_aux_set *aux)
{
mem_release(aux, &adv_aux_free);
}
static inline uint16_t aux_handle_get(struct ll_adv_aux_set *aux)
{
return mem_index_get(aux, ll_adv_aux_pool,
sizeof(struct ll_adv_aux_set));
}
static void mfy_aux_offset_get(void *param)
{
struct ll_adv_set *adv = param;
struct ll_adv_aux_set *aux;
uint32_t ticks_to_expire;
uint32_t ticks_current;
struct pdu_adv *pdu;
uint8_t ticker_id;
uint8_t retry;
uint8_t id;
aux = (void *)HDR_LLL2EVT(adv->lll.aux);
ticker_id = TICKER_ID_ADV_AUX_BASE + aux_handle_get(aux);
id = TICKER_NULL;
ticks_to_expire = 0U;
ticks_current = 0U;
retry = 4U;
do {
uint32_t volatile ret_cb = TICKER_STATUS_BUSY;
uint32_t ticks_previous;
uint32_t ret;
ticks_previous = ticks_current;
ret = ticker_next_slot_get(TICKER_INSTANCE_ID_CTLR,
TICKER_USER_ID_ULL_LOW,
&id,
&ticks_current, &ticks_to_expire,
ticker_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);
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.
*/
aux->lll.ticks_offset = ticks_to_expire + 1;
pdu = lll_adv_data_curr_get(&adv->lll);
lll_adv_aux_offset_fill(ticks_to_expire, 0, pdu);
}
static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
uint16_t lazy, void *param)
{
static memq_link_t link;
static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_aux_prepare};
static struct lll_prepare_param p;
struct ll_adv_aux_set *aux = param;
struct lll_adv_aux *lll;
uint32_t ret;
uint8_t ref;
DEBUG_RADIO_PREPARE_A(1);
lll = &aux->lll;
/* Increment prepare reference count */
ref = ull_ref_inc(&aux->ull);
LL_ASSERT(ref);
/* Append timing parameters */
p.ticks_at_expire = ticks_at_expire;
p.remainder = remainder;
p.lazy = lazy;
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);
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
struct ll_adv_set *adv;
adv = (void *)HDR_LLL2EVT(lll->adv);
if (adv->lll.sync) {
struct ll_adv_sync_set *sync;
sync = (void *)HDR_LLL2EVT(adv->lll.sync);
if (sync->is_started) {
ull_adv_sync_offset_get(adv);
}
}
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
DEBUG_RADIO_PREPARE_A(1);
}
static void ticker_op_cb(uint32_t status, void *param)
{
*((uint32_t volatile *)param) = status;
}

View file

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#define ULL_ADV_RANDOM_DELAY HAL_TICKER_US_TO_TICKS(10000)
int ull_adv_init(void);
int ull_adv_reset(void);
@ -25,9 +27,25 @@ uint32_t ull_adv_filter_pol_get(uint8_t handle);
/* Return ll_adv_set context if created */
struct ll_adv_set *ull_adv_is_created_get(uint8_t handle);
int ull_adv_aux_init(void);
int ull_adv_aux_reset(void);
/* helper function to start auxiliary advertising */
uint32_t ull_adv_aux_start(struct ll_adv_aux_set *aux, uint32_t ticks_anchor,
uint32_t volatile *ret_cb);
/* helper function to stop auxiliary advertising */
uint8_t ull_adv_aux_stop(struct ll_adv_aux_set *aux);
/* helper function to schedule a mayfly to get aux offset */
void ull_adv_aux_offset_get(struct ll_adv_set *adv);
int ull_adv_sync_init(void);
int ull_adv_sync_reset(void);
/* helper function to start periodic advertising */
uint32_t ull_adv_sync_start(struct ll_adv_sync_set *sync, uint32_t ticks_anchor,
uint32_t volatile *ret_cb);
/* helper function to schedule a mayfly to get sync offset */
void ull_adv_sync_offset_get(struct ll_adv_set *adv);

View file

@ -22,6 +22,7 @@
#include "lll_vendor.h"
#include "lll_adv.h"
#include "lll_adv_sync.h"
#include "lll_adv_internal.h"
#include "ull_adv_types.h"
@ -39,18 +40,21 @@ 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);
static inline uint8_t sync_stop(struct ll_adv_sync_set *sync);
static void mfy_sync_offset_get(void *param);
static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
uint16_t lazy, void *param);
static void ticker_op_cb(uint32_t status, void *param);
static struct ll_adv_sync_set ll_adv_sync_pool[CONFIG_BT_CTLR_ADV_SYNC_SET];
static void *adv_sync_free;
uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
{
struct lll_adv_sync *lll_sync;
struct pdu_adv_com_ext_adv *t;
struct ll_adv_sync_set *sync;
struct ext_adv_hdr *ht, _ht;
struct lll_adv_sync *lll;
struct ll_adv_set *adv;
struct pdu_adv *pdu;
uint8_t *_pt, *pt;
@ -61,48 +65,55 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
return BT_HCI_ERR_CMD_DISALLOWED;
}
lll = adv->lll.sync;
if (!lll) {
lll_sync = adv->lll.sync;
if (!lll_sync) {
struct pdu_adv_com_ext_adv *p, *_p, *s, *_s;
uint8_t pri_len, _pri_len, sec_len, _sec_len;
struct pdu_adv *_pri, *pri, *_sec, *sec;
struct ext_adv_hdr *hp, _hp, *hs, _hs;
struct ext_adv_sync_info *si;
struct lll_adv_aux *lll_aux;
uint8_t *_pp, *pp, *ps, *_ps;
uint8_t ip, is, ad_len;
struct lll_adv *lll;
sync = sync_acquire();
if (!sync) {
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
lll = &sync->lll;
adv->lll.sync = lll;
lll = &adv->lll;
lll_aux = lll->aux;
if (!lll_aux) {
}
lll_sync = &sync->lll;
lll->sync = lll_sync;
lll_sync->adv = lll;
ull_hdr_init(&sync->ull);
lll_hdr_init(lll, sync);
lll_hdr_init(lll_sync, sync);
util_aa_to_le32(lll->access_addr);
util_rand(lll->crc_init, sizeof(lll->crc_init));
util_aa_to_le32(lll_sync->access_addr);
util_rand(lll_sync->crc_init, sizeof(lll_sync->crc_init));
lll->latency_prepare = 0;
lll->latency_event = 0;
lll->event_counter = 0;
lll_sync->latency_prepare = 0;
lll_sync->latency_event = 0;
lll_sync->event_counter = 0;
lll->data_chan_count = ull_chan_map_get(lll->data_chan_map);
lll->data_chan_id = 0;
lll->adv = &adv->lll;
lll_sync->data_chan_count =
ull_chan_map_get(lll_sync->data_chan_map);
lll_sync->data_chan_id = 0;
/* Get reference to previous primary PDU data */
_pri = lll_adv_data_peek(&adv->lll);
_pri = lll_adv_data_peek(lll);
_p = (void *)&_pri->adv_ext_ind;
hp = (void *)_p->ext_hdr_adi_adv_data;
*(uint8_t *)&_hp = *(uint8_t *)hp;
_pp = (uint8_t *)hp + sizeof(*hp);
/* Get reference to new primary PDU data buffer */
pri = lll_adv_data_alloc(&adv->lll, &ip);
pri = lll_adv_data_alloc(lll, &ip);
pri->type = _pri->type;
pri->rfu = 0U;
pri->chan_sel = 0U;
@ -113,14 +124,14 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
*(uint8_t *)hp = 0U;
/* Get reference to previous secondary PDU data */
_sec = lll_adv_aux_data_peek(&adv->lll);
_sec = lll_adv_aux_data_peek(lll_aux);
_s = (void *)&_sec->adv_ext_ind;
hs = (void *)_s->ext_hdr_adi_adv_data;
*(uint8_t *)&_hs = *(uint8_t *)hs;
_ps = (uint8_t *)hs + sizeof(*hs);
/* Get reference to new secondary PDU data buffer */
sec = lll_adv_aux_data_alloc(&adv->lll, &is);
sec = lll_adv_aux_data_alloc(lll_aux, &is);
sec->type = pri->type;
sec->rfu = 0U;
@ -266,9 +277,10 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
si->offs = 0; /* NOTE: Filled by secondary prepare */
si->offs_units = 0;
si->interval = interval;
memcpy(si->sca_chm, lll->data_chan_map, sizeof(si->sca_chm));
memcpy(&si->aa, lll->access_addr, sizeof(si->aa));
memcpy(si->crc_init, lll->crc_init, sizeof(si->crc_init));
memcpy(si->sca_chm, lll_sync->data_chan_map,
sizeof(si->sca_chm));
memcpy(&si->aa, lll_sync->access_addr, sizeof(si->aa));
memcpy(si->crc_init, lll_sync->crc_init, sizeof(si->crc_init));
si->evt_cntr = 0; /* TODO: Implementation defined */
@ -368,15 +380,15 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
memcpy(ps, bdaddr, BDADDR_SIZE);
}
lll_adv_aux_data_enqueue(&adv->lll, is);
lll_adv_data_enqueue(&adv->lll, ip);
lll_adv_aux_data_enqueue(lll_aux, is);
lll_adv_data_enqueue(lll, ip);
} else {
sync = (void *)HDR_LLL2EVT(lll);
sync = (void *)HDR_LLL2EVT(lll_sync);
}
sync->interval = interval;
pdu = lll_adv_sync_data_peek(lll);
pdu = lll_adv_sync_data_peek(lll_sync);
pdu->type = PDU_ADV_TYPE_AUX_SYNC_IND;
pdu->rfu = 0U;
pdu->chan_sel = 0U;
@ -440,7 +452,7 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref,
uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable)
{
struct lll_adv_sync *lll;
struct lll_adv_sync *lll_sync;
struct ll_adv_sync_set *sync;
struct ll_adv_set *adv;
@ -449,16 +461,22 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable)
return BT_HCI_ERR_CMD_DISALLOWED;
}
lll = adv->lll.sync;
if (!lll) {
lll_sync = adv->lll.sync;
if (!lll_sync) {
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
}
sync = (void *)HDR_LLL2EVT(lll);
sync = (void *)HDR_LLL2EVT(lll_sync);
if (!enable) {
/* TODO */
return BT_HCI_ERR_CMD_DISALLOWED;
uint8_t err;
err = sync_stop(sync);
if (err) {
return err;
}
return 0;
}
/* TODO: Check for periodic data being complete */
@ -474,6 +492,7 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable)
}
if (!sync->is_started) {
/* TODO: */
}
return 0;
@ -513,11 +532,12 @@ uint32_t ull_adv_sync_start(struct ll_adv_sync_set *sync, uint32_t ticks_anchor,
{
uint32_t slot_us = EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
uint32_t ticks_slot_overhead;
uint32_t interval_us;
uint8_t sync_handle;
uint32_t ret;
/* TODO: Calc AUX_SYNC_IND slot_us */
slot_us = 1000;
slot_us += 1000;
/* TODO: active_to_start feature port */
sync->evt.ticks_active_to_start = 0;
@ -534,15 +554,16 @@ uint32_t ull_adv_sync_start(struct ll_adv_sync_set *sync, uint32_t ticks_anchor,
ticks_slot_overhead = 0;
}
interval_us = (uint64_t)sync->interval * 1250U;
sync_handle = sync_handle_get(sync);
*ret_cb = TICKER_STATUS_BUSY;
ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
(TICKER_ID_ADV_SYNC_BASE + sync_handle),
ticks_anchor, 0,
HAL_TICKER_US_TO_TICKS((uint64_t)sync->interval *
1250),
TICKER_NULL_REMAINDER, TICKER_NULL_LAZY,
HAL_TICKER_US_TO_TICKS(interval_us),
HAL_TICKER_REMAINDER(interval_us), TICKER_NULL_LAZY,
(sync->evt.ticks_slot + ticks_slot_overhead),
ticker_cb, sync,
ull_ticker_status_give, (void *)ret_cb);
@ -550,6 +571,18 @@ uint32_t ull_adv_sync_start(struct ll_adv_sync_set *sync, uint32_t ticks_anchor,
return ret;
}
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);
}
static int init_reset(void)
{
/* Initialize adv sync pool. */
@ -576,6 +609,94 @@ static inline uint16_t sync_handle_get(struct ll_adv_sync_set *sync)
sizeof(struct ll_adv_sync_set));
}
static inline uint8_t sync_stop(struct ll_adv_sync_set *sync)
{
volatile uint32_t ret_cb = TICKER_STATUS_BUSY;
uint8_t sync_handle;
void *mark;
uint32_t ret;
mark = ull_disable_mark(sync);
LL_ASSERT(mark == sync);
sync_handle = sync_handle_get(sync);
ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
TICKER_ID_ADV_SYNC_BASE + sync_handle,
ull_ticker_status_give, (void *)&ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
if (ret) {
mark = ull_disable_mark(sync);
LL_ASSERT(mark == sync);
return BT_HCI_ERR_CMD_DISALLOWED;
}
ret = ull_disable(&sync->lll);
LL_ASSERT(!ret);
mark = ull_disable_unmark(sync);
LL_ASSERT(mark == sync);
sync->is_started = 0U;
return 0;
}
static void mfy_sync_offset_get(void *param)
{
struct ll_adv_set *adv = param;
struct ll_adv_sync_set *sync;
uint32_t ticks_to_expire;
uint32_t ticks_current;
struct pdu_adv *pdu;
uint8_t ticker_id;
uint8_t retry;
uint8_t id;
sync = (void *)HDR_LLL2EVT(adv->lll.sync);
ticker_id = TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync);
id = TICKER_NULL;
ticks_to_expire = 0U;
ticks_current = 0U;
retry = 4U;
do {
uint32_t volatile ret_cb = TICKER_STATUS_BUSY;
uint32_t ticks_previous;
uint32_t ret;
ticks_previous = ticks_current;
ret = ticker_next_slot_get(TICKER_INSTANCE_ID_CTLR,
TICKER_USER_ID_ULL_LOW,
&id,
&ticks_current, &ticks_to_expire,
ticker_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);
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.
*/
sync->lll.ticks_offset = ticks_to_expire + 1;
pdu = lll_adv_aux_data_curr_get(adv->lll.aux);
lll_adv_sync_offset_fill(ticks_to_expire, 0, pdu);
}
static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
uint16_t lazy, void *param)
{
@ -609,3 +730,8 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
DEBUG_RADIO_PREPARE_A(1);
}
static void ticker_op_cb(uint32_t status, void *param)
{
*((uint32_t volatile *)param) = status;
}

View file

@ -31,6 +31,16 @@ struct ll_adv_set {
#endif /* CONFIG_BT_CTLR_PRIVACY */
};
struct ll_adv_aux_set {
struct evt_hdr evt;
struct ull_hdr ull;
struct lll_adv_aux lll;
uint16_t interval;
uint8_t is_started:1;
};
struct ll_adv_sync_set {
struct evt_hdr evt;
struct ull_hdr ull;