diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c new file mode 100644 index 00000000000..ab4f7491033 --- /dev/null +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#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 +#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; +} diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.h new file mode 100644 index 00000000000..020dd7ac8d4 --- /dev/null +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.h @@ -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); diff --git a/subsys/bluetooth/controller/ll_sw/nrf.cmake b/subsys/bluetooth/controller/ll_sw/nrf.cmake index a01a8ba5077..8b5187c757e 100644 --- a/subsys/bluetooth/controller/ll_sw/nrf.cmake +++ b/subsys/bluetooth/controller/ll_sw/nrf.cmake @@ -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( diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index 84b9fd42a06..0bda5961ac7 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -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; diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h index 6b590c6f5c3..a834429fcae 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h @@ -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); diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 86f8b082801..95d8dfae821 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -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; diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h index c01dcc2817b..f40087570cf 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h @@ -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 */