Bluetooth: Controller: Fix CIS offset_min for dissimilar interval

Fix CIS offset_min calculation to consider that ACL interval
and ISO interval can be dissimilar and the offset value has
to be compensated for the latency until the instant at which
the offset is used.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2023-05-14 15:32:02 +05:30 committed by Carles Cufí
parent 22e67eac6e
commit 3b3d53f09e
4 changed files with 34 additions and 3 deletions

View file

@ -53,6 +53,8 @@ struct lll_conn_iso_stream {
memq_link_t *link_tx_free;
};
#define LLL_CONN_ISO_EVENT_COUNT_MAX BIT64_MASK(39)
struct lll_conn_iso_group {
struct lll_hdr hdr;

View file

@ -351,6 +351,7 @@
((enc) ? \
(PDU_MIC_SIZE) : 0), \
(phy))
#define PDU_CIS_OFFSET_MIN_US 500U
struct pdu_adv_adv_ind {
uint8_t addr[BDADDR_SIZE];

View file

@ -563,7 +563,7 @@ void ll_cis_create(uint16_t cis_handle, uint16_t acl_handle)
/* Initialize stream states */
cis->established = 0;
cis->teardown = 0;
cis->lll.event_count = 0;
cis->lll.event_count = LLL_CONN_ISO_EVENT_COUNT_MAX;
cis->lll.sn = 0;
cis->lll.nesn = 0;
cis->lll.cie = 0;
@ -732,7 +732,6 @@ uint8_t ull_central_iso_setup(uint16_t cis_handle,
#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
cis->central.instant = instant;
cis->lll.event_count = -1;
cis->lll.next_subevent = 0U;
cis->lll.sn = 0U;
cis->lll.nesn = 0U;
@ -863,10 +862,13 @@ static void cis_offset_get(struct ll_conn_iso_stream *cis)
static void mfy_cis_offset_get(void *param)
{
uint32_t elapsed_acl_us, elapsed_cig_us;
uint16_t latency_acl, latency_cig;
struct ll_conn_iso_stream *cis;
struct ll_conn_iso_group *cig;
uint32_t cig_remainder_us;
uint32_t acl_remainder_us;
uint32_t cig_interval_us;
uint32_t ticks_to_expire;
uint32_t ticks_current;
uint32_t offset_min_us;
@ -953,6 +955,32 @@ static void mfy_cis_offset_get(void *param)
cig_remainder_us + cig->sync_delay -
acl_remainder_us - cis->sync_delay;
/* Calculate instant latency */
/* 32-bits are sufficient as maximum connection interval is 4 seconds,
* and latency counts (typically 3) is low enough to avoid 32-bit
* overflow. Refer to ull_central_iso_cis_offset_get().
*/
latency_acl = cis->central.instant - ull_conn_event_counter(conn);
elapsed_acl_us = latency_acl * conn->lll.interval * CONN_INT_UNIT_US;
/* Calculate elapsed CIG intervals until the instant */
cig_interval_us = cig->iso_interval * ISO_INT_UNIT_US;
latency_cig = DIV_ROUND_UP(elapsed_acl_us, cig_interval_us);
elapsed_cig_us = latency_cig * cig_interval_us;
/* Compensate for the difference between ACL elapsed vs CIG elapsed */
offset_min_us += elapsed_cig_us - elapsed_acl_us;
while (offset_min_us > (cig_interval_us + PDU_CIS_OFFSET_MIN_US)) {
offset_min_us -= cig_interval_us;
}
/* Decrement event_count to compensate for offset_min_us greater than
* CIG interval due to offset being atleast PDU_CIS_OFFSET_MIN_US.
*/
if (offset_min_us > cig_interval_us) {
cis->lll.event_count--;
}
ull_cp_cc_offset_calc_reply(conn, offset_min_us, offset_min_us);
}

View file

@ -319,7 +319,7 @@ uint8_t ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind *ind,
cis->sync_delay = sys_get_le24(ind->cis_sync_delay);
cis->offset = cis_offset;
memcpy(cis->lll.access_addr, ind->aa, sizeof(ind->aa));
cis->lll.event_count = -1;
cis->lll.event_count = LLL_CONN_ISO_EVENT_COUNT_MAX;
cis->lll.next_subevent = 0U;
cis->lll.sn = 0U;
cis->lll.nesn = 0U;