This is an automated email from the ASF dual-hosted git repository. andk pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 6349d771d5547c567e6c6e653c67b685166bf1e3 Author: Andrzej Kaczmarek <andrzej.kaczma...@codecoup.pl> AuthorDate: Tue Jan 31 14:27:20 2023 +0100 nimble/ll: Add BIGInfo to periodic adv train This enables BIGInfo in periodic advertising which allows receiver to synchronize with BIG. --- nimble/controller/include/controller/ble_ll_adv.h | 14 +++ .../controller/include/controller/ble_ll_iso_big.h | 6 + nimble/controller/src/ble_ll_adv.c | 98 ++++++++++++++++ nimble/controller/src/ble_ll_iso_big.c | 130 ++++++++++++++++++++- 4 files changed, 247 insertions(+), 1 deletion(-) diff --git a/nimble/controller/include/controller/ble_ll_adv.h b/nimble/controller/include/controller/ble_ll_adv.h index 4afaadd0..ba17ed5e 100644 --- a/nimble/controller/include/controller/ble_ll_adv.h +++ b/nimble/controller/include/controller/ble_ll_adv.h @@ -199,6 +199,20 @@ int ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len); int ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); +/* Get advertising instance with periodic advertising configured */ +struct ble_ll_adv_sm *ble_ll_adv_sync_get(uint8_t handle); + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +struct ble_ll_iso_big; + +/* Add BIG to periodic advertising instance */ +int ble_ll_adv_sync_big_add(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big); +/* Remove BIG from periodic advertising instance */ +int ble_ll_adv_sync_big_remove(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big); +#endif /* BLE_LL_ISO_BROADCASTER */ + /* Called to notify adv code about RPA rotation */ void ble_ll_adv_rpa_timeout(void); diff --git a/nimble/controller/include/controller/ble_ll_iso_big.h b/nimble/controller/include/controller/ble_ll_iso_big.h index 1756fd26..c9052126 100644 --- a/nimble/controller/include/controller/ble_ll_iso_big.h +++ b/nimble/controller/include/controller/ble_ll_iso_big.h @@ -26,6 +26,12 @@ extern "C" { #if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +struct ble_ll_iso_big; + +int ble_ll_iso_big_biginfo_copy(struct ble_ll_iso_big *big, uint8_t *dptr, + uint32_t base_ticks, uint8_t base_rem_us); +int ble_ll_iso_big_biginfo_len(struct ble_ll_iso_big *big); + void ble_ll_iso_big_chan_map_update(void); void ble_ll_iso_big_halt(void); diff --git a/nimble/controller/src/ble_ll_adv.c b/nimble/controller/src/ble_ll_adv.c index c7f16e11..7056c8de 100644 --- a/nimble/controller/src/ble_ll_adv.c +++ b/nimble/controller/src/ble_ll_adv.c @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ + +#include <errno.h> #include <stdint.h> #include <stdlib.h> #include <string.h> @@ -40,6 +42,7 @@ #include "controller/ble_ll_trace.h" #include "controller/ble_ll_utils.h" #include "controller/ble_ll_rfmgmt.h" +#include "controller/ble_ll_iso_big.h" #include "ble_ll_conn_priv.h" #include "ble_ll_priv.h" @@ -77,6 +80,9 @@ struct ble_ll_adv_sync { uint8_t data_len; uint8_t payload_len; uint8_t auxptr_zero; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + struct ble_ll_iso_big *big; +#endif }; /* @@ -174,6 +180,11 @@ struct ble_ll_adv_sm uint16_t periodic_event_cntr_last_sent; #endif #endif + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + struct ble_ll_iso_big *big; +#endif /* BLE_LL_ISO_BROADCASTER */ + #endif }; @@ -2107,6 +2118,9 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) uint8_t adv_mode; uint8_t pdu_type; uint8_t ext_hdr_len; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + uint8_t biginfo_len; +#endif uint32_t offset; advsm = pducb_arg; @@ -2126,10 +2140,17 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) dptr += 1; /* only put flags if needed */ +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + if (sync->ext_hdr_flags || sync->big) { + dptr[0] = sync->ext_hdr_flags; + dptr += 1; + } +#else if (sync->ext_hdr_flags) { dptr[0] = sync->ext_hdr_flags; dptr += 1; } +#endif if (sync->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { if (!SYNC_NEXT(advsm)->sch.enqueued) { @@ -2157,6 +2178,18 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; } +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + if (advsm->big) { + biginfo_len = ble_ll_iso_big_biginfo_copy(advsm->big, dptr, + sync->sch.start_time + + g_ble_ll_sched_offset_ticks, + sync->sch.remainder); + BLE_LL_ASSERT(biginfo_len > 0); + + dptr += biginfo_len; + } +#endif + if (sync->data_len) { os_mbuf_copydata(advsm->periodic_adv_data, sync->data_offset, sync->data_len, dptr); @@ -2316,9 +2349,25 @@ ble_ll_adv_sync_calculate(struct ble_ll_adv_sm *advsm, * how Aux calculate works and this also make it easier to add more fields * into flags if needed in future */ +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + sync->big = advsm->big; + /* If BIG is present flags will always be also present even if none is set + * to indicate ACAD is present. + */ + if (sync->ext_hdr_flags || sync->big) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + } +#else if (sync->ext_hdr_flags) { ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; } +#endif + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + if (advsm->big) { + ext_hdr_len += ble_ll_iso_big_biginfo_len(advsm->big); + } +#endif /* AdvData always */ sync->data_len = MIN(BLE_LL_MAX_PAYLOAD_LEN - ext_hdr_len, rem_data_len); @@ -5242,6 +5291,55 @@ ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm) advsm->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY; } +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +struct ble_ll_adv_sm * +ble_ll_adv_sync_get(uint8_t handle) +{ + struct ble_ll_adv_sm *advsm; + + advsm = ble_ll_adv_sm_find_configured(handle); + if (!advsm) { + return NULL; + } + + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED)) { + return NULL; + } + + return advsm; +} + +int +ble_ll_adv_sync_big_add(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big) +{ + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED)) { + return -EINVAL; + } + + if (advsm->big && (advsm->big != big)) { + return -EBUSY; + } + + advsm->big = big; + + return 0; +} + +int +ble_ll_adv_sync_big_remove(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big) +{ + if (advsm->big != big) { + return -EINVAL; + } + + advsm->big = NULL; + + return 0; +} +#endif /* BLE_LL_ISO_BROADCASTER */ + /** * Initialize the advertising functionality of a BLE device. This should * be called once on initialization diff --git a/nimble/controller/src/ble_ll_iso_big.c b/nimble/controller/src/ble_ll_iso_big.c index 20e5ff07..594ff4a1 100644 --- a/nimble/controller/src/ble_ll_iso_big.c +++ b/nimble/controller/src/ble_ll_iso_big.c @@ -24,6 +24,7 @@ #include <nimble/hci_common.h> #include <nimble/transport.h> #include <controller/ble_ll.h> +#include <controller/ble_ll_adv.h> #include <controller/ble_ll_crypto.h> #include <controller/ble_ll_hci.h> #include <controller/ble_ll_iso_big.h> @@ -90,6 +91,8 @@ struct big_params { }; struct ble_ll_iso_big { + struct ble_ll_adv_sm *advsm; + uint8_t handle; uint8_t num_bis; uint16_t iso_interval; @@ -119,6 +122,8 @@ struct ble_ll_iso_big { uint8_t chan_map[BLE_LL_CHAN_MAP_LEN]; uint8_t chan_map_used; + uint8_t biginfo[33]; + uint64_t big_counter; uint64_t bis_counter; @@ -155,6 +160,113 @@ static uint8_t bis_pool_free = BIS_POOL_SIZE; static struct ble_ll_iso_big *big_pending; static struct ble_ll_iso_big *big_active; +static void +ble_ll_iso_big_biginfo_calc(struct ble_ll_iso_big *big, uint32_t seed_aa) +{ + uint8_t *buf; + + buf = big->biginfo; + + /* big_offset, big_offset_units, iso_interval, num_bis */ + put_le32(buf, (big->num_bis << 27) | (big->iso_interval << 15)); + buf += 4; + + /* nse, bn */ + *(uint8_t *)buf = (big->bn << 5) | (big->nse); + buf += 1; + + /* sub_interval, pto */ + put_le24(buf,(big->pto << 20) | (big->sub_interval)); + buf += 3; + + /* bis_spacing, irc */ + put_le24(buf, (big->irc << 20) | (big->bis_spacing)); + buf += 3; + + /* max_pdu, rfu */ + put_le16(buf, big->max_pdu); + buf += 2; + + /* seed_access_address */ + put_le32(buf, seed_aa); + buf += 4; + + /* sdu_interval, max_sdu */ + put_le32(buf, (big->max_sdu << 20) | (big->sdu_interval)); + buf += 4; + + /* base_crc_init */ + put_le16(buf, big->crc_init); + buf += 2; + + /* chm, phy */ + memcpy(buf, big->chan_map, 5); + buf[4] |= (big->phy - 1) << 5; + buf += 5; + + /* bis_payload_cnt, framing */ + memset(buf, 0x00, 5); +} + +int +ble_ll_iso_big_biginfo_copy(struct ble_ll_iso_big *big, uint8_t *dptr, + uint32_t base_ticks, uint8_t base_rem_us) +{ + uint8_t *dptr_start; + uint64_t counter; + uint32_t offset_us; + uint32_t offset; + uint32_t d_ticks; + uint8_t d_rem_us; + + dptr_start = dptr; + counter = big->bis_counter; + + d_ticks = big->event_start - base_ticks; + d_rem_us = big->event_start_us; + ble_ll_tmr_sub(&d_ticks, &d_rem_us, base_rem_us); + + offset_us = ble_ll_tmr_t2u(d_ticks) + d_rem_us; + if (offset_us <= 600) { + counter += big->bn; + offset_us += big->iso_interval * 1250; + } + if (offset_us >= 491460) { + offset = 0x4000 | (offset_us / 300); + } else { + offset = offset_us / 30; + } + + *dptr++ = ble_ll_iso_big_biginfo_len(big) - 1; + *dptr++ = 0x2c; + + memcpy(dptr, big->biginfo, 33); + put_le32(dptr, get_le32(dptr) | (offset & 0x7fff)); + dptr += 28; + + *dptr++ = counter & 0xff; + *dptr++ = (counter >> 8) & 0xff; + *dptr++ = (counter >> 16) & 0xff; + *dptr++ = (counter >> 24) & 0xff; + *dptr++ = (counter >> 32) & 0xff; + + if (big->encrypted) { + memcpy(dptr, big->giv, 8); + dptr += 8; + memcpy(dptr, big->gskd, 16); + dptr += 16; + } + + return dptr - dptr_start; +} + +int +ble_ll_iso_big_biginfo_len(struct ble_ll_iso_big *big) +{ + return 2 + sizeof(big->biginfo) + + (big->encrypted ? sizeof(big->giv) + sizeof(big->gskd) : 0); +} + static void ble_ll_iso_big_free(struct ble_ll_iso_big *big) { @@ -655,6 +767,7 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, { struct ble_ll_iso_big *big = NULL; struct ble_ll_iso_bis *bis; + struct ble_ll_adv_sm *advsm; uint32_t seed_aa; uint8_t pte; uint8_t gc; @@ -677,8 +790,16 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, BLE_LL_ASSERT(big); - /* TODO find valid advertising instance */ + advsm = ble_ll_adv_sync_get(adv_handle); + if (!advsm) { + return -ENOENT; + } + + if (ble_ll_adv_sync_big_add(advsm, big) < 0) { + return -ENOENT; + } + big->advsm = advsm; big->handle = big_handle; big->crc_init = ble_ll_rand(); @@ -793,6 +914,8 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, ble_ll_iso_big_calculate_iv(big); } + ble_ll_iso_big_biginfo_calc(big, seed_aa); + /* For now we will schedule complete event as single item. This allows for * shortest possible subevent space (150us) but can create sequence of long * events that will block scheduler from other activities. To mitigate this @@ -845,6 +968,11 @@ ble_ll_iso_big_terminate(uint8_t big_handle, uint8_t reason) return -ENOENT; } + /* Not sure if this is correct, but let's remove BIGInfo now since there's + * no point for peer to syncing to a BIG that will be disconnected soon. + */ + ble_ll_adv_sync_big_remove(big->advsm, big); + big->term_reason = reason; big->term_pending = 1;