From cb9f39f18f3369563d3321eaafed413ddd89a5e1 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Fri, 6 Oct 2023 15:42:39 +0200 Subject: [PATCH] nimble/ll: Improve scheduling of 1st BIG event This improves BIG scheduling in case periodic advertising interval is an integer multiple of ISO interval. In such case placing BIG event directly before periodic advertising event makes sure both won't overlap even if periodic advertising data changes in future. Note that there may still be conflicts with other instances and this patch doesn't resolve that. --- .../include/controller/ble_ll_sched.h | 2 +- nimble/controller/src/ble_ll_iso_big.c | 38 ++++++++++++++----- nimble/controller/src/ble_ll_sched.c | 4 +- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/nimble/controller/include/controller/ble_ll_sched.h b/nimble/controller/include/controller/ble_ll_sched.h index cceb96ce11..5daa647fab 100644 --- a/nimble/controller/include/controller/ble_ll_sched.h +++ b/nimble/controller/include/controller/ble_ll_sched.h @@ -219,7 +219,7 @@ uint32_t ble_ll_sched_css_get_conn_interval_us(void); #endif #if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) -int ble_ll_sched_iso_big(struct ble_ll_sched_item *sch, int first); +int ble_ll_sched_iso_big(struct ble_ll_sched_item *sch, int first, int fixed); #endif /* BLE_LL_ISO_BROADCASTER */ #ifdef __cplusplus diff --git a/nimble/controller/src/ble_ll_iso_big.c b/nimble/controller/src/ble_ll_iso_big.c index 31bcd21f0f..b836fed0b8 100644 --- a/nimble/controller/src/ble_ll_iso_big.c +++ b/nimble/controller/src/ble_ll_iso_big.c @@ -498,7 +498,7 @@ ble_ll_iso_big_event_done(struct ble_ll_iso_big *big) } /* XXX this should always succeed since we preempt anything for now */ - rc = ble_ll_sched_iso_big(&big->sch, 0); + rc = ble_ll_sched_iso_big(&big->sch, 0, 0); assert(rc == 0); } while (rc < 0); @@ -1029,18 +1029,36 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, * not enough for some phys to run scheduler item. */ - /* Schedule 1st event a bit in future */ - /* FIXME schedule 6ms in the future to avoid conflict with periodic - * advertising when both are started at the same time; we should - * select this value in some smart way later... - */ - big->sch.start_time = ble_ll_tmr_get() + ble_ll_tmr_u2t(6000); + uint32_t start_time, end_time, big_time; + uint32_t sync_delay_ticks = ble_ll_tmr_u2t_up(big->sync_delay); + uint32_t iso_interval_ticks = ble_ll_tmr_u2t_up(big->iso_interval * 1250); + int big_event_fixed; + + rc = ble_ll_adv_sync_sched_get(big->advsm, &start_time, &end_time); + if (rc) { + /* Set 1st BIG one interval after "now", this ensures it's always + * scheduled in the future. + */ + big_time = ble_ll_tmr_get() + iso_interval_ticks; + big_event_fixed = 0; + } else { + /* Set 1st BIG event directly before periodic advertising event, this + * way it will not overlap it even if periodic advertising data changes. + * Make sure it's in the future. + */ + big_time = start_time - g_ble_ll_sched_offset_ticks - sync_delay_ticks - 1; + while (big_time - g_ble_ll_sched_offset_ticks < ble_ll_tmr_get()) { + big_time += iso_interval_ticks; + } + big_event_fixed = 1; + } + + big->sch.start_time = big_time; big->sch.remainder = 0; - big->sch.end_time = big->sch.start_time + - ble_ll_tmr_u2t_up(big->sync_delay) + 1; + big->sch.end_time = big->sch.start_time + sync_delay_ticks + 1; big->sch.start_time -= g_ble_ll_sched_offset_ticks; - rc = ble_ll_sched_iso_big(&big->sch, 1); + rc = ble_ll_sched_iso_big(&big->sch, 1, big_event_fixed); if (rc < 0) { ble_ll_iso_big_free(big); return -EFAULT; diff --git a/nimble/controller/src/ble_ll_sched.c b/nimble/controller/src/ble_ll_sched.c index 8e8cee18fe..5cd01e04a5 100644 --- a/nimble/controller/src/ble_ll_sched.c +++ b/nimble/controller/src/ble_ll_sched.c @@ -844,14 +844,14 @@ ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch) #if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) int -ble_ll_sched_iso_big(struct ble_ll_sched_item *sch, int first) +ble_ll_sched_iso_big(struct ble_ll_sched_item *sch, int first, int fixed) { os_sr_t sr; int rc; OS_ENTER_CRITICAL(sr); - if (first) { + if (first && !fixed) { rc = ble_ll_sched_insert(sch, BLE_LL_SCHED_MAX_DELAY_ANY, preempt_none); } else { /* XXX provide better strategy for preemption */