You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2023/06/09 07:49:23 UTC
[mynewt-nimble] 04/09: nimble/ll: Add BIGInfo to periodic adv train
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 <an...@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;