Bluetooth: Controller: Preliminary Central multiple CIS support
Implementation of preliminary Central with multiple CIS create support in Lower Link Layer. Uses a simple CIS offset calculation that works when ACL are created with connection interval that is multiple of CIG ISO interval. Each ACLs are offset using BT_CTLR_CENTRAL_SPACING hence having the same CIG sync delay values for all the ACLs. Advanced Scheduling to setup CIS in any order of ACL and CIS combination, ACL placed anywhere in timeline and CIS creation will come therein will be implemented in later Pull Requests. Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
parent
5152672d06
commit
ef8b05e83a
10 changed files with 448 additions and 99 deletions
|
@ -56,9 +56,6 @@ CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH=y
|
|||
CONFIG_BT_TICKER_EXT=y
|
||||
CONFIG_BT_TICKER_EXT_SLOT_WINDOW_YIELD=y
|
||||
|
||||
# Use 10 ms Central Connection Spacing for 10 ms ISO Interval
|
||||
CONFIG_BT_CTLR_CENTRAL_SPACING=10000
|
||||
|
||||
# Control Procedure
|
||||
CONFIG_BT_CTLR_LLCP_LOCAL_PROC_CTX_BUF_NUM=6
|
||||
|
||||
|
|
|
@ -186,6 +186,9 @@ enum {
|
|||
#else /* !CONFIG_BT_CTLR_ADV_ISO && !CONFIG_BT_CTLR_SYNC_ISO */
|
||||
#define BT_CTLR_CONN_ISO_STREAM_HANDLE_BASE (CONFIG_BT_MAX_CONN)
|
||||
#endif /* !CONFIG_BT_CTLR_ADV_ISO && !CONFIG_BT_CTLR_SYNC_ISO */
|
||||
#define LL_CIS_HANDLE_BASE (BT_CTLR_CONN_ISO_STREAM_HANDLE_BASE)
|
||||
#define LL_CIS_IDX_FROM_HANDLE(handle) \
|
||||
((handle) - LL_CIS_HANDLE_BASE)
|
||||
#endif /* CONFIG_BT_CTLR_CONN_ISO */
|
||||
|
||||
#define TICKER_ID_ULL_BASE ((TICKER_ID_LLL_PREEMPT) + 1)
|
||||
|
|
|
@ -93,6 +93,7 @@ ull_conn_iso_lll_stream_get_by_group(struct lll_conn_iso_group *cig_lll,
|
|||
uint16_t *handle_iter);
|
||||
extern struct lll_conn_iso_group *
|
||||
ull_conn_iso_lll_group_get_by_stream(struct lll_conn_iso_stream *cis_lll);
|
||||
extern struct lll_conn_iso_stream *ull_conn_iso_lll_stream_get(uint16_t handle);
|
||||
extern void
|
||||
ull_conn_iso_lll_cis_established(struct lll_conn_iso_stream *cis_lll);
|
||||
extern void ll_iso_rx_put(memq_link_t *link, void *rx);
|
||||
|
|
|
@ -47,11 +47,16 @@ static void isr_rx(void *param);
|
|||
static void isr_prepare_subevent(void *param);
|
||||
static void isr_done(void *param);
|
||||
|
||||
static uint8_t next_chan_use;
|
||||
static uint16_t data_chan_id;
|
||||
static uint16_t data_chan_prn_s;
|
||||
static uint16_t next_cis_chan_remap_idx;
|
||||
static uint16_t next_cis_chan_prn_s;
|
||||
static uint16_t data_chan_remap_idx;
|
||||
static uint16_t data_chan_prn_s;
|
||||
static uint8_t next_chan_use;
|
||||
static uint8_t next_cis_chan;
|
||||
|
||||
static uint32_t trx_performed_bitmask;
|
||||
static uint16_t cis_offset_first;
|
||||
static uint16_t cis_handle_curr;
|
||||
static uint8_t se_curr;
|
||||
static uint8_t bn_tx;
|
||||
static uint8_t bn_rx;
|
||||
|
@ -112,10 +117,12 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
struct pdu_cis *pdu_tx;
|
||||
uint16_t event_counter;
|
||||
uint64_t payload_count;
|
||||
uint16_t data_chan_id;
|
||||
uint8_t data_chan_use;
|
||||
struct ull_hdr *ull;
|
||||
uint32_t remainder;
|
||||
uint32_t start_us;
|
||||
uint32_t ret;
|
||||
uint8_t phy;
|
||||
|
||||
DEBUG_RADIO_START_M(1);
|
||||
|
@ -127,7 +134,15 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
#endif /* CONFIG_BT_CTLR_LE_ENC */
|
||||
|
||||
/* Get the first CIS */
|
||||
cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, NULL);
|
||||
cis_handle_curr = UINT16_MAX;
|
||||
do {
|
||||
cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle_curr);
|
||||
} while (cis_lll && !cis_lll->active);
|
||||
|
||||
LL_ASSERT(cis_lll);
|
||||
|
||||
/* Save first active CIS offset */
|
||||
cis_offset_first = cis_lll->offset;
|
||||
|
||||
/* Get reference to ACL context */
|
||||
conn_lll = ull_conn_lll_get(cis_lll->acl_handle);
|
||||
|
@ -143,6 +158,10 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
&data_chan_prn_s,
|
||||
&data_chan_remap_idx);
|
||||
|
||||
/* Adjust the SN and NESN for skipped CIG events */
|
||||
cis_lll->sn += cis_lll->tx.bn * p->lazy;
|
||||
cis_lll->nesn += cis_lll->rx.bn * p->lazy;
|
||||
|
||||
se_curr = 1U;
|
||||
bn_tx = 1U;
|
||||
bn_rx = 1U;
|
||||
|
@ -152,9 +171,9 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
radio_tx_power_set(cis_lll->tx_pwr_lvl);
|
||||
#else
|
||||
#else /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
radio_tx_power_set(RADIO_TXP_DEFAULT);
|
||||
#endif
|
||||
#endif /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
|
||||
phy = cis_lll->tx.phy;
|
||||
radio_phy_set(phy, cis_lll->tx.phy_flags);
|
||||
|
@ -186,7 +205,10 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
link = memq_peek(cis_lll->memq_tx.head,
|
||||
cis_lll->memq_tx.tail,
|
||||
(void **)&node_tx);
|
||||
if (link) {
|
||||
if (!link) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node_tx->payload_count < payload_count) {
|
||||
memq_dequeue(cis_lll->memq_tx.tail,
|
||||
&cis_lll->memq_tx.head,
|
||||
|
@ -206,7 +228,6 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (link);
|
||||
|
||||
if (!link) {
|
||||
|
@ -280,7 +301,8 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
ticks_at_event += lll_event_offset_get(ull);
|
||||
|
||||
ticks_at_start = ticks_at_event;
|
||||
ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
|
||||
ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US +
|
||||
cis_offset_first);
|
||||
|
||||
remainder = p->remainder;
|
||||
start_us = radio_tmr_start(1U, ticks_at_start, remainder);
|
||||
|
@ -321,12 +343,22 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
return -ECANCELED;
|
||||
#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
|
||||
|
||||
} else {
|
||||
uint32_t ret;
|
||||
}
|
||||
|
||||
/* Adjust the SN and NESN for skipped CIG events */
|
||||
uint16_t cis_handle = cis_handle_curr;
|
||||
|
||||
do {
|
||||
cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle);
|
||||
if (cis_lll && cis_lll->active) {
|
||||
cis_lll->sn += cis_lll->tx.bn * p->lazy;
|
||||
cis_lll->nesn += cis_lll->rx.bn * p->lazy;
|
||||
}
|
||||
} while (cis_lll);
|
||||
|
||||
/* Prepare is done */
|
||||
ret = lll_prepare_done(cig_lll);
|
||||
LL_ASSERT(!ret);
|
||||
}
|
||||
|
||||
DEBUG_RADIO_START_M(1);
|
||||
|
||||
|
@ -339,10 +371,9 @@ static void abort_cb(struct lll_prepare_param *prepare_param, void *param)
|
|||
|
||||
/* NOTE: This is not a prepare being cancelled */
|
||||
if (!prepare_param) {
|
||||
struct lll_conn_iso_group *cig_lll = param;
|
||||
struct lll_conn_iso_stream *cis_lll;
|
||||
|
||||
cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, NULL);
|
||||
cis_lll = ull_conn_iso_lll_stream_get(cis_handle_curr);
|
||||
|
||||
/* Perform event abort here.
|
||||
* After event has been cleanly aborted, clean up resources
|
||||
|
@ -367,7 +398,6 @@ static void isr_tx(void *param)
|
|||
{
|
||||
struct lll_conn_iso_stream *cis_lll;
|
||||
struct node_rx_pdu *node_rx;
|
||||
struct lll_conn *conn_lll;
|
||||
uint32_t hcto;
|
||||
|
||||
/* Clear radio tx status and events */
|
||||
|
@ -379,8 +409,10 @@ static void isr_tx(void *param)
|
|||
/* Get reference to CIS LLL context */
|
||||
cis_lll = param;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_LE_ENC)
|
||||
/* Get reference to ACL context */
|
||||
conn_lll = ull_conn_lll_get(cis_lll->acl_handle);
|
||||
struct lll_conn *conn_lll = ull_conn_lll_get(cis_lll->acl_handle);
|
||||
#endif /* CONFIG_BT_CTLR_LE_ENC */
|
||||
|
||||
/* Acquire rx node for reception */
|
||||
node_rx = ull_iso_pdu_rx_alloc_peek(1U);
|
||||
|
@ -427,6 +459,7 @@ static void isr_tx(void *param)
|
|||
hcto = radio_tmr_tifs_base_get() + EVENT_IFS_US +
|
||||
(EVENT_CLOCK_JITTER_US << 1) + RANGE_DELAY_US +
|
||||
HCTO_START_DELAY_US;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
hcto += radio_rx_chain_delay_get(cis_lll->rx.phy, PHY_FLAGS_S8);
|
||||
hcto += addr_us_get(cis_lll->rx.phy);
|
||||
|
@ -467,11 +500,13 @@ static void isr_tx(void *param)
|
|||
/* Schedule next subevent */
|
||||
if (se_curr < cis_lll->nse) {
|
||||
struct lll_conn *conn_lll;
|
||||
uint16_t data_chan_id;
|
||||
uint32_t subevent_us;
|
||||
uint32_t start_us;
|
||||
|
||||
subevent_us = radio_tmr_ready_restore();
|
||||
subevent_us += cis_lll->sub_interval * se_curr;
|
||||
subevent_us += cis_lll->offset - cis_offset_first +
|
||||
(cis_lll->sub_interval * se_curr);
|
||||
|
||||
start_us = radio_tmr_start_us(1U, subevent_us);
|
||||
LL_ASSERT(start_us == (subevent_us + 1U));
|
||||
|
@ -480,11 +515,130 @@ static void isr_tx(void *param)
|
|||
conn_lll = ull_conn_lll_get(cis_lll->acl_handle);
|
||||
|
||||
/* Calculate the radio channel to use for next subevent */
|
||||
data_chan_id = lll_chan_id(cis_lll->access_addr);
|
||||
next_chan_use = lll_chan_iso_subevent(data_chan_id,
|
||||
conn_lll->data_chan_map,
|
||||
conn_lll->data_chan_count,
|
||||
&data_chan_prn_s,
|
||||
&data_chan_remap_idx);
|
||||
} else {
|
||||
struct lll_conn_iso_stream *old_cis_lll;
|
||||
struct lll_conn_iso_stream *next_cis_lll;
|
||||
struct lll_conn_iso_group *cig_lll;
|
||||
struct lll_conn *next_conn_lll;
|
||||
uint16_t event_counter;
|
||||
uint16_t data_chan_id;
|
||||
uint32_t subevent_us;
|
||||
uint16_t cis_handle;
|
||||
uint32_t start_us;
|
||||
|
||||
/* Calculate channel for next CIS */
|
||||
cig_lll = ull_conn_iso_lll_group_get_by_stream(cis_lll);
|
||||
cis_handle = cis_handle_curr;
|
||||
do {
|
||||
next_cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll, &cis_handle);
|
||||
} while (next_cis_lll && !next_cis_lll->active);
|
||||
|
||||
if (!next_cis_lll) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get reference to ACL context */
|
||||
next_conn_lll = ull_conn_lll_get(next_cis_lll->acl_handle);
|
||||
|
||||
/* Event counter value, 0-15 bit of cisEventCounter */
|
||||
event_counter = next_cis_lll->event_count;
|
||||
|
||||
/* Calculate the radio channel to use for ISO event */
|
||||
data_chan_id = lll_chan_id(next_cis_lll->access_addr);
|
||||
next_cis_chan = lll_chan_iso_event(event_counter, data_chan_id,
|
||||
next_conn_lll->data_chan_map,
|
||||
next_conn_lll->data_chan_count,
|
||||
&next_cis_chan_prn_s,
|
||||
&next_cis_chan_remap_idx);
|
||||
|
||||
subevent_us = radio_tmr_ready_restore();
|
||||
subevent_us += next_cis_lll->offset - cis_offset_first;
|
||||
|
||||
start_us = radio_tmr_start_us(1U, subevent_us);
|
||||
LL_ASSERT(start_us == (subevent_us + 1U));
|
||||
|
||||
old_cis_lll = cis_lll;
|
||||
cis_lll = next_cis_lll;
|
||||
|
||||
struct node_tx_iso *node_tx;
|
||||
uint64_t payload_count;
|
||||
memq_link_t *link;
|
||||
|
||||
payload_count = cis_lll->event_count * cis_lll->tx.bn;
|
||||
|
||||
do {
|
||||
link = memq_peek(cis_lll->memq_tx.head,
|
||||
cis_lll->memq_tx.tail,
|
||||
(void **)&node_tx);
|
||||
if (!link) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node_tx->payload_count < payload_count) {
|
||||
memq_dequeue(cis_lll->memq_tx.tail,
|
||||
&cis_lll->memq_tx.head,
|
||||
NULL);
|
||||
|
||||
node_tx->next = link;
|
||||
ull_iso_lll_ack_enqueue(cis_lll->handle,
|
||||
node_tx);
|
||||
} else if (node_tx->payload_count >=
|
||||
(payload_count + cis_lll->tx.bn)) {
|
||||
link = NULL;
|
||||
} else {
|
||||
if (node_tx->payload_count !=
|
||||
payload_count) {
|
||||
link = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} while (link);
|
||||
|
||||
cis_lll = old_cis_lll;
|
||||
|
||||
/* Generate ISO Data Invalid Status */
|
||||
uint8_t bn = bn_rx;
|
||||
|
||||
while (bn <= cis_lll->rx.bn) {
|
||||
struct node_rx_iso_meta *iso_meta;
|
||||
struct node_rx_pdu *node_rx;
|
||||
|
||||
node_rx = ull_iso_pdu_rx_alloc_peek(2U);
|
||||
if (!node_rx) {
|
||||
break;
|
||||
}
|
||||
|
||||
node_rx->hdr.type = NODE_RX_TYPE_ISO_PDU;
|
||||
node_rx->hdr.handle = cis_lll->handle;
|
||||
iso_meta = &node_rx->hdr.rx_iso_meta;
|
||||
iso_meta->payload_number = (cis_lll->event_count *
|
||||
cis_lll->rx.bn) + (bn - 1U);
|
||||
iso_meta->timestamp =
|
||||
HAL_TICKER_TICKS_TO_US(radio_tmr_start_get()) +
|
||||
radio_tmr_ready_restore();
|
||||
iso_meta->timestamp %=
|
||||
HAL_TICKER_TICKS_TO_US(BIT(HAL_TICKER_CNTR_MSBIT + 1U));
|
||||
iso_meta->status = 1U;
|
||||
|
||||
ull_iso_pdu_rx_alloc();
|
||||
iso_rx_put(node_rx->hdr.link, node_rx);
|
||||
|
||||
bn++;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL)
|
||||
if (bn != bn_rx) {
|
||||
iso_rx_sched();
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -524,8 +678,8 @@ static void isr_rx(void *param)
|
|||
/* FIXME: Do not call this for every event/subevent */
|
||||
ull_conn_iso_lll_cis_established(param);
|
||||
|
||||
/* FIXME: set the bit corresponding to CIS index */
|
||||
trx_performed_bitmask = 1U;
|
||||
/* Set the bit corresponding to CIS index */
|
||||
trx_performed_bitmask |= (1U << LL_CIS_IDX_FROM_HANDLE(cis_lll->handle));
|
||||
|
||||
/* Get reference to received PDU */
|
||||
node_rx = ull_iso_pdu_rx_alloc_peek(1);
|
||||
|
@ -661,9 +815,163 @@ static void isr_rx(void *param)
|
|||
|
||||
isr_rx_next_subevent:
|
||||
if (cie || (se_curr == cis_lll->nse)) {
|
||||
struct lll_conn_iso_stream *old_cis_lll;
|
||||
struct lll_conn_iso_stream *next_cis_lll;
|
||||
struct lll_conn_iso_group *cig_lll;
|
||||
struct lll_conn *next_conn_lll;
|
||||
uint8_t phy;
|
||||
|
||||
/* Fetch next CIS */
|
||||
cig_lll = ull_conn_iso_lll_group_get_by_stream(cis_lll);
|
||||
do {
|
||||
next_cis_lll = ull_conn_iso_lll_stream_get_by_group(cig_lll,
|
||||
&cis_handle_curr);
|
||||
} while (next_cis_lll && !next_cis_lll->active);
|
||||
|
||||
if (!next_cis_lll) {
|
||||
goto isr_rx_done;
|
||||
}
|
||||
|
||||
/* Adjust sn when flushing Tx */
|
||||
/* FIXME: When Flush Timeout is implemented */
|
||||
if (bn_tx <= cis_lll->tx.bn) {
|
||||
cis_lll->sn += cis_lll->tx.bn + 1U - bn_tx;
|
||||
}
|
||||
|
||||
/* Adjust nesn when flushing Rx */
|
||||
/* FIXME: When Flush Timeout is implemented */
|
||||
if (bn_rx <= cis_lll->rx.bn) {
|
||||
cis_lll->nesn += cis_lll->rx.bn + 1U - bn_rx;
|
||||
}
|
||||
|
||||
/* Get reference to ACL context */
|
||||
next_conn_lll = ull_conn_lll_get(next_cis_lll->acl_handle);
|
||||
|
||||
/* Calculate CIS channel if not already calculated */
|
||||
if (se_curr < cis_lll->nse) {
|
||||
uint16_t event_counter;
|
||||
uint16_t data_chan_id;
|
||||
uint32_t subevent_us;
|
||||
uint32_t start_us;
|
||||
|
||||
/* Event counter value, 0-15 bit of cisEventCounter */
|
||||
event_counter = next_cis_lll->event_count;
|
||||
|
||||
/* Calculate the radio channel to use for ISO event */
|
||||
data_chan_id = lll_chan_id(next_cis_lll->access_addr);
|
||||
next_cis_chan = lll_chan_iso_event(event_counter, data_chan_id,
|
||||
next_conn_lll->data_chan_map,
|
||||
next_conn_lll->data_chan_count,
|
||||
&next_cis_chan_prn_s,
|
||||
&next_cis_chan_remap_idx);
|
||||
|
||||
subevent_us = radio_tmr_ready_restore();
|
||||
subevent_us += next_cis_lll->offset - cis_offset_first;
|
||||
|
||||
start_us = radio_tmr_start_us(1U, subevent_us);
|
||||
LL_ASSERT(start_us == (subevent_us + 1U));
|
||||
|
||||
old_cis_lll = cis_lll;
|
||||
cis_lll = next_cis_lll;
|
||||
|
||||
struct node_tx_iso *node_tx;
|
||||
uint64_t payload_count;
|
||||
memq_link_t *link;
|
||||
|
||||
payload_count = cis_lll->event_count * cis_lll->tx.bn;
|
||||
|
||||
do {
|
||||
link = memq_peek(cis_lll->memq_tx.head,
|
||||
cis_lll->memq_tx.tail,
|
||||
(void **)&node_tx);
|
||||
if (!link) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node_tx->payload_count < payload_count) {
|
||||
memq_dequeue(cis_lll->memq_tx.tail,
|
||||
&cis_lll->memq_tx.head,
|
||||
NULL);
|
||||
|
||||
node_tx->next = link;
|
||||
ull_iso_lll_ack_enqueue(cis_lll->handle,
|
||||
node_tx);
|
||||
} else if (node_tx->payload_count >=
|
||||
(payload_count + cis_lll->tx.bn)) {
|
||||
link = NULL;
|
||||
} else {
|
||||
if (node_tx->payload_count !=
|
||||
payload_count) {
|
||||
link = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} while (link);
|
||||
|
||||
cis_lll = old_cis_lll;
|
||||
|
||||
/* Generate ISO Data Invalid Status */
|
||||
uint8_t bn = bn_rx;
|
||||
|
||||
while (bn <= cis_lll->rx.bn) {
|
||||
struct node_rx_iso_meta *iso_meta;
|
||||
struct node_rx_pdu *node_rx;
|
||||
|
||||
node_rx = ull_iso_pdu_rx_alloc_peek(2U);
|
||||
if (!node_rx) {
|
||||
break;
|
||||
}
|
||||
|
||||
node_rx->hdr.type = NODE_RX_TYPE_ISO_PDU;
|
||||
node_rx->hdr.handle = cis_lll->handle;
|
||||
iso_meta = &node_rx->hdr.rx_iso_meta;
|
||||
iso_meta->payload_number = (cis_lll->event_count *
|
||||
cis_lll->rx.bn) + (bn - 1U);
|
||||
iso_meta->timestamp =
|
||||
HAL_TICKER_TICKS_TO_US(radio_tmr_start_get()) +
|
||||
radio_tmr_ready_restore();
|
||||
iso_meta->timestamp %=
|
||||
HAL_TICKER_TICKS_TO_US(BIT(HAL_TICKER_CNTR_MSBIT + 1U));
|
||||
iso_meta->status = 1U;
|
||||
|
||||
ull_iso_pdu_rx_alloc();
|
||||
iso_rx_put(node_rx->hdr.link, node_rx);
|
||||
|
||||
bn++;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_BT_CTLR_LOW_LAT_ULL)
|
||||
if (bn != bn_rx) {
|
||||
iso_rx_sched();
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_LOW_LAT_ULL */
|
||||
|
||||
}
|
||||
|
||||
/* Reset indices for the next CIS */
|
||||
se_curr = 0U; /* isr_prepare_subevent() will increase se_curr */
|
||||
bn_tx = 1U;
|
||||
bn_rx = 1U;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
radio_tx_power_set(next_cis_lll->tx_pwr_lvl);
|
||||
#else
|
||||
radio_tx_power_set(RADIO_TXP_DEFAULT);
|
||||
#endif
|
||||
|
||||
phy = next_cis_lll->tx.phy;
|
||||
radio_phy_set(phy, next_cis_lll->tx.phy_flags);
|
||||
radio_aa_set(next_cis_lll->access_addr);
|
||||
radio_crc_configure(PDU_CRC_POLYNOMIAL,
|
||||
sys_get_le24(next_conn_lll->crc_init));
|
||||
|
||||
param = next_cis_lll;
|
||||
next_chan_use = next_cis_chan;
|
||||
data_chan_prn_s = next_cis_chan_prn_s;
|
||||
data_chan_remap_idx = next_cis_chan_remap_idx;
|
||||
}
|
||||
|
||||
isr_prepare_subevent(param);
|
||||
|
||||
return;
|
||||
|
@ -782,15 +1090,9 @@ static void isr_prepare_subevent(void *param)
|
|||
|
||||
lll_chan_set(next_chan_use);
|
||||
|
||||
subevent_us = radio_tmr_ready_restore();
|
||||
subevent_us += cis_lll->sub_interval * se_curr;
|
||||
|
||||
radio_tmr_rx_disable();
|
||||
radio_tmr_tx_enable();
|
||||
|
||||
/* Compensate for the 1 us added by radio_tmr_start_us() */
|
||||
start_us = subevent_us + 1U;
|
||||
|
||||
radio_tmr_tifs_set(EVENT_IFS_US);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
|
@ -799,6 +1101,13 @@ static void isr_prepare_subevent(void *param)
|
|||
radio_switch_complete_and_rx(0U);
|
||||
#endif /* !CONFIG_BT_CTLR_PHY */
|
||||
|
||||
subevent_us = radio_tmr_ready_restore();
|
||||
subevent_us += cis_lll->offset - cis_offset_first +
|
||||
(cis_lll->sub_interval * se_curr);
|
||||
|
||||
/* Compensate for the 1 us added by radio_tmr_start_us() */
|
||||
start_us = subevent_us + 1U;
|
||||
|
||||
/* capture end of Tx-ed PDU, used to calculate HCTO. */
|
||||
radio_tmr_end_capture();
|
||||
|
||||
|
|
|
@ -164,10 +164,6 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
&data_chan_prn_s,
|
||||
&data_chan_remap_idx);
|
||||
|
||||
se_curr = 1U;
|
||||
bn_rx = 1U;
|
||||
has_tx = 0U;
|
||||
|
||||
/* current window widening */
|
||||
cig_lll->window_widening_event_us_frac +=
|
||||
cig_lll->window_widening_prepare_us_frac;
|
||||
|
@ -178,14 +174,22 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
EVENT_US_TO_US_FRAC(cig_lll->window_widening_max_us);
|
||||
}
|
||||
|
||||
/* Adjust sn and nesn for skipped CIG events */
|
||||
cis_lll->sn += cis_lll->tx.bn * p->lazy;
|
||||
cis_lll->nesn += cis_lll->rx.bn * p->lazy;
|
||||
|
||||
se_curr = 1U;
|
||||
bn_rx = 1U;
|
||||
has_tx = 0U;
|
||||
|
||||
/* Start setting up of Radio h/w */
|
||||
radio_reset();
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
|
||||
radio_tx_power_set(lll->tx_pwr_lvl);
|
||||
#else
|
||||
radio_tx_power_set(cis_lll->tx_pwr_lvl);
|
||||
#else /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
radio_tx_power_set(RADIO_TXP_DEFAULT);
|
||||
#endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
#endif /* !CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
|
||||
|
||||
phy = cis_lll->rx.phy;
|
||||
radio_phy_set(phy, cis_lll->rx.phy_flags);
|
||||
|
@ -247,7 +251,8 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
ticks_at_event += lll_event_offset_get(ull);
|
||||
|
||||
ticks_at_start = ticks_at_event;
|
||||
ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
|
||||
ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US +
|
||||
cis_lll->offset);
|
||||
|
||||
remainder = p->remainder;
|
||||
start_us = radio_tmr_start(0U, ticks_at_start, remainder);
|
||||
|
@ -261,9 +266,6 @@ static int prepare_cb(struct lll_prepare_param *p)
|
|||
EVENT_US_FRAC_TO_US(cig_lll->window_widening_event_us_frac)) <<
|
||||
1U);
|
||||
|
||||
/* Compensate for unused ticker remainder value starting CIG */
|
||||
hcto += EVENT_TICKER_RES_MARGIN_US;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
hcto += radio_rx_ready_delay_get(cis_lll->rx.phy, PHY_FLAGS_S8);
|
||||
hcto += addr_us_get(cis_lll->rx.phy);
|
||||
|
@ -582,7 +584,7 @@ static void isr_rx(void *param)
|
|||
(bn_tx > cis_lll->tx.bn) &&
|
||||
(se_curr < cis_lll->nse));
|
||||
|
||||
/* TODO: Get ISO data PDU */
|
||||
/* Get ISO data PDU */
|
||||
if (bn_tx > cis_lll->tx.bn) {
|
||||
payload_count = 0U;
|
||||
|
||||
|
@ -703,7 +705,8 @@ static void isr_rx(void *param)
|
|||
uint32_t start_us;
|
||||
|
||||
subevent_us = radio_tmr_aa_restore();
|
||||
subevent_us += cis_lll->sub_interval * se_curr;
|
||||
subevent_us += cis_lll->offset +
|
||||
(cis_lll->sub_interval * se_curr);
|
||||
subevent_us -= addr_us_get(cis_lll->rx.phy);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
|
@ -810,7 +813,7 @@ static void isr_tx(void *param)
|
|||
cig_lll = ull_conn_iso_lll_group_get_by_stream(cis_lll);
|
||||
|
||||
subevent_us = radio_tmr_aa_restore();
|
||||
subevent_us += cis_lll->sub_interval * se_curr;
|
||||
subevent_us += cis_lll->offset + (cis_lll->sub_interval * se_curr);
|
||||
subevent_us -= addr_us_get(cis_lll->rx.phy);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
|
@ -942,7 +945,8 @@ static void isr_prepare_subevent(void *param)
|
|||
/* Anchor point sync-ed */
|
||||
if (trx_performed_bitmask) {
|
||||
subevent_us = radio_tmr_aa_restore();
|
||||
subevent_us += cis_lll->sub_interval * se_curr;
|
||||
subevent_us += cis_lll->offset +
|
||||
(cis_lll->sub_interval * se_curr);
|
||||
subevent_us -= addr_us_get(cis_lll->rx.phy);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
|
@ -956,7 +960,8 @@ static void isr_prepare_subevent(void *param)
|
|||
#endif /* !CONFIG_BT_CTLR_PHY */
|
||||
} else {
|
||||
subevent_us = radio_tmr_ready_restore();
|
||||
subevent_us += cis_lll->sub_interval * se_curr;
|
||||
subevent_us += cis_lll->offset +
|
||||
(cis_lll->sub_interval * se_curr);
|
||||
}
|
||||
|
||||
start_us = radio_tmr_start_us(0U, subevent_us);
|
||||
|
|
|
@ -634,7 +634,6 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle,
|
|||
struct ll_conn_iso_group *cig;
|
||||
uint16_t event_counter;
|
||||
struct ll_conn *conn;
|
||||
uint16_t handle_iter;
|
||||
uint32_t cis_offset;
|
||||
uint16_t instant;
|
||||
|
||||
|
@ -648,21 +647,14 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle,
|
|||
return BT_HCI_ERR_UNSPECIFIED;
|
||||
}
|
||||
|
||||
/* ACL connection of the new CIS */
|
||||
conn = ll_conn_get(cis->lll.acl_handle);
|
||||
event_counter = ull_conn_event_counter(conn);
|
||||
instant = MAX(*conn_event_count, event_counter + 1);
|
||||
|
||||
handle_iter = UINT16_MAX;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
|
||||
cis_offset = *cis_offset_min;
|
||||
|
||||
#else /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
|
||||
cis_offset = MAX((HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) +
|
||||
(EVENT_TICKER_RES_MARGIN_US << 1U)), *cis_offset_min);
|
||||
|
||||
#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
|
||||
|
||||
/* Calculate offset for CIS */
|
||||
if (cig->started) {
|
||||
uint32_t time_of_intant;
|
||||
|
@ -690,6 +682,15 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle,
|
|||
}
|
||||
|
||||
cis->offset = cis_offset;
|
||||
|
||||
#else /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
|
||||
cis_offset = MAX((HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) +
|
||||
(EVENT_TICKER_RES_MARGIN_US << 1U) + cig->sync_delay -
|
||||
cis->sync_delay), *cis_offset_min);
|
||||
cis->offset = cis_offset;
|
||||
|
||||
#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
|
||||
|
||||
cis->central.instant = instant;
|
||||
cis->lll.event_count = -1;
|
||||
cis->lll.next_subevent = 0U;
|
||||
|
@ -718,32 +719,36 @@ uint16_t ull_central_iso_cis_offset_get(uint16_t cis_handle, uint32_t *cis_offse
|
|||
uint32_t *cis_offset_max)
|
||||
{
|
||||
struct ll_conn_iso_stream *cis;
|
||||
struct ll_conn_iso_group *cig;
|
||||
struct ll_conn *conn;
|
||||
|
||||
cis = ll_conn_iso_stream_get(cis_handle);
|
||||
LL_ASSERT(cis);
|
||||
|
||||
conn = ll_conn_get(cis->lll.acl_handle);
|
||||
|
||||
if (cis_offset_min && cis_offset_max) {
|
||||
struct ll_conn_iso_group *cig;
|
||||
|
||||
cig = cis->group;
|
||||
|
||||
conn = ll_conn_get(cis->lll.acl_handle);
|
||||
|
||||
/* 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_max = (conn->lll.interval * CONN_INT_UNIT_US) -
|
||||
cig->sync_delay;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_JIT_SCHEDULING)) {
|
||||
*cis_offset_min = MAX(400, EVENT_OVERHEAD_CIS_SETUP_US);
|
||||
} else {
|
||||
#if (CONFIG_BT_CTLR_CENTRAL_SPACING > 0)
|
||||
*cis_offset_min = HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) +
|
||||
(EVENT_TICKER_RES_MARGIN_US << 1U);
|
||||
}
|
||||
(EVENT_TICKER_RES_MARGIN_US << 1U) +
|
||||
cig->sync_delay - cis->sync_delay;
|
||||
#else /* !CONFIG_BT_CTLR_CENTRAL_SPACING */
|
||||
LL_ASSERT(false);
|
||||
#endif /* !CONFIG_BT_CTLR_CENTRAL_SPACING */
|
||||
}
|
||||
|
||||
cis->central.instant = ull_conn_event_counter(conn) + 3;
|
||||
|
||||
return cis->central.instant;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,6 +159,18 @@ struct ll_conn_iso_stream *ll_conn_iso_stream_get(uint16_t handle)
|
|||
LL_CIS_HANDLE_BASE);
|
||||
}
|
||||
|
||||
struct lll_conn_iso_stream *ull_conn_iso_lll_stream_get(uint16_t handle)
|
||||
{
|
||||
struct ll_conn_iso_stream *cis;
|
||||
|
||||
cis = ll_conn_iso_stream_get(handle);
|
||||
if (!cis) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &cis->lll;
|
||||
}
|
||||
|
||||
struct ll_conn_iso_stream *ll_iso_stream_connected_get(uint16_t handle)
|
||||
{
|
||||
struct ll_conn_iso_stream *cis;
|
||||
|
@ -256,6 +268,9 @@ ull_conn_iso_lll_stream_get_by_group(struct lll_conn_iso_group *cig_lll,
|
|||
|
||||
cig = HDR_LLL2ULL(cig_lll);
|
||||
cis = ll_conn_iso_stream_get_by_group(cig, handle_iter);
|
||||
if (!cis) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &cis->lll;
|
||||
}
|
||||
|
@ -419,6 +434,13 @@ void ull_conn_iso_cis_stop(struct ll_conn_iso_stream *cis,
|
|||
|
||||
if (cis->teardown) {
|
||||
/* Teardown already started */
|
||||
LL_ASSERT(!cis->released_cb || !cis_released_cb ||
|
||||
(cis->released_cb == cis_released_cb));
|
||||
|
||||
if (cis_released_cb) {
|
||||
cis->released_cb = cis_released_cb;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -998,13 +1020,15 @@ static void cis_disabled_cb(void *param)
|
|||
uint8_t active_cises;
|
||||
uint16_t handle_iter;
|
||||
uint8_t cis_idx;
|
||||
uint8_t num_cis;
|
||||
|
||||
cig = HDR_LLL2ULL(param);
|
||||
handle_iter = UINT16_MAX;
|
||||
active_cises = 0;
|
||||
|
||||
/* Remove all CISes marked for teardown */
|
||||
for (cis_idx = 0; cis_idx < cig->lll.num_cis; cis_idx++) {
|
||||
num_cis = cig->lll.num_cis;
|
||||
for (cis_idx = 0; cis_idx < num_cis; cis_idx++) {
|
||||
cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter);
|
||||
LL_ASSERT(cis);
|
||||
|
||||
|
@ -1020,6 +1044,7 @@ static void cis_disabled_cb(void *param)
|
|||
|
||||
conn = ll_conn_get(cis->lll.acl_handle);
|
||||
cis_released_cb = cis->released_cb;
|
||||
cis->released_cb = NULL;
|
||||
|
||||
if (IS_PERIPHERAL(cig)) {
|
||||
/* Remove data path and ISOAL sink/source associated with this
|
||||
|
@ -1031,12 +1056,19 @@ static void cis_disabled_cb(void *param)
|
|||
BT_HCI_DATAPATH_DIR_HOST_TO_CTLR);
|
||||
|
||||
ll_conn_iso_stream_release(cis);
|
||||
|
||||
cig->lll.num_cis--;
|
||||
|
||||
} else if (IS_CENTRAL(cig)) {
|
||||
cis->established = 0U;
|
||||
cis->teardown = 0U;
|
||||
|
||||
/* Prevent referencing inactive CIS */
|
||||
cis->lll.flushed = 0U;
|
||||
cis->lll.acl_handle = LLL_HANDLE_INVALID;
|
||||
|
||||
} else {
|
||||
LL_ASSERT(0);
|
||||
}
|
||||
|
||||
/* CIS is no longer active */
|
||||
|
@ -1056,10 +1088,11 @@ static void cis_disabled_cb(void *param)
|
|||
} else if (cis->teardown) {
|
||||
DECLARE_MAYFLY_ARRAY(mfys, cis_tx_lll_flush,
|
||||
CONFIG_BT_CTLR_CONN_ISO_GROUPS);
|
||||
struct node_rx_pdu *node_terminate;
|
||||
uint32_t ret;
|
||||
|
||||
if (cis->established) {
|
||||
struct node_rx_pdu *node_terminate;
|
||||
|
||||
/* Create and enqueue termination node. This shall prevent
|
||||
* further enqueuing of TX nodes for terminating CIS.
|
||||
*/
|
||||
|
@ -1130,7 +1163,6 @@ static void cis_tx_lll_flush(void *param)
|
|||
struct ll_conn_iso_group *cig;
|
||||
struct node_tx_iso *tx;
|
||||
memq_link_t *link;
|
||||
uint32_t ret;
|
||||
|
||||
lll = param;
|
||||
lll->flushed = 1U;
|
||||
|
@ -1159,9 +1191,8 @@ static void cis_tx_lll_flush(void *param)
|
|||
|
||||
/* Resume CIS teardown in ULL_HIGH context */
|
||||
mfys[cig->lll.handle].param = &cig->lll;
|
||||
ret = mayfly_enqueue(TICKER_USER_ID_LLL,
|
||||
(void)mayfly_enqueue(TICKER_USER_ID_LLL,
|
||||
TICKER_USER_ID_ULL_HIGH, 1, &mfys[cig->lll.handle]);
|
||||
LL_ASSERT(!ret);
|
||||
}
|
||||
|
||||
static void ticker_stop_op_cb(uint32_t status, void *param)
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
|
||||
/* CIS */
|
||||
#if defined(CONFIG_BT_CTLR_CONN_ISO)
|
||||
#define LL_CIS_HANDLE_BASE (BT_CTLR_CONN_ISO_STREAM_HANDLE_BASE)
|
||||
#define LL_CIS_IDX_FROM_HANDLE(_handle) \
|
||||
((_handle) - LL_CIS_HANDLE_BASE)
|
||||
#define LL_CIS_HANDLE_LAST \
|
||||
(CONFIG_BT_CTLR_CONN_ISO_STREAMS + LL_CIS_HANDLE_BASE - 1)
|
||||
#define IS_CIS_HANDLE(_handle) \
|
||||
|
|
|
@ -905,10 +905,9 @@ uint8_t ull_cp_cis_create(struct ll_conn *conn, struct ll_conn_iso_stream *cis)
|
|||
ctx->data.cis_create.c_ft = cis->lll.tx.ft;
|
||||
ctx->data.cis_create.p_ft = cis->lll.rx.ft;
|
||||
|
||||
ctx->data.cis_create.conn_event_count =
|
||||
ull_central_iso_cis_offset_get(cis->lll.handle,
|
||||
&ctx->data.cis_create.cis_offset_min,
|
||||
&ctx->data.cis_create.cis_offset_max);
|
||||
/* ctx->data.cis_create.conn_event_count will be filled when Tx PDU is
|
||||
* enqueued.
|
||||
*/
|
||||
|
||||
llcp_lr_enqueue(conn, ctx);
|
||||
|
||||
|
|
|
@ -751,7 +751,9 @@ static void lp_cc_send_cis_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8
|
|||
} 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);
|
||||
ull_central_iso_cis_offset_get(ctx->data.cis_create.cis_handle,
|
||||
&ctx->data.cis_create.cis_offset_min,
|
||||
&ctx->data.cis_create.cis_offset_max);
|
||||
|
||||
lp_cc_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CIS_REQ);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue