diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 4781a806b9c..0d49c28ac55 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -199,7 +199,7 @@ 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 + depends on BT_CTLR_ADV_ISO || BT_CTLR_SYNC_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. @@ -502,7 +502,7 @@ config BT_CTLR_ADV_ISO config BT_CTLR_SYNC_ISO bool "LE Broadcast Isochronous Channel advertising sync" if !BT_LL_SW_SPLIT - depends on BT_BROADCASTER && BT_CTLR_ADV_ISO_SUPPORT + depends on BT_OBSERVER && BT_CTLR_SYNC_ISO_SUPPORT select BT_CTLR_SYNC_PERIODIC help Enable support for Bluetooth 5.2 LE Isochronous Advertising sync in diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 9f37f597a17..689cef90df2 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -30,6 +30,7 @@ config BT_LLL_VENDOR_NORDIC select BT_CTLR_ADV_PERIODIC_SUPPORT select BT_CTLR_SYNC_PERIODIC_SUPPORT select BT_CTLR_ADV_ISO_SUPPORT + select BT_CTLR_SYNC_ISO_SUPPORT select BT_CTLR_DF_SUPPORT if HAS_HW_NRF_RADIO_BLE_DF select BT_CTLR_CHAN_SEL_2_SUPPORT select BT_CTLR_MIN_USED_CHAN_SUPPORT @@ -192,6 +193,14 @@ config BT_CTLR_SCAN_SYNC_SET help Maximum supported periodic sync sets. +config BT_CTLR_SCAN_SYNC_ISO_MAX + int "Maximum Broadcast Isochronous Groups syncs" + depends on BT_CTLR_SYNC_ISO + range 1 64 + default 1 + help + Maximum supported broadcast isochronous groups (BIGs) syncs. + config BT_CTLR_ZLI bool "Use Zero Latency IRQs" depends on ZERO_LATENCY_IRQS diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index eb1a13f80e6..2e67975716f 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -29,6 +29,7 @@ #include "ll_sw/pdu.h" #include "ll_sw/lll.h" #include "lll_adv.h" +#include "lll_sync_iso.h" #include "ll_sw/lll_scan.h" #include "ll_sw/lll_sync.h" #include "ll_sw/lll_conn.h" diff --git a/subsys/bluetooth/controller/ll_sw/lll.h b/subsys/bluetooth/controller/ll_sw/lll.h index ddea18d6b6b..bf87bd9e51d 100644 --- a/subsys/bluetooth/controller/ll_sw/lll.h +++ b/subsys/bluetooth/controller/ll_sw/lll.h @@ -176,6 +176,8 @@ enum node_rx_type { NODE_RX_TYPE_SYNC, NODE_RX_TYPE_SYNC_REPORT, NODE_RX_TYPE_SYNC_LOST, + NODE_RX_TYPE_SYNC_ISO, + NODE_RX_TYPE_SYNC_ISO_LOST, NODE_RX_TYPE_EXT_ADV_TERMINATE, NODE_RX_TYPE_BIG_COMPLETE, NODE_RX_TYPE_BIG_TERMINATE, diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index f427878d17e..f51312a8a4e 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -10,6 +10,7 @@ #include #include +#include #include "hal/cpu.h" #include "hal/ccm.h" @@ -42,7 +43,6 @@ #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) #define LOG_MODULE_NAME bt_ctlr_lll_adv #include "common/log.h" -#include #include "hal/debug.h" static int init_reset(void); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c index 398f2daa4cd..ee0e79424c8 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c @@ -9,6 +9,7 @@ #include #include +#include #include "hal/cpu.h" #include "hal/ccm.h" @@ -36,7 +37,6 @@ #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) #define LOG_MODULE_NAME bt_ctlr_lll_adv_aux #include "common/log.h" -#include #include "hal/debug.h" static uint8_t lll_adv_connect_rsp_pdu[PDU_AC_LL_HEADER_SIZE + diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.h b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.h new file mode 100644 index 00000000000..6a96f19a8df --- /dev/null +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync_iso.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +struct lll_sync_iso { + struct lll_hdr hdr; + uint8_t is_enabled:1; +}; diff --git a/subsys/bluetooth/controller/ll_sw/pdu.h b/subsys/bluetooth/controller/ll_sw/pdu.h index 42a487db46f..37dc230e720 100644 --- a/subsys/bluetooth/controller/ll_sw/pdu.h +++ b/subsys/bluetooth/controller/ll_sw/pdu.h @@ -732,3 +732,59 @@ struct pdu_bis { struct pdu_big_ctrl ctrl; } __packed; } __packed; + +struct pdu_biginfo { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + uint32_t offset:14; + uint32_t offset_units:1; + uint32_t iso_interval:12; + uint32_t num_bis:5; + + uint32_t nse:5; + uint32_t bn:3; + uint32_t sub_interval:20; + uint32_t pto:4; + + uint32_t spacing:20; + uint32_t irc:4; + uint32_t max_pdu:8; + + uint8_t rfu; + + uint32_t seed_access_addr; + + uint32_t sdu_interval:20; + uint32_t max_sdu:12; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint32_t num_bis:5; + uint32_t iso_interval:12; + uint32_t offset_units:1; + uint32_t offset:14; + + uint32_t pto:4; + uint32_t sub_interval:20; + uint32_t bn:3; + uint32_t nse:5; + + uint32_t max_pdu:8; + uint32_t irc:4; + uint32_t spacing:20; + + uint8_t rfu; + + uint32_t seed_access_addr; + + uint32_t max_sdu:12; + uint32_t sdu_interval:20; +#else +#error "Unsupported endianness" +#endif /* __BYTE_ORDER__ */ + + uint16_t base_crc_init; + + uint8_t chm_phy[5]; /* 37 bit chm; 3 bit phy */ + uint8_t payload_count_framing[5]; /* 39 bit count; 1 bit framing */ + + uint8_t giv; /* encryption required */ + uint16_t gskd; /* encryption required */ +} __packed; diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 8c6ebc88329..a59a65ee3bb 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -36,6 +36,7 @@ #include "lll_adv.h" #include "lll_scan.h" #include "lll_sync.h" +#include "lll_sync_iso.h" #include "lll_conn.h" #include "ull_adv_types.h" #include "ull_scan_types.h" @@ -48,6 +49,7 @@ #include "ull_adv_internal.h" #include "ull_scan_internal.h" #include "ull_sync_internal.h" +#include "ull_sync_iso_internal.h" #include "ull_conn_internal.h" #include "ull_df.h" @@ -391,6 +393,13 @@ int ll_init(struct k_sem *sem_rx) if (err) { return err; } + +#if defined(CONFIG_BT_CTLR_SYNC_ISO) + err = ull_sync_iso_init(); + if (err) { + return err; + } +#endif /* CONFIG_BT_CTLR_SYNC_ISO */ #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ #if defined(CONFIG_BT_CONN) @@ -476,6 +485,11 @@ void ll_reset(void) /* Reset periodic sync sets */ err = ull_sync_reset(); LL_ASSERT(!err); +#if defined(CONFIG_BT_CTLR_SYNC_ISO) + /* Reset periodic sync sets */ + err = ull_sync_iso_reset(); + LL_ASSERT(!err); +#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ #endif /* CONFIG_BT_CTLR_SYNC_PERIODIC */ #if defined(CONFIG_BT_CTLR_ADV_ISO) || \ diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index f1d21eb2042..8e429385350 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -22,6 +22,7 @@ #include "lll_scan.h" #include "lll_scan_aux.h" #include "lll_sync.h" +#include "lll_sync_iso.h" #include "ull_scan_types.h" #include "ull_sync_types.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index af599702b07..82f79bb55ab 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -27,6 +27,7 @@ #include "lll_clock.h" #include "lll_scan.h" #include "lll_sync.h" +#include "lll_sync_iso.h" #include "ull_scan_types.h" #include "ull_sync_types.h" @@ -43,7 +44,6 @@ static int init_reset(void); static inline struct ll_sync_set *sync_acquire(void); -static struct ll_sync_set *is_enabled_get(uint16_t handle); static void timeout_cleanup(struct ll_sync_set *sync); static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, uint16_t lazy, void *param); @@ -237,7 +237,7 @@ uint8_t ll_sync_terminate(uint16_t handle) struct ll_sync_set *sync; int err; - sync = is_enabled_get(handle); + sync = ull_sync_is_enabled_get(handle); if (!sync) { return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER; } @@ -296,6 +296,18 @@ struct ll_sync_set *ull_sync_set_get(uint16_t handle) return &ll_sync_pool[handle]; } +struct ll_sync_set *ull_sync_is_enabled_get(uint16_t handle) +{ + struct ll_sync_set *sync; + + sync = ull_sync_set_get(handle); + if (!sync || !sync->timeout_reload) { + return NULL; + } + + return sync; +} + uint16_t ull_sync_handle_get(struct ll_sync_set *sync) { return mem_index_get(sync, ll_sync_pool, sizeof(struct ll_sync_set)); @@ -548,18 +560,6 @@ static inline struct ll_sync_set *sync_acquire(void) return mem_acquire(&sync_free); } -static struct ll_sync_set *is_enabled_get(uint16_t handle) -{ - struct ll_sync_set *sync; - - sync = ull_sync_set_get(handle); - if (!sync || !sync->timeout_reload) { - return NULL; - } - - return sync; -} - static void timeout_cleanup(struct ll_sync_set *sync) { uint16_t sync_handle = ull_sync_handle_get(sync); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h b/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h index 9924c8221c9..bea57fdb252 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_internal.h @@ -7,6 +7,7 @@ int ull_sync_init(void); int ull_sync_reset(void); uint16_t ull_sync_handle_get(struct ll_sync_set *sync); +struct ll_sync_set *ull_sync_is_enabled_get(uint16_t handle); void ull_sync_release(struct ll_sync_set *sync); void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, struct node_rx_hdr *node_rx, struct pdu_adv_sync_info *si); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 50cb417a303..af1fcff81b3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -11,29 +11,195 @@ #include "common/log.h" #include "hal/debug.h" +#include "util/util.h" +#include "util/mem.h" +#include "util/memq.h" +#include "util/mayfly.h" + +#include "hal/ccm.h" +#include "hal/radio.h" +#include "hal/ticker.h" + +#include "ticker/ticker.h" + +#include "pdu.h" +#include "ll.h" + +#include "lll.h" +#include "lll_vendor.h" +#include "lll_clock.h" +#include "lll_scan.h" +#include "lll_sync.h" +#include "lll_sync_iso.h" + +#include "ull_scan_types.h" +#include "ull_sync_types.h" + +#include "ull_internal.h" +#include "ull_scan_internal.h" +#include "ull_sync_internal.h" +#include "ull_sync_iso_internal.h" + +static struct ll_sync_iso ll_sync_iso_pool[CONFIG_BT_CTLR_SCAN_SYNC_ISO_MAX]; +static void *sync_iso_free; + +static int init_reset(void); +static inline struct ll_sync_iso *sync_iso_acquire(void); + uint8_t ll_big_sync_create(uint8_t big_handle, uint16_t sync_handle, uint8_t encryption, uint8_t *bcode, uint8_t mse, uint16_t sync_timeout, uint8_t num_bis, uint8_t *bis) { - /* TODO: Implement */ - ARG_UNUSED(big_handle); - ARG_UNUSED(sync_handle); - ARG_UNUSED(encryption); - ARG_UNUSED(bcode); - ARG_UNUSED(mse); - ARG_UNUSED(sync_timeout); - ARG_UNUSED(num_bis); - ARG_UNUSED(bis); + memq_link_t *big_sync_estab; + memq_link_t *big_sync_lost; + struct lll_sync_iso *lll_sync; + struct ll_sync_set *sync; + struct ll_sync_iso *sync_iso; - return BT_HCI_ERR_CMD_DISALLOWED; + sync = ull_sync_is_enabled_get(sync_handle); + if (!sync || sync->sync_iso) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + + sync_iso = sync_iso_acquire(); + if (!sync_iso) { + return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + } + + big_sync_estab = ll_rx_link_alloc(); + if (!big_sync_estab) { + return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + } + + big_sync_lost = ll_rx_link_alloc(); + if (!big_sync_lost) { + ll_rx_link_release(big_sync_estab); + + return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; + } + + sync_iso->node_rx_lost.link = big_sync_lost; + sync_iso->node_rx_estab.link = big_sync_estab; + + lll_sync = &sync_iso->lll; + + /* Initialise ULL and LLL headers */ + ull_hdr_init(&sync_iso->ull); + lll_hdr_init(lll_sync, sync); + lll_sync->is_enabled = true; + + return BT_HCI_ERR_SUCCESS; } - uint8_t ll_big_sync_terminate(uint8_t big_handle) { - /* TODO: Implement */ - ARG_UNUSED(big_handle); + memq_link_t *big_sync_estab; + memq_link_t *big_sync_lost; + struct ll_sync_iso *sync_iso; + void *mark; - return BT_HCI_ERR_CMD_DISALLOWED; + sync_iso = ull_sync_iso_get(big_handle); + if (!sync_iso) { + return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER; + } + + if (!sync_iso->lll.is_enabled) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + + mark = ull_disable_mark(sync_iso); + LL_ASSERT(mark == sync_iso); + + /* TODO: Stop ticker */ + + mark = ull_disable_unmark(sync_iso); + LL_ASSERT(mark == sync_iso); + + big_sync_lost = sync_iso->node_rx_lost.link; + ll_rx_link_release(big_sync_lost); + + big_sync_estab = sync_iso->node_rx_estab.link; + ll_rx_link_release(big_sync_estab); + + sync_iso->lll.is_enabled = false; + ull_sync_iso_release(sync_iso); + + return BT_HCI_ERR_SUCCESS; +} + +int ull_sync_iso_init(void) +{ + int err; + + err = init_reset(); + if (err) { + return err; + } + + return 0; +} + +int ull_sync_iso_reset(void) +{ + int err; + + err = init_reset(); + if (err) { + return err; + } + + return 0; +} + +struct ll_sync_iso *ull_sync_iso_get(uint8_t handle) +{ + if (handle >= CONFIG_BT_CTLR_SCAN_SYNC_ISO_MAX) { + return NULL; + } + + return &ll_sync_iso_pool[handle]; +} + +uint8_t ull_sync_iso_handle_get(struct ll_sync_iso *sync) +{ + return mem_index_get(sync, ll_sync_iso_pool, + sizeof(struct ll_sync_iso)); +} + +uint8_t ull_sync_iso_lll_handle_get(struct lll_sync_iso *lll) +{ + return ull_sync_handle_get((void *)HDR_LLL2EVT(lll)); +} + +void ull_sync_iso_release(struct ll_sync_iso *sync_iso) +{ + mem_release(sync_iso, &sync_iso_free); +} + +void ull_sync_iso_setup(struct ll_sync_iso *sync_iso, + struct node_rx_hdr *node_rx, + struct pdu_biginfo *biginfo) +{ + /* TODO: Implement and start ticker. + * Depends on ACAD (biginfo) support + */ + ARG_UNUSED(sync_iso); + ARG_UNUSED(node_rx); + ARG_UNUSED(biginfo); +} + +static int init_reset(void) +{ + /* Initialize sync pool. */ + mem_init(ll_sync_iso_pool, sizeof(struct ll_sync_iso), + sizeof(ll_sync_iso_pool) / sizeof(struct ll_sync_iso), + &sync_iso_free); + + return 0; +} + +static inline struct ll_sync_iso *sync_iso_acquire(void) +{ + return mem_acquire(&sync_iso_free); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso_internal.h b/subsys/bluetooth/controller/ll_sw/ull_sync_iso_internal.h new file mode 100644 index 00000000000..145294c990d --- /dev/null +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso_internal.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +int ull_sync_iso_init(void); +int ull_sync_iso_reset(void); +struct ll_sync_iso *ull_sync_iso_get(uint8_t handle); +uint8_t ull_sync_iso_handle_get(struct ll_sync_iso *sync); +uint8_t ull_sync_iso_lll_handle_get(struct lll_sync_iso *lll); +void ull_sync_iso_release(struct ll_sync_iso *sync_iso); +void ull_sync_iso_setup(struct ll_sync_iso *sync_iso, + struct node_rx_hdr *node_rx, + struct pdu_biginfo *biginfo); diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_types.h b/subsys/bluetooth/controller/ll_sw/ull_sync_types.h index bd67747fa91..1a8f4d36d8b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_types.h @@ -8,6 +8,17 @@ #define LL_SYNC_STATE_ADDR_MATCH 0x01 #define LL_SYNC_STATE_CREATED 0x02 +#if defined(CONFIG_BT_CTLR_SYNC_ISO) +struct ll_sync_iso { + struct evt_hdr evt; + struct ull_hdr ull; + struct lll_sync_iso lll; + + struct node_rx_hdr node_rx_lost; + struct node_rx_hdr node_rx_estab; +}; +#endif /* CONFIG_BT_CTLR_SYNC_ISO */ + struct ll_sync_set { struct evt_hdr evt; struct ull_hdr ull; @@ -29,6 +40,10 @@ struct ll_sync_set { uint8_t reason; }; } node_rx_lost; + +#if defined(CONFIG_BT_CTLR_SYNC_ISO) + struct ll_sync_iso *sync_iso; +#endif /* CONFIG_BT_CTLR_SYNC_ISO */ }; struct node_rx_sync { diff --git a/tests/bluetooth/init/prj_ctlr_sync_iso.conf b/tests/bluetooth/init/prj_ctlr_sync_iso.conf new file mode 100644 index 00000000000..c61443085e1 --- /dev/null +++ b/tests/bluetooth/init/prj_ctlr_sync_iso.conf @@ -0,0 +1,13 @@ +CONFIG_BT=y +CONFIG_BT_CTLR=y +CONFIG_BT_BROADCASTER=n +CONFIG_BT_PERIPHERAL=n +CONFIG_BT_OBSERVER=y +CONFIG_BT_CENTRAL=n +CONFIG_BT_EXT_ADV=y +CONFIG_BT_PER_ADV_SYNC=y +CONFIG_BT_CTLR_ADV_EXT=y +CONFIG_BT_CTLR_SYNC_PERIODIC=y +CONFIG_BT_CTLR_SYNC_ISO=y +CONFIG_BT_LL_SW_SPLIT=y +CONFIG_ZTEST=y