Bluetooth: controller: Add support for linked adv PDUs
This adds support to allow advertising PDUs to be linked which is required to send advertising trains, i.e. AUX_CHAIN_IND. PDUs are linked with a simple single-linked list, the pointer to next PDU is stored at the very end of PDU buffer. This prevents it from being overwritten if PDU is modified and allows for build time offset calculation. There are few helpers added to make handling easier, e.g.: - get next linked PDU - get last linked PDU - link one PDU to another - link PDU at the end - release all linked PDUs (except for 1st) Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
This commit is contained in:
parent
1e02d400e2
commit
21892eecf1
10 changed files with 119 additions and 10 deletions
|
@ -165,6 +165,13 @@ config BT_CTLR_ADV_SYNC_SET
|
||||||
help
|
help
|
||||||
Maximum supported periodic advertising sets.
|
Maximum supported periodic advertising sets.
|
||||||
|
|
||||||
|
config BT_CTLR_ADV_PDU_LINK
|
||||||
|
bool "Enable linking of advertising PDU trains"
|
||||||
|
help
|
||||||
|
Enables extra space in each advertising PDU to allow linking PDUs. This
|
||||||
|
is required to enable advertising data trains (i.e. transmission of
|
||||||
|
AUX_CHAIN_IND).
|
||||||
|
|
||||||
config BT_CTLR_ADV_DATA_BUF_MAX
|
config BT_CTLR_ADV_DATA_BUF_MAX
|
||||||
int "Advertising Data Maximum Buffers"
|
int "Advertising Data Maximum Buffers"
|
||||||
depends on BT_BROADCASTER
|
depends on BT_BROADCASTER
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
#include "util/memq.h"
|
#include "util/memq.h"
|
||||||
|
#include "util/mem.h"
|
||||||
|
|
||||||
#include "hal/ecb.h"
|
#include "hal/ecb.h"
|
||||||
#include "hal/ccm.h"
|
#include "hal/ccm.h"
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
#include "util/memq.h"
|
#include "util/memq.h"
|
||||||
|
#include "util/mem.h"
|
||||||
|
|
||||||
#include "pdu.h"
|
#include "pdu.h"
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
#include "util/memq.h"
|
#include "util/memq.h"
|
||||||
|
#include "util/mem.h"
|
||||||
|
|
||||||
#include "pdu.h"
|
#include "pdu.h"
|
||||||
|
|
||||||
|
|
|
@ -97,8 +97,7 @@ static inline bool isr_rx_ci_adva_check(uint8_t tx_addr, uint8_t *addr,
|
||||||
#define BT_CTLR_ADV_SYNC_SET 0
|
#define BT_CTLR_ADV_SYNC_SET 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PDU_MEM_SIZE MROUND(PDU_AC_LL_HEADER_SIZE + \
|
#define PDU_MEM_SIZE PDU_ADV_MEM_SIZE
|
||||||
PDU_AC_PAYLOAD_SIZE_MAX)
|
|
||||||
#define PDU_MEM_COUNT_MIN (BT_CTLR_ADV_SET + \
|
#define PDU_MEM_COUNT_MIN (BT_CTLR_ADV_SET + \
|
||||||
(BT_CTLR_ADV_SET * PAYLOAD_FRAG_COUNT) + \
|
(BT_CTLR_ADV_SET * PAYLOAD_FRAG_COUNT) + \
|
||||||
(BT_CTLR_ADV_AUX_SET * PAYLOAD_FRAG_COUNT) + \
|
(BT_CTLR_ADV_AUX_SET * PAYLOAD_FRAG_COUNT) + \
|
||||||
|
@ -305,11 +304,17 @@ struct pdu_adv *lll_adv_pdu_alloc_pdu_adv(void)
|
||||||
|
|
||||||
MFIFO_DEQUEUE(pdu_free);
|
MFIFO_DEQUEUE(pdu_free);
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
||||||
|
PDU_ADV_NEXT_PTR(p) = NULL;
|
||||||
|
#endif
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = mem_acquire(&mem_pdu.free);
|
p = mem_acquire(&mem_pdu.free);
|
||||||
if (p) {
|
if (p) {
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
||||||
|
PDU_ADV_NEXT_PTR(p) = NULL;
|
||||||
|
#endif
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,9 +324,33 @@ struct pdu_adv *lll_adv_pdu_alloc_pdu_adv(void)
|
||||||
p = MFIFO_DEQUEUE(pdu_free);
|
p = MFIFO_DEQUEUE(pdu_free);
|
||||||
LL_ASSERT(p);
|
LL_ASSERT(p);
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
||||||
|
PDU_ADV_NEXT_PTR(p) = NULL;
|
||||||
|
#endif
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
||||||
|
void lll_adv_pdu_release(struct pdu_adv *pdu)
|
||||||
|
{
|
||||||
|
mem_release(pdu, &mem_pdu.free);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lll_adv_pdu_linked_release_all(struct pdu_adv *pdu_first)
|
||||||
|
{
|
||||||
|
struct pdu_adv *pdu = pdu_first;
|
||||||
|
|
||||||
|
while (pdu) {
|
||||||
|
struct pdu_adv *pdu_next;
|
||||||
|
|
||||||
|
pdu_next = PDU_ADV_NEXT_PTR(pdu);
|
||||||
|
PDU_ADV_NEXT_PTR(pdu) = NULL;
|
||||||
|
lll_adv_pdu_release(pdu);
|
||||||
|
pdu = pdu_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu,
|
struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu,
|
||||||
uint8_t *is_modified)
|
uint8_t *is_modified)
|
||||||
{
|
{
|
||||||
|
@ -333,11 +362,34 @@ struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu,
|
||||||
uint8_t pdu_idx;
|
uint8_t pdu_idx;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
if (!MFIFO_ENQUEUE_IDX_GET(pdu_free, &free_idx)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdu_idx = first;
|
pdu_idx = first;
|
||||||
|
p = pdu->pdu[pdu_idx];
|
||||||
|
|
||||||
|
do {
|
||||||
|
void *next;
|
||||||
|
|
||||||
|
/* Store partial list in current data index if there is
|
||||||
|
* no free slot in mfifo. It can be released on next
|
||||||
|
* switch attempt (on next event).
|
||||||
|
*/
|
||||||
|
if (!MFIFO_ENQUEUE_IDX_GET(pdu_free, &free_idx)) {
|
||||||
|
pdu->pdu[pdu_idx] = p;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
||||||
|
next = lll_adv_pdu_linked_next_get(p);
|
||||||
|
#else
|
||||||
|
next = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MFIFO_BY_IDX_ENQUEUE(pdu_free, free_idx, p);
|
||||||
|
k_sem_give(&sem_pdu_free);
|
||||||
|
|
||||||
|
p = next;
|
||||||
|
} while (p);
|
||||||
|
|
||||||
|
pdu->pdu[pdu_idx] = NULL;
|
||||||
|
|
||||||
first += 1U;
|
first += 1U;
|
||||||
if (first == DOUBLE_BUFFER_SIZE) {
|
if (first == DOUBLE_BUFFER_SIZE) {
|
||||||
|
@ -346,11 +398,7 @@ struct pdu_adv *lll_adv_pdu_latest_get(struct lll_adv_pdu *pdu,
|
||||||
pdu->first = first;
|
pdu->first = first;
|
||||||
*is_modified = 1U;
|
*is_modified = 1U;
|
||||||
|
|
||||||
p = pdu->pdu[pdu_idx];
|
|
||||||
pdu->pdu[pdu_idx] = NULL;
|
pdu->pdu[pdu_idx] = NULL;
|
||||||
|
|
||||||
MFIFO_BY_IDX_ENQUEUE(pdu_free, free_idx, p);
|
|
||||||
k_sem_give(&sem_pdu_free);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (void *)pdu->pdu[first];
|
return (void *)pdu->pdu[first];
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "hal/ticker.h"
|
#include "hal/ticker.h"
|
||||||
|
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
#include "util/mem.h"
|
||||||
#include "util/memq.h"
|
#include "util/memq.h"
|
||||||
|
|
||||||
#include "pdu.h"
|
#include "pdu.h"
|
||||||
|
|
|
@ -4,6 +4,18 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
||||||
|
#define PDU_ADV_MEM_SIZE MROUND(PDU_AC_LL_HEADER_SIZE + \
|
||||||
|
PDU_AC_PAYLOAD_SIZE_MAX + \
|
||||||
|
sizeof(uintptr_t))
|
||||||
|
#define PDU_ADV_NEXT_PTR(p) *(struct pdu_adv **)((uint8_t *)(p) + \
|
||||||
|
PDU_ADV_MEM_SIZE - \
|
||||||
|
sizeof(uintptr_t))
|
||||||
|
#else
|
||||||
|
#define PDU_ADV_MEM_SIZE MROUND(PDU_AC_LL_HEADER_SIZE + \
|
||||||
|
PDU_AC_PAYLOAD_SIZE_MAX)
|
||||||
|
#endif
|
||||||
|
|
||||||
int lll_adv_data_init(struct lll_adv_pdu *pdu);
|
int lll_adv_data_init(struct lll_adv_pdu *pdu);
|
||||||
int lll_adv_data_reset(struct lll_adv_pdu *pdu);
|
int lll_adv_data_reset(struct lll_adv_pdu *pdu);
|
||||||
int lll_adv_data_release(struct lll_adv_pdu *pdu);
|
int lll_adv_data_release(struct lll_adv_pdu *pdu);
|
||||||
|
@ -124,3 +136,38 @@ static inline struct pdu_adv *lll_adv_sync_data_peek(struct lll_adv_sync *lll,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
|
#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */
|
||||||
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
#endif /* CONFIG_BT_CTLR_ADV_EXT */
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
|
||||||
|
/* Release single PDU, shall only be called from ULL */
|
||||||
|
void lll_adv_pdu_release(struct pdu_adv *pdu);
|
||||||
|
/* Release PDU and all linked PDUs, shall only be called from ULL */
|
||||||
|
void lll_adv_pdu_linked_release_all(struct pdu_adv *pdu_first);
|
||||||
|
|
||||||
|
static inline struct pdu_adv *lll_adv_pdu_linked_next_get(struct pdu_adv *pdu)
|
||||||
|
{
|
||||||
|
return PDU_ADV_NEXT_PTR(pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct pdu_adv *lll_adv_pdu_linked_last_get(struct pdu_adv *pdu)
|
||||||
|
{
|
||||||
|
while (PDU_ADV_NEXT_PTR(pdu)) {
|
||||||
|
pdu = PDU_ADV_NEXT_PTR(pdu);
|
||||||
|
}
|
||||||
|
return pdu;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lll_adv_pdu_linked_append(struct pdu_adv *pdu,
|
||||||
|
struct pdu_adv *prev)
|
||||||
|
{
|
||||||
|
PDU_ADV_NEXT_PTR(prev) = pdu;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lll_adv_pdu_linked_append_end(struct pdu_adv *pdu,
|
||||||
|
struct pdu_adv *first)
|
||||||
|
{
|
||||||
|
struct pdu_adv *last;
|
||||||
|
|
||||||
|
last = lll_adv_pdu_linked_last_get(first);
|
||||||
|
lll_adv_pdu_linked_append(pdu, last);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "hal/radio_df.h"
|
#include "hal/radio_df.h"
|
||||||
|
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
#include "util/mem.h"
|
||||||
#include "util/memq.h"
|
#include "util/memq.h"
|
||||||
|
|
||||||
#include "pdu.h"
|
#include "pdu.h"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
#include "util/memq.h"
|
#include "util/memq.h"
|
||||||
|
#include "util/mem.h"
|
||||||
#include "util/mayfly.h"
|
#include "util/mayfly.h"
|
||||||
|
|
||||||
#include "hal/cpu.h"
|
#include "hal/cpu.h"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
#include "util/memq.h"
|
#include "util/memq.h"
|
||||||
|
#include "util/mem.h"
|
||||||
#include "util/mayfly.h"
|
#include "util/mayfly.h"
|
||||||
|
|
||||||
#include "hal/cpu.h"
|
#include "hal/cpu.h"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue