diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index b51fa4464a5..78fffc79790 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -212,7 +212,7 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) if (!cig->central.test) { /* TODO: Calculate ISO_Interval based on SDU_Interval and Max_SDU vs Max_PDU, - * taking the policy into consideration. It may also be intersting to select an + * taking the policy into consideration. It may also be interesting to select an * ISO_Interval which is less likely to collide with other connections. * For instance: * @@ -250,9 +250,8 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) for (uint8_t i = 0; i < cis_count; i++) { uint32_t mpt_c; uint32_t mpt_p; - - const bool tx = cig->c_sdu_interval > 0; - const bool rx = cig->p_sdu_interval > 0; + bool tx; + bool rx; /* Acquire new CIS */ cis = ll_conn_iso_stream_acquire(); @@ -263,16 +262,23 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) /* Transfer parameters from update cache */ memcpy(cis, &ll_iso_setup.stream[i], sizeof(struct ll_conn_iso_stream)); - cis->group = cig; + cis->group = cig; + cis->framed = cig->central.framing; cis->lll.handle = ll_conn_iso_stream_handle_get(cis); if (cig->central.test) { cis->lll.tx.flush_timeout = ll_iso_setup.c_ft; cis->lll.rx.flush_timeout = ll_iso_setup.p_ft; + + tx = cis->lll.tx.burst_number && cis->lll.tx.max_octets; + rx = cis->lll.rx.burst_number && cis->lll.rx.max_octets; } else { LL_ASSERT(iso_interval_us >= cig->c_sdu_interval); + 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, @@ -300,10 +306,8 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) } /* Calculate SE_Length */ - mpt_c = PDU_CIS_MAX_US(tx ? cis->lll.tx.max_octets : 0, tx ? 1 : 0, - cis->lll.tx.phy); - mpt_p = PDU_CIS_MAX_US(rx ? cis->lll.rx.max_octets : 0, rx ? 1 : 0, - cis->lll.rx.phy); + mpt_c = PDU_CIS_MAX_US(cis->lll.tx.max_octets, tx ? 1 : 0, cis->lll.tx.phy); + mpt_p = PDU_CIS_MAX_US(cis->lll.rx.max_octets, rx ? 1 : 0, cis->lll.rx.phy); se[i].length = mpt_c + EVENT_IFS_US + mpt_p + EVENT_MSS_US; max_se_length = MAX(max_se_length, se[i].length); @@ -366,10 +370,28 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) cis->lll.rx.flush_timeout = cis->lll.tx.flush_timeout; #elif defined(CONFIG_BT_CTLR_CONN_ISO_RELIABILITY_POLICY) - cis->lll.tx.flush_timeout = ceiling_fraction(cig->c_latency, - iso_interval_us); - cis->lll.rx.flush_timeout = ceiling_fraction(cig->p_latency, - iso_interval_us); + /* Utilize Max_Transmission_latency */ + if (cis->framed) { + /* TL = CIG_Sync_Delay + FT x ISO_Interval + SDU_Interval. + * SDU_Interval <= CIG_Sync_Delay + */ + cis->lll.tx.flush_timeout = + ceiling_fraction(cig->c_latency - cig->c_sdu_interval - + iso_interval_us, iso_interval_us); + cis->lll.rx.flush_timeout = + ceiling_fraction(cig->p_latency - cig->p_sdu_interval - + iso_interval_us, iso_interval_us); + } else { + /* TL = CIG_Sync_Delay + FT x ISO_Interval - SDU_Interval. + * SDU_Interval <= CIG_Sync_Delay + */ + cis->lll.tx.flush_timeout = + ceiling_fraction(cig->c_latency + cig->c_sdu_interval - + iso_interval_us, iso_interval_us); + cis->lll.rx.flush_timeout = + ceiling_fraction(cig->p_latency + cig->p_sdu_interval - + iso_interval_us, iso_interval_us); + } #else LL_ASSERT(0); #endif @@ -459,11 +481,20 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id) return BT_HCI_ERR_SUCCESS; } +/* Core 5.3 Vol 6, Part B section 7.8.100: + * The HCI_LE_Remove_CIG command is used by the Central’s Host to remove the CIG + * identified by CIG_ID. + * This command shall delete the CIG_ID and also delete the Connection_Handles + * of the CIS configurations stored in the CIG. + * This command shall also remove the isochronous data paths that are associated + * with the Connection_Handles of the CIS configurations. + */ uint8_t ll_cig_remove(uint8_t cig_id) { struct ll_conn_iso_stream *cis; struct ll_conn_iso_group *cig; uint16_t handle_iter; + bool has_cis; cig = ll_conn_iso_group_get_by_id(cig_id); if (!cig) { @@ -481,6 +512,10 @@ uint8_t ll_cig_remove(uint8_t cig_id) struct ll_conn *conn; cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); + if (!cis) { + break; + } + conn = ll_connected_get(cis->lll.acl_handle); if (conn) { @@ -493,8 +528,13 @@ uint8_t ll_cig_remove(uint8_t cig_id) /* CIG exists and is not active */ handle_iter = UINT16_MAX; + has_cis = false; + for (int i = 0; i < cig->cis_count; i++) { cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); + if (!cis) { + break; + } /* Remove data path and ISOAL sink/source associated with this CIS * for both directions. @@ -502,10 +542,16 @@ uint8_t ll_cig_remove(uint8_t cig_id) ll_remove_iso_path(cis->lll.handle, BT_HCI_DATAPATH_DIR_CTLR_TO_HOST); ll_remove_iso_path(cis->lll.handle, BT_HCI_DATAPATH_DIR_HOST_TO_CTLR); - ll_conn_iso_stream_release(cis); + has_cis = true; } - ll_conn_iso_group_release(cig); + if (has_cis) { + /* Clear configuration only - let CIS disconnection release instance */ + cig->cis_count = 0; + } else { + /* No CISes associated with the CIG - release the instance */ + ll_conn_iso_group_release(cig); + } return BT_HCI_ERR_SUCCESS; } @@ -611,22 +657,29 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle, return 0; } -uint16_t ull_central_iso_cis_offset_get(struct ll_conn_iso_stream *cis, uint32_t *cis_offset_min, +uint16_t ull_central_iso_cis_offset_get(uint16_t cis_handle, uint32_t *cis_offset_min, uint32_t *cis_offset_max) { - struct ll_conn_iso_group *cig; + struct ll_conn_iso_stream *cis; struct ll_conn *conn; - conn = ll_conn_get(cis->lll.acl_handle); - cig = cis->group; + cis = ll_conn_iso_stream_get(cis_handle); + LL_ASSERT(cis); - /* Provide CIS offset range - * CIS_Offset_Max < (connInterval - (CIG_Sync_Delay + T_MSS)) - */ - *cis_offset_max = (conn->lll.interval * CONN_INT_UNIT_US) - cig->sync_delay; - *cis_offset_min = MAX(400, EVENT_OVERHEAD_CIS_SETUP_US); + conn = ll_conn_get(cis->lll.acl_handle); + + if (cis_offset_min && cis_offset_max) { + struct ll_conn_iso_group *cig; + + cig = cis->group; + + /* Provide CIS offset range + * CIS_Offset_Max < (connInterval - (CIG_Sync_Delay + T_MSS)) + */ + *cis_offset_max = (conn->lll.interval * CONN_INT_UNIT_US) - cig->sync_delay; + *cis_offset_min = MAX(400, EVENT_OVERHEAD_CIS_SETUP_US); + } cis->central.instant = ull_conn_event_counter(conn) + 3; - return cis->central.instant; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso_internal.h b/subsys/bluetooth/controller/ll_sw/ull_central_iso_internal.h index afec5ce5fe2..8c929d58f3b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso_internal.h @@ -8,8 +8,7 @@ int ull_central_iso_init(void); int ull_central_iso_reset(void); -void ull_central_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire, uint16_t cis_handle); -uint16_t ull_central_iso_cis_offset_get(struct ll_conn_iso_stream *cis, uint32_t *cis_offset_min, +uint16_t ull_central_iso_cis_offset_get(uint16_t cis_handle, uint32_t *cis_offset_min, uint32_t *cis_offset_max); uint8_t ull_central_iso_setup(uint16_t cis_handle, uint32_t *cig_sync_delay, diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index ef594337f21..02303c82380 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -520,7 +520,7 @@ void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, /* New CIS may become available by creation prior to the CIG * event in which it has event_count == 0. Don't increment * event count until its handle is validated in - * ull_peripheral_iso_start, which means that its ACL instant + * ull_conn_iso_start, which means that its ACL instant * has been reached, and offset calculated. */ if (cis->lll.handle != 0xFFFF && cis->lll.active) { @@ -538,7 +538,7 @@ void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, /* Update the CIG reference point for this event. Event 0 for the * leading CIS in the CIG would have had it's reference point set in - * ull_peripheral_iso_start(). The reference point should only be + * ull_conn_iso_start(). The reference point should only be * updated from event 1 onwards. Although the cig reference point set * this way is not accurate, it is the best possible until the anchor * point for the leading CIS is available for this event. @@ -952,7 +952,7 @@ static void cig_disabled_cb(void *param) cig = HDR_LLL2ULL(param); - if (IS_PERIPHERAL(cig)) { + if (IS_PERIPHERAL(cig) || cig->cis_count == 0) { ll_conn_iso_group_release(cig); } else { /* CIG shall be released by ll_cig_remove */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index 032c669b3c7..3bbcfe60e49 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -905,8 +905,9 @@ uint8_t ull_cp_cis_create(struct ll_conn *conn, struct ll_conn_iso_stream *cis) ctx->data.cis_create.p_ft = cis->lll.rx.flush_timeout; ctx->data.cis_create.conn_event_count = - ull_central_iso_cis_offset_get(cis, &ctx->data.cis_create.cis_offset_min, - &ctx->data.cis_create.cis_offset_max); + ull_central_iso_cis_offset_get(cis->lll.handle, + &ctx->data.cis_create.cis_offset_min, + &ctx->data.cis_create.cis_offset_max); llcp_lr_enqueue(conn, ctx); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c index fe3201b6691..dd663be1dec 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c @@ -601,7 +601,7 @@ void llcp_rp_cc_run(struct ll_conn *conn, struct proc_ctx *ctx, void *param) } #endif /* CONFIG_BT_PERIPHERAL */ -#if defined(CONFIG_BT_CENTRAL) +#if defined(CONFIG_BT_CTLR_CENTRAL_ISO) static void lp_cc_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param); /* LLCP Local Procedure FSM states */ @@ -685,6 +685,10 @@ static void lp_cc_send_cis_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8 if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { ctx->state = LP_CC_STATE_WAIT_TX_CIS_REQ; } else { + /* Update conn_event_count */ + ctx->data.cis_create.conn_event_count = + ull_central_iso_cis_offset_get(ctx->data.cis_create.cis_handle, NULL, NULL); + lp_cc_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CIS_REQ); ctx->state = LP_CC_STATE_WAIT_RX_CIS_RSP; @@ -821,9 +825,6 @@ static void lp_cc_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint /* Now we can wait for CIS to become established */ ctx->state = LP_CC_STATE_WAIT_ESTABLISHED; - - /* Stop procedure response timeout timer */ - llcp_lr_prt_stop(conn); } } @@ -908,4 +909,4 @@ bool llcp_lp_cc_is_active(struct proc_ctx *ctx) { return ctx->state != LP_CC_STATE_IDLE; } -#endif /* CONFIG_BT_CENTRAL */ +#endif /* CONFIG_BT_CTLR_CENTRAL_ISO */ diff --git a/tests/bluetooth/controller/mock_ctrl/src/ull_central.c b/tests/bluetooth/controller/mock_ctrl/src/ull_central.c index 278eb11e5f5..691ad90b3a2 100644 --- a/tests/bluetooth/controller/mock_ctrl/src/ull_central.c +++ b/tests/bluetooth/controller/mock_ctrl/src/ull_central.c @@ -37,3 +37,20 @@ int ull_central_reset(void) { return 0; } + +uint16_t ull_central_iso_cis_offset_get(uint16_t cis_handle, uint32_t *cis_offset_min, + uint32_t *cis_offset_max) +{ + return 0; +} + +uint8_t ull_central_iso_setup(uint16_t cis_handle, + uint32_t *cig_sync_delay, + uint32_t *cis_sync_delay, + uint32_t *cis_offset_min, + uint32_t *cis_offset_max, + uint16_t *conn_event_count, + uint8_t *access_addr) +{ + return 0; +} diff --git a/tests/bluetooth/controller/mock_ctrl/src/ull_conn_iso.c b/tests/bluetooth/controller/mock_ctrl/src/ull_conn_iso.c index a774a83083c..306f0d7c823 100644 --- a/tests/bluetooth/controller/mock_ctrl/src/ull_conn_iso.c +++ b/tests/bluetooth/controller/mock_ctrl/src/ull_conn_iso.c @@ -77,3 +77,8 @@ void ull_conn_iso_cis_stop_by_id(uint8_t cig_id, uint8_t cis_id, uint8_t reason) { } + +void ull_conn_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire, uint16_t cis_handle) +{ + +} diff --git a/tests/bluetooth/controller/mock_ctrl/src/ull_peripheral_iso.c b/tests/bluetooth/controller/mock_ctrl/src/ull_peripheral_iso.c index 4fc0fef4fdc..e444246dc47 100644 --- a/tests/bluetooth/controller/mock_ctrl/src/ull_peripheral_iso.c +++ b/tests/bluetooth/controller/mock_ctrl/src/ull_peripheral_iso.c @@ -56,11 +56,6 @@ uint8_t ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind *ind, return 0; } -void ull_peripheral_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire, - uint16_t cis_handle) -{ -} - void ull_peripheral_iso_update_peer_sca(struct ll_conn *acl) { }