diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index e6016731910..172bc28d960 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -44,6 +44,8 @@ #include "hal/debug.h" +#define SDU_MAX_DRIFT_PPM 100 + /* Setup cache for CIG commit transaction */ static struct { struct ll_conn_iso_group group; @@ -167,6 +169,44 @@ uint8_t ll_cis_parameters_test_set(uint8_t cis_id, uint8_t nse, return BT_HCI_ERR_SUCCESS; } +static void set_bn_max_pdu(bool framed, uint32_t iso_interval, uint32_t sdu_interval, + uint16_t max_sdu, uint8_t *bn, uint8_t *max_pdu) +{ + uint32_t ceil_f_x_max_sdu; + uint16_t max_pdu_bn1; + uint32_t max_drift; + uint32_t ceil_f; + + if (framed) { + /* Framed (From ES-18002): + * Max_PDU >= ((ceil(F) x 5 + ceil(F x Max_SDU)) / BN) + 2 + * F = (1 + MaxDrift) x ISO_Interval / SDU_Interval + * SegmentationHeader + TimeOffset = 5 bytes + * Continuation header = 2 bytes + * MaxDrift (Max. allowed SDU delivery timing drift) = 100 ppm + */ + max_drift = ceiling_fraction(SDU_MAX_DRIFT_PPM * sdu_interval, 1000000U); + ceil_f = ceiling_fraction(iso_interval + max_drift, sdu_interval); + ceil_f_x_max_sdu = ceiling_fraction(max_sdu * (iso_interval + max_drift), + sdu_interval); + + /* Strategy: Keep lowest possible BN. + * TODO: Implement other strategies, possibly as policies. + */ + max_pdu_bn1 = ceil_f * 5 + ceil_f_x_max_sdu; + *bn = ceiling_fraction(max_pdu_bn1, CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE); + *max_pdu = ceiling_fraction(max_pdu_bn1, *bn) + 2; + } else { + /* For unframed, ISO_Interval must be N x SDU_Interval */ + LL_ASSERT(iso_interval % sdu_interval == 0); + + /* Core 5.3 Vol 6, Part G section 2.1: + * BN >= ceil(Max_SDU/Max_PDU * ISO_Interval/SDU_Interval) + */ + *bn = ceiling_fraction(max_sdu * iso_interval, (*max_pdu) * sdu_interval); + } +} + /* TODO: * - Drop retransmissions to stay within Max_Transmission_Latency instead of asserting @@ -278,30 +318,29 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) tx = cig->c_sdu_interval && cis->c_max_sdu; rx = cig->p_sdu_interval && cis->p_max_sdu; - if (cis->framed) { - cis->lll.tx.max_octets = - ceiling_fraction(cis->c_max_sdu * cig->c_sdu_interval, - iso_interval_us); - cis->lll.rx.max_octets = - ceiling_fraction(cis->p_max_sdu * cig->c_sdu_interval, - iso_interval_us); - } else { - /* For unframed, ISO_Interval must be N x SDU_Interval */ - LL_ASSERT(iso_interval_us % cig->c_sdu_interval == 0); + /* Use Max_PDU = MIN(, Max_SDU) as default. May be changed by + * set_bn_max_pdu. + */ + cis->lll.tx.max_octets = MIN(CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE, + cis->c_max_sdu); + cis->lll.rx.max_octets = MIN(251, cis->p_max_sdu); - /* Use Max_PDU = MIN(, Max_SDU) */ - cis->lll.tx.max_octets = MIN(CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE, - cis->c_max_sdu); - cis->lll.rx.max_octets = MIN(251, cis->p_max_sdu); + /* Calculate BN and Max_PDU (framed) for both directions */ + if (tx) { + set_bn_max_pdu(cis->framed, iso_interval_us, cig->c_sdu_interval, + cis->c_max_sdu, &cis->lll.tx.burst_number, + &cis->lll.tx.max_octets); + } else { + cis->lll.tx.burst_number = 0; } - /* BN >= Max_SDU/Max_PDU * ISO_Interval/SDU_Interval */ - cis->lll.tx.burst_number = tx ? - ceiling_fraction(cis->c_max_sdu * iso_interval_us, - cis->lll.tx.max_octets * cig->c_sdu_interval) : 0; - cis->lll.rx.burst_number = rx ? - ceiling_fraction(cis->p_max_sdu * iso_interval_us, - cis->lll.rx.max_octets * cig->p_sdu_interval) : 0; + if (rx) { + set_bn_max_pdu(cis->framed, iso_interval_us, cig->p_sdu_interval, + cis->p_max_sdu, &cis->lll.rx.burst_number, + &cis->lll.rx.max_octets); + } else { + cis->lll.rx.burst_number = 0; + } } /* Calculate SE_Length */ @@ -621,7 +660,6 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle, int16_t conn_events_since_ref; uint32_t iso_interval_us; uint32_t time_since_ref; - uint32_t acl_offset; c = ll_conn_iso_stream_get_by_group(cig, &handle_iter); if (c->cis_id != cis->cis_id && c->lll.active) { @@ -630,9 +668,8 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle, time_since_ref = c->offset + conn_events_since_ref * conn->lll.interval * CONN_INT_UNIT_US; - iso_interval_us = cig->iso_interval * CONN_INT_UNIT_US; - acl_offset = iso_interval_us - (time_since_ref % iso_interval_us); - cis_offset = acl_offset + (cig->sync_delay - cis->sync_delay); + iso_interval_us = cig->iso_interval * ISO_INT_UNIT_US; + cis_offset = time_since_ref % iso_interval_us; break; } } diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index 5bdbd395922..00b60e57467 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -442,7 +442,6 @@ void ull_conn_iso_resume_ticker_start(struct lll_event *resume_event, uint32_t resume_timeout) { struct lll_conn_iso_group *cig; - uint32_t ready_delay_us; uint32_t resume_delay_us; int32_t resume_offset_us; uint8_t ticker_id; @@ -458,26 +457,28 @@ void ull_conn_iso_resume_ticker_start(struct lll_event *resume_event, } cig->resume_cis = cis_handle; - if (0) { -#if defined(CONFIG_BT_CTLR_PHY) - } else { - struct ll_conn_iso_stream *cis; - struct ll_conn *acl; - - cis = ll_conn_iso_stream_get(cis_handle); - acl = ll_conn_get(cis->lll.acl_handle); - - ready_delay_us = lll_radio_rx_ready_delay_get(acl->lll.phy_rx, 1); -#else - } else { - ready_delay_us = lll_radio_rx_ready_delay_get(0, 0); -#endif /* CONFIG_BT_CTLR_PHY */ - } - resume_delay_us = EVENT_OVERHEAD_START_US; resume_delay_us += EVENT_TICKER_RES_MARGIN_US; - resume_delay_us += EVENT_JITTER_US; - resume_delay_us += ready_delay_us; + + if (cig->role == BT_HCI_ROLE_PERIPHERAL) { + /* Add peripheral specific delay */ + resume_delay_us += EVENT_JITTER_US; + if (0) { +#if defined(CONFIG_BT_CTLR_PHY) + } else { + struct ll_conn_iso_stream *cis; + struct ll_conn *acl; + + cis = ll_conn_iso_stream_get(cis_handle); + acl = ll_conn_get(cis->lll.acl_handle); + + resume_delay_us += lll_radio_rx_ready_delay_get(acl->lll.phy_rx, 1); +#else + } else { + resume_delay_us += lll_radio_rx_ready_delay_get(0, 0); +#endif /* CONFIG_BT_CTLR_PHY */ + } + } resume_offset_us = (int32_t)(resume_timeout - resume_delay_us); LL_ASSERT(resume_offset_us >= 0); @@ -631,8 +632,7 @@ void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, #elif !defined(CONFIG_BT_CTLR_CENTRAL_ISO) mfy.fp = lll_peripheral_iso_prepare; #else - mfy.fp = (cig->lll.role == BT_HCI_ROLE_PERIPHERAL) ? lll_peripheral_iso_prepare : - lll_central_iso_prepare; + mfy.fp = IS_PERIPHERAL(cig) ? lll_peripheral_iso_prepare : lll_central_iso_prepare; #endif if (IS_PERIPHERAL(cig) && cig->sca_update) {