get_default_secondaryCellGroup() would "sanitize" the servingCellConfig, i.e., remove BWP that are invalid. However, it is difficult to understand (we can do sanitization once at the beginning) and reason (why the servingCellConfig is modified in get_default_secondaryCellGroup(), because all we want is a new CellGroupConfig, without modifying other data structures). Instead, do sanitization once after reading the configuration in gnb_config.c. Also, modify physical simulators nr_dlsim and nr_ulsim to apply this sanitization before a call to get_default_secondaryCellGroup(), as the latter would have done the sanitization.
2413 lines
132 KiB
C
2413 lines
132 KiB
C
/*
|
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
|
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.openairinterface.org/?page_id=698
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*-------------------------------------------------------------------------------
|
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
|
* contact@openairinterface.org
|
|
*/
|
|
|
|
/*
|
|
gnb_config.c
|
|
-------------------
|
|
AUTHOR : Lionel GAUTHIER, navid nikaein, Laurent Winckel, WEI-TAI CHEN
|
|
COMPANY : EURECOM, NTUST
|
|
EMAIL : Lionel.Gauthier@eurecom.fr, navid.nikaein@eurecom.fr, kroempa@gmail.com
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "common/utils/LOG/log.h"
|
|
#include "common/utils/nr/nr_common.h"
|
|
#include "assertions.h"
|
|
#include "oai_asn1.h"
|
|
#include "executables/softmodem-common.h"
|
|
#include "gnb_config.h"
|
|
#include "gnb_paramdef.h"
|
|
#include "enb_paramdef.h"
|
|
#include "UTIL/OTG/otg.h"
|
|
#include "UTIL/OTG/otg_externs.h"
|
|
#include "intertask_interface.h"
|
|
#include "ngap_gNB.h"
|
|
#include "sctp_eNB_task.h"
|
|
#include "sctp_default_values.h"
|
|
#include "F1AP_CauseRadioNetwork.h"
|
|
#include "f1ap_common.h"
|
|
// #include "SystemInformationBlockType2.h"
|
|
// #include "LAYER2/MAC/extern.h"
|
|
// #include "LAYER2/MAC/proto.h"
|
|
#include "PHY/INIT/nr_phy_init.h"
|
|
#include "radio/ETHERNET/ethernet_lib.h"
|
|
#include "nfapi_vnf.h"
|
|
#include "nfapi_pnf.h"
|
|
#include "nr_pdcp/nr_pdcp_oai_api.h"
|
|
|
|
//#include "L1_paramdef.h"
|
|
#include "prs_nr_paramdef.h"
|
|
#include "L1_nr_paramdef.h"
|
|
#include "MACRLC_nr_paramdef.h"
|
|
#include "common/config/config_userapi.h"
|
|
//#include "RRC_config_tools.h"
|
|
#include "gnb_paramdef.h"
|
|
#include "NR_MAC_gNB/mac_proto.h"
|
|
#include <openair3/ocp-gtpu/gtp_itf.h>
|
|
|
|
#include "NR_asn_constant.h"
|
|
#include "executables/thread-common.h"
|
|
#include "NR_SCS-SpecificCarrier.h"
|
|
#include "NR_TDD-UL-DL-ConfigCommon.h"
|
|
#include "NR_FrequencyInfoUL.h"
|
|
#include "NR_RACH-ConfigGeneric.h"
|
|
#include "NR_RACH-ConfigCommon.h"
|
|
#include "NR_PUSCH-TimeDomainResourceAllocation.h"
|
|
#include "NR_PUSCH-ConfigCommon.h"
|
|
#include "NR_PUCCH-ConfigCommon.h"
|
|
#include "NR_PDSCH-TimeDomainResourceAllocation.h"
|
|
#include "NR_PDSCH-ConfigCommon.h"
|
|
#include "NR_RateMatchPattern.h"
|
|
#include "NR_RateMatchPatternLTE-CRS.h"
|
|
#include "NR_SearchSpace.h"
|
|
#include "NR_ControlResourceSet.h"
|
|
#include "NR_MeasurementTimingConfiguration.h"
|
|
#include "NR_EUTRA-MBSFN-SubframeConfig.h"
|
|
#include "uper_decoder.h"
|
|
#include "uper_encoder.h"
|
|
#include "common/utils/ds/seq_arr.h"
|
|
|
|
#include "RRC/NR/MESSAGES/asn1_msg.h"
|
|
#include "RRC/NR/nr_rrc_extern.h"
|
|
#include "openair2/LAYER2/nr_pdcp/nr_pdcp.h"
|
|
#include "nfapi/oai_integration/vendor_ext.h"
|
|
#ifdef ENABLE_AERIAL
|
|
#include "nfapi/oai_integration/aerial/fapi_vnf_p5.h"
|
|
#endif
|
|
|
|
extern uint16_t sf_ahead;
|
|
|
|
extern int config_check_band_frequencies(int ind, int16_t band, uint64_t downlink_frequency,
|
|
int32_t uplink_frequency_offset, uint32_t frame_type);
|
|
|
|
void prepare_scc(NR_ServingCellConfigCommon_t *scc) {
|
|
|
|
NR_FreqBandIndicatorNR_t *dl_frequencyBandList,*ul_frequencyBandList;
|
|
struct NR_SCS_SpecificCarrier *dl_scs_SpecificCarrierList,*ul_scs_SpecificCarrierList;
|
|
// struct NR_RateMatchPattern *ratematchpattern;
|
|
// NR_RateMatchPatternId_t *ratematchpatternid;
|
|
// NR_TCI_StateId_t *TCI_StateId;
|
|
// struct NR_ControlResourceSet *bwp_dl_controlresourceset;
|
|
// NR_SearchSpace_t *bwp_dl_searchspace;
|
|
|
|
scc->physCellId = CALLOC(1,sizeof(NR_PhysCellId_t));
|
|
scc->downlinkConfigCommon = CALLOC(1,sizeof(struct NR_DownlinkConfigCommon));
|
|
scc->downlinkConfigCommon->frequencyInfoDL = CALLOC(1,sizeof(struct NR_FrequencyInfoDL));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP = CALLOC(1,sizeof(struct NR_BWP_DownlinkCommon));
|
|
scc->uplinkConfigCommon = CALLOC(1,sizeof(struct NR_UplinkConfigCommon));
|
|
scc->uplinkConfigCommon->frequencyInfoUL = CALLOC(1,sizeof(struct NR_FrequencyInfoUL));
|
|
scc->uplinkConfigCommon->initialUplinkBWP = CALLOC(1,sizeof(struct NR_BWP_UplinkCommon));
|
|
//scc->supplementaryUplinkConfig = CALLOC(1,sizeof(struct NR_UplinkConfigCommon));
|
|
scc->n_TimingAdvanceOffset = CALLOC(1, sizeof(long));
|
|
scc->ssb_PositionsInBurst = CALLOC(1,sizeof(struct NR_ServingCellConfigCommon__ssb_PositionsInBurst));
|
|
scc->ssb_periodicityServingCell = CALLOC(1,sizeof(long));
|
|
// scc->rateMatchPatternToAddModList = CALLOC(1,sizeof(struct NR_ServingCellConfigCommon__rateMatchPatternToAddModList));
|
|
// scc->rateMatchPatternToReleaseList = CALLOC(1,sizeof(struct NR_ServingCellConfigCommon__rateMatchPatternToReleaseList));
|
|
scc->ssbSubcarrierSpacing = CALLOC(1,sizeof(NR_SubcarrierSpacing_t));
|
|
scc->tdd_UL_DL_ConfigurationCommon = CALLOC(1,sizeof(struct NR_TDD_UL_DL_ConfigCommon));
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2 = CALLOC(1,sizeof(struct NR_TDD_UL_DL_Pattern));
|
|
|
|
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB = CALLOC(1,sizeof(NR_ARFCN_ValueNR_t));
|
|
|
|
dl_frequencyBandList = CALLOC(1,sizeof(NR_FreqBandIndicatorNR_t));
|
|
dl_scs_SpecificCarrierList = CALLOC(1,sizeof(struct NR_SCS_SpecificCarrier));
|
|
|
|
asn1cSeqAdd(&scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list,dl_frequencyBandList);
|
|
asn1cSeqAdd(&scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list,dl_scs_SpecificCarrierList);
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.cyclicPrefix = CALLOC(1,sizeof(long));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon = CALLOC(1,sizeof(struct NR_SetupRelease_PDCCH_ConfigCommon));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->present=NR_SetupRelease_PDCCH_ConfigCommon_PR_setup;
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_PDCCH_ConfigCommon));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero = CALLOC(1,sizeof(long));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceZero = CALLOC(1,sizeof(long));
|
|
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet = NULL;
|
|
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList = CALLOC(1,sizeof(struct NR_PDCCH_ConfigCommon__commonSearchSpaceList));
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceSIB1 = CALLOC(1,sizeof(NR_SearchSpaceId_t));
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceOtherSystemInformation = CALLOC(1,sizeof(NR_SearchSpaceId_t));
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->pagingSearchSpace = CALLOC(1,sizeof(NR_SearchSpaceId_t));
|
|
// scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->ra_SearchSpace = CALLOC(1,sizeof(NR_SearchSpaceId_t));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon = CALLOC(1,sizeof(struct NR_SetupRelease_PDSCH_ConfigCommon));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->present = NR_SetupRelease_PDSCH_ConfigCommon_PR_setup;
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_PDSCH_ConfigCommon));
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList = CALLOC(1,sizeof(struct NR_PDSCH_TimeDomainResourceAllocationList));
|
|
|
|
ul_frequencyBandList = CALLOC(1,sizeof(NR_FreqBandIndicatorNR_t));
|
|
scc->uplinkConfigCommon->frequencyInfoUL->frequencyBandList = CALLOC(1,sizeof(struct NR_MultiFrequencyBandListNR));
|
|
asn1cSeqAdd(&scc->uplinkConfigCommon->frequencyInfoUL->frequencyBandList->list,ul_frequencyBandList);
|
|
|
|
scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA = CALLOC(1,sizeof(NR_ARFCN_ValueNR_t));
|
|
// scc->uplinkConfigCommon->frequencyInfoUL->additionalSpectrumEmission = CALLOC(1,sizeof(NR_AdditionalSpectrumEmission_t));
|
|
scc->uplinkConfigCommon->frequencyInfoUL->p_Max = CALLOC(1,sizeof(NR_P_Max_t));
|
|
// scc->uplinkConfigCommon->frequencyInfoUL->frequencyShift7p5khz = CALLOC(1,sizeof(long));
|
|
|
|
// scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.cyclicPrefix = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon = CALLOC(1,sizeof(NR_SetupRelease_RACH_ConfigCommon_t));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->present = NR_SetupRelease_RACH_ConfigCommon_PR_setup;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_RACH_ConfigCommon));
|
|
// scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB = CALLOC(1,sizeof(struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB));
|
|
// scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->groupBconfigured = CALLOC(1,sizeof(struct NR_RACH_ConfigCommon__groupBconfigured));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rsrp_ThresholdSSB = CALLOC(1,sizeof(NR_RSRP_Range_t));
|
|
// scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rsrp_ThresholdSSB_SUL = CALLOC(1,sizeof(NR_RSRP_Range_t));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing = CALLOC(1,sizeof(NR_SubcarrierSpacing_t));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder = CALLOC(1,sizeof(long));
|
|
// 0 - ENABLE, 1 - DISABLE, hence explicitly setting to DISABLED.
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon = CALLOC(1,sizeof(NR_SetupRelease_PUSCH_ConfigCommon_t));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->present = NR_SetupRelease_PUSCH_ConfigCommon_PR_setup;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_PUSCH_ConfigCommon));
|
|
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->groupHoppingEnabledTransformPrecoding = NULL;
|
|
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList = CALLOC(1,sizeof(struct NR_PUSCH_TimeDomainResourceAllocationList));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->p0_NominalWithGrant = CALLOC(1,sizeof(long));
|
|
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon = CALLOC(1,sizeof(struct NR_SetupRelease_PUCCH_ConfigCommon));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->present= NR_SetupRelease_PUCCH_ConfigCommon_PR_setup;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup = CALLOC(1,sizeof(struct NR_PUCCH_ConfigCommon));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->p0_nominal = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon = CALLOC(1,sizeof(long));
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId = CALLOC(1,sizeof(long));
|
|
|
|
// scc->ssb_PositionsInBurst->choice.shortBitmap.buf = MALLOC(1);
|
|
// scc->ssb_PositionsInBurst->choice.mediumBitmap.buf = MALLOC(1);
|
|
// scc->ssb_PositionsInBurst->choice.longBitmap.buf = MALLOC(8);
|
|
|
|
|
|
ul_scs_SpecificCarrierList = CALLOC(1,sizeof(struct NR_SCS_SpecificCarrier));
|
|
asn1cSeqAdd(&scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list,ul_scs_SpecificCarrierList);
|
|
|
|
//ratematchpattern = CALLOC(1,sizeof(struct NR_RateMatchPattern));
|
|
//ratematchpattern->patternType.choice.bitmaps = CALLOC(1,sizeof(struct NR_RateMatchPattern__patternType__bitmaps));
|
|
//ratematchpattern->patternType.choice.bitmaps->resourceBlocks.buf = MALLOC(35);
|
|
//ratematchpattern->patternType.choice.bitmaps->symbolsInResourceBlock.choice.oneSlot.buf = MALLOC(2);
|
|
//ratematchpattern->patternType.choice.bitmaps->symbolsInResourceBlock.choice.twoSlots.buf = MALLOC(4);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern = CALLOC(1,sizeof(struct NR_RateMatchPattern__patternType__bitmaps__periodicityAndPattern));
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n2.buf = MALLOC(1);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n4.buf = MALLOC(1);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n5.buf = MALLOC(1);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n8.buf = MALLOC(1);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n10.buf = MALLOC(2);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n20.buf = MALLOC(3);
|
|
//ratematchpattern->patternType.choice.bitmaps->periodicityAndPattern->choice.n40.buf = MALLOC(5);
|
|
//ratematchpattern->subcarrierSpacing = CALLOC(1,sizeof(NR_SubcarrierSpacing_t));
|
|
//ratematchpatternid = CALLOC(1,sizeof(NR_RateMatchPatternId_t));
|
|
|
|
scc->ext2 = CALLOC(1, sizeof(*scc->ext2));
|
|
scc->ext2->ntn_Config_r17 = CALLOC(1, sizeof(*scc->ext2->ntn_Config_r17));
|
|
scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 = CALLOC(1, sizeof(*scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17));
|
|
}
|
|
|
|
void fill_scc_sim(NR_ServingCellConfigCommon_t *scc,uint64_t *ssb_bitmap,int N_RB_DL,int N_RB_UL,int mu_dl,int mu_ul) {
|
|
|
|
*scc->physCellId=0; \
|
|
// *scc->n_TimingAdvanceOffset=NR_ServingCellConfigCommon__n_TimingAdvanceOffset_n0;
|
|
*scc->ssb_periodicityServingCell=NR_ServingCellConfigCommon__ssb_periodicityServingCell_ms20;
|
|
scc->dmrs_TypeA_Position=NR_ServingCellConfigCommon__dmrs_TypeA_Position_pos2;
|
|
*scc->ssbSubcarrierSpacing=mu_dl;
|
|
if (mu_dl == 0) {
|
|
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB=520432;
|
|
*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]=38;
|
|
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA=520000;
|
|
} else {
|
|
*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB=641032;
|
|
*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]=78;
|
|
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA=640000;
|
|
}
|
|
scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier=0;
|
|
scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing=mu_dl;
|
|
scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth=N_RB_DL;
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth =
|
|
PRBalloc_to_locationandbandwidth(N_RB_DL, 0);
|
|
scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing=mu_dl;//NR_SubcarrierSpacing_kHz30;
|
|
*scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero=12;
|
|
*scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceZero=0;
|
|
struct NR_PDSCH_TimeDomainResourceAllocation *timedomainresourceallocation0 = CALLOC(1,sizeof(NR_PDSCH_TimeDomainResourceAllocation_t));
|
|
timedomainresourceallocation0->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA;
|
|
timedomainresourceallocation0->startSymbolAndLength=54;
|
|
asn1cSeqAdd(&scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list,
|
|
timedomainresourceallocation0);
|
|
struct NR_PDSCH_TimeDomainResourceAllocation *timedomainresourceallocation1 = CALLOC(1,sizeof(NR_PDSCH_TimeDomainResourceAllocation_t));
|
|
timedomainresourceallocation1->mappingType=NR_PDSCH_TimeDomainResourceAllocation__mappingType_typeA;
|
|
timedomainresourceallocation1->startSymbolAndLength=57;
|
|
asn1cSeqAdd(&scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list,
|
|
timedomainresourceallocation1);
|
|
*scc->uplinkConfigCommon->frequencyInfoUL->frequencyBandList->list.array[0]=mu_ul?78:38;
|
|
*scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA=-1;
|
|
scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier=0;
|
|
scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing=mu_ul;
|
|
scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth=N_RB_UL;
|
|
*scc->uplinkConfigCommon->frequencyInfoUL->p_Max=20;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth = PRBalloc_to_locationandbandwidth(N_RB_UL, 0);
|
|
scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing=mu_ul;//NR_SubcarrierSpacing_kHz30;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex=98;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM=NR_RACH_ConfigGeneric__msg1_FDM_one;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FrequencyStart=0;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig=13;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower=-118;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleTransMax=NR_RACH_ConfigGeneric__preambleTransMax_n10;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.powerRampingStep=NR_RACH_ConfigGeneric__powerRampingStep_dB2;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow=NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present=NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.one=NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB__one_n64;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer=NR_RACH_ConfigCommon__ra_ContentionResolutionTimer_sf64;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rsrp_ThresholdSSB=19;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present=NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l139;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.choice.l139=0;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig=NR_RACH_ConfigCommon__restrictedSetConfig_unrestrictedSet;
|
|
struct NR_PUSCH_TimeDomainResourceAllocation *pusch_timedomainresourceallocation0 = CALLOC(1,sizeof(struct NR_PUSCH_TimeDomainResourceAllocation));
|
|
pusch_timedomainresourceallocation0->k2 = CALLOC(1,sizeof(long));
|
|
*pusch_timedomainresourceallocation0->k2=6;
|
|
pusch_timedomainresourceallocation0->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB;
|
|
pusch_timedomainresourceallocation0->startSymbolAndLength=55;
|
|
asn1cSeqAdd(&scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list,pusch_timedomainresourceallocation0);
|
|
struct NR_PUSCH_TimeDomainResourceAllocation *pusch_timedomainresourceallocation1 = CALLOC(1,sizeof(struct NR_PUSCH_TimeDomainResourceAllocation));
|
|
pusch_timedomainresourceallocation1->k2 = CALLOC(1,sizeof(long));
|
|
*pusch_timedomainresourceallocation1->k2=6;
|
|
pusch_timedomainresourceallocation1->mappingType=NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB;
|
|
pusch_timedomainresourceallocation1->startSymbolAndLength=38;
|
|
asn1cSeqAdd(&scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list,pusch_timedomainresourceallocation1);
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble=1;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->p0_NominalWithGrant=-90;
|
|
scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_GroupHopping=NR_PUCCH_ConfigCommon__pucch_GroupHopping_neither;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId=40;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->p0_nominal=-90;
|
|
scc->ssb_PositionsInBurst->present=NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap;
|
|
*ssb_bitmap=0xff;
|
|
scc->tdd_UL_DL_ConfigurationCommon->referenceSubcarrierSpacing=mu_dl;
|
|
if (mu_dl == 0)
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity=NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms10;
|
|
else
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity=NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms5;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots=7;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSymbols=6;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots=2;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols=4;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->dl_UL_TransmissionPeriodicity=321;
|
|
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofDownlinkSlots=-1;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofDownlinkSymbols=-1;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofUplinkSlots=-1;
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2->nrofUplinkSymbols=-1;
|
|
scc->ss_PBCH_BlockPower=20;
|
|
*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing=-1;
|
|
}
|
|
|
|
|
|
void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) {
|
|
|
|
int ssbmaplen = (int)scc->ssb_PositionsInBurst->present;
|
|
uint8_t curr_bit;
|
|
|
|
AssertFatal(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_shortBitmap ||
|
|
ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap ||
|
|
ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_longBitmap, "illegal ssbmaplen %d\n",ssbmaplen);
|
|
|
|
// changing endianicity of ssbmap and filling the ssb_PositionsInBurst buffers
|
|
if(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_shortBitmap){
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.size = 1;
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.bits_unused = 4;
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.buf = CALLOC(1,1);
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] = 0;
|
|
for (int i=0; i<8; i++) {
|
|
if (i<scc->ssb_PositionsInBurst->choice.shortBitmap.bits_unused)
|
|
curr_bit = 0;
|
|
else
|
|
curr_bit = (ssbmap>>(7-i))&0x01;
|
|
scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] |= curr_bit<<i;
|
|
}
|
|
}else if(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap){
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.size = 1;
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.bits_unused = 0;
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf = CALLOC(1,1);
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] = 0;
|
|
for (int i=0; i<8; i++)
|
|
scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] |= (((ssbmap>>(7-i))&0x01)<<i);
|
|
}else {
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.size = 8;
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.bits_unused = 0;
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.buf = CALLOC(1,8);
|
|
for (int j=0; j<8; j++) {
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.buf[j] = 0;
|
|
curr_bit = (ssbmap>>(j<<3))&(0xff);
|
|
for (int i=0; i<8; i++)
|
|
scc->ssb_PositionsInBurst->choice.longBitmap.buf[j] |= (((curr_bit>>(7-i))&0x01)<<i);
|
|
}
|
|
}
|
|
|
|
// fix SS0 and Coreset0
|
|
NR_PDCCH_ConfigCommon_t *pdcch_cc = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup;
|
|
if((int)*pdcch_cc->searchSpaceZero == -1) {
|
|
free(pdcch_cc->searchSpaceZero);
|
|
pdcch_cc->searchSpaceZero = NULL;
|
|
}
|
|
if((int)*pdcch_cc->controlResourceSetZero == -1) {
|
|
free(pdcch_cc->controlResourceSetZero);
|
|
pdcch_cc->controlResourceSetZero = NULL;
|
|
}
|
|
|
|
// fix UL absolute frequency
|
|
if ((int)*scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA==-1) {
|
|
free(scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA);
|
|
scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA = NULL;
|
|
}
|
|
|
|
// default value for msg3 precoder is NULL (0 means enabled)
|
|
if (*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder!=0)
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder = NULL;
|
|
|
|
frame_type_t frame_type = get_frame_type((int)*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
|
|
|
|
// prepare DL Allocation lists
|
|
nr_rrc_config_dl_tda(scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList,
|
|
frame_type, scc->tdd_UL_DL_ConfigurationCommon,
|
|
scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
|
|
|
|
if (frame_type == FDD) {
|
|
ASN_STRUCT_FREE(asn_DEF_NR_TDD_UL_DL_ConfigCommon, scc->tdd_UL_DL_ConfigurationCommon);
|
|
scc->tdd_UL_DL_ConfigurationCommon = NULL;
|
|
} else { // TDD
|
|
if (scc->tdd_UL_DL_ConfigurationCommon->pattern2->dl_UL_TransmissionPeriodicity > 320 ) {
|
|
free(scc->tdd_UL_DL_ConfigurationCommon->pattern2);
|
|
scc->tdd_UL_DL_ConfigurationCommon->pattern2 = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if ((int)*scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing == -1) {
|
|
free(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing);
|
|
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing=NULL;
|
|
}
|
|
|
|
if ((int)*scc->n_TimingAdvanceOffset == -1) {
|
|
free(scc->n_TimingAdvanceOffset);
|
|
scc->n_TimingAdvanceOffset = NULL;
|
|
}
|
|
|
|
// check pucch_ResourceConfig
|
|
AssertFatal(*scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon < 2,
|
|
"pucch_ResourceConfig should be 0 or 1 for now\n");
|
|
|
|
if(*scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 == 0) {
|
|
free(scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17);
|
|
free(scc->ext2->ntn_Config_r17);
|
|
free(scc->ext2);
|
|
scc->ext2 = NULL;
|
|
}
|
|
}
|
|
|
|
/* Function to allocate dedicated serving cell config strutures */
|
|
void prepare_scd(NR_ServingCellConfig_t *scd) {
|
|
// Allocate downlink structures
|
|
scd->downlinkBWP_ToAddModList = CALLOC(1, sizeof(*scd->downlinkBWP_ToAddModList));
|
|
scd->uplinkConfig = CALLOC(1, sizeof(*scd->uplinkConfig));
|
|
scd->uplinkConfig->uplinkBWP_ToAddModList = CALLOC(1, sizeof(*scd->uplinkConfig->uplinkBWP_ToAddModList));
|
|
scd->bwp_InactivityTimer = CALLOC(1, sizeof(*scd->bwp_InactivityTimer));
|
|
scd->uplinkConfig->firstActiveUplinkBWP_Id = CALLOC(1, sizeof(*scd->uplinkConfig->firstActiveUplinkBWP_Id));
|
|
scd->firstActiveDownlinkBWP_Id = CALLOC(1, sizeof(*scd->firstActiveDownlinkBWP_Id));
|
|
*scd->firstActiveDownlinkBWP_Id = 1;
|
|
*scd->uplinkConfig->firstActiveUplinkBWP_Id = 1;
|
|
scd->defaultDownlinkBWP_Id = CALLOC(1, sizeof(*scd->defaultDownlinkBWP_Id));
|
|
*scd->defaultDownlinkBWP_Id = 0;
|
|
|
|
for (int j = 0; j < NR_MAX_NUM_BWP; j++) {
|
|
|
|
// Downlink bandwidth part
|
|
NR_BWP_Downlink_t *bwp = calloc(1, sizeof(*bwp));
|
|
bwp->bwp_Id = j+1;
|
|
|
|
// Allocate downlink dedicated bandwidth part and PDSCH structures
|
|
bwp->bwp_Common = calloc(1, sizeof(*bwp->bwp_Common));
|
|
bwp->bwp_Common->pdcch_ConfigCommon = calloc(1, sizeof(*bwp->bwp_Common->pdcch_ConfigCommon));
|
|
bwp->bwp_Common->pdsch_ConfigCommon = calloc(1, sizeof(*bwp->bwp_Common->pdsch_ConfigCommon));
|
|
bwp->bwp_Dedicated = calloc(1, sizeof(*bwp->bwp_Dedicated));
|
|
bwp->bwp_Dedicated->pdsch_Config = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config));
|
|
bwp->bwp_Dedicated->pdsch_Config->present = NR_SetupRelease_PDSCH_Config_PR_setup;
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup));
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA));
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->present = NR_SetupRelease_DMRS_DownlinkConfig_PR_setup;
|
|
|
|
// Allocate DL DMRS and PTRS configuration
|
|
bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup));
|
|
NR_DMRS_DownlinkConfig_t *NR_DMRS_DownlinkCfg = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
|
|
NR_DMRS_DownlinkCfg->phaseTrackingRS=CALLOC(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS));
|
|
NR_DMRS_DownlinkCfg->phaseTrackingRS->present = NR_SetupRelease_PTRS_DownlinkConfig_PR_setup;
|
|
NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup = CALLOC(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup));
|
|
NR_PTRS_DownlinkConfig_t *NR_PTRS_DownlinkCfg = NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup;
|
|
NR_PTRS_DownlinkCfg->frequencyDensity = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->frequencyDensity));
|
|
long *dl_rbs = CALLOC(2, sizeof(long));
|
|
for (int i=0;i<2;i++) {
|
|
asn1cSeqAdd(&NR_PTRS_DownlinkCfg->frequencyDensity->list, &dl_rbs[i]);
|
|
}
|
|
NR_PTRS_DownlinkCfg->timeDensity = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->timeDensity));
|
|
long *dl_mcs = CALLOC(3, sizeof(long));
|
|
for (int i=0;i<3;i++) {
|
|
asn1cSeqAdd(&NR_PTRS_DownlinkCfg->timeDensity->list, &dl_mcs[i]);
|
|
}
|
|
NR_PTRS_DownlinkCfg->epre_Ratio = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->epre_Ratio));
|
|
NR_PTRS_DownlinkCfg->resourceElementOffset = CALLOC(1, sizeof(*NR_PTRS_DownlinkCfg->resourceElementOffset));
|
|
*NR_PTRS_DownlinkCfg->resourceElementOffset = 0;
|
|
asn1cSeqAdd(&scd->downlinkBWP_ToAddModList->list,bwp);
|
|
|
|
// Allocate uplink structures
|
|
|
|
NR_PUSCH_Config_t *pusch_Config = CALLOC(1, sizeof(*pusch_Config));
|
|
|
|
// Allocate UL DMRS and PTRS structures
|
|
pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB = CALLOC(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB));
|
|
pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->present = NR_SetupRelease_DMRS_UplinkConfig_PR_setup;
|
|
pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup = CALLOC(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup));
|
|
NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
|
|
NR_DMRS_UplinkConfig->phaseTrackingRS = CALLOC(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS));
|
|
NR_DMRS_UplinkConfig->phaseTrackingRS->present = NR_SetupRelease_PTRS_UplinkConfig_PR_setup;
|
|
NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup = CALLOC(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup));
|
|
NR_PTRS_UplinkConfig_t *NR_PTRS_UplinkConfig = NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup;
|
|
NR_PTRS_UplinkConfig->transformPrecoderDisabled = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled));
|
|
NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity));
|
|
long *n_rbs = CALLOC(2, sizeof(long));
|
|
for (int i=0;i<2;i++) {
|
|
asn1cSeqAdd(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity->list, &n_rbs[i]);
|
|
}
|
|
NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity));
|
|
long *ptrs_mcs = CALLOC(3, sizeof(long));
|
|
for (int i = 0; i < 3; i++) {
|
|
asn1cSeqAdd(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity->list, &ptrs_mcs[i]);
|
|
}
|
|
NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = CALLOC(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset));
|
|
*NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = 0;
|
|
|
|
// UL bandwidth part
|
|
NR_BWP_Uplink_t *ubwp = CALLOC(1, sizeof(*ubwp));
|
|
ubwp->bwp_Id = j+1;
|
|
ubwp->bwp_Common = CALLOC(1, sizeof(*ubwp->bwp_Common));
|
|
ubwp->bwp_Dedicated = CALLOC(1, sizeof(*ubwp->bwp_Dedicated));
|
|
|
|
ubwp->bwp_Dedicated->pusch_Config = CALLOC(1, sizeof(*ubwp->bwp_Dedicated->pusch_Config));
|
|
ubwp->bwp_Dedicated->pusch_Config->present = NR_SetupRelease_PUSCH_Config_PR_setup;
|
|
ubwp->bwp_Dedicated->pusch_Config->choice.setup = pusch_Config;
|
|
|
|
asn1cSeqAdd(&scd->uplinkConfig->uplinkBWP_ToAddModList->list,ubwp);
|
|
}
|
|
}
|
|
|
|
/* This function checks dedicated serving cell configuration and performs fixes as needed */
|
|
void fix_scd(NR_ServingCellConfig_t *scd) {
|
|
|
|
// Remove unused BWPs
|
|
int b = 0;
|
|
while (b<scd->downlinkBWP_ToAddModList->list.count) {
|
|
if (scd->downlinkBWP_ToAddModList->list.array[b]->bwp_Common->genericParameters.locationAndBandwidth == 0) {
|
|
asn_sequence_del(&scd->downlinkBWP_ToAddModList->list,b,1);
|
|
} else {
|
|
b++;
|
|
}
|
|
}
|
|
|
|
b = 0;
|
|
while (b<scd->uplinkConfig->uplinkBWP_ToAddModList->list.count) {
|
|
if (scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[b]->bwp_Common->genericParameters.locationAndBandwidth == 0) {
|
|
asn_sequence_del(&scd->uplinkConfig->uplinkBWP_ToAddModList->list,b,1);
|
|
} else {
|
|
b++;
|
|
}
|
|
}
|
|
|
|
// Check for DL PTRS parameters validity
|
|
for (int bwp_i = 0 ; bwp_i<scd->downlinkBWP_ToAddModList->list.count; bwp_i++) {
|
|
|
|
NR_DMRS_DownlinkConfig_t *dmrs_dl_config = scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
|
|
|
|
if (dmrs_dl_config->phaseTrackingRS) {
|
|
// If any of the frequencyDensity values are not set or are out of bounds, PTRS is assumed to be not present
|
|
for (int i = dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.count - 1; i >= 0; i--) {
|
|
if ((*dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] < 1)
|
|
|| (*dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] > 276)) {
|
|
LOG_I(GNB_APP, "DL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i);
|
|
free(dmrs_dl_config->phaseTrackingRS);
|
|
dmrs_dl_config->phaseTrackingRS = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dmrs_dl_config->phaseTrackingRS) {
|
|
// If any of the timeDensity values are not set or are out of bounds, PTRS is assumed to be not present
|
|
for (int i = dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.count - 1; i >= 0; i--) {
|
|
if ((*dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.array[i] < 0)
|
|
|| (*dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.array[i] > 29)) {
|
|
LOG_I(GNB_APP, "DL PTRS timeDensity %d not set. Assuming PTRS not present! \n", i);
|
|
free(dmrs_dl_config->phaseTrackingRS);
|
|
dmrs_dl_config->phaseTrackingRS = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dmrs_dl_config->phaseTrackingRS) {
|
|
if (*dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset > 2) {
|
|
LOG_I(GNB_APP, "Freeing DL PTRS resourceElementOffset \n");
|
|
free(dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset);
|
|
dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset = NULL;
|
|
}
|
|
if (*dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio > 1) {
|
|
LOG_I(GNB_APP, "Freeing DL PTRS epre_Ratio \n");
|
|
free(dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio);
|
|
dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for UL PTRS parameters validity
|
|
for (int bwp_i = 0 ; bwp_i<scd->uplinkConfig->uplinkBWP_ToAddModList->list.count; bwp_i++) {
|
|
|
|
NR_DMRS_UplinkConfig_t *dmrs_ul_config = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
|
|
|
|
if (dmrs_ul_config->phaseTrackingRS) {
|
|
// If any of the frequencyDensity values are not set or are out of bounds, PTRS is assumed to be not present
|
|
for (int i = dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.count-1; i >= 0; i--) {
|
|
if ((*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] < 1)
|
|
|| (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] > 276)) {
|
|
LOG_I(GNB_APP, "UL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i);
|
|
free(dmrs_ul_config->phaseTrackingRS);
|
|
dmrs_ul_config->phaseTrackingRS = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dmrs_ul_config->phaseTrackingRS) {
|
|
// If any of the timeDensity values are not set or are out of bounds, PTRS is assumed to be not present
|
|
for (int i = dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.count-1; i >= 0; i--) {
|
|
if ((*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] < 0)
|
|
|| (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] > 29)) {
|
|
LOG_I(GNB_APP, "UL PTRS timeDensity %d not set. Assuming PTRS not present! \n", i);
|
|
free(dmrs_ul_config->phaseTrackingRS);
|
|
dmrs_ul_config->phaseTrackingRS = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dmrs_ul_config->phaseTrackingRS) {
|
|
// Check for UL PTRS parameters validity
|
|
if (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset > 2) {
|
|
LOG_I(GNB_APP, "Freeing UL PTRS resourceElementOffset \n");
|
|
free(dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset);
|
|
dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset = NULL;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (scd->downlinkBWP_ToAddModList->list.count == 0) {
|
|
free(scd->downlinkBWP_ToAddModList);
|
|
scd->downlinkBWP_ToAddModList = NULL;
|
|
}
|
|
|
|
if (scd->uplinkConfig->uplinkBWP_ToAddModList->list.count == 0) {
|
|
free(scd->uplinkConfig->uplinkBWP_ToAddModList);
|
|
scd->uplinkConfig->uplinkBWP_ToAddModList = NULL;
|
|
}
|
|
}
|
|
|
|
static void verify_gnb_param_notset(paramdef_t *params, int paramidx, const char *paramname)
|
|
{
|
|
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
AssertFatal(!config_isparamset(params, paramidx),
|
|
"Option \"%s." GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON
|
|
".%s\" is not allowed in this config, please remove it\n",
|
|
aprefix,
|
|
paramname);
|
|
}
|
|
static void verify_section_notset(configmodule_interface_t *cfg, char *aprefix, const char *secname)
|
|
{
|
|
paramlist_def_t pl = {0};
|
|
strncpy(pl.listname, secname, sizeof(pl.listname) - 1);
|
|
config_getlist(cfg, &pl, NULL, 0, aprefix);
|
|
AssertFatal(pl.numelt == 0, "Section \"%s.%s\" not allowed in this config, please remove it\n", aprefix ? aprefix : "", secname);
|
|
}
|
|
void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type)
|
|
{
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
config_get(cfg, GNBSParams, sizeof(GNBSParams) / sizeof(paramdef_t), NULL);
|
|
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
AssertFatal(num_gnbs == 1, "need to have a " GNB_CONFIG_STRING_GNB_LIST " section, but %d found\n", num_gnbs);
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0};
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
config_getlist(cfg, &GNBParamList, GNBParams, sizeof(GNBParams) / sizeof(paramdef_t), NULL);
|
|
paramdef_t *gnbp = GNBParamList.paramarray[0];
|
|
|
|
if (NODE_IS_CU(node_type)) {
|
|
// verify that there is no SCC and radio config in the case of CU
|
|
verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".[0]", GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON);
|
|
|
|
verify_gnb_param_notset(gnbp, GNB_PDSCH_ANTENNAPORTS_N1_IDX, GNB_CONFIG_STRING_PDSCHANTENNAPORTS_N1);
|
|
verify_gnb_param_notset(gnbp, GNB_PDSCH_ANTENNAPORTS_N2_IDX, GNB_CONFIG_STRING_PDSCHANTENNAPORTS_N2);
|
|
verify_gnb_param_notset(gnbp, GNB_PDSCH_ANTENNAPORTS_XP_IDX, GNB_CONFIG_STRING_PDSCHANTENNAPORTS_XP);
|
|
verify_gnb_param_notset(gnbp, GNB_PUSCH_ANTENNAPORTS_IDX, GNB_CONFIG_STRING_PUSCHANTENNAPORTS);
|
|
verify_gnb_param_notset(gnbp, GNB_MINRXTXTIME_IDX, GNB_CONFIG_STRING_MINRXTXTIME);
|
|
verify_gnb_param_notset(gnbp, GNB_SIB1_TDA_IDX, GNB_CONFIG_STRING_SIB1TDA);
|
|
verify_gnb_param_notset(gnbp, GNB_DO_CSIRS_IDX, GNB_CONFIG_STRING_DOCSIRS);
|
|
verify_gnb_param_notset(gnbp, GNB_DO_SRS_IDX, GNB_CONFIG_STRING_DOSRS);
|
|
verify_gnb_param_notset(gnbp, GNB_FORCE256QAMOFF_IDX, GNB_CONFIG_STRING_FORCE256QAMOFF);
|
|
verify_gnb_param_notset(gnbp, GNB_MAXMIMOLAYERS_IDX, GNB_CONFIG_STRING_MAXMIMOLAYERS);
|
|
|
|
// check for some general sections
|
|
verify_section_notset(cfg, NULL, CONFIG_STRING_L1_LIST);
|
|
verify_section_notset(cfg, NULL, CONFIG_STRING_RU_LIST);
|
|
verify_section_notset(cfg, NULL, CONFIG_STRING_MACRLC_LIST);
|
|
} else if (NODE_IS_DU(node_type)) {
|
|
// verify that there is no bearer config
|
|
verify_gnb_param_notset(gnbp, GNB_ENABLE_SDAP_IDX, GNB_CONFIG_STRING_ENABLE_SDAP);
|
|
verify_gnb_param_notset(gnbp, GNB_DRBS, GNB_CONFIG_STRING_DRBS);
|
|
|
|
verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".", GNB_CONFIG_STRING_AMF_IP_ADDRESS);
|
|
verify_section_notset(cfg, NULL, CONFIG_STRING_SECURITY);
|
|
} // else nothing to be checked
|
|
|
|
/* other possible verifications: PNF, VNF, CU-CP, CU-UP, ...? */
|
|
}
|
|
|
|
void RCconfig_nr_prs(void)
|
|
{
|
|
uint16_t j = 0, k = 0;
|
|
prs_config_t *prs_config = NULL;
|
|
char str[7][100] = {0};
|
|
|
|
paramdef_t PRS_Params[] = PRS_PARAMS_DESC;
|
|
paramlist_def_t PRS_ParamList = {CONFIG_STRING_PRS_CONFIG,NULL,0};
|
|
if (RC.gNB == NULL) {
|
|
RC.gNB = (PHY_VARS_gNB **)malloc((1+NUMBER_OF_gNB_MAX)*sizeof(PHY_VARS_gNB*));
|
|
LOG_I(NR_PHY,"RC.gNB = %p\n",RC.gNB);
|
|
memset(RC.gNB,0,(1+NUMBER_OF_gNB_MAX)*sizeof(PHY_VARS_gNB*));
|
|
}
|
|
|
|
config_getlist(config_get_if(), &PRS_ParamList, PRS_Params, sizeofArray(PRS_Params), NULL);
|
|
|
|
if (PRS_ParamList.numelt > 0) {
|
|
for (j = 0; j < RC.nb_nr_L1_inst; j++) {
|
|
|
|
if (RC.gNB[j] == NULL) {
|
|
RC.gNB[j] = (PHY_VARS_gNB *)malloc(sizeof(PHY_VARS_gNB));
|
|
LOG_I(NR_PHY,"RC.gNB[%d] = %p\n",j,RC.gNB[j]);
|
|
memset(RC.gNB[j],0,sizeof(PHY_VARS_gNB));
|
|
RC.gNB[j]->Mod_id = j;
|
|
}
|
|
|
|
RC.gNB[j]->prs_vars.NumPRSResources = *(PRS_ParamList.paramarray[j][NUM_PRS_RESOURCES].uptr);
|
|
for (k = 0; k < RC.gNB[j]->prs_vars.NumPRSResources; k++)
|
|
{
|
|
prs_config = &RC.gNB[j]->prs_vars.prs_cfg[k];
|
|
prs_config->PRSResourceSetPeriod[0] = PRS_ParamList.paramarray[j][PRS_RESOURCE_SET_PERIOD_LIST].uptr[0];
|
|
prs_config->PRSResourceSetPeriod[1] = PRS_ParamList.paramarray[j][PRS_RESOURCE_SET_PERIOD_LIST].uptr[1];
|
|
// per PRS resources parameters
|
|
prs_config->SymbolStart = PRS_ParamList.paramarray[j][PRS_SYMBOL_START_LIST].uptr[k];
|
|
prs_config->NumPRSSymbols = PRS_ParamList.paramarray[j][PRS_NUM_SYMBOLS_LIST].uptr[k];
|
|
prs_config->REOffset = PRS_ParamList.paramarray[j][PRS_RE_OFFSET_LIST].uptr[k];
|
|
prs_config->PRSResourceOffset = PRS_ParamList.paramarray[j][PRS_RESOURCE_OFFSET_LIST].uptr[k];
|
|
prs_config->NPRSID = PRS_ParamList.paramarray[j][PRS_ID_LIST].uptr[k];
|
|
// Common parameters to all PRS resources
|
|
prs_config->NumRB = *(PRS_ParamList.paramarray[j][PRS_NUM_RB].uptr);
|
|
prs_config->RBOffset = *(PRS_ParamList.paramarray[j][PRS_RB_OFFSET].uptr);
|
|
prs_config->CombSize = *(PRS_ParamList.paramarray[j][PRS_COMB_SIZE].uptr);
|
|
prs_config->PRSResourceRepetition = *(PRS_ParamList.paramarray[j][PRS_RESOURCE_REPETITION].uptr);
|
|
prs_config->PRSResourceTimeGap = *(PRS_ParamList.paramarray[j][PRS_RESOURCE_TIME_GAP].uptr);
|
|
prs_config->MutingBitRepetition = *(PRS_ParamList.paramarray[j][PRS_MUTING_BIT_REPETITION].uptr);
|
|
for (int l = 0; l < PRS_ParamList.paramarray[j][PRS_MUTING_PATTERN1_LIST].numelt; l++)
|
|
{
|
|
prs_config->MutingPattern1[l] = PRS_ParamList.paramarray[j][PRS_MUTING_PATTERN1_LIST].uptr[l];
|
|
if (k == 0) // print only for 0th resource
|
|
snprintf(str[5]+strlen(str[5]),sizeof(str[5])-strlen(str[5]),"%d, ",prs_config->MutingPattern1[l]);
|
|
}
|
|
for (int l = 0; l < PRS_ParamList.paramarray[j][PRS_MUTING_PATTERN2_LIST].numelt; l++)
|
|
{
|
|
prs_config->MutingPattern2[l] = PRS_ParamList.paramarray[j][PRS_MUTING_PATTERN2_LIST].uptr[l];
|
|
if (k == 0) // print only for 0th resource
|
|
snprintf(str[6]+strlen(str[6]),sizeof(str[6])-strlen(str[6]),"%d, ",prs_config->MutingPattern2[l]);
|
|
}
|
|
|
|
// print to buffer
|
|
snprintf(str[0]+strlen(str[0]),sizeof(str[0])-strlen(str[0]),"%d, ",prs_config->SymbolStart);
|
|
snprintf(str[1]+strlen(str[1]),sizeof(str[1])-strlen(str[1]),"%d, ",prs_config->NumPRSSymbols);
|
|
snprintf(str[2]+strlen(str[2]),sizeof(str[2])-strlen(str[2]),"%d, ",prs_config->REOffset);
|
|
snprintf(str[3]+strlen(str[3]),sizeof(str[3])-strlen(str[3]),"%d, ",prs_config->PRSResourceOffset);
|
|
snprintf(str[4]+strlen(str[4]),sizeof(str[4])-strlen(str[4]),"%d, ",prs_config->NPRSID);
|
|
} // for k
|
|
|
|
prs_config = &RC.gNB[j]->prs_vars.prs_cfg[0];
|
|
LOG_I(PHY, "-----------------------------------------\n");
|
|
LOG_I(PHY, "PRS Config for gNB_id %d @ %p\n", j, prs_config);
|
|
LOG_I(PHY, "-----------------------------------------\n");
|
|
LOG_I(PHY, "NumPRSResources \t%d\n", RC.gNB[j]->prs_vars.NumPRSResources);
|
|
LOG_I(PHY, "PRSResourceSetPeriod \t[%d, %d]\n", prs_config->PRSResourceSetPeriod[0], prs_config->PRSResourceSetPeriod[1]);
|
|
LOG_I(PHY, "NumRB \t\t\t%d\n", prs_config->NumRB);
|
|
LOG_I(PHY, "RBOffset \t\t%d\n", prs_config->RBOffset);
|
|
LOG_I(PHY, "CombSize \t\t%d\n", prs_config->CombSize);
|
|
LOG_I(PHY, "PRSResourceRepetition \t%d\n", prs_config->PRSResourceRepetition);
|
|
LOG_I(PHY, "PRSResourceTimeGap \t%d\n", prs_config->PRSResourceTimeGap);
|
|
LOG_I(PHY, "MutingBitRepetition \t%d\n", prs_config->MutingBitRepetition);
|
|
LOG_I(PHY, "SymbolStart \t\t[%s\b\b]\n", str[0]);
|
|
LOG_I(PHY, "NumPRSSymbols \t\t[%s\b\b]\n", str[1]);
|
|
LOG_I(PHY, "REOffset \t\t[%s\b\b]\n", str[2]);
|
|
LOG_I(PHY, "PRSResourceOffset \t[%s\b\b]\n", str[3]);
|
|
LOG_I(PHY, "NPRS_ID \t\t[%s\b\b]\n", str[4]);
|
|
LOG_I(PHY, "MutingPattern1 \t\t[%s\b\b]\n", str[5]);
|
|
LOG_I(PHY, "MutingPattern2 \t\t[%s\b\b]\n", str[6]);
|
|
LOG_I(PHY, "-----------------------------------------\n");
|
|
} // for j
|
|
}
|
|
else
|
|
{
|
|
LOG_I(PHY,"No " CONFIG_STRING_PRS_CONFIG " configuration found..!!\n");
|
|
}
|
|
}
|
|
|
|
void RCconfig_NR_L1(void)
|
|
{
|
|
int j = 0;
|
|
if (RC.gNB == NULL) {
|
|
RC.gNB = (PHY_VARS_gNB **)malloc((1 + NUMBER_OF_gNB_MAX) * sizeof(PHY_VARS_gNB *));
|
|
LOG_I(NR_PHY, "RC.gNB = %p\n", RC.gNB);
|
|
memset(RC.gNB, 0, (1 + NUMBER_OF_gNB_MAX) * sizeof(PHY_VARS_gNB *));
|
|
|
|
if (RC.gNB[j] == NULL) {
|
|
RC.gNB[j] = calloc(1, sizeof(PHY_VARS_gNB));
|
|
}
|
|
}
|
|
if (NFAPI_MODE != NFAPI_MODE_PNF) {
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
////////// Identification parameters
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0};
|
|
|
|
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
|
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
AssertFatal(num_gnbs > 0, "Failed to parse config file no gnbs %s \n", GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
|
|
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
|
int N1 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr;
|
|
int N2 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr;
|
|
int XP = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr;
|
|
char *ulprbbl = *GNBParamList.paramarray[0][GNB_ULPRBBLACKLIST_IDX].strptr;
|
|
if (ulprbbl)
|
|
LOG_I(NR_PHY, "PRB blacklist %s\n", ulprbbl);
|
|
char *save = NULL;
|
|
char *pt = strtok_r(ulprbbl, ",", &save);
|
|
int prbbl[275];
|
|
int num_prbbl = 0;
|
|
memset(prbbl, 0, 275 * sizeof(int));
|
|
|
|
while (pt) {
|
|
const int rb = atoi(pt);
|
|
AssertFatal(rb < 275, "RB %d out of bounds (max 275)\n", rb);
|
|
prbbl[rb] = 0x3FFF; // all symbols taken
|
|
LOG_I(NR_PHY, "Blacklisting prb %d\n", atoi(pt));
|
|
pt = strtok_r(NULL, ",", &save);
|
|
num_prbbl++;
|
|
}
|
|
|
|
RC.gNB[j]->num_ulprbbl = num_prbbl;
|
|
LOG_I(NR_PHY, "Copying %d blacklisted PRB to L1 context\n", num_prbbl);
|
|
memcpy(RC.gNB[j]->ulprbbl, prbbl, 275 * sizeof(int));
|
|
|
|
RC.gNB[j]->ap_N1 = N1;
|
|
RC.gNB[j]->ap_N2 = N2;
|
|
RC.gNB[j]->ap_XP = XP;
|
|
}
|
|
|
|
paramdef_t L1_Params[] = L1PARAMS_DESC;
|
|
paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST, NULL, 0};
|
|
|
|
config_getlist(config_get_if(), &L1_ParamList, L1_Params, sizeofArray(L1_Params), NULL);
|
|
|
|
if (L1_ParamList.numelt > 0) {
|
|
for (j = 0; j < RC.nb_nr_L1_inst; j++) {
|
|
if (RC.gNB[j] == NULL) {
|
|
RC.gNB[j] = (PHY_VARS_gNB *)malloc(sizeof(PHY_VARS_gNB));
|
|
LOG_I(NR_PHY, "RC.gNB[%d] = %p\n", j, RC.gNB[j]);
|
|
memset(RC.gNB[j], 0, sizeof(PHY_VARS_gNB));
|
|
RC.gNB[j]->Mod_id = j;
|
|
}
|
|
AssertFatal(*L1_ParamList.paramarray[j][L1_THREAD_POOL_SIZE].uptr == 2022, "thread_pool_size removed, please use --thread-pool\n");
|
|
RC.gNB[j]->ofdm_offset_divisor = *(L1_ParamList.paramarray[j][L1_OFDM_OFFSET_DIVISOR].uptr);
|
|
RC.gNB[j]->pucch0_thres = *(L1_ParamList.paramarray[j][L1_PUCCH0_DTX_THRESHOLD].uptr);
|
|
RC.gNB[j]->prach_thres = *(L1_ParamList.paramarray[j][L1_PRACH_DTX_THRESHOLD].uptr);
|
|
RC.gNB[j]->pusch_thres = *(L1_ParamList.paramarray[j][L1_PUSCH_DTX_THRESHOLD].uptr);
|
|
RC.gNB[j]->srs_thres = *(L1_ParamList.paramarray[j][L1_SRS_DTX_THRESHOLD].uptr);
|
|
RC.gNB[j]->max_ldpc_iterations = *(L1_ParamList.paramarray[j][L1_MAX_LDPC_ITERATIONS].uptr);
|
|
RC.gNB[j]->L1_rx_thread_core = *(L1_ParamList.paramarray[j][L1_RX_THREAD_CORE].iptr);
|
|
RC.gNB[j]->L1_tx_thread_core = *(L1_ParamList.paramarray[j][L1_TX_THREAD_CORE].iptr);
|
|
LOG_I(PHY,"L1_RX_THREAD_CORE %d (%d)\n",*(L1_ParamList.paramarray[j][L1_RX_THREAD_CORE].iptr),L1_RX_THREAD_CORE);
|
|
RC.gNB[j]->TX_AMP = (int16_t)(32767.0 / pow(10.0, .05 * (double)(*L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr)));
|
|
RC.gNB[j]->phase_comp = *L1_ParamList.paramarray[j][L1_PHASE_COMP].uptr;
|
|
LOG_I(PHY, "TX_AMP = %d (-%d dBFS)\n", RC.gNB[j]->TX_AMP, *L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr);
|
|
AssertFatal(RC.gNB[j]->TX_AMP > 300, "TX_AMP is too small, must be larger than 300 (is %d)\n", RC.gNB[j]->TX_AMP);
|
|
if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_mac") == 0) {
|
|
// sf_ahead = 2; // Need 4 subframe gap between RX and TX
|
|
} else if (strcmp(*(L1_ParamList.paramarray[j][L1_TRANSPORT_N_PREFERENCE_IDX].strptr), "nfapi") == 0) {
|
|
RC.gNB[j]->eth_params_n.my_addr = strdup(*(L1_ParamList.paramarray[j][L1_LOCAL_N_ADDRESS_IDX].strptr));
|
|
RC.gNB[j]->eth_params_n.remote_addr = strdup(*(L1_ParamList.paramarray[j][L1_REMOTE_N_ADDRESS_IDX].strptr));
|
|
RC.gNB[j]->eth_params_n.my_portc = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTC_IDX].iptr);
|
|
RC.gNB[j]->eth_params_n.remote_portc = *(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTC_IDX].iptr);
|
|
RC.gNB[j]->eth_params_n.my_portd = *(L1_ParamList.paramarray[j][L1_LOCAL_N_PORTD_IDX].iptr);
|
|
RC.gNB[j]->eth_params_n.remote_portd = *(L1_ParamList.paramarray[j][L1_REMOTE_N_PORTD_IDX].iptr);
|
|
RC.gNB[j]->eth_params_n.transp_preference = ETH_UDP_MODE;
|
|
|
|
// sf_ahead = 2; // Cannot cope with 4 subframes betweem RX and TX - set it to 2
|
|
|
|
RC.nb_nr_macrlc_inst = 1; // This is used by mac_top_init_gNB()
|
|
|
|
// This is used by init_gNB_afterRU()
|
|
RC.nb_nr_CC = (int *)malloc((1 + RC.nb_nr_inst) * sizeof(int));
|
|
RC.nb_nr_CC[0] = 1;
|
|
|
|
LOG_I(PHY, "%s() NFAPI PNF mode - RC.nb_nr_inst=1 this is because phy_init_RU() uses that to index and not RC.num_gNB - why the 2 similar variables?\n", __FUNCTION__);
|
|
LOG_I(PHY, "%s() NFAPI PNF mode - RC.nb_nr_CC[0]=%d for init_gNB_afterRU()\n", __FUNCTION__, RC.nb_nr_CC[0]);
|
|
LOG_I(PHY, "%s() NFAPI PNF mode - RC.nb_nr_macrlc_inst:%d because used by mac_top_init_gNB()\n", __FUNCTION__, RC.nb_nr_macrlc_inst);
|
|
|
|
configure_nr_nfapi_pnf(RC.gNB[j]->eth_params_n.remote_addr,
|
|
RC.gNB[j]->eth_params_n.remote_portc,
|
|
RC.gNB[j]->eth_params_n.my_addr,
|
|
RC.gNB[j]->eth_params_n.my_portd,
|
|
RC.gNB[j]->eth_params_n.remote_portd);
|
|
} else { // other midhaul
|
|
}
|
|
} // for (j = 0; j < RC.nb_nr_L1_inst; j++)
|
|
printf("Initializing northbound interface for L1\n");
|
|
l1_north_init_gNB();
|
|
} else {
|
|
LOG_I(PHY, "No " CONFIG_STRING_L1_LIST " configuration found");
|
|
|
|
// need to create some structures for VNF
|
|
|
|
j = 0;
|
|
|
|
if (RC.gNB[j] == NULL) {
|
|
RC.gNB[j] = (PHY_VARS_gNB *)malloc(sizeof(PHY_VARS_gNB));
|
|
memset((void *)RC.gNB[j], 0, sizeof(PHY_VARS_gNB));
|
|
LOG_I(PHY, "RC.gNB[%d] = %p\n", j, RC.gNB[j]);
|
|
RC.gNB[j]->Mod_id = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cfg, int minRXTXTIME)
|
|
{
|
|
NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(*scc));
|
|
uint64_t ssb_bitmap=0xff;
|
|
prepare_scc(scc);
|
|
paramdef_t SCCsParams[] = SCCPARAMS_DESC(scc);
|
|
paramlist_def_t SCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0};
|
|
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
config_getlist(cfg, &SCCsParamList, NULL, 0, aprefix);
|
|
if (SCCsParamList.numelt > 0) {
|
|
sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0);
|
|
config_get(cfg, SCCsParams, sizeofArray(SCCsParams), aprefix);
|
|
struct NR_FrequencyInfoDL *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
|
|
LOG_I(RRC,
|
|
"Read in ServingCellConfigCommon (PhysCellId %d, ABSFREQSSB %d, DLBand %d, ABSFREQPOINTA %d, DLBW "
|
|
"%d,RACH_TargetReceivedPower %d\n",
|
|
(int)*scc->physCellId,
|
|
(int)*frequencyInfoDL->absoluteFrequencySSB,
|
|
(int)*frequencyInfoDL->frequencyBandList.list.array[0],
|
|
(int)frequencyInfoDL->absoluteFrequencyPointA,
|
|
(int)frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth,
|
|
(int)scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric
|
|
.preambleReceivedTargetPower);
|
|
// SSB of the PCell is always on the sync raster
|
|
uint64_t ssb_freq = from_nrarfcn(*frequencyInfoDL->frequencyBandList.list.array[0],
|
|
*scc->ssbSubcarrierSpacing,
|
|
*frequencyInfoDL->absoluteFrequencySSB);
|
|
LOG_I(RRC, "absoluteFrequencySSB %ld corresponds to %lu Hz\n", *frequencyInfoDL->absoluteFrequencySSB, ssb_freq);
|
|
if (get_softmodem_params()->sa)
|
|
check_ssb_raster(ssb_freq, *frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
|
|
fix_scc(scc, ssb_bitmap);
|
|
}
|
|
nr_rrc_config_ul_tda(scc, minRXTXTIME);
|
|
|
|
// the gNB uses the servingCellConfigCommon everywhere, even when it should use the servingCellConfigCommonSIB.
|
|
// previously (before this commit), the following fields were indirectly populated through get_SIB1_NR().
|
|
// since this might lead to memory problems (e.g., double frees), it has been moved here.
|
|
// note that the "right solution" would be to not populate the servingCellConfigCommon here, and use
|
|
// an "abstraction struct" that contains the corresponding values, from which SCC/SIB1/... is generated.
|
|
NR_PDCCH_ConfigCommon_t *pcc = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup;
|
|
AssertFatal(pcc != NULL && pcc->commonSearchSpaceList == NULL, "memory leak\n");
|
|
pcc->commonSearchSpaceList = calloc_or_fail(1, sizeof(*pcc->commonSearchSpaceList));
|
|
|
|
NR_SearchSpace_t *ss1 = rrc_searchspace_config(true, 1, 0);
|
|
asn1cSeqAdd(&pcc->commonSearchSpaceList->list, ss1);
|
|
NR_SearchSpace_t *ss2 = rrc_searchspace_config(true, 2, 0);
|
|
asn1cSeqAdd(&pcc->commonSearchSpaceList->list, ss2);
|
|
NR_SearchSpace_t *ss3 = rrc_searchspace_config(true, 3, 0);
|
|
asn1cSeqAdd(&pcc->commonSearchSpaceList->list, ss3);
|
|
|
|
asn1cCallocOne(pcc->searchSpaceSIB1, 0);
|
|
asn1cCallocOne(pcc->ra_SearchSpace, 1);
|
|
asn1cCallocOne(pcc->pagingSearchSpace, 2);
|
|
asn1cCallocOne(pcc->searchSpaceOtherSystemInformation, 3);
|
|
|
|
return scc;
|
|
}
|
|
|
|
static NR_ServingCellConfig_t *get_scd_config(configmodule_interface_t *cfg)
|
|
{
|
|
NR_ServingCellConfig_t *scd = calloc(1, sizeof(*scd));
|
|
prepare_scd(scd);
|
|
paramdef_t SCDsParams[] = SCDPARAMS_DESC(scd);
|
|
paramlist_def_t SCDsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, NULL, 0};
|
|
|
|
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
|
snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
config_getlist(cfg, &SCDsParamList, NULL, 0, aprefix);
|
|
if (SCDsParamList.numelt > 0) {
|
|
sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, 0);
|
|
config_get(cfg, SCDsParams, sizeof(SCDsParams) / sizeof(paramdef_t), aprefix);
|
|
const NR_BWP_UplinkDedicated_t *bwp_Dedicated = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated;
|
|
const NR_PTRS_UplinkConfig_t *setup =
|
|
bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup;
|
|
LOG_I(RRC,
|
|
"Read in ServingCellConfigDedicated UL (FreqDensity_0 %ld, FreqDensity_1 %ld, TimeDensity_0 %ld, TimeDensity_1 %ld, "
|
|
"TimeDensity_2 %ld, RE offset %ld, First_active_BWP_ID %ld SCS %ld, LocationandBW %ld\n",
|
|
*setup->transformPrecoderDisabled->frequencyDensity->list.array[0],
|
|
*setup->transformPrecoderDisabled->frequencyDensity->list.array[1],
|
|
*setup->transformPrecoderDisabled->timeDensity->list.array[0],
|
|
*setup->transformPrecoderDisabled->timeDensity->list.array[1],
|
|
*setup->transformPrecoderDisabled->timeDensity->list.array[2],
|
|
*setup->transformPrecoderDisabled->resourceElementOffset,
|
|
*scd->firstActiveDownlinkBWP_Id,
|
|
scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.subcarrierSpacing,
|
|
scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.locationAndBandwidth);
|
|
}
|
|
fix_scd(scd);
|
|
|
|
return scd;
|
|
}
|
|
|
|
static int read_du_cell_info(configmodule_interface_t *cfg,
|
|
bool separate_du,
|
|
uint32_t *gnb_id,
|
|
uint64_t *gnb_du_id,
|
|
char **name,
|
|
f1ap_served_cell_info_t *info,
|
|
int max_cell_info)
|
|
{
|
|
AssertFatal(max_cell_info == 1, "only one cell supported\n");
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
config_get(cfg, GNBSParams, sizeof(GNBSParams) / sizeof(paramdef_t), NULL);
|
|
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
AssertFatal(num_gnbs == 1, "cannot configure DU: required config section \"gNBs\" missing\n");
|
|
|
|
// Output a list of all eNBs.
|
|
config_getlist(cfg, &GNBParamList, GNBParams, sizeof(GNBParams) / sizeof(paramdef_t), NULL);
|
|
|
|
// read the gNB-ID. The DU itself only needs the gNB-DU ID, but some (e.g.,
|
|
// E2 agent) need the gNB-ID as well if it is running in a separate process
|
|
AssertFatal(config_isparamset(GNBParamList.paramarray[0], GNB_GNB_ID_IDX), "%s is not defined in configuration file\n", GNB_CONFIG_STRING_GNB_ID);
|
|
*gnb_id = *GNBParamList.paramarray[0][GNB_GNB_ID_IDX].uptr;
|
|
|
|
AssertFatal(strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[0], *GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr) == 0,
|
|
"no active gNB found/mismatch of gNBs: %s vs %s\n",
|
|
GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[0],
|
|
*GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr);
|
|
|
|
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
|
sprintf(aprefix, "%s.[0]", GNB_CONFIG_STRING_GNB_LIST);
|
|
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_PLMNParams[] = PLMNPARAMS_CHECK;
|
|
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
|
|
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
|
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
|
config_getlist(cfg, &PLMNParamList, PLMNParams, sizeof(PLMNParams) / sizeof(paramdef_t), aprefix);
|
|
AssertFatal(PLMNParamList.numelt > 0, "need to have a PLMN in PLMN section\n");
|
|
AssertFatal(PLMNParamList.numelt == 1, "cannot have more than one PLMN\n");
|
|
|
|
// if fronthaul is F1, require gNB_DU_ID, else use gNB_ID
|
|
if (separate_du) {
|
|
AssertFatal(config_isparamset(GNBParamList.paramarray[0], GNB_GNB_DU_ID_IDX), "%s is not defined in configuration file\n", GNB_CONFIG_STRING_GNB_DU_ID);
|
|
*gnb_du_id = *GNBParamList.paramarray[0][GNB_GNB_DU_ID_IDX].u64ptr;
|
|
} else {
|
|
AssertFatal(!config_isparamset(GNBParamList.paramarray[0], GNB_GNB_DU_ID_IDX),
|
|
"%s should not be defined in configuration file for monolithic gNB\n",
|
|
GNB_CONFIG_STRING_GNB_DU_ID);
|
|
*gnb_du_id = *gnb_id; // the gNB-DU ID is equal to the gNB ID, since the config has no gNB-DU ID
|
|
}
|
|
|
|
*name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr));
|
|
info->tac = malloc(sizeof(*info->tac));
|
|
AssertFatal(info->tac != NULL, "out of memory\n");
|
|
*info->tac = *GNBParamList.paramarray[0][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
|
info->plmn.mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
|
info->plmn.mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
|
info->plmn.mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
|
AssertFatal((info->plmn.mnc_digit_length == 2) || (info->plmn.mnc_digit_length == 3),
|
|
"BAD MNC DIGIT LENGTH %d",
|
|
info->plmn.mnc_digit_length);
|
|
info->nr_cellid = (uint64_t) * (GNBParamList.paramarray[0][GNB_NRCELLID_IDX].u64ptr);
|
|
|
|
paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC;
|
|
paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0};
|
|
checkedparam_t config_check_SNSSAIParams[] = SNSSAIPARAMS_CHECK;
|
|
for (int J = 0; J < sizeofArray(SNSSAIParams); ++J)
|
|
SNSSAIParams[J].chkPptr = &(config_check_SNSSAIParams[J]);
|
|
char snssaistr[MAX_OPTNAME_SIZE * 2 + 8];
|
|
sprintf(snssaistr, "%s.[0].%s.[0]", GNB_CONFIG_STRING_GNB_LIST, GNB_CONFIG_STRING_PLMN_LIST);
|
|
config_getlist(config_get_if(), &SNSSAIParamList, SNSSAIParams, sizeofArray(SNSSAIParams), snssaistr);
|
|
info->num_ssi = SNSSAIParamList.numelt;
|
|
for (int s = 0; s < info->num_ssi; ++s) {
|
|
info->nssai[s].sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr;
|
|
info->nssai[s].sd = *SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr;
|
|
AssertFatal(info->nssai[s].sd <= 0xffffff, "SD cannot be bigger than 0xffffff, but is %d\n", info->nssai[s].sd);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc)
|
|
{
|
|
const NR_FrequencyInfoDL_t *dl = scc->downlinkConfigCommon->frequencyInfoDL;
|
|
f1ap_tdd_info_t tdd = {
|
|
.freqinfo.arfcn = dl->absoluteFrequencyPointA,
|
|
.freqinfo.band = *dl->frequencyBandList.list.array[0],
|
|
.tbw.scs = dl->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
|
|
.tbw.nrb = dl->scs_SpecificCarrierList.list.array[0]->carrierBandwidth,
|
|
};
|
|
return tdd;
|
|
}
|
|
|
|
static f1ap_fdd_info_t read_fdd_config(const NR_ServingCellConfigCommon_t *scc)
|
|
{
|
|
const NR_FrequencyInfoDL_t *dl = scc->downlinkConfigCommon->frequencyInfoDL;
|
|
const NR_FrequencyInfoUL_t *ul = scc->uplinkConfigCommon->frequencyInfoUL;
|
|
f1ap_fdd_info_t fdd = {
|
|
.dl_freqinfo.arfcn = dl->absoluteFrequencyPointA,
|
|
.ul_freqinfo.arfcn = *ul->absoluteFrequencyPointA,
|
|
.dl_tbw.scs = dl->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
|
|
.ul_tbw.scs = ul->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
|
|
.dl_tbw.nrb = dl->scs_SpecificCarrierList.list.array[0]->carrierBandwidth,
|
|
.ul_tbw.nrb = ul->scs_SpecificCarrierList.list.array[0]->carrierBandwidth,
|
|
.dl_freqinfo.band = *dl->frequencyBandList.list.array[0],
|
|
.ul_freqinfo.band = *ul->frequencyBandList->list.array[0],
|
|
};
|
|
return fdd;
|
|
}
|
|
|
|
static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
|
|
const char *name,
|
|
const f1ap_served_cell_info_t *info,
|
|
const NR_ServingCellConfigCommon_t *scc,
|
|
NR_BCCH_BCH_Message_t *mib,
|
|
const NR_BCCH_DL_SCH_Message_t *sib1)
|
|
{
|
|
f1ap_setup_req_t *req = calloc(1, sizeof(*req));
|
|
AssertFatal(req != NULL, "out of memory\n");
|
|
req->gNB_DU_id = id;
|
|
req->gNB_DU_name = strdup(name);
|
|
req->num_cells_available = 1;
|
|
req->cell[0].info = *info;
|
|
LOG_I(GNB_APP,
|
|
"F1AP: gNB idx %d gNB_DU_id %ld, gNB_DU_name %s, TAC %d MCC/MNC/length %d/%d/%d cellID %ld\n",
|
|
0,
|
|
req->gNB_DU_id,
|
|
req->gNB_DU_name,
|
|
*req->cell[0].info.tac,
|
|
req->cell[0].info.plmn.mcc,
|
|
req->cell[0].info.plmn.mnc,
|
|
req->cell[0].info.plmn.mnc_digit_length,
|
|
req->cell[0].info.nr_cellid);
|
|
|
|
req->cell[0].info.nr_pci = *scc->physCellId;
|
|
if (scc->tdd_UL_DL_ConfigurationCommon) {
|
|
LOG_I(GNB_APP, "ngran_DU: Configuring Cell %d for TDD\n", 0);
|
|
req->cell[0].info.mode = F1AP_MODE_TDD;
|
|
req->cell[0].info.tdd = read_tdd_config(scc);
|
|
} else {
|
|
LOG_I(GNB_APP, "ngran_DU: Configuring Cell %d for FDD\n", 0);
|
|
req->cell[0].info.mode = F1AP_MODE_FDD;
|
|
req->cell[0].info.fdd = read_fdd_config(scc);
|
|
}
|
|
|
|
NR_MeasurementTimingConfiguration_t *mtc = get_new_MeasurementTimingConfiguration(scc);
|
|
uint8_t buf[1024];
|
|
int len = encode_MeasurementTimingConfiguration(mtc, buf, sizeof(buf));
|
|
DevAssert(len <= sizeof(buf));
|
|
free_MeasurementTimingConfiguration(mtc);
|
|
uint8_t *mtc_buf = calloc(len, sizeof(*mtc_buf));
|
|
AssertFatal(mtc_buf != NULL, "out of memory\n");
|
|
memcpy(mtc_buf, buf, len);
|
|
req->cell[0].info.measurement_timing_config = mtc_buf;
|
|
req->cell[0].info.measurement_timing_config_len = len;
|
|
|
|
if (get_softmodem_params()->sa) {
|
|
// in NSA we don't transmit SIB1, so cannot fill DU system information
|
|
// so cannot send MIB either
|
|
|
|
int buf_len = 3; // this is what we assume in monolithic
|
|
req->cell[0].sys_info = calloc(1, sizeof(*req->cell[0].sys_info));
|
|
AssertFatal(req->cell[0].sys_info != NULL, "out of memory\n");
|
|
f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info;
|
|
sys_info->mib = calloc(buf_len, sizeof(*sys_info->mib));
|
|
DevAssert(sys_info->mib != NULL);
|
|
DevAssert(mib != NULL);
|
|
// encode only the mib message itself
|
|
sys_info->mib_length = encode_MIB_NR_setup(mib->message.choice.mib, 0, sys_info->mib, buf_len);
|
|
DevAssert(sys_info->mib_length == buf_len);
|
|
|
|
DevAssert(sib1 != NULL);
|
|
NR_SIB1_t *bcch_SIB1 = sib1->message.choice.c1->choice.systemInformationBlockType1;
|
|
sys_info->sib1 = calloc(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1));
|
|
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, NULL, (void *)bcch_SIB1, sys_info->sib1, NR_MAX_SIB_LENGTH / 8);
|
|
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
|
sys_info->sib1_length = (enc_rval.encoded + 7) / 8;
|
|
}
|
|
|
|
int num = read_version(TO_STRING(NR_RRC_VERSION), &req->rrc_ver[0], &req->rrc_ver[1], &req->rrc_ver[2]);
|
|
AssertFatal(num == 3, "could not read RRC version string %s\n", TO_STRING(NR_RRC_VERSION));
|
|
|
|
return req;
|
|
}
|
|
|
|
void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
|
|
{
|
|
int j = 0;
|
|
uint16_t prbbl[275] = {0};
|
|
int num_prbbl = 0;
|
|
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0};
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
config_get(cfg, GNBSParams, sizeofArray(GNBSParams), NULL);
|
|
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
AssertFatal(num_gnbs == 1,
|
|
"Failed to parse config file: number of gnbs for gNB %s is %d != 1\n",
|
|
GNB_CONFIG_STRING_ACTIVE_GNBS,
|
|
num_gnbs);
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
config_getlist(cfg, &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
|
|
|
if (NFAPI_MODE != NFAPI_MODE_PNF) {
|
|
////////// Identification parameters
|
|
|
|
char *ulprbbl = *GNBParamList.paramarray[0][GNB_ULPRBBLACKLIST_IDX].strptr;
|
|
char *save = NULL;
|
|
char *pt = strtok_r(ulprbbl, ",", &save);
|
|
memset(prbbl, 0, sizeof(prbbl));
|
|
while (pt) {
|
|
const int prb = atoi(pt);
|
|
AssertFatal(prb < 275, "RB %d out of bounds (max 275)\n", prb);
|
|
prbbl[prb] = 0x3FFF; // all symbols taken
|
|
pt = strtok_r(NULL, ",", &save);
|
|
num_prbbl++;
|
|
}
|
|
}
|
|
paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC;
|
|
paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST, NULL, 0};
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_MacRLCParams[] = MACRLCPARAMS_CHECK;
|
|
for (int i = 0; i < sizeofArray(MacRLC_Params); ++i)
|
|
MacRLC_Params[i].chkPptr = &(config_check_MacRLCParams[i]);
|
|
config_getlist(config_get_if(), &MacRLC_ParamList, MacRLC_Params, sizeofArray(MacRLC_Params), NULL);
|
|
|
|
nr_mac_config_t config = {0};
|
|
config.pdsch_AntennaPorts.N1 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr;
|
|
config.pdsch_AntennaPorts.N2 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr;
|
|
config.pdsch_AntennaPorts.XP = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr;
|
|
config.pusch_AntennaPorts = *GNBParamList.paramarray[0][GNB_PUSCH_ANTENNAPORTS_IDX].iptr;
|
|
LOG_I(GNB_APP,
|
|
"pdsch_AntennaPorts N1 %d N2 %d XP %d pusch_AntennaPorts %d\n",
|
|
config.pdsch_AntennaPorts.N1,
|
|
config.pdsch_AntennaPorts.N2,
|
|
config.pdsch_AntennaPorts.XP,
|
|
config.pusch_AntennaPorts);
|
|
|
|
config.minRXTXTIME = *GNBParamList.paramarray[0][GNB_MINRXTXTIME_IDX].iptr;
|
|
LOG_I(GNB_APP, "minTXRXTIME %d\n", config.minRXTXTIME);
|
|
config.sib1_tda = *GNBParamList.paramarray[0][GNB_SIB1_TDA_IDX].iptr;
|
|
LOG_I(GNB_APP, "SIB1 TDA %d\n", config.sib1_tda);
|
|
config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr;
|
|
config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr;
|
|
config.force_256qam_off = *GNBParamList.paramarray[0][GNB_FORCE256QAMOFF_IDX].iptr;
|
|
config.force_UL256qam_off = *GNBParamList.paramarray[0][GNB_FORCEUL256QAMOFF_IDX].iptr;
|
|
config.use_deltaMCS = *GNBParamList.paramarray[0][GNB_USE_DELTA_MCS_IDX].iptr != 0;
|
|
config.maxMIMO_layers = *GNBParamList.paramarray[0][GNB_MAXMIMOLAYERS_IDX].iptr;
|
|
LOG_I(GNB_APP,
|
|
"CSI-RS %d, SRS %d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d\n",
|
|
config.do_CSIRS,
|
|
config.do_SRS,
|
|
config.force_256qam_off ? "force off" : "may be on",
|
|
config.use_deltaMCS ? "on" : "off",
|
|
config.maxMIMO_layers);
|
|
int tot_ant = config.pdsch_AntennaPorts.N1 * config.pdsch_AntennaPorts.N2 * config.pdsch_AntennaPorts.XP;
|
|
AssertFatal(config.maxMIMO_layers != 0 && config.maxMIMO_layers <= tot_ant, "Invalid maxMIMO_layers %d\n", config.maxMIMO_layers);
|
|
|
|
paramdef_t Timers_Params[] = GNB_TIMERS_PARAMS_DESC;
|
|
char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
|
|
sprintf(aprefix, "%s.[0].%s", GNB_CONFIG_STRING_GNB_LIST, GNB_CONFIG_STRING_TIMERS_CONFIG);
|
|
config_get(config_get_if(), Timers_Params, sizeofArray(Timers_Params), aprefix);
|
|
|
|
config.timer_config.sr_ProhibitTimer = *Timers_Params[GNB_TIMERS_SR_PROHIBIT_TIMER_IDX].iptr;
|
|
config.timer_config.sr_TransMax = *Timers_Params[GNB_TIMERS_SR_TRANS_MAX_IDX].iptr;
|
|
config.timer_config.sr_ProhibitTimer_v1700 = *Timers_Params[GNB_TIMERS_SR_PROHIBIT_TIMER_V1700_IDX].iptr;
|
|
config.timer_config.t300 = *Timers_Params[GNB_TIMERS_T300_IDX].iptr;
|
|
config.timer_config.t301 = *Timers_Params[GNB_TIMERS_T301_IDX].iptr;
|
|
config.timer_config.t310 = *Timers_Params[GNB_TIMERS_T310_IDX].iptr;
|
|
config.timer_config.n310 = *Timers_Params[GNB_TIMERS_N310_IDX].iptr;
|
|
config.timer_config.t311 = *Timers_Params[GNB_TIMERS_T311_IDX].iptr;
|
|
config.timer_config.n311 = *Timers_Params[GNB_TIMERS_N311_IDX].iptr;
|
|
config.timer_config.t319 = *Timers_Params[GNB_TIMERS_T319_IDX].iptr;
|
|
LOG_I(GNB_APP,
|
|
"sr_ProhibitTimer %d, sr_TransMax %d, sr_ProhibitTimer_v1700 %d, "
|
|
"t300 %d, t301 %d, t310 %d, n310 %d, t311 %d, n311 %d, t319 %d\n",
|
|
config.timer_config.sr_ProhibitTimer,
|
|
config.timer_config.sr_TransMax,
|
|
config.timer_config.sr_ProhibitTimer_v1700,
|
|
config.timer_config.t300,
|
|
config.timer_config.t301,
|
|
config.timer_config.t310,
|
|
config.timer_config.n310,
|
|
config.timer_config.t311,
|
|
config.timer_config.n311,
|
|
config.timer_config.t319);
|
|
|
|
NR_ServingCellConfigCommon_t *scc = get_scc_config(cfg, config.minRXTXTIME);
|
|
//xer_fprint(stdout, &asn_DEF_NR_ServingCellConfigCommon, scc);
|
|
NR_ServingCellConfig_t *scd = get_scd_config(cfg);
|
|
|
|
if (MacRLC_ParamList.numelt > 0) {
|
|
RC.nb_nr_macrlc_inst = MacRLC_ParamList.numelt;
|
|
ngran_node_t node_type = get_node_type();
|
|
mac_top_init_gNB(node_type, scc, scd, &config);
|
|
RC.nb_nr_mac_CC = (int *)malloc(RC.nb_nr_macrlc_inst * sizeof(int));
|
|
|
|
for (j = 0; j < RC.nb_nr_macrlc_inst; j++) {
|
|
RC.nb_nr_mac_CC[j] = *(MacRLC_ParamList.paramarray[j][MACRLC_CC_IDX].iptr);
|
|
RC.nrmac[j]->pusch_target_snrx10 = *(MacRLC_ParamList.paramarray[j][MACRLC_PUSCHTARGETSNRX10_IDX].iptr);
|
|
RC.nrmac[j]->pucch_target_snrx10 = *(MacRLC_ParamList.paramarray[j][MACRLC_PUCCHTARGETSNRX10_IDX].iptr);
|
|
RC.nrmac[j]->ul_prbblack_SNR_threshold = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_PRBBLACK_SNR_THRESHOLD_IDX].iptr);
|
|
RC.nrmac[j]->pucch_failure_thres = *(MacRLC_ParamList.paramarray[j][MACRLC_PUCCHFAILURETHRES_IDX].iptr);
|
|
RC.nrmac[j]->pusch_failure_thres = *(MacRLC_ParamList.paramarray[j][MACRLC_PUSCHFAILURETHRES_IDX].iptr);
|
|
|
|
LOG_I(NR_MAC,
|
|
"PUSCH Target %d, PUCCH Target %d, PUCCH Failure %d, PUSCH Failure %d\n",
|
|
RC.nrmac[j]->pusch_target_snrx10,
|
|
RC.nrmac[j]->pucch_target_snrx10,
|
|
RC.nrmac[j]->pucch_failure_thres,
|
|
RC.nrmac[j]->pusch_failure_thres);
|
|
if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "local_RRC") == 0) {
|
|
// check number of instances is same as RRC/PDCP
|
|
|
|
} else if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "f1") == 0
|
|
|| strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "cudu") == 0) {
|
|
printf("Configuring F1 interfaces for MACRLC\n");
|
|
char **f1caddr = MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_ADDRESS_IDX].strptr;
|
|
RC.nrmac[j]->eth_params_n.my_addr = strdup(*f1caddr);
|
|
char **f1uaddr = MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_ADDRESS_F1U_IDX].strptr;
|
|
RC.nrmac[j]->f1u_addr = f1uaddr != NULL ? strdup(*f1uaddr) : strdup(*f1caddr);
|
|
RC.nrmac[j]->eth_params_n.remote_addr = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_ADDRESS_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_n.my_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.remote_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.my_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTD_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.remote_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTD_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_n.transp_preference = ETH_UDP_MODE;
|
|
} else { // other midhaul
|
|
AssertFatal(1 == 0, "MACRLC %d: %s unknown northbound midhaul\n", j, *(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr));
|
|
}
|
|
|
|
if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_L1") == 0) {
|
|
} else if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "nfapi") == 0) {
|
|
RC.nrmac[j]->eth_params_s.my_addr = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_ADDRESS_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_s.remote_addr = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_ADDRESS_IDX].strptr));
|
|
RC.nrmac[j]->eth_params_s.my_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_s.remote_portc = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTC_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_s.my_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_PORTD_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_s.remote_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTD_IDX].iptr);
|
|
RC.nrmac[j]->eth_params_s.transp_preference = ETH_UDP_MODE;
|
|
|
|
printf("**************** vnf_port:%d\n", RC.nrmac[j]->eth_params_s.my_portc);
|
|
configure_nr_nfapi_vnf(
|
|
RC.nrmac[j]->eth_params_s.my_addr, RC.nrmac[j]->eth_params_s.my_portc, RC.nrmac[j]->eth_params_s.remote_addr, RC.nrmac[j]->eth_params_s.remote_portd, RC.nrmac[j]->eth_params_s.my_portd);
|
|
printf("**************** RETURNED FROM configure_nfapi_vnf() vnf_port:%d\n", RC.nrmac[j]->eth_params_s.my_portc);
|
|
} else if(strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "aerial") == 0){
|
|
#ifdef ENABLE_AERIAL
|
|
printf("Configuring VNF for Aerial connection\n");
|
|
aerial_configure_nr_fapi_vnf();
|
|
#endif
|
|
} else { // other midhaul
|
|
AssertFatal(1 == 0, "MACRLC %d: %s unknown southbound midhaul\n", j, *(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr));
|
|
}
|
|
RC.nrmac[j]->ulsch_max_frame_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_FRAME_INACTIVITY].uptr);
|
|
NR_bler_options_t *dl_bler_options = &RC.nrmac[j]->dl_bler;
|
|
dl_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_UPPER_IDX].dblptr);
|
|
dl_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_LOWER_IDX].dblptr);
|
|
dl_bler_options->max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_MAX_MCS_IDX].u8ptr);
|
|
dl_bler_options->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_HARQ_ROUND_MAX_IDX].u8ptr);
|
|
NR_bler_options_t *ul_bler_options = &RC.nrmac[j]->ul_bler;
|
|
ul_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_BLER_TARGET_UPPER_IDX].dblptr);
|
|
ul_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_BLER_TARGET_LOWER_IDX].dblptr);
|
|
ul_bler_options->max_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_MAX_MCS_IDX].u8ptr);
|
|
ul_bler_options->harq_round_max = *(MacRLC_ParamList.paramarray[j][MACRLC_UL_HARQ_ROUND_MAX_IDX].u8ptr);
|
|
RC.nrmac[j]->min_grant_prb = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_PRB_IDX].u8ptr);
|
|
RC.nrmac[j]->min_grant_mcs = *(MacRLC_ParamList.paramarray[j][MACRLC_MIN_GRANT_MCS_IDX].u8ptr);
|
|
RC.nrmac[j]->identity_pm = *(MacRLC_ParamList.paramarray[j][MACRLC_IDENTITY_PM_IDX].u8ptr);
|
|
RC.nrmac[j]->num_ulprbbl = num_prbbl;
|
|
memcpy(RC.nrmac[j]->ulprbbl, prbbl, 275 * sizeof(prbbl[0]));
|
|
} // for (j=0;j<RC.nb_nr_macrlc_inst;j++)
|
|
|
|
uint64_t gnb_du_id = 0;
|
|
uint32_t gnb_id = 0;
|
|
char *name = NULL;
|
|
f1ap_served_cell_info_t info;
|
|
read_du_cell_info(cfg, NODE_IS_DU(node_type), &gnb_id, &gnb_du_id, &name, &info, 1);
|
|
|
|
if (get_softmodem_params()->sa)
|
|
nr_mac_configure_sib1(RC.nrmac[0], &info.plmn, info.nr_cellid, *info.tac);
|
|
|
|
// read F1 Setup information from config and generated MIB/SIB1
|
|
// and store it at MAC for sending later
|
|
NR_BCCH_BCH_Message_t *mib = RC.nrmac[0]->common_channels[0].mib;
|
|
const NR_BCCH_DL_SCH_Message_t *sib1 = RC.nrmac[0]->common_channels[0].sib1;
|
|
f1ap_setup_req_t *req = RC_read_F1Setup(gnb_du_id, name, &info, scc, mib, sib1);
|
|
AssertFatal(req != NULL, "could not read F1 Setup information\n");
|
|
RC.nrmac[0]->f1_config.setup_req = req;
|
|
RC.nrmac[0]->f1_config.gnb_id = gnb_id;
|
|
|
|
free(name); /* read_du_cell_info() allocated memory */
|
|
|
|
} else { // MacRLC_ParamList.numelt > 0
|
|
LOG_E(PHY, "No %s configuration found\n", CONFIG_STRING_MACRLC_LIST);
|
|
// AssertFatal (0,"No " CONFIG_STRING_MACRLC_LIST " configuration found");
|
|
}
|
|
}
|
|
|
|
void config_security(gNB_RRC_INST *rrc)
|
|
{
|
|
paramdef_t sec_params[] = SECURITY_GLOBALPARAMS_DESC;
|
|
int ret = config_get(config_get_if(), sec_params, sizeofArray(sec_params), CONFIG_STRING_SECURITY);
|
|
int i;
|
|
|
|
if (ret < 0) {
|
|
LOG_W(RRC, "configuration file does not contain a \"security\" section, applying default parameters (nia2 nea0, integrity disabled for DRBs)\n");
|
|
rrc->security.ciphering_algorithms[0] = 0; /* nea0 = no ciphering */
|
|
rrc->security.ciphering_algorithms_count = 1;
|
|
rrc->security.integrity_algorithms[0] = 2; /* nia2 */
|
|
rrc->security.integrity_algorithms[1] = 0; /* nia0 = no integrity, as a fallback (but nia2 should be supported by all UEs) */
|
|
rrc->security.integrity_algorithms_count = 2;
|
|
rrc->security.do_drb_ciphering = 1; /* even if nea0 let's activate so that we don't generate cipheringDisabled in pdcp_Config */
|
|
rrc->security.do_drb_integrity = 0;
|
|
return;
|
|
}
|
|
|
|
if (sec_params[SECURITY_CONFIG_CIPHERING_IDX].numelt > 4) {
|
|
LOG_E(RRC, "too much ciphering algorithms in section \"security\" of the configuration file, maximum is 4\n");
|
|
exit(1);
|
|
}
|
|
if (sec_params[SECURITY_CONFIG_INTEGRITY_IDX].numelt > 4) {
|
|
LOG_E(RRC, "too much integrity algorithms in section \"security\" of the configuration file, maximum is 4\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* get ciphering algorithms */
|
|
rrc->security.ciphering_algorithms_count = 0;
|
|
for (i = 0; i < sec_params[SECURITY_CONFIG_CIPHERING_IDX].numelt; i++) {
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea0")) {
|
|
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 0;
|
|
rrc->security.ciphering_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea1")) {
|
|
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 1;
|
|
rrc->security.ciphering_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea2")) {
|
|
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 2;
|
|
rrc->security.ciphering_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i], "nea3")) {
|
|
rrc->security.ciphering_algorithms[rrc->security.ciphering_algorithms_count] = 3;
|
|
rrc->security.ciphering_algorithms_count++;
|
|
continue;
|
|
}
|
|
LOG_E(RRC, "unknown ciphering algorithm \"%s\" in section \"security\" of the configuration file\n",
|
|
sec_params[SECURITY_CONFIG_CIPHERING_IDX].strlistptr[i]);
|
|
exit(1);
|
|
}
|
|
|
|
/* get integrity algorithms */
|
|
rrc->security.integrity_algorithms_count = 0;
|
|
for (i = 0; i < sec_params[SECURITY_CONFIG_INTEGRITY_IDX].numelt; i++) {
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia0")) {
|
|
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 0;
|
|
rrc->security.integrity_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia1")) {
|
|
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 1;
|
|
rrc->security.integrity_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia2")) {
|
|
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 2;
|
|
rrc->security.integrity_algorithms_count++;
|
|
continue;
|
|
}
|
|
if (!strcmp(sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i], "nia3")) {
|
|
rrc->security.integrity_algorithms[rrc->security.integrity_algorithms_count] = 3;
|
|
rrc->security.integrity_algorithms_count++;
|
|
continue;
|
|
}
|
|
LOG_E(RRC, "unknown integrity algorithm \"%s\" in section \"security\" of the configuration file\n",
|
|
sec_params[SECURITY_CONFIG_INTEGRITY_IDX].strlistptr[i]);
|
|
exit(1);
|
|
}
|
|
|
|
if (rrc->security.ciphering_algorithms_count == 0) {
|
|
LOG_W(RRC, "no preferred ciphering algorithm set in configuration file, applying default parameters (no security)\n");
|
|
rrc->security.ciphering_algorithms[0] = 0; /* nea0 = no ciphering */
|
|
rrc->security.ciphering_algorithms_count = 1;
|
|
}
|
|
|
|
if (rrc->security.integrity_algorithms_count == 0) {
|
|
LOG_W(RRC, "no preferred integrity algorithm set in configuration file, applying default parameters (nia2)\n");
|
|
rrc->security.integrity_algorithms[0] = 2; /* nia2 */
|
|
rrc->security.integrity_algorithms[1] = 0; /* nia0 = no integrity */
|
|
rrc->security.integrity_algorithms_count = 2;
|
|
}
|
|
|
|
if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr, "yes")) {
|
|
rrc->security.do_drb_ciphering = 1;
|
|
} else if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr, "no")) {
|
|
rrc->security.do_drb_ciphering = 0;
|
|
} else {
|
|
LOG_E(RRC, "in configuration file, bad drb_ciphering value '%s', only 'yes' and 'no' allowed\n",
|
|
*sec_params[SECURITY_CONFIG_DO_DRB_CIPHERING_IDX].strptr);
|
|
exit(1);
|
|
}
|
|
|
|
if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr, "yes")) {
|
|
rrc->security.do_drb_integrity = 1;
|
|
} else if (!strcmp(*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr, "no")) {
|
|
rrc->security.do_drb_integrity = 0;
|
|
} else {
|
|
LOG_E(RRC, "in configuration file, bad drb_integrity value '%s', only 'yes' and 'no' allowed\n",
|
|
*sec_params[SECURITY_CONFIG_DO_DRB_INTEGRITY_IDX].strptr);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static int sort_neighbour_cell_config_by_cell_id(const void *a, const void *b)
|
|
{
|
|
const neighbour_cell_configuration_t *config_a = (const neighbour_cell_configuration_t *)a;
|
|
const neighbour_cell_configuration_t *config_b = (const neighbour_cell_configuration_t *)b;
|
|
|
|
if (config_a->nr_cell_id < config_b->nr_cell_id) {
|
|
return -1;
|
|
} else if (config_a->nr_cell_id > config_b->nr_cell_id) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc)
|
|
{
|
|
char gnbpath[MAX_OPTNAME_SIZE + 8];
|
|
sprintf(gnbpath, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx);
|
|
|
|
paramdef_t neighbour_list_params[] = GNB_NEIGHBOUR_LIST_PARAM_LIST;
|
|
paramlist_def_t neighbour_list_param_list = {GNB_CONFIG_STRING_NEIGHBOUR_LIST, NULL, 0};
|
|
|
|
config_getlist(config_get_if(), &neighbour_list_param_list, neighbour_list_params, sizeofArray(neighbour_list_params), gnbpath);
|
|
if (neighbour_list_param_list.numelt < 1)
|
|
return;
|
|
|
|
rrc->neighbour_cell_configuration = malloc(sizeof(seq_arr_t));
|
|
seq_arr_init(rrc->neighbour_cell_configuration, sizeof(neighbour_cell_configuration_t));
|
|
|
|
for (int elm = 0; elm < neighbour_list_param_list.numelt; ++elm) {
|
|
neighbour_cell_configuration_t *cell = calloc(1, sizeof(neighbour_cell_configuration_t));
|
|
AssertFatal(cell != NULL, "out of memory\n");
|
|
cell->nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr;
|
|
|
|
char neighbourpath[MAX_OPTNAME_SIZE + 8];
|
|
sprintf(neighbourpath, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm);
|
|
paramdef_t NeighbourCellParams[] = GNBNEIGHBOURCELLPARAMS_DESC;
|
|
paramlist_def_t NeighbourCellParamList = {GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, NULL, 0};
|
|
config_getlist(config_get_if(), &NeighbourCellParamList, NeighbourCellParams, sizeofArray(NeighbourCellParams), neighbourpath);
|
|
LOG_D(GNB_APP, "HO LOG: For the Cell: %d Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt);
|
|
if (NeighbourCellParamList.numelt < 1)
|
|
continue;
|
|
|
|
cell->neighbour_cells = malloc(sizeof(seq_arr_t));
|
|
AssertFatal(cell->neighbour_cells != NULL, "Memory exhausted!!!");
|
|
seq_arr_init(cell->neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t));
|
|
for (int l = 0; l < NeighbourCellParamList.numelt; ++l) {
|
|
nr_neighbour_gnb_configuration_t *neighbourCell = calloc(1, sizeof(nr_neighbour_gnb_configuration_t));
|
|
AssertFatal(neighbourCell != NULL, "out of memory\n");
|
|
neighbourCell->gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr);
|
|
neighbourCell->nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr);
|
|
neighbourCell->physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr;
|
|
neighbourCell->subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr;
|
|
neighbourCell->absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr;
|
|
neighbourCell->tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr;
|
|
|
|
char neighbour_plmn_path[CONFIG_MAXOPTLENGTH];
|
|
sprintf(neighbour_plmn_path,
|
|
"%s.%s.[%i].%s",
|
|
neighbourpath,
|
|
GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST,
|
|
l,
|
|
GNB_CONFIG_STRING_NEIGHBOUR_PLMN);
|
|
|
|
paramdef_t NeighbourPlmn[] = GNBPLMNPARAMS_DESC;
|
|
config_get(config_get_if(), NeighbourPlmn, sizeofArray(NeighbourPlmn), neighbour_plmn_path);
|
|
|
|
neighbourCell->plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
|
neighbourCell->plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
|
neighbourCell->plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr;
|
|
seq_arr_push_back(cell->neighbour_cells, neighbourCell, sizeof(nr_neighbour_gnb_configuration_t));
|
|
}
|
|
|
|
seq_arr_push_back(rrc->neighbour_cell_configuration, cell, sizeof(neighbour_cell_configuration_t));
|
|
}
|
|
void *base = seq_arr_front(rrc->neighbour_cell_configuration);
|
|
size_t nmemb = seq_arr_size(rrc->neighbour_cell_configuration);
|
|
size_t element_size = sizeof(neighbour_cell_configuration_t);
|
|
|
|
qsort(base, nmemb, element_size, sort_neighbour_cell_config_by_cell_id);
|
|
}
|
|
|
|
static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc)
|
|
{
|
|
char measurement_path[MAX_OPTNAME_SIZE + 8];
|
|
sprintf(measurement_path, "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION);
|
|
|
|
nr_measurement_configuration_t *measurementConfig = &rrc->measurementConfiguration;
|
|
// Periodical Event Configuration
|
|
char periodic_event_path[MAX_OPTNAME_SIZE + 8];
|
|
sprintf(periodic_event_path,
|
|
"%s.[%i].%s.%s",
|
|
GNB_CONFIG_STRING_GNB_LIST,
|
|
gnb_idx,
|
|
GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION,
|
|
MEASUREMENT_EVENTS_PERIODICAL);
|
|
paramdef_t Periodical_EventParams[] = MEASUREMENT_PERIODICAL_GLOBALPARAMS_DESC;
|
|
config_get(config_get_if(), Periodical_EventParams, sizeofArray(Periodical_EventParams), periodic_event_path);
|
|
if (*Periodical_EventParams[MEASUREMENT_EVENTS_ENABLE_IDX].i64ptr) {
|
|
nr_per_event_t *periodic_event = (nr_per_event_t *)calloc(1, sizeof(nr_per_event_t));
|
|
periodic_event->includeBeamMeasurements = *Periodical_EventParams[MEASUREMENT_EVENTS_INCLUDE_BEAM_MEAS_IDX].i64ptr;
|
|
periodic_event->maxReportCells = *Periodical_EventParams[MEASUREMENT_EVENTS_MAX_RS_INDEX_TO_REPORT].i64ptr;
|
|
|
|
measurementConfig->per_event = periodic_event;
|
|
}
|
|
|
|
// A2 Event Configuration
|
|
char a2_path[MAX_OPTNAME_SIZE + 8];
|
|
sprintf(a2_path,
|
|
"%s.[%i].%s.%s",
|
|
GNB_CONFIG_STRING_GNB_LIST,
|
|
gnb_idx,
|
|
GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION,
|
|
MEASUREMENT_EVENTS_A2);
|
|
paramdef_t A2_EventParams[] = MEASUREMENT_A2_GLOBALPARAMS_DESC;
|
|
config_get(config_get_if(), A2_EventParams, sizeofArray(A2_EventParams), a2_path);
|
|
if (*A2_EventParams[MEASUREMENT_EVENTS_ENABLE_IDX].i64ptr) {
|
|
nr_a2_event_t *a2_event = (nr_a2_event_t *)calloc(1, sizeof(nr_a2_event_t));
|
|
a2_event->threshold_RSRP = *A2_EventParams[MEASUREMENT_EVENTS_A2_THRESHOLD_IDX].i64ptr;
|
|
a2_event->timeToTrigger = *A2_EventParams[MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr;
|
|
|
|
measurementConfig->a2_event = a2_event;
|
|
}
|
|
// A3 Event Configuration
|
|
paramlist_def_t A3_EventList = {MEASUREMENT_EVENTS_A3, NULL, 0};
|
|
paramdef_t A3_EventParams[] = MEASUREMENT_A3_GLOBALPARAMS_DESC;
|
|
config_getlist(config_get_if(), &A3_EventList, A3_EventParams, sizeofArray(A3_EventParams), measurement_path);
|
|
LOG_D(GNB_APP, "HO LOG: A3 Configuration Exists: %d\n", A3_EventList.numelt);
|
|
|
|
if (A3_EventList.numelt < 1)
|
|
return;
|
|
|
|
measurementConfig->a3_event_list = malloc(sizeof(seq_arr_t));
|
|
seq_arr_init(measurementConfig->a3_event_list, sizeof(nr_a3_event_t));
|
|
for (int i = 0; i < A3_EventList.numelt; i++) {
|
|
nr_a3_event_t *a3_event = (nr_a3_event_t *)calloc(1, sizeof(nr_a3_event_t));
|
|
AssertFatal(a3_event != NULL, "out of memory\n");
|
|
a3_event->cell_id = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_CELL_ID_IDX].i64ptr;
|
|
a3_event->timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr;
|
|
a3_event->a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr;
|
|
a3_event->hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr;
|
|
|
|
if (a3_event->cell_id == -1)
|
|
measurementConfig->is_default_a3_configuration_exists = true;
|
|
|
|
seq_arr_push_back(measurementConfig->a3_event_list, a3_event, sizeof(nr_a3_event_t));
|
|
}
|
|
}
|
|
|
|
void RCconfig_NRRRC(gNB_RRC_INST *rrc)
|
|
{
|
|
|
|
int num_gnbs = 0;
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
int32_t gnb_id = 0;
|
|
int k = 0;
|
|
int i = 0;
|
|
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
////////// Identification parameters
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
|
|
////////// Physical parameters
|
|
|
|
/* get global parameters, defined outside any section in the config file */
|
|
|
|
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
|
num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
AssertFatal (i < num_gnbs,"Failed to parse config file no %dth element in %s \n", i, GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
AssertFatal(num_gnbs == 1, "required section \"gNBs\" not in config!\n");
|
|
|
|
if (num_gnbs > 0) {
|
|
|
|
// Output a list of all gNBs. ////////// Identification parameters
|
|
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
|
if (GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr == NULL) {
|
|
// Calculate a default gNB ID
|
|
if (get_softmodem_params()->sa) {
|
|
uint32_t hash;
|
|
hash = ngap_generate_gNB_id ();
|
|
gnb_id = i + (hash & 0xFFFFFF8);
|
|
} else {
|
|
gnb_id = i;
|
|
}
|
|
} else {
|
|
gnb_id = *(GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr);
|
|
}
|
|
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
|
|
printf("NRRRC %d: Southbound Transport %s\n", i, *(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr));
|
|
|
|
rrc->node_type = get_node_type();
|
|
rrc->node_id = gnb_id;
|
|
if (NODE_IS_CU(rrc->node_type)) {
|
|
paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC;
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(aprefix,"%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, i, GNB_CONFIG_STRING_SCTP_CONFIG);
|
|
config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix);
|
|
LOG_I(GNB_APP,"F1AP: gNB_CU_id[%d] %d\n", k, rrc->node_id);
|
|
rrc->node_name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr));
|
|
LOG_I(GNB_APP,"F1AP: gNB_CU_name[%d] %s\n", k, rrc->node_name);
|
|
rrc->eth_params_s.my_addr = strdup(*(GNBParamList.paramarray[i][GNB_LOCAL_S_ADDRESS_IDX].strptr));
|
|
rrc->eth_params_s.remote_addr = strdup(*(GNBParamList.paramarray[i][GNB_REMOTE_S_ADDRESS_IDX].strptr));
|
|
rrc->eth_params_s.my_portc = *(GNBParamList.paramarray[i][GNB_LOCAL_S_PORTC_IDX].uptr);
|
|
rrc->eth_params_s.remote_portc = *(GNBParamList.paramarray[i][GNB_REMOTE_S_PORTC_IDX].uptr);
|
|
rrc->eth_params_s.my_portd = *(GNBParamList.paramarray[i][GNB_LOCAL_S_PORTD_IDX].uptr);
|
|
rrc->eth_params_s.remote_portd = *(GNBParamList.paramarray[i][GNB_REMOTE_S_PORTD_IDX].uptr);
|
|
rrc->eth_params_s.transp_preference = ETH_UDP_MODE;
|
|
}
|
|
|
|
|
|
|
|
rrc->nr_cellid = (uint64_t)*(GNBParamList.paramarray[i][GNB_NRCELLID_IDX].u64ptr);
|
|
|
|
if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_mac") == 0) {
|
|
|
|
} else if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "cudu") == 0) {
|
|
rrc->eth_params_s.my_addr = strdup(*(GNBParamList.paramarray[i][GNB_LOCAL_S_ADDRESS_IDX].strptr));
|
|
rrc->eth_params_s.remote_addr = strdup(*(GNBParamList.paramarray[i][GNB_REMOTE_S_ADDRESS_IDX].strptr));
|
|
rrc->eth_params_s.my_portc = *(GNBParamList.paramarray[i][GNB_LOCAL_S_PORTC_IDX].uptr);
|
|
rrc->eth_params_s.remote_portc = *(GNBParamList.paramarray[i][GNB_REMOTE_S_PORTC_IDX].uptr);
|
|
rrc->eth_params_s.my_portd = *(GNBParamList.paramarray[i][GNB_LOCAL_S_PORTD_IDX].uptr);
|
|
rrc->eth_params_s.remote_portd = *(GNBParamList.paramarray[i][GNB_REMOTE_S_PORTD_IDX].uptr);
|
|
rrc->eth_params_s.transp_preference = ETH_UDP_MODE;
|
|
} else { // other midhaul
|
|
}
|
|
|
|
// search if in active list
|
|
|
|
gNB_RrcConfigurationReq nrrrc_config = {0};
|
|
for (k=0; k <num_gnbs ; k++) {
|
|
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[k], *(GNBParamList.paramarray[i][GNB_GNB_NAME_IDX].strptr) )== 0) {
|
|
|
|
char gnbpath[MAX_OPTNAME_SIZE + 8];
|
|
sprintf(gnbpath,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
|
|
|
fill_neighbour_cell_configuration(k, rrc);
|
|
|
|
fill_measurement_configuration(k, rrc);
|
|
|
|
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
|
|
|
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
|
|
|
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
|
|
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
|
|
|
nrrrc_config.tac = *GNBParamList.paramarray[i][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
|
AssertFatal(!GNBParamList.paramarray[i][GNB_MOBILE_COUNTRY_CODE_IDX_OLD].strptr
|
|
&& !GNBParamList.paramarray[i][GNB_MOBILE_NETWORK_CODE_IDX_OLD].strptr,
|
|
"It seems that you use an old configuration file. Please change the existing\n"
|
|
" tracking_area_code = \"1\";\n"
|
|
" mobile_country_code = \"208\";\n"
|
|
" mobile_network_code = \"93\";\n"
|
|
"to\n"
|
|
" tracking_area_code = 1; // no string!!\n"
|
|
" plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n");
|
|
config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), gnbpath);
|
|
|
|
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
|
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
|
PLMNParamList.numelt);
|
|
|
|
nrrrc_config.num_plmn = PLMNParamList.numelt;
|
|
|
|
for (int l = 0; l < PLMNParamList.numelt; ++l) {
|
|
|
|
nrrrc_config.mcc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
|
nrrrc_config.mnc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
|
nrrrc_config.mnc_digit_length[l] = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
|
AssertFatal((nrrrc_config.mnc_digit_length[l] == 2) ||
|
|
(nrrrc_config.mnc_digit_length[l] == 3),"BAD MNC DIGIT LENGTH %d",
|
|
nrrrc_config.mnc_digit_length[l]);
|
|
}
|
|
nrrrc_config.enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr;
|
|
LOG_I(GNB_APP, "SDAP layer is %s\n", nrrrc_config.enable_sdap ? "enabled" : "disabled");
|
|
nrrrc_config.drbs = *GNBParamList.paramarray[i][GNB_DRBS].iptr;
|
|
nrrrc_config.um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr);
|
|
LOG_I(GNB_APP, "Data Radio Bearer count %d\n", nrrrc_config.drbs);
|
|
|
|
}//
|
|
}//End for (k=0; k <num_gnbs ; k++)
|
|
openair_rrc_gNB_configuration(rrc, &nrrrc_config);
|
|
}//End if (num_gnbs>0)
|
|
|
|
config_security(rrc);
|
|
}//End RCconfig_NRRRC function
|
|
|
|
int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) {
|
|
|
|
int j,k = 0;
|
|
int gnb_id;
|
|
int32_t my_int;
|
|
const char* active_gnb[MAX_GNB];
|
|
char *address = NULL;
|
|
char *cidr = NULL;
|
|
|
|
// for no gcc warnings
|
|
|
|
(void) my_int;
|
|
|
|
memset((char*)active_gnb,0,MAX_GNB* sizeof(char*));
|
|
char* gnb_ipv4_address_for_NGU = NULL;
|
|
uint32_t gnb_port_for_NGU = 0;
|
|
char* gnb_ipv4_address_for_S1U = NULL;
|
|
uint32_t gnb_port_for_S1U = 0;
|
|
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
|
|
/* get global parameters, defined outside any section in the config file */
|
|
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
|
|
|
AssertFatal (i<GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt,
|
|
"Failed to parse config file %s, %uth attribute %s \n",
|
|
RC.config_file_name, i, GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
|
|
|
|
if (GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt>0) {
|
|
// Output a list of all gNBs.
|
|
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
|
if (GNBParamList.numelt > 0) {
|
|
for (k = 0; k < GNBParamList.numelt; k++) {
|
|
if (GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr == NULL) {
|
|
// Calculate a default gNB ID
|
|
if (get_softmodem_params()->sa) {
|
|
uint32_t hash;
|
|
|
|
hash = ngap_generate_gNB_id ();
|
|
gnb_id = k + (hash & 0xFFFFFF8);
|
|
} else {
|
|
gnb_id = k;
|
|
}
|
|
} else {
|
|
gnb_id = *(GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr);
|
|
}
|
|
|
|
|
|
// search if in active list
|
|
for (j=0; j < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; j++) {
|
|
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) {
|
|
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
|
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
|
paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC;
|
|
paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0};
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
|
checkedparam_t config_check_SNSSAIParams [] = SNSSAIPARAMS_CHECK;
|
|
|
|
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
|
|
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
|
for (int J = 0; J < sizeofArray(SNSSAIParams); ++J)
|
|
SNSSAIParams[J].chkPptr = &(config_check_SNSSAIParams[J]);
|
|
|
|
paramdef_t NGParams[] = GNBNGPARAMS_DESC;
|
|
paramlist_def_t NGParamList = {GNB_CONFIG_STRING_AMF_IP_ADDRESS,NULL,0};
|
|
|
|
paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC;
|
|
paramdef_t NETParams[] = GNBNETPARAMS_DESC;
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k);
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).gNB_id = gnb_id;
|
|
|
|
if (strcmp(*(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr), "CELL_MACRO_GNB") == 0) {
|
|
NGAP_REGISTER_GNB_REQ (msg_p).cell_type = CELL_MACRO_GNB;
|
|
} else if (strcmp(*(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr), "CELL_HOME_GNB") == 0) {
|
|
NGAP_REGISTER_GNB_REQ (msg_p).cell_type = CELL_HOME_ENB;
|
|
} else {
|
|
AssertFatal (0,
|
|
"Failed to parse gNB configuration file %s, gnb %u unknown value \"%s\" for cell_type choice: CELL_MACRO_GNB or CELL_HOME_GNB !\n",
|
|
RC.config_file_name, i, *(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr));
|
|
}
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).gNB_name = strdup(*(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr));
|
|
NGAP_REGISTER_GNB_REQ (msg_p).tac = *GNBParamList.paramarray[k][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
|
AssertFatal(!GNBParamList.paramarray[k][GNB_MOBILE_COUNTRY_CODE_IDX_OLD].strptr
|
|
&& !GNBParamList.paramarray[k][GNB_MOBILE_NETWORK_CODE_IDX_OLD].strptr,
|
|
"It seems that you use an old configuration file. Please change the existing\n"
|
|
" tracking_area_code = \"1\";\n"
|
|
" mobile_country_code = \"208\";\n"
|
|
" mobile_network_code = \"93\";\n"
|
|
"to\n"
|
|
" tracking_area_code = 1; // no string!!\n"
|
|
" plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n");
|
|
config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), aprefix);
|
|
|
|
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
|
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
|
PLMNParamList.numelt);
|
|
|
|
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn = PLMNParamList.numelt;
|
|
|
|
for (int l = 0; l < PLMNParamList.numelt; ++l) {
|
|
char snssaistr[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_PLMN_LIST, l);
|
|
config_getlist(config_get_if(), &SNSSAIParamList, SNSSAIParams, sizeofArray(SNSSAIParams), snssaistr);
|
|
|
|
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
|
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
|
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).default_drx = 0;
|
|
AssertFatal((NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length == 2)
|
|
|| (NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length == 3),
|
|
"BAD MNC DIGIT LENGTH %d",
|
|
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length);
|
|
|
|
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].num_nssai = SNSSAIParamList.numelt;
|
|
for (int s = 0; s < SNSSAIParamList.numelt; ++s) {
|
|
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai[s].sst =
|
|
*SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr;
|
|
// SD is optional
|
|
// 0xffffff is "no SD", see 23.003 Sec 28.4.2
|
|
NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai[s].sd =
|
|
(*SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr & 0xffffff);
|
|
}
|
|
}
|
|
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
|
config_getlist(config_get_if(), &NGParamList, NGParams, sizeofArray(NGParams), aprefix);
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).nb_amf = 0;
|
|
|
|
for (int l = 0; l < NGParamList.numelt; l++) {
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).nb_amf += 1;
|
|
strcpy(NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[l].ipv4_address,*(NGParamList.paramarray[l][GNB_AMF_IPV4_ADDRESS_IDX].strptr));
|
|
NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv4 = 1;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv6 = 0;
|
|
|
|
/* not in configuration yet ...
|
|
if (NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].iptr)
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].numelt;
|
|
else
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = 0;
|
|
|
|
AssertFatal(NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] <= NGAP_REGISTER_GNB_REQ(msg_p).num_plmn,
|
|
"List of broadcast PLMN to be sent to AMF can not be longer than actual "
|
|
"PLMN list (max %d, but is %d)\n",
|
|
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn,
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l]);
|
|
|
|
for (int el = 0; el < NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l]; ++el) {
|
|
// UINTARRAY gets mapped to int, see config_libconfig.c:223
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] = NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].iptr[el];
|
|
AssertFatal(NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] >= 0
|
|
&& NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn,
|
|
"index for AMF's MCC/MNC (%d) is an invalid index for the registered PLMN IDs (%d)\n",
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el],
|
|
NGAP_REGISTER_GNB_REQ(msg_p).num_plmn);
|
|
}
|
|
*/
|
|
|
|
/* if no broadcasst_plmn array is defined, fill default values */
|
|
if (NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] == 0) {
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = NGAP_REGISTER_GNB_REQ(msg_p).num_plmn;
|
|
|
|
for (int el = 0; el < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn; ++el)
|
|
NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] = el;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// SCTP SETTING
|
|
NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS;
|
|
if (get_softmodem_params()->sa) {
|
|
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG);
|
|
config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix);
|
|
NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr);
|
|
NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr);
|
|
}
|
|
|
|
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
|
// NETWORK_INTERFACES
|
|
config_get(config_get_if(), NETParams, sizeofArray(NETParams), aprefix);
|
|
|
|
// NGAP_REGISTER_GNB_REQ (msg_p).enb_interface_name_for_NGU = strdup(enb_interface_name_for_NGU);
|
|
cidr = *(NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr);
|
|
char *save = NULL;
|
|
address = strtok_r(cidr, "/", &save);
|
|
|
|
NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv6 = 0;
|
|
NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4 = 1;
|
|
|
|
strcpy(NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4_address, address);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int RCconfig_nr_parallel(void) {
|
|
char *parallel_conf = NULL;
|
|
char *worker_conf = NULL;
|
|
extern char *parallel_config;
|
|
extern char *worker_config;
|
|
paramdef_t ThreadParams[] = THREAD_CONF_DESC;
|
|
paramlist_def_t THREADParamList = {THREAD_CONFIG_STRING_THREAD_STRUCT,NULL,0};
|
|
config_getlist(config_get_if(), &THREADParamList, NULL, 0, NULL);
|
|
|
|
if(THREADParamList.numelt>0) {
|
|
config_getlist(config_get_if(), &THREADParamList, ThreadParams, sizeofArray(ThreadParams), NULL);
|
|
parallel_conf = strdup(*(THREADParamList.paramarray[0][THREAD_PARALLEL_IDX].strptr));
|
|
} else {
|
|
parallel_conf = strdup("PARALLEL_RU_L1_TRX_SPLIT");
|
|
}
|
|
|
|
if(THREADParamList.numelt>0) {
|
|
config_getlist(config_get_if(), &THREADParamList, ThreadParams, sizeofArray(ThreadParams), NULL);
|
|
worker_conf = strdup(*(THREADParamList.paramarray[0][THREAD_WORKER_IDX].strptr));
|
|
} else {
|
|
worker_conf = strdup("WORKER_ENABLE");
|
|
}
|
|
|
|
if(parallel_config == NULL) set_parallel_conf(parallel_conf);
|
|
if(worker_config == NULL) set_worker_conf(worker_conf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void NRRCConfig(void) {
|
|
|
|
paramlist_def_t MACRLCParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0};
|
|
paramlist_def_t L1ParamList = {CONFIG_STRING_L1_LIST,NULL,0};
|
|
paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0};
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
|
|
/* get global parameters, defined outside any section in the config file */
|
|
|
|
LOG_I(GNB_APP, "Getting GNBSParams\n");
|
|
|
|
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
|
RC.nb_nr_inst = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
|
|
|
// Get num MACRLC instances
|
|
config_getlist(config_get_if(), &MACRLCParamList, NULL, 0, NULL);
|
|
RC.nb_nr_macrlc_inst = MACRLCParamList.numelt;
|
|
// Get num L1 instances
|
|
config_getlist(config_get_if(), &L1ParamList, NULL, 0, NULL);
|
|
RC.nb_nr_L1_inst = L1ParamList.numelt;
|
|
|
|
// Get num RU instances
|
|
config_getlist(config_get_if(), &RUParamList, NULL, 0, NULL);
|
|
RC.nb_RU = RUParamList.numelt;
|
|
|
|
RCconfig_nr_parallel();
|
|
|
|
|
|
}
|
|
|
|
|
|
int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
|
|
int J, l;
|
|
char *address = NULL;
|
|
char *cidr = NULL;
|
|
//int num_gnbs = 0;
|
|
//int num_component_carriers = 0;
|
|
int j,k = 0;
|
|
int32_t gnb_id = 0;
|
|
|
|
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
|
////////// Identification parameters
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
/* get global parameters, defined outside any section in the config file */
|
|
config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL);
|
|
NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(NR_ServingCellConfigCommon_t));
|
|
uint64_t ssb_bitmap=0xff;
|
|
memset((void*)scc,0,sizeof(NR_ServingCellConfigCommon_t));
|
|
prepare_scc(scc);
|
|
paramdef_t SCCsParams[] = SCCPARAMS_DESC(scc);
|
|
paramlist_def_t SCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0};
|
|
|
|
AssertFatal(i < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt,
|
|
"Failed to parse config file %s, %uth attribute %s \n",
|
|
RC.config_file_name, i, GNB_CONFIG_STRING_ACTIVE_GNBS);
|
|
|
|
if (GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt > 0) {
|
|
// Output a list of all gNBs.
|
|
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
|
|
|
if (GNBParamList.numelt > 0) {
|
|
for (k = 0; k < GNBParamList.numelt; k++) {
|
|
if (GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr == NULL) {
|
|
// Calculate a default eNB ID
|
|
if (get_softmodem_params()->sa) {
|
|
uint32_t hash;
|
|
hash = ngap_generate_gNB_id ();
|
|
gnb_id = k + (hash & 0xFFFFFF8);
|
|
} else {
|
|
gnb_id = k;
|
|
}
|
|
} else {
|
|
gnb_id = *(GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr);
|
|
}
|
|
|
|
// search if in active list
|
|
for (j = 0; j < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; j++) {
|
|
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) {
|
|
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
|
|
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
|
|
/* map parameter checking array instances to parameter definition array instances */
|
|
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
|
|
|
|
for (int I = 0; I < sizeofArray(PLMNParams); ++I)
|
|
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
|
|
|
|
paramdef_t X2Params[] = X2PARAMS_DESC;
|
|
paramlist_def_t X2ParamList = {ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS,NULL,0};
|
|
paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC;
|
|
char* gnb_ipv4_address_for_NGU = NULL;
|
|
uint32_t gnb_port_for_NGU = 0;
|
|
char* gnb_ipv4_address_for_S1U = NULL;
|
|
uint32_t gnb_port_for_S1U = 0;
|
|
|
|
paramdef_t NETParams[] = GNBNETPARAMS_DESC;
|
|
/* TODO: fix the size - if set lower we have a crash (MAX_OPTNAME_SIZE was 64 when this code was written) */
|
|
/* this is most probably a problem with the config module */
|
|
char aprefix[MAX_OPTNAME_SIZE*80 + 8];
|
|
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
|
/* Some default/random parameters */
|
|
X2AP_REGISTER_ENB_REQ (msg_p).eNB_id = gnb_id;
|
|
|
|
if (strcmp(*(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr), "CELL_MACRO_GNB") == 0) {
|
|
X2AP_REGISTER_ENB_REQ (msg_p).cell_type = CELL_MACRO_GNB;
|
|
}else {
|
|
AssertFatal (0,
|
|
"Failed to parse eNB configuration file %s, enb %u unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n",
|
|
RC.config_file_name, i, *(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr));
|
|
}
|
|
|
|
X2AP_REGISTER_ENB_REQ (msg_p).eNB_name = strdup(*(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr));
|
|
X2AP_REGISTER_ENB_REQ (msg_p).tac = *GNBParamList.paramarray[k][GNB_TRACKING_AREA_CODE_IDX].uptr;
|
|
config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), aprefix);
|
|
|
|
if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6)
|
|
AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n",
|
|
PLMNParamList.numelt);
|
|
|
|
if (PLMNParamList.numelt > 1)
|
|
LOG_W(X2AP, "X2AP currently handles only one PLMN, ignoring the others!\n");
|
|
|
|
X2AP_REGISTER_ENB_REQ (msg_p).mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr;
|
|
AssertFatal(X2AP_REGISTER_ENB_REQ(msg_p).mnc_digit_length == 3
|
|
|| X2AP_REGISTER_ENB_REQ(msg_p).mnc < 100,
|
|
"MNC %d cannot be encoded in two digits as requested (change mnc_digit_length to 3)\n",
|
|
X2AP_REGISTER_ENB_REQ(msg_p).mnc);
|
|
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
|
|
config_getlist(config_get_if(), &SCCsParamList, NULL, 0, aprefix);
|
|
if (SCCsParamList.numelt > 0) {
|
|
sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0);
|
|
config_get(config_get_if(), SCCsParams, sizeofArray(SCCsParams), aprefix);
|
|
fix_scc(scc,ssb_bitmap);
|
|
}
|
|
X2AP_REGISTER_ENB_REQ (msg_p).num_cc = SCCsParamList.numelt;
|
|
for (J = 0; J < SCCsParamList.numelt ; J++) {
|
|
struct NR_FrequencyInfoDL *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
|
|
X2AP_REGISTER_ENB_REQ(msg_p).nr_band[J] = *frequencyInfoDL->frequencyBandList.list.array[0]; // nr_band; //78
|
|
X2AP_REGISTER_ENB_REQ(msg_p).nrARFCN[J] = frequencyInfoDL->absoluteFrequencyPointA;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).uplink_frequency_offset[J] = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->offsetToCarrier; //0
|
|
X2AP_REGISTER_ENB_REQ (msg_p).Nid_cell[J]= *scc->physCellId; //0
|
|
X2AP_REGISTER_ENB_REQ(msg_p).N_RB_DL[J] =
|
|
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; // 106
|
|
X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = TDD;
|
|
LOG_I(X2AP, "gNB configuration parameters: nr_band: %d, nr_ARFCN: %d, DL_RBs: %d, num_cc: %d \n",
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nr_band[J],
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nrARFCN[J],
|
|
X2AP_REGISTER_ENB_REQ (msg_p).N_RB_DL[J],
|
|
X2AP_REGISTER_ENB_REQ (msg_p).num_cc);
|
|
}
|
|
|
|
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k);
|
|
config_getlist(config_get_if(), &X2ParamList, X2Params, sizeofArray(X2Params), aprefix);
|
|
AssertFatal(X2ParamList.numelt <= X2AP_MAX_NB_ENB_IP_ADDRESS,
|
|
"value of X2ParamList.numelt %d must be lower than X2AP_MAX_NB_ENB_IP_ADDRESS %d value: reconsider to increase X2AP_MAX_NB_ENB_IP_ADDRESS\n",
|
|
X2ParamList.numelt,X2AP_MAX_NB_ENB_IP_ADDRESS);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nb_x2 = 0;
|
|
|
|
for (l = 0; l < X2ParamList.numelt; l++) {
|
|
X2AP_REGISTER_ENB_REQ (msg_p).nb_x2 += 1;
|
|
strcpy(X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4_address,*(X2ParamList.paramarray[l][ENB_X2_IPV4_ADDRESS_IDX].strptr));
|
|
X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv4 = 1;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).target_enb_x2_ip_address[l].ipv6 = 0;
|
|
}
|
|
|
|
// timers
|
|
{
|
|
int t_reloc_prep = 0;
|
|
int tx2_reloc_overall = 0;
|
|
int t_dc_prep = 0;
|
|
int t_dc_overall = 0;
|
|
paramdef_t p[] = {
|
|
{ "t_reloc_prep", "t_reloc_prep", 0, .iptr=&t_reloc_prep, .defintval=0, TYPE_INT, 0 },
|
|
{ "tx2_reloc_overall", "tx2_reloc_overall", 0, .iptr=&tx2_reloc_overall, .defintval=0, TYPE_INT, 0 },
|
|
{ "t_dc_prep", "t_dc_prep", 0, .iptr=&t_dc_prep, .defintval=0, TYPE_INT, 0 },
|
|
{ "t_dc_overall", "t_dc_overall", 0, .iptr=&t_dc_overall, .defintval=0, TYPE_INT, 0 }
|
|
};
|
|
config_get(config_get_if(), p, sizeofArray(p), aprefix);
|
|
|
|
if (t_reloc_prep <= 0 || t_reloc_prep > 10000 ||
|
|
tx2_reloc_overall <= 0 || tx2_reloc_overall > 20000 ||
|
|
t_dc_prep <= 0 || t_dc_prep > 10000 ||
|
|
t_dc_overall <= 0 || t_dc_overall > 20000) {
|
|
LOG_E(X2AP, "timers in configuration file have wrong values. We must have [0 < t_reloc_prep <= 10000] and [0 < tx2_reloc_overall <= 20000] and [0 < t_dc_prep <= 10000] and [0 < t_dc_overall <= 20000]\n");
|
|
exit(1);
|
|
}
|
|
|
|
X2AP_REGISTER_ENB_REQ (msg_p).t_reloc_prep = t_reloc_prep;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).tx2_reloc_overall = tx2_reloc_overall;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).t_dc_prep = t_dc_prep;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).t_dc_overall = t_dc_overall;
|
|
}
|
|
// SCTP SETTING
|
|
X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS;
|
|
|
|
if (get_softmodem_params()->sa) {
|
|
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG);
|
|
config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr);
|
|
}
|
|
|
|
sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
|
|
// NETWORK_INTERFACES
|
|
config_get(config_get_if(), NETParams, sizeofArray(NETParams), aprefix);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_X2C = (uint32_t)*(NETParams[GNB_PORT_FOR_X2C_IDX].uptr);
|
|
|
|
//temp out
|
|
if ((NETParams[GNB_IPV4_ADDR_FOR_X2C_IDX].strptr == NULL) || (X2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_X2C == 0)) {
|
|
LOG_E(RRC,"Add eNB IPv4 address and/or port for X2C in the CONF file!\n");
|
|
exit(1);
|
|
}
|
|
|
|
cidr = *(NETParams[ENB_IPV4_ADDR_FOR_X2C_IDX].strptr);
|
|
char *save = NULL;
|
|
address = strtok_r(cidr, "/", &save);
|
|
X2AP_REGISTER_ENB_REQ (msg_p).enb_x2_ip_address.ipv6 = 0;
|
|
X2AP_REGISTER_ENB_REQ (msg_p).enb_x2_ip_address.ipv4 = 1;
|
|
strcpy(X2AP_REGISTER_ENB_REQ (msg_p).enb_x2_ip_address.ipv4_address, address);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void wait_f1_setup_response(void)
|
|
{
|
|
gNB_MAC_INST *mac = RC.nrmac[0];
|
|
NR_SCHED_LOCK(&mac->sched_lock);
|
|
if (mac->f1_config.setup_resp != NULL) {
|
|
NR_SCHED_UNLOCK(&mac->sched_lock);
|
|
return;
|
|
}
|
|
|
|
LOG_W(GNB_APP, "waiting for F1 Setup Response before activating radio\n");
|
|
|
|
/* for the moment, we keep it simple and just sleep to periodically check.
|
|
* The actual check is protected by a mutex */
|
|
while (mac->f1_config.setup_resp == NULL) {
|
|
NR_SCHED_UNLOCK(&mac->sched_lock);
|
|
sleep(1);
|
|
NR_SCHED_LOCK(&mac->sched_lock);
|
|
}
|
|
NR_SCHED_UNLOCK(&mac->sched_lock);
|
|
}
|
|
static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t *plmn)
|
|
{
|
|
return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc;
|
|
}
|
|
|
|
int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update) {
|
|
int i, j, ret=0;
|
|
LOG_I(GNB_APP, "cells_to_activate %d, RRC instances %d\n",
|
|
gnb_cu_cfg_update->num_cells_to_activate, RC.nb_nr_inst);
|
|
|
|
AssertFatal(gnb_cu_cfg_update->num_cells_to_activate == 1, "only one cell supported at the moment\n");
|
|
AssertFatal(RC.nb_nr_inst == 1, "expected one instance\n");
|
|
gNB_MAC_INST *mac = RC.nrmac[0];
|
|
NR_SCHED_LOCK(&mac->sched_lock);
|
|
for (j = 0; j < gnb_cu_cfg_update->num_cells_to_activate; j++) {
|
|
for (i = 0; i < RC.nb_nr_inst; i++) {
|
|
f1ap_setup_req_t *setup_req = RC.nrmac[i]->f1_config.setup_req;
|
|
// identify local index of cell j by nr_cellid, plmn identity and physical cell ID
|
|
|
|
if (setup_req->cell[0].info.nr_cellid == gnb_cu_cfg_update->cells_to_activate[j].nr_cellid
|
|
&& check_plmn_identity(&setup_req->cell[0].info.plmn, &gnb_cu_cfg_update->cells_to_activate[j].plmn) > 0
|
|
&& setup_req->cell[0].info.nr_pci == gnb_cu_cfg_update->cells_to_activate[j].nrpci) {
|
|
// copy system information and decode it
|
|
AssertFatal(gnb_cu_cfg_update->cells_to_activate[j].num_SI == 0,
|
|
"gNB-CU Configuration Update: handling of additional SIs not implemend\n");
|
|
ret++;
|
|
mac->f1_config.setup_resp = malloc(sizeof(*mac->f1_config.setup_resp));
|
|
AssertFatal(mac->f1_config.setup_resp != NULL, "out of memory\n");
|
|
mac->f1_config.setup_resp->gNB_CU_name = gnb_cu_cfg_update->gNB_CU_name;
|
|
mac->f1_config.setup_resp->num_cells_to_activate = gnb_cu_cfg_update->num_cells_to_activate;
|
|
mac->f1_config.setup_resp->cells_to_activate[0] = gnb_cu_cfg_update->cells_to_activate[0];
|
|
} else {
|
|
LOG_E(GNB_APP, "GNB_CU_CONFIGURATION_UPDATE not matching\n");
|
|
}
|
|
}
|
|
}
|
|
NR_SCHED_UNLOCK(&mac->sched_lock);
|
|
MessageDef *msg_ack_p = NULL;
|
|
if (ret > 0) {
|
|
// generate gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE
|
|
msg_ack_p = itti_alloc_new_message (TASK_GNB_APP, 0, F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE);
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).num_cells_failed_to_be_activated = 0;
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).have_criticality = 0;
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).noofTNLAssociations_to_setup =0;
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).noofTNLAssociations_failed = 0;
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).noofDedicatedSIDeliveryNeededUEs = 0;
|
|
itti_send_msg_to_task (TASK_DU_F1, INSTANCE_DEFAULT, msg_ack_p);
|
|
|
|
}
|
|
else {
|
|
// generate gNB_CU_CONFIGURATION_UPDATE_FAILURE
|
|
msg_ack_p = itti_alloc_new_message (TASK_GNB_APP, 0, F1AP_GNB_CU_CONFIGURATION_UPDATE_FAILURE);
|
|
F1AP_GNB_CU_CONFIGURATION_UPDATE_FAILURE(msg_ack_p).cause = F1AP_CauseRadioNetwork_cell_not_available;
|
|
|
|
itti_send_msg_to_task (TASK_DU_F1, INSTANCE_DEFAULT, msg_ack_p);
|
|
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
ngran_node_t get_node_type(void)
|
|
{
|
|
paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC;
|
|
paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0};
|
|
paramdef_t GNBParams[] = GNBPARAMS_DESC;
|
|
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
|
|
paramdef_t GNBE1Params[] = GNBE1PARAMS_DESC;
|
|
paramlist_def_t GNBE1ParamList = {GNB_CONFIG_STRING_E1_PARAMETERS, NULL, 0};
|
|
|
|
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
|
|
|
if (GNBParamList.numelt == 0) // We have no valid configuration, let's return a default
|
|
return ngran_gNB;
|
|
|
|
config_getlist(config_get_if(), &MacRLC_ParamList, MacRLC_Params, sizeofArray(MacRLC_Params), NULL);
|
|
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
|
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
|
config_getlist(config_get_if(), &GNBE1ParamList, GNBE1Params, sizeofArray(GNBE1Params), aprefix);
|
|
if ( MacRLC_ParamList.numelt > 0) {
|
|
RC.nb_nr_macrlc_inst = MacRLC_ParamList.numelt;
|
|
for (int j = 0; j < RC.nb_nr_macrlc_inst; j++) {
|
|
if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "f1") == 0) {
|
|
return ngran_gNB_DU; // MACRLCs present in config: it must be a DU
|
|
}
|
|
}
|
|
}
|
|
|
|
if (strcmp(*(GNBParamList.paramarray[0][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "f1") == 0) {
|
|
if ( GNBE1ParamList.paramarray == NULL || GNBE1ParamList.numelt == 0 )
|
|
return ngran_gNB_CU;
|
|
else if (strcmp(*(GNBE1ParamList.paramarray[0][GNB_CONFIG_E1_CU_TYPE_IDX].strptr), "cp") == 0)
|
|
return ngran_gNB_CUCP;
|
|
else if (strcmp(*(GNBE1ParamList.paramarray[0][GNB_CONFIG_E1_CU_TYPE_IDX].strptr), "up") == 0)
|
|
return ngran_gNB_CUUP;
|
|
else
|
|
return ngran_gNB_CU;
|
|
} else {
|
|
return ngran_gNB;
|
|
}
|
|
}
|