@@ -81,6 +81,8 @@ static uint8_t mem_link_iq_report_quota_pdu;
8181#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX )
8282static struct lll_df_adv_cfg lll_df_adv_cfg_pool [CONFIG_BT_CTLR_ADV_AUX_SET ];
8383static void * df_adv_cfg_free ;
84+ static uint8_t cte_info_clear (struct ll_adv_set * adv , struct lll_df_adv_cfg * df_cfg ,
85+ uint8_t * ter_idx , struct pdu_adv * * first_pdu );
8486#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
8587
8688/* @brief Function performs common steps for initialization and reset
@@ -274,13 +276,12 @@ uint8_t ll_df_set_cl_cte_tx_params(uint8_t adv_handle, uint8_t cte_len,
274276 */
275277uint8_t ll_df_set_cl_cte_tx_enable (uint8_t adv_handle , uint8_t cte_enable )
276278{
277- void * extra_data_prev , * extra_data ;
278- struct pdu_adv * pdu_prev , * pdu ;
279279 struct lll_adv_sync * lll_sync ;
280280 struct lll_df_adv_cfg * df_cfg ;
281281 struct ll_adv_sync_set * sync ;
282282 struct ll_adv_set * adv ;
283283 uint8_t err , ter_idx ;
284+ struct pdu_adv * pdu ;
284285
285286 /* Get the advertising set instance */
286287 adv = ull_adv_is_created_get (adv_handle );
@@ -315,22 +316,7 @@ uint8_t ll_df_set_cl_cte_tx_enable(uint8_t adv_handle, uint8_t cte_enable)
315316 return BT_HCI_ERR_CMD_DISALLOWED ;
316317 }
317318
318- err = ull_adv_sync_pdu_alloc (adv , ULL_ADV_PDU_EXTRA_DATA_ALLOC_NEVER , & pdu_prev ,
319- & pdu , & extra_data_prev , & extra_data , & ter_idx );
320- if (err ) {
321- return err ;
322- }
323-
324- if (extra_data ) {
325- ull_adv_sync_extra_data_set_clear (extra_data_prev ,
326- extra_data , 0 ,
327- ULL_ADV_PDU_HDR_FIELD_CTE_INFO ,
328- NULL );
329- }
330-
331- err = ull_adv_sync_pdu_set_clear (lll_sync , pdu_prev , pdu , 0 ,
332- ULL_ADV_PDU_HDR_FIELD_CTE_INFO ,
333- NULL );
319+ err = cte_info_clear (adv , df_cfg , & ter_idx , & pdu );
334320 if (err ) {
335321 return err ;
336322 }
@@ -841,4 +827,185 @@ static uint8_t cte_info_set(struct ll_adv_set *adv, struct lll_df_adv_cfg *df_cf
841827
842828 return BT_HCI_ERR_SUCCESS ;
843829}
830+
831+ #if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 )
832+ static bool pdu_ext_adv_is_empty_without_cte (const struct pdu_adv * pdu )
833+ {
834+ if (pdu -> len != PDU_AC_PAYLOAD_SIZE_MIN ) {
835+ const struct pdu_adv_ext_hdr * ext_hdr ;
836+ uint8_t size_rem = 0 ;
837+
838+ if ((pdu -> adv_ext_ind .ext_hdr_len + PDU_AC_EXT_HEADER_SIZE_MIN ) != pdu -> len ) {
839+ /* There are adv. data in PDU */
840+ return false;
841+ }
842+
843+ /* Check size of the ext. header without cte_info and aux_ptr. If that is minimum
844+ * extended PDU size then the PDU was allocated to transport CTE only.
845+ */
846+ ext_hdr = & pdu -> adv_ext_ind .ext_hdr ;
847+
848+ if (ext_hdr -> cte_info ) {
849+ size_rem += sizeof (struct pdu_cte_info );
850+ }
851+ if (ext_hdr -> aux_ptr ) {
852+ size_rem += sizeof (struct pdu_adv_aux_ptr );
853+ }
854+
855+ if ((pdu -> adv_ext_ind .ext_hdr_len - size_rem ) != PDU_AC_EXT_HEADER_SIZE_MIN ) {
856+ return false;
857+ }
858+ }
859+
860+ return true;
861+ }
862+
863+ /*
864+ * @brief Function removes content of cte_info field in periodic advertising chain.
865+ *
866+ * The function removes cte_info from extended advertising header in all PDUs in periodic
867+ * advertising chain. If particular PDU is empty (holds cte_info only) it will be removed from
868+ * chain.
869+ *
870+ * @param lll_sync Pointer to periodic advertising sync object.
871+ * @param pdu_prev Pointer to a PDU that is already in use by LLL or was updated with new PDU
872+ * payload.
873+ * @param pdu Pointer to a new head of periodic advertising chain. The pointer may have
874+ * the same value as @p pdu_prev, if payload of PDU pointerd by @p pdu_prev was
875+ * already updated.
876+ *
877+ * @return Zero in case of success, other value in case of failure.
878+ */
879+ static uint8_t rem_cte_info_from_per_adv_chain (struct lll_adv_sync * lll_sync ,
880+ struct pdu_adv * pdu_prev , struct pdu_adv * pdu )
881+ {
882+ struct pdu_adv * pdu_new , * pdu_chained ;
883+ uint8_t pdu_rem_field_flags ;
884+ bool new_chain ;
885+ uint8_t err ;
886+
887+ pdu_rem_field_flags = ULL_ADV_PDU_HDR_FIELD_CTE_INFO ;
888+
889+ /* It is possible that the function is called after e.g. advertising data were updated.
890+ * In such situation the function will run on already allocated chain. Do not allocate
891+ * new chain then. Reuse already allocated PDUs and allocate new ones only if the chain
892+ * was not updated yet.
893+ */
894+ new_chain = (pdu_prev == pdu ? false : true);
895+
896+ /* Get next PDU in a chain. Alway use pdu_prev because it points to actual
897+ * former chain.
898+ */
899+ pdu_chained = lll_adv_pdu_linked_next_get (pdu_prev );
900+
901+ /* Go through existing chain and remove CTE info. */
902+ while (pdu_chained ) {
903+ if (pdu_ext_adv_is_empty_without_cte (pdu_chained )) {
904+ /* If there is an empty PDU then all remaining PDUs shoudl be released. */
905+ lll_adv_pdu_linked_release_all (pdu_chained );
906+ pdu_chained = NULL ;
907+ /* Set new end of chain in PDUs linked list. If pdu differs from prev_pdu
908+ * then it is alread end of a chain. If it doesn't differ, then chain end
909+ * is changed in rigth place by use of pdu_prev. That makes sure there
910+ * is no PDU released twice (here and when LLL swaps PDU buffers).
911+ */
912+ lll_adv_pdu_linked_append (NULL , pdu_prev );
913+ } else {
914+ /* Update one before pdu_chained */
915+ err = ull_adv_sync_pdu_set_clear (lll_sync , pdu_prev , pdu , 0 ,
916+ pdu_rem_field_flags , NULL );
917+ if (err != BT_HCI_ERR_SUCCESS ) {
918+ /* TODO: return here leaves periodic advertising chain in
919+ * an inconsisten state. Add gracefull return or assert.
920+ */
921+ return err ;
922+ }
923+
924+ /* Prepare for next iteration. Allocate new PDU or move to next one in
925+ * a chain.
926+ */
927+ if (new_chain ) {
928+ pdu_new = lll_adv_pdu_alloc_pdu_adv ();
929+ lll_adv_pdu_linked_append (pdu_new , pdu );
930+ pdu = pdu_new ;
931+ } else {
932+ pdu = lll_adv_pdu_linked_next_get (pdu );
933+ }
934+
935+ /* Move to next chained PDU (it moves through chain that is in use
936+ * by LLL or is new one with updated advertising payload).
937+ */
938+ pdu_prev = pdu_chained ;
939+ pdu_chained = lll_adv_pdu_linked_next_get (pdu_prev );
940+ }
941+ }
942+
943+ return BT_HCI_ERR_SUCCESS ;
944+ }
945+ #endif /* (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1) */
946+
947+ /*
948+ * @brief Function removes content of cte_info field from periodic advertising PDUs.
949+ *
950+ * @param adv Pointer to periodic advertising set.
951+ * @param df_cfg Pointer to direction finding configuration
952+ * @param[out] ter_idx Pointer used to return index of allocated or updated PDU.
953+ * Index is required for scheduling the PDU for transmission in LLL.
954+ * @param[out] first_pdu Pointer to return address of first PDU in a chain
955+ *
956+ * @return Zero in case of success, other value in case of failure.
957+ */
958+ static uint8_t cte_info_clear (struct ll_adv_set * adv , struct lll_df_adv_cfg * df_cfg ,
959+ uint8_t * ter_idx , struct pdu_adv * * first_pdu )
960+ {
961+ void * extra_data_prev , * extra_data ;
962+ struct pdu_adv * pdu_prev , * pdu ;
963+ struct lll_adv_sync * lll_sync ;
964+ uint8_t pdu_rem_field_flags ;
965+ uint8_t err ;
966+
967+ lll_sync = adv -> lll .sync ;
968+
969+ /* NOTE: ULL_ADV_PDU_HDR_FIELD_CTE_INFO is just information that extra_data
970+ * should be removed in case of this call ull_adv_sync_pdu_alloc.
971+ * Other flags here do not change anything. It may be changed to use
972+ * true/false flag for extra_data allocation.
973+ */
974+ err = ull_adv_sync_pdu_alloc (adv , ULL_ADV_PDU_EXTRA_DATA_ALLOC_NEVER , & pdu_prev , & pdu ,
975+ & extra_data_prev , & extra_data , ter_idx );
976+ if (err != BT_HCI_ERR_SUCCESS ) {
977+ return err ;
978+ }
979+
980+ if (extra_data ) {
981+ ull_adv_sync_extra_data_set_clear (extra_data_prev , extra_data , 0 ,
982+ ULL_ADV_PDU_HDR_FIELD_CTE_INFO , NULL );
983+ }
984+
985+ * first_pdu = pdu ;
986+
987+ pdu_rem_field_flags = ULL_ADV_PDU_HDR_FIELD_CTE_INFO ;
988+
989+ #if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 )
990+ err = rem_cte_info_from_per_adv_chain (lll_sync , pdu_prev , pdu );
991+ if (err != BT_HCI_ERR_SUCCESS ) {
992+ return err ;
993+ }
994+
995+ /* Update last PDU in a chain. It may not have aux_ptr.
996+ * NOTE: If there is no AuxPtr flag in the PDU, attempt to remove it does not harm.
997+ */
998+ pdu_rem_field_flags |= ULL_ADV_PDU_HDR_FIELD_AUX_PTR ;
999+ #endif /* CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 */
1000+
1001+ err = ull_adv_sync_pdu_set_clear (lll_sync , pdu_prev , pdu , 0 , pdu_rem_field_flags , NULL );
1002+ if (err != BT_HCI_ERR_SUCCESS ) {
1003+ /* TODO: return here leaves periodic advertising chain in an inconsisten state.
1004+ * Add gracefull return or assert.
1005+ */
1006+ return err ;
1007+ }
1008+
1009+ return BT_HCI_ERR_SUCCESS ;
1010+ }
8441011#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
0 commit comments