Bluetooth: controller: Enable back-to-back chaining for periodic adv
This enables chaining ota for periodic advertising. AUX_CHAIN_IND PDUs will be sent automatically if AuxPtr is detected in preceding PDU. AuxPtr offset is always set to achieve minimal required frame spacing, i.e. 300us (T_mafs). AuxPtr in all PDUs in advertising train are updated on enqueue since PDU spacing is already known at that time so we do not need to waste time in LLL. Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
This commit is contained in:
parent
21892eecf1
commit
7c81ed71d0
6 changed files with 197 additions and 12 deletions
|
@ -172,6 +172,26 @@ config BT_CTLR_ADV_PDU_LINK
|
||||||
is required to enable advertising data trains (i.e. transmission of
|
is required to enable advertising data trains (i.e. transmission of
|
||||||
AUX_CHAIN_IND).
|
AUX_CHAIN_IND).
|
||||||
|
|
||||||
|
config BT_CTLR_ADV_SYNC_PDU_BACK2BACK
|
||||||
|
bool "Enable back-to-back transmission of periodic advertising trains"
|
||||||
|
depends on BT_CTLR_ADV_PERIODIC
|
||||||
|
select BT_CTLR_ADV_PDU_LINK
|
||||||
|
help
|
||||||
|
Enables transmission of AUX_CHAIN_IND in periodic advertising train by
|
||||||
|
sending each AUX_CHAIN_IND one after another back-to-back.
|
||||||
|
Note, consecutive AUX_CHAIN_IND packets are not scheduled but sent at
|
||||||
|
a constant offset on a best effort basis. This means advertising train can
|
||||||
|
be preempted by other event at any time.
|
||||||
|
|
||||||
|
config BT_CTLR_ADV_SYNC_PDU_BACK2BACK_AFS
|
||||||
|
int "AUX Frame Space for back-to-back transmission of periodic advertising trains"
|
||||||
|
depends on BT_CTLR_ADV_SYNC_PDU_BACK2BACK
|
||||||
|
default 300
|
||||||
|
range 300 1000
|
||||||
|
help
|
||||||
|
Specific AUX Frame Space to be used for back-to-back transmission of
|
||||||
|
periodic advertising trains. Time specified in microseconds.
|
||||||
|
|
||||||
config BT_CTLR_ADV_DATA_BUF_MAX
|
config BT_CTLR_ADV_DATA_BUF_MAX
|
||||||
int "Advertising Data Maximum Buffers"
|
int "Advertising Data Maximum Buffers"
|
||||||
depends on BT_BROADCASTER
|
depends on BT_BROADCASTER
|
||||||
|
|
|
@ -27,6 +27,9 @@ struct lll_adv_sync {
|
||||||
uint32_t ticks_offset;
|
uint32_t ticks_offset;
|
||||||
|
|
||||||
struct lll_adv_pdu data;
|
struct lll_adv_pdu data;
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
||||||
|
struct pdu_adv *last_pdu;
|
||||||
|
#endif /* CONFIG_BT_CTLR_ADV_PDU_LINK */
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_ADV_ISO)
|
#if defined(CONFIG_BT_CTLR_ADV_ISO)
|
||||||
struct lll_adv_iso *iso;
|
struct lll_adv_iso *iso;
|
||||||
|
|
|
@ -91,6 +91,10 @@ static inline struct pdu_adv *lll_adv_aux_data_curr_get(struct lll_adv_aux *lll)
|
||||||
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
|
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
|
||||||
int lll_adv_and_extra_data_release(struct lll_adv_pdu *pdu);
|
int lll_adv_and_extra_data_release(struct lll_adv_pdu *pdu);
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
|
||||||
|
void lll_adv_sync_pdu_b2b_update(struct lll_adv_sync *lll, uint8_t idx);
|
||||||
|
#endif
|
||||||
|
|
||||||
struct pdu_adv *lll_adv_pdu_and_extra_data_alloc(struct lll_adv_pdu *pdu,
|
struct pdu_adv *lll_adv_pdu_and_extra_data_alloc(struct lll_adv_pdu *pdu,
|
||||||
void **extra_data,
|
void **extra_data,
|
||||||
uint8_t *idx);
|
uint8_t *idx);
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "lll_internal.h"
|
#include "lll_internal.h"
|
||||||
#include "lll_adv_internal.h"
|
#include "lll_adv_internal.h"
|
||||||
#include "lll_tim_internal.h"
|
#include "lll_tim_internal.h"
|
||||||
|
#include "lll_prof_internal.h"
|
||||||
#include "lll_df_internal.h"
|
#include "lll_df_internal.h"
|
||||||
|
|
||||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||||
|
@ -40,10 +41,21 @@
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "hal/debug.h"
|
#include "hal/debug.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
|
||||||
|
#define ADV_SYNC_PDU_B2B_AFS (CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK_AFS)
|
||||||
|
#endif
|
||||||
|
|
||||||
static int init_reset(void);
|
static int init_reset(void);
|
||||||
static int prepare_cb(struct lll_prepare_param *p);
|
static int prepare_cb(struct lll_prepare_param *p);
|
||||||
static void abort_cb(struct lll_prepare_param *prepare_param, void *param);
|
static void abort_cb(struct lll_prepare_param *prepare_param, void *param);
|
||||||
static void isr_done(void *param);
|
static void isr_done(void *param);
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
|
||||||
|
static void isr_tx(void *param);
|
||||||
|
static void pdu_b2b_update(struct lll_adv_sync *lll, struct pdu_adv *pdu);
|
||||||
|
static void pdu_b2b_aux_ptr_update(struct pdu_adv *pdu, uint8_t phy,
|
||||||
|
uint8_t flags, uint8_t chan_idx,
|
||||||
|
uint32_t tifs);
|
||||||
|
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
|
||||||
|
|
||||||
int lll_adv_sync_init(void)
|
int lll_adv_sync_init(void)
|
||||||
{
|
{
|
||||||
|
@ -148,6 +160,15 @@ static int prepare_cb(struct lll_prepare_param *p)
|
||||||
pdu = lll_adv_sync_data_latest_get(lll, &extra_data, &upd);
|
pdu = lll_adv_sync_data_latest_get(lll, &extra_data, &upd);
|
||||||
LL_ASSERT(pdu);
|
LL_ASSERT(pdu);
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
|
||||||
|
if (upd) {
|
||||||
|
/* AuxPtr offsets for b2b TX are fixed for given chain so we can
|
||||||
|
* calculate them here in advance.
|
||||||
|
*/
|
||||||
|
pdu_b2b_update(lll, pdu);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
||||||
if (extra_data) {
|
if (extra_data) {
|
||||||
df_cfg = (struct lll_df_adv_cfg *)extra_data;
|
df_cfg = (struct lll_df_adv_cfg *)extra_data;
|
||||||
|
@ -162,9 +183,18 @@ static int prepare_cb(struct lll_prepare_param *p)
|
||||||
|
|
||||||
radio_pkt_tx_set(pdu);
|
radio_pkt_tx_set(pdu);
|
||||||
|
|
||||||
/* TODO: chaining */
|
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
|
||||||
radio_isr_set(isr_done, lll);
|
if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
|
||||||
|
lll->last_pdu = pdu;
|
||||||
|
|
||||||
|
radio_isr_set(isr_tx, lll);
|
||||||
|
radio_tmr_tifs_set(ADV_SYNC_PDU_B2B_AFS);
|
||||||
|
radio_switch_complete_and_b2b_tx(phy_s, 0, phy_s, 0);
|
||||||
|
#else
|
||||||
|
if (0) {
|
||||||
|
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
|
||||||
|
} else {
|
||||||
|
radio_isr_set(isr_done, lll);
|
||||||
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
||||||
if (df_cfg) {
|
if (df_cfg) {
|
||||||
radio_switch_complete_and_phy_end_disable();
|
radio_switch_complete_and_phy_end_disable();
|
||||||
|
@ -173,6 +203,7 @@ static int prepare_cb(struct lll_prepare_param *p)
|
||||||
{
|
{
|
||||||
radio_switch_complete_and_disable();
|
radio_switch_complete_and_disable();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ticks_at_event = p->ticks_at_expire;
|
ticks_at_event = p->ticks_at_expire;
|
||||||
ull = HDR_LLL2ULL(lll);
|
ull = HDR_LLL2ULL(lll);
|
||||||
|
@ -256,3 +287,132 @@ static void isr_done(void *param)
|
||||||
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
||||||
lll_isr_done(lll);
|
lll_isr_done(lll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
|
||||||
|
static void isr_tx(void *param)
|
||||||
|
{
|
||||||
|
struct lll_adv_sync *lll_sync;
|
||||||
|
struct pdu_adv *pdu;
|
||||||
|
struct lll_adv *lll;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||||
|
lll_prof_latency_capture();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear radio tx status and events */
|
||||||
|
lll_isr_tx_status_reset();
|
||||||
|
|
||||||
|
lll_sync = param;
|
||||||
|
lll = lll_sync->adv;
|
||||||
|
|
||||||
|
/* TODO: do not hardcode to single value */
|
||||||
|
lll_chan_set(0);
|
||||||
|
|
||||||
|
pdu = lll_adv_pdu_linked_next_get(lll_sync->last_pdu);
|
||||||
|
LL_ASSERT(pdu);
|
||||||
|
lll_sync->last_pdu = pdu;
|
||||||
|
|
||||||
|
/* setup tIFS switching */
|
||||||
|
if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
|
||||||
|
radio_tmr_tifs_set(ADV_SYNC_PDU_B2B_AFS);
|
||||||
|
radio_isr_set(isr_tx, lll_sync);
|
||||||
|
radio_switch_complete_and_b2b_tx(lll->phy_s, 0, lll->phy_s, 0);
|
||||||
|
} else {
|
||||||
|
radio_isr_set(lll_isr_done, lll);
|
||||||
|
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
|
||||||
|
if (lll_sync->cte_started) {
|
||||||
|
radio_switch_complete_and_phy_end_disable();
|
||||||
|
} else
|
||||||
|
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
|
||||||
|
{
|
||||||
|
radio_switch_complete_and_disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
radio_pkt_tx_set(pdu);
|
||||||
|
|
||||||
|
/* assert if radio packet ptr is not set and radio started rx */
|
||||||
|
LL_ASSERT(!radio_is_ready());
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||||
|
lll_prof_cputime_capture();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* capture end of AUX_SYNC_IND/AUX_CHAIN_IND PDU, used for calculating
|
||||||
|
* next PDU timestamp.
|
||||||
|
*/
|
||||||
|
radio_tmr_end_capture();
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
|
||||||
|
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||||
|
/* PA/LNA enable is overwriting packet end used in ISR
|
||||||
|
* profiling, hence back it up for later use.
|
||||||
|
*/
|
||||||
|
lll_prof_radio_end_backup();
|
||||||
|
}
|
||||||
|
|
||||||
|
radio_gpio_lna_setup();
|
||||||
|
radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
|
||||||
|
ADV_SYNC_PDU_B2B_AFS - 4 -
|
||||||
|
radio_tx_chain_delay_get(lll->phy_s, 0) -
|
||||||
|
CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
|
||||||
|
#endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
|
||||||
|
lll_prof_send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pdu_b2b_update(struct lll_adv_sync *lll, struct pdu_adv *pdu)
|
||||||
|
{
|
||||||
|
while (pdu) {
|
||||||
|
pdu_b2b_aux_ptr_update(pdu, lll->adv->phy_s, 0, 0,
|
||||||
|
ADV_SYNC_PDU_B2B_AFS);
|
||||||
|
pdu = lll_adv_pdu_linked_next_get(pdu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pdu_b2b_aux_ptr_update(struct pdu_adv *pdu, uint8_t phy,
|
||||||
|
uint8_t flags, uint8_t chan_idx,
|
||||||
|
uint32_t tifs)
|
||||||
|
{
|
||||||
|
struct pdu_adv_com_ext_adv *com_hdr;
|
||||||
|
struct pdu_adv_ext_hdr *hdr;
|
||||||
|
struct pdu_adv_aux_ptr *aux;
|
||||||
|
uint32_t offs;
|
||||||
|
uint8_t *dptr;
|
||||||
|
|
||||||
|
com_hdr = &pdu->adv_ext_ind;
|
||||||
|
hdr = &com_hdr->ext_hdr;
|
||||||
|
/* Skip flags */
|
||||||
|
dptr = hdr->data;
|
||||||
|
|
||||||
|
if (!com_hdr->ext_hdr_len || !hdr->aux_ptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_ASSERT(!hdr->adv_addr);
|
||||||
|
LL_ASSERT(!hdr->tgt_addr);
|
||||||
|
|
||||||
|
if (hdr->cte_info) {
|
||||||
|
dptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_ASSERT(!hdr->adi);
|
||||||
|
|
||||||
|
/* Update AuxPtr */
|
||||||
|
aux = (void *)dptr;
|
||||||
|
offs = PKT_AC_US(pdu->len, phy) + tifs;
|
||||||
|
offs = offs / OFFS_UNIT_30_US;
|
||||||
|
if ((offs >> 13) != 0) {
|
||||||
|
aux->offs = offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US);
|
||||||
|
aux->offs_units = 1U;
|
||||||
|
} else {
|
||||||
|
aux->offs = offs;
|
||||||
|
aux->offs_units = 0U;
|
||||||
|
}
|
||||||
|
aux->chan_idx = chan_idx;
|
||||||
|
aux->ca = 0;
|
||||||
|
aux->phy = find_lsb_set(phy) - 1;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
|
||||||
|
|
|
@ -146,7 +146,7 @@ void lll_scan_prepare_connect_req(struct lll_scan *lll, struct pdu_adv *pdu_tx,
|
||||||
|
|
||||||
conn_interval_us = (uint32_t)lll_conn->interval * CONN_INT_UNIT_US;
|
conn_interval_us = (uint32_t)lll_conn->interval * CONN_INT_UNIT_US;
|
||||||
conn_offset_us = radio_tmr_end_get() + EVENT_IFS_US +
|
conn_offset_us = radio_tmr_end_get() + EVENT_IFS_US +
|
||||||
PKT_AC_US(sizeof(struct pdu_adv_connect_ind), 0,
|
PKT_AC_US(sizeof(struct pdu_adv_connect_ind),
|
||||||
phy == PHY_LEGACY ? PHY_1M : phy);
|
phy == PHY_LEGACY ? PHY_1M : phy);
|
||||||
|
|
||||||
/* Add transmitWindowDelay to default calculated connection offset:
|
/* Add transmitWindowDelay to default calculated connection offset:
|
||||||
|
|
|
@ -434,11 +434,9 @@ static int isr_rx_pdu(struct lll_scan_aux *lll, uint8_t devmatch_ok,
|
||||||
ull = HDR_LLL2ULL(lll_scan);
|
ull = HDR_LLL2ULL(lll_scan);
|
||||||
if (pdu_end_us > (HAL_TICKER_TICKS_TO_US(ull->ticks_slot) -
|
if (pdu_end_us > (HAL_TICKER_TICKS_TO_US(ull->ticks_slot) -
|
||||||
EVENT_IFS_US -
|
EVENT_IFS_US -
|
||||||
PKT_AC_US(aux_connect_req_len, 0,
|
PKT_AC_US(aux_connect_req_len, lll->phy) -
|
||||||
lll->phy) -
|
|
||||||
EVENT_IFS_US -
|
EVENT_IFS_US -
|
||||||
PKT_AC_US(aux_connect_rsp_len, 0,
|
PKT_AC_US(aux_connect_rsp_len, lll->phy) -
|
||||||
lll->phy) -
|
|
||||||
EVENT_OVERHEAD_START_US -
|
EVENT_OVERHEAD_START_US -
|
||||||
EVENT_TICKER_RES_MARGIN_US)) {
|
EVENT_TICKER_RES_MARGIN_US)) {
|
||||||
return -ETIME;
|
return -ETIME;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue