From 2f1a254eae3949423c9250c56769bb478edb4b12 Mon Sep 17 00:00:00 2001 From: Morten Priess Date: Tue, 2 Apr 2024 16:13:02 +0200 Subject: [PATCH] Bluetooth: controller: Implement LE Create BIG Test command Implement test version of the LE Create BIG command ll_big_test_create (BT_HCI_OP_LE_CREATE_BIG_TEST) in the controller. This enables use of CONFIG_BT_ISO_ADVANCED, which supports use of the following BIG/QoS configuration parameters (otherwise derived): - ISO_Interval - NSE - Max_PDU - BN - IRC - PTO Signed-off-by: Morten Priess --- .../bluetooth/controller/ll_sw/ull_adv_iso.c | 261 +++++++++++------- 1 file changed, 160 insertions(+), 101 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 99a19cb0e99..e6ecd840749 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -86,11 +86,13 @@ static struct lll_adv_iso_stream stream_pool[CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT]; static void *stream_free; -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) +static uint8_t 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, + uint16_t iso_interval, uint8_t nse, uint16_t max_pdu, + uint8_t bn, uint8_t irc, uint8_t pto, bool test_config) { uint8_t hdr_data[1 + sizeof(uint8_t *)]; struct lll_adv_sync *lll_adv_sync; @@ -118,7 +120,6 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, uint8_t *acad; uint32_t ret; uint8_t err; - uint8_t bn; int res; adv_iso = adv_iso_get(big_handle); @@ -156,14 +157,6 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, 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)) { @@ -181,6 +174,45 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, if (encryption > 1U) { return BT_HCI_ERR_INVALID_PARAM; } + + if (test_config) { + if (!IN_RANGE(iso_interval, 0x0004, 0x0C80)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!IN_RANGE(nse, 0x01, 0x1F)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!IN_RANGE(max_pdu, 0x01, MIN(0xFB, LL_BIS_OCTETS_TX_MAX))) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!IN_RANGE(bn, 0x01, 0x07)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (!IN_RANGE(irc, 0x01, 0x07)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + /* FIXME: PTO is currently limited to BN */ + if (!IN_RANGE(pto, 0x00, bn /*0x0F*/)) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (bn * irc + pto < nse) { + return BT_HCI_ERR_INVALID_PARAM; + } + } else { + if (max_latency > 0x0FA0) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (rtn > 0x0F) { + return BT_HCI_ERR_INVALID_PARAM; + } + } } /* Check if free BISes available */ @@ -276,7 +308,6 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, /* TODO: Move parameters to ULL if only accessed by ULL */ lll_adv_iso = &adv_iso->lll; lll_adv_iso->handle = big_handle; - lll_adv_iso->max_pdu = MIN(LL_BIS_OCTETS_TX_MAX, max_sdu); lll_adv_iso->phy = phy; lll_adv_iso->phy_flags = PHY_FLAGS_S8; @@ -304,31 +335,43 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, adv_iso_stream_handle_get(stream); } - /* FIXME: SDU per max latency */ - sdu_per_event = MAX((max_latency * USEC_PER_MSEC / sdu_interval), 2U) - - 1U; - - /* BN (Burst Count), Mandatory BN = 1 */ - bn = DIV_ROUND_UP(max_sdu, lll_adv_iso->max_pdu) * sdu_per_event; - if (bn > PDU_BIG_BN_MAX) { - /* Restrict each BIG event to maximum burst per BIG event */ - lll_adv_iso->bn = PDU_BIG_BN_MAX; - - /* Ceil the required burst count per SDU to next maximum burst - * per BIG event. - */ - bn = DIV_ROUND_UP(bn, PDU_BIG_BN_MAX) * PDU_BIG_BN_MAX; - } else { + if (test_config) { lll_adv_iso->bn = bn; - } + lll_adv_iso->iso_interval = iso_interval; + lll_adv_iso->irc = irc; + lll_adv_iso->nse = nse; + lll_adv_iso->max_pdu = max_pdu; + iso_interval_us = iso_interval * PERIODIC_INT_UNIT_US; - /* Calculate ISO interval */ - /* iso_interval shall be at least SDU interval, - * or integer multiple of SDU interval for unframed PDUs - */ - iso_interval_us = ((sdu_interval * lll_adv_iso->bn * sdu_per_event) / - (bn * PERIODIC_INT_UNIT_US)) * PERIODIC_INT_UNIT_US; - lll_adv_iso->iso_interval = iso_interval_us / PERIODIC_INT_UNIT_US; + } else { + lll_adv_iso->max_pdu = MIN(LL_BIS_OCTETS_TX_MAX, max_sdu); + + /* FIXME: SDU per max latency */ + sdu_per_event = MAX((max_latency * USEC_PER_MSEC / sdu_interval), 2U) - + 1U; + + /* BN (Burst Count), Mandatory BN = 1 */ + bn = DIV_ROUND_UP(max_sdu, lll_adv_iso->max_pdu) * sdu_per_event; + if (bn > PDU_BIG_BN_MAX) { + /* Restrict each BIG event to maximum burst per BIG event */ + lll_adv_iso->bn = PDU_BIG_BN_MAX; + + /* Ceil the required burst count per SDU to next maximum burst + * per BIG event. + */ + bn = DIV_ROUND_UP(bn, PDU_BIG_BN_MAX) * PDU_BIG_BN_MAX; + } else { + lll_adv_iso->bn = bn; + } + + /* Calculate ISO interval */ + /* iso_interval shall be at least SDU interval, + * or integer multiple of SDU interval for unframed PDUs + */ + iso_interval_us = ((sdu_interval * lll_adv_iso->bn * sdu_per_event) / + (bn * PERIODIC_INT_UNIT_US)) * PERIODIC_INT_UNIT_US; + lll_adv_iso->iso_interval = iso_interval_us / PERIODIC_INT_UNIT_US; + } /* Calculate max available ISO event spacing */ slot_overhead = HAL_TICKER_TICKS_TO_US(ticks_slot_overhead); @@ -338,42 +381,50 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, event_spacing_max = 0U; } -ll_big_create_rtn_retry: - /* Immediate Repetition Count (IRC), Mandatory IRC = 1 */ - lll_adv_iso->irc = rtn + 1U; + /* Negotiate event spacing */ + do { + if (!test_config) { + /* Immediate Repetition Count (IRC), Mandatory IRC = 1 */ + lll_adv_iso->irc = rtn + 1U; - /* Calculate NSE (No. of Sub Events), Mandatory NSE = 1, - * without PTO added. - */ - lll_adv_iso->nse = lll_adv_iso->bn * lll_adv_iso->irc; + /* Calculate NSE (No. of Sub Events), Mandatory NSE = 1, + * without PTO added. + */ + lll_adv_iso->nse = lll_adv_iso->bn * lll_adv_iso->irc; + } - /* NOTE: Calculate sub_interval, if interleaved then it is Num_BIS x - * BIS_Spacing (by BT Spec.) - * else if sequential, then by our implementation, lets keep it - * max_tx_time for Max_PDU + tMSS. - */ - lll_adv_iso->sub_interval = PDU_BIS_US(lll_adv_iso->max_pdu, encryption, - phy, lll_adv_iso->phy_flags) + - EVENT_MSS_US; - ctrl_spacing = PDU_BIS_US(sizeof(struct pdu_big_ctrl), encryption, phy, - lll_adv_iso->phy_flags); - latency_packing = lll_adv_iso->sub_interval * lll_adv_iso->nse * - lll_adv_iso->num_bis; - event_spacing = latency_packing + ctrl_spacing + - EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + /* NOTE: Calculate sub_interval, if interleaved then it is Num_BIS x + * BIS_Spacing (by BT Spec.) + * else if sequential, then by our implementation, lets keep it + * max_tx_time for Max_PDU + tMSS. + */ + lll_adv_iso->sub_interval = PDU_BIS_US(lll_adv_iso->max_pdu, encryption, + phy, lll_adv_iso->phy_flags) + + EVENT_MSS_US; + ctrl_spacing = PDU_BIS_US(sizeof(struct pdu_big_ctrl), encryption, phy, + lll_adv_iso->phy_flags); + latency_packing = lll_adv_iso->sub_interval * lll_adv_iso->nse * + lll_adv_iso->num_bis; + event_spacing = latency_packing + ctrl_spacing + + EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US; + + /* Check if ISO interval too small to fit the calculated BIG event + * timing required for the supplied BIG create parameters. + */ + if (event_spacing > event_spacing_max) { + /* Check if we can reduce RTN to meet eventing spacing */ + if (!test_config && rtn) { + rtn--; + } else { + break; + } + } + } while (event_spacing > event_spacing_max); /* Check if ISO interval too small to fit the calculated BIG event * timing required for the supplied BIG create parameters. */ if (event_spacing > event_spacing_max) { - - /* Check if we can reduce RTN to meet eventing spacing */ - if (rtn) { - rtn--; - - goto ll_big_create_rtn_retry; - } - /* Release allocated link buffers */ ll_rx_link_release(link_cmplt); ll_rx_link_release(link_term); @@ -381,29 +432,34 @@ ll_big_create_rtn_retry: return BT_HCI_ERR_INVALID_PARAM; } + if (test_config) { + lll_adv_iso->pto = pto; + + } else { + lll_adv_iso->ptc = ptc_calc(lll_adv_iso, event_spacing, + event_spacing_max); + + /* Pre-Transmission Offset (PTO) */ + if (lll_adv_iso->ptc) { + lll_adv_iso->pto = bn / lll_adv_iso->bn; + } else { + lll_adv_iso->pto = 0U; + } + + /* Make room for pre-transmissions */ + lll_adv_iso->nse += lll_adv_iso->ptc; + } + /* Based on packing requested, sequential or interleaved */ if (packing) { /* Interleaved Packing */ lll_adv_iso->bis_spacing = lll_adv_iso->sub_interval; - lll_adv_iso->ptc = ptc_calc(lll_adv_iso, event_spacing, - event_spacing_max); - lll_adv_iso->nse += lll_adv_iso->ptc; lll_adv_iso->sub_interval = lll_adv_iso->bis_spacing * - lll_adv_iso->nse; + lll_adv_iso->nse; } else { /* Sequential Packing */ - lll_adv_iso->ptc = ptc_calc(lll_adv_iso, event_spacing, - event_spacing_max); - lll_adv_iso->nse += lll_adv_iso->ptc; lll_adv_iso->bis_spacing = lll_adv_iso->sub_interval * - lll_adv_iso->nse; - } - - /* Pre-Transmission Offset (PTO) */ - if (lll_adv_iso->ptc) { - lll_adv_iso->pto = bn / lll_adv_iso->bn; - } else { - lll_adv_iso->pto = 0U; + lll_adv_iso->nse; } /* TODO: Group count, GC = NSE / BN; PTO = GC - IRC; @@ -588,6 +644,23 @@ ll_big_create_rtn_retry: return BT_HCI_ERR_SUCCESS; } +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) +{ + return big_create(big_handle, adv_handle, num_bis, sdu_interval, max_sdu, + max_latency, rtn, phy, packing, framing, encryption, bcode, + 0 /*iso_interval*/, + 0 /*nse*/, + 0 /*max_pdu*/, + 0 /*bn*/, + 0 /*irc*/, + 0 /*pto*/, + false); +} + 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, @@ -595,25 +668,11 @@ uint8_t ll_big_test_create(uint8_t big_handle, uint8_t adv_handle, uint8_t framing, uint8_t bn, uint8_t irc, uint8_t pto, uint8_t encryption, uint8_t *bcode) { - /* TODO: Implement */ - ARG_UNUSED(big_handle); - ARG_UNUSED(adv_handle); - ARG_UNUSED(num_bis); - ARG_UNUSED(sdu_interval); - ARG_UNUSED(iso_interval); - ARG_UNUSED(nse); - ARG_UNUSED(max_sdu); - ARG_UNUSED(max_pdu); - ARG_UNUSED(phy); - ARG_UNUSED(packing); - ARG_UNUSED(framing); - ARG_UNUSED(bn); - ARG_UNUSED(irc); - ARG_UNUSED(pto); - ARG_UNUSED(encryption); - ARG_UNUSED(bcode); - - return BT_HCI_ERR_CMD_DISALLOWED; + return big_create(big_handle, adv_handle, num_bis, sdu_interval, max_sdu, + 0 /*max_latency*/, + 0 /*rtn*/, + phy, packing, framing, encryption, bcode, + iso_interval, nse, max_pdu, bn, irc, pto, true); } uint8_t ll_big_terminate(uint8_t big_handle, uint8_t reason)