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:
Vinayak Kariappa Chettimada 2020-03-13 16:24:01 +05:30 committed by Carles Cufí
commit 5949205315
7 changed files with 256 additions and 7 deletions

View 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;
}

View file

@ -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);

View file

@ -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(

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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 */