Bluetooth: controller: Implements ULL handling for BIG create command

Implements handling of the BIG create command in the upper link layer.
Does not yet handle sending any BIS events.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2020-10-21 21:14:07 +02:00 committed by Carles Cufí
parent cc528d37c2
commit 5a512fbe2f
9 changed files with 300 additions and 22 deletions

View file

@ -489,6 +489,14 @@ config BT_CTLR_SYNC_ISO
Enable support for Bluetooth 5.2 LE Isochronous Advertising sync in
the Controller.
config BT_CTLR_ADV_ISO_SET
int "LE Isochronous Channel advertising sets"
depends on BT_CTLR_ADV_ISO
range 1 32
default 1
help
Maximum supported advertising sets.
config BT_CTLR_SYNC_ISO
bool "LE Broadcast Isochronous Channel advertising sync [EXPERIMENTAL]" if BT_LL_SW_SPLIT

View file

@ -29,6 +29,7 @@ config BT_LLL_VENDOR_NORDIC
select BT_CTLR_ADV_EXT_SUPPORT
select BT_CTLR_ADV_PERIODIC_SUPPORT
select BT_CTLR_SYNC_PERIODIC_SUPPORT
select BT_CTLR_ADV_ISO_SUPPORT
select BT_CTLR_CHAN_SEL_2_SUPPORT
select BT_CTLR_MIN_USED_CHAN_SUPPORT
select BT_CTLR_DTM_HCI_SUPPORT

View file

@ -28,9 +28,11 @@
#include "hal/ccm.h"
#include "ll_sw/pdu.h"
#include "ll_sw/lll.h"
#include "ll_sw/lll_adv.h"
#include "ll_sw/lll_scan.h"
#include "ll_sw/lll_sync.h"
#include "ll_sw/lll_conn.h"
#include "ll_sw/ull_adv_types.h"
#include "ll_sw/ull_scan_types.h"
#include "ll_sw/ull_sync_types.h"
#include "ll_sw/ull_conn_types.h"
@ -1377,22 +1379,37 @@ static void le_set_adv_enable(struct net_buf *buf, struct net_buf **evt)
}
#if defined(CONFIG_BT_CTLR_ADV_ISO)
static void le_create_big(struct net_buf *buf, struct net_buf **evt)
static void le_create_big(struct net_buf *buf, struct net_buf **evt,
void **node_rx)
{
struct bt_hci_cp_le_create_big *cmd = (void *)buf->data;
uint8_t status;
uint32_t sdu_interval;
uint16_t max_sdu;
uint16_t max_latency;
uint8_t big_handle;
uint8_t adv_handle;
status = ll_adv_iso_by_hci_handle_new(cmd->big_handle, &big_handle);
if (status) {
*evt = cmd_status(status);
return;
}
status = ll_adv_set_by_hci_handle_get(cmd->adv_handle, &adv_handle);
if (status) {
*evt = cmd_status(status);
return;
}
sdu_interval = sys_get_le24(cmd->sdu_interval);
max_sdu = sys_le16_to_cpu(cmd->max_sdu);
max_latency = sys_le16_to_cpu(cmd->max_latency);
status = ll_big_create(cmd->big_handle, cmd->adv_handle, cmd->num_bis,
status = ll_big_create(big_handle, adv_handle, cmd->num_bis,
sdu_interval, max_sdu, max_latency, cmd->rtn,
cmd->phy, cmd->packing, cmd->framing,
cmd->encryption, cmd->bcode);
cmd->encryption, cmd->bcode, node_rx);
*evt = cmd_status(status);
}
@ -3144,7 +3161,7 @@ static int controller_cmd_handle(uint16_t ocf, struct net_buf *cmd,
#if defined(CONFIG_BT_CTLR_ADV_ISO)
case BT_OCF(BT_HCI_OP_LE_CREATE_BIG):
le_create_big(cmd, evt);
le_create_big(cmd, evt, node_rx);
break;
case BT_OCF(BT_HCI_OP_LE_CREATE_BIG_TEST):
@ -5068,6 +5085,48 @@ static void le_per_adv_sync_lost(struct pdu_data *pdu_data,
sep->handle = sys_cpu_to_le16(node_rx->hdr.handle);
}
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
#if defined(CONFIG_BT_CTLR_ADV_ISO)
static void le_big_complete(struct pdu_data *pdu_data,
struct node_rx_pdu *node_rx,
struct net_buf *buf)
{
struct bt_hci_evt_le_big_complete *sep;
struct ll_adv_iso *adv_iso;
struct node_rx_sync *se;
size_t evt_size;
adv_iso = node_rx->hdr.rx_ftr.param;
evt_size = sizeof(*sep) +
adv_iso->num_bis * sizeof(adv_iso->bis_handle);
adv_iso = node_rx->hdr.rx_ftr.param;
sep = meta_evt(buf, BT_HCI_EVT_LE_BIG_COMPLETE, evt_size);
se = (void *)pdu_data;
sep->status = se->status;
sep->big_handle = sys_cpu_to_le16(node_rx->hdr.handle);
if (sep->status) {
return;
}
/* TODO: Fill values */
sys_put_le24(0, sep->sync_delay);
sys_put_le24(0, sep->latency);
sep->phy = adv_iso->phy;
sep->nse = 0;
sep->bn = 0;
sep->pto = 0;
sep->irc = 0;
sep->max_pdu = 0;
sep->num_bis = adv_iso->num_bis;
/* TODO: Add support for multiple BIS per BIG */
LL_ASSERT(sep->num_bis == 1);
sep->handle[0] = sys_cpu_to_le16(adv_iso->bis_handle);
}
#endif /* CONFIG_BT_CTLR_ADV_ISO */
#endif /* CONFIG_BT_CTLR_ADV_EXT */
#endif /* CONFIG_BT_OBSERVER */
@ -5438,6 +5497,10 @@ static void encode_control(struct node_rx_pdu *node_rx,
le_per_adv_sync_lost(pdu_data, node_rx, buf);
break;
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */
#if defined(CONFIG_BT_CTLR_ADV_ISO)
case NODE_RX_TYPE_BIG_COMPLETE:
le_big_complete(pdu_data, node_rx, buf);
#endif /* CONFIG_BT_CTLR_ADV_ISO */
#endif /* CONFIG_BT_CTLR_ADV_EXT */
#endif /* CONFIG_BT_OBSERVER */

View file

@ -36,7 +36,9 @@ static inline uint8_t ll_adv_set_by_hci_handle_get_or_new(uint8_t hci_handle,
return 0;
}
#endif
uint8_t ll_adv_iso_by_hci_handle_get(uint8_t hci_handle, uint8_t *handle);
uint8_t ll_adv_iso_by_hci_handle_new(uint8_t hci_handle, uint8_t *handle);
;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
#if defined(CONFIG_BT_HCI_RAW)
int ll_adv_cmds_set(uint8_t adv_cmds);
@ -98,7 +100,7 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis,
uint32_t sdu_interval, uint16_t max_sdu,
uint16_t max_latency, uint8_t rtn, uint8_t phy,
uint8_t packing, uint8_t framing, uint8_t encryption,
uint8_t *bcode);
uint8_t *bcode, void **node_rx);
uint8_t ll_big_test_create(uint8_t big_handle, uint8_t adv_handle,
uint8_t num_bis, uint32_t sdu_interval,
uint16_t iso_interval, uint8_t nse, uint16_t max_sdu,

View file

@ -174,6 +174,8 @@ enum node_rx_type {
NODE_RX_TYPE_SYNC_REPORT,
NODE_RX_TYPE_SYNC_LOST,
NODE_RX_TYPE_EXT_ADV_TERMINATE,
NODE_RX_TYPE_BIG_COMPLETE,
NODE_RX_TYPE_BIG_TERMINATE,
NODE_RX_TYPE_SCAN_REQ,
NODE_RX_TYPE_CONNECTION,
NODE_RX_TYPE_TERMINATE,

View file

@ -37,9 +37,16 @@ struct lll_adv_aux {
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
};
struct lll_adv_iso {
struct lll_hdr hdr;
};
struct lll_adv_sync {
struct lll_hdr hdr;
struct lll_adv *adv;
#if defined(CONFIG_BT_CTLR_ADV_ISO)
struct lll_adv_iso *adv_iso;
#endif /* CONFIG_BT_CTLR_ADV_ISO */
uint8_t access_addr[4];
uint8_t crc_init[3];

View file

@ -10,28 +10,176 @@
#define LOG_MODULE_NAME bt_ctlr_ull_adv_iso
#include "common/log.h"
#include "hal/debug.h"
#include "hal/cpu.h"
#include "util/util.h"
#include "util/memq.h"
#include "pdu.h"
#include "ll.h"
#include "lll.h"
#include "lll_adv.h"
#include "lll_scan.h"
#include "ull_adv_types.h"
#include "ull_adv_internal.h"
static struct ll_adv_iso ll_adv_iso[CONFIG_BT_CTLR_ADV_SET];
uint8_t ll_adv_iso_by_hci_handle_get(uint8_t hci_handle, uint8_t *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->hci_handle == hci_handle)) {
*handle = idx;
return 0;
}
}
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
}
uint8_t ll_adv_iso_by_hci_handle_new(uint8_t hci_handle, uint8_t *handle)
{
struct ll_adv_iso *adv_iso, *adv_iso_empty;
uint8_t idx;
adv_iso = &ll_adv_iso[0];
adv_iso_empty = NULL;
for (idx = 0U; idx < CONFIG_BT_CTLR_ADV_SET; idx++, adv_iso++) {
if (adv_iso->is_created) {
if (adv_iso->hci_handle == hci_handle) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
} else if (!adv_iso_empty) {
adv_iso_empty = adv_iso;
*handle = idx;
}
}
if (adv_iso_empty) {
memset(adv_iso_empty, 0, sizeof(*adv_iso_empty));
adv_iso_empty->hci_handle = hci_handle;
return 0;
}
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
static inline struct ll_adv_iso *ull_adv_iso_get(uint8_t handle)
{
if (handle >= CONFIG_BT_CTLR_ADV_SET) {
return NULL;
}
return &ll_adv_iso[handle];
}
uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis,
uint32_t sdu_interval, uint16_t max_sdu,
uint16_t max_latency, uint8_t rtn, uint8_t phy,
uint8_t packing, uint8_t framing, uint8_t encryption,
uint8_t *bcode)
uint8_t *bcode, void **rx)
{
/* TODO: Implement */
ARG_UNUSED(big_handle);
ARG_UNUSED(adv_handle);
ARG_UNUSED(num_bis);
ARG_UNUSED(sdu_interval);
ARG_UNUSED(max_sdu);
ARG_UNUSED(max_latency);
ARG_UNUSED(rtn);
ARG_UNUSED(phy);
ARG_UNUSED(packing);
ARG_UNUSED(framing);
ARG_UNUSED(encryption);
ARG_UNUSED(bcode[16]);
struct ll_adv_iso *adv_iso;
struct ll_adv_set *adv;
struct node_rx_pdu *node_rx;
return BT_HCI_ERR_CMD_DISALLOWED;
adv_iso = ull_adv_iso_get(big_handle);
if (!adv_iso) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
adv = ull_adv_is_created_get(adv_handle);
if (!adv) {
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
} else if (!adv->lll.sync) {
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
} else if (adv->lll.sync->adv_iso) {
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
}
if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) {
if (num_bis == 0 || num_bis > 0x1F) {
return BT_HCI_ERR_INVALID_PARAM;
}
if (sdu_interval < 0x000100 || sdu_interval > 0x0FFFFF) {
return BT_HCI_ERR_INVALID_PARAM;
}
if (max_sdu < 0x0001 || max_sdu > 0x0FFF) {
return BT_HCI_ERR_INVALID_PARAM;
}
if (max_latency > 0x0FA0) {
return BT_HCI_ERR_INVALID_PARAM;
}
if (rtn > 0x0F) {
return BT_HCI_ERR_INVALID_PARAM;
}
if (phy > (BT_HCI_LE_EXT_SCAN_PHY_1M |
BT_HCI_LE_EXT_SCAN_PHY_2M |
BT_HCI_LE_EXT_SCAN_PHY_CODED)) {
return BT_HCI_ERR_INVALID_PARAM;
}
if (packing > 1) {
return BT_HCI_ERR_INVALID_PARAM;
}
if (framing > 1) {
return BT_HCI_ERR_INVALID_PARAM;
}
if (encryption > 1) {
return BT_HCI_ERR_INVALID_PARAM;
}
}
/* TODO: Allow more than 1 BIS in a BIG */
if (num_bis != 1) {
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
/* TODO: For now we can just use the unique BIG handle as the BIS
* handle until we support multiple BIS
*/
adv_iso->bis_handle = big_handle;
adv_iso->num_bis = num_bis;
adv_iso->sdu_interval = sdu_interval;
adv_iso->max_sdu = max_sdu;
adv_iso->max_latency = max_latency;
adv_iso->rtn = rtn;
adv_iso->phy = phy;
adv_iso->packing = packing;
adv_iso->framing = framing;
adv_iso->encryption = encryption;
memcpy(adv_iso->bcode, bcode, sizeof(adv_iso->bcode));
/* TODO: Add ACAD to AUX_SYNC_IND */
/* TODO: start sending BIS empty data packet for each BIS */
/* Prepare BIG complete event */
node_rx = (void *)&adv_iso->node_rx_complete;
node_rx->hdr.type = NODE_RX_TYPE_BIG_COMPLETE;
node_rx->hdr.handle = big_handle;
node_rx->hdr.rx_ftr.param = adv_iso;
*rx = node_rx;
return 0;
}
uint8_t ll_big_test_create(uint8_t big_handle, uint8_t adv_handle,
@ -64,8 +212,15 @@ uint8_t ll_big_test_create(uint8_t big_handle, uint8_t adv_handle,
uint8_t ll_big_terminate(uint8_t big_handle, uint8_t reason)
{
struct ll_adv_iso *adv_iso;
adv_iso = ull_adv_iso_get(big_handle);
if (!adv_iso) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
/* TODO: Implement */
ARG_UNUSED(big_handle);
ARG_UNUSED(reason);
return BT_HCI_ERR_CMD_DISALLOWED;

View file

@ -59,4 +59,33 @@ struct ll_adv_sync_set {
uint8_t is_enabled:1;
uint8_t is_started:1;
};
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;
uint16_t bis_handle; /* TODO: Support multiple BIS per BIG */
uint8_t is_created:1;
uint8_t encryption:1;
uint8_t framing:1;
uint8_t num_bis:5;
uint32_t sdu_interval:20;
uint16_t max_sdu:12;
uint16_t max_latency:12;
uint8_t rtn:4;
uint8_t phy:3;
uint8_t packing:1;
uint8_t bcode[16];
struct node_rx_hdr *node_rx_complete;
};
#endif /* CONFIG_BT_CTLR_ADV_EXT */

View file

@ -0,0 +1,11 @@
CONFIG_BT=y
CONFIG_BT_CTLR=y
CONFIG_BT_BROADCASTER=y
CONFIG_BT_PERIPHERAL=n
CONFIG_BT_OBSERVER=n
CONFIG_BT_CENTRAL=n
CONFIG_BT_EXT_ADV=y
CONFIG_BT_LL_SW_SPLIT=y
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_CTLR_ADV_ISO=y
CONFIG_ZTEST=y