@@ -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
@@ -259,13 +261,12 @@ uint8_t ll_df_set_cl_cte_tx_params(uint8_t adv_handle, uint8_t cte_len,
259261 */
260262uint8_t ll_df_set_cl_cte_tx_enable (uint8_t adv_handle , uint8_t cte_enable )
261263{
262- void * extra_data_prev , * extra_data ;
263- struct pdu_adv * pdu_prev , * pdu ;
264264 struct lll_adv_sync * lll_sync ;
265265 struct lll_df_adv_cfg * df_cfg ;
266266 struct ll_adv_sync_set * sync ;
267267 struct ll_adv_set * adv ;
268268 uint8_t err , ter_idx ;
269+ struct pdu_adv * pdu ;
269270
270271 /* Get the advertising set instance */
271272 adv = ull_adv_is_created_get (adv_handle );
@@ -300,22 +301,7 @@ uint8_t ll_df_set_cl_cte_tx_enable(uint8_t adv_handle, uint8_t cte_enable)
300301 return BT_HCI_ERR_CMD_DISALLOWED ;
301302 }
302303
303- err = ull_adv_sync_pdu_alloc (adv , ULL_ADV_PDU_EXTRA_DATA_ALLOC_NEVER , & pdu_prev ,
304- & pdu , & extra_data_prev , & extra_data , & ter_idx );
305- if (err ) {
306- return err ;
307- }
308-
309- if (extra_data ) {
310- ull_adv_sync_extra_data_set_clear (extra_data_prev ,
311- extra_data , 0 ,
312- ULL_ADV_PDU_HDR_FIELD_CTE_INFO ,
313- NULL );
314- }
315-
316- err = ull_adv_sync_pdu_set_clear (lll_sync , pdu_prev , pdu , 0 ,
317- ULL_ADV_PDU_HDR_FIELD_CTE_INFO ,
318- NULL );
304+ err = cte_info_clear (adv , df_cfg , & ter_idx , & pdu );
319305 if (err ) {
320306 return err ;
321307 }
@@ -826,4 +812,185 @@ static uint8_t cte_info_set(struct ll_adv_set *adv, struct lll_df_adv_cfg *df_cf
826812
827813 return BT_HCI_ERR_SUCCESS ;
828814}
815+
816+ #if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 )
817+ static bool pdu_ext_adv_is_empty_without_cte (const struct pdu_adv * pdu )
818+ {
819+ if (pdu -> len != PDU_AC_PAYLOAD_SIZE_MIN ) {
820+ const struct pdu_adv_ext_hdr * ext_hdr ;
821+ uint8_t size_rem = 0 ;
822+
823+ if ((pdu -> adv_ext_ind .ext_hdr_len + PDU_AC_EXT_HEADER_SIZE_MIN ) != pdu -> len ) {
824+ /* There are adv. data in PDU */
825+ return false;
826+ }
827+
828+ /* Check size of the ext. header without cte_info and aux_ptr. If that is minimum
829+ * extended PDU size then the PDU was allocated to transport CTE only.
830+ */
831+ ext_hdr = & pdu -> adv_ext_ind .ext_hdr ;
832+
833+ if (ext_hdr -> cte_info ) {
834+ size_rem += sizeof (struct pdu_cte_info );
835+ }
836+ if (ext_hdr -> aux_ptr ) {
837+ size_rem += sizeof (struct pdu_adv_aux_ptr );
838+ }
839+
840+ if ((pdu -> adv_ext_ind .ext_hdr_len - size_rem ) != PDU_AC_EXT_HEADER_SIZE_MIN ) {
841+ return false;
842+ }
843+ }
844+
845+ return true;
846+ }
847+
848+ /*
849+ * @brief Function removes content of cte_info field in periodic advertising chain.
850+ *
851+ * The function removes cte_info from extended advertising header in all PDUs in periodic
852+ * advertising chain. If particular PDU is empty (holds cte_info only) it will be removed from
853+ * chain.
854+ *
855+ * @param lll_sync Pointer to periodic advertising sync object.
856+ * @param pdu_prev Pointer to a PDU that is already in use by LLL or was updated with new PDU
857+ * payload.
858+ * @param pdu Pointer to a new head of periodic advertising chain. The pointer may have
859+ * the same value as @p pdu_prev, if payload of PDU pointerd by @p pdu_prev was
860+ * already updated.
861+ *
862+ * @return Zero in case of success, other value in case of failure.
863+ */
864+ static uint8_t rem_cte_info_from_per_adv_chain (struct lll_adv_sync * lll_sync ,
865+ struct pdu_adv * pdu_prev , struct pdu_adv * pdu )
866+ {
867+ struct pdu_adv * pdu_new , * pdu_chained ;
868+ uint8_t pdu_rem_field_flags ;
869+ bool new_chain ;
870+ uint8_t err ;
871+
872+ pdu_rem_field_flags = ULL_ADV_PDU_HDR_FIELD_CTE_INFO ;
873+
874+ /* It is possible that the function is called after e.g. advertising data were updated.
875+ * In such situation the function will run on already allocated chain. Do not allocate
876+ * new chain then. Reuse already allocated PDUs and allocate new ones only if the chain
877+ * was not updated yet.
878+ */
879+ new_chain = (pdu_prev == pdu ? false : true);
880+
881+ /* Get next PDU in a chain. Alway use pdu_prev because it points to actual
882+ * former chain.
883+ */
884+ pdu_chained = lll_adv_pdu_linked_next_get (pdu_prev );
885+
886+ /* Go through existing chain and remove CTE info. */
887+ while (pdu_chained ) {
888+ if (pdu_ext_adv_is_empty_without_cte (pdu_chained )) {
889+ /* If there is an empty PDU then all remaining PDUs shoudl be released. */
890+ lll_adv_pdu_linked_release_all (pdu_chained );
891+ pdu_chained = NULL ;
892+ /* Set new end of chain in PDUs linked list. If pdu differs from prev_pdu
893+ * then it is alread end of a chain. If it doesn't differ, then chain end
894+ * is changed in rigth place by use of pdu_prev. That makes sure there
895+ * is no PDU released twice (here and when LLL swaps PDU buffers).
896+ */
897+ lll_adv_pdu_linked_append (NULL , pdu_prev );
898+ } else {
899+ /* Update one before pdu_chained */
900+ err = ull_adv_sync_pdu_set_clear (lll_sync , pdu_prev , pdu , 0 ,
901+ pdu_rem_field_flags , NULL );
902+ if (err != BT_HCI_ERR_SUCCESS ) {
903+ /* TODO: return here leaves periodic advertising chain in
904+ * an inconsisten state. Add gracefull return or assert.
905+ */
906+ return err ;
907+ }
908+
909+ /* Prepare for next iteration. Allocate new PDU or move to next one in
910+ * a chain.
911+ */
912+ if (new_chain ) {
913+ pdu_new = lll_adv_pdu_alloc_pdu_adv ();
914+ lll_adv_pdu_linked_append (pdu_new , pdu );
915+ pdu = pdu_new ;
916+ } else {
917+ pdu = lll_adv_pdu_linked_next_get (pdu );
918+ }
919+
920+ /* Move to next chained PDU (it moves through chain that is in use
921+ * by LLL or is new one with updated advertising payload).
922+ */
923+ pdu_prev = pdu_chained ;
924+ pdu_chained = lll_adv_pdu_linked_next_get (pdu_prev );
925+ }
926+ }
927+
928+ return BT_HCI_ERR_SUCCESS ;
929+ }
930+ #endif /* (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1) */
931+
932+ /*
933+ * @brief Function removes content of cte_info field from periodic advertising PDUs.
934+ *
935+ * @param adv Pointer to periodic advertising set.
936+ * @param df_cfg Pointer to direction finding configuration
937+ * @param[out] ter_idx Pointer used to return index of allocated or updated PDU.
938+ * Index is required for scheduling the PDU for transmission in LLL.
939+ * @param[out] first_pdu Pointer to return address of first PDU in a chain
940+ *
941+ * @return Zero in case of success, other value in case of failure.
942+ */
943+ static uint8_t cte_info_clear (struct ll_adv_set * adv , struct lll_df_adv_cfg * df_cfg ,
944+ uint8_t * ter_idx , struct pdu_adv * * first_pdu )
945+ {
946+ void * extra_data_prev , * extra_data ;
947+ struct pdu_adv * pdu_prev , * pdu ;
948+ struct lll_adv_sync * lll_sync ;
949+ uint8_t pdu_rem_field_flags ;
950+ uint8_t err ;
951+
952+ lll_sync = adv -> lll .sync ;
953+
954+ /* NOTE: ULL_ADV_PDU_HDR_FIELD_CTE_INFO is just information that extra_data
955+ * should be removed in case of this call ull_adv_sync_pdu_alloc.
956+ * Other flags here do not change anything. It may be changed to use
957+ * true/false flag for extra_data allocation.
958+ */
959+ err = ull_adv_sync_pdu_alloc (adv , ULL_ADV_PDU_EXTRA_DATA_ALLOC_NEVER , & pdu_prev , & pdu ,
960+ & extra_data_prev , & extra_data , ter_idx );
961+ if (err != BT_HCI_ERR_SUCCESS ) {
962+ return err ;
963+ }
964+
965+ if (extra_data ) {
966+ ull_adv_sync_extra_data_set_clear (extra_data_prev , extra_data , 0 ,
967+ ULL_ADV_PDU_HDR_FIELD_CTE_INFO , NULL );
968+ }
969+
970+ * first_pdu = pdu ;
971+
972+ pdu_rem_field_flags = ULL_ADV_PDU_HDR_FIELD_CTE_INFO ;
973+
974+ #if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 )
975+ err = rem_cte_info_from_per_adv_chain (lll_sync , pdu_prev , pdu );
976+ if (err != BT_HCI_ERR_SUCCESS ) {
977+ return err ;
978+ }
979+
980+ /* Update last PDU in a chain. It may not have aux_ptr.
981+ * NOTE: If there is no AuxPtr flag in the PDU, attempt to remove it does not harm.
982+ */
983+ pdu_rem_field_flags |= ULL_ADV_PDU_HDR_FIELD_AUX_PTR ;
984+ #endif /* CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 */
985+
986+ err = ull_adv_sync_pdu_set_clear (lll_sync , pdu_prev , pdu , 0 , pdu_rem_field_flags , NULL );
987+ if (err != BT_HCI_ERR_SUCCESS ) {
988+ /* TODO: return here leaves periodic advertising chain in an inconsisten state.
989+ * Add gracefull return or assert.
990+ */
991+ return err ;
992+ }
993+
994+ return BT_HCI_ERR_SUCCESS ;
995+ }
829996#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
0 commit comments