Bluetooth: controller: split: Add periodic adv LLL implementation
Add LLL implementation to perform periodic advertising. Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
parent
3eac6c3a52
commit
5949205315
7 changed files with 256 additions and 7 deletions
197
subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c
Normal file
197
subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <toolchain.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <sys/util.h>
|
||||
|
||||
#include "hal/ccm.h"
|
||||
#include "hal/radio.h"
|
||||
#include "hal/ticker.h"
|
||||
|
||||
#include "util/memq.h"
|
||||
|
||||
#include "pdu.h"
|
||||
|
||||
#include "lll.h"
|
||||
#include "lll_vendor.h"
|
||||
#include "lll_clock.h"
|
||||
#include "lll_chan.h"
|
||||
#include "lll_adv_sync.h"
|
||||
|
||||
#include "lll_internal.h"
|
||||
#include "lll_tim_internal.h"
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||
#define LOG_MODULE_NAME bt_ctlr_lll_master
|
||||
#include "common/log.h"
|
||||
#include <soc.h>
|
||||
#include "hal/debug.h"
|
||||
|
||||
static int init_reset(void);
|
||||
static int prepare_cb(struct lll_prepare_param *prepare_param);
|
||||
|
||||
int lll_adv_sync_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = init_reset();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lll_adv_sync_reset(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = init_reset();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lll_adv_sync_prepare(void *param)
|
||||
{
|
||||
struct lll_prepare_param *p = param;
|
||||
int err;
|
||||
|
||||
err = lll_hfclock_on();
|
||||
LL_ASSERT(!err || err == -EINPROGRESS);
|
||||
|
||||
err = lll_prepare(lll_conn_is_abort_cb, lll_conn_abort_cb, prepare_cb,
|
||||
0, p);
|
||||
LL_ASSERT(!err || err == -EINPROGRESS);
|
||||
}
|
||||
|
||||
static int init_reset(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int prepare_cb(struct lll_prepare_param *prepare_param)
|
||||
{
|
||||
struct lll_adv_sync *lll = prepare_param->param;
|
||||
uint32_t ticks_at_event, ticks_at_start;
|
||||
struct evt_hdr *evt;
|
||||
uint16_t event_counter;
|
||||
uint32_t remainder_us;
|
||||
uint8_t data_chan_use;
|
||||
uint32_t remainder;
|
||||
uint16_t lazy;
|
||||
|
||||
DEBUG_RADIO_START_A(1);
|
||||
|
||||
/* TODO: Do the below in ULL ? */
|
||||
lazy = prepare_param->lazy;
|
||||
|
||||
/* save the latency for use in event */
|
||||
lll->latency_prepare += lazy;
|
||||
|
||||
/* calc current event counter value */
|
||||
event_counter = lll->event_counter + lll->latency_prepare;
|
||||
|
||||
/* store the next event counter value */
|
||||
lll->event_counter = event_counter + 1;
|
||||
|
||||
/* TODO: Do the above in ULL ? */
|
||||
|
||||
/* Reset connection event global variables */
|
||||
lll_conn_prepare_reset();
|
||||
|
||||
/* TODO: can we do something in ULL? */
|
||||
lll->latency_event = lll->latency_prepare;
|
||||
lll->latency_prepare = 0;
|
||||
|
||||
data_chan_use = lll_chan_sel_2(lll->event_counter - 1,
|
||||
lll->data_chan_id,
|
||||
&lll->data_chan_map[0],
|
||||
lll->data_chan_count);
|
||||
|
||||
/* Start setting up of Radio h/w */
|
||||
radio_reset();
|
||||
#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
|
||||
|
||||
radio_aa_set(lll->access_addr);
|
||||
radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
|
||||
(((uint32_t)lll->crc_init[2] << 16) |
|
||||
((uint32_t)lll->crc_init[1] << 8) |
|
||||
((uint32_t)lll->crc_init[0])));
|
||||
lll_chan_set(data_chan_use);
|
||||
|
||||
/* setup the radio tx packet buffer */
|
||||
lll_conn_tx_pkt_set(lll, pdu_data_tx);
|
||||
|
||||
radio_isr_set(lll_conn_isr_tx, lll);
|
||||
|
||||
radio_tmr_tifs_set(EVENT_IFS_US);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
radio_switch_complete_and_rx(lll->phy_rx);
|
||||
#else /* !CONFIG_BT_CTLR_PHY */
|
||||
radio_switch_complete_and_rx(0);
|
||||
#endif /* !CONFIG_BT_CTLR_PHY */
|
||||
|
||||
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;
|
||||
remainder_us = radio_tmr_start(1, ticks_at_start, remainder);
|
||||
|
||||
/* 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();
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
radio_gpio_pa_lna_enable(remainder_us +
|
||||
radio_tx_ready_delay_get(lll->phy_tx,
|
||||
lll->phy_flags) -
|
||||
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);
|
||||
#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_CONN_BASE + lll->handle),
|
||||
ticks_at_event)) {
|
||||
radio_isr_set(lll_conn_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_M(1);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
int lll_adv_sync_init(void);
|
||||
int lll_adv_sync_reset(void);
|
||||
void lll_adv_sync_prepare(void *param);
|
|
@ -13,6 +13,10 @@ if(CONFIG_BT_LL_SW_SPLIT)
|
|||
CONFIG_BT_CTLR_ADV_EXT
|
||||
ll_sw/nordic/lll/lll_adv_aux.c
|
||||
)
|
||||
zephyr_library_sources_ifdef(
|
||||
CONFIG_BT_CTLR_ADV_PERIODIC
|
||||
ll_sw/nordic/lll/lll_adv_sync.c
|
||||
)
|
||||
endif()
|
||||
if(CONFIG_BT_OBSERVER)
|
||||
zephyr_library_sources(
|
||||
|
|
|
@ -341,6 +341,9 @@ uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type,
|
|||
/* NOTE: TargetA, filled at enable and RPA timeout */
|
||||
|
||||
/* NOTE: AdvA, filled at enable and RPA timeout */
|
||||
|
||||
/* Mark the adv set as created */
|
||||
adv->is_created = 1;
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
} else if (pdu->len == 0) {
|
||||
|
@ -1046,6 +1049,11 @@ int ull_adv_init(void)
|
|||
{
|
||||
int err;
|
||||
|
||||
err = ull_adv_sync_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = init_reset();
|
||||
if (err) {
|
||||
return err;
|
||||
|
@ -1059,6 +1067,11 @@ int ull_adv_reset(void)
|
|||
uint8_t handle;
|
||||
int err;
|
||||
|
||||
err = ull_adv_sync_reset();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
for (handle = 0U; handle < BT_CTLR_ADV_MAX; handle++) {
|
||||
(void)disable(handle);
|
||||
}
|
||||
|
@ -1126,6 +1139,20 @@ uint32_t ull_adv_filter_pol_get(uint8_t handle)
|
|||
return adv->lll.filter_policy;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ADV_EXT)
|
||||
struct ll_adv_set *ull_adv_is_created_get(uint8_t handle)
|
||||
{
|
||||
struct ll_adv_set *adv;
|
||||
|
||||
adv = ull_adv_set_get(handle);
|
||||
if (!adv || !adv->is_created) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return adv;
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
||||
static int init_reset(void)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -22,6 +22,12 @@ uint32_t ull_adv_is_enabled(uint8_t handle);
|
|||
/* Return filter policy used */
|
||||
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_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);
|
||||
|
|
|
@ -50,7 +50,7 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
|
|||
struct ll_adv_set *adv;
|
||||
struct pdu_adv *pdu;
|
||||
|
||||
adv = ull_adv_is_enabled_get(handle);
|
||||
adv = ull_adv_is_created_get(handle);
|
||||
if (!adv) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
@ -64,6 +64,9 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
|
|||
|
||||
lll = &sync->lll;
|
||||
adv->lll.sync = lll;
|
||||
|
||||
ull_hdr_init(&sync->ull);
|
||||
lll_hdr_init(lll, sync);
|
||||
} else {
|
||||
sync = (void *)HDR_LLL2EVT(lll);
|
||||
}
|
||||
|
@ -77,6 +80,8 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
|
|||
pdu->tx_addr = 0U;
|
||||
pdu->rx_addr = 0U;
|
||||
|
||||
pdu->len = 0U;
|
||||
|
||||
if (flags & BIT(6)) {
|
||||
/* TODO: add/remove Tx Power in AUX_SYNC_IND PDU */
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
|
@ -94,21 +99,21 @@ 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_sync;
|
||||
struct lll_adv_sync *lll;
|
||||
struct ll_adv_sync_set *sync;
|
||||
struct ll_adv_set *adv;
|
||||
|
||||
adv = ull_adv_is_enabled_get(handle);
|
||||
adv = ull_adv_is_created_get(handle);
|
||||
if (!adv) {
|
||||
return BT_HCI_ERR_CMD_DISALLOWED;
|
||||
}
|
||||
|
||||
lll_sync = adv->lll.sync;
|
||||
if (!lll_sync) {
|
||||
lll = adv->lll.sync;
|
||||
if (!lll) {
|
||||
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
|
||||
}
|
||||
|
||||
sync = (void *)HDR_LLL2EVT(lll_sync);
|
||||
sync = (void *)HDR_LLL2EVT(lll);
|
||||
|
||||
if (!enable) {
|
||||
/* TODO */
|
||||
|
@ -229,7 +234,7 @@ 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_prepare};
|
||||
static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_sync_prepare};
|
||||
static struct lll_prepare_param p;
|
||||
struct ll_adv_sync_set *sync = param;
|
||||
struct lll_adv_sync *lll;
|
||||
|
|
|
@ -18,6 +18,7 @@ struct ll_adv_set {
|
|||
uint32_t interval;
|
||||
uint8_t sid:4;
|
||||
uint8_t phy_s:3;
|
||||
uint8_t is_created:1;
|
||||
#else /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
uint16_t interval;
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_EXT */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue