Bluetooth: controller: BIG create sends empty BIS PDUs (ULL)

When a BIG is create, it will now start sending empty BIS PDUs;
at least from an ULL perspective, as the LLL support is still
missing.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2020-10-30 11:26:26 +01:00 committed by Carles Cufí
commit 339b9b8df5
7 changed files with 273 additions and 2 deletions

View file

@ -193,6 +193,23 @@ config BT_CTLR_TX_BUFFER_SIZE
Maximum is set to 251 due to implementation limitations (use of
uint8_t for length field in PDU buffer structure).
config BT_CTLR_ISO_TX_BUFFERS
int "Number of Isochronous Tx buffers"
default 3
range 1 19
depends on BT_CTLR_ADV_ISO || BT_CTLR_CENTRAL_ISO || BT_CTLR_PERIPHERAL_ISO
help
Set the number of Isochronous Tx PDUs to be queued for transmission
in the controller.
config BT_CTLR_ISO_TX_BUFFER_SIZE
int "Isochronous Tx buffer size"
range 1 4095
default 27
help
Size of the Isochronous Tx buffers and the value returned in HCI LE
Read Buffer Size V2 command response.
choice BT_CTLR_TX_PWR
prompt "Tx Power"
default BT_CTLR_TX_PWR_0

View file

@ -58,6 +58,11 @@ enum {
TICKER_ID_ADV_SYNC_BASE,
TICKER_ID_ADV_SYNC_LAST = ((TICKER_ID_ADV_SYNC_BASE) +
(CONFIG_BT_CTLR_ADV_SYNC_SET) - 1),
#if defined(CONFIG_BT_CTLR_ADV_ISO)
TICKER_ID_ADV_ISO_BASE,
TICKER_ID_ADV_ISO_LAST = ((TICKER_ID_ADV_ISO_BASE) +
(CONFIG_BT_CTLR_ADV_ISO_SET) - 1),
#endif /* CONFIG_BT_CTLR_ADV_ISO */
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
#endif /* CONFIG_BT_CTLR_ADV_AUX_SET > 0 */
#endif /* CONFIG_BT_CTLR_ADV_EXT */

View file

@ -690,6 +690,17 @@ struct pdu_big_ctrl {
} __packed;
} __packed;
enum pdu_bis_llid {
/** Unframed complete or end fragment */
PDU_BIS_LLID_COMPLETE_END = 0x00,
/** Unframed start or continuation fragment */
PDU_BIS_LLID_START_CONTINUE = 0x01,
/** Framed; one or more segments of a SDU */
PDU_BIS_LLID_FRAMED = 0x02,
/** BIG Control PDU */
PDU_BIS_LLID_CTRL = 0x03,
};
struct pdu_bis {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
uint8_t ll_id:2;

View file

@ -403,6 +403,13 @@ int ll_init(struct k_sem *sem_rx)
}
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_CTLR_ADV_ISO)
err = ull_adv_iso_init();
if (err) {
return err;
}
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_CTLR_USER_EXT)
err = ull_user_init();
if (err) {
@ -450,6 +457,12 @@ void ll_reset(void)
LL_ASSERT(!err);
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC)
/* Reset periodic sync sets */
err = ull_adv_iso_reset();
LL_ASSERT(!err);
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
#if defined(CONFIG_BT_CONN)
#if defined(CONFIG_BT_CENTRAL)
/* Reset initiator */

View file

@ -128,4 +128,7 @@ uint32_t ull_adv_sync_start(struct ll_adv_sync_set *sync,
/* helper function to schedule a mayfly to get sync offset */
void ull_adv_sync_offset_get(struct ll_adv_set *adv);
int ull_adv_iso_init(void);
int ull_adv_iso_reset(void);
#endif /* CONFIG_BT_CTLR_ADV_EXT */

View file

@ -11,20 +11,131 @@
#include "common/log.h"
#include "hal/debug.h"
#include "hal/cpu.h"
#include "hal/ccm.h"
#include "hal/ticker.h"
#include "util/util.h"
#include "util/memq.h"
#include "util/mayfly.h"
#include "util/mem.h"
#include "util/mfifo.h"
#include "ticker/ticker.h"
#include "pdu.h"
#include "ll.h"
#include "lll.h"
#include "lll_vendor.h"
#include "lll_adv.h"
#include "lll_scan.h"
#include "lll_conn.h"
#include "ull_internal.h"
#include "ull_adv_types.h"
#include "ull_adv_internal.h"
static struct ll_adv_iso ll_adv_iso[CONFIG_BT_CTLR_ADV_SET];
static void *adv_iso_free;
static MFIFO_DEFINE(iso_tx, sizeof(struct lll_tx),
CONFIG_BT_CTLR_ISO_TX_BUFFERS);
/* TODO: Share between BIS and CIS */
static struct {
void *free;
uint8_t pool[CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE *
CONFIG_BT_CTLR_ISO_TX_BUFFERS];
} mem_iso_tx;
static struct ll_adv_iso *adv_iso_by_bis_handle_get(uint16_t bis_handle)
{
struct ll_adv_iso *adv_iso;
uint8_t idx;
adv_iso = &ll_adv_iso[0];
for (idx = 0U; idx < CONFIG_BT_CTLR_ADV_SET; idx++, adv_iso++) {
if (adv_iso->is_created &&
(adv_iso->bis_handle == bis_handle)) {
return adv_iso;
}
}
return NULL;
}
void *ll_iso_tx_mem_acquire(void)
{
return mem_acquire(&mem_iso_tx.free);
}
void ll_iso_tx_mem_release(void *tx)
{
mem_release(tx, &mem_iso_tx.free);
}
static int init_reset(void)
{
/* Initialize conn pool. */
mem_init(ll_adv_iso, sizeof(struct ll_adv_iso),
sizeof(ll_adv_iso) / sizeof(struct ll_adv_iso), &adv_iso_free);
/* Initialize tx pool. */
mem_init(mem_iso_tx.pool, CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE,
CONFIG_BT_CTLR_ISO_TX_BUFFERS, &mem_iso_tx.free);
return 0;
}
int ull_adv_iso_init(void)
{
int err;
err = init_reset();
if (err) {
return err;
}
return 0;
}
int ull_adv_iso_reset(void)
{
int err;
/* Re-initialize the Tx mfifo */
MFIFO_INIT(iso_tx);
err = init_reset();
if (err) {
return err;
}
return 0;
}
int ll_iso_tx_mem_enqueue(uint16_t handle, void *tx)
{
struct lll_tx *lll_tx;
struct ll_adv_iso *adv_iso;
uint8_t idx;
adv_iso = adv_iso_by_bis_handle_get(handle);
if (!adv_iso) {
return -EINVAL;
}
idx = MFIFO_ENQUEUE_GET(iso_tx, (void **) &lll_tx);
if (!lll_tx) {
return -ENOBUFS;
}
lll_tx->handle = handle;
lll_tx->node = tx;
MFIFO_ENQUEUE(iso_tx, idx);
return 0;
}
uint8_t ll_adv_iso_by_hci_handle_get(uint8_t hci_handle, uint8_t *handle)
{
@ -72,6 +183,93 @@ uint8_t ll_adv_iso_by_hci_handle_new(uint8_t hci_handle, uint8_t *handle)
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder,
uint16_t lazy, void *param)
{
/* TODO: LLL support for ADV ISO */
#if 0
static memq_link_t link;
static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_iso_prepare};
static struct lll_prepare_param p;
struct ll_adv_iso *adv_iso = param;
struct lll_adv_iso *lll;
uint32_t ret;
uint8_t ref;
DEBUG_RADIO_PREPARE_A(1);
lll = &adv_iso->lll;
/* Increment prepare reference count */
ref = ull_ref_inc(&adv_iso->ull);
LL_ASSERT(ref);
/* Append timing parameters */
p.ticks_at_expire = ticks_at_expire;
p.remainder = remainder;
p.lazy = lazy;
p.param = lll;
mfy.param = &p;
/* Kick LLL prepare */
ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH,
TICKER_USER_ID_LLL, 0, &mfy);
LL_ASSERT(!ret);
DEBUG_RADIO_PREPARE_A(1);
#endif
}
uint32_t ull_adv_iso_start(struct ll_adv_iso *adv_iso, uint32_t ticks_anchor)
{
uint32_t ticks_slot_overhead;
uint32_t volatile ret_cb;
uint32_t iso_interval_us;
uint32_t slot_us;
uint32_t ret;
ull_hdr_init(&adv_iso->ull);
/* TODO: Calc slot_us */
slot_us = EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
slot_us += 1000;
adv_iso->evt.ticks_active_to_start = 0;
adv_iso->evt.ticks_xtal_to_start =
HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US);
adv_iso->evt.ticks_preempt_to_start =
HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US);
adv_iso->evt.ticks_slot = HAL_TICKER_US_TO_TICKS(slot_us);
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
ticks_slot_overhead = MAX(adv_iso->evt.ticks_active_to_start,
adv_iso->evt.ticks_xtal_to_start);
} else {
ticks_slot_overhead = 0;
}
/* TODO: Calculate ISO interval */
/* iso_interval shall be at least SDU interval,
* or integer multiple of SDU interval for unframed PDUs
*/
iso_interval_us = adv_iso->sdu_interval;
ret_cb = TICKER_STATUS_BUSY;
ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
(TICKER_ID_ADV_ISO_BASE + adv_iso->bis_handle),
ticks_anchor, 0,
HAL_TICKER_US_TO_TICKS(iso_interval_us),
HAL_TICKER_REMAINDER(iso_interval_us),
TICKER_NULL_LAZY,
(ll_adv_iso->evt.ticks_slot + ticks_slot_overhead),
ticker_cb, ll_adv_iso,
ull_ticker_status_give, (void *)&ret_cb);
ret = ull_ticker_status_take(ret, &ret_cb);
return 0;
}
static inline struct ll_adv_iso *ull_adv_iso_get(uint8_t handle)
{
if (handle >= CONFIG_BT_CTLR_ADV_SET) {
@ -90,6 +288,8 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis,
struct ll_adv_iso *adv_iso;
struct ll_adv_set *adv;
struct node_rx_pdu *node_rx;
struct pdu_bis *pdu_bis;
struct node_tx *tx;
adv_iso = ull_adv_iso_get(big_handle);
@ -170,6 +370,28 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis,
/* TODO: Add ACAD to AUX_SYNC_IND */
/* TODO: start sending BIS empty data packet for each BIS */
ull_adv_iso_start(adv_iso, 0 /* TODO: Calc ticks_anchor */);
tx = ll_iso_tx_mem_acquire();
if (!tx) {
BT_ERR("Tx Buffer Overflow");
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
adv_iso->is_created = true;
pdu_bis = (void *)tx->pdu;
/* Empty BIS packet */
pdu_bis->length = 0;
pdu_bis->ll_id = PDU_BIS_LLID_COMPLETE_END;
pdu_bis->cssn = 0;
pdu_bis->cstf = 0;
if (ll_iso_tx_mem_enqueue(adv_iso->bis_handle, tx)) {
BT_ERR("Invalid Tx Enqueue");
ll_iso_tx_mem_release(tx);
return BT_HCI_ERR_CMD_DISALLOWED;
}
/* Prepare BIG complete event */
node_rx = (void *)&adv_iso->node_rx_complete;

View file

@ -63,7 +63,6 @@ struct ll_adv_sync_set {
struct ll_adv_iso {
struct evt_hdr evt;
struct ull_hdr ull;
struct ll_adv_aux_set adv_aux;
struct lll_adv_iso lll;
uint8_t hci_handle;
@ -86,6 +85,7 @@ struct ll_adv_iso {
uint8_t bcode[16];
struct node_rx_hdr *node_rx_complete;
struct pdu_bis pdu;
};
#endif /* CONFIG_BT_CTLR_ADV_EXT */