From 5a512fbe2f17df1f3cf0772dbcc7933a4e3fcf8d Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 21 Oct 2020 21:14:07 +0200 Subject: [PATCH] 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 --- subsys/bluetooth/controller/Kconfig | 8 + .../bluetooth/controller/Kconfig.ll_sw_split | 1 + subsys/bluetooth/controller/hci/hci.c | 71 ++++++- subsys/bluetooth/controller/include/ll.h | 6 +- subsys/bluetooth/controller/ll_sw/lll.h | 2 + .../controller/ll_sw/nordic/lll/lll_adv.h | 7 + .../bluetooth/controller/ll_sw/ull_adv_iso.c | 187 ++++++++++++++++-- .../controller/ll_sw/ull_adv_types.h | 29 +++ .../init/prj_ctlr_broadcaster_iso.conf | 11 ++ 9 files changed, 300 insertions(+), 22 deletions(-) create mode 100644 tests/bluetooth/init/prj_ctlr_broadcaster_iso.conf diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index d0b18064d74..d6651882244 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -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 diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 331416716a1..fa67ef171bf 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.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 diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index e273a61780b..619167ace6e 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -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 */ diff --git a/subsys/bluetooth/controller/include/ll.h b/subsys/bluetooth/controller/include/ll.h index 5d06a3a6084..8e33bf14b9d 100644 --- a/subsys/bluetooth/controller/include/ll.h +++ b/subsys/bluetooth/controller/include/ll.h @@ -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, diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index 765ea7975d4..8695ad288d0 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -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, diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.h index 43be5be2c35..8b334040c69 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.h @@ -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]; diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 5ef107f1621..34d63f66388 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -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; diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h index 64b925a4c90..07fb4cf9cb1 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h @@ -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 */ diff --git a/tests/bluetooth/init/prj_ctlr_broadcaster_iso.conf b/tests/bluetooth/init/prj_ctlr_broadcaster_iso.conf new file mode 100644 index 00000000000..cd6f57dd75c --- /dev/null +++ b/tests/bluetooth/init/prj_ctlr_broadcaster_iso.conf @@ -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