Bluetooth: Controller: Add back the use of pre-transmissions

Add back the implementation in the Controller that tries to
enable pre-transmissions to improve time diversity to aid a
remote ISO Sync Receiver role device.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2025-01-08 06:19:15 +01:00 committed by Benjamin Cabé
commit 9cd9f4150d
3 changed files with 67 additions and 9 deletions

View file

@ -669,6 +669,10 @@ static void isr_tx_common(void *param,
(tx->payload_count < payload_count)); (tx->payload_count < payload_count));
} }
if (!link || (tx->payload_count != payload_count)) { if (!link || (tx->payload_count != payload_count)) {
/* FIXME: Do not transmit on air an empty PDU if this is a Pre-Transmission
* subevent, instead use radio_tmr_start_us() to schedule next valid
* subevent.
*/
pdu = radio_pkt_empty_get(); pdu = radio_pkt_empty_get();
pdu->ll_id = lll->framing ? PDU_BIS_LLID_FRAMED : pdu->ll_id = lll->framing ? PDU_BIS_LLID_FRAMED :
PDU_BIS_LLID_START_CONTINUE; PDU_BIS_LLID_START_CONTINUE;

View file

@ -51,6 +51,17 @@
#include "hal/debug.h" #include "hal/debug.h"
/* Controller implementation dependent minimum Pre-Transmission Offset and
* Pre-Transmission Group Count to use when there is available time space in the
* BIG events.
* The number of Pre-Transmission Group Count configure how many future ISO SDUs
* from the Offset will be Pre-Transmitted in advance in the current BIG event.
*
* TODO: These could be a Kconfig option.
*/
#define BT_CTLR_ADV_ISO_PTO_MIN 1U
#define BT_CTLR_ADV_ISO_PTO_GROUP_COUNT 1U
static int init_reset(void); static int init_reset(void);
static struct ll_adv_iso_set *adv_iso_get(uint8_t handle); static struct ll_adv_iso_set *adv_iso_get(uint8_t handle);
static struct stream *adv_iso_stream_acquire(void); static struct stream *adv_iso_stream_acquire(void);
@ -357,7 +368,12 @@ static uint8_t big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bi
lll_adv_iso->max_pdu = MIN(LL_BIS_OCTETS_TX_MAX, max_sdu); lll_adv_iso->max_pdu = MIN(LL_BIS_OCTETS_TX_MAX, max_sdu);
} }
/* FIXME: SDU per max latency */ /* FIXME: SDU per max latency, consider how to use Pre-transmission in the
* calculations.
* Take decision based on how ptc_calc function forces the use of
* Pre-Transmission when not using test command. Refer to comments in
* ptc_calc function.
*/
sdu_per_event = MAX((max_latency * USEC_PER_MSEC / sdu_interval), 2U) - sdu_per_event = MAX((max_latency * USEC_PER_MSEC / sdu_interval), 2U) -
1U; 1U;
@ -443,6 +459,9 @@ static uint8_t big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bi
return BT_HCI_ERR_INVALID_PARAM; return BT_HCI_ERR_INVALID_PARAM;
} }
/* Decision to use requested Pre-Transmission Offset or force Pre-Transmission when
* possible (Zephyr Controller decision).
*/
lll_adv_iso->ptc = ptc_calc(lll_adv_iso, event_spacing, event_spacing_max); lll_adv_iso->ptc = ptc_calc(lll_adv_iso, event_spacing, event_spacing_max);
if (test_config) { if (test_config) {
@ -454,7 +473,7 @@ static uint8_t big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bi
} else { } else {
/* Pre-Transmission Offset (PTO) */ /* Pre-Transmission Offset (PTO) */
if (lll_adv_iso->ptc) { if (lll_adv_iso->ptc) {
lll_adv_iso->pto = bn / lll_adv_iso->bn; lll_adv_iso->pto = MAX((bn / lll_adv_iso->bn), BT_CTLR_ADV_ISO_PTO_MIN);
} else { } else {
lll_adv_iso->pto = 0U; lll_adv_iso->pto = 0U;
} }
@ -1154,15 +1173,43 @@ static uint8_t ptc_calc(const struct lll_adv_iso *lll, uint32_t event_spacing,
uint32_t event_spacing_max) uint32_t event_spacing_max)
{ {
if (event_spacing < event_spacing_max) { if (event_spacing < event_spacing_max) {
uint8_t ptc; uint32_t ptc;
uint8_t nse;
/* Possible maximum Pre-transmission Subevents per BIS */ /* Possible maximum Pre-transmission Subevents per BIS.
* sub_interval is at least T_MSS_150 + MPT (hence a value in 8 bits or more), i.e.
* the below division and the subsequent multiplication with lll->bn does not
* overflow.
*/
ptc = ((event_spacing_max - event_spacing) / ptc = ((event_spacing_max - event_spacing) /
(lll->sub_interval * lll->bn * lll->num_bis)) * (lll->sub_interval * lll->bn * lll->num_bis)) *
lll->bn; lll->bn;
/* Restrict PTC to number of available subevents */ /* Required NSE */
ptc = MIN(ptc, lll->nse - lll->bn * lll->irc); nse = lll->bn * lll->irc; /* 3 bits * 4 bits, total 7 bits */
/* Requested NSE is greater than Required NSE, Pre-Transmission offset has been
* provided.
*
* NOTE: This is the case under HCI test command use to create BIG, i.e. test_config
* variable is true.
*/
if (lll->nse > nse) {
/* Restrict PTC to number of available subevents */
ptc = MIN(ptc, lll->nse - nse);
} else {
/* No PTO requested, Zephyr Controller implementation here will try using
* Pre-Transmisson offset of BT_CTLR_ADV_ISO_PTO_MIN, i.e. restrict to a
* maximum of BN Pre-Transmission subevents per BIS. This allows for a
* better time diversity ensuring skipped or missing reception at the ISO
* Sync Receiver so it can still have another chance at receiving the ISO
* PDUs within the permitted maximum transport latency.
*
* Usecases where BAP Broadcast Audio Assistant role device has a drifting
* ACL Peripheral role active in the BAP Broadcast Audio Sink device.
*/
ptc = MIN(ptc, (lll->bn * BT_CTLR_ADV_ISO_PTO_GROUP_COUNT));
}
return ptc; return ptc;
} }

View file

@ -483,13 +483,20 @@ void ull_sync_iso_setup(struct ll_sync_iso_set *sync_iso,
lll->sub_interval = PDU_BIG_INFO_SUB_INTERVAL_GET(bi); lll->sub_interval = PDU_BIG_INFO_SUB_INTERVAL_GET(bi);
lll->max_pdu = bi->max_pdu; lll->max_pdu = bi->max_pdu;
lll->pto = PDU_BIG_INFO_PTO_GET(bi); lll->pto = PDU_BIG_INFO_PTO_GET(bi);
lll->bis_spacing = PDU_BIG_INFO_SPACING_GET(bi);
lll->irc = PDU_BIG_INFO_IRC_GET(bi);
if (lll->pto) { if (lll->pto) {
lll->ptc = lll->bn; uint8_t nse;
nse = lll->irc * lll->bn; /* 4 bits * 3 bits, total 7 bits */
if (nse >= lll->nse) {
return;
}
lll->ptc = lll->nse - nse;
} else { } else {
lll->ptc = 0U; lll->ptc = 0U;
} }
lll->bis_spacing = PDU_BIG_INFO_SPACING_GET(bi);
lll->irc = PDU_BIG_INFO_IRC_GET(bi);
lll->sdu_interval = PDU_BIG_INFO_SDU_INTERVAL_GET(bi); lll->sdu_interval = PDU_BIG_INFO_SDU_INTERVAL_GET(bi);
/* Pick the 39-bit payload count, 1 MSb is framing bit */ /* Pick the 39-bit payload count, 1 MSb is framing bit */