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:
parent
cc528d37c2
commit
5a512fbe2f
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
11
tests/bluetooth/init/prj_ctlr_broadcaster_iso.conf
Normal file
11
tests/bluetooth/init/prj_ctlr_broadcaster_iso.conf
Normal 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
|
Loading…
Reference in a new issue