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:
parent
3c68fa45d2
commit
218da91211
5 changed files with 77 additions and 13 deletions
|
@ -496,7 +496,10 @@ struct event_done_extra {
|
||||||
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */
|
#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint16_t trx_cnt;
|
union {
|
||||||
|
uint32_t trx_performed_mask;
|
||||||
|
uint16_t trx_cnt;
|
||||||
|
};
|
||||||
uint8_t crc_valid:1;
|
uint8_t crc_valid:1;
|
||||||
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) && \
|
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) && \
|
||||||
defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT)
|
defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT)
|
||||||
|
|
|
@ -74,4 +74,6 @@ struct lll_conn_iso_group {
|
||||||
|
|
||||||
int lll_conn_iso_init(void);
|
int lll_conn_iso_init(void);
|
||||||
int lll_conn_iso_reset(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);
|
void lll_conn_iso_flush(uint16_t handle, struct lll_conn_iso_stream *lll);
|
||||||
|
|
|
@ -286,8 +286,11 @@ void ull_conn_iso_done(struct node_rx_event_done *done)
|
||||||
{
|
{
|
||||||
struct lll_conn_iso_group *lll;
|
struct lll_conn_iso_group *lll;
|
||||||
struct ll_conn_iso_group *cig;
|
struct ll_conn_iso_group *cig;
|
||||||
|
struct ll_conn_iso_stream *cis;
|
||||||
uint32_t ticks_drift_minus;
|
uint32_t ticks_drift_minus;
|
||||||
uint32_t ticks_drift_plus;
|
uint32_t ticks_drift_plus;
|
||||||
|
uint16_t handle_iter;
|
||||||
|
uint8_t cis_idx;
|
||||||
|
|
||||||
/* Get reference to ULL context */
|
/* Get reference to ULL context */
|
||||||
cig = CONTAINER_OF(done->param, struct ll_conn_iso_group, ull);
|
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_plus = 0;
|
||||||
ticks_drift_minus = 0;
|
ticks_drift_minus = 0;
|
||||||
|
handle_iter = UINT16_MAX;
|
||||||
|
cis = NULL;
|
||||||
|
|
||||||
if (done->extra.trx_cnt) {
|
/* Check all CISes for supervison/establishment timeout */
|
||||||
if (IS_ENABLED(CONFIG_BT_CTLR_PERIPHERAL_ISO) && lll->role) {
|
for (cis_idx = 0; cis_idx < cig->lll.num_cis; cis_idx++) {
|
||||||
ull_drift_ticks_get(done, &ticks_drift_plus,
|
cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter);
|
||||||
&ticks_drift_minus);
|
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 (done->extra.trx_performed_mask &&
|
||||||
if (ticks_drift_plus || ticks_drift_minus) {
|
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 +
|
uint8_t ticker_id = TICKER_ID_CONN_ISO_BASE +
|
||||||
ll_conn_iso_group_handle_get(cig);
|
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;
|
uint32_t ticker_status;
|
||||||
|
|
||||||
ticker_status = ticker_update(TICKER_INSTANCE_ID_CTLR,
|
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.handle = cis_handle;
|
||||||
cis->lll.active = 1U;
|
cis->lll.active = 1U;
|
||||||
|
|
||||||
|
/* Connection establishment timeout */
|
||||||
|
cis->event_expire = CONN_ESTAB_COUNTDOWN;
|
||||||
|
|
||||||
/* Check if another CIS was already started and CIG ticker is
|
/* Check if another CIS was already started and CIG ticker is
|
||||||
* running. If so, we just return with updated offset and
|
* running. If so, we just return with updated offset and
|
||||||
* validated handle.
|
* validated handle.
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct ll_conn_iso_stream {
|
||||||
* notified.
|
* notified.
|
||||||
*/
|
*/
|
||||||
uint16_t teardown:1; /* 1 if CIS teardown has been initiated */
|
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 p_max_sdu:12; /* Maximum SDU size P_To_C */
|
||||||
uint16_t c_max_sdu:12; /* Maximum SDU size C_To_P */
|
uint16_t c_max_sdu:12; /* Maximum SDU size C_To_P */
|
||||||
union {
|
union {
|
||||||
|
@ -33,6 +34,7 @@ struct ll_conn_iso_stream {
|
||||||
uint16_t instant;
|
uint16_t instant;
|
||||||
} central;
|
} central;
|
||||||
};
|
};
|
||||||
|
uint16_t event_expire; /* Supervision & Connect Timeout event counter */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ll_conn_iso_group {
|
struct ll_conn_iso_group {
|
||||||
|
|
|
@ -49,12 +49,21 @@
|
||||||
#include <soc.h>
|
#include <soc.h>
|
||||||
#include "hal/debug.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 =
|
const struct ll_conn_iso_stream *cis =
|
||||||
ll_conn_iso_stream_get(ctx->data.cis_create.cis_handle);
|
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)
|
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) {
|
switch (evt) {
|
||||||
case RP_CC_EVT_RUN:
|
case RP_CC_EVT_RUN:
|
||||||
/* Check for CIS state */
|
/* Check for CIS state */
|
||||||
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 */
|
/* CIS was established or establishement timed out,
|
||||||
|
* In either case complete procedure and generate
|
||||||
|
* notification
|
||||||
|
*/
|
||||||
rp_cc_complete(conn, ctx, evt, param);
|
rp_cc_complete(conn, ctx, evt, param);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -858,7 +870,7 @@ static void lp_cc_st_wait_established(struct ll_conn *conn, struct proc_ctx *ctx
|
||||||
{
|
{
|
||||||
switch (evt) {
|
switch (evt) {
|
||||||
case LP_CC_EVT_RUN:
|
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 */
|
/* CIS was established, so let's got ahead and complete procedure */
|
||||||
lp_cc_complete(conn, ctx, evt, param);
|
lp_cc_complete(conn, ctx, evt, param);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue