diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index afd882d88f447..5fa6d96c87fda 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -5019,9 +5019,13 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, sys_le16_to_cpu(si->offs), si->offs_units, sys_le16_to_cpu(si->interval), - (si->sca_chm[4] >> 5), + ((si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] & + PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK) >> + PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS), si->sca_chm[0], si->sca_chm[1], si->sca_chm[2], - si->sca_chm[3], (si->sca_chm[4] & 0x3F), + si->sca_chm[3], + (si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] & + ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK), sys_le32_to_cpu(si->aa), si->crc_init[0], si->crc_init[1], si->crc_init[2], sys_le16_to_cpu(si->evt_cntr)); diff --git a/subsys/bluetooth/controller/ll_sw/pdu.h b/subsys/bluetooth/controller/ll_sw/pdu.h index be1bc6afeebdd..b9ab8188a9d87 100644 --- a/subsys/bluetooth/controller/ll_sw/pdu.h +++ b/subsys/bluetooth/controller/ll_sw/pdu.h @@ -366,6 +366,11 @@ struct pdu_adv_sync_info { uint16_t evt_cntr; } __packed; +#define PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET 4 +#define PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS 5 +#define PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK \ + (0x07 << (PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS)) + enum pdu_adv_type { PDU_ADV_TYPE_ADV_IND = 0x00, PDU_ADV_TYPE_DIRECT_IND = 0x01, diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index a63a98e9f74df..22b10fa865dc2 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020 Nordic Semiconductor ASA + * Copyright (c) 2016-2021 Nordic Semiconductor ASA * Copyright (c) 2016 Vinayak Kariappa Chettimada * * SPDX-License-Identifier: Apache-2.0 @@ -10,6 +10,7 @@ #include #include #include +#include #include "hal/cpu.h" #include "hal/ccm.h" @@ -1208,14 +1209,24 @@ uint8_t ll_adv_enable(uint8_t enable) if (lll->sync) { sync = HDR_LLL2ULL(lll->sync); if (sync->is_enabled && !sync->is_started) { + struct pdu_adv_sync_info *sync_info; + uint8_t value[1 + sizeof(sync_info)]; uint8_t err; err = ull_adv_aux_hdr_set_clear(adv, ULL_ADV_PDU_HDR_FIELD_SYNC_INFO, - 0, NULL, NULL, &pri_idx); + 0, value, NULL, &pri_idx); if (err) { return err; } + + /* First byte in the length-value encoded + * parameter is size of sync_info structure, + * followed by pointer to sync_info in the + * PDU. + */ + memcpy(&sync_info, &value[1], sizeof(sync_info)); + ull_adv_sync_info_fill(sync, sync_info); } else { /* Do not start periodic advertising */ sync = NULL; diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c index ad8eb0005c678..c6ba67cdf6e40 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020 Nordic Semiconductor ASA + * Copyright (c) 2017-2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,7 +22,6 @@ #include "pdu.h" #include "lll.h" -#include "lll_clock.h" #include "lll/lll_vendor.h" #include "lll/lll_adv_types.h" #include "lll_adv.h" @@ -47,10 +46,6 @@ static int init_reset(void); #if (CONFIG_BT_CTLR_ADV_AUX_SET > 0) static inline struct ll_adv_aux_set *aux_acquire(void); static inline void aux_release(struct ll_adv_aux_set *aux); -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) -static inline void sync_info_fill(struct lll_adv_sync *lll_sync, - uint8_t **dptr); -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ static void mfy_aux_offset_get(void *param); static void ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, uint16_t lazy, uint8_t force, void *param); @@ -93,7 +88,7 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui uint8_t const *const data) { struct ll_adv_set *adv; - uint8_t value[5]; + uint8_t value[1 + sizeof(data)]; uint8_t *val_ptr; uint8_t pri_idx; uint8_t err; @@ -122,7 +117,7 @@ uint8_t ll_adv_aux_ad_data_set(uint8_t handle, uint8_t op, uint8_t frag_pref, ui val_ptr = value; *val_ptr++ = len; - sys_put_le32((uint32_t)data, val_ptr); + memcpy(val_ptr, &data, sizeof(data)); err = ull_adv_aux_hdr_set_clear(adv, ULL_ADV_PDU_HDR_FIELD_AD_DATA, 0, value, NULL, &pri_idx); if (err) { @@ -441,6 +436,7 @@ uint8_t ull_adv_aux_hdr_set_clear(struct ll_adv_set *adv, struct pdu_adv_ext_hdr *sec_hdr, sec_hdr_prev; struct pdu_adv *pri_pdu, *pri_pdu_prev; struct pdu_adv *sec_pdu_prev, *sec_pdu; + struct pdu_adv_sync_info *sync_info; uint8_t *pri_dptr, *pri_dptr_prev; uint8_t *sec_dptr, *sec_dptr_prev; uint8_t pri_len, sec_len_prev; @@ -611,16 +607,30 @@ uint8_t ull_adv_aux_hdr_set_clear(struct ll_adv_set *adv, /* No SyncInfo flag in primary channel PDU */ /* Add/Remove SyncInfo flag in secondary channel PDU */ - if ((sec_hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_SYNC_INFO) || - (!(sec_hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_SYNC_INFO) && - sec_hdr_prev.sync_info)) { + if (sec_hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_SYNC_INFO) { sec_hdr->sync_info = 1; - } - if (sec_hdr_prev.sync_info) { - sec_dptr_prev += sizeof(struct pdu_adv_sync_info); - } - if (sec_hdr->sync_info) { - sec_dptr += sizeof(struct pdu_adv_sync_info); + sync_info = NULL; + + /* return the size of sync info structure */ + *(uint8_t *)value = sizeof(*sync_info); + value = (uint8_t *)value + 1; + + /* return the pointer to sync info struct inside the PDU + * buffer + */ + memcpy(value, &sec_dptr, sizeof(sec_dptr)); + value = (uint8_t *)value + sizeof(sec_dptr); + + sec_dptr += sizeof(*sync_info); + } else if (!(sec_hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_SYNC_INFO) && + sec_hdr_prev.sync_info) { + sec_hdr->sync_info = 1; + sync_info = (void *)sec_dptr_prev; + + sec_dptr_prev += sizeof(*sync_info); + sec_dptr += sizeof(*sync_info); + } else { + sync_info = NULL; } /* Tx Power flag */ @@ -724,10 +734,15 @@ uint8_t ull_adv_aux_hdr_set_clear(struct ll_adv_set *adv, /* No SyncInfo in primary channel PDU */ /* Fill SyncInfo in secondary channel PDU */ if (sec_hdr_prev.sync_info) { - sec_dptr_prev -= sizeof(struct pdu_adv_sync_info); + sec_dptr_prev -= sizeof(*sync_info); } + if (sec_hdr->sync_info) { - sync_info_fill(lll->sync, &sec_dptr); + sec_dptr -= sizeof(*sync_info); + } + + if (sync_info) { + memmove(sec_dptr, sync_info, sizeof(*sync_info)); } #endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ @@ -1016,37 +1031,6 @@ inline uint8_t ull_adv_aux_handle_get(struct ll_adv_aux_set *aux) sizeof(struct ll_adv_aux_set)); } -#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) -static inline void sync_info_fill(struct lll_adv_sync *lll_sync, - uint8_t **dptr) -{ - struct ll_adv_sync_set *sync; - struct pdu_adv_sync_info *si; - - *dptr -= sizeof(*si); - si = (void *)*dptr; - - /* NOTE: sync offset and offset unit filled by secondary prepare */ - si->offs_units = 0U; - /* If sync_info is part of ADV PDU the offs_adjust field - * is always set to 0. - */ - si->offs_adjust = 0U; - si->offs = 0U; - - sync = HDR_LLL2ULL(lll_sync); - si->interval = sys_cpu_to_le16(sync->interval); - memcpy(si->sca_chm, lll_sync->data_chan_map, - sizeof(si->sca_chm)); - si->sca_chm[4] &= 0x1f; - si->sca_chm[4] |= lll_clock_sca_local_get() << 5; - memcpy(&si->aa, lll_sync->access_addr, sizeof(si->aa)); - memcpy(si->crc_init, lll_sync->crc_init, sizeof(si->crc_init)); - - si->evt_cntr = 0U; /* NOTE: Filled by secondary prepare */ -} -#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ - static void mfy_aux_offset_get(void *param) { struct ll_adv_set *adv = param; diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h index 8b589a6dcd700..332ce4bf8a029 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020 Nordic Semiconductor ASA + * Copyright (c) 2017-2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -46,20 +46,24 @@ const uint8_t *ull_adv_pdu_update_addrs(struct ll_adv_set *adv, #if defined(CONFIG_BT_CTLR_ADV_EXT) +/* Below are BT Spec v5.2, Vol 6, Part B Section 2.3.4 Table 2.12 defined */ #define ULL_ADV_PDU_HDR_FIELD_ADVA BIT(0) #define ULL_ADV_PDU_HDR_FIELD_TARGETA BIT(1) #define ULL_ADV_PDU_HDR_FIELD_CTE_INFO BIT(2) #define ULL_ADV_PDU_HDR_FIELD_ADI BIT(3) #define ULL_ADV_PDU_HDR_FIELD_AUX_PTR BIT(4) #define ULL_ADV_PDU_HDR_FIELD_SYNC_INFO BIT(5) -#define ULL_ADV_PDU_HDR_FIELD_TX_POWER BIT(7) -#define ULL_ADV_PDU_HDR_FIELD_AD_DATA BIT(8) +#define ULL_ADV_PDU_HDR_FIELD_TX_POWER BIT(6) +#define ULL_ADV_PDU_HDR_FIELD_RFU BIT(7) +/* Below are implementation defined bit fields */ +#define ULL_ADV_PDU_HDR_FIELD_ACAD BIT(8) +#define ULL_ADV_PDU_HDR_FIELD_AD_DATA BIT(9) /* Helper type to store data for extended advertising * header fields and extra data. */ -struct adv_pdu_field_data { - uint8_t *field_data; +struct ull_adv_ext_hdr_data { + void *field_data; #if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY) void *extra_data; @@ -107,39 +111,6 @@ uint8_t ull_adv_aux_hdr_set_clear(struct ll_adv_set *adv, struct pdu_adv_adi *adi, uint8_t *pri_idx); -/* helper function to release periodic advertising instance */ -void ull_adv_sync_release(struct ll_adv_sync_set *sync); - -/* helper function to allocate new PDU data for AUX_SYNC_IND and return - * previous and new PDU for further processing. - */ -uint8_t ull_adv_sync_pdu_alloc(struct ll_adv_set *adv, - uint16_t hdr_add_fields, - uint16_t hdr_rem_fields, - struct adv_pdu_field_data *data, - struct pdu_adv **ter_pdu_prev, - struct pdu_adv **ter_pdu_new, - void **extra_data_prev, - void **extra_data_new, - uint8_t *ter_idx); - -/* helper function to set/clear common extended header format fields - * for AUX_SYNC_IND PDU. - */ -uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, - struct pdu_adv *ter_pdu_prev, - struct pdu_adv *ter_pdu, - uint16_t hdr_add_fields, - uint16_t hdr_rem_fields, - struct adv_pdu_field_data *data); - -/* helper function to update extra_data field */ -void ull_adv_sync_extra_data_set_clear(void *extra_data_prev, - void *extra_data_new, - uint16_t hdr_add_fields, - uint16_t hdr_rem_fields, - void *data); - /* helper function to calculate common ext adv payload header length and * adjust the data pointer. * NOTE: This function reverts the header data pointer if there is no @@ -180,10 +151,47 @@ uint32_t ull_adv_sync_start(struct ll_adv_set *adv, struct ll_adv_sync_set *sync, uint32_t ticks_anchor); +/* helper function to release periodic advertising instance */ +void ull_adv_sync_release(struct ll_adv_sync_set *sync); + +/* helper function to fill initial value of sync_info structure */ +void ull_adv_sync_info_fill(struct ll_adv_sync_set *sync, + struct pdu_adv_sync_info *si); + /* helper function to update periodic advertising event length */ void ull_adv_sync_update(struct ll_adv_sync_set *sync, uint32_t slot_plus_us, uint32_t slot_minus_us); +/* helper function to allocate new PDU data for AUX_SYNC_IND and return + * previous and new PDU for further processing. + */ +uint8_t ull_adv_sync_pdu_alloc(struct ll_adv_set *adv, + uint16_t hdr_add_fields, + uint16_t hdr_rem_fields, + struct ull_adv_ext_hdr_data *hdr_data, + struct pdu_adv **ter_pdu_prev, + struct pdu_adv **ter_pdu_new, + void **extra_data_prev, + void **extra_data_new, + uint8_t *ter_idx); + +/* helper function to set/clear common extended header format fields + * for AUX_SYNC_IND PDU. + */ +uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, + struct pdu_adv *ter_pdu_prev, + struct pdu_adv *ter_pdu, + uint16_t hdr_add_fields, + uint16_t hdr_rem_fields, + struct ull_adv_ext_hdr_data *hdr_data); + +/* helper function to update extra_data field */ +void ull_adv_sync_extra_data_set_clear(void *extra_data_prev, + void *extra_data_new, + uint16_t hdr_add_fields, + uint16_t hdr_rem_fields, + void *data); + /* helper function to schedule a mayfly to get sync offset */ void ull_adv_sync_offset_get(struct ll_adv_set *adv); diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 4efca418c1ec6..16996408fcd01 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -58,11 +58,18 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, uint8_t packing, uint8_t framing, uint8_t encryption, uint8_t *bcode) { + uint8_t field_data[1 + sizeof(uint8_t *)]; + struct ull_adv_ext_hdr_data hdr_data; + void *extra_data_prev, *extra_data; struct lll_adv_sync *lll_adv_sync; struct lll_adv_iso *lll_adv_iso; + struct pdu_adv *pdu_prev, *pdu; struct node_rx_pdu *node_rx; struct ll_adv_iso *adv_iso; struct ll_adv_set *adv; + uint8_t ter_idx; + uint8_t *acad; + uint8_t err; adv_iso = ull_adv_iso_get(big_handle); @@ -130,6 +137,30 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, if (num_bis != 1) { return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED; } + + /* Allocate next PDU */ + err = ull_adv_sync_pdu_alloc(adv, 0, 0, NULL, &pdu_prev, &pdu, + &extra_data_prev, &extra_data, &ter_idx); + if (err) { + return err; + } + + /* Add ACAD to AUX_SYNC_IND */ + hdr_data.field_data = field_data; + field_data[0] = sizeof(struct pdu_big_info) + 2; + err = ull_adv_sync_pdu_set_clear(lll_adv_sync, pdu_prev, pdu, + ULL_ADV_PDU_HDR_FIELD_ACAD, 0U, + &hdr_data); + if (err) { + return err; + } + + memcpy(&acad, &field_data[1], sizeof(acad)); + acad[0] = sizeof(struct pdu_big_info) + 1; + acad[1] = BT_DATA_BIG_INFO; + + lll_adv_sync_data_enqueue(lll_adv_sync, ter_idx); + /* TODO: For now we can just use the unique BIG handle as the BIS * handle until we support multiple BIS */ @@ -146,8 +177,6 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, adv_iso->encryption = encryption; memcpy(adv_iso->bcode, bcode, sizeof(adv_iso->bcode)); - /* TODO: Add ACAD to AUX_SYNC_IND */ - /* TODO: start sending BIS empty data packet for each BIS */ ull_adv_iso_start(adv_iso, 0 /* TODO: Calc ticks_anchor */); @@ -198,12 +227,17 @@ uint8_t ll_big_test_create(uint8_t big_handle, uint8_t adv_handle, uint8_t ll_big_terminate(uint8_t big_handle, uint8_t reason) { + void *extra_data_prev, *extra_data; struct lll_adv_sync *lll_adv_sync; struct lll_adv_iso *lll_adv_iso; + struct pdu_adv *pdu_prev, *pdu; struct node_rx_pdu *node_rx; struct ll_adv_iso *adv_iso; struct lll_adv *lll_adv; + struct ll_adv_set *adv; + uint8_t ter_idx; uint32_t ret; + uint8_t err; adv_iso = ull_adv_iso_get(big_handle); if (!adv_iso) { @@ -217,6 +251,23 @@ uint8_t ll_big_terminate(uint8_t big_handle, uint8_t reason) } lll_adv_sync = lll_adv->sync; + adv = HDR_LLL2ULL(lll_adv); + + /* Allocate next PDU */ + err = ull_adv_sync_pdu_alloc(adv, 0, 0, NULL, &pdu_prev, &pdu, + &extra_data_prev, &extra_data, &ter_idx); + if (err) { + return err; + } + + /* Remove ACAD to AUX_SYNC_IND */ + err = ull_adv_sync_pdu_set_clear(lll_adv_sync, pdu_prev, pdu, + 0U, ULL_ADV_PDU_HDR_FIELD_ACAD, NULL); + if (err) { + return err; + } + + lll_adv_sync_data_enqueue(lll_adv_sync, ter_idx); /* TODO: Terminate all BIS data paths */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 6b3fbd4411264..291d0b21b13e4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020 Nordic Semiconductor ASA + * Copyright (c) 2017-2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,7 @@ #include "pdu.h" #include "lll.h" +#include "lll_clock.h" #include "lll/lll_vendor.h" #include "lll/lll_adv_types.h" #include "lll_adv.h" @@ -400,12 +401,12 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags) uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, uint8_t const *const data) { + struct ull_adv_ext_hdr_data hdr_data; + uint8_t field_data[1 + sizeof(data)]; void *extra_data_prev, *extra_data; - struct adv_pdu_field_data pdu_data; struct pdu_adv *pdu_prev, *pdu; struct lll_adv_sync *lll_sync; struct ll_adv_set *adv; - uint8_t value[5]; uint8_t ter_idx; uint8_t err; @@ -426,12 +427,12 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER; } - pdu_data.field_data = value; - *pdu_data.field_data = len; - sys_put_le32((uint32_t)data, pdu_data.field_data + 1); + hdr_data.field_data = field_data; + field_data[0] = len; + memcpy(&field_data[1], &data, sizeof(data)); err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_HDR_FIELD_AD_DATA, 0, - &pdu_data, &pdu_prev, &pdu, + &hdr_data, &pdu_prev, &pdu, &extra_data_prev, &extra_data, &ter_idx); if (err) { return err; @@ -441,13 +442,13 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, if (extra_data) { ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data, ULL_ADV_PDU_HDR_FIELD_AD_DATA, - 0, &pdu_data); + 0, &hdr_data); } #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */ err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, ULL_ADV_PDU_HDR_FIELD_AD_DATA, - 0, &pdu_data); + 0, &hdr_data); #if defined(CONFIG_BT_CTLR_ADV_PDU_LINK) @@ -525,6 +526,8 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable) } if (adv->is_enabled && !sync->is_started) { + struct pdu_adv_sync_info *sync_info; + uint8_t value[1 + sizeof(sync_info)]; uint32_t ticks_slot_overhead_aux; struct lll_adv_aux *lll_aux; struct ll_adv_aux_set *aux; @@ -537,11 +540,18 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable) /* Add sync_info into auxiliary PDU */ err = ull_adv_aux_hdr_set_clear(adv, ULL_ADV_PDU_HDR_FIELD_SYNC_INFO, - 0, NULL, NULL, &pri_idx); + 0, value, NULL, &pri_idx); if (err) { return err; } + /* First byte in the length-value encoded parameter is size of + * sync_info structure, followed by pointer to sync_info in the + * PDU. + */ + memcpy(&sync_info, &value[1], sizeof(sync_info)); + ull_adv_sync_info_fill(sync, sync_info); + if (lll_aux) { /* FIXME: Find absolute ticks until after auxiliary PDU * on air to place the periodic advertising PDU. @@ -695,6 +705,38 @@ void ull_adv_sync_release(struct ll_adv_sync_set *sync) sync_release(sync); } +void ull_adv_sync_info_fill(struct ll_adv_sync_set *sync, + struct pdu_adv_sync_info *si) +{ + struct lll_adv_sync *lll_sync; + + /* NOTE: sync offset and offset unit filled by secondary prepare. + * + * If sync_info is part of ADV PDU the offs_adjust field + * is always set to 0. + */ + si->offs_units = 0U; + si->offs_adjust = 0U; + si->offs = 0U; + + /* Fill the interval, channel map, access address and CRC init */ + si->interval = sys_cpu_to_le16(sync->interval); + lll_sync = &sync->lll; + memcpy(si->sca_chm, lll_sync->data_chan_map, + sizeof(si->sca_chm)); + si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &= + ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK; + si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] |= + ((lll_clock_sca_local_get() << + PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS) & + PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK); + memcpy(&si->aa, lll_sync->access_addr, sizeof(si->aa)); + memcpy(si->crc_init, lll_sync->crc_init, sizeof(si->crc_init)); + + /* NOTE: Filled by secondary prepare */ + si->evt_cntr = 0U; +} + void ull_adv_sync_offset_get(struct ll_adv_set *adv) { static memq_link_t link; @@ -729,7 +771,7 @@ void ull_adv_sync_update(struct ll_adv_sync_set *sync, uint32_t slot_plus_us, uint8_t ull_adv_sync_pdu_alloc(struct ll_adv_set *adv, uint16_t hdr_add_fields, uint16_t hdr_rem_fields, - struct adv_pdu_field_data *data, + struct ull_adv_ext_hdr_data *hdr_data, struct pdu_adv **ter_pdu_prev, struct pdu_adv **ter_pdu_new, void **extra_data_prev, @@ -821,7 +863,7 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, struct pdu_adv *ter_pdu, uint16_t hdr_add_fields, uint16_t hdr_rem_fields, - struct adv_pdu_field_data *data) + struct ull_adv_ext_hdr_data *hdr_data) { struct pdu_adv_com_ext_adv *ter_com_hdr, *ter_com_hdr_prev; struct pdu_adv_ext_hdr *ter_hdr, ter_hdr_prev; @@ -831,13 +873,14 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, uint8_t hdr_buf_len; uint16_t ter_len; uint8_t *ad_data; + uint8_t acad_len; #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) uint8_t cte_info; #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */ uint8_t ad_len; void *value; - value = data ? data->field_data : NULL; + value = hdr_data ? hdr_data->field_data : NULL; /* Get common pointers from reference to previous tertiary PDU data */ ter_com_hdr_prev = (void *)&ter_pdu_prev->adv_ext_ind; @@ -919,7 +962,6 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, acad_len_prev = hdr_buf_len - ter_len_prev; ter_len_prev += acad_len_prev; ter_dptr_prev += acad_len_prev; - ter_dptr += acad_len_prev; } else { acad_len_prev = 0; /* NOTE: If no flags are set then extended header length will be @@ -938,6 +980,21 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, return BT_HCI_ERR_UNSPECIFIED; } + /* Add/Retain/Remove ACAD */ + if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_ACAD) { + acad_len = *(uint8_t *)value; + value = (uint8_t *)value + 1; + /* return the pointer to ACAD offset */ + memcpy(value, &ter_dptr, sizeof(ter_dptr)); + value = (uint8_t *)value + sizeof(ter_dptr); + ter_dptr += acad_len; + } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_ACAD)) { + acad_len = acad_len_prev; + ter_dptr += acad_len_prev; + } else { + acad_len = 0U; + } + /* Calc current tertiary PDU len */ ter_len = ull_adv_aux_hdr_len_calc(ter_com_hdr, &ter_dptr); ull_adv_aux_hdr_len_fill(ter_com_hdr, ter_len); @@ -965,7 +1022,7 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, return BT_HCI_ERR_PACKET_TOO_LONG; } - /* set the secondary PDU len */ + /* set the tertiary PDU len */ ter_pdu->len = ter_len; /* Start filling tertiary PDU payload based on flags from here @@ -980,10 +1037,12 @@ uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync, return 0; } - /* Fill ACAD in tertiary PDU */ + /* Retain ACAD in tertiary PDU */ ter_dptr_prev -= acad_len_prev; - ter_dptr -= acad_len_prev; - memmove(ter_dptr, ter_dptr_prev, acad_len_prev); + if (acad_len) { + ter_dptr -= acad_len; + memmove(ter_dptr, ter_dptr_prev, acad_len_prev); + } /* Tx Power */ if (ter_hdr->tx_pwr) { diff --git a/subsys/bluetooth/controller/ll_sw/ull_df.c b/subsys/bluetooth/controller/ll_sw/ull_df.c index 7d0d448d7b764..31407b9256c5c 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df.c +++ b/subsys/bluetooth/controller/ll_sw/ull_df.c @@ -334,7 +334,7 @@ uint8_t ll_df_set_cl_cte_tx_enable(uint8_t adv_handle, uint8_t cte_enable) df_cfg->is_enabled = 0U; } else { struct pdu_cte_info cte_info; - struct adv_pdu_field_data pdu_data; + struct ull_adv_ext_hdr_data hdr_data; if (df_cfg->is_enabled) { return BT_HCI_ERR_CMD_DISALLOWED; @@ -342,8 +342,8 @@ uint8_t ll_df_set_cl_cte_tx_enable(uint8_t adv_handle, uint8_t cte_enable) cte_info.type = df_cfg->cte_type; cte_info.time = df_cfg->cte_length; - pdu_data.field_data = (uint8_t *)&cte_info; - pdu_data.extra_data = df_cfg; + hdr_data.field_data = (uint8_t *)&cte_info; + hdr_data.extra_data = df_cfg; err = ull_adv_sync_pdu_alloc(adv, 0, ULL_ADV_PDU_HDR_FIELD_CTE_INFO, @@ -358,12 +358,12 @@ uint8_t ll_df_set_cl_cte_tx_enable(uint8_t adv_handle, uint8_t cte_enable) ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data, ULL_ADV_PDU_HDR_FIELD_CTE_INFO, - 0, &pdu_data); + 0, &hdr_data); } err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, ULL_ADV_PDU_HDR_FIELD_CTE_INFO, - 0, &pdu_data); + 0, &hdr_data); if (err) { return err; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index 418110cd52d48..8420007ead217 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -383,8 +383,13 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, } lll = &sync->lll; + + /* Copy channel map from sca_chm field in sync_info structure, and + * clear the SCA bits. + */ memcpy(lll->data_chan_map, si->sca_chm, sizeof(lll->data_chan_map)); - lll->data_chan_map[4] &= ~0xE0; + lll->data_chan_map[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &= + ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK; lll->data_chan_count = util_ones_count_get(&lll->data_chan_map[0], sizeof(lll->data_chan_map)); if (lll->data_chan_count < 2) { @@ -397,7 +402,13 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux, lll->event_counter = si->evt_cntr; lll->phy = aux->lll.phy; - sca = si->sca_chm[4] >> 5; + /* Extract the SCA value from the sca_chm field of the sync_info + * structure. + */ + sca = (si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] & + PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK) >> + PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS; + interval = sys_le16_to_cpu(si->interval); interval_us = interval * CONN_INT_UNIT_US; diff --git a/tests/bluetooth/bsim_bt/bsim_test_iso/src/main.c b/tests/bluetooth/bsim_bt/bsim_test_iso/src/main.c index 701ff32c9b122..39c230c25ac75 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_iso/src/main.c +++ b/tests/bluetooth/bsim_bt/bsim_test_iso/src/main.c @@ -44,16 +44,26 @@ extern enum bst_result_t bst_result; #include "subsys/bluetooth/host/hci_core.h" #endif /* !USE_HOST_API */ +static uint8_t mfg_data1[] = { 0xff, 0xff, 0x01, 0x02, 0x03, 0x04 }; +static uint8_t mfg_data2[] = { 0xff, 0xff, 0x05 }; + +static const struct bt_data per_ad_data1[] = { + BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data1, 6), +}; + +static const struct bt_data per_ad_data2[] = { + BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data2, 3), +}; + static void test_iso_main(void) { struct bt_le_ext_adv *adv; int err; - int index; uint8_t bis_count = 1; /* TODO: Add support for multiple BIS per BIG */ printk("\n*ISO broadcast test*\n"); - printk("Bluetooth initializing...\n"); + printk("Bluetooth initializing..."); err = bt_enable(NULL); if (err) { FAIL("Could not init BT: %d\n", err); @@ -61,7 +71,7 @@ static void test_iso_main(void) } printk("success.\n"); - printk("Create advertising set...\n"); + printk("Create advertising set..."); err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, &adv); if (err) { FAIL("Failed to create advertising set (err %d)\n", err); @@ -70,7 +80,7 @@ static void test_iso_main(void) printk("success.\n"); - printk("Setting Periodic Advertising parameters...\n"); + printk("Setting Periodic Advertising parameters..."); err = bt_le_per_adv_set_param(adv, BT_LE_PER_ADV_DEFAULT); if (err) { FAIL("Failed to set periodic advertising parameters (err %d)\n", @@ -79,22 +89,25 @@ static void test_iso_main(void) } printk("success.\n"); - printk("Enable Periodic Advertising...\n"); + printk("Enable Periodic Advertising..."); err = bt_le_per_adv_start(adv); if (err) { FAIL("Failed to enable periodic advertising (err %d)\n", err); return; } + printk("success.\n"); - /* Start extended advertising */ + printk("Start extended advertising..."); err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); if (err) { printk("Failed to start extended advertising (err %d)\n", err); return; } + printk("success.\n"); #if !IS_ENABLED(USE_HOST_API) uint8_t big_handle = 0; + uint8_t adv_handle; uint32_t sdu_interval = 0x10000; /*us */ uint16_t max_sdu = 0x10; uint16_t max_latency = 0x0A; @@ -106,10 +119,10 @@ static void test_iso_main(void) uint8_t bcode[16] = { 0 }; /* Assume that index == handle */ - index = bt_le_ext_adv_get_index(adv); + adv_handle = bt_le_ext_adv_get_index(adv); - printk("Creating BIG...\n"); - err = ll_big_create(big_handle, index, bis_count, sdu_interval, max_sdu, + printk("Creating BIG..."); + err = ll_big_create(big_handle, adv_handle, bis_count, sdu_interval, max_sdu, max_latency, rtn, phy, packing, framing, encryption, bcode); if (err) { @@ -120,7 +133,29 @@ static void test_iso_main(void) k_sleep(K_MSEC(5000)); - printk("Terminating BIG...\n"); + printk("Update periodic advertising data 1..."); + err = bt_le_per_adv_set_data(adv, per_ad_data1, + ARRAY_SIZE(per_ad_data1)); + if (err) { + FAIL("Failed to update periodic advertising data 1 (%d).\n", + err); + } + printk("success.\n"); + + k_sleep(K_MSEC(5000)); + + printk("Update periodic advertising data 2..."); + err = bt_le_per_adv_set_data(adv, per_ad_data2, + ARRAY_SIZE(per_ad_data2)); + if (err) { + FAIL("Failed to update periodic advertising data 2 (%d).\n", + err); + } + printk("success.\n"); + + k_sleep(K_MSEC(5000)); + + printk("Terminating BIG..."); err = ll_big_terminate(big_handle, BT_HCI_ERR_LOCALHOST_TERM_CONN); if (err) { FAIL("Could not terminate BIG: %d\n", err); @@ -245,7 +280,7 @@ static void test_iso_recv_main(void) printk("\n*ISO broadcast test*\n"); - printk("Bluetooth initializing...\n"); + printk("Bluetooth initializing..."); err = bt_enable(NULL); if (err) { FAIL("Could not init BT: %d\n", err); @@ -313,7 +348,7 @@ static void test_iso_recv_main(void) uint16_t sync_timeout = 0; struct node_rx_hdr *node_rx; - printk("Creating BIG...\n"); + printk("Creating BIG..."); err = ll_big_sync_create(big_handle, sync->handle, encryption, bcode, mse, sync_timeout, bis_count, &bis_handle); if (err) { @@ -322,9 +357,9 @@ static void test_iso_recv_main(void) } printk("success.\n"); - k_sleep(K_MSEC(5000)); + k_sleep(K_MSEC(15000)); - printk("Terminating BIG...\n"); + printk("Terminating BIG..."); err = ll_big_sync_terminate(big_handle, (void **)&node_rx); if (err) { FAIL("Could not terminate BIG sync: %d\n", err); @@ -342,7 +377,7 @@ static void test_iso_recv_main(void) static void test_iso_init(void) { - bst_ticker_set_next_tick_absolute(20e6); + bst_ticker_set_next_tick_absolute(30e6); bst_result = In_progress; } diff --git a/tests/bluetooth/bsim_bt/bsim_test_iso/tests_scripts/broadcast_iso.sh b/tests/bluetooth/bsim_bt/bsim_test_iso/tests_scripts/broadcast_iso.sh index 2de760bdcac22..83de75763f3c8 100755 --- a/tests/bluetooth/bsim_bt/bsim_test_iso/tests_scripts/broadcast_iso.sh +++ b/tests/bluetooth/bsim_bt/bsim_test_iso/tests_scripts/broadcast_iso.sh @@ -14,7 +14,7 @@ function Execute(){ compile it?)\e[39m" exit 1 fi - timeout 20 $@ & process_ids="$process_ids $!" + timeout 30 $@ & process_ids="$process_ids $!" } : "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}"