Skip to content

Commit a58854d

Browse files
committed
Bluetooth: controller: ULL: Add sending of number of CTEs in per adv chain
Direction finding functionality allows to send a number of periodic advertising PDUs in a chain that have CTE. ll_df_set_cl_cte_tx_enable function was changed to update periodic advertising chain to include cte_info field. If the chain is too short, there is less PDUs in the chain than requested number of CTEs, the function will add new empty PDUs to the chain end. Signed-off-by: Piotr Pryga <[email protected]>
1 parent 5aee904 commit a58854d

File tree

1 file changed

+182
-21
lines changed
  • subsys/bluetooth/controller/ll_sw

1 file changed

+182
-21
lines changed

subsys/bluetooth/controller/ll_sw/ull_df.c

Lines changed: 182 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ static int init_reset(void);
9898
* @return Pointer to lll_df_adv_cfg or NULL if there is no more free memory.
9999
*/
100100
static struct lll_df_adv_cfg *df_adv_cfg_acquire(void);
101+
102+
static uint8_t cte_info_set(struct ll_adv_set *adv, struct lll_df_adv_cfg *df_cfg, uint8_t *ter_idx,
103+
struct pdu_adv **first_pdu);
101104
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
102105

103106
/* @brief Function performs ULL Direction Finding initialization
@@ -319,31 +322,11 @@ uint8_t ll_df_set_cl_cte_tx_enable(uint8_t adv_handle, uint8_t cte_enable)
319322

320323
df_cfg->is_enabled = 0U;
321324
} else {
322-
struct pdu_cte_info cte_info;
323-
void *hdr_data;
324-
325325
if (df_cfg->is_enabled) {
326326
return BT_HCI_ERR_CMD_DISALLOWED;
327327
}
328328

329-
cte_info.type = df_cfg->cte_type;
330-
cte_info.time = df_cfg->cte_length;
331-
hdr_data = (uint8_t *)&cte_info;
332-
333-
err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_ALWAYS, &pdu_prev,
334-
&pdu, &extra_data_prev, &extra_data, &ter_idx);
335-
if (err) {
336-
return err;
337-
}
338-
339-
if (extra_data) {
340-
ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data,
341-
ULL_ADV_PDU_HDR_FIELD_CTE_INFO, 0,
342-
df_cfg);
343-
}
344-
345-
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
346-
ULL_ADV_PDU_HDR_FIELD_CTE_INFO, 0, hdr_data);
329+
err = cte_info_set(adv, df_cfg, &ter_idx, &pdu);
347330
if (err) {
348331
return err;
349332
}
@@ -665,4 +648,182 @@ static struct lll_df_adv_cfg *df_adv_cfg_acquire(void)
665648

666649
return df_adv_cfg;
667650
}
651+
652+
#if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1)
653+
/*
654+
* @brief Function sets content of cte_info field in periodic advertising chain.
655+
*
656+
* The function allocates new PDU (or chain of PDUs) for periodic advertising to
657+
* fill it with information about CTE, that is going to be transmitted with the PDU.
658+
* If there is already allocated PDU, it will be updated to hold information about
659+
* CTE.
660+
*
661+
* @param lll_sync Pointer to periodic advertising sync object.
662+
* @param pdu_prev Pointer to a PDU that is already in use by LLL or was updated with new PDU
663+
* payload.
664+
* @param pdu Pointer to a new head of periodic advertising chain. The pointer may have
665+
* the same value as @p pdu_prev, if payload of PDU pointerd by @p pdu_prev
666+
* was already updated.
667+
* @param cte_count Number of CTEs that should be transmitted in periodic advertising chain.
668+
* @param cte_into Pointer to instence of cte_info stuctuct that is added to PDUs extended
669+
* advertising header.
670+
*
671+
* @return Zero in case of success, other value in case of failure.
672+
*/
673+
static uint8_t per_adv_chain_cte_info_set(struct lll_adv_sync *lll_sync, struct pdu_adv *pdu_prev,
674+
struct pdu_adv *pdu, uint8_t cte_count,
675+
struct pdu_cte_info *cte_info)
676+
{
677+
uint8_t pdu_add_field_flags;
678+
struct pdu_adv *pdu_next;
679+
uint8_t cte_index = 1;
680+
bool new_chain;
681+
uint8_t err;
682+
683+
new_chain = (pdu_prev == pdu ? false : true);
684+
685+
pdu_add_field_flags = ULL_ADV_PDU_HDR_FIELD_CTE_INFO;
686+
687+
pdu_prev = lll_adv_pdu_linked_next_get(pdu_prev);
688+
689+
/* Update PDUs in existing chain. Add cte_info to extended advertising header. */
690+
while (pdu_prev) {
691+
if (new_chain) {
692+
pdu_next = lll_adv_pdu_alloc_pdu_adv();
693+
lll_adv_pdu_linked_append(pdu_next, pdu);
694+
pdu = pdu_next;
695+
} else {
696+
pdu = lll_adv_pdu_linked_next_get(pdu);
697+
}
698+
699+
pdu_next = lll_adv_pdu_linked_next_get(pdu_prev);
700+
/* If all CTEs were added to chain, remove CTE from flags */
701+
if (cte_index >= cte_count) {
702+
pdu_add_field_flags = 0;
703+
} else {
704+
++cte_index;
705+
/* If it is last PDU in existing chain and there are CTE to be included
706+
* add aux_ptr to flags.
707+
*/
708+
if (!pdu_next && cte_index < cte_count) {
709+
pdu_add_field_flags |= ULL_ADV_PDU_HDR_FIELD_AUX_PTR;
710+
}
711+
}
712+
713+
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, pdu_add_field_flags, 0,
714+
cte_info);
715+
if (err != BT_HCI_ERR_SUCCESS) {
716+
/* TODO: implement gracefull error handling, cleanup of
717+
* changed PDUs and notify host abut issue during start of CTE
718+
* transmission.
719+
*/
720+
return err;
721+
}
722+
pdu_prev = pdu_next;
723+
}
724+
725+
/* If there is missing only one CTE do not add aux_ptr to PDU */
726+
if (cte_count - cte_index >= 2) {
727+
pdu_add_field_flags |= ULL_ADV_PDU_HDR_FIELD_AUX_PTR;
728+
} else {
729+
pdu_add_field_flags = ULL_ADV_PDU_HDR_FIELD_CTE_INFO;
730+
}
731+
732+
/* Add new PDUs if the number of PDUs in existing chain is lower than requested number
733+
* of CTEs.
734+
*/
735+
while (cte_index < cte_count) {
736+
pdu_prev = pdu;
737+
pdu = lll_adv_pdu_alloc_pdu_adv();
738+
if (!pdu) {
739+
/* TODO: implement graceful error handling, cleanup of
740+
* changed PDUs.
741+
*/
742+
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
743+
}
744+
ull_adv_sync_pdu_init(pdu, pdu_add_field_flags);
745+
ull_adv_sync_pdu_cte_info_set(pdu, cte_info);
746+
747+
/* Link PDU into a chain */
748+
lll_adv_pdu_linked_append(pdu, pdu_prev);
749+
750+
++cte_index;
751+
/* If next PDU in a chain is last PDU, then remove aux_ptr field flag from
752+
* extended advertising header.
753+
*/
754+
if (cte_index == cte_count - 1) {
755+
pdu_add_field_flags &= (~ULL_ADV_PDU_HDR_FIELD_AUX_PTR);
756+
}
757+
}
758+
759+
return BT_HCI_ERR_SUCCESS;
760+
}
761+
#endif /* CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 */
762+
763+
/*
764+
* @brief Function sets content of cte_info field for periodic advertising
765+
*
766+
* @param adv Pointer to periodic advertising set.
767+
* @param df_cfg Pointer to direction finding configuration
768+
* @param[out] ter_idx Pointer used to return index of allocated or updated PDU.
769+
* Index is required for scheduling the PDU for transmission in LLL.
770+
* @param[out] first_pdu Pointer to return address of first PDU in a periodic advertising chain
771+
*
772+
* @return Zero in case of success, other value in case of failure.
773+
*/
774+
static uint8_t cte_info_set(struct ll_adv_set *adv, struct lll_df_adv_cfg *df_cfg, uint8_t *ter_idx,
775+
struct pdu_adv **first_pdu)
776+
{
777+
struct pdu_adv *pdu_prev, *pdu;
778+
struct lll_adv_sync *lll_sync;
779+
struct pdu_cte_info cte_info;
780+
uint8_t pdu_add_field_flags;
781+
void *extra_data;
782+
uint8_t err;
783+
784+
lll_sync = adv->lll.sync;
785+
786+
cte_info.type = df_cfg->cte_type;
787+
cte_info.time = df_cfg->cte_length;
788+
789+
/* Note: ULL_ADV_PDU_HDR_FIELD_CTE_INFO is just information that extra_data
790+
* is required in case of this ull_adv_sync_pdu_alloc.
791+
* Other flags here do not change anything. It may be changed to use
792+
* true/false flag for extra_data allocation.
793+
*/
794+
err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_ALWAYS, &pdu_prev, &pdu,
795+
NULL, &extra_data, ter_idx);
796+
if (err != BT_HCI_ERR_SUCCESS) {
797+
return err;
798+
}
799+
800+
ull_adv_sync_extra_data_set_clear(NULL, extra_data, ULL_ADV_PDU_HDR_FIELD_CTE_INFO, 0,
801+
df_cfg);
802+
803+
#if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1)
804+
if (df_cfg->cte_count > 1) {
805+
pdu_add_field_flags =
806+
ULL_ADV_PDU_HDR_FIELD_CTE_INFO | ULL_ADV_PDU_HDR_FIELD_AUX_PTR;
807+
} else
808+
#endif /* CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 */
809+
{
810+
pdu_add_field_flags = ULL_ADV_PDU_HDR_FIELD_CTE_INFO;
811+
}
812+
813+
err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu, pdu_add_field_flags, 0,
814+
&cte_info);
815+
if (err != BT_HCI_ERR_SUCCESS) {
816+
return err;
817+
}
818+
819+
*first_pdu = pdu;
820+
#if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1)
821+
err = per_adv_chain_cte_info_set(lll_sync, pdu_prev, pdu, df_cfg->cte_count, &cte_info);
822+
if (err != BT_HCI_ERR_SUCCESS) {
823+
return err;
824+
}
825+
#endif /* CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 */
826+
827+
return BT_HCI_ERR_SUCCESS;
828+
}
668829
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */

0 commit comments

Comments
 (0)