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 */
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue