Bluetooth: controller: Implementing CIS STO & establishment timeout

Adding a bit-mask to the 'extra' data structure allowing passing info
re. active CIS's to the ull_conn_iso_done handling. Per CIS storing
an expiration time counter, monitoring in done handling. Adding
establishment timeout monitor in CIS Create procedure, completing
and ntf'ing accordingly.

Signed-off-by: Erik Brockhoff <erbr@oticon.com>
This commit is contained in:
Erik Brockhoff 2022-09-08 13:38:08 +02:00 committed by Carles Cufí
commit 218da91211
5 changed files with 77 additions and 13 deletions

View file

@ -496,7 +496,10 @@ struct event_done_extra {
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */
union {
struct {
uint16_t trx_cnt;
union {
uint32_t trx_performed_mask;
uint16_t trx_cnt;
};
uint8_t crc_valid:1;
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) && \
defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT)

View file

@ -74,4 +74,6 @@ struct lll_conn_iso_group {
int lll_conn_iso_init(void);
int lll_conn_iso_reset(void);
void lll_conn_iso_done(struct lll_conn_iso_group *cig, uint32_t trx_performed,
uint16_t prog_to_anchor_us, uint8_t mic_state);
void lll_conn_iso_flush(uint16_t handle, struct lll_conn_iso_stream *lll);

View file

@ -286,8 +286,11 @@ void ull_conn_iso_done(struct node_rx_event_done *done)
{
struct lll_conn_iso_group *lll;
struct ll_conn_iso_group *cig;
struct ll_conn_iso_stream *cis;
uint32_t ticks_drift_minus;
uint32_t ticks_drift_plus;
uint16_t handle_iter;
uint8_t cis_idx;
/* Get reference to ULL context */
cig = CONTAINER_OF(done->param, struct ll_conn_iso_group, ull);
@ -300,19 +303,58 @@ void ull_conn_iso_done(struct node_rx_event_done *done)
ticks_drift_plus = 0;
ticks_drift_minus = 0;
handle_iter = UINT16_MAX;
cis = NULL;
if (done->extra.trx_cnt) {
if (IS_ENABLED(CONFIG_BT_CTLR_PERIPHERAL_ISO) && lll->role) {
ull_drift_ticks_get(done, &ticks_drift_plus,
&ticks_drift_minus);
/* Check all CISes for supervison/establishment timeout */
for (cis_idx = 0; cis_idx < cig->lll.num_cis; cis_idx++) {
cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter);
LL_ASSERT(cis);
if (cis->lll.handle != LLL_HANDLE_INVALID) {
/* CIS was setup and is now expected to be going */
if (!(done->extra.trx_performed_mask &
(1U << LL_CIS_IDX_FROM_HANDLE(cis->lll.handle)))) {
/* We did NOT have successful transaction on established CIS,
* or CIS was not yet established, so handle timeout
*/
if (!cis->event_expire) {
struct ll_conn *conn = ll_conn_get(cis->lll.acl_handle);
cis->event_expire =
RADIO_CONN_EVENTS(
conn->supervision_timeout * 10U * 1000U,
cig->iso_interval * CONN_INT_UNIT_US) + 1;
}
if (--cis->event_expire == 0) {
/* Stop CIS and defer cleanup to after teardown. */
ull_conn_iso_cis_stop(cis, NULL,
cis->established ?
BT_HCI_ERR_CONN_TIMEOUT :
BT_HCI_ERR_CONN_FAIL_TO_ESTAB);
}
} else {
cis->event_expire = 0;
}
}
}
/* Update CIG ticker to compensate for drift */
if (ticks_drift_plus || ticks_drift_minus) {
if (done->extra.trx_performed_mask &&
IS_ENABLED(CONFIG_BT_CTLR_PERIPHERAL_ISO) && lll->role) {
ull_drift_ticks_get(done, &ticks_drift_plus,
&ticks_drift_minus);
}
/* Update CIG ticker to compensate for drift.
* Since all CISes in a CIG 'belong to' the same ACL,
* any CIS found in the above for-loop will do to dereference the ACL
*/
if (cis && (ticks_drift_plus || ticks_drift_minus)) {
uint8_t ticker_id = TICKER_ID_CONN_ISO_BASE +
ll_conn_iso_group_handle_get(cig);
struct ll_conn *conn = lll->hdr.parent;
struct ll_conn *conn = ll_connected_get(cis->lll.acl_handle);
uint32_t ticker_status;
ticker_status = ticker_update(TICKER_INSTANCE_ID_CTLR,
@ -645,6 +687,9 @@ void ull_conn_iso_start(struct ll_conn *acl, uint32_t ticks_at_expire, uint16_t
cis->lll.handle = cis_handle;
cis->lll.active = 1U;
/* Connection establishment timeout */
cis->event_expire = CONN_ESTAB_COUNTDOWN;
/* Check if another CIS was already started and CIG ticker is
* running. If so, we just return with updated offset and
* validated handle.

View file

@ -24,6 +24,7 @@ struct ll_conn_iso_stream {
* notified.
*/
uint16_t teardown:1; /* 1 if CIS teardown has been initiated */
uint16_t trx_performed:1; /* 1 if CIS had a transaction */
uint16_t p_max_sdu:12; /* Maximum SDU size P_To_C */
uint16_t c_max_sdu:12; /* Maximum SDU size C_To_P */
union {
@ -33,6 +34,7 @@ struct ll_conn_iso_stream {
uint16_t instant;
} central;
};
uint16_t event_expire; /* Supervision & Connect Timeout event counter */
};
struct ll_conn_iso_group {

View file

@ -49,12 +49,21 @@
#include <soc.h>
#include "hal/debug.h"
static bool cc_check_cis_established_lll(struct proc_ctx *ctx)
static bool cc_check_cis_established_or_timeout_lll(struct proc_ctx *ctx)
{
const struct ll_conn_iso_stream *cis =
ll_conn_iso_stream_get(ctx->data.cis_create.cis_handle);
return cis->established;
if (cis->established) {
return true;
}
if (!cis->event_expire) {
ctx->data.cis_create.error = BT_HCI_ERR_CONN_FAIL_TO_ESTAB;
return true;
}
return false;
}
static void cc_ntf_established(struct ll_conn *conn, struct proc_ctx *ctx)
@ -508,8 +517,11 @@ static void rp_cc_state_wait_cis_established(struct ll_conn *conn, struct proc_c
switch (evt) {
case RP_CC_EVT_RUN:
/* Check for CIS state */
if (cc_check_cis_established_lll(ctx)) {
/* CIS was established, so let's got ahead and complete procedure */
if (cc_check_cis_established_or_timeout_lll(ctx)) {
/* CIS was established or establishement timed out,
* In either case complete procedure and generate
* notification
*/
rp_cc_complete(conn, ctx, evt, param);
}
break;
@ -858,7 +870,7 @@ static void lp_cc_st_wait_established(struct ll_conn *conn, struct proc_ctx *ctx
{
switch (evt) {
case LP_CC_EVT_RUN:
if (cc_check_cis_established_lll(ctx)) {
if (cc_check_cis_established_or_timeout_lll(ctx)) {
/* CIS was established, so let's got ahead and complete procedure */
lp_cc_complete(conn, ctx, evt, param);
}