blob: c2a17dd2f141081bedbc4c672172ec506d57f01a [file] [log] [blame]
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <soc.h>
#include "hal/cpu.h"
#include "hal/ccm.h"
#include "hal/radio.h"
#include "hal/ticker.h"
#include "util/util.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.h"
#include "lll_adv_sync.h"
#include "lll_internal.h"
#include "lll_adv_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_adv_sync
#include "common/log.h"
#include "hal/debug.h"
static int init_reset(void);
static int prepare_cb(struct lll_prepare_param *p);
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;
struct lll_adv_sync *lll;
uint16_t elapsed;
int err;
err = lll_hfclock_on();
LL_ASSERT(err >= 0);
p = param;
/* Instants elapsed */
elapsed = p->lazy + 1;
lll = p->param;
/* Save the (latency + 1) for use in event */
lll->latency_prepare += elapsed;
/* Invoke common pipeline handling of prepare */
err = lll_prepare(lll_is_abort_cb, lll_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 *p)
{
struct lll_adv_sync *lll;
uint32_t ticks_at_event;
uint32_t ticks_at_start;
uint16_t event_counter;
uint8_t data_chan_use;
struct pdu_adv *pdu;
struct evt_hdr *evt;
uint32_t remainder;
uint32_t start_us;
uint8_t phy_s;
uint8_t upd;
DEBUG_RADIO_START_A(1);
lll = p->param;
/* Deduce the latency */
lll->latency_event = lll->latency_prepare - 1;
/* Calculate the current event counter value */
event_counter = lll->event_counter + lll->latency_event;
/* Update event counter to next value */
lll->event_counter = lll->event_counter + lll->latency_prepare;
/* Reset accumulated latencies */
lll->latency_prepare = 0;
/* Calculate the radio channel to use */
data_chan_use = lll_chan_sel_2(event_counter, 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
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));
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);
pdu = lll_adv_sync_data_latest_get(lll, &upd);
radio_pkt_tx_set(pdu);
/* TODO: chaining */
radio_isr_set(lll_isr_done, lll);
radio_switch_complete_and_disable();
ticks_at_event = p->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 = p->remainder;
start_us = radio_tmr_start(1, ticks_at_start, remainder);
#if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
radio_gpio_pa_setup();
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_SYNC_BASE +
ull_adv_sync_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;
}