From 952a216b92433e06c3c725263e187fd51799241c Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 2 May 2022 11:37:19 +0100 Subject: [PATCH 01/61] Remove sib1_tda from configuration files to use default value --- targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf | 1 - targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf | 1 - .../CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf | 1 - .../CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf | 1 - .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 - 7 files changed, 7 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf index c07a0db649..92d1ce432c 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf @@ -48,7 +48,6 @@ gNBs = pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf index 256d724f3f..f95bdf91ae 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf @@ -38,7 +38,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf index 726e43d7ad..74f6c34f57 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.tm1.106PRB.usrpn300.gtp-itti.conf @@ -37,7 +37,6 @@ gNBs = ////////// Physical parameters: ssb_SubcarrierOffset = 0; - sib1_tda = 0; servingCellConfigCommon = ( { #spCellConfigCommon diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index 7e2db64aaa..d124c5692f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; do_SRS = 1; pdcch_ConfigSIB1 = ( diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf index cab801525b..ff64fe718a 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -36,7 +36,6 @@ gNBs = pdsch_AntennaPorts = 1; pusch_AntennaPorts = 1; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index 950e9c1d38..1bc6de3bfe 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -35,7 +35,6 @@ gNBs = ssb_SubcarrierOffset = 0; pdsch_AntennaPorts_N1 = 2; pusch_AntennaPorts = 2; - sib1_tda = 0; do_SRS = 1; ul_prbblacklist = "51,52,53,54" diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index 1dc903b811..a0cee6f9ca 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -34,7 +34,6 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; - sib1_tda = 0; pdcch_ConfigSIB1 = ( { From 39ea2c936fd16f551cc7a32d5c3c0aaa73b82084 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 4 May 2022 15:05:23 +0100 Subject: [PATCH 02/61] Creation of config_srs() function --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 123 +++------------------------- openair2/RRC/NR/nr_rrc_config.c | 107 +++++++++++++++++++++++- openair2/RRC/NR/nr_rrc_config.h | 4 + 3 files changed, 121 insertions(+), 113 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 9252a23596..c0676814f7 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -395,7 +395,6 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, NR_BWP_DownlinkCommon_t *initialDownlinkBWP=&ServCellCom->downlinkConfigCommon.initialDownlinkBWP; initialDownlinkBWP->genericParameters= configuration->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; - for(int i = 0; i< configuration->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.count; i++) { asn1cSequenceAdd(ServCellCom->downlinkConfigCommon.frequencyInfoDL.frequencyBandList.list, @@ -403,7 +402,6 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, nrMultiBandInfo->freqBandIndicatorNR = configuration->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[i]; } - int scs_scaling0 = 1<<(configuration->scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing); int scs_scaling = scs_scaling0; int scs_scaling2 = scs_scaling0; @@ -512,7 +510,6 @@ uint8_t do_SIB1_NR(rrc_gNB_carrier_data_t *carrier, ss7->searchSpaceType->choice.common=calloc(1,sizeof(*ss7->searchSpaceType->choice.common)); ss7->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0 = calloc(1,sizeof(*ss7->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0)); - asn1cCallocOne(initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceSIB1, 0); asn1cCallocOne(initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceOtherSystemInformation, 7); asn1cCallocOne(initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->pagingSearchSpace, 5); @@ -980,36 +977,11 @@ uint8_t do_RRCReject(uint8_t Mod_id, return((enc_rval.encoded+7)/8); } -// TODO: Implement to b_SRS = 1 and b_SRS = 2 -long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { - - if(b_SRS>0) { - LOG_E(NR_RRC,"rrc_get_max_nr_csrs(): Not implemented yet for b_SRS>0\n"); - return 0; // This c_srs is always valid - } - - const uint16_t m_SRS[64] = { 4, 8, 12, 16, 16, 20, 24, 24, 28, 32, 36, 40, 48, 48, 52, 56, 60, 64, 72, 72, 76, 80, 88, - 96, 96, 104, 112, 120, 120, 120, 128, 128, 128, 132, 136, 144, 144, 144, 144, 152, 160, - 160, 160, 168, 176, 184, 192, 192, 192, 192, 208, 216, 224, 240, 240, 240, 240, 256, 256, - 256, 264, 272, 272, 272 }; - - long c_srs = 0; - uint16_t m = 4; - for(int c = 1; c<64; c++) { - if(m_SRS[c]>m && m_SRS[c]tp_pi2BPSK=NULL; initialUplinkBWP->srs_Config = calloc(1,sizeof(*initialUplinkBWP->srs_Config)); - initialUplinkBWP->srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; - NR_SRS_Config_t *srs_Config = calloc(1,sizeof(*srs_Config)); - initialUplinkBWP->srs_Config->choice.setup=srs_Config; - srs_Config->srs_ResourceSetToReleaseList=NULL; - srs_Config->srs_ResourceSetToAddModList=calloc(1,sizeof(*srs_Config->srs_ResourceSetToAddModList)); - NR_SRS_ResourceSet_t *srs_resset0=calloc(1,sizeof(*srs_resset0)); - srs_resset0->srs_ResourceSetId = 0; - srs_resset0->srs_ResourceIdList=calloc(1,sizeof(*srs_resset0->srs_ResourceIdList)); - NR_SRS_ResourceId_t *srs_resset0_id=calloc(1,sizeof(*srs_resset0_id)); - *srs_resset0_id=0; - ASN_SEQUENCE_ADD(&srs_resset0->srs_ResourceIdList->list,srs_resset0_id); - srs_Config->srs_ResourceToReleaseList=NULL; - - if (configuration->do_SRS) { - srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_periodic; - srs_resset0->resourceType.choice.periodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.periodic)); - srs_resset0->resourceType.choice.periodic->associatedCSI_RS = NULL; - } else { - srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_aperiodic; - srs_resset0->resourceType.choice.aperiodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic)); - srs_resset0->resourceType.choice.aperiodic->aperiodicSRS_ResourceTrigger=1; - srs_resset0->resourceType.choice.aperiodic->csi_RS=NULL; - srs_resset0->resourceType.choice.aperiodic->slotOffset= calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic->slotOffset)); - *srs_resset0->resourceType.choice.aperiodic->slotOffset=2; - srs_resset0->resourceType.choice.aperiodic->ext1=NULL; - } - - srs_resset0->usage=NR_SRS_ResourceSet__usage_codebook; - srs_resset0->alpha = calloc(1,sizeof(*srs_resset0->alpha)); - *srs_resset0->alpha = NR_Alpha_alpha1; - srs_resset0->p0=calloc(1,sizeof(*srs_resset0->p0)); - *srs_resset0->p0=-80; - srs_resset0->pathlossReferenceRS=NULL; - srs_resset0->srs_PowerControlAdjustmentStates=NULL; - ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceSetToAddModList->list,srs_resset0); - srs_Config->srs_ResourceToReleaseList=NULL; - srs_Config->srs_ResourceToAddModList=calloc(1,sizeof(*srs_Config->srs_ResourceToAddModList)); - NR_SRS_Resource_t *srs_res0=calloc(1,sizeof(*srs_res0)); - srs_res0->srs_ResourceId=0; - srs_res0->nrofSRS_Ports=NR_SRS_Resource__nrofSRS_Ports_port1; - srs_res0->ptrs_PortIndex=NULL; - srs_res0->transmissionComb.present=NR_SRS_Resource__transmissionComb_PR_n2; - srs_res0->transmissionComb.choice.n2=calloc(1,sizeof(*srs_res0->transmissionComb.choice.n2)); - srs_res0->transmissionComb.choice.n2->combOffset_n2=0; - srs_res0->transmissionComb.choice.n2->cyclicShift_n2=0; - srs_res0->resourceMapping.startPosition = 2 + uid%2; - srs_res0->resourceMapping.nrofSymbols=NR_SRS_Resource__resourceMapping__nrofSymbols_n1; - srs_res0->resourceMapping.repetitionFactor=NR_SRS_Resource__resourceMapping__repetitionFactor_n1; - srs_res0->freqDomainPosition=0; - srs_res0->freqDomainShift=0; - srs_res0->freqHopping.b_SRS=0; - srs_res0->freqHopping.b_hop=0; - srs_res0->freqHopping.c_SRS = rrc_get_max_nr_csrs( - NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, 275), - srs_res0->freqHopping.b_SRS); - srs_res0->groupOrSequenceHopping=NR_SRS_Resource__groupOrSequenceHopping_neither; - - if (configuration->do_SRS) { - srs_res0->resourceType.present= NR_SRS_Resource__resourceType_PR_periodic; - srs_res0->resourceType.choice.periodic=calloc(1,sizeof(*srs_res0->resourceType.choice.periodic)); - srs_res0->resourceType.choice.periodic->periodicityAndOffset_p.present = NR_SRS_PeriodicityAndOffset_PR_sl160; - srs_res0->resourceType.choice.periodic->periodicityAndOffset_p.choice.sl160 = 17 + (uid>1)*10; // 17/17/.../147/157 are mixed slots - } else { - srs_res0->resourceType.present= NR_SRS_Resource__resourceType_PR_aperiodic; - srs_res0->resourceType.choice.aperiodic=calloc(1,sizeof(*srs_res0->resourceType.choice.aperiodic)); - } - - srs_res0->sequenceId=40; - srs_res0->spatialRelationInfo=calloc(1,sizeof(*srs_res0->spatialRelationInfo)); - srs_res0->spatialRelationInfo->servingCellId=NULL; - srs_res0->spatialRelationInfo->referenceSignal.present=NR_SRS_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; - srs_res0->spatialRelationInfo->referenceSignal.choice.csi_RS_Index=0; - ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceToAddModList->list,srs_res0); + config_srs(initialUplinkBWP->srs_Config, scc, uid, configuration->do_SRS); // configure Scheduling request // 40 slot period @@ -1325,13 +1225,13 @@ void fill_initial_SpCellConfig(int uid, bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->maxLength=NULL; bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition)); - *bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1; - bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation = NR_PDSCH_Config__resourceAllocation_resourceAllocationType1; - bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling; - bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling)); - bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = - calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize)); - *bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = NR_PDSCH_Config__prb_BundlingType__staticBundling__bundleSize_wideband; + *bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_AdditionalPosition = NR_DMRS_DownlinkConfig__dmrs_AdditionalPosition_pos1; + bwp_Dedicated->pdsch_Config->choice.setup->resourceAllocation = NR_PDSCH_Config__resourceAllocation_resourceAllocationType1; + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling; + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling = calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling)); + bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = + calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize)); + *bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.choice.staticBundling->bundleSize = NR_PDSCH_Config__prb_BundlingType__staticBundling__bundleSize_wideband; bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList=calloc(1,sizeof(*bwp_Dedicated->pdsch_Config->choice.setup->tci_StatesToAddModList)); NR_TCI_State_t *tcic; @@ -1351,6 +1251,7 @@ void fill_initial_SpCellConfig(int uid, NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig = calloc(1,sizeof(*pdsch_servingcellconfig)); SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->present = NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup; SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; + pdsch_servingcellconfig->codeBlockGroupTransmission = NULL; pdsch_servingcellconfig->xOverhead = NULL; pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH = calloc(1, sizeof(*pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH)); @@ -1452,7 +1353,6 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr ASN_SEQUENCE_ADD(&ue_context_mastercellGroup->rlc_BearerToAddModList->list, rlc_BearerConfig_drb); } - void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq* configuration) { @@ -1476,7 +1376,6 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, } } - void fill_initial_cellGroupConfig(int uid, NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc, diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 54fb5a168b..5bcdf86a95 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -81,7 +81,6 @@ void set_csirs_periodicity(NR_NZP_CSI_RS_Resource_t *nzpcsi0, int uid, int nb_sl } } - void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_CSI_MeasConfig_t *csi_MeasConfig, int uid, @@ -170,6 +169,112 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, csi_MeasConfig->nzp_CSI_RS_ResourceToReleaseList = NULL; } +// TODO: Implement to b_SRS = 1 and b_SRS = 2 +long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { + + if(b_SRS>0) { + LOG_E(NR_RRC,"rrc_get_max_nr_csrs(): Not implemented yet for b_SRS>0\n"); + return 0; // This c_srs is always valid + } + + const uint16_t m_SRS[64] = { 4, 8, 12, 16, 16, 20, 24, 24, 28, 32, 36, 40, 48, 48, 52, 56, 60, 64, 72, 72, 76, 80, 88, + 96, 96, 104, 112, 120, 120, 120, 128, 128, 128, 132, 136, 144, 144, 144, 144, 152, 160, + 160, 160, 168, 176, 184, 192, 192, 192, 192, 208, 216, 224, 240, 240, 240, 240, 256, 256, + 256, 264, 272, 272, 272 }; + + long c_srs = 0; + uint16_t m = 4; + for(int c = 1; c<64; c++) { + if(m_SRS[c]>m && m_SRS[c]present = NR_SetupRelease_SRS_Config_PR_setup; + setup_release_srs_Config->choice.setup = calloc(1,sizeof(*setup_release_srs_Config->choice.setup)); + + NR_SRS_Config_t *srs_Config = setup_release_srs_Config->choice.setup; + + srs_Config->srs_ResourceSetToReleaseList = NULL; + + srs_Config->srs_ResourceSetToAddModList = calloc(1,sizeof(*srs_Config->srs_ResourceSetToAddModList)); + NR_SRS_ResourceSet_t *srs_resset0 = calloc(1,sizeof(*srs_resset0)); + srs_resset0->srs_ResourceSetId = 0; + srs_resset0->srs_ResourceIdList = calloc(1,sizeof(*srs_resset0->srs_ResourceIdList)); + NR_SRS_ResourceId_t *srs_resset0_id = calloc(1,sizeof(*srs_resset0_id)); + *srs_resset0_id = 0; + ASN_SEQUENCE_ADD(&srs_resset0->srs_ResourceIdList->list, srs_resset0_id); + srs_Config->srs_ResourceToReleaseList=NULL; + if (do_srs) { + srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_periodic; + srs_resset0->resourceType.choice.periodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.periodic)); + srs_resset0->resourceType.choice.periodic->associatedCSI_RS = NULL; + } else { + srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_aperiodic; + srs_resset0->resourceType.choice.aperiodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic)); + srs_resset0->resourceType.choice.aperiodic->aperiodicSRS_ResourceTrigger=1; + srs_resset0->resourceType.choice.aperiodic->csi_RS=NULL; + srs_resset0->resourceType.choice.aperiodic->slotOffset = calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic->slotOffset)); + *srs_resset0->resourceType.choice.aperiodic->slotOffset = 2; + srs_resset0->resourceType.choice.aperiodic->ext1 = NULL; + } + srs_resset0->usage=NR_SRS_ResourceSet__usage_codebook; + srs_resset0->alpha = calloc(1,sizeof(*srs_resset0->alpha)); + *srs_resset0->alpha = NR_Alpha_alpha1; + srs_resset0->p0 = calloc(1,sizeof(*srs_resset0->p0)); + *srs_resset0->p0 =-80; + srs_resset0->pathlossReferenceRS = NULL; + srs_resset0->srs_PowerControlAdjustmentStates = NULL; + ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceSetToAddModList->list,srs_resset0); + + srs_Config->srs_ResourceToReleaseList = NULL; + + srs_Config->srs_ResourceToAddModList = calloc(1,sizeof(*srs_Config->srs_ResourceToAddModList)); + NR_SRS_Resource_t *srs_res0=calloc(1,sizeof(*srs_res0)); + srs_res0->srs_ResourceId = 0; + srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_port1; + srs_res0->ptrs_PortIndex = NULL; + srs_res0->transmissionComb.present = NR_SRS_Resource__transmissionComb_PR_n2; + srs_res0->transmissionComb.choice.n2 = calloc(1,sizeof(*srs_res0->transmissionComb.choice.n2)); + srs_res0->transmissionComb.choice.n2->combOffset_n2 = 0; + srs_res0->transmissionComb.choice.n2->cyclicShift_n2 = 0; + srs_res0->resourceMapping.startPosition = 2 + uid%2; + srs_res0->resourceMapping.nrofSymbols = NR_SRS_Resource__resourceMapping__nrofSymbols_n1; + srs_res0->resourceMapping.repetitionFactor = NR_SRS_Resource__resourceMapping__repetitionFactor_n1; + srs_res0->freqDomainPosition = 0; + srs_res0->freqDomainShift = 0; + srs_res0->freqHopping.b_SRS = 0; + srs_res0->freqHopping.b_hop = 0; + srs_res0->freqHopping.c_SRS = rrc_get_max_nr_csrs( + NRRIV2BW(servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, 275), + srs_res0->freqHopping.b_SRS); + srs_res0->groupOrSequenceHopping = NR_SRS_Resource__groupOrSequenceHopping_neither; + if (do_srs) { + srs_res0->resourceType.present = NR_SRS_Resource__resourceType_PR_periodic; + srs_res0->resourceType.choice.periodic = calloc(1,sizeof(*srs_res0->resourceType.choice.periodic)); + srs_res0->resourceType.choice.periodic->periodicityAndOffset_p.present = NR_SRS_PeriodicityAndOffset_PR_sl160; + srs_res0->resourceType.choice.periodic->periodicityAndOffset_p.choice.sl160 = 17 + (uid>1)*10; // 17/17/.../147/157 are mixed slots + } else { + srs_res0->resourceType.present = NR_SRS_Resource__resourceType_PR_aperiodic; + srs_res0->resourceType.choice.aperiodic = calloc(1,sizeof(*srs_res0->resourceType.choice.aperiodic)); + } + srs_res0->sequenceId = 40; + srs_res0->spatialRelationInfo = calloc(1,sizeof(*srs_res0->spatialRelationInfo)); + srs_res0->spatialRelationInfo->servingCellId = NULL; + srs_res0->spatialRelationInfo->referenceSignal.present = NR_SRS_SpatialRelationInfo__referenceSignal_PR_csi_RS_Index; + srs_res0->spatialRelationInfo->referenceSignal.choice.csi_RS_Index = 0; + ASN_SEQUENCE_ADD(&srs_Config->srs_ResourceToAddModList->list,srs_res0); +} + void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, NR_ServingCellConfigCommon_t *scc, int numerology, diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 7a0fe892fd..ff71f73333 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -119,6 +119,10 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, int num_dl_antenna_ports, int curr_bwp, int do_csirs); +void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, + NR_ServingCellConfigCommon_t *servingcellconfigcommon, + int uid, + int do_srs); void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, NR_ServingCellConfigCommon_t *scc); From 70cfd057ec317f6d3cc7b791e1f6156f2ea10ebb Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 4 May 2022 15:09:59 +0100 Subject: [PATCH 03/61] Add do_SRS flag in gnb.sa.band78.fr1.106PRB.usrpb210.conf --- .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index a0cee6f9ca..22f02f66e4 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -34,6 +34,7 @@ gNBs = ssb_SubcarrierOffset = 0; min_rxtxtime = 6; + do_SRS = 1; pdcch_ConfigSIB1 = ( { From 2fb8d96f1153bc229668e127218e01872de32d14 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 4 May 2022 16:25:15 +0100 Subject: [PATCH 04/61] Move SRS config to update_cellGroupConfig() --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 21 ++++++++++++++++++++- openair2/RRC/NR/MESSAGES/asn1_msg.h | 1 + openair2/RRC/NR/nr_rrc_config.c | 29 ++++++++++++++++++++++++----- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index c0676814f7..3e38c772da 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1098,8 +1098,9 @@ void fill_initial_SpCellConfig(int uid, pusch_Config->uci_OnPUSCH=NULL; pusch_Config->tp_pi2BPSK=NULL; + // We are using do_srs = 0 here because the periodic SRS will only be enabled in update_cellGroupConfig() if do_srs == 1 initialUplinkBWP->srs_Config = calloc(1,sizeof(*initialUplinkBWP->srs_Config)); - config_srs(initialUplinkBWP->srs_Config, scc, uid, configuration->do_SRS); + config_srs(initialUplinkBWP->srs_Config, scc, uid, 0); // configure Scheduling request // 40 slot period @@ -1354,6 +1355,7 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr } void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, + int uid, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq* configuration) { @@ -1362,6 +1364,22 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_ServingCellConfigCommon_t *scc = configuration->scc; + if (configuration && + configuration->do_SRS && + SpCellConfig && + SpCellConfig->spCellConfigDedicated && + SpCellConfig->spCellConfigDedicated->uplinkConfig && + SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { + if (!SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config) { + SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config = + calloc(1,sizeof(*SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config)); + } + config_srs(SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config, + scc, + uid, + configuration->do_SRS); + } + NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; set_dl_mcs_table(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing, configuration->force_256qam_off ? NULL : uecap, bwp_Dedicated, scc); @@ -1850,6 +1868,7 @@ int16_t do_RRCReconfiguration( if(cellGroupConfig!=NULL){ update_cellGroupConfig(cellGroupConfig, + ue_context_pP->local_uid, ue_context_pP->ue_context.UE_Capability_nr, configuration); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index aeef5f93a7..f056088da8 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -112,6 +112,7 @@ void fill_initial_cellGroupConfig(int uid, const gNB_RrcConfigurationReq *configuration); void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, + int uid, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 5bcdf86a95..2e44a8022e 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -200,9 +200,27 @@ void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, int do_srs) { setup_release_srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; - setup_release_srs_Config->choice.setup = calloc(1,sizeof(*setup_release_srs_Config->choice.setup)); - NR_SRS_Config_t *srs_Config = setup_release_srs_Config->choice.setup; + NR_SRS_Config_t *srs_Config; + if (setup_release_srs_Config->choice.setup) { + srs_Config = setup_release_srs_Config->choice.setup; + if (srs_Config->srs_ResourceSetToReleaseList) { + free(srs_Config->srs_ResourceSetToReleaseList); + } + if (srs_Config->srs_ResourceSetToAddModList) { + free(srs_Config->srs_ResourceSetToAddModList); + } + if (srs_Config->srs_ResourceToReleaseList) { + free(srs_Config->srs_ResourceToReleaseList); + } + if (srs_Config->srs_ResourceToAddModList) { + free(srs_Config->srs_ResourceToAddModList); + } + free(srs_Config); + } + + setup_release_srs_Config->choice.setup = calloc(1,sizeof(*setup_release_srs_Config->choice.setup)); + srs_Config = setup_release_srs_Config->choice.setup; srs_Config->srs_ResourceSetToReleaseList = NULL; @@ -254,9 +272,10 @@ void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, srs_res0->freqDomainShift = 0; srs_res0->freqHopping.b_SRS = 0; srs_res0->freqHopping.b_hop = 0; - srs_res0->freqHopping.c_SRS = rrc_get_max_nr_csrs( - NRRIV2BW(servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, 275), - srs_res0->freqHopping.b_SRS); + srs_res0->freqHopping.c_SRS = servingcellconfigcommon ? + rrc_get_max_nr_csrs( + NRRIV2BW(servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, 275), + srs_res0->freqHopping.b_SRS) : 0; srs_res0->groupOrSequenceHopping = NR_SRS_Resource__groupOrSequenceHopping_neither; if (do_srs) { srs_res0->resourceType.present = NR_SRS_Resource__resourceType_PR_periodic; From b106913dc0c72a8c276067892e95e81ba6269956 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 5 May 2022 18:10:08 +0100 Subject: [PATCH 05/61] Send SRS measurements (still empty) from PHY to MAC --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 13 +++++++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 12 +++++++ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 12 ++++++- openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 36 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 46816d0373..c071127717 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -829,6 +829,19 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); + uint16_t num_srs = gNB->UL_INFO.srs_ind.number_of_pdus; + gNB->UL_INFO.srs_ind.pdu_list = &gNB->srs_pdu_list[0]; + gNB->UL_INFO.srs_ind.sfn = frame_rx; + gNB->UL_INFO.srs_ind.slot = slot_rx; + //gNB->srs_pdu_list[num_srs].handle; + gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; + //gNB->srs_pdu_list[num_srs].timing_advance; + gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; + //gNB->srs_pdu_list[num_srs].wide_band_snr; + //gNB->srs_pdu_list[num_srs].num_reported_symbols; + //gNB->srs_pdu_list[num_srs].reported_symbol_list; + gNB->UL_INFO.srs_ind.number_of_pdus += 1; + srs->active = 0; } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 72061bb9ba..b3a241af0b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -879,6 +879,18 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, } } +void handle_nr_srs_measurements(const module_id_t module_id, + const frame_t frame, + const sub_frame_t slot, + const rnti_t rnti, + const uint16_t timing_advance, + const uint8_t num_symbols, + const uint8_t wide_band_snr, + const uint8_t num_reported_symbols, + nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list) { + LOG_I(NR_MAC, "(%d.%d) Received SRS indication for rnti: 0x%04x\n", frame, slot, rnti); +} + long get_K2(NR_ServingCellConfigCommon_t *scc, NR_ServingCellConfigCommonSIB_t *scc_sib1, NR_BWP_Uplink_t *ubwp, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 399033abd0..9b299eb1a3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -482,9 +482,19 @@ void handle_nr_ul_harq(const int CC_idP, sub_frame_t slot, const nfapi_nr_crc_t *crc_pdu); +void handle_nr_srs_measurements(const module_id_t module_id, + const frame_t frame, + const sub_frame_t slot, + const rnti_t rnti, + const uint16_t timing_advance, + const uint8_t num_symbols, + const uint8_t wide_band_snr, + const uint8_t num_reported_symbols, + nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list); + int16_t ssb_index_from_prach(module_id_t module_idP, frame_t frameP, - sub_frame_t slotP, + sub_frame_t slotP, uint16_t preamble_index, uint8_t freq_index, uint8_t symbol); diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index 2654988557..4b8edd526f 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -217,6 +217,41 @@ void handle_nr_ulsch(NR_UL_IND_t *UL_info) UL_info->crc_ind.number_crcs = 0; } +void handle_nr_srs(NR_UL_IND_t *UL_info) { + + if(NFAPI_MODE == NFAPI_MODE_PNF) { + if (UL_info->srs_ind.number_of_pdus > 0) { + LOG_D(PHY,"PNF Sending UL_info->srs_ind.number_of_pdus: %d, SFN/SF:%d.%d \n", + UL_info->srs_ind.number_of_pdus, UL_info->frame, UL_info->slot); + oai_nfapi_nr_srs_indication(&UL_info->srs_ind); + UL_info->srs_ind.number_of_pdus = 0; + } + return; + } + + const module_id_t module_id = UL_info->module_id; + const frame_t frame = UL_info->srs_ind.sfn; + const sub_frame_t slot = UL_info->srs_ind.slot; + int num_srs = UL_info->srs_ind.number_of_pdus; + nfapi_nr_srs_indication_pdu_t *srs_list = UL_info->srs_ind.pdu_list; + + for (int i = 0; i < num_srs; i++) { + const nfapi_nr_srs_indication_pdu_t *srs_ind = &srs_list[i]; + LOG_D(NR_PHY, "(%d.%d) UL_info->srs_ind.pdu_list[%d].rnti: 0x%04x\n", frame, slot, i, srs_ind->rnti); + handle_nr_srs_measurements(module_id, + frame, + slot, + srs_ind->rnti, + srs_ind->timing_advance, + srs_ind->num_symbols, + srs_ind->wide_band_snr, + srs_ind->num_reported_symbols, + srs_ind->reported_symbol_list); + } + + UL_info->srs_ind.number_of_pdus = 0; +} + static void free_unqueued_nfapi_indications(nfapi_nr_rach_indication_t *rach_ind, nfapi_nr_uci_indication_t *uci_ind, nfapi_nr_rx_data_indication_t *rx_ind, @@ -436,6 +471,7 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) { // clear UL DCI prior to handling ULSCH mac->UL_dci_req[CC_id].numPdus = 0; handle_nr_ulsch(UL_info); + handle_nr_srs(UL_info); if (get_softmodem_params()->emulate_l1) { free_unqueued_nfapi_indications(rach_ind, uci_ind, rx_ind, crc_ind); From dce83a05089e225706fe8380ae924ae1bf8d3420 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 5 May 2022 19:49:06 +0100 Subject: [PATCH 06/61] Add comments in FAPI for SRS indication --- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index c3a173758c..0326bd20b1 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1665,41 +1665,34 @@ typedef struct } nfapi_nr_uci_indication_t; -//3.4.10 srs_indication -//table 3-73 -typedef struct -{ - uint8_t rb_snr; -}nfapi_nr_srs_indication_reported_symbol_resource_block_t; +/// 5G PHY FAPI Specification: SRS indication - Section 3.4.10, Table 3-73 -typedef struct -{ - uint16_t num_rbs; +typedef struct { + uint8_t rb_snr; // SNR value in dB. Value: 0 -> 255 representing -64 dB to 63 dB with a step size 0.5 dB, 0xff will be set if this field is invalid. +} nfapi_nr_srs_indication_reported_symbol_resource_block_t; + +typedef struct { + uint16_t num_rbs; // Number of PRBs to be reported for this SRS PDU. Value: 0 -> 272. nfapi_nr_srs_indication_reported_symbol_resource_block_t* rb_list; -}nfapi_nr_srs_indication_reported_symbol_t; +} nfapi_nr_srs_indication_reported_symbol_t; -#define NFAPI_NR_SRS_IND_MAX_PDU 100 -typedef struct -{ - uint32_t handle; - uint16_t rnti; - uint16_t timing_advance; - uint8_t num_symbols; - uint8_t wide_band_snr; - uint8_t num_reported_symbols; +typedef struct { + uint32_t handle; // The handle passed to the PHY in the the UL_TTI.request SRS PDU. + uint16_t rnti; // The RNTI passed to the PHY in the UL_TTI.request SRS PDU. Value: 1 -> 65535. + uint16_t timing_advance; // Timing advance TA measured for the UE [TS 38.213, Section 4.2]. NTA_new = NTA_old + (TA − 31) * 16 * 64 / (2^u). Value: 0 -> 63. 0xffff should be set if this field is invalid. + uint8_t num_symbols; // Number of symbols for SRS. Value: 1 -> 4. If a PHY does not report for individual symbols then this parameter should be set to 1. + uint8_t wide_band_snr; // SNR value in dB measured within configured SRS bandwidth on each symbol. Value: 0 -> 255 representing -64 dB to 63 dB with a step size 0.5 dB. 0xff will be set if this field is invalid. + uint8_t num_reported_symbols; // Number of symbols reported in this message. This allows PHY to report individual symbols or aggregated symbols where this field will be set to 1. Value: 1 -> 4. nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list; +} nfapi_nr_srs_indication_pdu_t; -}nfapi_nr_srs_indication_pdu_t; - -typedef struct -{ +typedef struct { nfapi_p7_message_header_t header; - uint16_t sfn; - uint16_t slot; - uint8_t number_of_pdus; + uint16_t sfn; // SFN. Value: 0 -> 1023 + uint16_t slot; // Slot. Value: 0 -> 159 + uint8_t number_of_pdus; // Number of PDUs included in this message. Value: 0 -> 255 nfapi_nr_srs_indication_pdu_t* pdu_list; - } nfapi_nr_srs_indication_t; From dcf4fd1db2270e1780680712e905f964a83d44ee Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Fri, 6 May 2022 19:07:59 +0100 Subject: [PATCH 07/61] Compute the noise power per RB --- openair1/PHY/INIT/nr_init.c | 1 + .../NR_ESTIMATION/nr_ul_channel_estimation.c | 45 +++++++++++++++++++ openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 1 + openair1/PHY/defs_nr_common.h | 1 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 1 + 5 files changed, 49 insertions(+) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 9ffc0f75ad..64bbdfa487 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -618,6 +618,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, gNB->nr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); gNB->nr_srs_info[id]->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); gNB->nr_srs_info[id]->srs_generated_signal = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); + gNB->nr_srs_info[id]->noise_power_per_rb = (uint32_t*)malloc16_clear(fp->N_RB_UL*sizeof(uint32_t)); gNB->nr_srs_info[id]->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 4a6f8ef9af..ffdf07860d 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1099,6 +1099,7 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, int32_t **srs_estimated_channel_freq, int32_t **srs_estimated_channel_time, int32_t **srs_estimated_channel_time_shifted, + uint32_t *noise_power_per_rb, uint32_t *noise_power) { if(nr_srs_info->sc_list_length == 0) { @@ -1216,6 +1217,50 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, (gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t)); } + // Compute noise power + + uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*12; + uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; + uint8_t n_noise_estimates = frame_parms->nb_antennas_rx*srs_symbols_per_rb; + uint8_t count_estimates = 0; + uint64_t sum_re = 0; + uint64_t sum_re2 = 0; + uint64_t sum_im = 0; + uint64_t sum_im2 = 0; + + for (int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { + + int subcarrier0 = nr_srs_info->sc_list[sc_idx]-subcarrier_offset; + if(subcarrier0 < 0) { + subcarrier0 = subcarrier0 + frame_parms->ofdm_symbol_size; + } + int rb = subcarrier0/NR_NB_SC_PER_RB; + + for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { + + sum_re = sum_re + noise_real[ant*nr_srs_info->sc_list_length+sc_idx]; + sum_re2 = sum_re2 + noise_real[ant*nr_srs_info->sc_list_length+sc_idx]*noise_real[ant*nr_srs_info->sc_list_length+sc_idx]; + sum_im = sum_im + noise_imag[ant*nr_srs_info->sc_list_length+sc_idx]; + sum_im2 = sum_im2 + noise_imag[ant*nr_srs_info->sc_list_length+sc_idx]*noise_imag[ant*nr_srs_info->sc_list_length+sc_idx]; + + count_estimates++; + if (count_estimates == n_noise_estimates) { + noise_power_per_rb[rb] = sum_re2/n_noise_estimates - (sum_re/n_noise_estimates)*(sum_re/n_noise_estimates) + + sum_im2/n_noise_estimates - (sum_im/n_noise_estimates)*(sum_im/n_noise_estimates); + count_estimates = 0; + sum_re = 0; + sum_re2 = 0; + sum_im = 0; + sum_im2 = 0; + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"noise_power_per_rb[%i] = %i\n", rb, noise_power_per_rb[rb]); +#endif + + } + } + } + *noise_power = calc_power(noise_real,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length) + calc_power(noise_imag,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index a01106adb5..9c7d67b25d 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -73,5 +73,6 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, int32_t **srs_estimated_channel_freq, int32_t **srs_estimated_channel_time, int32_t **srs_estimated_channel_time_shifted, + uint32_t *noise_power_per_rb, uint32_t *noise_power); #endif diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index b24abd7de3..80842eef38 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -244,6 +244,7 @@ typedef struct { int32_t **srs_estimated_channel_freq; int32_t **srs_estimated_channel_time; int32_t **srs_estimated_channel_time_shifted; + uint32_t *noise_power_per_rb; uint32_t *noise_power; } nr_srs_info_t; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index c9f4cf7b33..aa75cc64ef 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -834,6 +834,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, + gNB->nr_srs_info[i]->noise_power_per_rb, gNB->nr_srs_info[i]->noise_power); T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), From ab6d7afd09b02963ba345c983acef44acfdf8322 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 9 May 2022 15:54:20 +0100 Subject: [PATCH 08/61] Compute the SNR per RB using the SRS --- openair1/PHY/INIT/nr_init.c | 2 + .../NR_ESTIMATION/nr_ul_channel_estimation.c | 37 ++++++++++++++----- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 4 +- openair1/PHY/defs_nr_common.h | 2 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 4 +- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 64bbdfa487..21ebcc1405 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -618,8 +618,10 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, gNB->nr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); gNB->nr_srs_info[id]->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); gNB->nr_srs_info[id]->srs_generated_signal = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); + gNB->nr_srs_info[id]->signal_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); gNB->nr_srs_info[id]->noise_power_per_rb = (uint32_t*)malloc16_clear(fp->N_RB_UL*sizeof(uint32_t)); gNB->nr_srs_info[id]->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); + gNB->nr_srs_info[id]->snr_per_rb = (int8_t*)malloc16_clear(fp->N_RB_UL*sizeof(int8_t)); gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_estimated_channel_freq = (int32_t **)malloc16(Prx*sizeof(int32_t*)); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index ffdf07860d..8db33e3e18 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1079,9 +1079,9 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, }//Antenna loop } -uint32_t calc_power(uint16_t *x, uint32_t size) { - uint64_t sum_x = 0; - uint64_t sum_x2 = 0; +uint32_t calc_power(const int16_t *x, uint32_t size) { + int64_t sum_x = 0; + int64_t sum_x2 = 0; for(int k = 0; ksc_list_length == 0) { LOG_E(NR_PHY, "(%d.%d) nr_srs_info was not generated yet!\n", frame, slot); @@ -1110,8 +1112,10 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; int32_t **srs_ls_estimated_channel = nr_srs_info->srs_ls_estimated_channel; - uint16_t noise_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; - uint16_t noise_imag[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; + int16_t ch_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; + int16_t ch_imag[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; + int16_t noise_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; + int16_t noise_imag[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; int16_t ls_estimated[2]; @@ -1199,8 +1203,10 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, // Compute noise for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { - noise_real[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)((srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]]-srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]]) & 0xFFFF)); - noise_imag[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)(((srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]]-srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]]) >> 16) & 0xFFFF)); + ch_real[ant*nr_srs_info->sc_list_length + sc_idx] = (int16_t)(srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF); + ch_imag[ant*nr_srs_info->sc_list_length + sc_idx] = (int16_t)((srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF); + noise_real[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)(srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF) - ch_real[ant*nr_srs_info->sc_list_length + sc_idx]); + noise_imag[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)((srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF) - ch_imag[ant*nr_srs_info->sc_list_length + sc_idx]); } // Convert to time domain @@ -1217,8 +1223,20 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, (gNB->frame_parms.ofdm_symbol_size>>1)*sizeof(int32_t)); } + // Compute signal power + *signal_power = calc_power(ch_real,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length) + + calc_power(ch_imag,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length); + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"signal_power = %u\n", *signal_power); +#endif + // Compute noise power + uint8_t signal_power_bits = log2_approx(*signal_power); + uint8_t factor_bits = signal_power_bits < 32 ? 32 - signal_power_bits : 0; // 32 due to input of dB_fixed(uint32_t x) + int32_t factor_dB = dB_fixed(1<first_carrier_offset + srs_pdu->bwp_start*12; uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; uint8_t n_noise_estimates = frame_parms->nb_antennas_rx*srs_symbols_per_rb; @@ -1247,6 +1265,7 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, if (count_estimates == n_noise_estimates) { noise_power_per_rb[rb] = sum_re2/n_noise_estimates - (sum_re/n_noise_estimates)*(sum_re/n_noise_estimates) + sum_im2/n_noise_estimates - (sum_im/n_noise_estimates)*(sum_im/n_noise_estimates); + snr_per_rb[rb] = dB_fixed((int32_t)((*signal_power<nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, + gNB->nr_srs_info[i]->signal_power, gNB->nr_srs_info[i]->noise_power_per_rb, - gNB->nr_srs_info[i]->noise_power); + gNB->nr_srs_info[i]->noise_power, + gNB->nr_srs_info[i]->snr_per_rb); T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_freq[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); From d914817806a331335cf40dde50cfedf54cd57db2 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 9 May 2022 17:58:42 +0100 Subject: [PATCH 09/61] Fill srs_reported_symbol_list in SRS indication --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 49 ++++++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index b342b87fa8..597b165f9e 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -45,6 +45,7 @@ #include "intertask_interface.h" //#define DEBUG_RXDATA +//#define SRS_IND_DEBUG uint8_t SSB_Table[38]={0,2,4,6,8,10,12,14,254,254,16,18,20,22,24,26,28,30,254,254,32,34,36,38,40,42,44,46,254,254,48,50,52,54,56,58,60,62}; @@ -624,6 +625,30 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) } +int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list, + nfapi_nr_srs_pdu_t *srs_pdu, + int N_RB_UL, + const int8_t *snr_per_rb) { + + reported_symbol_list->num_rbs = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0]; + + if (!reported_symbol_list->rb_list) { + reported_symbol_list->rb_list = (nfapi_nr_srs_indication_reported_symbol_resource_block_t*) calloc(1, N_RB_UL*sizeof(nfapi_nr_srs_indication_reported_symbol_resource_block_t)); + } + + for(int rb = 0; rb < reported_symbol_list->num_rbs; rb++) { + if (snr_per_rb[rb] < -64) { + reported_symbol_list->rb_list[rb].rb_snr = 0; + } else if (snr_per_rb[rb] > 63) { + reported_symbol_list->rb_list[rb].rb_snr = 255; + } else { + reported_symbol_list->rb_list[rb].rb_snr = (snr_per_rb[rb] + 64)<<1; + } + } + + return 0; +} + int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { /* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */ int pucch_decode_done = 0; @@ -854,10 +879,30 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { //gNB->srs_pdu_list[num_srs].timing_advance; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; //gNB->srs_pdu_list[num_srs].wide_band_snr; - //gNB->srs_pdu_list[num_srs].num_reported_symbols; - //gNB->srs_pdu_list[num_srs].reported_symbol_list; + gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; + if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { + gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); + } + fill_srs_reported_symbol_list(&gNB->srs_pdu_list[num_srs].reported_symbol_list[0], + srs_pdu, + gNB->frame_parms.N_RB_UL, + gNB->nr_srs_info[i]->snr_per_rb); + gNB->UL_INFO.srs_ind.number_of_pdus += 1; +#ifdef SRS_IND_DEBUG + LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.sfn = %i\n", gNB->UL_INFO.srs_ind.sfn); + LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.slot = %i\n", gNB->UL_INFO.srs_ind.slot); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].rnti = 0x%04x\n", num_srs, gNB->srs_pdu_list[num_srs].rnti); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_symbols); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_reported_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_reported_symbols); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].reported_symbol_list[0].num_rbs = %i\n", num_srs, gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs); + for(int rb = 0; rb < gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs; rb++) { + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].reported_symbol_list[0].rb_list[%3i].rb_snr = %i\n", + num_srs, rb, gNB->srs_pdu_list[num_srs].reported_symbol_list[0].rb_list[rb].rb_snr); + } +#endif + srs->active = 0; } } From bdff42cf77e5a304f5337472b7a75c8758dceb75 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 9 May 2022 18:21:04 +0100 Subject: [PATCH 10/61] Compute and fill wide_band_snr field for SRS indication --- openair1/PHY/INIT/nr_init.c | 1 + openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 7 +++++-- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 3 ++- openair1/PHY/defs_nr_common.h | 1 + openair1/SCHED_NR/phy_procedures_nr_gNB.c | 8 +++++--- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 21ebcc1405..1722dfb861 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -622,6 +622,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, gNB->nr_srs_info[id]->noise_power_per_rb = (uint32_t*)malloc16_clear(fp->N_RB_UL*sizeof(uint32_t)); gNB->nr_srs_info[id]->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); gNB->nr_srs_info[id]->snr_per_rb = (int8_t*)malloc16_clear(fp->N_RB_UL*sizeof(int8_t)); + gNB->nr_srs_info[id]->snr = (int8_t*)malloc16_clear(sizeof(int8_t)); gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_estimated_channel_freq = (int32_t **)malloc16(Prx*sizeof(int32_t*)); diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 8db33e3e18..4ff9952077 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1102,7 +1102,8 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, uint32_t *signal_power, uint32_t *noise_power_per_rb, uint32_t *noise_power, - int8_t *snr_per_rb) { + int8_t *snr_per_rb, + int8_t *snr) { if(nr_srs_info->sc_list_length == 0) { LOG_E(NR_PHY, "(%d.%d) nr_srs_info was not generated yet!\n", frame, slot); @@ -1283,6 +1284,8 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, *noise_power = calc_power(noise_real,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length) + calc_power(noise_imag,frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length); + *snr = dB_fixed((int32_t)((*signal_power<first_carrier_offset + srs_pdu->bwp_start*12; uint8_t R = srs_pdu->comb_size == 0 ? 2 : 4; @@ -1312,7 +1315,7 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, } } - LOG_I(NR_PHY,"noise_power = %u\n", *noise_power); + LOG_I(NR_PHY,"noise_power = %u, SNR = %i dB\n", *noise_power, *snr); #endif return 0; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index f7ac055dcc..38b6556948 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -76,5 +76,6 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, uint32_t *signal_power, uint32_t *noise_power_per_rb, uint32_t *noise_power, - int8_t *snr_per_rb); + int8_t *snr_per_rb, + int8_t *snr); #endif diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 4109b13831..a30baabd10 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -248,6 +248,7 @@ typedef struct { uint32_t *noise_power_per_rb; uint32_t *noise_power; int8_t *snr_per_rb; + int8_t *snr; } nr_srs_info_t; typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 597b165f9e..b8aa108f10 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -862,7 +862,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->nr_srs_info[i]->signal_power, gNB->nr_srs_info[i]->noise_power_per_rb, gNB->nr_srs_info[i]->noise_power, - gNB->nr_srs_info[i]->snr_per_rb); + gNB->nr_srs_info[i]->snr_per_rb, + gNB->nr_srs_info[i]->snr); T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_freq[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); @@ -874,11 +875,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->UL_INFO.srs_ind.pdu_list = &gNB->srs_pdu_list[0]; gNB->UL_INFO.srs_ind.sfn = frame_rx; gNB->UL_INFO.srs_ind.slot = slot_rx; - //gNB->srs_pdu_list[num_srs].handle; + gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; //gNB->srs_pdu_list[num_srs].timing_advance; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; - //gNB->srs_pdu_list[num_srs].wide_band_snr; + gNB->srs_pdu_list[num_srs].wide_band_snr = (*gNB->nr_srs_info[i]->snr + 64)<<1; gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); @@ -895,6 +896,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.slot = %i\n", gNB->UL_INFO.srs_ind.slot); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].rnti = 0x%04x\n", num_srs, gNB->srs_pdu_list[num_srs].rnti); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_symbols); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].wide_band_snr = %i\n", num_srs, gNB->srs_pdu_list[num_srs].wide_band_snr); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_reported_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_reported_symbols); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].reported_symbol_list[0].num_rbs = %i\n", num_srs, gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs); for(int rb = 0; rb < gNB->srs_pdu_list[num_srs].reported_symbol_list[0].num_rbs; rb++) { From 99b262d7647121cdaa786e9402d07eda88904ea2 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 9 May 2022 19:25:33 +0100 Subject: [PATCH 11/61] Compute and fill timing_advance field for SRS indication --- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 43 +++++++++++++++++++ openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 3 ++ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 3 +- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index fb56322e54..a2ee62fbde 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -67,6 +67,49 @@ int nr_est_timing_advance_pusch(PHY_VARS_gNB* gNB, int UE_id) return max_pos - sync_pos; } +int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, + int32_t **srs_estimated_channel_time) { + int timing_advance = 0; + int max_val = 0; + + for (int i = 0; i < frame_parms->ofdm_symbol_size; i++) { + int temp = 0; + for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + int Re = ((int16_t*)srs_estimated_channel_time[aa])[(i<<1)]; + int Im = ((int16_t*)srs_estimated_channel_time[aa])[1+(i<<1)]; + temp += (Re*Re/2) + (Im*Im/2); + } + if (temp > max_val) { + timing_advance = i; + max_val = temp; + } + } + + if (timing_advance > frame_parms->ofdm_symbol_size/2) { + timing_advance = timing_advance - frame_parms->ofdm_symbol_size; + } + + // Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size + uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 11; + + // do some integer rounding to improve TA accuracy + int sync_pos_rounded; + if (timing_advance > 0) { + sync_pos_rounded = timing_advance + (bw_scaling >> 1) - 1; + } else { + sync_pos_rounded = timing_advance - (bw_scaling >> 1) + 1; + } + + int timing_advance_update = sync_pos_rounded / bw_scaling; + + // put timing advance command in 0..63 range + timing_advance_update += 31; + + if (timing_advance_update < 0) timing_advance_update = 0; + if (timing_advance_update > 63) timing_advance_update = 63; + + return timing_advance_update; +} void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB) { diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 38b6556948..914b0d7385 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -55,6 +55,9 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t ulsch_id, unsigned char harq int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id); +int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, + int32_t **srs_estimated_channel_time); + void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, nfapi_nr_pusch_pdu_t *rel15_ul, diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index b8aa108f10..4e75090d4b 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -877,7 +877,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->UL_INFO.srs_ind.slot = slot_rx; gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; - //gNB->srs_pdu_list[num_srs].timing_advance; + gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, gNB->nr_srs_info[i]->srs_estimated_channel_time); gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; gNB->srs_pdu_list[num_srs].wide_band_snr = (*gNB->nr_srs_info[i]->snr + 64)<<1; gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; @@ -895,6 +895,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.sfn = %i\n", gNB->UL_INFO.srs_ind.sfn); LOG_I(NR_PHY, "gNB->UL_INFO.srs_ind.slot = %i\n", gNB->UL_INFO.srs_ind.slot); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].rnti = 0x%04x\n", num_srs, gNB->srs_pdu_list[num_srs].rnti); + LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].timing_advance = %i\n", num_srs, gNB->srs_pdu_list[num_srs].timing_advance); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_symbols); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].wide_band_snr = %i\n", num_srs, gNB->srs_pdu_list[num_srs].wide_band_snr); LOG_I(NR_PHY, "gNB->srs_pdu_list[%i].num_reported_symbols = %i\n", num_srs, gNB->srs_pdu_list[num_srs].num_reported_symbols); From 61a2f398db15e386981bd4e523f1f423049a8bcb Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 10 May 2022 10:43:24 +0100 Subject: [PATCH 12/61] Add LOGs of SRS indication in handle_nr_srs_measurements --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 03cb48e5da..e763548ea3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -37,6 +37,8 @@ #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h" +//#define SRS_IND_DEBUG + int get_dci_format(NR_UE_sched_ctrl_t *sched_ctrl) { int dci_format = sched_ctrl->search_space && sched_ctrl->search_space->searchSpaceType && @@ -887,7 +889,23 @@ void handle_nr_srs_measurements(const module_id_t module_id, const uint8_t wide_band_snr, const uint8_t num_reported_symbols, nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list) { + LOG_I(NR_MAC, "(%d.%d) Received SRS indication for rnti: 0x%04x\n", frame, slot, rnti); + +#ifdef SRS_IND_DEBUG + LOG_I(NR_MAC, "frame = %i\n", frame); + LOG_I(NR_MAC, "slot = %i\n", slot); + LOG_I(NR_MAC, "rnti = 0x%04x\n", rnti); + LOG_I(NR_MAC, "timing_advance = %i\n", timing_advance); + LOG_I(NR_MAC, "num_symbols = %i\n", num_symbols); + LOG_I(NR_MAC, "wide_band_snr = %i (%i dB)\n", wide_band_snr, (wide_band_snr>>1)-64); + LOG_I(NR_MAC, "num_reported_symbols = %i\n", num_reported_symbols); + LOG_I(NR_MAC, "reported_symbol_list[0].num_rbs = %i\n", reported_symbol_list[0].num_rbs); + for(int rb = 0; rb < reported_symbol_list[0].num_rbs; rb++) { + LOG_I(NR_MAC, "reported_symbol_list[0].rb_list[%3i].rb_snr = %i (%i dB)\n", + rb, reported_symbol_list[0].rb_list[rb].rb_snr, (reported_symbol_list[0].rb_list[rb].rb_snr>>1)-64); + } +#endif } long get_K2(NR_ServingCellConfigCommon_t *scc, From 5ed67b85a78b4ff7be4dda5b2c93b8b3207bd24f Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 10 May 2022 13:03:41 +0100 Subject: [PATCH 13/61] Free allocated memory --- openair1/PHY/INIT/nr_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 1722dfb861..e2f549f12e 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -788,7 +788,11 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) } free_and_zero(gNB->nr_srs_info[id]->sc_list); free_and_zero(gNB->nr_srs_info[id]->srs_generated_signal); + free_and_zero(gNB->nr_srs_info[id]->signal_power); + free_and_zero(gNB->nr_srs_info[id]->noise_power_per_rb); free_and_zero(gNB->nr_srs_info[id]->noise_power); + free_and_zero(gNB->nr_srs_info[id]->snr_per_rb); + free_and_zero(gNB->nr_srs_info[id]->snr); free_and_zero(gNB->nr_srs_info[id]->srs_received_signal); free_and_zero(gNB->nr_srs_info[id]->srs_ls_estimated_channel); free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_freq); From 08975e451fd9110ff6401589d45437c5cdb5115e Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 10 May 2022 14:03:24 +0100 Subject: [PATCH 14/61] Update the ul_prbblacklist based on SRS measurements and an ul_prbblack_SNR_threshold --- openair2/GNB_APP/MACRLC_nr_paramdef.h | 21 +++++++++++-------- openair2/GNB_APP/gnb_config.c | 1 + .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 14 ++++++++++++- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 4 +++- ...gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf | 1 + .../gnb.sa.band78.fr1.106PRB.usrpb210.conf | 1 + 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index e634f077e2..3cc0396a3e 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -58,6 +58,7 @@ #define CONFIG_STRING_MACRLC_ULSCH_MAX_FRAME_INACTIVITY "ulsch_max_frame_inactivity" #define CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10 "pusch_TargetSNRx10" #define CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10 "pucch_TargetSNRx10" +#define CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD "ul_prbblack_SNR_threshold" #define CONFIG_STRING_MACRLC_PUCCHFAILURETHRES "pucch_FailureThres" #define CONFIG_STRING_MACRLC_PUSCHFAILURETHRES "pusch_FailureThres" #define CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER "dl_bler_target_upper" @@ -93,6 +94,7 @@ {CONFIG_STRING_MACRLC_ULSCH_MAX_FRAME_INACTIVITY, NULL, 0, uptr:NULL, defintval:10, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \ +{CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER, "Upper threshold of BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.15, TYPE_DOUBLE, 0}, \ @@ -123,14 +125,15 @@ #define MACRLC_ULSCH_MAX_FRAME_INACTIVITY 17 #define MACRLC_PUSCHTARGETSNRX10_IDX 18 #define MACRLC_PUCCHTARGETSNRX10_IDX 19 -#define MACRLC_PUCCHFAILURETHRES_IDX 20 -#define MACRLC_PUSCHFAILURETHRES_IDX 21 -#define MACRLC_DL_BLER_TARGET_UPPER_IDX 22 -#define MACRLC_DL_BLER_TARGET_LOWER_IDX 23 -#define MACRLC_DL_RD2_BLER_THRESHOLD_IDX 24 -#define MACRLC_DL_MAX_MCS_IDX 25 -#define MACRLC_HARQ_ROUND_MAX_IDX 26 -#define MACRLC_MIN_GRANT_PRB_IDX 27 -#define MACRLC_MIN_GRANT_MCS_IDX 28 +#define MACRLC_UL_PRBBLACK_SNR_THRESHOLD_IDX 20 +#define MACRLC_PUCCHFAILURETHRES_IDX 21 +#define MACRLC_PUSCHFAILURETHRES_IDX 22 +#define MACRLC_DL_BLER_TARGET_UPPER_IDX 23 +#define MACRLC_DL_BLER_TARGET_LOWER_IDX 24 +#define MACRLC_DL_RD2_BLER_THRESHOLD_IDX 25 +#define MACRLC_DL_MAX_MCS_IDX 26 +#define MACRLC_HARQ_ROUND_MAX_IDX 27 +#define MACRLC_MIN_GRANT_PRB_IDX 28 +#define MACRLC_MIN_GRANT_MCS_IDX 29 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 62dc72a857..530725bb51 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -770,6 +770,7 @@ void RCconfig_nr_macrlc() { 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); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index e763548ea3..39a6f52327 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -890,7 +890,7 @@ void handle_nr_srs_measurements(const module_id_t module_id, const uint8_t num_reported_symbols, nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list) { - LOG_I(NR_MAC, "(%d.%d) Received SRS indication for rnti: 0x%04x\n", frame, slot, rnti); + LOG_D(NR_MAC, "(%d.%d) Received SRS indication for rnti: 0x%04x\n", frame, slot, rnti); #ifdef SRS_IND_DEBUG LOG_I(NR_MAC, "frame = %i\n", frame); @@ -906,6 +906,18 @@ void handle_nr_srs_measurements(const module_id_t module_id, rb, reported_symbol_list[0].rb_list[rb].rb_snr, (reported_symbol_list[0].rb_list[rb].rb_snr>>1)-64); } #endif + + int ul_prbblack_SNR_threshold = RC.nrmac[module_id]->ul_prbblack_SNR_threshold; + uint16_t *ulprbbl = RC.nrmac[module_id]->ulprbbl; + + memset(ulprbbl, 0, reported_symbol_list[0].num_rbs*sizeof(uint16_t)); + for (int rb = 0; rb < reported_symbol_list[0].num_rbs; rb++) { + int snr = (reported_symbol_list[0].rb_list[rb].rb_snr>>1)-64; + if (snr < ul_prbblack_SNR_threshold) { + ulprbbl[rb] = 0x3FFF; // all symbols taken + } + LOG_D(NR_MAC, "ulprbbl[%3i] = 0x%x\n", rb, ulprbbl[rb]); + } } long get_K2(NR_ServingCellConfigCommon_t *scc, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index a2c77234c0..5ddeacf4ed 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -721,6 +721,8 @@ typedef struct gNB_MAC_INST_s { int pusch_target_snrx10; /// Pucch target SNR int pucch_target_snrx10; + /// SNR threshold needed to put or not a PRB in the black list + int ul_prbblack_SNR_threshold; /// PUCCH Failure threshold (compared to consecutive PUCCH DTX) int pucch_failure_thres; /// PUSCH Failure threshold (compared to consecutive PUSCH DTX) @@ -735,7 +737,7 @@ typedef struct gNB_MAC_INST_s { /// current PDU index (BCH,DLSCH) uint16_t pdu_index[NFAPI_CC_MAX]; int num_ulprbbl; - uint16_t ulprbbl[275]; + uint16_t ulprbbl[MAX_BWP_SIZE]; /// NFAPI Config Request Structure nfapi_nr_config_request_scf_t config[NFAPI_CC_MAX]; /// NFAPI DL Config Request Structure diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index 2881a77d48..33c7353151 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -207,6 +207,7 @@ MACRLCs = ( tr_n_preference = "local_RRC"; #pusch_TargetSNRx10 = 150; #pucch_TargetSNRx10 = 200; + ul_prbblack_SNR_threshold = 10; ulsch_max_frame_inactivity = 0; } ); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index c83565e8bb..12feb0d4b0 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -205,6 +205,7 @@ MACRLCs = ( tr_n_preference = "local_RRC"; pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; + ul_prbblack_SNR_threshold = 10; ulsch_max_frame_inactivity = 0; } ); From ba5bda5c6e25c3d4674394f32a753360249f8d32 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 10 May 2022 15:00:43 +0100 Subject: [PATCH 15/61] Fix bw_scaling --- openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index a2ee62fbde..403a96983c 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -90,7 +90,7 @@ int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, } // Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size - uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 11; + uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 7; // do some integer rounding to improve TA accuracy int sync_pos_rounded; From 9e2086c77c4ce562fcd22fcd4c379927ac9a0c46 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 18 May 2022 12:51:18 +0100 Subject: [PATCH 16/61] Fix warning after merge --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 1e019a4744..906a5d2d6c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -840,12 +840,13 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, mappingtype, add_pos, dmrslength, pusch_config_pdu->start_symbol_index, mac->scc ? mac->scc->dmrs_TypeA_Position : mac->mib->dmrs_TypeA_Position); - if ((mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled)) + if ((mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled)) { if (*dci_format != NR_UL_DCI_FORMAT_0_1) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; } - else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) + } else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; + } // Num PRB Overhead from PUSCH-ServingCellConfig if (mac->cg && From 0eeb174253f93847e5990adf2ea210345ec28eed Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 23 May 2022 11:43:32 +0100 Subject: [PATCH 17/61] Add wideband SNR based on SRS in MAC stats --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 15 +++++++++++++-- openair2/LAYER2/NR_MAC_gNB/main.c | 5 +++-- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 7c61eb3b5a..38e6ca0d6f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -907,8 +907,19 @@ void handle_nr_srs_measurements(const module_id_t module_id, } #endif - int ul_prbblack_SNR_threshold = RC.nrmac[module_id]->ul_prbblack_SNR_threshold; - uint16_t *ulprbbl = RC.nrmac[module_id]->ulprbbl; + const int UE_id = find_nr_UE_id(module_id,rnti); + if (UE_id < 0) { + LOG_W(NR_MAC, "Could not find UE for RNTI 0x%04x\n", rnti); + return; + } + + gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; + NR_UE_info_t *UE_info = &nr_mac->UE_info; + NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + stats->srs_wide_band_snr = (wide_band_snr>>1)-64; + + int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; + uint16_t *ulprbbl = nr_mac->ulprbbl; memset(ulprbbl, 0, reported_symbol_list[0].num_rbs*sizeof(uint16_t)); for (int rb = 0; rb < reported_symbol_list[0].num_rbs; rb++) { diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index e047494b52..b7bf30f056 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -84,7 +84,7 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp const NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; - stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n", + stroff+=sprintf(output+stroff,"UE ID %d RNTI %04x (%d/%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas), UL-SNR %d dB\n", UE_id, UE_info->rnti[UE_id], num++, @@ -92,7 +92,8 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp sched_ctrl->ph, sched_ctrl->pcmax, avg_rsrp, - stats->num_rsrp_meas); + stats->num_rsrp_meas, + stats->srs_wide_band_snr); stroff+=sprintf(output+stroff,"UE %d: CQI %d, RI %d, PMI (%d,%d)\n", UE_id, UE_info->UE_sched_ctrl[UE_id].CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index b2b6d3d516..4e896c2f49 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -690,6 +690,7 @@ typedef struct { uint32_t pucch0_DTX; int cumul_rsrp; uint8_t num_rsrp_meas; + int8_t srs_wide_band_snr; } NR_mac_stats_t; From 5092eca8cbd6d0d5e877593a37f9f4e99289e3ab Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Mon, 23 May 2022 13:30:38 +0100 Subject: [PATCH 18/61] Some robustness improvements --- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 5 +++ openair1/PHY/NR_TRANSPORT/srs_rx.c | 13 +++++- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 42 +++++++++++-------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 3 +- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index be2d03d0db..70a06d4727 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1089,6 +1089,11 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, LOG_I(NR_PHY,"signal_power = %u\n", *signal_power); #endif + if (*signal_power == 0) { + LOG_W(NR_PHY, "Received SRS signal power is 0\n"); + return -1; + } + // Compute noise power uint8_t signal_power_bits = log2_approx(*signal_power); diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 2d7aefdee0..ffcd7362f3 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -113,6 +113,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, uint64_t symbol_offset = (n_symbols+l0)*frame_parms->ofdm_symbol_size; int32_t *rx_signal; + bool no_srs_signal = true; for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { memset(srs_received_signal[ant], 0, frame_parms->ofdm_symbol_size*sizeof(int32_t)); @@ -121,6 +122,10 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { srs_received_signal[ant][nr_srs_info->sc_list[sc_idx]] = rx_signal[nr_srs_info->sc_list[sc_idx]]; + if (rx_signal[nr_srs_info->sc_list[sc_idx]] != 0) { + no_srs_signal = false; + } + #ifdef SRS_DEBUG uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*12; int subcarrier_log = nr_srs_info->sc_list[sc_idx]-subcarrier_offset; @@ -140,5 +145,11 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, #endif } } - return 0; + + if (no_srs_signal) { + LOG_W(NR_PHY, "No SRS signal\n"); + return -1; + } else { + return 0; + } } \ No newline at end of file diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 84370f2509..a8e5f84d9c 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -636,7 +636,8 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list, nfapi_nr_srs_pdu_t *srs_pdu, int N_RB_UL, - const int8_t *snr_per_rb) { + const int8_t *snr_per_rb, + int srs_est) { reported_symbol_list->num_rbs = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0]; @@ -645,10 +646,12 @@ int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t* rep } for(int rb = 0; rb < reported_symbol_list->num_rbs; rb++) { - if (snr_per_rb[rb] < -64) { + if (srs_est<0) { + reported_symbol_list->rb_list[rb].rb_snr = 0xFF; + } else if (snr_per_rb[rb] < -64) { reported_symbol_list->rb_list[rb].rb_snr = 0; } else if (snr_per_rb[rb] > 63) { - reported_symbol_list->rb_list[rb].rb_snr = 255; + reported_symbol_list->rb_list[rb].rb_snr = 0xFE; } else { reported_symbol_list->rb_list[rb].rb_snr = (snr_per_rb[rb] + 64)<<1; } @@ -858,20 +861,22 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { generate_srs_nr(srs_pdu, &gNB->frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); } - nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); + int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); - nr_srs_channel_estimation(gNB,frame_rx,slot_rx,srs_pdu, - gNB->nr_srs_info[i], - gNB->nr_srs_info[i]->srs_generated_signal, - gNB->nr_srs_info[i]->srs_received_signal, - gNB->nr_srs_info[i]->srs_estimated_channel_freq, - gNB->nr_srs_info[i]->srs_estimated_channel_time, - gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, - gNB->nr_srs_info[i]->signal_power, - gNB->nr_srs_info[i]->noise_power_per_rb, - gNB->nr_srs_info[i]->noise_power, - gNB->nr_srs_info[i]->snr_per_rb, - gNB->nr_srs_info[i]->snr); + if (srs_est >= 0) { + nr_srs_channel_estimation(gNB,frame_rx,slot_rx,srs_pdu, + gNB->nr_srs_info[i], + gNB->nr_srs_info[i]->srs_generated_signal, + gNB->nr_srs_info[i]->srs_received_signal, + gNB->nr_srs_info[i]->srs_estimated_channel_freq, + gNB->nr_srs_info[i]->srs_estimated_channel_time, + gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, + gNB->nr_srs_info[i]->signal_power, + gNB->nr_srs_info[i]->noise_power_per_rb, + gNB->nr_srs_info[i]->noise_power, + gNB->nr_srs_info[i]->snr_per_rb, + gNB->nr_srs_info[i]->snr); + } T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_freq[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); @@ -887,7 +892,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, gNB->nr_srs_info[i]->srs_estimated_channel_time); gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; - gNB->srs_pdu_list[num_srs].wide_band_snr = (*gNB->nr_srs_info[i]->snr + 64)<<1; + gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (*gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); @@ -895,7 +900,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { fill_srs_reported_symbol_list(&gNB->srs_pdu_list[num_srs].reported_symbol_list[0], srs_pdu, gNB->frame_parms.N_RB_UL, - gNB->nr_srs_info[i]->snr_per_rb); + gNB->nr_srs_info[i]->snr_per_rb, + srs_est); gNB->UL_INFO.srs_ind.number_of_pdus += 1; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 8680cc25d1..35b2c4b167 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -125,7 +125,8 @@ void nr_schedule_srs(int module_id, frame_t frame) { sched_ctrl->sched_srs.slot = -1; sched_ctrl->sched_srs.srs_scheduled = false; - if(!UE_info->Msg4_ACKed[UE_id] || sched_ctrl->rrc_processing_timer > 0) { + if((sched_ctrl->ul_failure == 1 && get_softmodem_params()->phy_test==0) || + !UE_info->Msg4_ACKed[UE_id] || sched_ctrl->rrc_processing_timer > 0) { continue; } From af95f834f1f03d7cef7fa9690344431d79513e10 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 25 May 2022 10:36:30 +0100 Subject: [PATCH 19/61] Fix scheduling SRS reception at gNB when there is Dedicated BWPs --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 35b2c4b167..18b723ccc0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -41,15 +41,16 @@ void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id, int NR_UE_info_t *UE_info = &nrmac->UE_info; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - NR_BWP_t ubwp = sched_ctrl->active_ubwp ? - sched_ctrl->active_ubwp->bwp_Common->genericParameters : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + const NR_SIB1_t *sib1 = nrmac->common_channels[0].sib1 ? nrmac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, + scc, + sib1); srs_pdu->rnti = UE_info->rnti[UE_id]; srs_pdu->handle = 0; - srs_pdu->bwp_size = NRRIV2BW(ubwp.locationAndBandwidth, MAX_BWP_SIZE);; - srs_pdu->bwp_start = NRRIV2PRBOFFSET(ubwp.locationAndBandwidth, MAX_BWP_SIZE);; - srs_pdu->subcarrier_spacing = ubwp.subcarrierSpacing; + srs_pdu->bwp_size = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE);; + srs_pdu->bwp_start = NRRIV2PRBOFFSET(genericParameters->locationAndBandwidth, MAX_BWP_SIZE);; + srs_pdu->subcarrier_spacing = genericParameters->subcarrierSpacing; srs_pdu->cyclic_prefix = 0; srs_pdu->num_ant_ports = srs_resource->nrofSRS_Ports; srs_pdu->num_symbols = srs_resource->resourceMapping.nrofSymbols; @@ -131,13 +132,20 @@ void nr_schedule_srs(int module_id, frame_t frame) { } NR_SRS_Config_t *srs_config = NULL; - if (cg && - cg->spCellConfig && - cg->spCellConfig->spCellConfigDedicated && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { + if (sched_ctrl->active_ubwp) { + if (sched_ctrl->active_ubwp->bwp_Dedicated && + sched_ctrl->active_ubwp->bwp_Dedicated->srs_Config) { + srs_config = sched_ctrl->active_ubwp->bwp_Dedicated->srs_Config->choice.setup; + } + } else if (cg && + cg->spCellConfig && + cg->spCellConfig->spCellConfigDedicated && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { srs_config = cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config->choice.setup; - } else { + } + + if (!srs_config) { continue; } @@ -167,14 +175,15 @@ void nr_schedule_srs(int module_id, frame_t frame) { continue; } - NR_BWP_t ubwp = sched_ctrl->active_ubwp ? - sched_ctrl->active_ubwp->bwp_Common->genericParameters : - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters; + const NR_SIB1_t *sib1 = nrmac->common_channels[0].sib1 ? nrmac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; + NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, + scc, + sib1); uint16_t period = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present]; uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p); - int n_slots_frame = nr_slots_per_frame[ubwp.subcarrierSpacing]; + int n_slots_frame = nr_slots_per_frame[genericParameters->subcarrierSpacing]; // Check if UE will transmit the SRS in this frame if ( ((frame - offset/n_slots_frame)*n_slots_frame)%period == 0) { From 8d02c2c0fcecc100002e5d627ec71956248112be Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 25 May 2022 11:06:55 +0100 Subject: [PATCH 20/61] Fix scheduling SRS transmission at UE when there is Dedicated BWPs --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 906a5d2d6c..b394d18cb8 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -929,15 +929,23 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo bool srs_scheduled = false; NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); + NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; NR_SRS_Config_t *srs_config = NULL; - if (mac->cg && - mac->cg->spCellConfig && - mac->cg->spCellConfig->spCellConfigDedicated && - mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && - mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { + if (ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1]) { + if (mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated && + mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->srs_Config) { + srs_config = mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->srs_Config->choice.setup; + } + } else if (mac->cg && + mac->cg->spCellConfig && + mac->cg->spCellConfig->spCellConfigDedicated && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && + mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { srs_config = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config->choice.setup; - } else { + } + + if (!srs_config) { return false; } @@ -965,7 +973,6 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo continue; } - NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; NR_BWP_t ubwp = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Common->genericParameters : mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.genericParameters; From 264eebfb3f4d25cbdb10a7201d2b32fff574172d Mon Sep 17 00:00:00 2001 From: rmagueta Date: Fri, 27 May 2022 11:54:53 +0100 Subject: [PATCH 21/61] Fix build after merge --- openair2/GNB_APP/MACRLC_nr_paramdef.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index 1f57087194..22b83f4064 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -130,18 +130,18 @@ #define MACRLC_ULSCH_MAX_FRAME_INACTIVITY 17 #define MACRLC_PUSCHTARGETSNRX10_IDX 18 #define MACRLC_PUCCHTARGETSNRX10_IDX 19 -#define MACRLC_UL_PRBBLACK_SNR_THRESHOLD_IDX -#define MACRLC_PUCCHFAILURETHRES_IDX 20 -#define MACRLC_PUSCHFAILURETHRES_IDX 21 -#define MACRLC_DL_BLER_TARGET_UPPER_IDX 22 -#define MACRLC_DL_BLER_TARGET_LOWER_IDX 23 -#define MACRLC_DL_MAX_MCS_IDX 24 -#define MACRLC_UL_BLER_TARGET_UPPER_IDX 25 -#define MACRLC_UL_BLER_TARGET_LOWER_IDX 26 -#define MACRLC_UL_MAX_MCS_IDX 27 -#define MACRLC_HARQ_ROUND_MAX_IDX 28 -#define MACRLC_MIN_GRANT_PRB_IDX 29 -#define MACRLC_MIN_GRANT_MCS_IDX 30 +#define MACRLC_UL_PRBBLACK_SNR_THRESHOLD_IDX 20 +#define MACRLC_PUCCHFAILURETHRES_IDX 21 +#define MACRLC_PUSCHFAILURETHRES_IDX 22 +#define MACRLC_DL_BLER_TARGET_UPPER_IDX 23 +#define MACRLC_DL_BLER_TARGET_LOWER_IDX 24 +#define MACRLC_DL_MAX_MCS_IDX 25 +#define MACRLC_UL_BLER_TARGET_UPPER_IDX 26 +#define MACRLC_UL_BLER_TARGET_LOWER_IDX 27 +#define MACRLC_UL_MAX_MCS_IDX 28 +#define MACRLC_HARQ_ROUND_MAX_IDX 29 +#define MACRLC_MIN_GRANT_PRB_IDX 30 +#define MACRLC_MIN_GRANT_MCS_IDX 31 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif From 616927c04d993820cefc25fb5276c22bf7a19837 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Wed, 1 Jun 2022 17:22:59 +0100 Subject: [PATCH 22/61] Fixes after merge --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 5571d27597..ad7db304bf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -789,15 +789,14 @@ void handle_nr_srs_measurements(const module_id_t module_id, } #endif - const int UE_id = find_nr_UE_id(module_id,rnti); - if (UE_id < 0) { + NR_UE_info_t* UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, rnti); + if (!UE) { LOG_W(NR_MAC, "Could not find UE for RNTI 0x%04x\n", rnti); return; } gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; - NR_UE_info_t *UE_info = &nr_mac->UE_info; - NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + NR_mac_stats_t *stats = &UE->mac_stats; stats->srs_wide_band_snr = (wide_band_snr>>1)-64; int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; From f6cbde534391d2a3d73ecbe3a91f2f92c22304c2 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 16 Jun 2022 12:49:13 +0100 Subject: [PATCH 23/61] Add const qualifier in some variables --- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 6 ++-- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 30 +++++++++---------- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 18 +++++------ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 22 ++++++++------ openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 14 ++++----- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 4 +-- openair2/NR_PHY_INTERFACE/NR_IF_Module.c | 4 +-- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/NR/MESSAGES/asn1_msg.h | 2 +- openair2/RRC/NR/nr_rrc_config.c | 8 ++--- openair2/RRC/NR/nr_rrc_config.h | 6 ++-- 12 files changed, 61 insertions(+), 57 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 403a96983c..c1be11c468 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -67,8 +67,8 @@ int nr_est_timing_advance_pusch(PHY_VARS_gNB* gNB, int UE_id) return max_pos - sync_pos; } -int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, - int32_t **srs_estimated_channel_time) { +int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, + const int32_t **srs_estimated_channel_time) { int timing_advance = 0; int max_val = 0; @@ -90,7 +90,7 @@ int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, } // Scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size - uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 7; + const uint16_t bw_scaling = frame_parms->ofdm_symbol_size >> 7; // do some integer rounding to improve TA accuracy int sync_pos_rounded; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 448df9b468..f28f68acbd 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -950,7 +950,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, }//Antenna loop } -uint32_t calc_power(const int16_t *x, uint32_t size) { +uint32_t calc_power(const int16_t *x, const uint32_t size) { int64_t sum_x = 0; int64_t sum_x2 = 0; for(int k = 0; kframe_parms; + const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; int32_t **srs_ls_estimated_channel = nr_srs_info->srs_ls_estimated_channel; int16_t ch_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; @@ -1110,13 +1110,13 @@ int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, // Compute noise power - uint8_t signal_power_bits = log2_approx(*signal_power); - uint8_t factor_bits = signal_power_bits < 32 ? 32 - signal_power_bits : 0; // 32 due to input of dB_fixed(uint32_t x) - int32_t factor_dB = dB_fixed(1<first_carrier_offset + srs_pdu->bwp_start*12; - uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; - uint8_t n_noise_estimates = frame_parms->nb_antennas_rx*srs_symbols_per_rb; + const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*12; + const uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; + const uint8_t n_noise_estimates = frame_parms->nb_antennas_rx*srs_symbols_per_rb; uint8_t count_estimates = 0; uint64_t sum_re = 0; uint64_t sum_re2 = 0; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 914b0d7385..01af743473 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -55,8 +55,8 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t ulsch_id, unsigned char harq int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id); -int nr_est_timing_advance_srs(NR_DL_FRAME_PARMS *frame_parms, - int32_t **srs_estimated_channel_time); +int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, + const int32_t **srs_estimated_channel_time); void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, @@ -66,13 +66,13 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, unsigned char symbol, uint32_t nb_re_pusch); -int nr_srs_channel_estimation(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_srs_pdu_t *srs_pdu, - nr_srs_info_t *nr_srs_info, - int32_t *srs_generated_signal, - int32_t **srs_received_signal, +int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, + const int frame, + const int slot, + const nfapi_nr_srs_pdu_t *srs_pdu, + const nr_srs_info_t *nr_srs_info, + const int32_t *srs_generated_signal, + const int32_t **srs_received_signal, int32_t **srs_estimated_channel_freq, int32_t **srs_estimated_channel_time, int32_t **srs_estimated_channel_time_shifted, diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 0198298101..522487c53a 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -633,11 +633,11 @@ void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) } -int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t* reported_symbol_list, - nfapi_nr_srs_pdu_t *srs_pdu, - int N_RB_UL, +int fill_srs_reported_symbol_list(nfapi_nr_srs_indication_reported_symbol_t *reported_symbol_list, + const nfapi_nr_srs_pdu_t *srs_pdu, + const int N_RB_UL, const int8_t *snr_per_rb, - int srs_est) { + const int srs_est) { reported_symbol_list->num_rbs = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0]; @@ -865,13 +865,16 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { generate_srs_nr(srs_pdu, &gNB->frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); } - int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); + const int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); if (srs_est >= 0) { - nr_srs_channel_estimation(gNB,frame_rx,slot_rx,srs_pdu, + nr_srs_channel_estimation(gNB, + frame_rx, + slot_rx, + srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_generated_signal, - gNB->nr_srs_info[i]->srs_received_signal, + (const int32_t **)gNB->nr_srs_info[i]->srs_received_signal, gNB->nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, @@ -888,13 +891,14 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); - uint16_t num_srs = gNB->UL_INFO.srs_ind.number_of_pdus; + const uint16_t num_srs = gNB->UL_INFO.srs_ind.number_of_pdus; gNB->UL_INFO.srs_ind.pdu_list = &gNB->srs_pdu_list[0]; gNB->UL_INFO.srs_ind.sfn = frame_rx; gNB->UL_INFO.srs_ind.slot = slot_rx; gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; - gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, gNB->nr_srs_info[i]->srs_estimated_channel_time); + gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, + (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time); gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (*gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 9f7fa89146..ce4b16fdc7 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -928,7 +928,7 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo bool srs_scheduled = false; NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); - NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; + const NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; NR_SRS_Config_t *srs_config = NULL; if (ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1]) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index 7a21ad82e8..e737fc7107 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -41,9 +41,9 @@ void nr_configure_srs(nfapi_nr_srs_pdu_t *srs_pdu, int module_id, int CC_id,NR_U NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; const NR_SIB1_t *sib1 = nrmac->common_channels[0].sib1 ? nrmac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - scc, - sib1); + const NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, + scc, + sib1); srs_pdu->rnti = UE->rnti; srs_pdu->handle = 0; @@ -173,14 +173,14 @@ void nr_schedule_srs(int module_id, frame_t frame) { } const NR_SIB1_t *sib1 = nrmac->common_channels[0].sib1 ? nrmac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, - scc, - sib1); + const NR_BWP_t *genericParameters = get_ul_bwp_genericParameters(sched_ctrl->active_ubwp, + scc, + sib1); uint16_t period = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present]; uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p); - int n_slots_frame = nr_slots_per_frame[genericParameters->subcarrierSpacing]; + const int n_slots_frame = nr_slots_per_frame[genericParameters->subcarrierSpacing]; // Check if UE will transmit the SRS in this frame if ( ((frame - offset/n_slots_frame)*n_slots_frame)%period == 0) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index e815ffcc47..21045cd21e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -789,7 +789,7 @@ void handle_nr_srs_measurements(const module_id_t module_id, } #endif - NR_UE_info_t* UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, rnti); + NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, rnti); if (!UE) { LOG_W(NR_MAC, "Could not find UE for RNTI 0x%04x\n", rnti); return; @@ -799,7 +799,7 @@ void handle_nr_srs_measurements(const module_id_t module_id, NR_mac_stats_t *stats = &UE->mac_stats; stats->srs_wide_band_snr = (wide_band_snr>>1)-64; - int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; + const int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold; uint16_t *ulprbbl = nr_mac->ulprbbl; memset(ulprbbl, 0, reported_symbol_list[0].num_rbs*sizeof(uint16_t)); diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index c78a4e926e..47705082d1 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -230,8 +230,8 @@ void handle_nr_srs(NR_UL_IND_t *UL_info) { const module_id_t module_id = UL_info->module_id; const frame_t frame = UL_info->srs_ind.sfn; const sub_frame_t slot = UL_info->srs_ind.slot; - int num_srs = UL_info->srs_ind.number_of_pdus; - nfapi_nr_srs_indication_pdu_t *srs_list = UL_info->srs_ind.pdu_list; + const int num_srs = UL_info->srs_ind.number_of_pdus; + const nfapi_nr_srs_indication_pdu_t *srs_list = UL_info->srs_ind.pdu_list; for (int i = 0; i < num_srs; i++) { const nfapi_nr_srs_indication_pdu_t *srs_ind = &srs_list[i]; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index a2fb44aac9..fff4043a4d 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -2067,7 +2067,7 @@ void fill_mastercellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CellGr } void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, - int uid, + const int uid, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq* configuration) { diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 3b881231b0..bff7dcfce5 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -114,7 +114,7 @@ void fill_initial_cellGroupConfig(int uid, const gNB_RrcConfigurationReq *configuration); void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, - int uid, + const int uid, NR_UE_NR_Capability_t *uecap, const gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index c71e21f999..fd2c92d867 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -324,7 +324,7 @@ void config_csiim(int do_csirs, int dl_antenna_ports, int curr_bwp, } // TODO: Implement to b_SRS = 1 and b_SRS = 2 -long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { +long rrc_get_max_nr_csrs(const uint8_t max_rbs, const long b_SRS) { if(b_SRS>0) { LOG_E(NR_RRC,"rrc_get_max_nr_csrs(): Not implemented yet for b_SRS>0\n"); @@ -349,9 +349,9 @@ long rrc_get_max_nr_csrs(uint8_t max_rbs, long b_SRS) { } void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, - NR_ServingCellConfigCommon_t *servingcellconfigcommon, - int uid, - int do_srs) { + const NR_ServingCellConfigCommon_t *servingcellconfigcommon, + const int uid, + const int do_srs) { setup_release_srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index 31d8ad9c80..4544f9e92f 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -129,9 +129,9 @@ void config_csirs(NR_ServingCellConfigCommon_t *servingcellconfigcommon, void config_csiim(int do_csirs, int dl_antenna_ports, int curr_bwp, NR_CSI_MeasConfig_t *csi_MeasConfig); void config_srs(NR_SetupRelease_SRS_Config_t *setup_release_srs_Config, - NR_ServingCellConfigCommon_t *servingcellconfigcommon, - int uid, - int do_srs); + const NR_ServingCellConfigCommon_t *servingcellconfigcommon, + const int uid, + const int do_srs); void set_dl_mcs_table(int scs, NR_UE_NR_Capability_t *cap, NR_SpCellConfig_t *SpCellConfig, NR_BWP_DownlinkDedicated_t *bwp_Dedicated, From 61e42ce9c61a14a827dfe323807b78f6674fa55f Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 16 Jun 2022 13:29:30 +0100 Subject: [PATCH 24/61] Consider the invalid timing advance value case for SRS estimation --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 522487c53a..fb4e5a85ef 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -897,8 +897,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->UL_INFO.srs_ind.slot = slot_rx; gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; - gNB->srs_pdu_list[num_srs].timing_advance = nr_est_timing_advance_srs(&gNB->frame_parms, - (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time); + gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(&gNB->frame_parms, + (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time) : 0xFFFF; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (*gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; From 1a4686b021fac4581383ca0823664dee2867744a Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 23 Jun 2022 14:52:05 +0100 Subject: [PATCH 25/61] Remove UE->Msg4_ACKed from condition in nr_schedule_srs --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index e737fc7107..4be176714e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -124,7 +124,7 @@ void nr_schedule_srs(int module_id, frame_t frame) { sched_ctrl->sched_srs.srs_scheduled = false; if((sched_ctrl->ul_failure == 1 && get_softmodem_params()->phy_test==0) || - !UE->Msg4_ACKed || sched_ctrl->rrc_processing_timer > 0) { + sched_ctrl->rrc_processing_timer > 0) { continue; } From 07a3634e4523ceb43c18b29eaa52dd8694615b75 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 23 Jun 2022 18:23:23 +0100 Subject: [PATCH 26/61] Change some heap allocations to stack allocations --- openair1/PHY/INIT/nr_init.c | 14 -------------- openair1/PHY/INIT/nr_init_ue.c | 6 ------ openair1/PHY/defs_nr_common.h | 14 +++++++------- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 8 ++++---- 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 1f2383c60c..bd349d146a 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -613,13 +613,6 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, for (int id=0; idnr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); - gNB->nr_srs_info[id]->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); - gNB->nr_srs_info[id]->srs_generated_signal = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->signal_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); - gNB->nr_srs_info[id]->noise_power_per_rb = (uint32_t*)malloc16_clear(fp->N_RB_UL*sizeof(uint32_t)); - gNB->nr_srs_info[id]->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); - gNB->nr_srs_info[id]->snr_per_rb = (int8_t*)malloc16_clear(fp->N_RB_UL*sizeof(int8_t)); - gNB->nr_srs_info[id]->snr = (int8_t*)malloc16_clear(sizeof(int8_t)); gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); gNB->nr_srs_info[id]->srs_estimated_channel_freq = (int32_t **)malloc16(Prx*sizeof(int32_t*)); @@ -796,13 +789,6 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time[i]); free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted[i]); } - free_and_zero(gNB->nr_srs_info[id]->sc_list); - free_and_zero(gNB->nr_srs_info[id]->srs_generated_signal); - free_and_zero(gNB->nr_srs_info[id]->signal_power); - free_and_zero(gNB->nr_srs_info[id]->noise_power_per_rb); - free_and_zero(gNB->nr_srs_info[id]->noise_power); - free_and_zero(gNB->nr_srs_info[id]->snr_per_rb); - free_and_zero(gNB->nr_srs_info[id]->snr); free_and_zero(gNB->nr_srs_info[id]->srs_received_signal); free_and_zero(gNB->nr_srs_info[id]->srs_ls_estimated_channel); free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_freq); diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index c6e6ecd463..254a25097c 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -377,9 +377,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } ue->nr_srs_info = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); - ue->nr_srs_info->sc_list = (uint16_t *) malloc16_clear(6*fp->N_RB_UL*sizeof(uint16_t)); - ue->nr_srs_info->srs_generated_signal = (int32_t *) malloc16_clear( (2*(fp->samples_per_frame)+2048)*sizeof(int32_t) ); - ue->nr_srs_info->noise_power = (uint32_t*)malloc16_clear(sizeof(uint32_t)); ue->nr_srs_info->srs_received_signal = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); ue->nr_srs_info->srs_ls_estimated_channel = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); ue->nr_srs_info->srs_estimated_channel_freq = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); @@ -527,9 +524,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) free_and_zero(ue->nr_srs_info->srs_estimated_channel_time[i]); free_and_zero(ue->nr_srs_info->srs_estimated_channel_time_shifted[i]); } - free_and_zero(ue->nr_srs_info->sc_list); - free_and_zero(ue->nr_srs_info->srs_generated_signal); - free_and_zero(ue->nr_srs_info->noise_power); free_and_zero(ue->nr_srs_info->srs_received_signal); free_and_zero(ue->nr_srs_info->srs_ls_estimated_channel); free_and_zero(ue->nr_srs_info->srs_estimated_channel_freq); diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 657d05fc6e..fe895d1770 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -241,19 +241,19 @@ typedef struct { typedef struct { uint16_t sc_list_length; - uint16_t *sc_list; + uint16_t sc_list[6*273]; uint8_t srs_generated_signal_bits; - int32_t *srs_generated_signal; + int32_t srs_generated_signal[OFDM_SYMBOL_SIZE_SAMPLES_MAX * MAX_NUM_NR_SRS_SYMBOLS]; int32_t **srs_received_signal; int32_t **srs_ls_estimated_channel; int32_t **srs_estimated_channel_freq; int32_t **srs_estimated_channel_time; int32_t **srs_estimated_channel_time_shifted; - uint32_t *signal_power; - uint32_t *noise_power_per_rb; - uint32_t *noise_power; - int8_t *snr_per_rb; - int8_t *snr; + uint32_t signal_power; + uint32_t noise_power_per_rb[273]; + uint32_t noise_power; + int8_t snr_per_rb[273]; + int8_t snr; } nr_srs_info_t; typedef struct { diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index fb4e5a85ef..56ee0d8db2 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -878,11 +878,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, - gNB->nr_srs_info[i]->signal_power, + &gNB->nr_srs_info[i]->signal_power, gNB->nr_srs_info[i]->noise_power_per_rb, - gNB->nr_srs_info[i]->noise_power, + &gNB->nr_srs_info[i]->noise_power, gNB->nr_srs_info[i]->snr_per_rb, - gNB->nr_srs_info[i]->snr); + &gNB->nr_srs_info[i]->snr); } T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), @@ -900,7 +900,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(&gNB->frame_parms, (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time) : 0xFFFF; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; - gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (*gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid + gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); From c2fee0520c1bf91b33f6b8429ebef14a7d2a6add Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 30 Jun 2022 17:59:11 +0100 Subject: [PATCH 27/61] Fix variable redefinition --- openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index f28f68acbd..f802c5b869 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -1163,7 +1163,6 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, *snr = dB_fixed((int32_t)((*signal_power<first_carrier_offset + srs_pdu->bwp_start*12; uint8_t R = srs_pdu->comb_size == 0 ? 2 : 4; for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { From 253e037fb284239b56c05c4f7358478c86dbef03 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 5 Jul 2022 11:07:01 +0100 Subject: [PATCH 28/61] Remove some variables from nr_srs_info_t --- openair1/PHY/defs_nr_common.h | 5 ----- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 19 ++++++++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index fe895d1770..a5a0824166 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -249,11 +249,6 @@ typedef struct { int32_t **srs_estimated_channel_freq; int32_t **srs_estimated_channel_time; int32_t **srs_estimated_channel_time_shifted; - uint32_t signal_power; - uint32_t noise_power_per_rb[273]; - uint32_t noise_power; - int8_t snr_per_rb[273]; - int8_t snr; } nr_srs_info_t; typedef struct { diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1635de7e81..f92190df56 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -848,6 +848,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_D(NR_PHY, "(%d.%d) gNB is waiting for SRS, id = %i\n", frame_rx, slot_rx, i); nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + uint32_t noise_power_per_rb[srs_pdu->bwp_size]; + int8_t snr_per_rb[srs_pdu->bwp_size]; + uint32_t signal_power; + uint32_t noise_power; + int8_t snr; // At least currently, the configuration is constant, so it is enough to generate the sequence just once. if(gNB->nr_srs_info[i]->sc_list_length == 0) { @@ -867,11 +872,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->nr_srs_info[i]->srs_estimated_channel_freq, gNB->nr_srs_info[i]->srs_estimated_channel_time, gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, - &gNB->nr_srs_info[i]->signal_power, - gNB->nr_srs_info[i]->noise_power_per_rb, - &gNB->nr_srs_info[i]->noise_power, - gNB->nr_srs_info[i]->snr_per_rb, - &gNB->nr_srs_info[i]->snr); + &signal_power, + noise_power_per_rb, + &noise_power, + snr_per_rb, + &snr); } T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), @@ -889,7 +894,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(&gNB->frame_parms, (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time) : 0xFFFF; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; - gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (gNB->nr_srs_info[i]->snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid + gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; if(!gNB->srs_pdu_list[num_srs].reported_symbol_list) { gNB->srs_pdu_list[num_srs].reported_symbol_list = (nfapi_nr_srs_indication_reported_symbol_t*) calloc(1, gNB->srs_pdu_list[num_srs].num_reported_symbols*sizeof(nfapi_nr_srs_indication_reported_symbol_t)); @@ -897,7 +902,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { fill_srs_reported_symbol_list(&gNB->srs_pdu_list[num_srs].reported_symbol_list[0], srs_pdu, gNB->frame_parms.N_RB_UL, - gNB->nr_srs_info[i]->snr_per_rb, + snr_per_rb, srs_est); gNB->UL_INFO.srs_ind.number_of_pdus += 1; From 52f6d38a3478fd6bb13bb2dd0527153003605145 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 5 Jul 2022 12:58:53 +0100 Subject: [PATCH 29/61] Remove more variables from nr_srs_info_t --- openair1/PHY/INIT/nr_init.c | 24 --------------- openair1/PHY/INIT/nr_init_ue.c | 25 ---------------- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- .../NR_ESTIMATION/nr_ul_channel_estimation.c | 10 +++---- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 11 +++---- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 2 +- openair1/PHY/NR_TRANSPORT/srs_rx.c | 2 +- openair1/PHY/defs_nr_common.h | 5 ---- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 30 ++++++++++++------- 9 files changed, 33 insertions(+), 78 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index bd349d146a..4fe66a5cbf 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -613,18 +613,6 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB, for (int id=0; idnr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); - gNB->nr_srs_info[id]->srs_received_signal = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - gNB->nr_srs_info[id]->srs_ls_estimated_channel = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - gNB->nr_srs_info[id]->srs_estimated_channel_freq = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - gNB->nr_srs_info[id]->srs_estimated_channel_time = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted = (int32_t **)malloc16(Prx*sizeof(int32_t*)); - for (i=0;inr_srs_info[id]->srs_received_signal[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->srs_ls_estimated_channel[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->srs_estimated_channel_freq[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->srs_estimated_channel_time[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted[i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - } } generate_ul_reference_signal_sequences(SHRT_MAX); @@ -782,18 +770,6 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(gNB->nr_csi_rs_info); for (int id = 0; id < NUMBER_OF_NR_SRS_MAX; id++) { - for (int i = 0; i < Prx; i++) { - free_and_zero(gNB->nr_srs_info[id]->srs_received_signal[i]); - free_and_zero(gNB->nr_srs_info[id]->srs_ls_estimated_channel[i]); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_freq[i]); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time[i]); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted[i]); - } - free_and_zero(gNB->nr_srs_info[id]->srs_received_signal); - free_and_zero(gNB->nr_srs_info[id]->srs_ls_estimated_channel); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_freq); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time); - free_and_zero(gNB->nr_srs_info[id]->srs_estimated_channel_time_shifted); free_and_zero(gNB->nr_srs_info[id]); } diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 254a25097c..a332c2067c 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -377,19 +377,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) } ue->nr_srs_info = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); - ue->nr_srs_info->srs_received_signal = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - ue->nr_srs_info->srs_ls_estimated_channel = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - ue->nr_srs_info->srs_estimated_channel_freq = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - ue->nr_srs_info->srs_estimated_channel_time = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - ue->nr_srs_info->srs_estimated_channel_time_shifted = (int32_t **)malloc16( fp->nb_antennas_rx*sizeof(int32_t *) ); - for (i=0; inb_antennas_rx; i++) { - ue->nr_srs_info->srs_received_signal[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - ue->nr_srs_info->srs_ls_estimated_channel[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - ue->nr_srs_info->srs_estimated_channel_freq[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - ue->nr_srs_info->srs_estimated_channel_time[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - ue->nr_srs_info->srs_estimated_channel_time_shifted[i] = (int32_t *) malloc16_clear(fp->ofdm_symbol_size*MAX_NUM_NR_SRS_SYMBOLS*sizeof(int32_t)); - } - // RACH prach_vars[gNB_id]->prachF = (int16_t *)malloc16_clear( sizeof(int)*(7*2*sizeof(int)*(fp->ofdm_symbol_size*12)) ); @@ -517,18 +504,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) free_and_zero(ue->nr_csi_rs_info->csi_rs_estimated_channel_freq); free_and_zero(ue->nr_csi_rs_info); - for (int i = 0; i < fp->nb_antennas_rx; i++) { - free_and_zero(ue->nr_srs_info->srs_received_signal[i]); - free_and_zero(ue->nr_srs_info->srs_ls_estimated_channel[i]); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_freq[i]); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_time[i]); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_time_shifted[i]); - } - free_and_zero(ue->nr_srs_info->srs_received_signal); - free_and_zero(ue->nr_srs_info->srs_ls_estimated_channel); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_freq); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_time); - free_and_zero(ue->nr_srs_info->srs_estimated_channel_time_shifted); free_and_zero(ue->nr_srs_info); free_and_zero(ue->csiim_vars[gNB_id]); diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index c1be11c468..1793a76fe1 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -68,7 +68,7 @@ int nr_est_timing_advance_pusch(PHY_VARS_gNB* gNB, int UE_id) } int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, - const int32_t **srs_estimated_channel_time) { + const int32_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size]) { int timing_advance = 0; int max_val = 0; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 84470be571..080b9b65d5 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -965,10 +965,11 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, const nfapi_nr_srs_pdu_t *srs_pdu, const nr_srs_info_t *nr_srs_info, const int32_t *srs_generated_signal, - const int32_t **srs_received_signal, - int32_t **srs_estimated_channel_freq, - int32_t **srs_estimated_channel_time, - int32_t **srs_estimated_channel_time_shifted, + int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_ls_estimated_channel[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_estimated_channel_freq[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_estimated_channel_time[][gNB->frame_parms.ofdm_symbol_size], + int32_t srs_estimated_channel_time_shifted[][gNB->frame_parms.ofdm_symbol_size], uint32_t *signal_power, uint32_t *noise_power_per_rb, uint32_t *noise_power, @@ -981,7 +982,6 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, } const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - int32_t **srs_ls_estimated_channel = nr_srs_info->srs_ls_estimated_channel; int16_t ch_real[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; int16_t ch_imag[frame_parms->nb_antennas_rx*nr_srs_info->sc_list_length]; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 01af743473..b0ed3662ea 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -56,7 +56,7 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, uint8_t ulsch_id, unsigned char harq int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id); int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, - const int32_t **srs_estimated_channel_time); + const int32_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size]); void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, @@ -72,10 +72,11 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, const nfapi_nr_srs_pdu_t *srs_pdu, const nr_srs_info_t *nr_srs_info, const int32_t *srs_generated_signal, - const int32_t **srs_received_signal, - int32_t **srs_estimated_channel_freq, - int32_t **srs_estimated_channel_time, - int32_t **srs_estimated_channel_time_shifted, + int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_ls_estimated_channel[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_estimated_channel_freq[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)], + int32_t srs_estimated_channel_time[][gNB->frame_parms.ofdm_symbol_size], + int32_t srs_estimated_channel_time_shifted[][gNB->frame_parms.ofdm_symbol_size], uint32_t *signal_power, uint32_t *noise_power_per_rb, uint32_t *noise_power, diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index e3b7efacfb..109fac7e2d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -330,7 +330,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, int slot, nfapi_nr_srs_pdu_t *srs_pdu, nr_srs_info_t *nr_srs_info, - int32_t **srs_received_signal); + int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)]); void init_prach_list(PHY_VARS_gNB *gNB); void init_prach_ru_list(RU_t *ru); diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index ffcd7362f3..39c3846db5 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -98,7 +98,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, int slot, nfapi_nr_srs_pdu_t *srs_pdu, nr_srs_info_t *nr_srs_info, - int32_t **srs_received_signal) { + int32_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size*(1<num_symbols)]) { if(nr_srs_info->sc_list_length == 0) { LOG_E(NR_PHY, "(%d.%d) nr_srs_info was not generated yet!\n", frame, slot); diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 93c419da6f..ebcf8361f6 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -244,11 +244,6 @@ typedef struct { uint16_t sc_list[6*273]; uint8_t srs_generated_signal_bits; int32_t srs_generated_signal[OFDM_SYMBOL_SIZE_SAMPLES_MAX * MAX_NUM_NR_SRS_SYMBOLS]; - int32_t **srs_received_signal; - int32_t **srs_ls_estimated_channel; - int32_t **srs_estimated_channel_freq; - int32_t **srs_estimated_channel_time; - int32_t **srs_estimated_channel_time_shifted; } nr_srs_info_t; typedef struct { diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 635a0d0f37..d2cf0f141f 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -850,7 +850,14 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_D(NR_PHY, "(%d.%d) gNB is waiting for SRS, id = %i\n", frame_rx, slot_rx, i); + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + uint8_t N_symb_SRS = 1<num_symbols; + int32_t srs_received_signal[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; + int32_t srs_ls_estimated_channel[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; + int32_t srs_estimated_channel_freq[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size*N_symb_SRS]; + int32_t srs_estimated_channel_time[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size]; + int32_t srs_estimated_channel_time_shifted[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size]; uint32_t noise_power_per_rb[srs_pdu->bwp_size]; int8_t snr_per_rb[srs_pdu->bwp_size]; uint32_t signal_power; @@ -859,10 +866,10 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { // At least currently, the configuration is constant, so it is enough to generate the sequence just once. if(gNB->nr_srs_info[i]->sc_list_length == 0) { - generate_srs_nr(srs_pdu, &gNB->frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); + generate_srs_nr(srs_pdu, frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); } - const int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx,srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_received_signal); + const int srs_est = nr_get_srs_signal(gNB,frame_rx,slot_rx, srs_pdu, gNB->nr_srs_info[i], srs_received_signal); if (srs_est >= 0) { nr_srs_channel_estimation(gNB, @@ -871,10 +878,11 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { srs_pdu, gNB->nr_srs_info[i], gNB->nr_srs_info[i]->srs_generated_signal, - (const int32_t **)gNB->nr_srs_info[i]->srs_received_signal, - gNB->nr_srs_info[i]->srs_estimated_channel_freq, - gNB->nr_srs_info[i]->srs_estimated_channel_time, - gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted, + srs_received_signal, + srs_ls_estimated_channel, + srs_estimated_channel_freq, + srs_estimated_channel_time, + srs_estimated_channel_time_shifted, &signal_power, noise_power_per_rb, &noise_power, @@ -883,10 +891,10 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } T(T_GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), - T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_freq[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); + T_BUFFER(srs_estimated_channel_freq[0], frame_parms->ofdm_symbol_size*sizeof(int32_t))); T(T_GNB_PHY_UL_TIME_CHANNEL_ESTIMATE, T_INT(0), T_INT(srs_pdu->rnti), T_INT(frame_rx), T_INT(0), T_INT(0), - T_BUFFER(gNB->nr_srs_info[i]->srs_estimated_channel_time_shifted[0], gNB->frame_parms.ofdm_symbol_size*sizeof(int32_t))); + T_BUFFER(srs_estimated_channel_time_shifted[0], frame_parms->ofdm_symbol_size*sizeof(int32_t))); const uint16_t num_srs = gNB->UL_INFO.srs_ind.number_of_pdus; gNB->UL_INFO.srs_ind.pdu_list = &gNB->srs_pdu_list[0]; @@ -894,8 +902,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { gNB->UL_INFO.srs_ind.slot = slot_rx; gNB->srs_pdu_list[num_srs].handle = srs_pdu->handle; gNB->srs_pdu_list[num_srs].rnti = srs_pdu->rnti; - gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(&gNB->frame_parms, - (const int32_t **)gNB->nr_srs_info[i]->srs_estimated_channel_time) : 0xFFFF; + gNB->srs_pdu_list[num_srs].timing_advance = srs_est >= 0 ? nr_est_timing_advance_srs(frame_parms, + srs_estimated_channel_time) : 0xFFFF; gNB->srs_pdu_list[num_srs].num_symbols = 1<num_symbols; gNB->srs_pdu_list[num_srs].wide_band_snr = srs_est >= 0 ? (snr + 64)<<1 : 0xFF; // 0xFF will be set if this field is invalid gNB->srs_pdu_list[num_srs].num_reported_symbols = 1<num_symbols; @@ -904,7 +912,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } fill_srs_reported_symbol_list(&gNB->srs_pdu_list[num_srs].reported_symbol_list[0], srs_pdu, - gNB->frame_parms.N_RB_UL, + frame_parms->N_RB_UL, snr_per_rb, srs_est); From 805b35643f047857fe3604c5fd1c265753418855 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 24 Jun 2022 10:37:22 +0200 Subject: [PATCH 30/61] Updates in TESTBench documentation - Correct carabe name - NR freq bands with "nXX" - add amariue in figure - minor changes --- doc/TESTBenches.md | 12 ++++++------ .../4g-faraday-bench.pdf | Bin 53134 -> 53079 bytes .../4g-faraday-bench.png | Bin 92391 -> 92377 bytes .../5g-nsa-faraday-bench.pdf | Bin 337513 -> 337509 bytes .../5g-nsa-faraday-bench.png | Bin 89436 -> 89413 bytes .../5g-nsa-faraday-bench.tex | 2 +- .../5g-ota-bench.pdf | Bin 232494 -> 232400 bytes .../5g-ota-bench.png | Bin 90027 -> 96734 bytes .../5g-ota-bench.tex | 13 +++++++++---- 9 files changed, 16 insertions(+), 11 deletions(-) diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md index 547fd5a23b..7951bb6a88 100644 --- a/doc/TESTBenches.md +++ b/doc/TESTBenches.md @@ -9,19 +9,19 @@ | Machine | IP address | Lockable Resource | Function | Connected devices | | ------------- | --------------- | --------------------- | ------------------ | ----------------------------------------------------- | -| asterix | 172.21.16.127 | CI-Asterix-Usage | gNB | 173.21.19.14 | -| obelix | 172.21.16.128 | CI-Obelix-Usage | eNB, UE (5G) | 172.21.19.13, X300 (192.168.60.2), B200mini (30C51EB) | +| asterix | 172.21.16.127 | CI-Asterix-Usage | gNB (n78) | 173.21.19.14 | +| obelix | 172.21.16.128 | CI-Obelix-Usage | eNB (n40, n78), nrUE | 172.21.19.13, X300 (192.168.60.2), B200mini (30C51EB) | | porcepix | 172.21.16.136 | CI-NSA-MiniBench | Executor, EPC, 5GC | -- | | nrmodule2 | 172.21.16.139 | CI-NSA-MiniBench | Quectel | Quectel module | -| nepes | 172.21.16.137 | CI-NSA-MiniBench | gNB | B200mini (30C51D4) | +| nepes | 172.21.16.137 | CI-NSA-MiniBench | gNB (n78) | B200mini (30C51D4) | | caracal | 172.21.16.132 | CI-Caracal | gNB/phytest | N300 (192.168.10.2) | | idefix | 172.21.16.135 | CI-NSA-MiniBench | Quectel | Quectel module | -| amariue | 172.21.16.144 | CI-Amarisoft-UE-Usage | TBD | Amarisoft UE simulator | +| amariue | 172.21.16.144 | CI-Amarisoft-UE-Usage | nrUE | Amarisoft UE simulator | | bellatrix | 192.168.117.115 | CI-RAN-VM-Deployment | Executor | -- | | nano | 192.168.12.62 | CI-Bench-1-Phones | EPC, adb | 2x COTS (adb) | | hutch | 192.168.12.19 | CI-Bench-1-Phones | eNB (B7) | B200mini (30C5239) | | starsky | 192.168.12.18 | CI-Bench-1-Phones | eNB (B40) | b200mini (30A3E3C) | -| carabe | 192.168.12.211 | CI-Bench-2-OAI-Phone | UE 4G (B) | B200mini (30AE8C9) | +| carabe | 192.168.12.211 | CI-Bench-2-OAI-Phone | UE (B7UE) | B200mini (30AE8C9) | Note: The available resources, and their current usage, is indicated here: - [Lockable resources of jenkins-oai](https://jenkins-oai.eurecom.fr/lockable-resources/): @@ -40,7 +40,7 @@ Note: The available resources, and their current usage, is indicated here: ### OTA Testbench -[Proper image to be followed up. TBD: add antennas/circulators] +**Purpose**: Over-the-air 4G/5G (NSA/SA) tests Note: obelix and porcepix are both used in the OTA testbench and the 5G NSA/Faraday Cage testbench! diff --git a/doc/testbenches_doc_resources/4g-faraday-bench.pdf b/doc/testbenches_doc_resources/4g-faraday-bench.pdf index 7e31789e9acb9a3cc05719d98304966708925ff9..f6f7b078e67c61044004c70a92c729b14079cafc 100644 GIT binary patch delta 8561 zcmai3V{jb+gKQe3u^U@W^ImMfG`4Nqe6elYwrwYE)W){0m)tjVb2srp$B28)mX3Pz{ecdEblnrju~7ZGdt8%F?(PD^N`mxx9aiv8g;de zWDjzhetg&8BL16vD*JN5jSJr)DN-_QgRSK0bS-$rWm8ayCk4{c_-TaDJoRvKdD?=? z6pmeN)CO)0WXNChe*D;dC`rP5E0Ydcd4rTB;0gZhK)umT1vwq2xtHN8q7 zs&KmL7)TS4+JNuVa~p71a{I*p4nmx-fiZ#WRNKX0X&n!;hi6Q|jE$vXBPfVul?FP5o7*K^m)nH!c2AoHc@M%~S(k+T$Ajz^EyCB%)v63#qs%F78u zd&v1tZv(6cAC~+=_xZ~PD3rr4%)*q)T72?S*b1PCh80^uB3>G`5{^?GP0Rz)RjF4} z|HoNfYJGVMfsGbp#*aFeI4SD5_(k*12SF>-mfk_kOyjRSnnIW7pqk;azk`g~1t}j( zqQFArw^LVlqKVQJxwW6 zLIi1Cv>0nehF`huB1KKqg=JLfCn)mhiF8)0myjd)t2*B)G@3LJK9r$bN5ZEkL+Sj%W%AzLYbjZDq zX#WD}*KpnyIBFHCCM#xe$gN2sp7BQzjAFL|ZOs)1TyP%S!S9{u4fJ-)J*?V#Cx=9j z8zj!{BRz$z%nw?@p1*kr-6X3D+vtxfcVEDhc+cnG@7fDip|QodddQn*(K2Sz7&BUG zrXNc^8#ZRG;VQ^{faZl7F=4b@ zQB*d$%-KkD410GoL`>%^xAzO6@3)P;k67dT=Qjij(2F!PYLP1a)yAs09Wv!}5$`73 z4{!;~i^6oc2yPF?a&3HBHd&+DGHCOp284BT#QPW@meVb>F*o5&;=BubL}vl0ni914 z$3lBHml2EHoU^QoM)UQ${Uy3t=0HO_DYv&gIxwkG0n4lFCjD!33n<*cKT zj~juyZ6wnV_0?`fNwFNc`w%4xr?7O|)fkPsJDWRPni|75Uk}-aa$;`9V$9@E> znQ{m3d*dgs(}}0Pur9m%B*i+cCL!4RDneEcq@OaTcIGY?tYj?z1IgGqxc@r|U6oyR zlC`@^gr$@S;o@rxoE5Y>g{2}q2|xyL83ZE2mc%ya4 z=S%llckmVI)uuJSH-E#*p%Etwu2LYy1(Yk**B?|2D5=mV1G*OgI%D48*m#UDL;kfw zlDtOD%vfBju+MnD;^pnoZWdf%%mS;h-d)*j7BXF4_jr7KDx_5Csd33jy_$htFdW6k zfe_rKgZe&YJd{7&y6$#3qZH1GzauQVg>iIN7BZ1PAru|e=mwO~L;z78!<)NWJkp<; zHDXj}ksuG*nCTZ77?@9xn5n6$@Z%;JNT&J)HjG?oT^$*%ANJ&taUlg94Cnu4y)H8J zBa+>rSvhF%ci$@P4Nt*uJ0}VXyI8k=9GYk+Y|s}AjNU4dC3FRx;!xy?xrenoB-74jwRBHs{-bz`RM$Gb$(frOJ5o%4M`UnPcq7Wn8J z249AYiwi5XLlc^y_1D(!*gr7hJG>j$S%ZlIMF2B%-`f$S$Z=lvh%O%WSpACG?eY_;%{ipY<1-EV6NL@_Zs3@Y_+;l2O4jd$Vi=-x*-cZJ-^^LDg};ipRW#RCd;Sb6Uk z{7XK(s&EV~j+9KU2qX0FRf$ZTpV42c@FJc1v|z{8hvOV@R6127nknXj>Nl?(?5S!8 zSH}iXqm0GEV*VV{l&oOHit?Zehs$7qA5N{>d=ljbZ_>lSDNL-^*`3HXL~-4oPIFp$6Jn`MsyM^s|(dge(30# zGKEV@ygrlQB2!7Fw}o*n{LqzncEYKa5zAx)m-jG;V-S)jz018Fy*Aj3$t^z zf$nRj+!p8rfyAkw{O?7@F!wienr4y{CnxX_YFC|uGNSNwr7^=x zj|aI#JI-;Dz(%eU08cQXK5m)(>Fcl;Z6-}ZEIbQ1Ydjx~Eyk6&tio)s)}@J(qo<05 z;bLYLS=v`4Ww}}-bXq>);0B5W-Q=P)uJi`dx{ggBlMWXF-zZgw?PhILu_K=~Wwfvt z{+EMQV;L^S{pwj{DSuZ=l^pkAXUB(Q}DwEDLfMI~q)4)P2~3%6INu)rg*D z2U7)h?}_r&hXc9HJiD|>hK}`}(zWN{JDQC6VBPh`dz-JV_Gk=L9xax$gnwt~2Q1I= zNfe_PLjED3a&+dN4o(`Qev9%7;mvWCFgCUU?Cvv7dtCm@Dx-llZeoeoSKDXR`9nm) zU#)&{bB}4AW*T`RU!o&5jn!_H>lzR93J?ajz6?f53{> z$)l}AmjN%0dI^+$&nxjyX}F|U4bS7+b^FnHDJrcfO&l3gojOK*#p)Kk`wm|b2F?wX z9FS)2ym+()@q_t%jG`*Fi=(soGUwNBa|Ojc%Q5$Ys_Qcc3y|}ck(73Q&e==I3+urn zEF)LeMi8lVHB)46({z`Yc8nGS=&@yi4X&8uwdBoCZD4V5s$=fpw|j#Lm(|nPNp77h z3HIDL6Zc&b{L9Y8zL08h1oPltNj+q(zQwGHc$@ptyU+XW*e;@fPW*3k?rUG`2kuaN@LI+{_M0q2MID2E!bgjaaK4|a z&EEpJ+|xQP2Uo5JlLfO~Jm0ULri@Z%(2DU!!9btCU3O$?Wmy# z-yMr897Qzvbg3`1(0siRfuZ0>hSDhN_VghvDGL>ijK(O< z`-9TldXq_sa3!JYwVCF#Yr_>hnuQDvtJ<6ar#S%!5gpKPq;KK`xELa)o4-Cm6*fC^ zedew!q;qC9IxwM!9VB5E1^COvyS7{1N|fcX8b!C?-4cB>osujpdjMd8Q&dGsqpgVA zutG0BY{-&=Uz*Bo;Ov|{5nkEw&FhV|nq4RM)u3Dup`UV9_=?nbU|WZ;F98;TY%a2= zZ4tJyJB~WHHo5JpB3XAB&7Lt1t4C9>`@+ax44Pmo4Brx4M9d5nXL`lXM|G=UhcjnH zfF*Pjnc6?OS9$}+S4ObDe>==ijJ1}lb=eq*mc@AGdr|)|Wi4C@#V?wA6ExSEf0%d(Tl>X3W%6(Xsq(kSN!3ku?)>xfOI<)A;q7Dxxh5DU~4E zX^v4W9AO;Rdyo*j;_Rw*Ry$QtkV@K>*^_K2sd7>sht%4T&JtWxRf5*c(n;$D3KT@Y zWGwOU06SRIx=cE?*NJ2`MXDR@Ts;j?I3Feq8rpI{X}yvpCrtZy?28{nKI|9&+}!^n zP_{>)GGU-H^}rjmgem>G+z|WWYx*Mdm60~`o5O8%qs+=n2!9zTbDzQNq-TIYte?VS z4K`xYtw0jWgatT&Q#bj6hHnZq=1Pkb#VrT_RNXyE63gL-+viV zaaz~V{Z5zZc{EO$Pn^m0sA?#4KRgQ2?3T!p+7Ax~&PuOkg)V+wLm)IMS3__VK`RdJ zH~+eir|fyD5#n<^(<9H^K0b;h_w2qVtF~04God65?ovnIo3p&?k*c%I`a34b@h5kb z(Ljp-k0V%r%rMb29dNfp-ZY5oHzYk`nO6M!44FtO+YE^#+!3R4E{E}wIuGP3aewGH zE&yOp*2U+(NTUcdKb`YG%tP~Z5c>_|6bB~+@vyUOJ`x-`?QG5M9TGi(_j??k)Y|Cu z@2r3%?hw%>R>;yYi%{%%$Rzp5;dHGqJTs9->Vr8X(C1~anT;-IY<{qQ?e0jp_d8KZ z)Jk*hutDVIeC>rhx~s^@G0F&wy8Eiat~)G}E{yPdZ(XG%f1L6RNAo=E<#Hp%dT%<~ zI*{?>Y*5bjU+ve3s=v(clx^Sb@P&}~G;;XwBU~-7WcmiAOZk`b!HAr8mr6dh$<3=E#G9I0vVY)4b(&-H&No(o#bB&~jU%*Io1c&qU@_Y5zx(lwoZ;`<|B;=}Eci5!DF zg+^6DS{=86WP4|?h^un=FW+>b7$W)2$2GyVKTPR~u96PZJ3?yfKUp;wY6DJuzNQl1 zqR}^u%BByd+H^idYGFzYDZiK=Fs0A|mB)ony(7u8=NETcj8z?vo?PnFh7k(@QGvX+ z&(OC?3K`xj;tPJqfSK?wwjfWP6i(6VLA(2y!1Z z#8j7S*`PKiQi3TyLw!#6>zM<^R--JG$oPnj2tM5fUw+}MH4bG+!CWf;gV+?680t*0 z2Q|xRE(S-|=oqhrxqS_l+l_y9C{nk zX^+JDTEXaLKXx0hjL(Kln`gnRU1s;Tz)|Zpu5TsC>Gex99hFhi_!~6e#RwgH0XCQ{ z`mzO>WxpzWiQ4L;sJN#}sb}Nd`F7NkI`?t<_zuoa50F+yck6-=`E{}4Zm|j`<3G~P zastymudp9Fi2X+EUt)0LW^Y)X1?_yZTREVcP)gu06fBx$hr(Q@>cqhz8TuEy9EXY{ zlteLg`U`MvD`=z74|`NxeRgYAdA7@^I4SSIh#R{GD3X3&( zyRghR-#SmiZMlVJjmUG z-VvEu7dtJ)BJYg%9Z%$h&bq@RchZbJQ8W5r-;x6iX}42*!h7=~PT@{XBBSuB5Tsb% z_AHovTMazE7oH0wa;&p5G1YHoTSAmhKn;!9=v*p)enj97R zmntL@a5+=7!bi`p5}co%c$UjREgLC_$&2on7q**om%g@FO>l74c#V%p}XvGbe%?kMtQF z3D@OdA)ciR`(WZs{kS40$>`}eM2rjmT03@#r|@_2Yi{q5(2KK4wl^akN%9GphR^z^ zaJ{@S_4D?2NZec6i~MF?0K=Udrd=X(jV(s{78Zsj3HGhLwDPM(xj6guU)Pz<+gV-h z#j_pZy;<`ugU}ANFtfeqqB8b4b{{WXd2U#ys3lv~8Sp=Pw#>)NfI@r+hpY*MBKmxJ z``Ru6avw=cO{}J$INWicOvTaFv_#vAX1zL=IpjtTzEx!!i4voJ3FzvZ!!P-f`#c!e zDi0S)GCz{`fz4aUYmrpsz8b0&x4joDe~aTgx;lLT8^;!$NPZ5AKU0@6RY97r)2}}U zx^L`dGr;;~X5jq3eN8-hUnbA`vErCJ@pRq%$>zj}c+k|Qvb~?uDC0;3vTd@4c^GRb zj~#A>4;3uVQM%7Rm-$d>tl7n!45o@^7B5T&Uv-NVqw*_PxYX+*i50p|iuZ~mbC71P z0_h=UFLEB%d9w*}+T}{yxgD2`bg5hJS{jOs2bf^oYLY$wd0+e&MxH4U0^0xQlX7Qm z=_?Ad9lkW>vfV_$iOt--=vn^uuW9bJLJ}k^IvK)P+ug_r6Kraact!)M{Pupi`HB$H zXB$muLOy9ffu7V!kjcLOV#swE^S3iOWpM4?JQVHNElmqA424Z3BM;}=Ijye?zSN)X z7F<{54gX`qPk`cxe&VxaS;EZd+>+eQ$7yJp&R>(u{E{Zn>wt=Y?aqArD6Qit^yqjIqqd4uaWy$LJ7eF4Pm?jx6fppi{KK&f6QGMp;m2^gm0~ zjcL+*rrjPdZ%IEs6MmAW<=JDf4Vtu!II>N3%tat<;CiMrHUyc6cL2BzG+aE%2cuO! z8>}z~rGh*JnzQ{le{#1Z@Z0l7(_qVl2y0 z5#5`-q*b+Wjq5t}=MptsTytsDId~q?-s9pzWkY4z>Uvc>jp#(?_))k>X7}V}EC-SE zB2rynS)3tR4K{5vCoL@%6z-X@feF6X0-@><4m4*uL0%yGc+CIfG&?X3NI z=g#Oyd&!8X-_2#Ko{;aQig-^$8V?>U1sL{hjLad?!EmRvUuRf!W9~_47|i`87l*5N zb!H&;Gr-1&=(JO4%w2A<)$yrL+eBb^S-V2J?|aJlq7`K zYBI-l?E4M`SHSlN^9@+XWpLtzp4%*8mNuTMPFy#E*I~Zj{c;K*|6aJKNRz8Q3IJ+7$pgTMa z?-s`YlVjYYYV9S;&QD!^i^rfe73yfCA5*ViDTRY6g7Y(hpt4P=1Ki}@dO2fE$vYc6 z*hFbx&1h1f;o0bl{i}(yk8-*qskOfOVhrBXL3pze1W;TDQL%7MuyErR&gW8#?rOEa ziC>3(=e2TQ;J5sftY1s@_A51jM2!%&L)Jd(G(DPz-!R=O>5t#bR~hLn?qG7>Osv?R z`5A)qdGU#p!)^D>IPgk~@l5>h_NvXGYFCXE+r8xRRvi#<`EQTE!l>#CI21-AYZ2Hz zzcuKIv(iP+Wx%}x;fpgpcfGkgkG**Bz*Uj~O=l?^!JV9Ykv3OjNG>riG)Z>3T;fje zb2gC4>}MUo_9^S<*aTqiuLQ`fo*nw_M3B;r-986toGv1YfSc93nPlxXFHsJIJBkVTk*$s%#I2jE1GlTu$h*=C!!?Zr*SSkX`JhYj z9|(W-@3u%dl2kq?QFi$nKi$mgy@X2(J-_cEm;qy{eQZ=v6UQBu#!mNw5GiOY;2clu z8d~#rZW*{z&F-T`FxsCZp$|xYMSBwjQ55U6WPHOEz2i zUKmbG;@|ONAtk%@x+?;uL{s>fq(P`#1^=mo+1Z2h^JymzYDosF5|oN`8SDfpy2VHp zDMRd}RBUP4RRtrK#$*iy3ztxrUy_M%guux_TH!pZVr3<`1vn|2?D*fuSmL3w_|kBP zyJCa*(FXlqVAE)TSPKfYnyEp^k9rd8jySp<)J{Y7pb%a%5Il7HGP#Qe3pKzbUoC`2 z!A4E%3z_jyJQ*6XV|^Q5c+^@5t>a;-0J?vUVhItZ70 z*a2;)32K##d>OreR<6{8>KA?-?D~RKh^Zo!_~NP!Zm!a)d)h~Q4sUNF1l(8U zrS{mo9srr_Djh}{KQq+B^gk$gcLcDm*glb#sPuDf@0hQPQF`ss+>|7<<#6)nqkEm-&4k z34r-_Pp8G6%SueV@W;QD->d7B`ZGg}`ukCJ{OW{o;td zk2gMk#tL*mVVG+Ei4H$SvDbp0=){&)k0l zk0$LqBe6&Oz3Z@_Jn^anqF4K4NkR+{o`MQiGi7~eZtRvIdp%QtRggh?5Mx>C4UQke z2D+6#>i5l4HE3blNQTul(a3xSWnvt!kvDw_@N0DzPluWbFD&g!=HNqFfd#~pelwgx zpsB$Ai(d8vJc93Mg&_&HqlC*6_thm>oC6MOi_&*Pf)NPEh*S2@Kmb*`+w-vYB@ z{-EM}a0(e3f4@G=0~GJ0HM@$%%&tH{6acj(rj%(jls+@0sA&+<#|%k0%{DPmF#ssRh&R(?;b60y#W6ma1} z1F-EwuqYEE8m^53f%-BdGCtVg5IS*955)+r#g9?E!rU$|8p7Z2s*xq_IN-O+^^R32QhhsCw8h`tG<56T9(+$pJ<|4xO|G z9@3URVfeW~6ntMM0g5^*=p#lA?!_7#WVX{yYl-ZlMi~havNd46Pe%K*t79XPPM5nZ}3mkJkO{)efB&R>0UnAUDa85 zHE#+*jsAooyR?OTEKU99{#&%0ypxio>lqtG5pi*Dac(v-Ads6~j9U~WEY2p($-*tp z#?8vgD#pPsK*sm~N_7ACy92PXCDqI_fG4C;2Mn-BZk#98=PK(q=T<}6HG=rl0c|i1 zP%>g7Sjx%+`PP-r@O}H>Iamdl@K9hPU;|SocY6mumvf#29lhZ}r}F)>Mwxu5#+8hk zKB`DRptqhsIdZXhwy3FwTsBv4IiZ>A@W9MnyPN9I4g^VH+2HVEB_;RXlm^QT)qbt4 eaoZgJko!Yb4HukbHb;WQ!Nrb5O)V}DLi#Uk5Z#Ob delta 8689 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

U^jvkQkX}oYqF9J@~lgByn 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 literal 92391 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

h0&06N?X9REx=xt1C&ZPLaVB>*KpD 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 diff --git a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.pdf b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.pdf index f6d960c1a257651b538b404f8f019438d3014f15..1b921e64370954673e45ed70ff1643462f4774ed 100644 GIT binary patch delta 1414 zcmV;11$p}E%oOF!6p$tYHz1eLtpg{KPYnXF!I54he~5nMzTLNY0IkHGP~vK(j+~K? zN}wRJpp_R9!6*_p`_(tWpevD)D+M|REB+Db@+Keo^HC7Q5Q6T{pM?S?Zjb#{8Ujm- zNVHL~po}u64W4&m^;Zpte5WeEhvS>Q7*gHTPsgz)C<6o}VFD<0DZf`guzv!f0~4)~ zs3RB*f9WZg+ts`G&as9kTKHgrhwYvCkEy;(Ao9nyX z`t$a~>ep@4V)O(KvuQNCJY-8`He0k292sF8kPdIk_uGm)0hP{=IvA#&=mV4s?|$2( z_~mi6Nk1)ojV@dG1(q5VSrILerPEaL1QfU+e;6D%Yvx5Mpo+;x^)Q z`}D-FaZJsmM6CrEXrXHgs)D+%@soBLUBQO!Qpn1l?TfxCLz-!LF5_&`7k$%sHa+dR z9ZsyhM+iEZgNERie6zz8NUr#`Q(dlskN zA2dyq-0FyD7R>7`vptjD0vUflpTlI0Xu-!GE9XsC&bzEUYO{v76ub;euR&YGwu+JO zwG^|_25)h}XdQy)sUscZ6`g9en$10?Z7kR&pY0$S(M@(ArY?H`8unMA*;vlb9O64; z@I2sdq@QlFHGGS{z>*1YGL#JY#FFzSF%=v+qM`+d?JyORi~jWZe6xRhnr=;p&|&E- zUD^1SZccikVOKW%US+k7-3(1u$lo|Yp22L|v2<<2%Y_@{=#F9Gc;)g5gdUW7vx}?X znS2(v4YRmuyPdx1s15`+GXl#(p)r^f*rz$nb>pm}K22V&2#ia)qJWJFyUMI~w?JVDeuD0{T?6}0=-vk>iy!gD6NjH||TE=c6b zGZQ9)h(!5mf2*Ufx#-YN8_&KN&@L~}p%~GcgJ)v+KKz=BF=Nm z@yp|ClYUzG8eO*V3oNw)vLaeVmQGW}lcK-{f5G6Cvu0kD0;-s-$>W#Z*ZY6R#UCMu zwXb|-BRroMGG}LnH7Z7WYxOAvUWvK-?Xaspvg#p!4@Q}AAOp?GP-w`;W07u*yz)}t z#nWU!G)kl91J7mWs?X|BQ5BShxFi6%zkj$NYcWQT#3-y~qupo6bhNU;SuLDb=)ili ze@~~06vR}M{`A)alQ}GkCWY)-ycVOkZCn1bfiMC9M5q@9j2UhIw6qQ_airYvf|6$iff5@m0M?o zGu)>qc8z0dCM9aEa)B1Qrl2aQ>l#04UzZVV*e->v?AgBPn=+)8hUYTQ7Jbn-jc3!- zp4;KX+Iv(%Cv(s$xFz50Fa?t9{;+%6eV@4I05>(wM7D8#(KDrwN>ezyX*L=!dZsj9 z1;QURO_SW}h-Vhe>nyX~liLCrf8U?OWQ}OS#~v%^O;*mktUPM7Rv}=ju;&#)jt2<> zp5|iAPRlW)TX0&3$_L&>?h13N)v_ksSUkpZ@UY~x9jIW6(T1th4q(GB>$ozrT50etl0L^qdSt7%wn5!rPZQOvyxe> zFi1+iPOJ22Ps87tvTD(1vg*W&!xofB)M8iUtIW9`T(ZW0`N@@LP44uMH=casiO(&~ z12FRXWMhl$GYe0yimIS&Z1=ajPXIJ|c8$R!Un`_#W8J5QhLq!WqfDAPr#Y8w2>E+2 z6@MP`_SnBY{|Ddy4by|Z1c$x^0f)W>0*Af?1Bbo@1h>8f1uq&bH83_YGBGqVF)J`K zConK4DGD!5Z)8MabY&nYL^?7sGBPkVFg7tVF*GtUw;3M=A_h?~GDA5tLqtR|L^d=q zLoq@)IXFW#MK>}vG&nRfH%3A}AUrTKLpd`;L_{$}HZ(9pF+w;wI72l>H!?LeI5aai zMnXPa3NK7$ZfA68ATcvJmy9I^D}TEU!axv&;Ti9pdE006j3A)_%0QwWN` zPAGr`%0L3oCZG1#XaV4t0Yws(sEP0dQE#B^(2i%&Zfnm{G%HHaiD)w}?w(UYB2S)~ zFcCx~(x>^Y_P*w#MLVoKyP`)sy*&G3K)dcd3x@B*udx_1hOOsF%oyhvFbFQ+_ydl+ T5oMP=CIuk~GYTaoMNdWw2!WYd diff --git a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.png b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.png index c677b598e9894a1bbf0e1e7321497e4c51e6fb17..006e6ab347d2dcd3283f5cdb59c65d1d1ba1ea8e 100644 GIT binary patch delta 49697 zcmXtAcRbYpA3tY>q7+g_#gQ|vH0)K$-VWJ`WbZvbsJ;nB$B`|WXRmBdg;1245M||L z&$I6L`P}t;K6~&-WqdyG&-?v)J)h6lXS{*7y@9s8oPmL!mQ~>FT|rils(J=v46wq0 z;15^)bLA`a=o41e z$8k?KHHk<5JEMM{w~iwi7{*%{-%nS2^`=Q(Q~Mc|G0)A;%kr_EmNr>aalZG(xzQ!O z-(+s?sB_xmC|pv^{-pHOFjXxxj2YmT_WtwrqIG|cTD*W3JaGH(XqCMVPkyv=$6>CW zl>-E!a=(?I%|SZ^_Ry^_QuKzYd2T5!4$|(stG_-xW1&_fBe2pSnIG%;Y{Ip6Y)R1; zLXNy%EU!Z7!LG+t)&fWd_Y*!KX;SY z)Dt~3)ZGzm)E%gZPkmEUB<6`v|Vdx^G64M%W`iopU zWftPgyxb5@_y>>?v)?BrIX}gPul@}3_?GWDY256-;x@S9ig8o)?@)Wi9Wr{MOPGD(`*H8F7 za7TEVa|)N(2GnDclg!2P2fkP8hz`w10ETe2_E$8L+W8+m^4Np+T3OE&u8H3(>zVbG zO793+8!x5NZ^-VxR)ASjU9~Ir#`thPzBbfbW<#4aP?!-L_;7Y-#1;;x4he2*rm7l! zST#Dh;VZehEjzLjkX#^LpVR;nPKBax;##fD7*l2Bo0<1}2tlCpu*eJzOdsvDub4Ht zU5z6J9L*CmsUuZne=m|YTBf85-nmXR_$(U9G5laNHuq>}Glsd0y#xQ0WW;DBuD5B= z3tWd_xRY>T#b7o5v#!|#ztBIBo39Zr?v-30Gnsbb5`^sN9DsCmxW6-^6#x0T$lRAy z3AdlJQ*HFT!N6)8{npk>(?+k%N)z?xG%2sS&&l|iu6RM6jL*|*KGD_N@f!w-`fVa@ zSVL3J$HEWVhjP0oc$Ox(Vews?xhZeEY+hZU*Tvq2#bH3C9sm2i!ewmk3tmg&a6yOf zE{uVJMC`*L8f>P1IPLH7%9^lD!I9sk0@go1FBZuH>goy#vS5;dn}5E2coyE@4}J~S zsnuV6Dld6xms|FK2J!l5{Wdogh<9WtIDgP}?J^1Is4skCsCl>&5JaN_9Mr9|p^JH*rdh{0z&CLxBO+=45Pc+!|%zaT@`5Cgexk&F#7|hk! zSyr5EIoxOADyVg<8g(8fg<4o4^Sb-uE8d&|D383N-m4#(*_YT}&(3AYr>8QVVP`*c z=8V6QHn!|je+9Vd0Oq`i+H;S^vQwH+V4OjfB?Yv|$LRs)SGGJJ+M4&eB>O9j-6y4*y+A0zMD zDTdC;bt7(Nla>k>rrTpUu365|^HDa9A<<|Klx36u)vs?=VtM2O4UcEp5>S(r!MfFxGgQ)&`lzjS)=dLj~XW*TJ(qiPMp8#T)-qYGrvD8zr3;p;lxKW z{&)Zm$^KKr)U`ZyY@Z~t9>{6&w6_DMX6L1Y$wwTzaOvCI2HLEIy&iriK|niA(&P7& zj4^_~pd4bB!$XRhzD(MGsI4gMH($F-RP5^GSZIm&zN|iuVF%B+8s(#mB$Q?Md|Y(_ z3JIZqCn@~A!!HE2+{d~rBX>~gJHO?Bh+OTD+t%_CLVOd7SoWr3=D zwfN{5=YD7){~TF0Th7e6O=cYD(ty}!jK!oF0A6$jfs1d3npO`E;Qe0zsupe1B~dufcG zOOm`)6v4$H?L){x@~7S$nw}8%8_JcZjSCJ{6O@`Z*BAO=@L&FM`lw;H5@FM48V|(^ zH|&~C&i`yA7Z*O(2sSjPT)j+L%@&0{ZH(;5vCBNTAX9PlaqskE__&~F=BE(&<^6Ym zfw4+AD(}1Y-gETa&>~OgPX3r4S@3RYvK89o_f~#RcS2={IdE}cSIdzYWC9mSMk*o& zpz|Bt^ir4#_+fEUWieP}2Oh}}A?LRp1M`#5SMPX>%>-jIrz;Z}g&9icdede6md!2h zqesV$DqEtp`iT5WQH+2)bbQYChsRZSUmKQQF!G;$EYi2fmwa2jM1@CiallKvYaAUo z(csy=lvrP|nbG5Go32llX9~l0qXJ@_&BQdO5TeX-!d>QKc$=%q-L-qyj5M*6jzo>w zSd?%6;A7S=Dwt6oM-D5PNSF1 z^pc+sX2wewe~`{V4YBLqD={h>V&q3aSg`t@!(nF^Mc!z_C&(Auj0D4Gsbh?!?j!1O zs2rcn1j%kY;=_Bt@}Fk1hcebpk9#ajX2e1D*_}Iv3SF>-<1{^z;lW;}a3M~5ATGC} z5-ARW^?Osm26&n}xdJbg!mbz@sVQ2g@u|Yaru#pgHQ}Tdt#>|-H|bJVoNdFVWp+%d z&((<=nRZpagMPyH>{kEMAC?PKDyF1+BKmJ~OvI8VOH;!s4Tys z7O2;vRYS&M@T$g_x_o^Ak-5lU)fVL^Zt2pSg)tW+W7F=S*$fHijCA$1FkxyP zvjhDQyo(yZU3RkGYaYCpK7uzMs8qy2IL`fNuy&fy;9OT7U>V!Q6CfA%x7C(}*hhs` zrGw<|%U1`q4M(C%TaWe@%UXFPJ!d|>;#1jtF4zXdq=or5f@Q983lBrqJGV*jA@H^M zF`{jpML_%TKZ{e8m1*Fm0fclHBGU(T{$&Z5Zm8y^-$ zIT8s%4r_e;1(@);DwkR4tAdZ#NU$P0xf`Bc#XXhOod|B6+|q#eG5@J>dLI8NDsFeR zDFoGHbGPFi$T40c&sXySR|D3e;$<;6O^4OIi}>hxX$+h34HaaVp)H@%5V)#*ohKN* zm&bE8YF#sY3~-mgi;89O_bx}UY42_11?w7wHnQGXh(gp`$Z7Z8$b}0y%+7lj))&am zx9GEJfL{|(cy~@zvzIZ5ZF5tC1vT zVd^nXa-M&g(CwI9r7quTE4LnW%ZQALRJbbqGO>Pf1wt86+EdrM@47Rw-1w&R5VgS` ziZ0w{2lR>jf{E3u@w{=Kjlq040EzjmjzN~d5OtV-fT37yn7)d?#WSKiH2ti%&DZBj zie29@ZxJd~UIq~H>oK#OJ=emn;W?*{Pd!(qtm>`!^Wg}}oqnp>=fg{ap>j)HwzswzqyQpIW7+#+a8J%o=5n{fW% z;n2n@wrL@5rGTH79>wu&hK51>kyl^t_w+eT*R>j|qLo`dU2IiRwKMXDa6K*wLOyT= zSQL8z$+wYLAn2|b-~ABtALj`wl>)xOQ;e?#l0i~kzI7@Jme%2rHb*qTI)WRXDq*Y^ zTB%zS`8k6+mUS}_Y$twe2kLaAvh4SnQZzG=g2f*FH7U#Yh59rC)z!08;~`9ci*o0g zyPpx7*6!e8ng(+PI+yCWHFckp7j1#1hAM=wNr>0t%>3z2x(I5Eq#~x08P*Pb6xKXR zFu(#VsKK&=t2sekSW1VE89FQ!4+F(a%B|ZXXySYRYX)fzaZI0S!hVK1(=9qRx z!r1uHlP6F9`|la`hi72<43^PlP2yg28Yrq*KtVoW-9U%RtyL~)yZD~sbO(WHB^QL9 zouZ!J{rgH(?vo)8I%E&ZUAqLS;-9Ekg%ZK991I7`GY|!+#7y}TY5De#FyLt8)2rIa zWlqTj7}IK6H0~h(wa2nhAA6{4?Vha22ToqQfp|LcZ; z^rm;tqm_0&iDBd=VLT*QnzmbMsdnA2QU9LZUx$!hdO~Y+)hvDW-^?aGCR2`Tu}3Ff zyI!5J0R;#JYXE-~*2(g)acub=^)Ays_>!xNo}DbC7H5p4TR z=~nVP4`s+rGrb%l_Ds&F-C#!u$hg-K3S{1Nap>UA?IiWuR$6wQn3<2DFm8k`}u;zz2jHn4ie_hvHadb z7U(sqsojn5zD%S=t8bLn{f-hYt-F;eiMi9wfNcG9us!D1dbph`e?Rv<4yj+yk2PKY z?-gD>R4Fm1250qpmfBL={{h3~+TBjzJhvN-qznXVb`xtV>vyS34`sqizDJetC`=8% z1_^Vm`!yG!0&R6S?$9MjW~qQhC|$O+-|~39m;K?>{%%!8G+Gxi4HxG?gFAGC_rm*W zi!qZfpMY1>5)VJWzWSiUe0MJft0F#cps%mrUuuDW!f;wpe*1N4F%T8I(x2;O3_iW6 zme&frkuiqT|0x`9PRD8_!3DJo>K%ShgLP9stx1jJY&V==wzj)R!qbVsCpdT~e;}rhij2!Fn*(b~<1m>dalZt^yGA#cQKI1piGrwNV@5sx zv(e-|>MNTTh9zyOu2plCZ(q3W``VLfhR)Nl#j6nUG^aITQi}C*HH!v_|?q&$xwR%SK*|ky}9jq+0GoTts%0p>c!RJOH@|@3jp8T4@T7K?< zymjx@`PW{sd4)8R`w=zXr;d4K?IRyWx6pWeU_t2{t$Y*_xN|1h);=If)C}AJ#1FqX z6CYNYC$iu6p?w@zB_mcm(;%y=jHzyr@zwl-=H=nx`C0y^fj%pL9aI-qf8Bl-21y{T z%hFT(E8tD9r1>+^sFUebs#o%%zu%BnrSs)p^vu$jm4|Y^wj!j^7$xGqu5Qyc_^o_< zYp=5vaEhI-+HDemnm)z*Z*X;A*$lMvaqjw5DWB8rDhi?mYt6n;BRpP}reOg4mzZ(a zAwu6QauWQ23CQg&&943(VxpwXkr^||D@CrS8m|378(a7cp^X$ON$><93<3QH>Jm>O;3k#S3Zw~bz(74WW17&mzMdzy5(^4A$}tG~0sPnAHk*3z=~&e*E?D9}jv zTf4yYN)TB}j%Ci9*(f)wg(|{<`mmUN4SWrxW-N{@*5}R41LzW%@cEr2RQcKY7ECwp zL38Yu{P6ityom}Tz}c{}wHqyTB4!YAp)GS?AOc}Q4IrhhNK8=wnD{eJ#uwDw9z2ux z_)W&=E{j7R0AU$V%Ing%c7>Ee<RCdfPF5?j}uTCAeP2!=CY+Q#dLEXe|Tm=00;+8M0}LahyCkwZeNcE4Io| z5&9n2A7vpWn7Q?-N9E;l2y5FMOA`1!Kz%bWqGWpsEi7Mk?}Y*m7To#LWh@M=++g>$yrQklg*M{7 z%(?J4>q?kX4Sl6=SYvR_<;S{qt45f*=iA%1ty z^0Je~#8s)a85-=zDsmU+{WU&YZ5BIj73$uz)i15va$nD^n+Fxt^w%R~w7(N1y?ao7 z^SGt#8s$p;>Hk`200}GrRTcR$WxoPCD{Ir8nWQ~i?dS8Ez!7milU{(VPJN8piMNho zqcP+iN>VQcPxBbgYjX#}?_z#o4l)f{(Z#w*UdeiM>C5oJeT!w(;?9BKi8XILe;X$7 z$!PKLOg&E@qxQXSb3^G>eUh!V&?t4h+H$_lrRMbYa3GDh)9)|J`8_O4~hhHIzq69m{fvO;`&g3%pP@rO&Ov)@A4s%!mxKYxqi3dFmSn*WiTZD4qp8!Vp+fbn~LZ6OPM^=EgCO}WoKma12=3pbqo@OL&-LNA2B zrfPf(&AtnBEDeZOE}8TKW{&hP<~}Z1$C}>SHZZpRG;ZL?Ec8H^zYQ>MU(AJT zY}X!a-IZ>#IjNk)lH8~c$p|Pm18{S*GJH-3)jJmhuP>sY_`UYK9Y59fn4X2l{Dq9b z^bz1i`f^x%ZTx7`18DkhWc8d$mgmdjtwV-S5+ySw#~$ z9zcYh$p%h71>8F=|2(w}Bl>JCKBP1JcVIjZSjbJX3|z?Vc1x1F{NxMhg*i({;#Ne9 z&g!0WVEwDQC=;zre?$M*%;>r{y>dft#yElVWS6r}zq-y*(Mmoc70Fa?D+B)8wZ@@& z!p$}7u}Ls3)$)gFOg&ZExL`wpwj}3gO2C;{dcF|e@qp)M^(X(9Go}A5#0FNgWh;x` zz;WPshxKvmfPwYAS*?~(`<}o;xi^r8{#ldTT&@2{@jYk@S?C(dd9oUzg{RSk6_e}_ z6&6Y9AD*W#ee$*4py8(!pgkHceW$eU)bvgK1j$p*bu|@0Uq-joWLChtOr+3P3lh79 z97c^>*1OJ<&I;#vYshoUrq}lu2ICDY^otJ6jT_*a^yV2}76C@ug(`*fkgbTj_4o4{ z_Gf0dYe@#DFGUf+ch3vF-E$y|S2}c*79?hm6r84=Kd?{?uKTuxGq}H?m_GuPS`6(< zZDaNkI~rj=uR(qvRp{MHUz8c~+qH641U?5A%2!lE5SJ@7g<4Uia92+2gN|XMXSEMV zS}r%KpPo%V%drxz&Y`0R;yQQ8zb*Koq56+e222ov* z0ppF&Ia&lf>&>B8)<7(H#AHViF zxE^QQY@Si@*}@JypL`p&P5OW_xjOnC*sw&go5`dkX{au?5hOL#@)7^9ZryRIsZ0gs z5zx#JXE-gO`5Nzb>GY6r2cy7)DZZrK->Uy%U(_yMP=kvW<{)_uyKXeBtD)Vyw&iYL z>bp>UaITxhJ*f97VzI(xGtDH--Y%gOX0T(t2x=r66F@1lNj9_WXONCPj-}`*E2=;~ z9&}JRgWr@yXl-bMge|%Zj}_OZlLFI<(m_&v8D;9m8f9SY(d{-Bu$!qvjx~fHqasuFuMdh%DosV% zi_r8^8Eh&UY^vH{$W)Q zSY$jaR&gB}E0i3;&aZ!daZJjdO;5`+bn#%Axb!r3KXv)Wgi}LOXBE`2?3^=EN<7GAcP+zANn}A zB)kwAYJGqjf@*LAw7_;I{HRgQoBbN7<{VzqT&i0OQ9zJeP?~R=!yqOJ5e8Z@(EkpD z(!iFL@c?&_;;opoY<2G`cHGR^q)@6X z$3|^(`ZLzh{%6COMJOrPF0(<)t#cQUoh2?tiA`j$#^SPKYKI584DTdenjma&DU|(m zZ~YZYeT6MGN~=BWw6-M5R^>=$*=_IhX7a){U)`eP)Htu1z_G1&i!OM~{jPFb!|6bd zdiHvDs@IXvUw@j`q->==@rJ5uU#tK13E|EU?65Q%SIJO}2G~VSs~=Gno7a2Jc4PNK zJGzCFWlZ74gJd)S!D3jog+gCdcf(Qrv($)sXItl*QA*!M2vZY#2I`7Wo)|WnAA0l2 z_dWD!*s>x@;kp%Y!9{ZM4DQmxbe6O8?=baQ-ZTOwn}Z?UZj(#HF1xbA`C!GppIiGD z?0+8Tue0f~y+v3Ep^tnSzHT06KCcLWV~_9fW6`?-n1;CSjc-a>Hw<|fEesRPR!AL( zW$)2-QJtfaR70abo~M6jNN6_Ob{%b0L}Tc?K*H_-L`8VoP_{c$4JxFYXaT_Pa8 z`prj`)jELgW@UmDF2+l#enKGrj&{aQ(pLS1SknAbhL^Qkd!oG^c5KNTw?#PIG|#NQ zoG@kq+FJ{Qi{H8@CucE-148gSe7hXSCI!riWU;+&{E-V z^&2uPw)WHl@k5RkX#qe;NDqo?s%FHsE_~%-Hq-SJ16NAsIu9oX#zC&O7Cu(JuZX4{ zD9SU|DuYMf0r)Rb`CS89l`>iCRSZ%j%x_KX=j&J)W>Q+tYZ9c#)DO}Fzkz0 zFY;bl_3`V;vMa`+s2psj^TY-*fu-Qw^`2g=zpsL8Ea$_s*Oiis`<%CnXZvGcu|H-#-et#~wh)Etn-|>~@IVvqhEJGje&u!QRk;m3A>=(W5v!v9oB<3#YGhTwwX$@sx*0~qV z_a7=MLmL@7PRb%O(lLbweQPcbbR{DSyTOL>z*dMV!BD%4%cw(Lq@m8F-a8;}Wa(CH zt?Mg6F9|G53V*|^3*G)f?TKM~p2Yf`O)l_;Z+jOha%-ywcZ%#B&S&~uHs(_G47}xcr4qN*Ea*1ON zzuU$FgobhZekT%d{oAXb(5QB(XHgFMaTY?OxbXnRLDV(;yS4Wv5H z_tLV9nb*1hx)l=Q31Pk781x{Da@(`#48`d*q}g%Kd6xs47)$vtV|LZx{PA73m80IP zw&O27f^bnq!OB=u^{2+f=5N3?^?AP9v-SD2^FUF5 z>`pP4aO?7V(x9dp+vDrQT6!VB-6gr0>2>vg&(FKVQg5=cyN=P>+7?@;C(>;ahTf`_ zS=Q{fKYetE?_4=c4agFi&aR;zkWB7wJ|LS9dgG-zbeDb%6_38Tt#~hah~NzuHJzEe z>1G*3g$>96$ure58d3%9&q?n_efg;Q`6DUNj?x{T(wk`SM&PtOk5pj@r9AV*4JCL1 z`JjE0BBQ|n=@lcw;$DtxQupPHYcDd!)T~zS{mLmd=uuz}0~dDR)_LJwO9Vo5^;&jk;FHxt9^=EiM} zmU!Uwg|zfcGxxO9%Nw1;>C@BN9{F_!Vv`$hnQ0A;in?gL2?=Rj9Q2Z0>>65WS?DM* zWJtwf?mpDU@p&_H;nV;hj8QN0Rw$lw1nW)kQ_q5CxCY1mA z_*@anX!!m;CcBEKW|3W0oCxBXH?6Ox1gc=|WZ=oxXId9{Z8$rkz=c3Wcp0b{b$PiA z`Moh0D|GjiPVbEhPq1fFNdBNkE9F`{P`F~Bc3a(8XyJmIT<^lBdF8oh}an8F-3laFIvAMcfoDRuodsN`tk@V@tMcjXQ<4LoL(Bk5zDd0of{*tplvScYB%1vS020W zrsrTZG=p=Yb*T*?hkqFt3#DWWS*JWo0Uo9N@%T-??@E0aFH)!1$emQavpMe7C$}^1 zg-;~A6Yy#WvX2SI=pdzm=?ohLDoTpe{EhI_xxP#V;3#+sy29XP4qq&7Ty9t_Evi3E z2oENX7ngSDmP5FbMUGY6fLjJF)r?pMy_g4R(S1b6;z-N|17x;sX;Q;!XToS2|L&{A z;0!kXhJJNqvNv}EuCBigRM+GzRlt)mWdnC$t`8=->}lgG#5IP?9w6%{Y+gxK5Bd)J z&K{+B0Glbf+#32LD zau@J&g8J9e);g3%dC5hUN3mv8SPC3*o`scR(SOW)c^@bz&=j!V5v4fnY>x*T?jmz! z?ZfoLV`)?fnf6a#%{OUuEZVsW97;08#nh5x>$g9U-K27 z^eqq0O^ET6PRCVhy!$)K`qe80*t?hDX8p+7{*!+c;dB5mC@A63!A<9OP(p>x9son0 z)UuUIUu;9e15Eij4Qr>AkvnD2El)4@G5z^Y0Lhqj@m%)(FK#FlA4uv?C%%BBji`JK zlBlFXK2^Ny_YXGu6i5eN)?|${mYyso{^C5+UIHi{5tS7gA87XhN=O*Cv#taam+ej zaCXMOmur*B;P5LL6ba#GKb)?A{qy!N?+sutlDC?2_9mr*K1!KYD^FxBgpp~OI7fV(5peen8DJ$zE~ULE zkYz2_ipm-M?&3yw)N&JObf9>%Y(Qm;`AFxt-o*B7WL}zfQqO{jl?T6fT>+WSh<^ie-u0JnU96({Bc5>UA=_OgYV{&zWsIR06ZLPQ}l}>F#A$D&i`m zggOkouiDu|pgtmlt<_zBE0^5<{uE9_%@f=fuIvHV<^y-;oEG#Sl3k$u?0|-uKPga}{QEC&vYucSO z4rTN#)Jpk{S;K}Oy%?^kwV0=Zn04~$Wg7RHLOvbt0LDj#-wVq1E?Se44z0EWcRK{h z$9DF{0FE5*r=slsdn+!S--o>L31zZz^@U^`tB>cxMF>=9$JnbS~rV+TMXhOca8la?s8v z)t>fQ#fuF4WBi#08Em>>R>&oxECy$ymn&Q=oB6Ebsg+&Z>G`behC40(P_7(<$!=9; zg=P)_?vS<4!xvQUA-p?&vdjMCYm#9v|3tooe&do}v-Dbcz^B_hVZUXfS43J)KN>93 zE4$kaTa*M@$26(^g4XcFIY=)IXU^j<_(4gjgi~6}vytSOVB;=olhiV*t0SOMFX5p;4n9Bpq3L zgB8iMqgzGC-PNujM*PUSvly5|7d9$3X$y-Y2!Q*P2eayf=$0NIZPf>>Gro=H871qs z+WApfUB?A5be5VU-hGy4VXQ|*rc%DITj&OTLUAi_z!y`pJJ>=vyQGOVVXY2w)%lcW zkYTnq-cs=%M~Li>ykY3QcIPexf(NM@!gaZ2RHh%O7de1)E)zs9T-o$dsY3nH%-(5h z`9~oA*S6n!2QF;(FW@VbJK4F5Iy^|=>f?_?UWV{hDS^fS3g3DEISG_g(rpW4D5HfV zlIa00I~_aS@CTj$;AgU6`(pY6Ez4ln(6zST^2v6{k$-v$t z1f49&`JYF#rvfi;^YvuSyeVr+6Ku~3W~XmOk@agu zLkJ0_X^G&@UTQmT1up@9Y`3xlTR!6?b@S)KRArAX>6@7?4<=rDkTx9_2Kw`<^ro{r zl!w~G)I+ag-83mWhKqEVBV>L1E`_B*;G(3PxM1WW>ig9!iYo>?Aj9zp-_1g|q7Xpp z+Sl3Ip?;q{``Pm$dU7wva08$meNsD}8p>#+{9^5U>0yyBr^YV5TYH=aF2#a8)t(EN zvVZtO9#6iG@qtWZCDnNMCx86TB$yrFncS$;Uy74@6T_z0-=GswK+D7~Vp1OF^&-7_ zy=2$>ia}_pfWx8vO^xzt;=OEF<5*0V#&G^JpHgB*mAXY@Jx~*}%;(UDSIjzM7VWx*RR zmh?f-w7V)=j5+yzekB;^(*UPIP77+M!N_`NC-Vgn2*)2$oHMCqpp=XDC0vCnEc`4G z8P3rn&$&aXtj78d*Yx$UV{)}Yu6`FDJ^0#@^*7x=raF*3*?=Y;sbfsb3#|3pvI7qoD$W&EoGbrQ4U%S@w?V-h z0FFs6dydc66%n4z&q08L3A@=Ot561tuW$no*^;rmEZ)#qNUiI9i&=X})c%>BU-Xic z<)1qThQOfMyH5`zXajbro)#@$syq1^%3P1v?^RX@zHRtLacu_6;%W3en=5W) z(inJ$0{mC{?_*r;jO8P7P487Fkc(fHUKOkGxTJmPjPmipNdxZgHDcQiDpYRxPx>(@UrWY`&w zt&`zB#SdC15-3G)raZ}mbU;Tuv3?$=bnMpG0NG6F zzWG&G@5QsqGo;zRM5+;9QYPr+k{vZ6#Iyh*pzI0Ohl7H}<7Ev8D7C|m{qrks1k!VY z`2t9WI^RZ+)XTgR3Jm~_Zj^q4QE>W9>brHVEOOB(rO&%V&d`KyO!Dp|Eu$u^;QmaY z@emq!ntXpOkU4Cb2hE`6B7%}&_12y6=LR1Zad%|f0GKTXz|x@@rLicF<4I2D1QBSi zhRg*WP)FHbFIPcD*7efF< zvcT*k*kufYqhsVyMy6O?oCi?&6(_cS)N0sq$n7V+>^;s=@LK5e znGP0rO3k711v0ZrEtt$hwuX$YLT>1iBhlOR)SRX3Uf&G!-kFkg4+TVbk*UJ!b5AfZ zbvnY?J3}HUAn0orz7RAt2Z9tDSRZ`jAE&%^I@lGnxO7RD8a3Ttm*-Weg1}jdYon&u^s_3- zxm5{*$6Qfq0|8f5+CNQPf0{@hp!u#_y9r>~+xi)GJ!yn=rA9nR-N<)~OLe5HJ0S4^ z-$9;rkM#pde}(bw6~-_oG5-Tg1g#)%FgR()8w`U?^iOdYZ%8ZyZydpkf7*c6KuvKL z2A<*K&vV9IMTln5lm@!UTUe3UeoK3hEE6`MNj4Yd#QJU!_W>)W2siFY>6Q`|!AIeZ zcnetFJBTpQxn@OXywOXPug0Hc(84Te4xHLBs#lrxFBET$EL z!YbK4nM>U}-x^Lv7^R1f-Jk6+Ifc-0V6$`nCOBfSB)(Dw6jzthb-Y;I)|zaEUA+oD zF^az1;nc~=cpTcu$+ffvu=5&5`yOuev7Ei)efi|6H+k$*A<~H1j|>+?MFl$gSiaZl z_&ENkUHPWcx4GBT@S{3lYv?gO*aI6(KWFYt6a|NBZ$H~!p2%l$Un~K02j^&Fcn*7I z+zypgvT(pQDaEO~8%`ZATo&`fW#ZhQpUqmS+e_hv2BeKl&;**UFP7aIsUzLtcx-sL zi#S2qmBHGU5RyU3RCKP4k^A%W7MuujCM(Nl!e_+7Z^9>#%ZyQkqQZJV9j*uC=o}9S z6LqAe<*|uc>e3POvUt09#i2jzsccU^~ZN-FOff4*D5{S_Ok0P`cwrYi6FV zL4nYjV@vEmM61s$;3>9)*p2m_IvRER^SWr|qva%&$=p1I#oW*6ZMZ)dJnNK}craGB)zAK@BF1oo*y_A{ztfomLp#AszRYCgQ zzg0eq#YWZ({Ra8q&1??J46fAUv;I--GInqX-diro)gMmb?a>NHyQywrLI#$>9{o8{ zV-i4z8hQy7B*4C;BvqQZ^^k5naIrv7V$$404EaE}{X!Js5<^P=00f^!Lk5hk?9spC z;$JI+C+~17#@d`_hyUc?h6g_=XKgXi7nez||LM|>jG0g9xB|0BBz4+8MA(iPL_^^0 zPEz+TP?vzjiEpB;xJ$a(1$0S zXS(Z|4fX<5gHZmj%&JUKV-X76ST=kA7HqZtG!5pE!Eg$P97Afwj1F8>N@>ei&^p^fM>$qS~% zwDfN5RXpGj-J3Z*Rn?afyk5~6CbRtd#v;~ub4lA?P0f-AoJ%M%O_x9Mv9s2d`wWeU zX|<1&8iREW9X&lgb?X5pEtqg-b!()R)Z!}&ekQDacxDyi)0ct2F(SMFcR~n%(*Q>QPo2^eV!^08vqR6hqd=Jy@_7?oy@wsM8@C#E14r9q1{S=f)3>b0Nld}vD427{ zL+8@n{azg~;60$DKm|@m1K>0V^A$>+I($^uTAvE?{K<%uPhjN_&8kX9=UZF6mLqPF4_RDUoCtLr6>%Z0cjW{F-cgq3ZHNY>t@VizE&P$v9cfBCa5GpmCVzfyv^oAVdJ zwlhOIJ@Uk$@v5S5Fxp3Q+4ns>vTX1MLxwzsdutUmxQ37>C&AHl3yb zFRz=M^|$PAZ_R4p<6!wY{{^6K*|k}zz`X>?`r;O_r~0s$z=P#@ng?%@iF_g zsgtgujYRxo7Wv(&$1H@G=KT?Us^I$^-X_zSi2R+|mT|pdJ|2ydi+1Me#lgYsPnMi?E7P-_y6Je3TkIh={TNtZ; z^{mI>yTCJk(m% zKK!+&tDo9)#+0aNbQoWou15tJ94#L_oN!IjK>JFkBeRgaPlAHRmW+yiXxs9`3bNGT zS4K-Mb%;v=bjFp3mE!n^OblylRO7CYiU|e~x0l{#4+h%FwYO)Cc}NaU%cWAou|w)t zGqO{_8==2je(-EoL4-u*{|lJqunhfWXAP#>z}ap(Coc;&(QaCVFd&HFS7#C1B*POBgr?h@V<;=PV z9kHAW51X{_fT8r3{pCg-V@Xc6zDEz#vNRI~5W)QhCh(H~7jw6es03%@(5o1p?^`ac zXrW*K#>fy$`V~fIUTSDbk3f?klOR}&@vh~sAlj2H;=y*i>QILQKoysTD`+x;37Iof zVCWS}zJ}Xp1k5GdXGoE<2>+T(aMlexJEvn6j!Y(9A)SQjB-pJK(j_d|#8H&HX$i11 zuA_T=8ICLq9vn$33;UYX%_6h7U$FS1;$=&1L&vo&%)QLs&121$(`mZ1sGiUOBS0GK zrn1|qhw+dJ6vKfhhvfI((ZYhc6Lt6TC#YS&_Sk2JY=Z-5v=k>uMD9qQk|15Ub%sw! z_LaF}$04QuF>TIpDy^SOaVq`R7Grp_Ynnd}v!9;_VR&*{_~~VZgVhf#3I{L|XyBvL zuEAz0`^7%cY9G?K$8&NuGmJ!YK!0rXOr?;m!3o#0JZ*D^|8g({H(-Bk@@QLPiu_)M zj`QI%%XQN)WtIzewFFZkRVVCU?rgoQKZnhl{BnUsW1_8tew)ub(IWz*kjnwMZGd|R zHTals4mX(~f-T=R-wk>}ckZ*>6`-{(7%%%Bu#NeltnX->Y)gqSLhNJMI=vOMZpdz>`+LWz^OATc^=8?~9rO zY;9>$iMYR~u(cmgv+8orKgTR3u#|;iFqPu*40XU>xZsEjCxfi#2d&aSwc)S$${Glo z(=iRMZ-c+u9`Eh$yk{SH!23W}nd32yArL|+(>dG{vL<{iJe{vSnBIJ}p456Uivp-z z8y50X!4H4Ip)SVroI6RAr(?JWkmq;G+*+WRFnA8zTvT`ILm)msg9sx{9s)ZgfcqG5 z^`L!~gQ_W#W6eg?xiwE>bp;^pPm+!#;?iEFz52TrJ(uqHGhja54-US*0xDJYh|?h< zxo3>D{u7wQzsf-eigl+MiA!J&HPy2Ck`|Fdzf#Gj;%T3S#%ldENc$1f#-dp1ys;%-pfA1#4+AaEv6YkvoPQ%;d_e%|(9hGLTcnw)|+e7Vu>U{^<;Dlb-> zYkcc!UnjcwIuFUCTw8?h z5x(goWAZ|>EELYMWxP>c1ueEl`(p0rn36t9xg0dO3EE_PrHwnvm$MRqQ`Sbe3orWxy>h0nep&bgk`7Tv4 zVea)CK?{R~SL^ks#1^O&Z@UV8%O>xs=~Kl&B*?c;4aCuv^XYBp^rR2f*f1dTqR~P> zo|mqCpl8dSIHeI@J*w}llcc^MY%$u;y{G#4IA#_guhXRn{0bovNlhaz#^S?{Hit6g zZnW(w=I|X@(Ek1v*}fj6UjhPYvm-Osh?sl!p^3KZ(*vumskzCy>AUy7F=D3e-*0-BdeT;qA*_Z{IHVccitmzzgI2lg~4E2k@JTAc`|M34qCO=8>ina#@D$Cf{R(>}&^ zb9n}7wm_DTOkg|H#K+LUMU4@2zAkO7PgBoKnVQu^Re3YR%qaZ7us6{JFGc*;QpiRL z4&m8B+^ga0b!2!UucUG`ZO6BNi|{mL`^4I|RUn%X@>@elSSjy;hWxICUTtH}GPJ3V zln&J^N8C~u*oqmcqzFn$u+SqNC6h4go|qZ`L6_UkYfV2l!T3H{m+A>7^>aEv*G!a9Y<{8 zj@jdluocoHK?Sv5)L9J-43Zwxb87FbK3ZJt7`c(&Ritcaims01O2cQBg|$MXDMx86 zXT7Yx@A)S1Re~6QSjQYOWOJe%b>zST%0@JI+6u`D>Tz&YDK<#&6Dn!|WdjoqfD4)} zn43r}7K*rQPCO$p-4vMcU<@c*q9LRtgciq%_H(G+&cfiHSj;5mcOBxOpNmo1!_Div zEceDu18YrsHYB?{$-W+uPJGp5(Gk!4{IPrlkejrC*Z>-!?#gYa?qHOUiJKz3~4sXDz z2d});s!a9t_UoT}9}@CweyMRFT@hiv5LPOF--zX~(RZsW!3mtN(AHI=eNb4(#NyQ@U+z;ko=`g-!Z}zOKPhd# z8|YlIs>zB;Pq9roCkX}g7y3c9gl0j>&rQ@R&^al2TLHosVPOkG1P~vV=BNG8?nI1Y zQNREG>fPvKq&L9YeDAs7aV5`U0XT-@h47Dq~qgk zF;5w(W+ZRB7^OGMQQF!_5*JGpI4QrCJ&%zSCtQUT1UK#lX)?MOye$^zJ&8;er_guT z8~!Ieek0$!GuO%64C&Ip!5o^oTRjYvOeE1SD!@aZiFmMx=7UR5CzWx*5=%SQenD3A z0~akWGlzm{8s6;kluW`&9_)DlAfP+yuo5>k;53T%Jj*X0o$%ek(teFys*9n zJLLUlGEd{O=R)n`i@z z`u^w9W>kyec|$N38ZFD#|E=Z5H-ge}UPpw-6SzfBhJqkF>6Zyu@pD z=Q=fX)pfZ92~jSXe0qEDny+gVEPkcO=q5Axt3q~SL_^tn=^sn$uJs{G>k|45?9dRm z#A*{AEMf(vEOdga%Vx|exJ(P5gCr!;%n(E>0u4mkFSPt9i!Rn52uSRn?1ZPqH1qADbTNh!$#kJu+ zbT@)HZHcbp;wFum|Bj3|78*>OFYE{bMJTSV+dqMyFfWzyE;`{R{;v7YHPl6Rgeuc1 zZ+D@~H{mWUR!b8*Se#79xBa%PyXCul8y1uHF)T$xlyk>|*hTre!-!Xto(B2Zu|5CU zgT@*o=y*g{_EJ~?mr=~)nWl!`(o^B&p2ai%iBmEz3t8l+{c0tnlq#EnCeEyASe3*vAa?liU;Tqlk{Rov+Px?$q zHh0*hcTz?b7WL60_-k)pV=bi@SjSM6fs1W^rARMuv8}BI7Qs)H1fW%S-s*goxukYO z%f~4!ZEwBg2cj1+X*2G+4h<4G9f?hIDU(J$WTq5OL%xiS8Ji8+#hDinpN+@nj}1&m z)jIpG?p;+|2`2n1HUHK3ANJt7$XLa;wS3U_EUXrMBz@pGp5G2v*B|_0vAWP)vNDq% zKyIJ9lT$@GdT+2@Ekk_#oJW^>veK3O{m$x@{M=K;q3XLml(vswx0~D_?>}|nNq{I@ zT+P%6zEb33 zCh`4Yn>7N8W172)R>o#-Fh)$$uNM{ffTkjuT#+qD%RaM0wan@`dQkFNUJp zoah%#kNN8rqq)3Lzk3+%4M2my6-gH3n+uDrRAu=$K~IH5*~6A-MKFE4Cse}=}IldW?rL4@zy)>Si}6kdP$J{aiMJ$u&&vsY9pZly;ayccxcT;skE2>W-drvY3P zcYoY+_R*3o{ZCHEeu z)oms>NFgMnn9cx~mvJ+VH=t~>dQrdgby;_E0S#ISq1qdj|Hs}yf2McO&KwD}6<}tt ziOP*xT#E2mmnaz=_CU{nzXUI~O?cO32Z!i}G1o?*} z`Y{R`9^jf(WsDRjS%iY%aGKHs}SX*lDy!Rr;l0w?o0hV;XG>%L$lEJN86}r*0 z0}c=g0fV^j6YwygPlPhou;+9D7y#Wz7yjUytuAJ;?n3>$2>UQIK$7C(uQ#=di)Rf~ zF=1^((y{00_YqEcJNMF4P2_cGtnH5vcR036T5&MLbwlDb?odtJ-P*3@cDU{69zi2H zTu-+Pwh@B0GN3R6w#+yH89b2Bn9iB`gpuqb03D;B(Q&616E zZS_6(TXi2jh6cX_%4`ZAVAj26h-tON{BTn<16G}Xa=UyMM{~Q(C*3?&WxziY6sc=J zwgUJ^2&?$h`LKP4ybYHC8tJ0jTX@X=a|nw3on}2Y6N-@@c^-$M!Gd10Q>O@DvG8og zi-6&3)T*>S?_f7ZkAIAT2sP9Gi86aJC(#l41e{9f2i9$H9;h0q=itQU1t;9Xn7gTO z3J^pTMx4q+NzY~o9ZXEZH(x9bVWLgl{Q}J-7S3&q9`xO*&1whw(1wNVV+?dox*kqY z?@!w=iAGa3M&sMa=t4tq?k_NbX&nRmCxz*iv#CsHr;53_(O@YoLcQvH< zZ+LxZuUCT z-vN^jSCMW%EJ>yz;vzBN;=}K zr`CRyD*gOp^Tn4~zu6Zfe%%x>fZHujgO^Mx5U*&bqFSPZ7np8Q&|fXU7-WdsC@Bpq zxQh!ea2x=wnu|iMk2h}0a6C{5>?H zuHC!+%frzoHZg`kcMHY^>3koWpK7`Zk@f)|xC1_*I}I<9na7V+OcM$fA_&do_Lzvwk&l-D*fs>NrZrQNWN1ow_fWiOXeZz|jI>NkE z=`+0OUERp7q=bN0u*8`s5!;{WYw7?TV-mABAVCUnqpYg@jhQ;Ll{IGgNfWcg3}@1t zXTvSkNj6uO)zG_hhJ#Gm&9jlZMw4e?TdZjX_O&Ix@}8;`jk!5hd54u6%0)ec?Q|rJ zK!lX67*D!^JV`oYPGNm?;B@NE6kB_GA{zV5URdw-bAc?~(ea=KD|(?8%HR~H>f*I) zni$>6o^lX1*>&!pz}RrKaEw-3r&8M*gg52}vh#K7cmKkga^J6tbz&OHqZX`j)4O=@ z(Q=Sq$!D!Y18GI8!iIma=*N_Y)UFKwfI*&$y*(SLYNvU<{sS_XuGtY(MSSiRNP<8E zeC6D7>o_iB;mZTk1TZJemyby{pweN0RED=8YZS@!>$4aGuAUbXkg?w7BN$>aFtX+5 zrFTe3)tRLDsv0zypJT2gh`=_C)N_(zZ$Oc}hVCdm|DVq!4#z9bnbqu4#HIb%&;GSk z^nC-qf9kCMvG7mAGf38_*k}FrdldETZOPbGhc^NVI5h`RzJNyD^NZ>fh2E7lV3yMm zV7W#*>)Vf*`-OYwdb4}DWjp&IhO>D4;`NUb(*kDTh2VwrtKpdxywoiCnTZK8|1=N* zmakmQ1y6RUG`lC!ej+^`JRG9QZ1nh2B*xL6!a_rDp~jOed8ff2O;2y*8XU^QSd%qk zsaWrzpWVE-rZJ1U^&QU3)j{{@U8vh~iV+#>hTmobQ+`y&-9^O3-M;Bqa6dYP*{lBU z>01C-cep<`V-1|V9_|kRLkM=bnzGio@~%pvHVq0#K{rDG!Nbi)w^BY8hJG;W@$VRK z&ZKB>T*1{f;A-g)+AuUP-1ZkMm{G){V8+H<*m*n3{rf6-QTenB@qtR?8ezhOD4hsz z0YMoLGqKO_3o}97`Oz#v@`jB7DUL%_B~)BEk$ycmxOuCzY$*;ya)_f!zYljj?GFrT zD&f|t`pXL97R9KM@q%k`dG!MQS-csz9pd zwLedh#mx312exj|^%hk^R(qXecstO`3>R87|G&htM8f+~eey~BTy}!HsbmPdUAsN+ z9L>j+=CFr&v$U;ma!P?_gL?4Te6AbO^?O-tmKNTeFI~2*OQg+=2d3m^jjr>E;@9r+ zM6WC!w(KTL8yba@?4DF5RZ)<^B~|Mu)OCC`eI!#v;&;4Lg`ttv-cX~m@*T7sfh6~! z<&7T&g{v$vmG}{v4MVdb!{$Dna1ZgZT1*$g3-H;H~9F9olgU$Ez=)j%lx} z!s4=;NA1W0`7um-jYUcubt*kX--moYZyj}up2dJFAW`vg%&n+%Pwow~&mS+zLb_(r zqX9(Gr>Pu!RS$lV-|I~KS_;Cpq!0D-!3rBOnM{c@w&JAk6|&T!y?Y=rL0>4#IarbOYlTMJUFq37 znI#AxEK9J=Pa&y22!RSktW~kZLks^3;Ga2nh`e7<3#l~vV`T1FF@tT?Ms7AMD{e9Q zu`=I(DA9mcGo1|0nFfdEd!|VV>Jb34^j97_^|Tu_HcCH%TU&B| z{=NPO{N<_P2V-{^+}r!~aR7yl-V*l;aZ^>^M-2S@b+7ZWN>j~^-4)AXd;Ef#R6|qG z7*Fw$Ukra2^eFrl$V3CrR}d`wA52O?&jC%JKuc?J^b~`0%vv8Fp8MJ)W;Xg>xyJ+z ze-^z5&K|UX{I^CVS5~w*WoBKEs`jKyU-*RHv(%`b$~grC{UmC~;vob-JqD-C^8{MW zt$EL5pVMXRfkffoBYQ*RuCiEl%4Mco^zZU3jWeu6cUI0Dn=O7MU<8@OKNI7qU^VW| z$1TVy*T+okdc-}>8!P!S$H=v-Is?Vqz2O5rvg2S$Ot>F<(DhdK?~7tQ@cgX>{Bhra zL;U#jd?blLQ)ZBxW2N|wjT6_R^;NWLS z#HoR5kRPmNxqBTj#|y2=Is6qH-~M0egc)gXBAz{c<)v}b(Z>RhM9B;HmEtri)@~sv z?nE$e@Ik`;dy)bk7LxepMe9N=I&-C2qd!ZW<1-q^lZHf-&lR3f1pv2S-I=QMoQMO{^)bD?X;1CPr#L4(H86aI)K zTiPZpW(ID7E34+kd^3OHdDAD1B>E_AcH!Q=2ffp$6}#rNq}Y| zFT1qm*;6xTth*SY*IBCdD8ZC-Mtz}^St;c$+Z$S(bXfisyLyn?F_Ij>biF=ERZ_!u z>vlAZGkI%UJ8M-*<r&kM1%#fqsP2MOkEVqqXf?dnoAFTYd%(N(+T_8=ZB0R_w5;sHO;P?S8kYb=1=&uAW7ze=r?p zSAbo%b0n}LB(era2e^z0p8+Y4Os;lyy^3nqS} zvpD^ixS%HF_*NyDX~)LHYQmuhTOJFYLHZ8|`D%jW-HuC~z7L?6Djd%wugAC7nNMxKzLAbzE5A-?61~sN zHC6jL=A6{Q8}54i>HqewLy+j4qMrQQVa1eTh#KQi?Xl_4hiWJC>gEsXZ{xcq67f!z z6zzQNhv;l@KnlG-K1ewwOFo0{<^A__xLi4ZUuk!ot%%?M(b!yb(Gaj5|T?ig?~mEfOr#kCDC`k{KFn zr|mD&8bj}oqL0mB8z%hYYl0tKX0DCX5_R9dF~)>r zEc@1)%!!`IG1{51CwDa7U_s90+Afy=LO!pQ+X(@YkRx+4?_23EVi42WjZgUoo)#F6 z?AaZpu9wu%+m4&fVY$QZI7)@7p0<{|(}&+4nh^J|toaACFz4#Wbm z^oZ#oN&r&4BIkfjba+I-rO?uKS=I;&ewi24mSE!|Zm@J>wVC(UIUsic;3Q^g+0MxG zb7VY}?R4*XC`-CtxLUS&y^!a2%L%((GS4y03;PPFUXYobnt7f*wgYEfyRQF+TU8P< zvBG!}>l#`*lYV0OMEDxYg-oouAuQzOTyBXwfB##+7B+ALto(Z1TStlhD?`R^1tKN8{zSVsWgezBCTaApAwX{@JuIzVM$Sx>JPge-k zj;^YdcV$=AuKj$>dpn`sK6l4H30H+04x3n*#U`XAxNpB>cn>G>By#f*n4$c<9moUb zT+n@781XGBNx!bT&QjV)oRUS6kl0WBpHXVIRrm-uvXP;B&brmju_IBC`d6 zjdXM7%av9p1Cb^2Q%u}Fjk-C5fMSCoKFGlryO!$&UVpdAOe9XOwIZaxeM2w}&uJ5k zCci6i>;4;^^IwjFd+YQ7+!05|3A62otgG@I8HFA<+P}V&b!avNmQKeFWy{z~s~l31 z7kIgYdC`TRFum~)K|i^=&xIrsTp8al^9IZh8EtL0Gk;hD?oUtO51^)4=aOq8lf#0_ z120)e%Ml?Dx`+gJAW8>rjKTJ|TFidC-JUTj6R9a8Bq^z&Kw+OlHNUMTf`g68+A-!u zz9{Vb+l4WzPoz3#ve((k9C`h$+8T~W-N|LSq{spo+iOG+IW z_k#)kh~@AaVfRKiaK=&MxG#px*C}&RBhQ*PHR+Mw1AvCW-}(kx*Y(_E08#QMM|b!8pdh61 zn2>_P-c!u2!osbsz8_zZ_TD8symJ-)mUJ#3g7GgGkd$q>bPNqmO-(srV%nwGuSWtz zEG!~xsyQ6;qqK5&+zW(Jhmu;k^&Fg3UaBv96gtIYl%=YQ>I(+N1)w~ko$c$*>kt-( z*Qca{-|D%YWLG8Be#;Q?MV5L}a~06Jg*dDSh2@3GU3s*e3P$gdFVSFi{$E!5qweALN#ux_m5s2c%t^oftT?WDt3 zn=)QBvL9Prg6fF@{yg0Xpq%sM_k^wXDM@Mh9SqFoE{ zVU<=nKb4ug(iZhxY3y7E>Ka$CQHZ`x#dJOIoIy61_^_QKH zoZR8;^Cx5T@={Vj7Nn~$rlS}4yu9q8*Q|&zn5>Bev%j*Fxz7v@8Zj|Rko(Y%Cj1oV zH4F_S6&KT|km}}Ua6$7$t!(d}?C9zvRaH4TJrZO+aq{8?<6IVYc6IfD`+fk52r9a) zQ&qQZ%`!TqZ2JaU+%N8yJtPMNI5|m6`~LiS+)F>be;#Xlz;_hR1Id<4XS+rREWgMLP_qr_+gmC#gsNM(; za#dBn#omGZm7ke*@6LKNJ>?rK#3*OYFizEv`=+kXp z$NOFQR_Nxpy_GN~pw==fDwGQ8NI#f~IwEnzAUY-{UFvc8fD34TKo{Osa&;?^l*z1* z1bJ@XNr+Fe;Nh45Io_4FGvneJmG_mwjQdiL_*+5yyEy*Nt*@7`Lw2mQ=xVr6m#MdF zq|B2ijPw#@tkwC~HcOf0Dj01+yPCw}7f{I*5*h(s{+2ReuYYKwFB}rO_pHj1GSNqK zuaG(U<*X{|UMSnVven&&P8;Iq%6<4!Xse#H1x$^ZO&Gbm5|(W~7K#;fQ2+%=W`cfP!e%|9`r`c%BnyVHGIk*a8?9nP|z+LrAlrkL@DH4EPt}c7bf)~ zW1}6(lwj_i>|CSmd~)6e+1Yv9DyrM^oxh2|$XwuO9wFbnxwLfirf--;g22KIXzI` z_U>AnAK7oi9udugS#v^$p`8q4h?=^4;IqeMX}JKoEHLJ{*L#xXj}JZN%S)hQUY?Et zmbClei^k;UbXK4k6yEeEzW(;ZL4lY|qls6xpX==8zT3))DURxq1lS#$(;zLV+6!zI zJ-V3uFN;{bdLNYC90)BIO0S=kq zN}K6F2#fd@+6Eh$#ksjT=wO0~+)K9GEm>Ks)KpomvcMHK<>F!@@%?*Blat(Uep8UP zT&~MI2#lMP|Nb81f{dq)%TWBu6EL(?Zcf{C#Nvq%p1G#S$bAY>=O1S5F@{KQxuRKS{3I>)?24;a0x}*Q61> zX5z#hshdR9eZAk~pT>`U6tQ!(Q}#EE_||XTy0Jc%2p?^e$gveU9i6&(wdycN%<8W` znhs%UI>y2$|H>xIOeUs8`Dm-R`)LoUroRw)c6>Y1zV!V3xwI6wn_)9OmDNTR6qJ&J zW6kKzy?ZQNzHRm(rMA}SesX4ulzGwi%k3>g*{yI!Gb=-C1^Yjwm^mB=B6jaCEcC6Y zh>EJ$v;6j|u<*E-FGD$U^!Jrm@5Ppu{u;lisKUZ;uZgsn1VizH(3t9km53UIu1+~n zXFoe@@II)GE6=n(E+aNJWBtSoEmSi<-`d(<)-s2V7#V3s{__v%>sLNLd3j~?=cPa0 z$VB3BVw!o8hx3Kq8J;t*GO0lEL`Qc% zSE3#oD_I@Qjq&21TSN!s{J87aZ7CSTPzEY=cJ{?`Uw?l%&vVFV=FYn5>Y0;04CrbP7w7y^QP_|i8uMe=nUEpQuc(KXmR+8X@aXGv~7e|z>7Q+`Y7 z(eJLk>oOcK28*bu_*TYuin_f6&oBCHU@Ir^RvfzPUf7D!@5HhPg-Lb29UatdWS^Kg zZ@KvAM=RYD`<(+t{LwJ8M}dc}9q6?7u?`M?9DM+P zZ*iEI5T^Bd`@OXB6DQG_nZn$WVptya3RE5s;t1(5b#rd5A=qX3kz1&mk9KNkYHA|1 zP!G4G>$kXdGvZFebXRlpA3qq-a34^zK)8Un^yU(H;RFeTQm%9>413INuTS18T=s`-WdD6JQMvTOBxjU^3IBj zoS;5+9T~g~YL146!eb1(w@4f9K!Si&@uH-#@P4+-EjrBllqKdAeVQXMD?18u>{?%O zWn61RaRQ>Kc36lz%Sq|n5G*@?^(e5BP7>$cmt^^QRKK2 zb2e`p**|?ceC4MTbl)|?ZLFZYY)k#4%Y2@X?=H{v4t8|^&AtMnHO!qJO6r1}2LM8{ zg>jg~cATXsh=U?T5*8FBipn{PU;BcYm}BO~C=`Vz>iPLI19@{8Ha6Vk4FmCnO#8bj zPxTL^T5cZ*ihI-Jrco__nleQR4$87^jJ!_z@#Dpd_wNyK<@H?n5>2QpUXE2^eB_a} z?d>6BG#rNmQ1e{tD7eT9Qv8hbw^)e!BWN|iZJ0`Vq~NV^?AYPW>o`9{2Z0D#<>cku z7`Z1g>HSW662DXQgV{3LQuPG|%_MsJtaCg)lG-G;cyKes(!p`^77r;|e|bO&d?ic~ zuhE(28{=vA;pLu+*FB;JX0~ulOjSGgiyJe+NjR`|3#r+nE7<@n3c@5nWY94(?~(B6 z|VS$e|~t`*qB|_JES#5aR4figwXW#XUSE4Q!_Ku z+qF0gi;G5(EqfJ=aJ>SJx9N%7n2Bo$8DT)@qm89sm3&1 zIY?Slnc*IR-ND*6U!o4PWf-cf zPfhzhKVDs>pALo}G7-kv1h=uXYHb4Wl12@glW#dUP&`fdk8XXlptxw7kbrV0%7^o)%3 zF}IBR_{i)4mxwN(cP>e`eV3$(Vg@U}!N?GUNON;-4_?kB6c=}Pnw$HA$8y!w%#p~Q z+%PsFFYoO&zsVlKn-1-AuEz;L-n}u_b{)(bMb4ey^*CnS0nS>lS;$vh#gGG56*PmK z>pY*zXUCD5M#iI^m6dn7iCZ*`B0laKzs$=-mw!#o&^I)sQgvb}DaQhHV`A8|0J+Y* zFr?QwwVv>2jK*ts?)8^vGgH+JUV{`9Syzg~;%Jel8FHKu5^8;k%oyuXT4n-}{F^om z6k`m2)d-7!-P|?p0S0jhn07FQNuixrr{WT+HLef=>&xz)a9?X1FMq-iC@Q;JY4GRN zkY{uj8(FN!ECR(dgt37tO;`dAE_5zYMMd4nbzHr<#yJ!cJ;N2EaYygk6Td4-OYEFz zFroY>WNON{{Z+oEb0q1J4h&e`%!rx1w8VEn^9Zay4`_2vFUqzSTfe6S#z5Qf6 z=bB5*k)3&9XFFaz0EWqnAZP0I@&o_(-X~`Sh)eUwmL-@N2MW?K7I= zA`EwmkhXciZVow|oxbMOXB#+wYVEJL91!Qsn=G^M_?|<4Bp@Mn{~qCc_J0qrePhAU zBpyWqP@O%brFhn{4b{C++Z3Bv(cE0l3LgPJ#E^((*@O6a7$CN^bg^9ekY7+xN=mya z;1h5#0@%5{2=}HSYw-eQ*N@jRkRbHeT)gP_^eN11f6E+(h)2kdN8bRr3O!DCILKYN zNW1#szfFSPn_J$(^*p#i4n_?|&!F7mT=#=uguLgUrTJQA9Ub?)N+#%707^5v)1g|T z+4S2huE)U_WmuVEvsHtq0!ZKROWO%PK3cEaxIplX4yE&L^z5zpZxiFs=)>);b__G* zMvfhyAkWgo$y+R)oscX=MVjcde2xJDP7K0r>RiJm`+Gdy*nP|9LHUfcB8|i2f7)W) ze|Fp;TJ}{LSTOsRJv7N>A>93F$Fh6R#}6d3RP^*soQFez6CDs)gW~bp(4{4-x;5%U zI0^O_>S#Q(1xh>lwBdAEa4|RcQS3&!lmo1C z(FH;3%v7z{ABpj=fI84k$Z#F$uYm-4WrhBsa#SXQpBrYb0{Q)q5!_w8C%Es@Zx>8| z8TuCEvwfdLO$CtUGYlKr&z7tdc+I}O#<&z?Z55Bi6J)#i1-o95Cwhawy*j>p7{1HV z?;YN`w$TQ9B=~}Zgzs-5>gt-C7Z-zP__LRl<*(I(GY-H_2R)KmGqVV*%tU(X%QLfM znrcM7b2NtrbPLwiRsN^!#mVwV@JBm4-Hsk`83Zq(S$;yx=*kM?Evh+aUuR{Nhyw(0-+GAT(}2L>cJvY$F7$1k&^ z+v(07W@e&+#Wk6>QAU4FLc(ipvdwg5Ff%hF&Fn5u%rUkH0>^!pmS@Sr!t{;eQrF8L zb-eTQS>7(o&2f&`8t%0lU8&|phz-{PyOwyhHU{gwA2y@LQY|O~&0C?sG@2(UiAe#(e*3{BY`}Q7!{2SZpG>2IEbtFTltUjebC+ zTOZsFQ#ZOSXs;5hf~L(7^*c{f3@8as{e7RSBUq#CJhO%>U-@2r3~Rk*ZT6+_hmMDR z`~{1U!eCG7o_ER*o-T}4W{zmf6$MowskHRYozhZe7nl269327Q>pzfXOcM@)X*ex* z@RT|@=sadGJS*b*?%ASRbh_KS8k=15yBpWRkn9jxP7fdh1FtD`Q_0x)_{7BcQymsH z%+}JacFLBP@MjM={5)l2<0b=jet!JIpXh@+r5N2#+@FCw9hnVug*U2l_{?3WMp*y z{FVKWW006guZ6=(9t~7KQ96?meP+St(x_-yI>lVh_b&Q8mRQl1*w%qaW%)dII>`pTqZY}5l zJKLclQEh;y<*h0-Wr@PVPo9_+3=%r>z(omcUHeIHST_dxG53L_wxMxb(t|b6T~}cm zKI4=FL@lVMB^6^U^VYq2O<$i0HBK@wG6xa~&`HQz;%1*m7e}{X*udauWt4Wkr?xT4 z(+iD}rc0p`!h=Ei>3em8!~B!3>NUrw5uHk^mMODhMS^4U=<hqZbR*YfBA z!3YFIXF5(uiipU_C~VJwp1>Qv%S|a)zS-3H{`0VbAF)TrIQ#i2`>YIo1CYwIz}6dt z4NwB*DXdOU6Je5w8S@Fy!jNEoaaAbCR+6>#{CsOGYz6FY-Vn=64aI=z1MV*$t?b}% zi{;@Ca%t)5)1{@p;ReAXwk4i_etlyFL?=gV57{CA5r1VhnVmf-NLre}n~=1M(DNgy z_myE#V;CbLd$U76H6iSF-D~ZEK5)^>GezC<1GTjt**@8?@{oGZ!z;PTPenyPIecsE z^ZnqN&f8dYG{a{ZWe9WV7}GCA`;&Mlyq9OQSMTIZOm3{Mwl{eHqBJfh<~he%=6fQ+k0RRb zEkE4@arCVDPHI*CHr42nD62Ib{FLiX;Be}uK9NrZURs0Dx|9I4u zOwNG-qmog}LtmH)jShyc^V6kifj>7g)vE>~1<$_8J6PaKsWhJ`m?d5%#ul%)`y4Fd zz+rSTzBj@8!@1*;3g-pF$V}5nYBTxOS9F27Ei5iy_fLDC50v)VzxT%^Edj*areTbi zCb_6zgWkaPo-$?kJcYoMCq8^o*PvzeI)O(@E?sr1(A1c{-D6;Nxhwk$W9JR<&M5X~ zywXJPUY2aT)&z~}FxX;L@0BPWaJigrzPw1D?NYLDhf2c2JIAKxdkzdLhq9Oi{!87; zHX<3eq3nk08utU>O%g&{Ip^j;q*ZXF+X?KIe<#}RN_=hr_mAl>HyVbAwAUgWyN8LDEGEZ{xSI^)gkZA4@dJwK08h8~X zpNZhj>x(-%<@jy8=j)13E^?2O)whI;OB!)@U%mM-omjmERv10^Ql}j(&b-&}U`@}w zo_g>;Br_p0>Tb#MTXarVs6oBz>F$yA)e(#IV)oCGv(T&d1}r;C-yQ5qm<`6CnQ7pU~; zJ_kE#VWzFH)k<%40StUL6O~oo7kjgEgYi{=P?j;6>y}bZpXNSe#Mj;Pl9cxG?(8pJ z33=L`C&!eMY0MX%`#mltp`&@ASV@!AOXW#TQ}vT}0+sGZjsnkrE4D;j*yCbo}dW!39-uPol>F6!IT{W1_H#8pc{ zWd^Jhda`drLw0sgx!=jV4N=Z3D}H`NA|t1HrB5pG7-?=1py@e+*}J#)9j_jC3KBAq zw#I?;=U=4pA9*_m^HlNE9&|n^14FU^lP&EQ!l?Uf>u||GufE>oUOy_P9oy@G6IO>S zeo3^pRyP_}dQMMKH8LBHo*O?~v?;?S6BaSWuSxl;kcAZ8yiA!&GG#;P zblXvp-0HIZaYH1ZeiJ!0)*<%(4m<{6*OwyljRnkLwB|UyvuwMFv*|Xf?68Y6@=&B zf0ACmI!i1p+HrUtH;d1T$NbchtG?cg(6w^*s{$IH|yi4d9EXWM(M^?qb&aZ)YJU~F{^VuFx@Cd zarAp>dGbKAv2<8^NKgWkAv)lQp0F!AP&2Y&L&d)DdfS|=IYuP zIAud;^=6Qic}33}&$sw5$C-fgiWF2Sk=S(FMK_^6Cut&|P^X$wB2IOF`23?f%Tll7 zUxkzj`*R7tyl~&xf;?;yChjUN%`em=wHzn!gfQtj<)cLhG#8Oraf)8*=+rbVxhjgE zx54TXxfSBI*3gJEIz!2sHj-CZ7!bJQ@L<`F^b&z>vSSZrpCbZtuIk5&ElOHiS`48b z|6T`XkU(oJ#scyuCdh1Hj5rf>(hM^b6 zTsyXQhmSyza@mw&*BZdf#>U7v52wp7HgK@CSoLhXrkrjbt>8Mw=`s}8zw+$pZ1?;4 zz1;&bpnG>>s;H229sb1DT`&Unsg3L{NQsh&h&bngh-b2a{}J7OU2d0?+or0)v2J3D zq@SAA)?p7K9(noWJ5{x`w6!(J|8fp>7Mr-VJ?m^t|;}w9VR{e9FFB?#Ji@NhPB~@MNshntyvjfU;9byt6CKYuFr6Wk^E?vdR~k%~@D_(PSD@!n z#x7bLOOHRr`Z|D)JMWp{T&L#w@yBd+B9bBgeAJ2R7&HSxGt@t^OY9s2P@QPJGo_RIeJr>`622s1@} z0s7s}dfs#3seSK_A@y8wP!On+vI+2P{TXi#tp4()wzh`(#0e_1_4yan?Q&asYN?|cMM zP!?=k97ey7wn6s^vMScHM>~(@AxQUhZMdYSDna4KSi^orL||@y0CuN8+s@A=vdbjJ2Q?dHG+N9&?%s!u=Xf!^Sc^%_BNU!W>uXhxPM!X*s_7`M zKpL)+_@BT=@(lm55U|@=ekDlTt~sQT-{B%i;kwM1^apuA{@sDVP*s)=>4`N%K|lQW zPuIwwGd6Z!yt*A-9ESDcSHcb#og$FdGn%KfR*6ep3>A{VMKM{Fe;_5bW-t*mP>e;v zorLV0!R4)}u_?Eyn9`By z%|L8`|0rzWr`=*flSpE2SLfSnXF2QWH0XL9Ucdc&k=HvnM)VE0!MYSaplC+Q)I1}~ zwja1$=Zg?Q6$t>N<4g9=W8{3-5ue3tqsDOjkEHE5Kmaq8oU6zpS49n)dKo{;zm#BQ zZ|^4KFy~-zuf+{T{k;vq(tsSpa^LO~G?N`Wog zQ-h)r6x^u%j`|PENjrU-sG>sudBWIE?LOlgR+(`jhJ}V)n|ZKtDJsf6W%MIPpm9ML zvHSKWfzb6&Z^=I;TWQE-`jb|&Z*`8U&c0jvfC%3E88>8HnO=UtSk9sRe z@#y4e5p)13CB(l93tLzq`T2RxzKSQ@xwEp;*{OW~yrUzS0cWCFkn-ir-(JyaF^KU9 zufeCXx0ivm@;E39QR;?ajkaUS^?G;72O^`j?vjDA2o{omjA4ACjJ@d_78nHd@LE07 zWpU%CM5E z&ysyL*LCFUOXXa936ru?BG>jr#u8Nj?NI+W8!$iIXt;ggnY4ZdVm7vSeNdR!g*90p z@iCKz6EZLF_!hPcNP`T`hN!LWFdBl%I!kb)Rpm;BkE+g^s_Yb?GlLsE@^zH?XBmI*w0fbg{-R+l?I(>y!EYWF?f zpYF5#v*(=)5#^s1dbG(v-X1Qs+P4)7Q&yhhA1p%h^MhYQHe0r46?wgR<5#QHm9198 zH9OM`ZC1%}dR>+wm0*<_5}Mxu9EJ4sTxioiJF73|@R189sMQ>S4gtGMivF8cdsdON z?vtgmT@9gT?`{YxxJ(EU602?A(D#8fSXe^_x!yF=QRsoXmHLjh9lc@Sx^bUaTb6Z~ z;t|m>Ky4LVr{deVdixjVlh~88q{B6u=-)S1MY$#VS`Oh-w$xsQ9I!JHkBFGvOq|(qPIYh zE6nNxaxnpzVPF@NjF;e?s+cPPDF7RIlzjfyrUS%Hgu?%1Cq=sLhhZ(S&UW2H9=5E@ zD{)2!R=)I1{=Pe0rR+^}{t}g1MX`DyK{zf(|7=r)PC1IyWaW2K)W|q^wF!ux?apvq zySsn<7kKogpKjkFdU&X*E&fRwO*dh6_wevqoFj~v2nvk3k$?P9QQ5W2m;Q(ZgZH0QG-|HZ05 z>QITZ$W-rQ;dmQB0AIiQ`R&>TgeF_pYZ72y0p4j7BhZ{HL1V9slB~ZvL+>nQWzf~9+{e&TC{T= zcNl2`oo`T}AS7b*t7ZQ=U!yl7+CIG-ELVM!>P4YVQ(_=B^u4KpfWp;^iuD7RuROW6 ze?Z^o%k2Bcjl=-wK3#)N<*PXo9Hq1AFD-{{5wXyyOQ&43k@xa-PChYmJOg33dvz)PUuN2{G4M;aXsN-Q>kjR@N!M6lqhanru5AxGFV>@#7_ zGhY`!y`tz?Qa|3gN+c8 zDKeytJ0i1870K3MmRUNPGEX5{TM{ag3>{@iIcAb6Q?{Z}p+lrdB&0}4=J#1^tKa$O zeV)J0b-IdA#ksWT8FT3N!Ze=tGl+lxDXB> z_VSXI)wR!1iYjbaUJh*(cJoR(CvCzhQ968dO?PQJ>|)9Fy}?zbK_dywmZd7!{ep7` z$I`f(uU^*@Kle{UY)>4E>~w8Qv5c!&J{SHvvnf)lR9|>|;yxW-P%d_fKCqPfEZa(P z_6N3nmEq$X=XeBqP^c#77{R-EL0nL}#^H?MIa`Cm?cGmnQp13@ns07wU~9 zTarn#=*e(50pqfOmPBxmuaoCaKvVO+DHAcaO1oxef>%;;aY;=hA{G_}1@7+fxqSQx zr)rxec1R>_Ar{-FrMcD+eVWeBj_Iu8d%x){8(T8&v|pU-0hPDbnYwzxc-qQ*)9mXv zCA5!^+}+2=sjdEBk9o@(TaS;Ae_{Fb>84Ir7Khr_moMQyA96(=)Sh4(9PPOs18T_C zB}2nqO>CF9T)VD@gem#{{JJm$R|rRrSX&#$alb!SLS^>Zw@*{+Y&i8CAv&kzFniMH zcE|hQ3-YKfEuFXFs($R9sLNqQJ%$1tTqedwC-=F%j-x2n1?J$2G|Sf9eIssy-KD z@MQQzNz=+kDd~cIsa;GLHlo8fkykc-&*=e8QBhHOc~RZWEfVLX{j^$xxSNyjKNwO7 zV&^oD8yutX9D9}GX2nu@GfLfW-AbLfa_Z>Q@owk-VfD75W* zkQ){Tvh_Dz535_*#fk1`5aGQ9k>R*+-%N`%qV}>Rr^Bg8#TI@=35mz=1n(Xr5aI6h z*|n*#NXg3i3prr`P0R`DG>J@TU7TJ;^w(i3I`{_{-56YfbPqk(avF@HUNa*sCZ0k z;ZESH%{LvUpw}l9W(-SGwS7!FAwFXl!O!o&?KF_6qSPK@XXl0u3JM^2A(28u;hYxE zrgp#;d|cfA7y`0(#>3+PBfNY99=q|;(IX=#PeQWL+qb#7rmQ--h$+jRJ0+C~l-#a! zcMYyoxL ~>6&siKM%jg7bP`32K+%KX%4*BTqdwu1~2#1*?4p0@XRSjdQ~*WSCA zL+HIf9k1$emM3JYvHZkTtwFkd_kbMYka5IAK?>I7Y>ZLOqE<)Zo~tc-#aUa5$$!Zw zJpVg@DlSu~!BUO1v`2raBcNt)sIf5gqJKyA#jg*{E_pC+`kQlg?06#4-Aix(8YVE8h(ew&nX?Z zO`C*EEhpx5{mNrvY&Q0K#>exr4o->i^74?BRM@weT1i%M1^VG-$fr)7^1$)&sj5cp zUDOoYWLkuex!u_BLgZ#C2!8HuRirFHbM_1B_K2*jyTDkn#aOBf4#|HZA7dUqd~fIO zkh*W1g>y;D$cZRaa#ECwgR%aQ)QQ?*5C$>nJxKEYx_}+$40wK99977 z6%x`EL1cWoH#r6hiD4T2EJ1S0d1%IPrAz%L`R{+|h%$21(aO)8_g-`Buc3S8p6^Xz zrsM%b{}qh*8Y<1{Cr{bRde#p zo7#t8=9@%Ry_Z8kOe-(1b}aqYU%L&F<|9GM@@E%IYSItUriVX-2YhDx-pU8#{VN=M zj1sw^xb5A$exYB>GqbZI5xCW#HU0HhgotgQQ{f`ZxS-3!JvdcO$Nff1m1{e!H>ses z*|rTFLMA3h5(0(c=r>vVQOp&7JU^R8Ml%k?Pj?JCbl7@5OxBKGZ@8lVEvs=5+nr`%8Rlaq|Z z4q*3O;*Fqk^Wyz4>Bc0P}8yDQc zO#rA9O?v^HB~sPb&2v9+e0jkrjcVm+Ukjv2eEj47{(sH9-;Rz;TO`K~?qjgb>HZL} z5>QfacoeO)o;6Cz3d3}m0+GUCLgz!*EH}<#sG!s<+X*`@jn|)0Ik-f}_{=o(LyV_I zo!)vuZ*<}dK5iwsd~UU9u?+drL^yU{|5!^<)5obIvblLs*HF9qeXg=oK1{`yqB~mt zVqs?lXVbrVO$&@2Zkn2Q_V`@?L7K^J-0kvOb?|rHS5SH5#^9+^RaeRm5Yf$&#g@8x ztQ+U%VeAIoDuRe=HD-(Mv1Ru(HHC35jC<_uzpbq=H^yFsz~4bc*J)~CcJ{VGuA-IH z9m?%$71*y87n|i#>*_v#UJP@ZpRBChZg6LdvC54~$6PM{-7QZfk17@)T@#%{_;lElogfeC_@76QY@e?ZJb{g>1 z6Acu1PVGt|JfIs&2NG+VlJoD-V;k>>tE3<^3v`VW=T$(raCYwMjy<46NY6mq-nSuh zEG`pwFEM(j+*~*Wa|NS?*Fr(VYl8gl6VZBbw z3QtPb`BHV*>Gk;WrLzcn4Q^y*`?oG%)OYaCGh=D|mXI=uk!rx+$a5 zjb=sN6L{ScUWDu+e{k(&1qjX#9}ZFmwVS*9lPkmz2xM^kDfo_??%#ik3~{Vqy4U6$ zXLaNy{r} zjW~VD(vgfRnBa(#qTki$WT9r~&h}48NbB^)VIG?QQ|SDOgd(kMXxyMY`>=f3qnA0i zx0t>YM7@+X`V}Re+3)k$qss3RrBhA!VDOooZp@?U9hn-nkz@HvacWLWCO_VS*?wJ2TY&>INz#+tP zC?l+0i$j}vhd5GVztm+$yWtbDJY9YQm)&^~?zcvI3oQVu*v}FY>aGNb3e(O(RUiQP z$Z<_#Zi0zF{=n@{shZgU2ZP_j2SI@OiRF+(xvvbFgce0IrpswIoIqQXy3%`P1-I3g zs_5>mA!KoAB``~^YB2!Ar{RGIh^&C4s=E5kn>UuCU>BY1*yi*eT;39g5{WXLx^dJN z^^h-P_lH8^X%|SkfiC<25xpBGF%p`g_U`==G4{v_7i}t4Nl-!~s?v5?-pww>t zQKr*0vv6r9spn|Ps#T=Jnflh(1MEtwMm(l20cX$dCmNfXfiD>0Ft@Zc9}A@2+HY_r zVo};@cXW(_J{~-lixUuKxIB4!!-mdI*oJg=f&jO<83x;NqMOp|ujKm1l9JjjFfk23 zVP&N=9H}q<_}#}`0J0HVCxr4BZ{RsN3c7o%{`sXl9XUj#m3KkU_GQF;b9jd|R-fr~ zS1cP_{JhmE?&3`l+g7>{9~k67u4{(=_{-^AA2=}QEJOix=r`-8Th=pSZzsn=iEzJE zd#XRF^fq;Z(wru$UBmpdp-~GeGI7)N>eyH$anC^6%n8oRhTS&QeaDq#xM7By9}wgb zuW<%@vef`!LR?#8v+&>{$q!e{Os59&x|{E%ucAfC7O?Kb7={TYv#Y) zOg#|~z0s+x(yEVK*1srq>pU0r>|JPiwQCnwWjU#_&vVlp&|?<@q@w{7A&iAz(dFU! z>ETGAsDp=HC(U&aDwVFSwMQxvOU*w9Ath>7)$4N==hgG@Q3mbt@?wnYX5r>3Fb@r- zz73zvf6K-O?zb^GT|%$)92_zb;p!0E23cX_!zR#pZsm&t`Y)>-MV36!)>SuyzBbRg za_UvdDnJbtoPYVkk@ncwnA>36-)4DWm^(9-q2#_CB8rHQfG%z6P(+gh{BGx{@M^m$ z70)hI^+fJ~ofMQEQ|WK7FTCVmE_@BH>hosu4~RNPF&Y{5sci+fLj9zs=eFuiw#*&( z@=uz)$nmb!jh52emL1J&Gawg85e} zbbh)#zPHAwr?kHwTsn&nYU|N*6gF1~xm8q-W#*;%3q_RBS%?=g@*X_I9#zmXc6r58 zIIMcARWjK5HIyXt5G1?6Fz=N23j2|w=tZH%YTv&oy zz!zB|Wj0m*;@Le-i-kpGz?s0?Hcj%K?+37~AQRvlom*i`E_52bGCj|2UR#Stceel9 zBeJ;hzCOCuw)Xcm=?>KW-+uv45Q>V(V1uba&qQykU(3o$A(>ld>NuL5K>5m9mTir<#cEL< zHHX(ou72~tlUOq&77OxVe{}kEqeI~x4>GqbFxK|}= zHAC-N;50!L5f#N5x0^tJoWE5M2Sxee*nx382|}diCLGUfJV;5ZCXs4u!JSRXHK&vi zlm#-_@7lbB$~~*TRX2PYxF!CqzMtFTHjj`0n13E>^jjRJDv5rcZK`JF2*T+6tCQ#4`J_A`k)Ci`Pp?BMvtHETFjp_84Uli z@M-3m?qDiSHqw^gJjhBc8~)PF2}^Y1B@KYTuxwXT+p$B58$0pa$zU!Me;}7&E>mxx zOW4XDy{|Cw9!L-20QG6&c?MXWuZ(s2G@aD{L)I`v-`PAeCRru*Vf9Ir!e9obPAKp& zpx|x%`3q=avv6~B&-a$J6Y8msSDJdejfuXRgCVqO98Ns>{slbM>mKxO;|C?-whJnv z4BMDL_T;?d!lz&(Efqn>xf_D$5mm$VV?j7iUqLq;#BJM5Nq@n4l%b!3Q;kuISvM3c zNY8H=e%v3x0Ve;y{yN6r(cAm}eV+^yEoUU}x`}u-A&L&`g>PO^5Pekwb5b0!fSN6I zTJr{Q8A3hf5diBGlj=TKW z?ec0~yK1{ayTVl3)YLjK=m>^aa+kjEdwOkQijT*ldjW0TE3v|yT4KLe#!7G6uExDJ z7dbl%DAot8mxcBmhtL&M)+d8b+2v3V5aE!o<>UW~gfZurmKHaJn6NZd+6-o#UL8fM zJ@J(`8LwJNzlKFz+d`K8r1Sm#u97A7LvCD=|Ik26Wll zT+iiBXuL0fj358qc(ify95dg2&K0gJq}0)}ejtqT)InVU!hssVx;HI{+wfJ&x!L2K zRD(~bHi`6SZ>ptELGQhiqHKs(xsqoQ2sy zX*Y1kr;s7^td$SHtL*A_5oGIiCHLpt71r$ef5x)UIlgKUg*>8Si~8(e)$fkdga@P3 z977hO(<0Zs)2WD@jK~+PKG7aw(Ya=&#au{a;;&FRx;b^K$j(~)TuB33n%S6^)0Dk( zT?w=hVpY#0%T$CN{8IyVWt~}g|DtCt=-z>2+lx7=L06$Uoj$liGhyU-v8GZ?3LxA| z4{D>*H|czIc%mXbZe&KVEdk+*wDvs$&E90tBRE~gSY(l|AU=5;DW$f(B-z*s3dq?L zgwF;(NoYF+!NEYI5Cmt>lPg(jCW{dU`p=sAK!5uCG{z3K24=i+l84DnRNJAj7<;Pu zI5eaPl8TOGDl7Yf=LRN06cQUUEtZ&qpg>~M7&_AKTC-y?%i$TMWAa6rESiFYyN~ji z52rs?j<5GCjq+%M*1_%hdiOab zG~Zo_&d3`vxzuBd>{@y{6?9B$z8#{{ZYl!E$W%p0Q?JPH_%5-W8z{8-OCX&lqic(n zpc9H#yk=K!4h#&SU~GjOS=eyV$xjTR-$(h>&md?PUaQ$L6H&}P#BdNR9D1WsR5bF| z(is7Yg0N=D_gx&vBGMa&M}|g*f{>NsikI&`d(ALztq_97?`$>QnF8;MV+&isdX%L@ zyFDmE`>Ko{$YuQ0$vhZzMQySwcqdIst`8d>ydR#)Wy&35Wz~6 zPV@2Rw8ZjXMB7VQurD<&D*63;1icXl5(xTNOSZ)i&_nCe>_Ww5io!66kZczb5G8O@y)Hqs4l?^Ps1a~Go4I!42VqH}F8ZF1R2s21eUXORs?-y) z>($!fdVt`xcT*I7hK4@z zo`8f=sMl;aA0G$}w!mh9@$EIDn@6`-=ZITl*4rpe)`_rfE(b~=^8g&{{wMqBc?~{6 z_PJe0*P;w9#fy^gS&UhXNERc_E9aeFP2BRp`auwU&Dp+cdWvMR9LK!xZXY`z-ljdQ zV(pQ$V?}+TupWk7=$X;>EROYrh<76ur*77uo`%42u0-sSaL~VKro%%)V)-6e`Ud0r zSf<|l`~_M>7WCc{VTCVa8mlxBEAwECPo9FOW3oNx?R_{uK`J(UUK{;cTO>0>hT0T&&hF`TIB_QaWGfcCg^fe@3FvA&op=Tvh?$NxI8R?}C4YMJn>)_2J~dde z7wZ{|pF_5Dw!~hPGMV0CgBL)TXhJAz=xQ%}#cn&}~auzdy)WjmPLVyp4{jV)LZiF=$%z7&Z|w4+t6} zlJovY+3oDYDzq$0x6(oHiBU3~A%N(IdRE4Y1vaGG;_L3C6}U#Fv?ZcJEYjh$~=6D_AL}4%$4(6zjfp{wxXe{7v{oAs-0-DIcmvL_` z5S!J!5yVEWrgWV#s^R@?w1H>p1s%MI{n!RL1w-|ywf=?m7RGUuGWr_8J|Y5wZGpQt zv1n~tocMcdB$o3EeKbg&kV5^J>DnvpXT#+-p%_*H7R~jnmrYo@^BX_olPC{>4DK%| zroUX#`kf)O2^(UOZv+_yqc7_~Mk+lJgW)=TcB+p^P4>=&79L!UTw9WTI#&~!Q?ed(CiO%iBCI+l<=yVu3W<1Jd#^MuQ^H9(?^v#HMnrkH09$!xg#z!Lc#M4ZZ zE`N?>^z`gw&|i9gzE>GE6R&pl_wwi~&lLZrN7X5Xrgo>;;DakyO33*wI}7ND{{gsc zMT?5f$~zW9GW09I1RVB*#)ltW$o!$zy7cFhh%MEESt_ufQf63Yh?L=Zk6LS(O5rU4EOR;dWcjAjKtDXk)t||KUQ}uq7{ja>N+A%U!lb~fUK=RSc9Xt^cZ^BI~f6? zBn>nb&iU-cr8(ihE z_#=kN&cmHB{LIO1#rXFl(!tbF?S!d@_0n-uZl9w+I1fL`dy)tLPyNK9`UhNBS+dl$ zt_J0V0Cl^6739u5!arbG81tR*{3++ynfgL#QK@T{E%q7Xty^^TH_m71BtJSj?>C;} zZe)B!J)WS^Zp=q@YC zg23>j(tWHUbl2xFspfYbJ+b4`m9AmM8DDMr5G6cj~QorT9S7}Z=wn=0nV<+`dO)RK#R@Tbwp zqSp5eg?a1gp1T~ffhJagqqe5n`OVc<#IrgPQq_OGsz;it^LtlKDuW-H!{U{VviMTlO_o_R}7|e~@daYgL_zpwA_tj`UUln6gfGzqml_x`%;GuTS)Z~u-(Ry#PC9XyuzKPvi; z@caN~^K;XJW<^dTAZW1vz2gXh{?ntQyfUuO4?Y%Hh5apU76|@ZTC=-1h+kSUF!Vr- z8C+p9m1-uGc55e@B3}fyOnb>c6Wi@I3KiD^5OEkjG;Y#Ip3l*xG?#)>i$5iiuwG*& zp4{U!%-uDweL5RORJ@NIjA5{C(iS#Pz9?%vzt?K&A@^!_JI~R?54dsu^y$Xt<{@6m zlzTEMH{e| zRD4%LP)t8^mrLBSJ>rowrQ7m?Bcs>KS$z76@DnQjaPUalHR9m(KHr4A&qgsG<`Ok~ z3kz8Kz$_R7EUAU=Te{b;_glKd%N@JYl!9d>eP?^~jdNE5jONc4?N99`W@99EJP-tv zrtwxYPv2^@r;O9#<_ZF?d=SakpS!A)zxtDwec%>FL{is6$B zTKjQve4%!+elwi8wM)Z6DnAKV^C4aFei_9vHAP$NOD`p@QqyCtITmGUSm8IXw7IoI zXJaFi(v!b=+@m@&3SK!hBZ@TQyoo?Kn`0OXEeL6yTmZ&;%DY2$VT_0^Fe$Qto12>h z;7?Tx2&ZBP9^#k7%zsZo_~S|Gd767%Uzje(7h>|*YDw9JYsg%gdq3Yf^_;hxYS3SLN?e9QdKD|8oIrg{;lb1@z{^d>MhWMwn zE7EQ8-gU6dp$!M5xYf+$q_}m{n@PPz=-WczNjzG(kbB%Z4C!OEgTu>g!4CEO4Eb) z?PwhqW$nq5crUclv8(gd(EFJ-qZteaV`gRm16+sR`_3hasirH3?rtoy`z#DsxWo#m zlEUbjj-1M>bT1!t?WcrU+ahyXJ1=IF8_O)#t<26Ru)Y&A!)Lc-B~??Qdh_+q^p96L zpHEMv$|WSwpExl^CX<6r^aw>?yGxT88~`gpMCGab;+eB{e4EK#DC%nvR9XN8PeAzW zx$n)t8T%9he2)rTH1j2a_JCtr7K!gJIDIEvTClw*coU!D_T%kM@P4mhut0`SF~)I! z-hu|AB7Cs}9LwbI2R^=q^ZO`*Fuko4b&ejPBkNL*m z!SWCofM^p=3;6X^IPC&Zf5cUqdUbOY(|iKs#*yG*6c^WvO-9Ed#4a))J$3o+w~Un! zSnF47HhAjNoU+88ut90vli7n{8edGKH-DM=vspoe` zAFPC&Y9Ny`;#LkXvZ!zy$vOJgZ@x>V#0p^HQx5rKV8r3^=UX`a)2C_hxI)W2ACU_F zi5L^PS452rw=);!w|dWAlIrg1>4w!>KO;MU(IYFD{xMs=-O7+VY5VtFNqB-V7WEE1 z)x~?unuD2P0!{nNu2;7-oBPTMXHa>0IW6QL)G%vXg36=54mEmfk25M`K*^dX;7-M9 zc?cGTL)H*dafARQUjIxNA{7~f1;`oylXw?r>#|26K+wMUr!gVsipr~|OQjh5bC zwMgPHLq|0dP^QIJ)ke%F96mgPrly^y)~~ZZ61c=}-Lk0c_g1SOA!d)f@{i&1UaU_m z+7r_1_P+9>qlVE&U463Y`*+pJruca9ms&r5d7oJz>po(V&(ztr_f+3bFFCG(G$cmA zI-nAIgQfx>Jic=G+uPRyB-fD|Y=O+ZwS%T6znSieg0OcCchh`tI-I+7`%ACjnDZVV zq9$=;af}2|!p6rx+-GJNU;q!paJ9E1_RL_`Q-Q^#>H={vxKFL>$hYv2@!A6Mif02E z47PyaiN%Mc$+8zZvscX}`W|i04}ryoGQSyGgCJDc?PAC=*f#x{5P8vQP*~-wo||m- z#1zwM^3zmduQZr8NqoO%%>`!tjnR5bO%r;f$=A<&3ZEr9F|+Z>dW_=^YBxVWJq}hO z-)z5L4ok2&5J-aQ-q##{0;Buh`|% zr^r>J*&nqd3bt3tUFj;ere@g7m4w1YqaJT%bX+DKUvk@wPqoi!p`w-O3cVUmo59m< zdb(8NYch2A9u;Bd+KOoErj?+BgExQP;Y( zrIHW7HPg*0D>{hgG!Jd9ctF%# zvS@vf$Rcta7s1GQn3W6GNlxvOOQ&B_2y0$cv?YpWlvxy+6mV+kLg*#EMN70sp5TN4 zhe7~Q?ihOjN2(Eoio8B*dtgnq=9EP|6Wdlg$|7P9D~oTP^k}ZSJ$zB|%)b!ghKFC^ zIh5o{xBdGagOL>5X`R~+Sm>QsXL#$-mLz8R9y4}u>OSmdVIdyZD61LAVAYfzfAOsp zlZDsdNn9yD3Kw}FC8zT20~oy>3W0Zcha2VKw-}`XEL&C7cYla|cTjGYbrl^Nrqy^( zEeWF+DDx>n$LI`V;+aM4@HJ*#uM}21<}@NazE~YUKWo-rUXgw=P72>2TJtc2?LCa& z49h3?v=y1xD_xk8IV%KDh;GZxfiP?0OO{_CxeOFr*ZR%qIXA`JngM1Y$bZXsY1YiS zjQ6Arr&TL?2h*7YEjv2>wlGHph-vzq2dQ~P&JmAKN3RTf(0i=?`Tj;TcJ{b_1dkki z-miAVtt3E+Lv@~7rtsIiBS9gWSEhIDGag^{i;AD#s?*H(_vrpR2_Y}t^o|xt;L!Mw z36O9*m5tjfxRal8aL#}Ao?-VdO)UcieFynxD+x?a;GI!&fFqveWK<{1H%bu19@A>~ zrAB&oMeu|CIKEMbj;VU|WHk1jO5xPmuGL%ALPoDoM=o8c3cvdOq!kaUm>7$J<$t{% zL42j)zW@xsKl-OT+ht&3L}@MuqY+oEj^thXW2b{mT_fKZ%*grchj`M>spC}}l$z$E z&8XYm+BI$DZ5Y@YnvF~XzbMeeDp5_^>nUQzG7>N**vkWnY3FooyVVGaF`O98DY}N-izXI4mW-|40by1b^5Zy+ zSo*5HU0nx?r^%5>O4ltBUagtdGfvNhKg5yO<&POr+V8MD5Xv*Ml{D?sOH+%FiHP<# zlY1p^My$#Nv}fP8n(F267Ld=iHXF-Ftkl)-nF)g_>$ldi+hD1X-qYj>4S zCD~7_xl&jz19V((i7hE?e`m&B4?yRq*Lk3+sQL10EiKVjwQHUG@(V?*p4nuUOW(*R zqqO9;#6Cq9su3?l&Mq?LO1YfcN)IjVLZLc}ipJh?*Ee zHNN$=zVi0gts|yg2;|Q2043^slu>|Zb=NqR7u?DPm zfHATieoETNHb6oIgcu|1;lr#etKqu~yjK<`9{cJjvpg44+}T?Nzwn=Pr&S=>h61H~ z?L2+UBJ!uUR?{_~)l9N=HKLi#aAYftgUXj^Z~egcOWw78Uv_?8WL5e$jZ#e#Rp5dG8&rV4r zRT$%SGPlmj%r=|nK!o3oZo1pPO18q9t0G8WwXXimxsd{v z+<#y*w6xkQ@ppN$IaW}G4J=%t?nplH9#lvtiNPfxl(gzw$t^q78nC5JkesM<1Wv!sVieo^J&$p?$0;UKZoj%zyg~j%CO21`eq6iSHaxj(9 z7{Tc2>E6Jin<^W)k|=_V^OVJ<@~vwG@HFb(Q1U!0jSUqjvSfbeK2~h~n9Z3rzQ{8C z<|nu6>3+-bjMLIfVwX%fPvqfr{1J#{kOy=Gb}_@R$uOi2h{cPQ^!@;7Qk~-V$&QDtv@5 zZ~sC&fRe}y-F{Sc_?}f9Oeajh`fn9U7cDfGY!ddcguB6JOWtEAJ(m)=la7-c<#Uf= z{)^b)2!7gJyG)uqD8@pBEqt`DiXwMa6IZwZBOU}m%FuSQf!aU6zj^w6=(Awxvh@ku zUmvgq_Oa=2jc#Ij@~!aNVu7Eu>=2~WI^7n7674H+3E{fZ2aD>Tjvv*(%#dmg5q4Pg zElhH#!>^pbQO5O?Ost^CoGwThn6Xyt&OvgE^I3XrzHjF;U!J8mw5GNKK-9riCk>$t zqG%r86aFHKNXw4X%f(KGQ#EB@m%%1)80;&=!$O-{&%Ia`xp?uS=cb!ocUDV+V6d*K z$(JU-`JY9+Z|{D0Oc%2{q^_Rl`AHDin|M6k1{URg!fDAT59`fHCzeR?{sv?-?*T_w6A5<)Cy8jJp_ zD3NUjPob>UOg4hLSdsgbpkRl&#?CN%ICv#Hz{Fia{mxBHwOYD>7Yf?QbEs3B$w`fP zUd;7=)WZuL(GMR(n2S8$!rbXQY@72pexG0m{8it3x^;XRw_XKO)-HnOJZxcXm{bkW z>vAQ0v0vV*Z<_I|d8Mc#o>)TJlB}5i_&)*c8 zi^r?55T_WDj_bK4v-`~Ci-<8#GpMYToTJFENM!f~&8&6L;AXsg$T?l`RV!fCYSk+C zXjhYKJJZ`^hf9x1I;NC&4B}SPI{|qL%XpAg>|Ee4T1D`ETJ4}X_8EjC#S9L@(Zbd- zGRmaTtn}8ygFEj-%FV@fqF(=uQ2ScV&u!vm&69N&Z85^HQv939e)#ZVmv5>g^xupF z`4s%7zD|6C1Q8}H08m<*uLLu*B@-CNDi@d%T3kICrHMd%4Fr0cw)r9JDQ7-KAlwUz$hLCtS z!FXlyuOWV@$YQ_R%E1!+AXU;^jZI7q{HvX94ph!3LzUZK?NcTE~M+>fg#ghj{xL=D9N{|;0v*ML!I5` z!bmOPzt|6ywE5XvosoiI#B7>;ik>+8LA$u-%gE@+hY_363Fp}(QH)zX>DQydB!zX* zz?_InN=gd@b=BQ@|4})=LN=>Zz4b8CVgsmX{WEkmzY8cUgC(Fxx)K-+ zI6m+0%nsRvu0P^6Q`1O(8BJOosr6qRt(Sj}@A?G3YVdPwGM&_d1RNNkN|!$}$S?8f z6hZ}E;oV`|hQ?c|yV}Ttm`%A+a)97z_khu*x(Qgr=j1Jpx2_c+i}to(Rz3#_TX+F6 zWM3j_-RPcK&^2na)cI=XGgV7@`dyfq_!BLOARPk((4CH#(lt}I7KhU2{HD1r^1tHc zfSirtI`VI&EA;)Qg(YUT)k|c@pAH}y$B|YK3j#9#f9s(eUR#;#yo$v1uINYPLgD&H z>6>58Eo0jih>Xmi&j?o1ZT3jZiQ|Hl$yiWUXqr5A876fJk}bj?3%rzFb_eKf0v$H~ za@%4!b;Y^I7Z=Io#S$R49HaUGj7y*bjJ(1oXhJ`ztV~4MsXwrx#PCDCaB)P@#yl3K zTyFkMg$N5Fcg_!mLsCo3Gwg1`hNZ>gj9mWkLRrx^tgAoFtCp4M<6u0vWzB4IKH*EI z<+ikQ7V@hoSMA819&ax+BAMaliin7}O=(1=^Xej_6tEyMxhO@5jc(Ind^ZKBb{X!1 z|0K5i$eBVDp6yW8hQ_mj5k6Wve&-buUg2iqKpwMuxc>2De70F+_IMS*S=yh(AJ3tZ zpNO|r2UD1!dXqpB?Fuyh%dm5T!$v$<9w#M_*CZ{|Kg@eLL6~9$pt*EN|1wl+oIP8k zh|d1_@W6UrZfRC75%o$Rd6vGsn>8-){9F9o-q+xt^CpX{wTlg#qs#)|KE&2h9P9!= zJ^=Gj=)1r2S&=QW3W=-_TA9!_;%G(IH0n5F5~$Q{8@~ zaYH1uZf&`{dEG(B7GmT4^oCdP@@FWGLvxdBnG zV4Iu{2s~G$s#9%a`Vk@~#|*47rpRilYCBwYxa5b_Bb^n%2tZ>RuI9UrPkGH`95Pt+ zuO=0at)^f8+yhTw(3$=3PPs(_IY<#D>mcH7IMb-JpCFfQ&#rsEIz95~nqMoE(awR< zo9x&pjv7hIHq)q*)?a)W%;r~abNf!@c0`otu!<4{eo#0B>-?iWs76}31u$n)u?AF; z+HdBL@snjLhXNHM-^j8i>WaOvkiy#DQ+5W~I)K57t~m^1E^`#a6K;R zq`JEFG^iZzZwvwM;nZq&i2L~!_tCn*RUGZhaQ>l1EL2z>sB$c=^_kj+uJ@TXK43Y1 zUiUfd2=%hP4mxe}J2MIW{b{kfG`7XJw1@!__uX6ml@iz#wq!~0PI6DaEhoS6%}(se zKYNZPa}E470lY(vRVtKNlI>Lxae$HKdkZnH0&L~!wc)NZZymyjt&{KFBfqBvI2nyN z*~^ndN7a4f-|Z;SrfsdUyKMoa6KPses^E$9vAbjvX(HVd0I_l9{q()IA%QE=%>mKm zxxm+jzV{v6D%cDs~qAS#qvJ$$jmv61t`xYdwTwil#r1?$dtu=c<(}!W3{2I_*`BX_N0_ z70DOcnKTKSO=rXTATS!?>>0mbR+{zhC~aykNN^g-KS5gNBkWatH6FDqW&e(oV$$FU zA&_j4Z|#9L8~3bFC?-Rn>A30wAsjw^7aSr^9;|2({y?~Ex9cZ8FboRc$>P?mM|h+l zbroB6TWWy<_-~Gl04iB**_NU-czpYYP|?~HX(x=>ke>UfSpcl-fzCi*91=rgc!2lNm%y^zRE*|d=);c0)P%eicDWZ0h(n(Bjo}5IfEI+ zdB0%2gzS0CQLc>7ToL|nX448vp6bU9JG?9XK{AVKcHH6ACfu8MEK~)1J_0*2+e_PG zgHRMA)uhtIDl&rCXV!Nt@j>!R5=wfJ3Il{4Xn1(%OwKG6oNyt zH*+&B3+_C61;vO{m-BvAx8%9Kl&6m2!f9!{U_nJNw`ayjz75ppB@qvi)OsS=pEE3` zek!bGpTmyd4P@9ttas?-PSg6)gJj-sg5@^F`i1WxVDyPe=@3dRnNE^QeP8q4;|B=` znt5Zc@VTc_COafjY-LF8peFPW;u1C3bOvn))N7wf#iyY@2>ftcIbM6r=zTXjLWo~7 zpF*9I&hP~AkQ(Ko+oI%VUE4rW77B8 z=oDEzyGE;N-=$> z+q@)E80l>~2q})m$NLZau`hg3!mW?>1D2G~i2~1b50J27k53(||6a!Ilb6m8SEy1v znGTwWU4A;Iex7I?&8gees41=ke2G7T;&mTT!!uYIp|LV~co(1P1mZY;KKPM(nwr_5 zbRz%wM(Sam{@bO0=d zb<2`5h3h#;SpQH_rKLM*X-JSseZ3fS-sh~l>bpY5L7 zlvYfGZXt~H58}fo&XFOVYv7m)Yy;%AcKhHWEa6%2i4!KC{7+T*p|po2X~xFD+SRu#rx^Z5lzZOsV?1 zik_GlR|UzdR*~I2cDT6GIII}eH9g4tpI0X`b9QR)=XS;FT$JGEl@XVk0UwE2M~6a1 z268h$ImWvg{#E_F6r6k=WK)zG@cO9C4_IA<=@KjKxbArDNosySOFU;UFJ3xS?` zhu%9SNmH8Uh7cawG&SGb2o3Yy9Pu9u-5hDuk*Htm){&TL?n(hOnWCP&o{veBM9xVG z9hfgwqSB{_{-7?fyg~FO^%L*<#8yD7I-~(C9|^`yK?s%@AC#(6GiFeF2B$Sb%49`V zR~ElD^0q;L!8bGyqVhW%d@F1J9_X|w`=*S>EC;r(4scr6XiNxV)p*>Ciska2h-=pL zkpshQ_J{V}H%V~g`24RJ2HA-RtGE27KoKNIUpM`^@=fN7NXZO&{o*UufP2j-gXm0> zk4_M0vHw$-r!FkGmgmteik-Abicvs6Ok}tLx*Nc;=Y4^%GA1VIw!a98Q8$_cvRl3RFZzg-aNKA8n#GuJ3_VA(szU_LGNeWGjPGNgK<>dha z@bK7f!|Gr8wd!h;Ye^xzdPDsCruF^LOD|x#J6O0_(lVLX&DT60@PX;l$hHM_gF6Z{;=IGx@r^^}A zt$g8DP_usEK1^}8dR7pa`s}2^s{-pE4*_e{nW1d= z|9v;%ngeB~QFGu78q~gjd^P%=C)LR~?U$mj z?=RTw@eb|IG;s5;PSwjbF405<1IaoYZ!*oZ4^GZyKOx4>u=VigDB$qZh&G)hdb39k zW+v-Hr7~q8e=UpqTLm2ITvnG(X+M9-&e9$vhJGlxXDw&u28_$hZem%OR>l6jVF7HR zrxV`oB(w^HGnC4qaGIYcgC>{KbyLw=2}`uo?mt&~9Q&}1t;6hiMqq>KdNn zkq$JG4`fo1N$GPgpPB!&-kNIQSRiktSdwfKDi2l(H;MSxTcs8V9MW#R2zv0)g?lu1UccuZ{inb+K9o+<;B(^7V$4r{dj5+8d*11vmY>JU}*5 za@fv3gkur9B`se3J{r3b6ULzn2fZEPwh_KP7p@5VUdRo`m$3`2cKXaQGCfwlA zZBg9^8+0gm{Ta%}rXOh+w*;s@h{i0cTY;e+s_BQT8&ljHwtuI%&&uV`T12T3c?zwF zyo%)KMuh84s(B$940&_mD<5Jpx`FS9R}14-Tz`=R(Gh2=zm&g3W946TAW!0((URG8 zGF@^7_VwLT-|ScFYzOP(Ov1{1yU4~e8AMx^%O~Di)Ytt5{4(UwnNvGOO!ts{+NOIP-aemCt?Dy``naYV04Nw!ItX)$VmVCkJwVdYZY z?c)KB{1Djmv!lfKP=d7BDTJKksblb zFIgg0B6TSPdM`4yzov?-tM}cAK%Vi|LN^M1z-VlOqH$Rw4A4gA+OwfLm$5#{1n=RwJ>Sz#Rp4Bk(qllPx_y96#E{==>{$n7d-GM#{p-zp=v0vGiZOQSPD*|24Ax zZH&ZY4=vQ7?^KPKwT$FeoLWX!;WM;;3A4oMo=<4G z)AJ$0Q=w@-A6Z<+iFFp?v~k$H-gRM`CwwNm_;Z<=VhZalE7FPoZsD;@3+aC!7f#2< zwh6M6j`y)i`P*NGKnM1q3Fn`kf`fz9yWii>XY+3QZvb8!UK@0&3LulchDqE(uet5a z@0j1YsfrC2I-iszpm=ENcd>O!%3+`RpQX2x#Z_sMdEI@i;v2|gZ}rPS5;d5AcWqrd zXlIv!E;u+i;m^vRbnML3iwCAs?!Cp)9#q z*K+#)<^CIn*1tT!K@78jl~qaFC%EgVmBHIkg}Af^zkANeZ?*niY4yPaJG87z60cZE1;n7Y^_=m?BA2~n4La5+oYg}<=x%*gr2&<4o1vxMu@mw zu1&E8OXmrc3~%{GUdkK+O?xBME4Wd~dFNZU&w+RH3or9dW|oX!lMo6P_u@`#A`^Wa z;%lstZytQU667WvTJQKUp+--PA`9y-qEi}hFMQGs6v5k+^)^18yb!pM?1)HYdt2CF zwp(DyM3gIBTlT2# z3*?1%O@^S7p@!IPL>`Q%APzmJIjqd9)%!k~{RcW)N%n5qPSSx5MLXh2Z3s?1z1$vi zWiWP62m{`-`KO!b{p8p8qrJ6ekO+RE{ARgVX>;)wLM)NJCap|ZBRTAQI&Ef4=THYr z*euz91J(wbIQxRyn2fHb4Glj2-Y2G5n_s-T0f8wbWMy^UFC%pK)8iBwMpv0!V+-5< zyr1$5l(GGtv6VwH<6jBhX}vFTvo&)&Yt_Jph27%lr^lO%%-ub)eCQjDFo5!Mn4KmA zSnNegs~x`#*G;$qQc2H>`ZoQM6SB`J&tcAd@+2*Ip_-f)%=Uvi=C=%|IRu&hP&I{p z+(!skGpH6vzh1)C!`$LlRUT)S)_U|+_SbqE*9QP_)U`ffIu_Qd+7RMqf}J+H3*o{y zs?m*?uB3kBr%OqF(`p3qcZjr!Iyz2-(@<(aXP!l7-BpicPfJG`R1d735Cq*CHf^lc z%((VKi9pFY;d1kiK&+p*$OzrH@`x6*7l^rmi-cjf(yx3L&I-=8UO-2c%8o?^pyHVB z-CB;Y8+2(qu-&eTgmd+UDO2G*OsSc}S=X`&j+Qga`XVn~y0pp>a;k5`69^pWy4Z2C z;{zvX%yXebf(=E51t`o~RLp*ZUl4ce&T`Ocgv`(zFSk7N!x%X4aDyBOH(dx+j3vV_ zwM(w9#z39sK^w5u;lzYd#~5ef??U!#(-Nk%kd+qU^bn4vO%Qvt`A2@dr&_Q#f&yvQ z6FREw=Y40L8PkWY#uzqg_$ZTOOV4W4VOTP`#4MoNc;$oBJy1bNyQG@ms2Oo?y{r7= zSMO28LX77!(n-pH@ zVFwYG8?G#Ws+IReTV*6KzrSR!sNwsxj=je3ULR7%Da_rP!!iJ^yYvm~3Wd2i$* z+UyzPZC{5=*?@gXi!Yhc$JHAo{WsXrZy7t4$th_d*`^*qgoT>};pXAydl?Ao!K&#F z-I>Wv58Dxuq=~6?RNvvaD3H4W&e`?Tm2o9hG}s`EoSpepnKlZ7aHRLlOc({N3>0Sw zhkDC;Q-27DZXf5u#sb^I2IZ)cQJ0CDkoS$5)(d?N`p7Ir$0tVZcci}^O=R~{Bu4@( z!|Yv=h^|(#dOiLV=v~#x4W)CaNr%AHFGeyK5;9uLzoa`dCYRz{%}lYLb1M6X8lv)w zi3^^T@_LePj=bVR`eVf@>?C>JbfIL}7Vemn`oilDYuu&tj=G)CU-E92yvHFScd)Q# z`rV39DZOpD(NakSz`0kjP+vL^0Hu^K2g#=bZufeFq}M~FYReK}_Rt*gPNPfVfLTeY z>L>P7Vc(YM!@kj+7S>MGhUgR1X&DG6vGiZ9bgx?M^E`Y2;g4KCt#tM&sH=&9a|YrY zTfiVhFyc_W0p*_F{2i}*f|?4ZTv5d5UVyx{cy77tm-u!O#>At~74M&ADW39dYD8D= zB=~B-!^o(1Z=!hbq1W+b<-krS2iK!_T?cbp4hSQ~r2?%d?Vm={Aa)DwASB+n?@w~yI09tr;o`oc-TUkd#!p%;~J zO7}pCa|83k7)#oAKAaaB1%YOc_B(P29AO?l4EcFMAAb2u)P#a5MaQTz=-&EIi%mU@ zX(sAB;ZTOO#T(y_djo;rKpwjQ26h-<=b53L#iq3R&mlF4tKPtpO!Ztq5{r}kXjPhuf3H&Ms*W&)+FI7wh@k2KJ?9MO;x0qys*Y-GKa$--=e(YO-#jBSd}8M}C`s zxas0t)`fnRUR?u% z^^PZS8)h}oyw4x2AmFdamT_GEwK4RHQ&wfj_f*Bb;tyxs_4)oM^SkP&(WAjv{vI_G zhG@0tM-&4Kf5`W!UeK7%n>ly^uXcm8vPUX9KS(n;nnjrOYj=kKZZrF7b93 z3-~m=ST*LU5?3SSi=O4kSmu2;c6aZ3->bL(Z_@cevt?sAeb8wwWX8efX6B~}57{+t z3kRG|gh+J*%~QbmufAl$U=(;znbF>=r!3d3^S!SEr|t_^4o$DP5`?|w2_+AVbdq&C zMuZ54O{cZSY-E1MuLqjw<;!K*?>h+Ibp4XMfo;C)SnwI2G2$J3^>^yZa3p!-8K((B z6LY=rb*2ujxx5;?`_J_UN~3iyG^xm?i)>)czv;i1mOCt+O}7W>OkF=)n5lcWFmVrl^Svx4g7%>O#N+^O*`vn^?_UV@$^C9*>~ z(DRXhrRNAt&#@eW0Hc}WxdcpW-XV!k@U6o6Pqeild?OfTeI?@<3_p5{gQ@0HoDn?9 z>UOD_DDs%mfQ|;i@hxI5fmMv9LGixiWcMXA{G1ZK$fTbls=RkqKDa>nCiqvI=3m_d zU=^J|eo*#=Q9ArbCxfQJG#BIqNWIWiQ)_f783{PoB}H^vd3YkF155-s>eye)T25^8 zfWxW}(YUTg7S$w|QL07RX<-R(o#p!0A%=ovaSnSz&d(Cxy@8guPqH zvFAT&vlU-hA8o1vAEcs@>JU~u#HT{l^Z-?w^#;}p={WU4eSjV4l-x|OqfG7R*6hM3 z+I{ZGUn+15H6s4Yerc4+>`Y|2_Z@P3r|Q4`FFmi8Z<>-03BFry;Rp3VDY)SsndGUBt-tXh=OUtyMs$9 zh#$*)qK1_Pn&@wcIpfXv(>h(|+2U=(*rv$yUHu_xo5^xn_LNp;?b)Ef)Kagut!>A` zUMUj`G-qFe{>B177n50$jg1M)z`_EPm|lYX%*R$ykLRfHk%uR@OJ8_?jQ~)>Wt$m5M_i~L{qYi99TVubZAv3dX5qGkSg@#^FO#evruBCt?kW5y=5Mi6_3xdNc zFlg-AO43`oVYz+&8_k259a~F+KzXUZ*m{h*fGNL$lcclKoXtEu+ zEOv@TKF_a?4ZK@;WC`O=|J=mM*}j6@eI_<=nsUr zW&(RntBHJzgE@(8F}1VuI?*QmujV#a=&YZ$`?OqoqD?H>CQ!L^#z$6LCmavp@f@78 zJa44Cm~c%xO%=!cL|Sh&Xu7q^3Ggo4}S4Eo306G3prQs*&{m+O_ z0J87VRN)#%J68yW%7)ol?Pe>&pncm`QfMNf*|cvMyO0CXcky%L@$Z3OK_2pmg}9{X zJ%MW$WTH9c&MhrBgZ{VW=AHXDX~xW+5`FB&hcB<*c)bUs<))h9LRubflpe71?f|3* zVA)gvl5rDA1@0Rf&ct>0zI)vfC7IQk_Iek~d{oDG~{mUor!f>PSg z_w&6hTPtm!KOc5NVB=HV-TH{vnC%A3_ILf~i8bq^K`tpWujJu6$qOTvgk8%6**v+L z^Ll@ON-GXuT9Oif<|3aS1Yk0Wh{-i60SQLrKVezGvEiQ;ODRpl_O8>v@x6|%(|@8x zFob3t9buJ!vn20UZD-7`pg&0FR85GmO?8N{+mcMTVO8T1&5KwgkCoA2aFcB`xRH88 z^IL>Y9&i_cZ@%0`#65u-elAx`&dK{k{H|Rc*~YmPfJET}KA&sYdn$rR>aNkJQx-8NedB2Gc9?Mj*~0Ge zFY{u-@h|9l%tX<3t}iY{(yCPWD)74loQ$L$G`Uk<)Ufe+2pyAQ*%wXJTZ}9;cr4di z)-mPnyJ7`JF5xW4Yk0pX%GTUp zq!|PI^k^OQ;z@W6-2>yFz>#SFU2r>bPfatUb%XNLMMsC84p&g@++XPHlA#$3w%e7= zIr@}?UC=o(`XKg=EWiEZ}M96AgXcEyE+-Z zQ1=bB;6Z$rtfFVnLGXRpzYRKAxNpx6S5f#E6o&m_#RFC))i&3vp>isI(!urO9{5c` zdy{=C3-0$E?m5&y(ev*E-Q`ZC)VQXW?w?f6M1kLqy3x}R8We-fPsJbip$;(?`<0N{ zLT_mf4q(7Nda+>_Tz72f5iWEkTLGTZp*MFvu4&AxsJ;4>3KF(yvT0K3D7kKH+g!KWGDUIBoIJTF$|Bz0#T5_{;z?PS+km zu81cGO4q^!w9Z5gFIx5Ocv4P&KF#E@;17~{xON1jq1&)6^05lIoC$7dYE^1M%iW;! zD4eDME#x1J5IiYMydT{UktRM4cz*!Pz=#V8E{se>chQqAPtSiyWH9(Q%1aY1qE!g} zPl5Ekh%>Qsv;(s)Y?$G}VGLJr;q3f5q;+$vo z$uAfByG(<$wOMSj9SGlsz2eo{&PDmg;Mz^U#d%t^CAv{P1$X1pjBi6N3Nzc3=b6me zbDT)2fe#O*Oa#7yW<4oRT)eBk1%2PzSS?1{-mV91mgzk}B|(-MDDD&MQmXWvY$Y@* zEb6|H3Y78~3-u-+?2b*7F)PsyttO{u<`hc=Rl-{EvC4GH+fyyVg26|sRy*aqZ2~pM z7JRt4$-n6~M+S&}FD|LNy3X~7hd1I8L+?4c=}lY=3=Du{ORHUIbgn)YK^giijcQzr5>FV0S@0gmv- zpizy-g)uWlLWO`=g!WY=vxT1P_Cs}TI>Zt_%S3y?-pGVH66~UI|N5ziY@7O=$o}Xd zRXsFd_LtVc_uvxX!t{D{uZONxK9+h;jqzt|TwAzrpi+W~Wu#Bfyp3D9%~7m*2UiSM z##*{u4!=)SPTF)5?l1s9Yt_ofnR}5Kvdl1 z1IFMO?71!*^SD=jxN|;scBt~+P?}PBmvXsT44+}TR(3XSXx{7I@S(l!E_!C7NBazr zxL(jDSFbXA;8s~#^92;Q;R!9!QoUK3{ofxZMX<`?t~AEOxGrU0sn0`}V`Jb* zbK1LohGE#vY2JT>XLrgklPENKFwgbg@`u}*rSbdh%3I_2YtALV8@~h=vNLzj!;_=u z9H~XrY%A*abYk>w+hj@YLd_finuB9^DKtSg;b0p{5(G=Cc+7c|wcYF1XT;d3TDZ!A znQ0pO3+6@_!r^J@XR}+l@xLHlN4&Ogz4BM(bUpl@ama`Llkh^&uVUc^x`mXmv9;Zt zIibbZj|GDMynYM{@lb!WEjqXDj`pKUym`eBewI4|(AK?=MiPT4hb|hWDl$`$H|4$! zn$wac2D~lN5`Sy-M#rg3`*z{Q_6eWYjP~gqQ*MK#e;{~N-C7a*%?ZG@MKmNsg ze?}@)sb2BxU-(Tr2e@rRmcM}BTSeH}vGF8#vjHxScUJjA9#SUiK+Ba;hvBQp(CM=1 z5jmM>ImfjmF_^6W z3_4L?08}uH2;lw0n%BxSF*@p3+edtV{69Dhc^41UeP1wO>=&H&f#6DdcjE0}#Qo3^ zSmn^bzySB3pA|sp?pLh}8*_cbc(NZK+j>CPZ=9+|g;8{Fo;-LVPAC`dxlQ|{Nc1)V z+Ygg%19;5-ZE=H7>;MCj26twnWf!2*1?GRqK5xOD_mx}k-;%S^f`oCO7D|<85qvBG zw6+6EKjBGG+DCkNmgl0DsHLX|=;`S(LGC^K7LHK9sVLq)rDTjo-TA;9D=!%yP{j7! zCjk1t@C{h7YF`m0lbqo^S{u0dyFNUfW;E>=UZ{FHc|Im3@A!9W7T;ay;ncg{ed(te z$AyG!u$x&sk)-NEoAUOM;#vT!6QY56RDd36s6n{rb#+94UYJ$ zr5o(1sQ%eSTVUDV$>@V`vDkt0VUc?w)KYy>NhvvTt-lU~2(h_c-xTzWaaN*`^!DIt zqvB_f4+MYEq(4(6&vSfrhE3o!!BmkP5l`xxUJTj3zP3mL3(`f>9EsdR#rh=lP!jOT zB)aToZ2{qXN>)P_yVeWQoQ7qIfctx1%eB(JGuB5E&>E7CvDwHV^)F(}4;U~_ftmIS z4xdmNRaNhL?dggG$6LlKW9S5`m+zSNrZnamg0|fEp4Y7_4Q1|1F*!O+7M3d=#9mCx z)KQ}&l9bjfa}PF7NQSPgwe$$jb=m;iZMFw1$t2j7v5?gc@WTSQJoylK28O~#mZlgd z&S$#=(lk*d%(CHFb`BZO@%s}*+?ab9X?vgPLH)^%TR);;HlL#cN}1lUaiKKwIyoHvl)Yy-kin5BFJ`2x`1;0h+R{Xw9ARNZ`W{n05R(nu+h) zRZM|25EzOG_@^^^$D!MlnT)5uC<8K9$FEQ`8z^nvI_8V0x5C~njPHK@7r50?O%Jk`(0BobnUxl z6=f-eGb$}wh)`J*#aJtnecG&{M3S|v zk!;zw?>^_u`~QF6cR##YK;ZY`z$0l)oY$qb{DWEFUAg=^pZOA*V&AK`+}f*unmB z)irrbMYhjaM%dywyn~kDJAdnWqVEPMGbofVP8fDGPgWVRnV4^-ie-rpQA=A*=^c$l zOMZVlHlmP(DSeaT6s)R2#Ofj9NT#iz!QWk&5)XS*`*IUBQNfk&dxr4fN8!lcZaBPV z%2$>=I%3TX=B2_T#6dhDF5GNln;iRzX48;z$xaC6; zdHXZdQz-uW24~&NF zqAfJ!Dg=D8RKzC@DM#9UhT&fYFDl-tyFS0n?@Qe)G7}?V)E@zA1!kM6ClXf!>^uj# zlj@2+d>#DS2Bf}_D2eCE>k5)kBQRCD zXjo07F}0sW-k}@EBr)K1cgvWv7D}yVj=n==i8OIJaUL03*|8Qg#+t)uz)ar+myDnn zP8h^+wi;97anun&uA}hvf6BtQ2H#aPGU4mU`O+WfanrM>Ecd#GY;!hxHY6P!3H@eB z<9!v`P2Xaso_OnKnm@Jq4T8m)&v+A3bd$z|6#qKdgEJMG`v2-cUUCaZHa}a7n6GjY zKL?A4bq%+eu=?7uzz;KgU3x?Hex}1kN`^ApoZcxnQWt++u9Yij_pFth7s~ptcmvD= zREnW4e>So(<>V*y)#UClG=n>A@M4JTS&DPRfQKeBIk$0b=@x(8e_To96BV@^6;AEM zkox(Nd4Hmv5Ca>Uoh)aHGtG9{Bs1H?gx_9Y(kgl;vZSGRbY`{GFrOF3wsD^u&Y?73 zF(xNFYa2`7jTz_XOiE$VwVBfYxc=%6xS9IkKWdwlF+A?2F8jH5GqVdoL)fbe`IY>R zIhLw-SpKr=6B-21%| zN{+Ar4lxv+)y&g)L7Rn~9v&Xbot|b>=-F2jB{Lp-ayMc(PzqTwR| z5_fG((GS>kQ~nxjH4a5AOII-b7+#_vlW}v8#qsI|`|OyREIY@xt^%sPj!Wjvh}1mZ z2aH=@Yx(&w5I7nRs4UPjMUWO1U_ z|6UQ@0-8aKOA<&7g$n)Irj=*?zk9o?%h#>lyW8z#(^wTe+!Aw|1O4>pT!YTX358Abvb=VZm!(6cHc**6^w89*2Dn<~02 z>xa*l*(Kckm-|4A5*c)Ke(!Hfd;d#q$hm@!i*4r^%)^{orkT$0hjC>?POj?sO7 zTLuSl zK_6WSzL*!Mxpx3^PLUx;`UV6qQY*ju#|qR~$}sa+ba9=N6WI7tbMtUkcJ=LB*{l^a zVXUSCbv)ZfJ?5nU;pZ-C4@xF@e_b0F>3EJ@-JV_&5lyS;roXRh5D9T-#i zB!zUx4wHo9?Vp1S@YXB}@m~E~FqyRD(N+T+j@sEWij@mqQZZVGG2+}eF=0y*VF|>oSnK zUm|{YM)~#ZdNUor^ur$`SxqMbdSB*sMpl2VM0qytD(t3kFPimjCaWjz>xudG-q!=s zOtdd)*k#ORx~%+nrEq0nIgu3YZ1_^jx~pMW++k&Go}+szzoo^&(W||@=u!KMPpTO0 zYc?!-38XFhTkZjm=c0!XmYgkR@d1?b6&T zBn-;@@R`r*Dl7ww>z?jZ*>EE36hT?=5{iRA9(syQWk_O=dfViorr(aB1h0eoGK@? zhS+>kG50t(9j~tV1)yKyj zYG!#*an>zGCFf8^Y=2$R#}+2Lh=@aZF&;N9brbWUcagLDuph7NJ<=vgqo;!-GzV@!@ftcO6bH$S=$ zf8-zxFtq1{iA!c$guVw_PR(AgXc_q_Ym303&y-&Yges5(DuySZ#`_=|H5QCFK#y|Z z5}D=2z8DE;LtlUQ`sq;CS)hoXDYqoN;r*5P;LD~5*oWk zO3!;@ic4;+kc!@TPjtp;vg0KZbWW6Ups(+5l#a?locYFm8o?DceNriSf#j(ICM9@q z(8*r@KS9PY8T`4R7r4vfh`xywGRTce3^Ib%QQ*%AT0KDfEh%ctS+XF?lGU%YY#{+J>ce5{x#~He%@C84l3mt?g@!x{vbJ zAlmpMCVSm5VBc>Gn%M&C52;z8c2+7rZ!hFpgWACO z|6X$hD^*b_ibC0iUU71f5xH`BC@vO96ET>vtIYE|wUe91`XR!bvc_w{!3ci+1;3o; z0=fzwVWwV&-rE=%c8a%dBvJHj5?WXqQsaDfDuWn!C2h4RmcAoT)lNqz6}^50*e@u}O#RPK=d0nMLJiOhegFAP z>(cPzX1!LDB0J#l=(uvs+QV48Tc+He6Ab}GWW*bMb_j$ExMI!iEE=ke{XJKw%kjz% z&WEW}==sXmEXSR8Q~j_B?wk-o;%y-XhZ5giSIOv;8=7WDtU}@@)IBDf&_BUP#818n z!@0JjXtexmSlfHEeBQ*1mxUnhfMX`2@3S^yC|zC1ozdsD0lcuOABryNEGf)RizrM# zh&?dTuyyc}rqtgUAO_j=FHR1B?EXfvx25FXVHL{k;_O9CTC!l$N1|x0S+JFLZCNOV zGH2Dg;CRIa7p*PhMfZshk4)OlW!e!%c^%k)FJe^S)0>$DtPQ!S3y)Q9iC_AQDU%ZwdA_r`ZpYKA7*t!bkQzuNx=@{(K zlLiVSsLTk*bv&$}Xp0Ip#Ci;~YN&T@2KCJ?Y8(|wbUfK@DG0*>QrL0n{ab(MUJNqK z@vRhDig9wo-tNC_%o0xEWxQ)o0M-?XBf)?<+5{||3Qrn%7!k@_xPp2ja7QEylzTB0 zJn|VelLY01LMO13J(D<(=A0gm-OR5R42oCW!aE6g;+!3zf$Lr%rP;oJFb;94x3-jk z`NT3)>CSHvb$~-;AZHBdTp_!TgZ6f)4yw;-+8j=FzmFZ2s{(Ka_9kXv!o;}xOV|cE zMn(slS#Ku&cqy4o$CKJ`M2v**%0Gs-AD{=J?dgfY9aZceMlIuN51{G*SGVL_7=*he z(qF8FQ(|7w&5b$NuR31mK9;XWFRh-3L{28pUOfQt$+h>T;KKN*cX7y+g~F}0>Bl&r zRHiHtReg?;XJgh10!vXmdsvuzskLQw98!Vqp?{UaCVcj+;5Klv7H}JQICS%7O%W=O zUOHtV#(};cGVzaY&<1~j4>aVY5B=!v^$GcObQkvS4v_FS=|#fEBmQ5*HefC&s+<>7 zEcQ$d>gXMRSym(M8dF*ApOT!7YChWJA)gJc8}P%}K5$_xzMq~Gw%>Kf;+=K7<`!;Y*`e|CJ-eh_la=EyDQIs;A6cEt?m%N`^-)MNEklY#XktLG9O^ z?mQYE|(dpr_girCQ{vASO#efY*49LB6EGGyCEsZ4Zm&kdZN!3z4%r(_~9pg2tp_^ zhv5f!;J47UgFy>TV@E`;k~voiQ<`N@tS+f3yKs)%lU#(jL>+!9=2!AZ4=(J_jSERe zqt(cV>h8b91j>mM6M3989n?_r1KhqH2-5x06F{MDj( z#EV~|j|g}Zw_QETqmpS6gxgWO@~`IoJ0Y_MefF5aABX40yOSNFsHi*^XA>V+{J^zV z$J`PAF$0jq+#FiVNk0Ut>7KoZH&K}Bq`D^j4=Lp;ZxwP;PXYO->A4CnaRU&eIj3T9!@oO zRQR7eW6v&`hUu9|^ zs>`vnK#?Q#lMz}q5GE_LHSttbpo19Jw0+NH zN%$^Tp20JpeKQM|Et5Odx@P>&T^6fom?`q_obaQJPQJ10LMATr+GeA1?$R!BS227d zv}kPu_IG`2qq@|@YYPxv=*mDOtE=!ru6D^hcI z_ZjIgN2pWtP~PaB)Ya^oozuZ~AVv8+FFCpPAveKLLP~&3(do!RA3fbJMwAD8trAR;1`*j(&U6khGj619zjS+|C4QWD{12QWUXejJ#ILuNRY9k>s zqj&EHt0$n0$z9}mka287Lt@nEXTJXm8|0FR;;ZWNyWTfj`{8|-FYP%IPv>IK_B&C6{K6tKNAAu<_Q-l^i#R5R z-YfnScH!@8>o8Gq&X>K*xI-H#+l2o>NHMMx1-=NRBqt38Y&$BQe0y8)Rmx||Ar_vV z1g$}i4eodu#f^%tkIEVisGhXN)l>dWdB!1kqD}~O7&|<_ z-68H*^5WwYJ{ddo;eZVqyrqQ>a!HcjDoUJLJgLP;)jFX~;p0?FiO`EX)Av-p-ilLl zbS3mkM2)ccHln3V!$3gGHXT!4;$!uC;qz3%@73cunOlDE4-32h$5?l`M{)>191eP? zq9-?7B=KtvC%fmZv>|Fp)a^wWW!rIY}Rf2z_^Px7f$Hhbou zJs7ik_ZlKZVI!xwX?MKz^`%l+Rn0^sy+riaT9}%ceGxSgNYCuEr)C)^pecEAM_)|7 z1`{F3^o9p1M~z|<!$S7x^C z#2Z@oD@P2r3LJ>4BW^3eI4_HHYH#jyNfp|YA0WNcc=su5Vrl2=`3I^gcd}SrF7xlH zUZyAwP^dX!__IL^Rp6g)$~V@GS_BnL>~m`WaA95LQP$+As09Nj8||qv8I!vMSFq~s z8$RK^Cz~Fco}l4br;zWtA7{Qg#Io-h?I^i4*{Pn5#1z-`TkxBiO1`~&p`LugC4yCB zz>tM(UCw$M7sb0gr(Ny45=uc|Iot*(oM66zAcTi%LN~sN+aRYk#%8RM#Hkr;22TBA z!y5~`v~jm1cBPfFFbF$8DcDW4%oPfhRhO)7NlFdL_fNR8g zeJ`U1P{3+uMf+LB?WnDqMN8~0<;w!TfI0!_iD@?qlLo9b4dq-8w-^_!M}slk=ov6% zith`eKQ=jQ9;P)lYd$}ZYdIq8@RF&Vn>&JG9*)zPa3xkIgHq#CGtQ*o`V_a*>)j{L zxMIw`<6ni>!i4XOfFZQN3!h5Pir~ylri_{)hpv$AW}g>^tvSrzF^L5;+TZs@Ylbzs zeFvW)C|q-MS@wUM{2*mvR}w`1*FQ-~>D*)8w~QI%KP4O0)K9<_JewV8=!lsU)>pkl zz}rXutMSPbtW3$NZmg{qWjR~)zcJhhL=!jVFXO-`-p@#uPr8Z8atM-{Ocfz=nMin}^N^BZ&-KW7nL{?bvfkJ72}0JNlzS+Zf67u*sTy(`}ztmjHm44eE zi;b%8GjP(7_;AlRgt_(b!nXR`N$jy=zqs*|$Xn>I#860omV?3wS zOTYQwOS~OJ!i&wmgok(<7>pkPrVaM_6VEc=ogxs-#`O>CP>Q3vvKH?R2*K5(2JHZ< z`0LrN$!Z6#M4|_Zs4^d(F@MuB#EPuz!@d?q^h}|&KVZ5ri#fK-vt_OfO8ZSKV#@2qs$UIH|3Y7#6xE!$WxKKGQok=4tAKzcJO|!X=Ik)r)f#bD|Mgf2 zE=~a3DS5II-K~YVETJKXI1csX9%G`SnCP&l117)X%=W&@L*37&L7W^(!(zq~VLY1M zL`!keuZ@TvU;Mv6To550r1Zp`TTK)~4DoYrzrw4RsL`-$c^+r(pBJ!xUSMu-xTe+U zHPPcgNlgvbhLtT2*8W#uQ%6-yw3b!QGbujmMll9B$!RS*0!AP;M+>jQ&~Qqq*tX=! z9&dVTU)+XcMTnieP!d_#?+^5Wn=sJQCsKjquqXf+HP(^%a3-`%FAo} z&J)tpt*swD(!O{xC`h04eE*%I@|+yCFyqAfdd!7h?vwi3bqR)!_+26DeV9#`R$19j73SS!$RIkBX*H#BLVwlj5r+Vd6-zNGP??Q4)CSX*8#>|me zrDH7csqvSlf0NpMT4FtdCVAGbg$vAr>1Ci)^P5Fd@=sgAB?YJaB0HmPPLO!Gx$n+s zK29tt&9dI%g_c~$#=~fl*O1iiE}$(SkWQ#OY3@ZYv;$|z`u!~L zjas(#>)&*M!u5!pP8@*XpZ?mOKS~2ad3sWf^TdRikEwLzk9*auZ|u;r73_e z{NroD`d08N6nW;}<>s@`Wj1rMN}m&r_u2Az7y=}Y6+(hv|D#h0e(Y&@E2>#LzxspA zQ8}r#=p+pU{_^Q-`t~j>#CCNsCZfU0Zl0nNk0KZu4O*jZ1+I}?SM22BtVs0z1#E`M zZ4GhNb!=h*W0A(+aya7ZOG*|4nyc#jSc2wUn&~_nK@FV^T0&ge?e0|TUeEL-dR|i> zS&q%UG#^hGCW&_wS-u{rV@poHa+MlxZxy zK)JK+v%n1cMr30{3(P=lu&}UsoPBy?D!;X)gn-VVDh~esy}$0nac`MY8iA_Amd2zyh^aR3GMU*8>FI4YWOhKS%eSX=hIWU0 zDqy&IA8_l97=3287oo`#vl@_2Qif$qf>kwKyxES41DpTb^{SAG9~6>RCBx!U*>qWL z+FLdkCw8$gV<#LxS=U1`UtB`XM`C+$)A+N>STPSS$*%Z-OA{S5S0uzW#FdREG{)l4 zeWAEfRI>yf)rW4)#j&gc7C8A%JLR*0znSeZRwqKE%IA#HJ$lJ2o8aUv&7t*ZyR4D} zCU_DlrT%o?Q;;g%0yV7m+2I_mCDuJ>E>1O%w2|r_>+0@3!~T6_DDh)5OWd#H0<3#a z0|~J)RU2_lkBMpJhM(&*JUv4D+L~#7TTnYF$icxOfh+ZhbW#dhT${@Z0HR6aYpFfAnwvl(G# z;Ip$zx7oJK%F4-+0dhm#m-v+<<@~K=|+xxCO4}+HS7^R{!LN^bzPNzk2ocYjAQh=zV4P z&Hbm&WyuTG0PnZ$wH>g688IYB-T>?TZw5!%wrrtfWaA}sjRI3lhfSX|%$EA1jasY7 znQ{d)8m7X>?KJQp-u$8w(O_T9Mfs6WJ-P;_rU8q)8wg*Yui5nD&91fUQ?49sPT{qB zGxq7xrz1|a(Md31hj6+v#pev+JWBEoTDm7zS4DXD{?$uQuV98Yqmm;Rnt-u9(BquU zurx;44hY`ndYIypFd%9KQS`k{4h|p-0logyM3kos6hevGv+OYZ^saJ~ozK+J+&oKR zq0uQFB0RrfQt>6y8ZGtHpFiBvK7HDA;yMrG%hRBsksmOQvwt8_jjd$%SDGn_olw5? z`tqfVO1Z9I6Euo14bRl=ZOL;5md+yF|IX6NFw)6a^Z?IdYJRla+O&s9v|ZDydp(IK zU$vc6B0;|c;)GHTfHbBW#wszAbRgH;$nNZ%CK!S?33YTpMWCNC-ya(#(~?QF%T7*? z;P38>>GB`0Qzm9msrT**^KFWcB(ZXgwhef*=;~TqZ!>0bzoescQX0uU{_*mtoHffG z;qmdxxUHBp6!=|v4(P5Pq@Kj(-dUOOIX>9was{YbAIwbIWQTTf>z=XaHZRKCB{Z1b zdn#%fW0=38?SgaV{Y`qb_YI;!{bRe;#ee_#kvG@Y6)n&9BM<83bsLh7y}u#8JZ+nl zhE#QxTkm$71b;AEw0gFDWpesnD9fQc-``xQ0 zdQz1$WE_-`=;k3$BIEbheV4>ExU7&Y`tQ!NK)T}Zv7h1L^7gddrwj~0i?O}kzF5hF zeW=BwF~!xKQTg0KLtH$`rMBYkR@lE<&({sMcmP*6XJu63z)8kQ^Mz-x+0V9pd-a^F zpYrjc|MTh+b4I2$xX_7O?dL`vMfN@d=`#ql#%WB&B4!SUhkzSkz!5qzG8mh9c0?>El$9Md1edu=3eG-gSZ@G}#YjQ5 zwD%uBLuB}lPsN1qmyq#k_qL0lC7gPzc9{Py6#^+^G#H^~RK0lvbA{*izC7IA|TcuGGn*fbeAFzEAp(bW4j z<;xp#ZE}jUL3H5L!}7(xw;au06XV2hnXM(Nn~B0ZlWYtAc7WbUPo;63NkK;8OUiA{ z$m+97j|dsm{IN4F?(eV1?*pnMa&mH-9mdA+om5(wot-7bDuc&8wWj-GhPKg1JM9bO zqval5DCA{^Lx+Plm|UM#2EZ?;08oQ1dEI|9xGWszK&v&c7glTLw;q7 zS+-#t*#79Mb-@AGmTl5r^p_+BhWhnM^R=VfVSsz|k5qGroRU zwm+=NA$}tLyJ`DIjTTIyh)*YJYw9^XJqssi3Q~9I1_FYz>pOFS;oAIqm*e*H=XO z7%tjbC4u!Wr#w1}E-O1JhTOR92L-a$Rw*e)e_dhWv=_JaoJBIDIFoZ>E8E;GD=Xph%(G`=TD-jj z1!r5cH#rqt_Dg3R&hPb7I{{HGCDqwvt%(hJQYF1cQk#m9qaLIQUX+iC5hCQBY00vE zZdA0zb+j`tZ{0RpQj+vhP>_sto%#DzFZgKe24!AuR$xPEzGy>7Hc`x0925JubE{bZ#Jz#xUN8Wz9=kChlK>VeYP=kW$$k6RK4%Dei zwG0m=Cm@y<7CON{65L9Ed!|o0yR@G5bd2Qmo&6c>K40rdt2!*8V)!u{rm4LqG&^9p zV%W%o2JgAZTZ($IE_at^Hx42FnniHgAz<|q!aHqmd%T979K%dg&+i#HUH?Ti>0flC zt$_#8=_-#X;~Cj=5%D#E^OpYURa@}q&sRBOWQl5*rYE>olY*A#fXBDU5A+br9L+$Q zOKoT1%&P`kU#&-J{v{9X{^N~?&&}l^Lwyz8-3ozzU(AYAY*t{HyoiV( z`Xm15Gka!o-N35GSF}cm^|v~d3?*~ zq+qU0%Is>ZEc!14a$?aXkJgt*H##j$qq;8~M)73%Y3}RJ?mM2pLgoE8iDyvRtjH#2 zZy&a0B@}>1jNyrHnmp6$*;NKl@ayxslNkax@42^s?_-IGj8On+%%6(|wj)ou-l3Y8 zt;lO0XnX5Nez!_U{O>gHbAp-$wZ6}c^ae*464v6dqFGFr-EvVST^Q)g7<+kG%daGl z{Xt;{j*b|rzc4<9T65Ndfnl@un@?|}w6-FLmbvStbO$O%qNBY+DZNxlRlmB&Fmog~ z7Xg^41Ss#yookUNobC!5a{`*xMx}q_#CuS$*aOAIuZhsuFI*?A6*N2c_9`*Mr>CMT zh?Hp|pck*YPEe4ag_YGAodqu)N%zfbGfwzaYwo3*F6eKO0cqKYMMhXyw&29XOVD|0 z8WFs$&Hzo5xnG@3>xtQrR7!X`^Pj}sk&ROQ`ans$coh`4#P+ut`G#WN$d4VIO4BMAEjWs9g&K%D_- zU?*ps>Z_n7Ax8oM>Rq@Mz1#^!NOB7!R7wS0`SHmLef1ETCx5v(XQ)F*@eLOlhEG;c9A>7uji|QLbqqI*HW+Uv{b*_zN-8SHPUE>_`M{9x0i^^TB zi;G8|U15<>X!tocPMjV=KozD<$!YL&Mvi-z*v-3}b^_3j7QZhtf>)efHX6-II=_%t zQM`=OowAb9;)x^G%1><6e~J>G?_5o%*2ZK+-yr0AB+{K?H3RG8VjS7kE-o$sG&OkN z-@%TB>l+D4d3$756Q=*njq5>WJRxWvlJbgs_OE5-vi>6Rl{n&OZ7#-5vYZICZ)P@D zB`_)0gvzUU9coCh9&%2q5jiB~S31tjVn;EaKM6|M1fP=?sEAxpWZ7Q!Z1(Z5GlYNIYyJ_Ad_4-w zuhZ_gqzM-fHEQ3_pL~4ak%2@3FsLA|?`O&3B3jEB(%$FHksiP8!}n{=zHG0!2Nj@t zQM7L0CoRu=`rDt1jfsJRko)gF6Ep{9vEdK5N-rZ2RPU{heC^i>pt@@zMCFdA(#ypc z8CeAmKF#?pEKl`7q30$aEyu$mx|%gkGd?aZcC|{pgTwMN%%0Ej&?cN8&H~Qna28{F zglEISgMgu~3_Ep_1u~wXrN15885X9dkPo5t19dv)^YV}gtYV5DZcNI^kv_vCKt z=I_sIqkit|b5Uv=VQjht$nQ1}63ljN~FzpQHpeut;KGMc8Se`F=?@2N+)Wuf4e@l3WbhX4D)bb`q zs(NrLyH7|I<#ctNQEMyx<$DzqM{0`ClTT7qE7a0v3~hv9p6l_aL2)jRVQrvQz(`kh zkL*2)pJ9wQT6|86_C2|Ktw?K;4?N%HCBUHkU{gm>;R54_N&VN%W9Mx;j-0U8A(G6Um z9#4%Tu*I^EytJag0KxBNfz{R82BBQ{hTz6(De@mS)(V)Ny#Rl-t<9a|IuGa^K}(WQ z+|jTG{@=;|qp`Gq-qaVTk^Jk|nsRay#$TM!wt4*ct9xzqp}X(i2mkHpaL=HgD{#=j z$}A7oOYHnyTkFR5?)@fSNPi0VA0Ux}&t#htzedYRNu8=EoSaNIpPOU+?a;dyr^a?? z)4mJ8ptAY#Bb{GX`O-kW#%0>_5_PO^WMp)7gaFy-rqosA1PjPpPTHR9|jcU zTaLLPW?w(K7RFTGOsipz_GaK|9G&zWhaqPZnT@R^oIv?SZVYSow8+CC+Wyn@JCyDE zPJom9Ao*qj!{-*y8th148#%?!iW;GH^-CdV1%eT>SGBp9vW~I$J1pVcQ{Q+05fQ8X zISq>dGZiex0}30f{Sp#$u6)|G4}~Srpj>z*d5Z*@u6z5TFyp6*m#}pfJtPkJ3E$6Z zJ0;OsJwZMP1~O*%2bm3IbU-y1+-LENWpQWH&fPpLPPM z;&2RpeeN~z-6|=mdttOCha+gN54vY?lopJ(I4XOvA9)tPZ_OsO$RK4t^A{8n&T`7y z&;K~HGJ`OhEiXYYPUieX%Ew=x#Ja~LU5Ssm9y~}x48DLm&7be38-Z56Fx^qy{K}^| zn3~bpXcW%^dR&8_V?EeIZ*SdFbg`LObOCCoAly2|_JGla zi@&a^txQf36cmc>+4j??dUMLN9ZG$7nb#F&Hf;MsCUzq?u1 zNE~8RV9OE{!4D#F$iK>yYm;1T9JqtUGo@;8hwiXuBU6Q!mQucpp1KFHPj#b=w z5XlmzjzBb3RVAhYFmK3I1`>loN^-b&AcHnqs}LhQHzWfg6QqB+I$9n_J0QayuB|p* zD0cmdb~1cY}VG&hMp^NbCHM&l< zo(ElF9xIRBPN&lUCfmjhql@rii{J}&g>3KJf`MqOIC_ml?@LxO2)AK^P=Ok{G#wHbslhtOP+#5Cu_l*t`b)3l~EP zGFjz&!x~|w%uAz05^Z5LapzA+A{5H33f!0c8MU<_Oa%wBs_)LNB&%14*kq-oLPDgZ z=w>x%VJ?B1_vwxe=L^AcT|AP%meP;`%?bI7#q=h`EI9Jo0mxOH^M{2qX(-m=+kiR?m(Yg#!-$r0MeB)c% z`zP!PYeuz7R>p#od|k&If2ICEQ*Q$<_sgM+cKI1BX-9-yD||%6wy4?<8Xa(?JJ?^4 zx=UdNDZ=vQsi6!Qt1cci`<4UB*lr<0{K;e}J1wGIjrGuhMkD9oLwCV_wF%~0A!u{6 zd$M8XPirx}o@+SAXE^3(%KINXl+scpJv?5C%#OW(_>iHUgsjNf9+7U&Zg4i!;Un}8 zz`-?^#P!%&en*A?Y@$pvtHJXRqFFRG$=zz6&Z7>^5$06k>d99&REd6(Ro1e!m>4K* zu?-GwX|6FLmx6-n_ZQ~dkXw%^JNqt@mX}Yys%G`Qyf6m^{-B`En?Wlt-Q3z*M1)Q~ zec^?_rbWiQo$FWj^TojWFo5kRuJi|nz=MFrL@kIA`%j_zF*)oI#G6C!1m@{_)k6)7 zb#{T&Vm}j8u0FAV#$71_XI`9?TH+e^z4qRO3+AQQ6@R%%rK#mKh4KySFvcCXP={~ZMzW8h@? z&A)N=_mSb2m5J5iktpwt#LAW)`p$pq_;H&&Li^u8e==pE)+>EPSX1=P-=adV@>!Pi z#ru3hZxR+4H|z}!WoiHW;RA`o+fe7Zc{A6eBl0o+nr6h5{-TH>P?dT2u0&lz@&n>N zGs6KRo}pQcHWS>~JiR6-CMKy+H8-aoOi<@^J}E7I(wR^f3p|EQk)5uM4|gri69Kc6 zpm9cUEDTXcnT#xeHGmm(B?PN1vhb@`%Gyi4huz%#)yDq3GS=98ZbSEoeR+_{THp%- zA;6a7PnVZWqulJC`uL@j?ED-&Za() zm13Z&pP3v_jx19Oa=9euPM-HBe6l?aLvkQ{4ZF(xUimNKs`z=6U5S{?v#ME+W7V=8 zkb_`i(fq)J0OA2LWgIdwG06ntWuIL%lILqyGi%Mmr<@Re|E4Q$mPU>JH0})kiCQRr z-WIlijkfr`t;1~0u9{KG%1Zs%jG6#K6JPAEY>8RE>>x}|0scYlM=&@y*<6l2aXSaX zG&aXDR`12+hhUb@9K@*C5Z!NNxrZ`9{YRR7#A=c7UieDJtfe^WuGEOp%b>(Q-;xW%(& zQj?#e0Ve;O@d^+in>z{OWz>vcJ;6WULt&LC_K)g68P(pM0{hF>o z%L3l0!b!=~I3M%dz*X5C??!$lO-%%93}uU+IGMUpOXws9Q#|X$93MG5Vn~pZI}yTa z#-E~3kY139>6@ni5XU2c?lJMZF8_^@x?1?v09e{mzgJMAuvqVrE^zwXGqE{>F;qxd7ElKYVLUD!-mQGX60_ z>b4*ep2_K*Kq3g{X#CZ3d9UM)3 z#QAS%>c^R`0MfOPxmjPobk*mwf~EG&(QD7Eg+T||%JK*lyd~<7n;xADy=_~7xPM_G zOpj`v*VdAkkx@|C#<7amLf`=#8#&FhFb)s^t5%tKnSvZ`jAPld+SvSXV&LnGS@h2l zT)SV1fcHD95hS{bbA0?oTd*TSO(eBAwBn!>GuH{E4`n1i!8>!!7?b!C(V)*qrLU?R!6r1;u z_tF#$XIQNeFxC9)BctN(u3gHVt5if|mA6T=$j8uWHTCti`vNyWNNq5`d|5&g8YPGB z(#FmU98nb|uYK7{IU4!?N&m%&u@A>hz4TholB-O28$*}p@xB`P4-_6TlnKs-^!DYS z8}=mHzFsd>+yVH9WZg(&+J6Bt zx8$?r4^aX1V815PpcB~_g)Ezo#;EltL`A5oT3a*jZ&g)oZDpJ*xGU-h^(j=?b7hRQ zR?PiH+JJ=4eaf43i$J82{JGDpa-Zy{hK4Tj!$$Qr&?nol*DOna6R&`?!1}bB*Dzrk zkeTb>EYFK+pbBwD)j_}j8MslB9hL8&@+$J1zmP#$w?uFRtMP=_p~E3fc-6;dZdq6+ zm+92A52CHV`Uv6zj(4*c5x@d5PK1@69=h7~h16T%XF#~y#Vc!1XAk9ABL;wCrzF#@ z&5twbZ+_Wb$W|d3sr)qM3|9HDnU`@MhVz!)vm|qhNdI2z2QGqJ;E4*Wtg^D9muQ;_Mkgf1 zeC721-T36a57I(RO*I;Lu!Gh-KiN=xDPwEqH#$omG~eA9r!2KMa5)4{Q7!EQ_vX4r z(sR}Pn||lDQl9EWa<1ax;okEI`t)(4Q>$X@+@Ydw7k2E99pKaf zNkOsU$~yyUxKQGm`738z@qsWkoWb=1l6jN^NpN%&2se~)i91tcwOMcAkj;3tA_f5d zyV$ZDkD`YSo`;ePdi~RzB9aWQfMSLJ{knIOIJC@7b-E}_P z>7B4$wb_;JJw11_x_X25UHWmh^fC#GU0wr!I~eux(4uZ7LHKj=&oxe3!6j2uH*$FN zx0LF!pW6H1-P^>;sU52%XX8CcP@n!Dr)sRlV}}GGc^)=x+fL--82uQD03W!tP#tt}1+^2Wv#cy-l!XEHb|rD9Ee^37xvw z=JxZBL4~gCKxo)t=WSg!Z9zlV^fn%do#*{81CRkyDHg193n04L*);7+x4p3=7o8eY zgdF3P*8pMM1}WV{PghW``{Rd$ErYq1yD&Fl7FVn!m?rx)3k_2 zmPAZ;@T2H5`A|123C@#!3uuh72#VZ^s96{=}4lc(j|73Mh|vl~S@wf-ml z5hqGbmk6dZ({M>F5QD-qYSi4f`VX(^6Z(&d^%MU}qYF8|a`ZcL?I>*lB&7a&sEZjR zX|K7PER|Y571Go8SA2)*amh7jzZpV{A-C0=v3cMX>qf8s#mU454UTIeAt8HD6V(5i zpiv4O*$>|!|mlHR@b0`Zzz)0S-KmY3hY zh0zi4=9U)wJDl8|>ke}gHYyR&AK2N6_Uqd{i{tA7ebnZmyo_9)*(64N^qRPsknl+| zazD%OyK7g4AKD&TW58;y9i5#v%X#J}a-fLour1r&E1@)5*=~+4zfzMgP=9Q3+Id`J z6?^zKZ+?EW?Z15#`xbg;{V(3Q3uB48mzQ?$8;RRJs=BVQzjMIv-X?(Y$daQdh0ULx zlwbmGSs9VY=(v>8EFb`K=K$ZXkzwQ>GmI(w$G?_8`Rnf~?ZDDJhq}5(vP_g2a?Z+k z_QeTTSDK9+Rdz>|P1Ye2!7TN0qQznjwRDCp-Pyhn9W?!iB)2egtEUrJ zvCGcRD{`1lyiM#!mhGjn*e`iHm?*&4F(E6M&Sq(inuv)#YCJdzxpoFo@Oq=#F3S6` zLTlzO0U-{PH7_lu8sZE4`;3i8&P)#%sMud+8~x@^(D&^YTtkTxZT zv)k#Nk7!;4(7Am@R4&+k3ecV*``!Asjfj|#Q)iGl7gN&{TXX$=Mmsw@8BY%Q2f|2- z$jC%wT6U}_EIqvoS#!4S;vhs`@SCqr!MK4;`^&RqYqS7#xb@KDZ)0s89S4VFn~}9* ze+Ps%aDhVB&;9Q5p9^xHKaUYIv5R~3=swY|WP4pianHTapWQoBxTN^L6Sa^1?5h=0 zU@=JDQ>*Xxo?~#zChIE6#L5cop0)c}1}ugOXxo7-tiXDLt}dLk8eGD60~abj9Nt}; zVsXXn%>LWDpOz!YnJHu`!p=u2t%$>~RVk0t$Hu_L|DU?91Dfjp{olc*?4o6+l&-6g zm8?o+Wpq(ww2)0^;d7-$k;*6yqm&U^C?l5=h3q}EM-m~s-}Cugb-w3+&i{E%b)3^J zKI8p>4CS?L<_qU7{I$(O=B*ItTV zXY4YqTb9@9Xygb==Y1*KH-DlTeGJP-eVp7-=i~UpM$eLu1TLgYeg^HUp1F6HEoM3` zYA%R1lS!h7PFmE(b)Z;M=MaQ)h*Z7VuZ51Z>?W@UoERtaqmd)|c|`?f2j0Q4t`-hm zUcGwqB$BuLN8W+`xjrnKVWHRgm3WW76y4kAz?|)(e|UL-pYE_UQJN^)eR=)+CGRSs z_)}VTc8__0!qa4BQ7EM7DK6IkaTWcvlE+pFHt5;BygZp?cJDe~_8IS#J%1kHCF2G9 z_p_ae`T0tS=g%3E>MXQL(@jAM2YP!*T%@m$3fwlU371t+$Yk+|i~O%Qa(~lTr=_J` zWr?_-W+*H7d0%bCz1MbXzXiD0EBO8__)W0P`}9%cAilShOQ87~m!YZm#L2Te3@tnA zsmE4{^BN1>ywuA;ycPJrzZ=QgG*6+=Yh3*T*l3SgJGBkC!e@`L@YIZ-M$Uhj zx-uN5W^=&0o6R3D&P9gwuyi$(%o=$WCwIo$UF;$|kN;ggbUY=ipqoCzPTFCZnwbe= zkoYT{VK+Q|pl`PBN*1^I-n=kA-pB#Bq2&5t1s;@Ck!8CPYWMK7^_05`T*=81sW$`! z2!zDP_~3+>H4enF+EJ|>$A@y^F>5}`I#}{xmAIC?|oN7TMie$y#HI-ywrEcmh+V!)}J(dGrxNS zJ1KZy#)CCTl)Gnu#^qbp#%ZcGYYdq*3$yo^tJ2rtkLngh2dI0eHwLZj^*J)I*J~8s z8lyqt;_qcZE|)qt%|D&iAH7fGkZ*olkwf9pdsF|adU-DT#~*){<*B!JT|<{|Q+_TehIG?+iuCz8a}caB-mn$#1#=`stb)9-dpbz%3*$FxN{$%Fm-P z(8#E^V(a?#fCGQ*evWwi_G-49!Yn;KFz;<(V_jvGHho@1t*hir${6~h=(<$fmYer?(`D3`Z5*SdnPNjVH1aq z%pN6&EcG*Iyu9=|;ti7<$b7Jl`}rL^R+~?`yg&6L;7MpBBd=uCQz9G16n+<9F5W*Z zx0*TLR9EuP6S<|TX=YrKajxrYZ9bq;EX?{|fU|RB3Hp^Q1GcX>Dtc2S$0|13d@Ba# zn*qx@%515cX(q`(APMoBn7lnR0q#OE(BE^fsYS=>9^CysXb=?lXyflD|Ku&&qOB3( znSRW?$4~m#uzC8_cZqu$a=kj-ZEN@4vG2%XjK9kEMJc+}tTxPFHs>?@KX>h92;?f8 zy=Nik;I7G6LvqvAkO_muJEQ*P)>?%!$!qvj3bTtxst_URlYNIo)C!Y_ikayj4m<-- zLf7|jKtE&zW$fN@_SFQCPRtws`T!47$vSCP1y8;_OBD6-v9lA|y<2)>VLWM_FPRTu z3J0#VpW})*PHCw9PH|tXbv{4;NClvIr#^vl?s-`tEFd9k;p-nij2-j#1%tgp%i7tI zG+{(fpV_u@)9!&9EjSBYvnJa$h9CcOAKrxOF(@cpp@7GQf54S+f zPpBstraW0quAv&9Z*+&ii zvO9N%htrH(UJu6aqtzU>j*Db^ZY9WfMwWoU$&Tf*Rr%A66TP;(#9e_Qc({mg75ZkHrXU6hYtxE9)5Nh z9~Ct{ZDIl_fE_!oa_I&|l!!W;r7+D;P5k^h%{(&l1vc#<_g*1in<;zxX_fj-Ne8HrZ=BQka6LUg^0>GsI7LhZ@WzJ3Ay4D}+q_JcpcSrYun3GwW^&(@8QV!U)l^=~>(t$pxstZ|&dA zd~{RT8|3=IR#(j{^|b~`w>wY0)-Ij?BJpcLW%;e=1M_sx2eo^%%nO8Y^$sr+Ng&-r zSw}xj-c{(qJUi1C8F{LdCLE~fC!;3(*8g2@?n@qE-3{0NS+censb^+uOefyZO!0!M zBdc#MzA5n_9FE5_Z50bx7|XCk=wKW2EAGM!?!<|XJgtLxD5oJjq^8H??i5iMN<>x| z)3m5iTfxb-xf7=s@>Ju<${>2Gn-8}`%$cT*|_2*r^T4&v&kfqVfS0FxV z(w*ct?6hK9T(Y#>WyLf#Possdrk9iyeJkUMe@@vxSg|qXpw+1@-Q&W%ePbLTtJvYg zCB&|w^?Uf-;6qx2gN&R!LEgf|;1rwQq^Kc4WssC8|evocV#&PL;w8F(R6?a`aaF1*3 zWjFOhS2cQQ<;nF-I|&F|Pf3IBRfzKDE{FJ_r+hxH{AVFo*{IE&Qp52(y_k5@?qZ&L zcYaRkrQ`HqHySu!KR=jq5cKs?Yz3yUeNt2k74&|r`56x`&>HF|g_X13STAfmb`b@T z%L17b=$yN{#~}u{yZV$x6b1M8WT-Aji${fr8>`zPvh#EJZFR_>#hFr9wLIMf!?ZsZ z@lEYcGO&g$`Bc*z-BS($(m1spX*4tc7dJn1nx7zg;$&6~e{185KwIJ297 zK2t0Cq^W_k%+u5W|E}2uSXYzS;%g4Q&V1hZ^y&P0fF#@$EH5YeW07Iy1Fa;2wv&l% z%zz?sIOl)`ZvFa{hUUtrvxXB1JqPGB7sr^}*c8SUDO^W|UMSP}<$r~?DlFi1seN!- zZCg3gK(}6&K@S~Z!kSsQJaAtfwC3Pkh-Q`9v{&)CVB~Sv>+kM&+|Ed%jhYw5h^XeU z&a`)+&1w)0hfFMAyY@)MqBCPDfaivGgE=u_Yx6sap`AlvoiyirkQ;3zv!cy)T|4K+ z6D|QqAO})G@lI&qEmn1n{#wUOqy)JAL{MG;J!BOYc0nbFdLYHaDK>aE1@5TwX5b+l zkk=6zCf~eXH=AXzRPa2vF8ztKgo_p%%T9s{=bUEJm#-vFK^?R~ici&X$Z9aBNJnqb zWv97sxav+zJZ_XBUO1P-kOa>^JQUNCGtaMxxY22OVD-w z<6cf(nizczPPXFg-MZ>%LV|MNX0Gb}Y?8ay=aOpne?=XU?U@jH=kp6=a*lwnhe>Nz z6D_mwFl``K< z5g09ego$V?yV3Bsq2~H0b@+e7-%a3_Zb%=! z8hDR2Iv;Svun2$}0_9l#hU(ES|GFBU=7NQ^%;o7_Hf0fTHhKdGgQfljn2RpCNGOqdRY0iiD+a5Ix1sqi$4!|Oy1gpu4|*y9wqC7|8fLG2`C5O zaWP?T`0DU;G$?1i!_p*xqzFOzL+dcTw$476YMHt-Ybia)FAS1{)^azjB^}AJ)(sac zy-lotEHsV#x=X2WXi=1*IKpCRa0IgVcS8D_qFc%Sq3H7)O6Ux{(EkPW@q2oc+S=Qn zKfl4Qo@7i;G7Z`kc9`XEB^tHaPVyq#24HUSmI%I1vlDB#_l-v_N&a2BIv&CITf<=| zyD1FO+`_#U4ZuU90dfXt&~ngF;O0eRtC>eTMXf5H{D#+jbz9eY3sW?SVIp%j^9p$Zwm7#>02b8qVNN_<-!f(F&NLs)>k5af^$i!n;H& zIZP8tB2dX`CP@S*dFV1DWZ;<>k$Ghh2WPAwL;Ct2YaKKC_gtWdqMjcB;RgYGFd81* zVi!{$pdrvb3$SJAjR`1ti-^RCPNk}B9 zr?TY!bp;}xRUKEj&N-Sj8Lo=vWBdaY6fLfwF{|jt&iwR5t(zGt{Xj{1&aoo<`?iIgxxk*oL|6p9B5+h7#xnBD%(Pjl1NI5*{K~A zW6GBQyYtUdSFRV$G_7urBJQS|s^4Utf$qMj;NatXc3hN}W((itXe@EIHl)DK$tyi2V09pv=KLAP3mocA7!dCKQfZxHn!9N) z1&8Fl|LznIj5FYz zalT>52yyu#h0~^Q1SqIYnFR4`Vc_!gugsi3zfNM+@2^bQ1q8E2-X+Cg2NSWQt1+&-f?|Z-fAr7{yxGb>kx6=eELK`9<1vy+tN23L z#GjV7%bN7a_hei48(HB0etqcZ7=+=LRLtiCuU;)LT5qxVZ?&;PSq};i(0z?vUGE0< zm=R3tVP5YKs=o-J-V2l+QyH>l=x6~>m&8O=&=9O1ojzXx7l`RdB40OZp(~&$!eUbB zuaz>A*32k;`xg&H^*13(im1Fcx8q;mIy;!+;=H`aj0<{IaMQm zD|sWjm86ppOtdWVNi^c+MbGI1ZbDiNuPlGqCg5;*NZXUv^Zp6+?tLU_ZWqhg4PA|10IOa>%=Ma_Y*v&x_E zb9RBd{+74bTDt#t=XZj9|{Sp^gWVV86s?PIEFDqTzjqolS%r)Zy9c8Z;3+Bln?toAk^2P zIa}~omQghKVT#rKs+fz{GGZ(uAh{#rq9BY(D!`Pev%@GhDmJD5etc` zj1h)1Qs27MJ-#2)?X^wOj>}TAs@P%I$BJYC62W=DUIwCf0eHckeuEDi(<0~R)TCCW zGMNy%jm9836vMnXjmgG#@iR6r_?^Hjf8XBrpvKffpV%NI@pVjOyFiB@M}dHYcq=l+LN@jz-a&~ zf1=z*#!k=&MwUXqfT#t!U3N1NZO(b4k{9z$(okJG9hab4h7arRN%oA!r}q;e@t&I+ z&mMht;`u-EMbX4GR85Y509}PSzvBmX#^%}o5JlcicOBqTnW{d(g~u?`S)*A*2_9-l z_aP?fL{S~8GCUM}z#K6Cow4xU5rj#@t7X(}S33i$}NF7cm@@ig`vLT zVx=x-s~x~FACvz3mM}b5&W~2zu0<-VA#o4XJeRBI4$#pxLDTB$zq{et`=UgcCuOpFy4gjY^E;E;83Qvj^!FYD*UG_Xf}*(#)O-|VshDqwZ2N7a!>$TMGt&jEUCYbsGaxz_Zx{oB77L=w-HRthTk2t=SWv^cI63mA{`^hFmc zdQ};E&1Jh^Mq_?oll%(0I((_CO)e8+wd8I(2!VtByBUu$=Al6}e=7Z3nG>_MD#b(+ zXUL5zjfhI4;Osoch;m%9JjSh9QiHG(1nX>D*YZqG;gY^f%5N>6^aX5Gq`JVq;&K-R zqADFz_F(%X>awQxPwCj^B)$e`kUWZ$8aY5Ytnm-3@GC2O1hxp`{eKpr=Qly^#?{!8J=fZHe8s zymDbK#XV@O7-YOu)^z}>T(BL-GrW0bqjNHUq(QQY=b?%FVt6K5hSx2>ZNjBA4<93f zrm5=R1%sz%>^fS$&8!HSzFVVn_h;*+rfvBMiQ?;6WWm;XJ9wKBJ}H?>C6n<1DetM) zt2dC)#EnFudED&pWfV<}hS`bey!OF!kh=|yOd&~^W-mj!TmD<$uPxg{@$#QYHbEEG z|3rN(+z$}F{1-;pSo%MIBRv$p>HkC)>Im_ls83xMRx~XssHtrGgTvv(JP#iAJbl9R zjM6EOGw=saMoLCTQc6xzN}eh$qa-7vBr7i=C8H!I^*H?UQ^p4*RzBhEdit!b-~a!K O+B%g@F&i!Ml>Y&OOLdk2 diff --git a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.tex b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.tex index 66b52f7f69..a9f12fe3df 100644 --- a/doc/testbenches_doc_resources/5g-nsa-faraday-bench.tex +++ b/doc/testbenches_doc_resources/5g-nsa-faraday-bench.tex @@ -30,7 +30,7 @@ \draw (obelix) -- (b210o); \node[above right=0.35cm of faraday.south west] (antn) {\includegraphics[width=0.3cm]{antenna}}; - \draw (b210n) -| node [pos=0.2, duplexer] {B78} (antn); + \draw (b210n) -| node [pos=0.2, duplexer] {n78} (antn); \node[left=5cm of faraday, label=above:porcepix] (porcepix) {\includegraphics[width=1.2cm]{server}}; diff --git a/doc/testbenches_doc_resources/5g-ota-bench.pdf b/doc/testbenches_doc_resources/5g-ota-bench.pdf index e4d4c15e394ad4664d6eea6580db9952d8d7e341..121969030e64e03ac0e4fedc9ba4fc1c692de71c 100644 GIT binary patch delta 9332 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 delta 9435 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%0Df-%sBKKHZvL8?Bum$h#?LEP24qI0hr%B-N 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⁣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 literal 90027 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%0D%sqj=-Kn=?=3kz@z+nwCt^ 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

vh4ehB$&?ymC@{5J~(+oo1-;TWB{07$j*UR>Bk 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 Date: Tue, 5 Jul 2022 17:17:40 +0100 Subject: [PATCH 31/61] To use some casts to c16_t --- openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c | 4 ++-- .../PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 1793a76fe1..935798334f 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -75,8 +75,8 @@ int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, for (int i = 0; i < frame_parms->ofdm_symbol_size; i++) { int temp = 0; for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { - int Re = ((int16_t*)srs_estimated_channel_time[aa])[(i<<1)]; - int Im = ((int16_t*)srs_estimated_channel_time[aa])[1+(i<<1)]; + int Re = ((c16_t*)srs_estimated_channel_time[aa])[i].r; + int Im = ((c16_t*)srs_estimated_channel_time[aa])[i].i; temp += (Re*Re/2) + (Im*Im/2); } if (temp > max_val) { diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 080b9b65d5..00b053e3ff 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -999,11 +999,11 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { - int16_t generated_real = srs_generated_signal[nr_srs_info->sc_list[sc_idx]] & 0xFFFF; - int16_t generated_imag = (srs_generated_signal[nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF; + int16_t generated_real = ((c16_t*)srs_generated_signal)[nr_srs_info->sc_list[sc_idx]].r; + int16_t generated_imag = ((c16_t*)srs_generated_signal)[nr_srs_info->sc_list[sc_idx]].i; - int16_t received_real = srs_received_signal[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF; - int16_t received_imag = (srs_received_signal[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF; + int16_t received_real = ((c16_t*)srs_received_signal[ant])[nr_srs_info->sc_list[sc_idx]].r; + int16_t received_imag = ((c16_t*)srs_received_signal[ant])[nr_srs_info->sc_list[sc_idx]].i; // We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the generated_real and generated_imag. // So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 bits. @@ -1074,10 +1074,10 @@ int nr_srs_channel_estimation(const PHY_VARS_gNB *gNB, // Compute noise for(int sc_idx = 0; sc_idx < nr_srs_info->sc_list_length; sc_idx++) { - ch_real[ant*nr_srs_info->sc_list_length + sc_idx] = (int16_t)(srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF); - ch_imag[ant*nr_srs_info->sc_list_length + sc_idx] = (int16_t)((srs_estimated_channel_freq[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF); - noise_real[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)(srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]] & 0xFFFF) - ch_real[ant*nr_srs_info->sc_list_length + sc_idx]); - noise_imag[ant*nr_srs_info->sc_list_length + sc_idx] = abs((int16_t)((srs_ls_estimated_channel[ant][nr_srs_info->sc_list[sc_idx]] >> 16) & 0xFFFF) - ch_imag[ant*nr_srs_info->sc_list_length + sc_idx]); + ch_real[ant*nr_srs_info->sc_list_length + sc_idx] = ((c16_t*)srs_estimated_channel_freq[ant])[nr_srs_info->sc_list[sc_idx]].r; + ch_imag[ant*nr_srs_info->sc_list_length + sc_idx] = ((c16_t*)srs_estimated_channel_freq[ant])[nr_srs_info->sc_list[sc_idx]].i; + noise_real[ant*nr_srs_info->sc_list_length + sc_idx] = abs(((c16_t*)srs_ls_estimated_channel[ant])[nr_srs_info->sc_list[sc_idx]].r - ch_real[ant*nr_srs_info->sc_list_length + sc_idx]); + noise_imag[ant*nr_srs_info->sc_list_length + sc_idx] = abs(((c16_t*)srs_ls_estimated_channel[ant])[nr_srs_info->sc_list[sc_idx]].i - ch_imag[ant*nr_srs_info->sc_list_length + sc_idx]); } // Convert to time domain From d68f7d6270df9806cc833fc98d45b5db693433ce Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Tue, 5 Jul 2022 17:50:58 +0100 Subject: [PATCH 32/61] Add help string --- openair2/GNB_APP/MACRLC_nr_paramdef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index 22b83f4064..4359cb0c86 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -97,7 +97,7 @@ {CONFIG_STRING_MACRLC_ULSCH_MAX_FRAME_INACTIVITY, NULL, 0, uptr:NULL, defintval:10, TYPE_UINT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:200, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHTARGETSNRX10, NULL, 0, iptr:NULL, defintval:150, TYPE_INT, 0}, \ -{CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ +{CONFIG_STRING_MACRLC_UL_PRBBLACK_SNR_THRESHOLD, "SNR threshold to decide whether a PRB will be blacklisted or not", 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUSCHFAILURETHRES, NULL, 0, iptr:NULL, defintval:10, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_DL_BLER_TARGET_UPPER, "Upper threshold of BLER to decrease DL MCS", 0, dblptr:NULL, defdblval:0.15, TYPE_DOUBLE, 0}, \ From 24745eafca450f4f7fde10b2bf8986ab883a4a89 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 6 Jul 2022 08:45:48 +0100 Subject: [PATCH 33/61] Rename variable from phy_procedures_errors to pusch_DTX --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1428987d40..8e1f2bbd4c 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -625,7 +625,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { /* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */ int pucch_decode_done = 0; int pusch_decode_done = 0; - int phy_procedures_errors = 0; + int pusch_DTX = 0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,1); LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx); @@ -765,7 +765,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { if (no_sig) { LOG_D(PHY, "PUSCH not detected in frame %d, slot %d\n", frame_rx, slot_rx); nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); - phy_procedures_errors++; + pusch_DTX++; continue; } gNB->pusch_vars[ULSCH_id]->ulsch_power_tot=0; @@ -790,7 +790,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { /* in case of phy_test mode, we still want to decode to measure execution time. Therefore, we don't yet call nr_fill_indication, it will be called later */ nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1); - phy_procedures_errors++; + pusch_DTX++; continue; } } else { @@ -858,5 +858,5 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,0); - return phy_procedures_errors; + return pusch_DTX; } From 79586c03f401d9d874678856e16f9dfb640eacfc Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 5 Jul 2022 14:16:06 +0200 Subject: [PATCH 34/61] fix for pointa and ssboffset --- openair1/PHY/NR_TRANSPORT/nr_pbch.c | 6 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 7 +- openair1/SIMULATION/NR_PHY/pbchsim.c | 6 +- openair2/LAYER2/NR_MAC_gNB/config.c | 24 +++---- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 68 ++++--------------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + openair2/RRC/NR/MESSAGES/asn1_msg.c | 14 ++-- 8 files changed, 44 insertions(+), 84 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_TRANSPORT/nr_pbch.c index fc7df46496..278c2dfd58 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_pbch.c @@ -35,6 +35,7 @@ #include "PHY/NR_TRANSPORT/nr_transport_proto.h" #include "PHY/LTE_REFSIG/lte_refsig.h" #include "PHY/sse_intrin.h" +#include "executables/softmodem-common.h" //#define DEBUG_PBCH //#define DEBUG_PBCH_ENCODING @@ -248,6 +249,9 @@ int nr_generate_pbch(nfapi_nr_dl_tti_ssb_pdu *ssb_pdu, for (int i=0; ipbch_a |= ((pbch_pdu[i>>3]>>(7-(i&7)))&1)<sa ? config->ssb_table.ssb_subcarrier_offset.value : 31; + #ifdef DEBUG_PBCH_ENCODING for (int i=0; i<3; i++) printf("pbch_pdu[%d]: 0x%02x\n", i, pbch_pdu[i]); @@ -265,7 +269,7 @@ int nr_generate_pbch(nfapi_nr_dl_tti_ssb_pdu *ssb_pdu, for (int i=0; i<3; i++) pbch->pbch_a |= ((ssb_index>>(5-i))&1)<<(29+i); // resp. 6th, 5th and 4th bits of ssb_index else - pbch->pbch_a |= ((config->ssb_table.ssb_subcarrier_offset.value>>4)&1)<<29; //MSB of k_SSB (bit index 4) + pbch->pbch_a |= ((ssb_sc_offset>>4)&1)<<29; //MSB of k_SSB (bit index 4) LOG_D(PHY,"After extra byte: pbch_a = 0x%08x\n",pbch->pbch_a); diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1428987d40..4d511a2e95 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -72,8 +72,11 @@ void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot,nfapi_nr_ ssb_start_symbol = ssb_start_symbol_abs % fp->symbols_per_slot; // start symbol wrt slot // setting the first subcarrier - fp->ssb_start_subcarrier = (12 * cfg->ssb_table.ssb_offset_point_a.value + ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset); - LOG_D(PHY, "SSB first subcarrier %d (%d,%d)\n", fp->ssb_start_subcarrier,cfg->ssb_table.ssb_offset_point_a.value,ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset); + const int scs = cfg->ssb_config.scs_common.value; + const int prb_offset = (fp->freq_range == nr_FR1) ? ssb_pdu.ssb_pdu_rel15.ssbOffsetPointA>>scs : ssb_pdu.ssb_pdu_rel15.ssbOffsetPointA>>(scs-2); + const int sc_offset = (fp->freq_range == nr_FR1) ? ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset>>scs : ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset; + fp->ssb_start_subcarrier = (12 * prb_offset + sc_offset); + LOG_D(PHY, "SSB first subcarrier %d (%d,%d)\n", fp->ssb_start_subcarrier, prb_offset, sc_offset); LOG_D(PHY,"SS TX: frame %d, slot %d, start_symbol %d\n",frame,slot, ssb_start_symbol); nr_generate_pss(&txdataF[0][txdataF_offset], AMP, ssb_start_symbol, cfg, fp); diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 07c5f118dc..b43cb6b00d 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -67,7 +67,10 @@ openair0_config_t openair0_cfg[MAX_CARDS]; uint8_t const nr_rv_round_map[4] = {0, 2, 3, 1}; uint64_t get_softmodem_optmask(void) {return 0;} -softmodem_params_t *get_softmodem_params(void) {return 0;} +static softmodem_params_t softmodem_params; +softmodem_params_t *get_softmodem_params(void) { + return &softmodem_params; +} void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) {} @@ -174,6 +177,7 @@ int main(int argc, char **argv) int ssb_subcarrier_offset = 0; channel_desc_t *gNB2UE; + get_softmodem_params()->sa = 0; //uint8_t extended_prefix_flag=0; //int8_t interf1=-21,interf2=-21; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 218b75b2e8..4daddbf03a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -335,22 +335,13 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, int pusch_AntennaPorts, cfg->num_tlv++; // SSB Table Configuration - int scs_scaling = 1<<(cfg->ssb_config.scs_common.value); - if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000) - scs_scaling = scs_scaling*3; - if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666) - scs_scaling = scs_scaling>>2; uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); - - RC.nrmac[Mod_idP]->ssb_SubcarrierOffset = absolute_diff%(12*scs_scaling); - int sco = 31; // no SIB1 - if(get_softmodem_params()->sa) { - sco = RC.nrmac[Mod_idP]->ssb_SubcarrierOffset; - if(frequency_range == FR1) - sco <<= cfg->ssb_config.scs_common.value; // 38.211 section 7.4.3.1 in FR1 it is expresses in terms of 15kHz SCS - } - - cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scs_scaling) - 10; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total + const int scaling_5khz = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000 ? 3 : 1; + int sco = (absolute_diff*scaling_5khz) % 24; + if(frequency_range == FR2) + sco >>= 1; // this assumes 120kHz SCS for SSB and subCarrierSpacingCommon (only option supported by OAI for + const int scs_scaling = frequency_range == FR2 ? 1 << (*scc->ssbSubcarrierSpacing - 2) : 1 << *scc->ssbSubcarrierSpacing; + cfg->ssb_table.ssb_offset_point_a.value = absolute_diff/(12*scaling_5khz) - 10*scs_scaling; //absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total cfg->ssb_table.ssb_offset_point_a.tl.tag = NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG; cfg->num_tlv++; cfg->ssb_table.ssb_period.value = *scc->ssb_periodicityServingCell; @@ -360,6 +351,9 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, int pusch_AntennaPorts, cfg->ssb_table.ssb_subcarrier_offset.tl.tag = NFAPI_NR_CONFIG_SSB_SUBCARRIER_OFFSET_TAG; cfg->num_tlv++; + RC.nrmac[Mod_idP]->ssb_SubcarrierOffset = cfg->ssb_table.ssb_subcarrier_offset.value; + RC.nrmac[Mod_idP]->ssb_OffsetPointA = cfg->ssb_table.ssb_offset_point_a.value; + switch (scc->ssb_PositionsInBurst->present) { case 1 : cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0]<<24; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index e2ceadb889..828cb2b880 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -54,52 +54,6 @@ extern RAN_CONTEXT_t RC; - -uint16_t get_ssboffset_pointa(NR_ServingCellConfigCommon_t *scc,const long band) { - - int ratio; - switch (*scc->ssbSubcarrierSpacing) { - case NR_SubcarrierSpacing_kHz15: - AssertFatal(band <= 95, - "Band %ld is not possible for SSB with 15 kHz SCS\n", - band); - // no band available above 3GHz using 15kHz - ratio = 3; // NRARFCN step is 5 kHz - break; - case NR_SubcarrierSpacing_kHz30: - AssertFatal(band <= 96, - "Band %ld is not possible for SSB with 30 kHz SCS\n", - band); - if (band == 46 || band == 48 || band == 77 || - band == 78 || band == 79 || band == 96) // above 3GHz - ratio = 2; // NRARFCN step is 15 kHz - else - ratio = 6; // NRARFCN step is 5 kHz - break; - case NR_SubcarrierSpacing_kHz120: - AssertFatal(band >= 257, - "Band %ld is not possible for SSB with 120 kHz SCS\n", - band); - ratio = 2; // NRARFCN step is 15 kHz - break; - case NR_SubcarrierSpacing_kHz240: - AssertFatal(band >= 257, - "Band %ld is not possible for SSB with 240 kHz SCS\n", - band); - ratio = 4; // NRARFCN step is 15 kHz - break; - default: - AssertFatal(1 == 0, "SCS %ld not allowed for SSB \n", - *scc->ssbSubcarrierSpacing); - } - - const uint32_t ssb_offset0 = *scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA; - - return (ssb_offset0/(ratio*12) - 10); // absoluteFrequencySSB is the center of SSB - -} - - void schedule_ssb(frame_t frame, sub_frame_t slot, NR_ServingCellConfigCommon_t *scc, nfapi_nr_dl_tti_request_body_t *dl_req, @@ -190,7 +144,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) NR_SubcarrierSpacing_t scs = *scc->ssbSubcarrierSpacing; const long band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; - uint16_t offset_pointa = get_ssboffset_pointa(scc,band); + const uint16_t offset_pointa = gNB->ssb_OffsetPointA; uint8_t ssbSubcarrierOffset = gNB->ssb_SubcarrierOffset; const BIT_STRING_t *shortBitmap = &scc->ssb_PositionsInBurst->choice.shortBitmap; @@ -207,8 +161,9 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters if ((ssb_start_symbol/14) == rel_slot){ + const int prb_offset = offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, (*(uint32_t*)cc->MIB_pdu.payload) & ((1<<24)-1)); - fill_ssb_vrb_map(cc, offset_pointa, ssb_start_symbol, CC_id); + fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); if (get_softmodem_params()->sa == 1) { get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], frameP, @@ -221,7 +176,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) band, i_ssb, ssb_frame_periodicity, - offset_pointa); + prb_offset); gNB->type0_PDCCH_CSS_config[i_ssb].active = true; } } @@ -235,8 +190,9 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters if ((ssb_start_symbol/14) == rel_slot){ + const int prb_offset = offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, (*(uint32_t*)cc->MIB_pdu.payload) & ((1<<24)-1)); - fill_ssb_vrb_map(cc, offset_pointa, ssb_start_symbol, CC_id); + fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); if (get_softmodem_params()->sa == 1) { get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], frameP, @@ -249,7 +205,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) band, i_ssb, ssb_frame_periodicity, - offset_pointa); + prb_offset); gNB->type0_PDCCH_CSS_config[i_ssb].active = true; } } @@ -264,8 +220,9 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb); // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters if ((ssb_start_symbol/14) == rel_slot){ + const int prb_offset = offset_pointa >> (scs-2); // reference 60kHz schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, ssbSubcarrierOffset, offset_pointa, (*(uint32_t*)cc->MIB_pdu.payload) & ((1<<24)-1)); - fill_ssb_vrb_map(cc, offset_pointa, ssb_start_symbol, CC_id); + fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id); const NR_TDD_UL_DL_Pattern_t *tdd = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; // FR2 is only TDD, to be fixed for flexible TDD @@ -286,7 +243,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) band, i_ssb, ssb_frame_periodicity, - offset_pointa); + prb_offset); gNB->type0_PDCCH_CSS_config[i_ssb].active = true; } } @@ -306,7 +263,7 @@ void schedule_nr_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframe //---------------------------------------- } -void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, uint16_t symStart, int CC_id) { +void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, int ssb_subcarrier_offset, uint16_t symStart, int CC_id) { AssertFatal(*cc->ServingCellConfigCommon->ssbSubcarrierSpacing != NR_SubcarrierSpacing_kHz240, @@ -314,7 +271,8 @@ void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, uint16_t symStart uint16_t *vrb_map = cc[CC_id].vrb_map; - for (int rb = 0; rb < 20; rb++) + const int extra_prb = ssb_subcarrier_offset > 0; + for (int rb = 0; rb < 20+extra_prb; rb++) vrb_map[rbStart + rb] = SL_to_bitmap(symStart, 4); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 3fd394abdb..364f0255d2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -434,7 +434,7 @@ int binomial(int n, int k); bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot); -void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, uint16_t symStart, int CC_id); +void fill_ssb_vrb_map (NR_COMMON_channels_t *cc, int rbStart, int ssb_subcarrier_offset, uint16_t symStart, int CC_id); /* \brief Function to indicate a received SDU on ULSCH. diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 40d16f8e8d..49c1f5caf2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -765,6 +765,7 @@ typedef struct gNB_MAC_INST_s { int pusch_failure_thres; /// Subcarrier Offset int ssb_SubcarrierOffset; + int ssb_OffsetPointA; /// SIB1 Time domain allocation int sib1_tda; int minRXTXTIMEpdsch; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index ea4e038ca0..d08f816cdb 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -226,17 +226,13 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { AssertFatal(scc->ssbSubcarrierSpacing != NULL, "scc->ssbSubcarrierSpacing is null\n"); int band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; frequency_range_t frequency_range = band<100?FR1:FR2; - int scs_scaling = 1<<*scc->ssbSubcarrierSpacing; - if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000) - scs_scaling = scs_scaling*3; - if (scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666) - scs_scaling = scs_scaling>>2; - uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); int ssb_subcarrier_offset = 31; // default value for NSA if (get_softmodem_params()->sa) { - ssb_subcarrier_offset = absolute_diff%(12*scs_scaling); - if(frequency_range == FR1) - ssb_subcarrier_offset <<= *scc->ssbSubcarrierSpacing; + uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); + int scs_scaling = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000 ? 3 : 1; + ssb_subcarrier_offset = (absolute_diff*scs_scaling)%24; + if(frequency_range == FR2) + ssb_subcarrier_offset >>= 1; // this assumes 120kHz SCS for SSB and subCarrierSpacingCommon (only option supported by OAI for now) } mib->message.choice.mib->ssb_SubcarrierOffset = ssb_subcarrier_offset&15; From edcb1b2bf578ed980935d5774c4ef80d4ff8cd10 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 5 Jul 2022 18:30:02 +0200 Subject: [PATCH 35/61] workaround for pbchsim --- openair1/SIMULATION/NR_PHY/pbchsim.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index b43cb6b00d..0e648c945f 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -177,7 +177,7 @@ int main(int argc, char **argv) int ssb_subcarrier_offset = 0; channel_desc_t *gNB2UE; - get_softmodem_params()->sa = 0; + get_softmodem_params()->sa = 1; //uint8_t extended_prefix_flag=0; //int8_t interf1=-21,interf2=-21; @@ -464,6 +464,7 @@ int main(int argc, char **argv) frame_parms->Nid_cell = Nid_cell; frame_parms->nushift = Nid_cell%4; frame_parms->ssb_type = nr_ssb_type_C; + frame_parms->freq_range = mu<2 ? nr_FR1 : nr_FR2; nr_phy_config_request_sim_pbchsim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions); phy_init_nr_gNB(gNB,0,1); @@ -588,9 +589,12 @@ int main(int argc, char **argv) for (i=0; iLmax; i++) { if((SSB_positions >> i) & 0x01) { + const int sc_offset = frame_parms->freq_range == nr_FR1 ? ssb_subcarrier_offset<freq_range == nr_FR1 ? gNB->gNB_config.ssb_table.ssb_offset_point_a.value<gNB_config.ssb_table.ssb_offset_point_a.value << (mu - 2); msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.bchPayload = 0x55dd33; msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = i; - msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset = ssb_subcarrier_offset; + msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset = sc_offset; + msgDataTx.ssb[i].ssb_pdu.ssb_pdu_rel15.ssbOffsetPointA = prb_offset; start_symbol = nr_get_ssb_start_symbol(frame_parms,i); int slot = start_symbol/14; From 43c980d36bf277e49e3f22ea545e309af7099239 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 7 Jul 2022 09:24:31 +0200 Subject: [PATCH 36/61] CI: NSA-B200-Container: no Qlog --- ci-scripts/xml_files/container_nsa_b200_quectel.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/ci-scripts/xml_files/container_nsa_b200_quectel.xml b/ci-scripts/xml_files/container_nsa_b200_quectel.xml index 8d04be3efd..51e6668cf0 100644 --- a/ci-scripts/xml_files/container_nsa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_nsa_b200_quectel.xml @@ -53,7 +53,6 @@ Initialize_UE Initialize Quectel idefix - yes From f1e3f7fb1f0fc8acc69d096987c2f6324f362e50 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 7 Jul 2022 17:59:33 +0200 Subject: [PATCH 37/61] CI: Abort pipeline if DeployObject fails --- ci-scripts/cls_containerize.py | 2 ++ ci-scripts/main.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 259db7bffe..49aeeeed55 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -567,8 +567,10 @@ class Containerize(): if status: HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) else: + self.exitStatus = 1 HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK) + def UndeployObject(self, HTML, RAN): if self.eNB_serverId[self.eNB_instance] == '0': lIpAddr = self.eNBIPAddress diff --git a/ci-scripts/main.py b/ci-scripts/main.py index adef885942..448f2636e3 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -919,6 +919,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re CONTAINERS.Copy_Image_to_Test_Server(HTML) elif action == 'Deploy_Object': CONTAINERS.DeployObject(HTML, EPC) + if CONTAINERS.exitStatus==1: + RAN.prematureExit = True elif action == 'Undeploy_Object': CONTAINERS.UndeployObject(HTML, RAN) elif action == 'Cppcheck_Analysis': From 5928d571e7c82040bf8e04f8fc9f1f29a9db7014 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 8 Jul 2022 11:14:04 +0200 Subject: [PATCH 38/61] CI: Fix log message typo in UndeployObject() --- ci-scripts/cls_containerize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 49aeeeed55..6abf444a0d 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -590,7 +590,7 @@ class Containerize(): if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') - logging.debug('\u001B[1m Deploying OAI Object on server: ' + lIpAddr + '\u001B[0m') + logging.debug('\u001B[1m Undeploying OAI Object from server: ' + lIpAddr + '\u001B[0m') mySSH = SSH.SSHConnection() mySSH.open(lIpAddr, lUserName, lPassWord) mySSH.command('cd ' + lSourcePath + '/' + self.yamlPath[self.eNB_instance], '\$', 5) From 87d1a53ca39585246131a5e6af32929e09b89f7b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 14 Jul 2022 17:08:59 +0200 Subject: [PATCH 39/61] CI: Allow publickey authentication in SSHConnection For pubkey, checks that we are on the right machine --- ci-scripts/sshconnection.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index dca3daa817..d9ab3c5011 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -60,7 +60,7 @@ class SSHConnection(): count = 0 connect_status = False while count < 4: - self.ssh = pexpect.spawn('ssh -o PubkeyAuthentication=no {}@{}'.format(username,ipaddress)) + self.ssh = pexpect.spawn('ssh -o PubkeyAuthentication=yes {}@{}'.format(username,ipaddress)) # Longer timeout at connection due to asterix slowness self.ssh.timeout = 25 self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT]) @@ -85,13 +85,15 @@ class SSHConnection(): logging.debug('self.sshresponse = ' + str(self.sshresponse)) elif self.sshresponse == 2: # Checking if we are really on the remote client defined by its IP address - self.command('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "', prompt, 5) - result = re.search(str(ipaddress), str(self.ssh.before)) - if result is None: - self.close() - else: + self.ssh.sendline('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "') + self.sshresponse = self.ssh.expect([ipaddress, pexpect.EOF, pexpect.TIMEOUT]) + if self.sshresponse == 0: count = 10 connect_status = True + # this expect seems to be necessary to advance the read buffer until the prompt, or getBefore() will not return the last command + self.sshresponse = self.ssh.expect([prompt]) + else: + logging.error('logged in to ' + ipaddress + ' without password but IP is not found via ifconfig on remote host, aborting') else: # debug output logging.debug(str(self.ssh.before)) From 4b50e4b1f684f958f3bdcd604a4a10de64fa94db Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 14 Jul 2022 22:18:01 +0200 Subject: [PATCH 40/61] CI: decode in getBefore() --- ci-scripts/sshconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index d9ab3c5011..52d799ebe3 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -274,4 +274,4 @@ class SSHConnection(): sys.exit('SCP failed') def getBefore(self): - return str(self.ssh.before) + return self.ssh.before.decode('utf-8') From b308cbe1019002a1f51dedde0c1cb84fd62a62f2 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 7 Jul 2022 09:07:58 +0200 Subject: [PATCH 41/61] Add RAN-SA-B200-Module-SABOX-Container test --- .../gnb.sa.band78.fr1.106PRB.usrpb210.conf | 344 ++++++++++++++++++ .../xml_files/container_sa_b200_quectel.xml | 169 +++++++++ .../xml_files/container_sa_b200_terminate.xml | 42 +++ ci-scripts/xml_files/fr1_5gc_closure.xml | 37 ++ ci-scripts/xml_files/fr1_5gc_start.xml | 38 ++ .../yaml_files/sa_b200_gnb/docker-compose.yml | 44 +++ doc/TESTBenches.md | 5 +- docker/scripts/generateTemplate.py | 1 + docker/scripts/gnb_entrypoint.sh | 1 + docker/scripts/gnb_parameters.yaml | 30 ++ 10 files changed, 710 insertions(+), 1 deletion(-) create mode 100644 ci-scripts/conf_files/gnb.sa.band78.fr1.106PRB.usrpb210.conf create mode 100644 ci-scripts/xml_files/container_sa_b200_quectel.xml create mode 100644 ci-scripts/xml_files/container_sa_b200_terminate.xml create mode 100644 ci-scripts/xml_files/fr1_5gc_closure.xml create mode 100644 ci-scripts/xml_files/fr1_5gc_start.xml create mode 100644 ci-scripts/yaml_files/sa_b200_gnb/docker-compose.yml diff --git a/ci-scripts/conf_files/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.sa.band78.fr1.106PRB.usrpb210.conf new file mode 100644 index 0000000000..2a6053ab46 --- /dev/null +++ b/ci-scripts/conf_files/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -0,0 +1,344 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ + mcc = 222; + mnc = 01; + mnc_length = 2; + snssaiList = ( + { + sst = 1; + #sd = 0x1; // 0 false, else true + } + ); + + }); + + nr_cellid = 12345678L; + + ////////// Physical parameters: + + min_rxtxtime = 2; + do_CSIRS = 1; + do_SRS = 1; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 12; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 641280; + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 640008; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952 +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 4; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_PositionsInBurs_BitmapPR +# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR = 2; + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + +# Dedicated Serving Cell Configuration +servingCellConfigDedicated = ({ + # BWP-Downlink + # BWP 1 Configuration + dl_bwp-Id_1 = 1; + dl_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_bwp1_subcarrierSpacing = 1; + + # BWP 2 Configuration + dl_bwp-Id_2 = 2; + dl_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_bwp2_subcarrierSpacing = 1; + + # BWP 3 Configuration + dl_bwp-Id_3 = 3; + dl_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_bwp3_subcarrierSpacing = 1; + + firstActiveDownlinkBWP-Id = 1; #BWP-Id + defaultDownlinkBWP-Id = 1; #BWP-Id + + # bwp-InactivityTimer ENUMERATED {ms2, ms3, ms4, ms5, ms6, ms8, ms10, ms20, ms30, + # ms40,ms50, ms60, ms80,ms100, ms200,ms300, ms500, + # ms750, ms1280, ms1920, ms2560, spare10, spare9, spare8, + # spare7, spare6, spare5, spare4, spare3, spare2, spare1 } + + # UplinkConfig + # BWP-Uplink + # BWP 1 Configuration + ul_bwp-Id_1 = 1; + ul_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_bwp1_subcarrierSpacing = 1; + + # BWP 2 Configuration + ul_bwp-Id_2 = 2; + ul_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_bwp2_subcarrierSpacing = 1; + + # BWP 3 Configuration + ul_bwp-Id_3 = 3; + ul_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW) + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_bwp3_subcarrierSpacing = 1; + + firstActiveUplinkBWP-Id = 1; #BWP-Id + } +); + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "172.21.16.136"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + + NETWORK_INTERFACES : + { + GNB_INTERFACE_NAME_FOR_NG_AMF = "demo-oai"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.137/24"; + GNB_INTERFACE_NAME_FOR_NGU = "demo-oai"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.137/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 200; + ulsch_max_frame_inactivity = 0; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 100; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +} +); + +RUs = ( +{ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 10; + att_rx = 10; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + #beamforming 1x4 matrix: + bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000]; + clock_src = "internal"; +} +); + +THREAD_STRUCT = ( +{ + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_SINGLE_THREAD"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; +} +); + +rfsimulator : +{ + serveraddr = "server"; + serverport = "4043"; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs"; +}; + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + ngap_log_level ="debug"; + f1ap_log_level ="debug"; +}; + diff --git a/ci-scripts/xml_files/container_sa_b200_quectel.xml b/ci-scripts/xml_files/container_sa_b200_quectel.xml new file mode 100644 index 0000000000..971fd1deed --- /dev/null +++ b/ci-scripts/xml_files/container_sa_b200_quectel.xml @@ -0,0 +1,169 @@ + + + TEST-SA-FR1-B200 + SA SanityCheck with QUECTEL + tasks + 1 + + 000001 + 010002 + 030000 + 030101 + 000001 + 010000 + 000001 + 050000 + 050001 + 010002 + 000001 + 030201 + + + + + + Initialize_UE + Initialize Quectel + idefix + + + + + Terminate_UE + Terminate Quectel + idefix + + + + Copy_Image_to_Test + Copy gNB image to test server + oai-gnb + 1 + 0 + + + + Deploy_Object + Deploy gNB (TDD/Band78/40MHz/B200) in a container + ci-scripts/yaml_files/sa_b200_gnb + 0 + 0 + + + + IdleSleep + Sleep + 5 + + + + IdleSleep + Sleep + 20 + + + + + Ping + Ping: 20pings in 20sec + idefix + -c 20 + 1 + 15 + + + + Ping + Ping: 100pings in 20sec + idefix + -c 100 -i 0.2 + 1 + 15 + + + + Ping + Ping: 20pings in 20sec + idefix + -c 20 + 1 + 15 + + + + Ping + Ping: 100pings in 20sec + idefix + -c 100 -i 0.2 + 1 + 15 + + + + Iperf + iperf (DL/125Mbps/UDP)(60 sec)(single-ue profile) + -u -b 125M -t 60 -i 1 -fm + DL + idefix + 25 + 80 + single-ue + + + + Iperf + iperf (UL/8Mbps/UDP)(60 sec)(single-ue profile) + -u -b 8M -t 60 -i 1 -fm + UL + idefix + 1 + 95 + single-ue + + + + Iperf + iperf (BIDIR TCP)(10 sec)(single-ue profile) + -t 10 --bidir + BIDIR + idefix + single-ue + + + + Undeploy_Object + Undeploy gNB + ci-scripts/yaml_files/sa_b200_gnb + 0 + 0 + + + + diff --git a/ci-scripts/xml_files/container_sa_b200_terminate.xml b/ci-scripts/xml_files/container_sa_b200_terminate.xml new file mode 100644 index 0000000000..5a2b6bd454 --- /dev/null +++ b/ci-scripts/xml_files/container_sa_b200_terminate.xml @@ -0,0 +1,42 @@ + + + TEST-SA-FR1-B200-terminate + SA tear-down in case of problem + tasks + 1 + + 030201 + + + + + Undeploy_Object + Undeploy gNB + ci-scripts/yaml_files/sa_b200_gnb + 1 + 1 + sa-test + + + diff --git a/ci-scripts/xml_files/fr1_5gc_closure.xml b/ci-scripts/xml_files/fr1_5gc_closure.xml new file mode 100644 index 0000000000..e5e57fa694 --- /dev/null +++ b/ci-scripts/xml_files/fr1_5gc_closure.xml @@ -0,0 +1,37 @@ + + + 5gc-closure + 5GC-Closure + log-out + +060000 + + + + + Terminate_5GCN + Terminate 5GC + + + diff --git a/ci-scripts/xml_files/fr1_5gc_start.xml b/ci-scripts/xml_files/fr1_5gc_start.xml new file mode 100644 index 0000000000..8758b761cd --- /dev/null +++ b/ci-scripts/xml_files/fr1_5gc_start.xml @@ -0,0 +1,38 @@ + + + 5gc-start-tab + 5GC-Start + log-in + + 000100 + + + + + + Initialize_5GCN + Initialize 5GC + + + diff --git a/ci-scripts/yaml_files/sa_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_b200_gnb/docker-compose.yml new file mode 100644 index 0000000000..9ea52c1247 --- /dev/null +++ b/ci-scripts/yaml_files/sa_b200_gnb/docker-compose.yml @@ -0,0 +1,44 @@ +version: '3.8' + +services: + gnb_mono_tdd: + image: oai-gnb:latest + privileged: true + container_name: sa-b200-gnb + environment: + USE_SA_TDD_MONO_B2XX: 'yes' + USE_B2XX: 'yes' + GNB_NAME: gNB-in-docker + MCC: '222' + MNC: '01' + MNC_LENGTH: 2 + TAC: 1 + NSSAI_SST: 1 + NSSAI_SD0: 1 + AMF_IP_ADDRESS: 172.21.16.136 + GNB_NGA_IF_NAME: eth0 + GNB_NGA_IP_ADDRESS: 192.168.68.194 + GNB_NGU_IF_NAME: eth0 + GNB_NGU_IP_ADDRESS: 192.168.68.194 + USE_ADDITIONAL_OPTIONS: --sa -E -q --RUs.[0].sdr_addrs serial=30C51D4 --continuous-tx --log_config.global_log_options level,nocolor,time,line_num,function + volumes: + - /dev:/dev + networks: + public_net: + ipv4_address: 192.168.68.194 + #entrypoint: /bin/bash -c "sleep infinity" + healthcheck: + # pgrep does NOT work + test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem" + interval: 10s + timeout: 5s + retries: 5 + +networks: + public_net: + name: sa-b200-gnb-net + ipam: + config: + - subnet: 192.168.68.192/26 + driver_opts: + com.docker.network.bridge.name: "sa-gnb-net" diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md index 547fd5a23b..24e649ccc0 100644 --- a/doc/TESTBenches.md +++ b/doc/TESTBenches.md @@ -89,7 +89,10 @@ Webhook currently only ping - [RAN-NSA-B200-Module-LTEBOX-Container](https://jenkins-oai.eurecom.fr/job/RAN-NSA-B200-Module-LTEBOX-Container/) - obelix + B200, nepes + B200, idefix + Quectel, porcepix w/ ltebox - - basic NSA test, known to be instable + - basic NSA test +- [RAN-SA-B200-Module-SABOX-Container](https://jenkins-oai.eurecom.fr/job/RAN-SA-B200-Module-SABOX-Container/) + - obelix + B200, nepes + B200, idefix + Quectel, porcepix w/ sabox + - basic SA test (40 MHz TDD) - [RAN-PhySim-Cluster](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster/) - asterix (`Asterix-OC-oaicicd-session` resource), tests in OpenShift Cluster - unitary simulators (`nr_dlsim`, etc.) diff --git a/docker/scripts/generateTemplate.py b/docker/scripts/generateTemplate.py index 850bb535a5..ec8f32ec6e 100644 --- a/docker/scripts/generateTemplate.py +++ b/docker/scripts/generateTemplate.py @@ -60,6 +60,7 @@ def main(): "rcc.band40.tm1.25PRB": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gnb.band78.tm1.fr1.106PRB.usrpb210.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gnb.band78.sa.fr1.106PRB.usrpn310.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', + "gnb.sa.band78.fr1.106PRB.usrpb210.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gnb.sa.band66.fr1.106PRB.usrpn300.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gNB_SA_CU.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', "gNB_SA_DU.conf": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', diff --git a/docker/scripts/gnb_entrypoint.sh b/docker/scripts/gnb_entrypoint.sh index dd6256609c..ac0e0d4c88 100755 --- a/docker/scripts/gnb_entrypoint.sh +++ b/docker/scripts/gnb_entrypoint.sh @@ -10,6 +10,7 @@ THREAD_PARALLEL_CONFIG=${THREAD_PARALLEL_CONFIG:-PARALLEL_SINGLE_THREAD} if [[ -v USE_NSA_TDD_MONO ]]; then cp $PREFIX/etc/gnb.nsa.tdd.conf $PREFIX/etc/gnb.conf; fi if [[ -v USE_SA_TDD_MONO ]]; then cp $PREFIX/etc/gnb.sa.tdd.conf $PREFIX/etc/gnb.conf; fi +if [[ -v USE_SA_TDD_MONO_B2XX ]]; then cp $PREFIX/etc/gnb.sa.tdd.b2xx.conf $PREFIX/etc/gnb.conf; fi if [[ -v USE_SA_FDD_MONO ]]; then cp $PREFIX/etc/gnb.sa.fdd.conf $PREFIX/etc/gnb.conf; fi if [[ -v USE_SA_CU ]]; then cp $PREFIX/etc/gnb.sa.cu.conf $PREFIX/etc/gnb.conf; fi if [[ -v USE_SA_TDD_CU ]]; then cp $PREFIX/etc/gnb.sa.du.tdd.conf $PREFIX/etc/gnb.conf; fi diff --git a/docker/scripts/gnb_parameters.yaml b/docker/scripts/gnb_parameters.yaml index d5942f2c9b..420559ff3f 100644 --- a/docker/scripts/gnb_parameters.yaml +++ b/docker/scripts/gnb_parameters.yaml @@ -94,6 +94,36 @@ - key: parallel_config env: "@THREAD_PARALLEL_CONFIG@" + - filePrefix: gnb.sa.band78.fr1.106PRB.usrpb210.conf + outputfilename: "gnb.sa.tdd.b2xx.conf" + config: + - key: Active_gNBs + env: "@GNB_NAME@" + - key: gNB_name + env: "@GNB_NAME@" + - key: mcc + env: "@MCC@" + - key: mnc + env: "@MNC@" + - key: mnc_length + env: "@MNC_LENGTH@" + - key: tracking_area_code + env: "@TAC@" + - key: sst + env: "@NSSAI_SST@" + - key: ipv4 + env: "@AMF_IP_ADDRESS@" + - key: GNB_INTERFACE_NAME_FOR_NG_AMF + env: "@GNB_NGA_IF_NAME@" + - key: GNB_IPV4_ADDRESS_FOR_NG_AMF + env: "@GNB_NGA_IP_ADDRESS@" + - key: GNB_INTERFACE_NAME_FOR_NGU + env: "@GNB_NGU_IF_NAME@" + - key: GNB_IPV4_ADDRESS_FOR_NGU + env: "@GNB_NGU_IP_ADDRESS@" + - key: parallel_config + env: "@THREAD_PARALLEL_CONFIG@" + - filePrefix: gnb.sa.band66.fr1.106PRB.usrpn300.conf outputfilename: "gnb.sa.fdd.conf" config: From 0c4aa33939cf0b6cb9142a37019b8fc58bf97cde Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 14 Jul 2022 23:57:52 +0200 Subject: [PATCH 42/61] Trigger SA-B200 test from RAN-Container-Parent --- ci-scripts/Jenkinsfile-GitLab-Container | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container index c22e6fabec..b37c9d4f4b 100644 --- a/ci-scripts/Jenkinsfile-GitLab-Container +++ b/ci-scripts/Jenkinsfile-GitLab-Container @@ -278,6 +278,26 @@ pipeline { } } } + stage ("SA B200 Sanity Check") { + when { expression {doMandatoryTests} } + steps { + script { + triggerSlaveJob ('RAN-SA-B200-Module-SABOX-Container', 'Test-SA-B200') + } + } + post { + always { + script { + finalizeSlaveJob('RAN-SA-B200-Module-SABOX-Container') + } + } + failure { + script { + currentBuild.result = 'FAILURE' + } + } + } + } stage ("Test OAI NR UE - OAI gNB - TDD - Band 78 - N300") { when { expression {doMandatoryTests} } steps { From 63daf5793b414a92fb87e6f77845fb9c68c22752 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 15 Jul 2022 11:01:26 +0200 Subject: [PATCH 43/61] Remove useless SA test sleep --- ci-scripts/xml_files/container_sa_b200_quectel.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/ci-scripts/xml_files/container_sa_b200_quectel.xml b/ci-scripts/xml_files/container_sa_b200_quectel.xml index 971fd1deed..7f0475629d 100644 --- a/ci-scripts/xml_files/container_sa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_sa_b200_quectel.xml @@ -26,7 +26,6 @@ tasks 1 - 000001 010002 030000 030101 From 52168e5201c9b93a2632ec6c40f8de210491e351 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 15 Jul 2022 11:00:18 +0200 Subject: [PATCH 44/61] Shut off quectel before running SA tests --- ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml | 1 + ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml | 1 + ci-scripts/xml_files/fr1_nsa_quectel.xml | 1 + ci-scripts/xml_files/fr1_sa_quectel.xml | 1 + ci-scripts/xml_files/fr1_sa_quectel_162prb.xml | 1 + ci-scripts/xml_files/fr1_sa_quectel_stages.xml | 1 + ci-scripts/xml_files/lte_2x2_tm1_quectel.xml | 1 + ci-scripts/xml_files/lte_2x2_tm2_quectel.xml | 1 + 8 files changed, 8 insertions(+) diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml index 2ef2b7d7ce..459a16c323 100644 --- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 030000 040000 000002 diff --git a/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml b/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml index 335fe873a1..c8e0659330 100644 --- a/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml +++ b/ci-scripts/xml_files/fr1_nsa_2x2_quectel_attach_detach.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 031000 041000 000002 diff --git a/ci-scripts/xml_files/fr1_nsa_quectel.xml b/ci-scripts/xml_files/fr1_nsa_quectel.xml index a7fd0fc0d7..c72c61c0a2 100644 --- a/ci-scripts/xml_files/fr1_nsa_quectel.xml +++ b/ci-scripts/xml_files/fr1_nsa_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 030000 040000 000002 diff --git a/ci-scripts/xml_files/fr1_sa_quectel.xml b/ci-scripts/xml_files/fr1_sa_quectel.xml index 2b215479c2..fd983d8835 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 040000 000002 010000 diff --git a/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml b/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml index 23eaccfcfd..f426bd6035 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel_162prb.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 042000 000002 010000 diff --git a/ci-scripts/xml_files/fr1_sa_quectel_stages.xml b/ci-scripts/xml_files/fr1_sa_quectel_stages.xml index 603f3f919b..48a9b60e7d 100644 --- a/ci-scripts/xml_files/fr1_sa_quectel_stages.xml +++ b/ci-scripts/xml_files/fr1_sa_quectel_stages.xml @@ -26,6 +26,7 @@ tasks 1 + 011002 041000 000002 011000 diff --git a/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml b/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml index 0d18a52839..b6388eede2 100644 --- a/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml +++ b/ci-scripts/xml_files/lte_2x2_tm1_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 030000 000002 010000 diff --git a/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml b/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml index f84691ab48..99c8f75e06 100644 --- a/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml +++ b/ci-scripts/xml_files/lte_2x2_tm2_quectel.xml @@ -26,6 +26,7 @@ tasks 1 + 010002 030001 000002 010000 From 0700d5d078297494331c0ee112c658a66e67af8b Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Tue, 14 Jun 2022 18:35:40 +0100 Subject: [PATCH 45/61] Add 5G SA end-to-end, step-by-step, tutorials for OAI CN5G, OAI gNB and COTS UE --- doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md | 14 ++- doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md | 14 ++- .../docker-compose-basic-nrf.yaml | 96 ++++++++++++++----- doc/tutorial_resources/oai_db.sql | 22 ++++- 4 files changed, 107 insertions(+), 39 deletions(-) diff --git a/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md index 1110a5bc6c..da013515da 100644 --- a/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md +++ b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md @@ -86,6 +86,7 @@ cd ~/oai-cn5g-fed git checkout master ./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop +# Pull docker images docker pull oaisoftwarealliance/oai-amf:develop docker pull oaisoftwarealliance/oai-nrf:develop docker pull oaisoftwarealliance/oai-smf:develop @@ -95,7 +96,9 @@ docker pull oaisoftwarealliance/oai-ausf:develop docker pull oaisoftwarealliance/oai-upf-vpp:develop docker pull oaisoftwarealliance/oai-spgwu-tiny:develop docker pull oaisoftwarealliance/oai-nssf:develop +docker pull oaisoftwarealliance/trf-gen-cn5g:latest +# Tag docker images docker image tag oaisoftwarealliance/oai-amf:develop oai-amf:develop docker image tag oaisoftwarealliance/oai-nrf:develop oai-nrf:develop docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop @@ -105,16 +108,17 @@ docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop +docker image tag oaisoftwarealliance/trf-gen-cn5g:latest trf-gen-cn5g:latest ``` ## 2.3 OAI CN5G Configuration files -Download and copy the configuration files to ~/oai-cn5g-fed/docker-compose: -- [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml) -- [oai_db.sql](tutorial_resources/oai_db.sql) +Download and copy configuration files: +- Copy [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml) to `~/oai-cn5g-fed/docker-compose` +- Copy [oai_db.sql](tutorial_resources/oai_db.sql) to `~/oai-cn5g-fed/docker-compose/database` Change permissions on oai_db.sql to prevent mysql permission denied error: ```bash -chmod 644 ~/oai-cn5g-fed/docker-compose/oai_db.sql +chmod 644 ~/oai-cn5g-fed/docker-compose/database/oai_db.sql ``` ## 2.4 SIM Card @@ -175,7 +179,7 @@ cd cmake_targets ```bash cd ~/oai-cn5g-fed/docker-compose -python3 core-network.py --type start-basic --fqdn yes --scenario 1 +python3 core-network.py --type start-basic --scenario 1 ``` ## 4.2 Run OAI gNB diff --git a/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md index ed917e09ea..ac61363af0 100644 --- a/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md +++ b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md @@ -87,6 +87,7 @@ cd ~/oai-cn5g-fed git checkout master ./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop +# Pull docker images docker pull oaisoftwarealliance/oai-amf:develop docker pull oaisoftwarealliance/oai-nrf:develop docker pull oaisoftwarealliance/oai-smf:develop @@ -96,7 +97,9 @@ docker pull oaisoftwarealliance/oai-ausf:develop docker pull oaisoftwarealliance/oai-upf-vpp:develop docker pull oaisoftwarealliance/oai-spgwu-tiny:develop docker pull oaisoftwarealliance/oai-nssf:develop +docker pull oaisoftwarealliance/trf-gen-cn5g:latest +# Tag docker images docker image tag oaisoftwarealliance/oai-amf:develop oai-amf:develop docker image tag oaisoftwarealliance/oai-nrf:develop oai-nrf:develop docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop @@ -106,16 +109,17 @@ docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop +docker image tag oaisoftwarealliance/trf-gen-cn5g:latest trf-gen-cn5g:latest ``` ## 2.3 OAI CN5G Configuration files -Download and copy the configuration files to ~/oai-cn5g-fed/docker-compose: -- [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml) -- [oai_db.sql](tutorial_resources/oai_db.sql) +Download and copy configuration files: +- Copy [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml) to `~/oai-cn5g-fed/docker-compose` +- Copy [oai_db.sql](tutorial_resources/oai_db.sql) to `~/oai-cn5g-fed/docker-compose/database` Change permissions on oai_db.sql to prevent mysql permission denied error: ```bash -chmod 644 ~/oai-cn5g-fed/docker-compose/oai_db.sql +chmod 644 ~/oai-cn5g-fed/docker-compose/database/oai_db.sql ``` ## 2.4 SIM Card @@ -193,7 +197,7 @@ The following steps are recommended. Please change the network interface(s) as r ```bash cd ~/oai-cn5g-fed/docker-compose -python3 core-network.py --type start-basic --fqdn yes --scenario 1 +python3 core-network.py --type start-basic --scenario 1 ``` ## 4.2 Run OAI gNB diff --git a/doc/tutorial_resources/docker-compose-basic-nrf.yaml b/doc/tutorial_resources/docker-compose-basic-nrf.yaml index 6750cb78be..93c438055e 100644 --- a/doc/tutorial_resources/docker-compose-basic-nrf.yaml +++ b/doc/tutorial_resources/docker-compose-basic-nrf.yaml @@ -4,8 +4,8 @@ services: container_name: "mysql" image: mysql:5.7 volumes: - - ./oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - - ./mysql-healthcheck2.sh:/tmp/mysql-healthcheck.sh + - ./database/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql + - ./healthscripts/mysql-healthcheck2.sh:/tmp/mysql-healthcheck.sh environment: - TZ=Europe/Paris - MYSQL_DATABASE=oai_db @@ -21,35 +21,45 @@ services: public_net: ipv4_address: 192.168.70.131 oai-udr: - container_name: oai-udr + container_name: "oai-udr" image: oai-udr:develop environment: - TZ=Europe/Paris - INSTANCE=0 - PID_DIRECTORY=/var/run + - UDR_NAME=OAI_UDR - UDR_INTERFACE_NAME_FOR_NUDR=eth0 - UDR_INTERFACE_PORT_FOR_NUDR=80 - UDR_INTERFACE_HTTP2_PORT_FOR_NUDR=8080 + - USE_HTTP2=no - UDR_API_VERSION=v1 - MYSQL_IPV4_ADDRESS=192.168.70.131 - MYSQL_USER=test - MYSQL_PASS=test + - DB_CONNECTION_TIMEOUT=300 # Reset the connection to the DB after expiring the timeout (in second) currently can't be changed - MYSQL_DB=oai_db - WAIT_MYSQL=120 + - USE_FQDN_DNS=yes + - REGISTER_NRF=yes + - NRF_IPV4_ADDRESS=192.168.70.130 + - NRF_PORT=80 + - NRF_API_VERSION=v1 + - NRF_FQDN=oai-nrf depends_on: - mysql + - oai-nrf networks: public_net: ipv4_address: 192.168.70.136 volumes: - - ./udr-healthcheck.sh:/openair-udr/bin/udr-healthcheck.sh + - ./healthscripts/udr-healthcheck.sh:/openair-udr/bin/udr-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-udr/bin/udr-healthcheck.sh" interval: 10s timeout: 5s retries: 5 oai-udm: - container_name: oai-udm + container_name: "oai-udm" image: oai-udm:develop environment: - TZ=Europe/Paris @@ -58,26 +68,33 @@ services: - UDM_NAME=OAI_UDM - SBI_IF_NAME=eth0 - SBI_PORT=80 + - SBI_HTTP2_PORT=8080 + - USE_HTTP2=no - UDM_VERSION_NB=v1 - USE_FQDN_DNS=yes - UDR_IP_ADDRESS=192.168.70.136 - UDR_PORT=80 - UDR_VERSION_NB=v1 - UDR_FQDN=oai-udr + - REGISTER_NRF=yes + - NRF_IPV4_ADDRESS=192.168.70.130 + - NRF_PORT=80 + - NRF_API_VERSION=v1 + - NRF_FQDN=oai-nrf depends_on: - oai-udr networks: public_net: ipv4_address: 192.168.70.137 volumes: - - ./udm-healthcheck.sh:/openair-udm/bin/udm-healthcheck.sh + - ./healthscripts/udm-healthcheck.sh:/openair-udm/bin/udm-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-udm/bin/udm-healthcheck.sh" interval: 10s timeout: 5s retries: 5 oai-ausf: - container_name: oai-ausf + container_name: "oai-ausf" image: oai-ausf:develop environment: - TZ=Europe/Paris @@ -86,18 +103,25 @@ services: - AUSF_NAME=OAI_AUSF - SBI_IF_NAME=eth0 - SBI_PORT=80 + - USE_HTTP2 + - SBI_HTTP2_PORT - USE_FQDN_DNS=yes - UDM_IP_ADDRESS=192.168.70.137 - UDM_PORT=80 - UDM_VERSION_NB=v1 - UDM_FQDN=oai-udm + - REGISTER_NRF=yes + - NRF_IPV4_ADDRESS=192.168.70.130 + - NRF_PORT=80 + - NRF_API_VERSION=v1 + - NRF_FQDN=oai-nrf depends_on: - oai-udm networks: public_net: ipv4_address: 192.168.70.138 volumes: - - ./ausf-healthcheck.sh:/openair-ausf/bin/ausf-healthcheck.sh + - ./healthscripts/ausf-healthcheck.sh:/openair-ausf/bin/ausf-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-ausf/bin/ausf-healthcheck.sh" interval: 10s @@ -107,9 +131,10 @@ services: container_name: "oai-nrf" image: oai-nrf:develop environment: + - TZ=Europe/Paris - NRF_INTERFACE_NAME_FOR_SBI=eth0 - NRF_INTERFACE_PORT_FOR_SBI=80 - - NRF_INTERFACE_HTTP2_PORT_FOR_SBI=9090 + - NRF_INTERFACE_HTTP2_PORT_FOR_SBI=8080 - NRF_API_VERSION=v1 - INSTANCE=0 - PID_DIRECTORY=/var/run @@ -117,7 +142,7 @@ services: public_net: ipv4_address: 192.168.70.130 volumes: - - ./nrf-healthcheck.sh:/openair-nrf/bin/nrf-healthcheck.sh + - ./healthscripts/nrf-healthcheck.sh:/openair-nrf/bin/nrf-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-nrf/bin/nrf-healthcheck.sh" interval: 10s @@ -146,9 +171,7 @@ services: - PLMN_SUPPORT_MNC=99 - PLMN_SUPPORT_TAC=0x0001 - SST_0=1 - - SD_0=1 - - SST_1=1 - - SD_1=12 + - SD_0=0x1 - AMF_INTERFACE_NAME_FOR_NGAP=eth0 - AMF_INTERFACE_NAME_FOR_N11=eth0 - SMF_INSTANCE_ID_0=1 @@ -168,22 +191,30 @@ services: - OPERATOR_KEY=1006020f0a478bf6b699f15c062e42b3 - NRF_IPV4_ADDRESS=192.168.70.130 - NRF_PORT=80 + - EXTERNAL_NRF=no - NF_REGISTRATION=yes - SMF_SELECTION=yes - USE_FQDN_DNS=yes - EXTERNAL_AUSF=yes + - EXTERNAL_UDM=no + - EXTERNAL_NSSF=no + - USE_HTTP2=no - NRF_API_VERSION=v1 - NRF_FQDN=oai-nrf - AUSF_IPV4_ADDRESS=192.168.70.138 - AUSF_PORT=80 - AUSF_API_VERSION=v1 - AUSF_FQDN=oai-ausf + - UDM_IPV4_ADDRESS=192.168.70.137 + - UDM_PORT=80 + - UDM_API_VERSION=v2 + - UDM_FQDN=oai-udm depends_on: - mysql - oai-nrf - oai-ausf volumes: - - ./amf-healthcheck.sh:/openair-amf/bin/amf-healthcheck.sh + - ./healthscripts/amf-healthcheck.sh:/openair-amf/bin/amf-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-amf/bin/amf-healthcheck.sh" interval: 10s @@ -212,26 +243,35 @@ services: - AMF_FQDN=oai-amf - UDM_IPV4_ADDRESS=192.168.70.137 - UDM_PORT=80 - - UDM_API_VERSION=v1 + - UDM_API_VERSION=v2 - UDM_FQDN=oai-udm - UPF_IPV4_ADDRESS=192.168.70.134 - UPF_FQDN_0=oai-spgwu - NRF_IPV4_ADDRESS=192.168.70.130 - NRF_PORT=80 - NRF_API_VERSION=v1 - - USE_LOCAL_SUBSCRIPTION_INFO=yes + - USE_LOCAL_SUBSCRIPTION_INFO=yes #Set to yes if SMF uses local subscription information instead of from an UDM + - USE_NETWORK_INSTANCE=no #Set yes if network instance is to be used for given UPF - NRF_FQDN=oai-nrf - REGISTER_NRF=yes - DISCOVER_UPF=yes - USE_FQDN_DNS=yes - - DNN_RANGE1=12.1.1.2 - 12.1.1.128 - - DNN_RANGE0=12.2.1.2 - 12.2.1.128 - - DNN_NI1=oai + - HTTP_VERSION=1 # Default: 1 + - UE_MTU=1500 + - DNN_NI0=oai + - TYPE0=IPv4 + - DNN_RANGE0=12.1.1.2 - 12.1.1.253 + - NSSAI_SST0=1 + - NSSAI_SD0=0x1 + - SESSION_AMBR_UL0=1000Mbps + - SESSION_AMBR_DL0=1000Mbps + - DEFAULT_CSCF_IPV4_ADDRESS=127.0.0.1 # only needed when ims is being used + - ENABLE_USAGE_REPORTING=no # Set yes if UE USAGE REPORTING is to be done at UPF depends_on: - oai-nrf - oai-amf volumes: - - ./smf-healthcheck.sh:/openair-smf/bin/smf-healthcheck.sh + - ./healthscripts/smf-healthcheck.sh:/openair-smf/bin/smf-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-smf/bin/smf-healthcheck.sh" interval: 10s @@ -258,17 +298,23 @@ services: - MNC03=099 - TAC=1 - GW_ID=1 + - THREAD_S1U_PRIO=80 + - S1U_THREADS=8 + - THREAD_SX_PRIO=81 + - SX_THREADS=1 + - THREAD_SGI_PRIO=80 + - SGI_THREADS=8 - REALM=openairinterface.org - ENABLE_5G_FEATURES=yes - REGISTER_NRF=yes - - USE_FQDN_NRF=no + - USE_FQDN_NRF=yes - UPF_FQDN_5G=oai-spgwu - NRF_IPV4_ADDRESS=192.168.70.130 - NRF_PORT=80 - NRF_API_VERSION=v1 - NRF_FQDN=oai-nrf - NSSAI_SST_0=1 - - NSSAI_SD_0=1 + - NSSAI_SD_0=0x1 - DNN_0=oai depends_on: - oai-nrf @@ -280,7 +326,7 @@ services: - ALL privileged: true volumes: - - ./spgwu-healthcheck.sh:/openair-spgwu-tiny/bin/spgwu-healthcheck.sh + - ./healthscripts/spgwu-healthcheck.sh:/openair-spgwu-tiny/bin/spgwu-healthcheck.sh healthcheck: test: /bin/bash -c "/openair-spgwu-tiny/bin/spgwu-healthcheck.sh" interval: 10s @@ -290,12 +336,10 @@ services: public_net: ipv4_address: 192.168.70.134 oai-ext-dn: - image: ubuntu:bionic + image: trf-gen-cn5g:latest privileged: true container_name: oai-ext-dn entrypoint: /bin/bash -c \ - "apt update; apt install -y iptables iproute2 iperf iperf3 iputils-ping;"\ - "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.70.134 dev eth0; sleep infinity" depends_on: - oai-spgwu diff --git a/doc/tutorial_resources/oai_db.sql b/doc/tutorial_resources/oai_db.sql index e019c60e86..fb8f4b20ed 100644 --- a/doc/tutorial_resources/oai_db.sql +++ b/doc/tutorial_resources/oai_db.sql @@ -151,10 +151,13 @@ CREATE TABLE `AuthenticationSubscription` ( -- INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES -('208950000000031', '5G_AKA', '0C0A34601D4F07677303652C0462535B', '0C0A34601D4F07677303652C0462535B', '{\"sqn\": \"000000000020\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', '63bfa50ee6523365ff14c1f45f88737d', NULL, NULL, NULL, NULL, '208950000000031'); - + ('2089900007487', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000000\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '2089900007487'); INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES -('208990000000001', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000020\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '208990000000001'); + ('208990000000001', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000000\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '208990000000001'); +INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES + ('208990000000002', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000000\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '208990000000002'); +INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES + ('208990000000003', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000000\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '208990000000003'); -- -------------------------------------------------------- @@ -203,6 +206,19 @@ CREATE TABLE `SessionManagementSubscriptionData` ( `3gppChargingCharacteristics` varchar(50) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Dumping data for table `SessionManagementSubscriptionData` +-- + +INSERT INTO `SessionManagementSubscriptionData` (`ueid`, `servingPlmnid`, `singleNssai`, `dnnConfigurations`) VALUES + ('2089900007487', '20899', '{\"sst\": 1, \"sd\": \"1\"}','{\"oai\":{\"pduSessionTypes\":{ \"defaultSessionType\": \"IPV4\"},\"sscModes\": {\"defaultSscMode\": \"SSC_MODE_1\"},\"5gQosProfile\": {\"5qi\": 6,\"arp\":{\"priorityLevel\": 1,\"preemptCap\": \"NOT_PREEMPT\",\"preemptVuln\":\"NOT_PREEMPTABLE\"},\"priorityLevel\":1},\"sessionAmbr\":{\"uplink\":\"1000Mbps\", \"downlink\":\"1000Mbps\"},\"staticIpAddress\":[{\"ipv4Addr\": \"12.1.1.2\"}]}}'); +INSERT INTO `SessionManagementSubscriptionData` (`ueid`, `servingPlmnid`, `singleNssai`, `dnnConfigurations`) VALUES + ('208990000000001', '20899', '{\"sst\": 1, \"sd\": \"1\"}','{\"oai\":{\"pduSessionTypes\":{ \"defaultSessionType\": \"IPV4\"},\"sscModes\": {\"defaultSscMode\": \"SSC_MODE_1\"},\"5gQosProfile\": {\"5qi\": 6,\"arp\":{\"priorityLevel\": 1,\"preemptCap\": \"NOT_PREEMPT\",\"preemptVuln\":\"NOT_PREEMPTABLE\"},\"priorityLevel\":1},\"sessionAmbr\":{\"uplink\":\"1000Mbps\", \"downlink\":\"1000Mbps\"},\"staticIpAddress\":[{\"ipv4Addr\": \"12.1.1.2\"}]}}'); +INSERT INTO `SessionManagementSubscriptionData` (`ueid`, `servingPlmnid`, `singleNssai`, `dnnConfigurations`) VALUES + ('208990000000002', '20899', '{\"sst\": 1, \"sd\": \"1\"}','{\"oai\":{\"pduSessionTypes\":{ \"defaultSessionType\": \"IPV4\"},\"sscModes\": {\"defaultSscMode\": \"SSC_MODE_1\"},\"5gQosProfile\": {\"5qi\": 6,\"arp\":{\"priorityLevel\": 1,\"preemptCap\": \"NOT_PREEMPT\",\"preemptVuln\":\"NOT_PREEMPTABLE\"},\"priorityLevel\":1},\"sessionAmbr\":{\"uplink\":\"1000Mbps\", \"downlink\":\"1000Mbps\"},\"staticIpAddress\":[{\"ipv4Addr\": \"12.1.1.3\"}]}}'); +INSERT INTO `SessionManagementSubscriptionData` (`ueid`, `servingPlmnid`, `singleNssai`, `dnnConfigurations`) VALUES + ('208990000000003', '20899', '{\"sst\": 1, \"sd\": \"1\"}','{\"oai\":{\"pduSessionTypes\":{ \"defaultSessionType\": \"IPV4\"},\"sscModes\": {\"defaultSscMode\": \"SSC_MODE_1\"},\"5gQosProfile\": {\"5qi\": 6,\"arp\":{\"priorityLevel\": 1,\"preemptCap\": \"NOT_PREEMPT\",\"preemptVuln\":\"NOT_PREEMPTABLE\"},\"priorityLevel\":1},\"sessionAmbr\":{\"uplink\":\"1000Mbps\", \"downlink\":\"1000Mbps\"},\"staticIpAddress\":[{\"ipv4Addr\": \"12.1.1.4\"}]}}'); + -- -------------------------------------------------------- -- From ae05420c84ccbdc04843db1d5b318176998220b4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 15 Jul 2022 13:35:19 +0200 Subject: [PATCH 46/61] CI: log error if oai-amf container is not present for AMF IP addr retrieval --- ci-scripts/epc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py index 0e0afefaaf..9113d29ac9 100644 --- a/ci-scripts/epc.py +++ b/ci-scripts/epc.py @@ -311,6 +311,8 @@ class EPCManagement(): tmp = str(response[0],'utf-8') self.MmeIPAddress = tmp.rstrip() logging.debug('AMF IP Address ' + self.MmeIPAddress) + else: + logging.error('no container with name oai-amf found, could not retrieve AMF IP address') mySSH.close() def CheckHSSProcess(self, status_queue): From 43298fd02ce8b46636273049a393338117e63aca Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 15 Jul 2022 13:19:37 +0100 Subject: [PATCH 47/61] Address merge request review comments --- doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md | 11 ---------- doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md | 11 ---------- .../docker-compose-basic-nrf.yaml | 20 +++++++++---------- 3 files changed, 10 insertions(+), 32 deletions(-) diff --git a/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md index da013515da..fc0700c699 100644 --- a/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md +++ b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md @@ -71,10 +71,6 @@ reboot # https://docs.docker.com/compose/install/ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose - -docker network create --driver=bridge --subnet=192.168.70.128/26 -o "com.docker.network.bridge.name"="demo-oai" demo-oai-public-net -sudo service docker restart - ``` ## 2.2 OAI CN5G Setup @@ -82,9 +78,6 @@ sudo service docker restart ```bash # Git oai-cn5g-fed repository git clone https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-fed.git ~/oai-cn5g-fed -cd ~/oai-cn5g-fed -git checkout master -./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop # Pull docker images docker pull oaisoftwarealliance/oai-amf:develop @@ -93,9 +86,7 @@ docker pull oaisoftwarealliance/oai-smf:develop docker pull oaisoftwarealliance/oai-udr:develop docker pull oaisoftwarealliance/oai-udm:develop docker pull oaisoftwarealliance/oai-ausf:develop -docker pull oaisoftwarealliance/oai-upf-vpp:develop docker pull oaisoftwarealliance/oai-spgwu-tiny:develop -docker pull oaisoftwarealliance/oai-nssf:develop docker pull oaisoftwarealliance/trf-gen-cn5g:latest # Tag docker images @@ -105,9 +96,7 @@ docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop docker image tag oaisoftwarealliance/oai-udr:develop oai-udr:develop docker image tag oaisoftwarealliance/oai-udm:develop oai-udm:develop docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop -docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop -docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop docker image tag oaisoftwarealliance/trf-gen-cn5g:latest trf-gen-cn5g:latest ``` diff --git a/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md index ac61363af0..d68057fd08 100644 --- a/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md +++ b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md @@ -72,10 +72,6 @@ reboot # https://docs.docker.com/compose/install/ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose - -docker network create --driver=bridge --subnet=192.168.70.128/26 -o "com.docker.network.bridge.name"="demo-oai" demo-oai-public-net -sudo service docker restart - ``` ## 2.2 OAI CN5G Setup @@ -83,9 +79,6 @@ sudo service docker restart ```bash # Git oai-cn5g-fed repository git clone https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-fed.git ~/oai-cn5g-fed -cd ~/oai-cn5g-fed -git checkout master -./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop # Pull docker images docker pull oaisoftwarealliance/oai-amf:develop @@ -94,9 +87,7 @@ docker pull oaisoftwarealliance/oai-smf:develop docker pull oaisoftwarealliance/oai-udr:develop docker pull oaisoftwarealliance/oai-udm:develop docker pull oaisoftwarealliance/oai-ausf:develop -docker pull oaisoftwarealliance/oai-upf-vpp:develop docker pull oaisoftwarealliance/oai-spgwu-tiny:develop -docker pull oaisoftwarealliance/oai-nssf:develop docker pull oaisoftwarealliance/trf-gen-cn5g:latest # Tag docker images @@ -106,9 +97,7 @@ docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop docker image tag oaisoftwarealliance/oai-udr:develop oai-udr:develop docker image tag oaisoftwarealliance/oai-udm:develop oai-udm:develop docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop -docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop -docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop docker image tag oaisoftwarealliance/trf-gen-cn5g:latest trf-gen-cn5g:latest ``` diff --git a/doc/tutorial_resources/docker-compose-basic-nrf.yaml b/doc/tutorial_resources/docker-compose-basic-nrf.yaml index 93c438055e..cd1e957ad8 100644 --- a/doc/tutorial_resources/docker-compose-basic-nrf.yaml +++ b/doc/tutorial_resources/docker-compose-basic-nrf.yaml @@ -347,14 +347,14 @@ services: public_net: ipv4_address: 192.168.70.135 networks: + # public_net: + # external: + # name: demo-oai-public-net public_net: - external: - name: demo-oai-public-net -# public_net: -# driver: bridge -# name: demo-oai-public-net -# ipam: -# config: -# - subnet: 192.168.70.128/26 -# driver_opts: -# com.docker.network.bridge.name: "demo-oai" + driver: bridge + name: demo-oai-public-net + ipam: + config: + - subnet: 192.168.70.128/26 + driver_opts: + com.docker.network.bridge.name: "demo-oai" From 16c758ae0972a35bef28af38c82122232926f563 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 15 Jul 2022 16:00:52 +0200 Subject: [PATCH 48/61] CI: Drop IP check when connectiong via SSH and pubkey --- ci-scripts/sshconnection.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py index 52d799ebe3..035da71426 100644 --- a/ci-scripts/sshconnection.py +++ b/ci-scripts/sshconnection.py @@ -84,16 +84,11 @@ class SSHConnection(): else: logging.debug('self.sshresponse = ' + str(self.sshresponse)) elif self.sshresponse == 2: - # Checking if we are really on the remote client defined by its IP address - self.ssh.sendline('stdbuf -o0 ifconfig | egrep --color=never "inet addr:|inet "') - self.sshresponse = self.ssh.expect([ipaddress, pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - # this expect seems to be necessary to advance the read buffer until the prompt, or getBefore() will not return the last command - self.sshresponse = self.ssh.expect([prompt]) - else: - logging.error('logged in to ' + ipaddress + ' without password but IP is not found via ifconfig on remote host, aborting') + # We directly ended up on the remote server because of pubkey auth + count = 10 + connect_status = True + # this expect() seems to be necessary to advance the read buffer until the prompt, or getBefore() will not return the last command + self.sshresponse = self.ssh.expect([prompt]) else: # debug output logging.debug(str(self.ssh.before)) From 04251d5b06f4ab5abbe560905efac74e496a101c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 18 Jul 2022 17:39:52 +0200 Subject: [PATCH 49/61] Correctly initialize protocol_ctxt in F1 code In the previous version, not all fields, and in particular the `eNB_index`, were not initialized, leading to errors when they were used (e.g., the PDCP code checks that eNB_index == 0). --- openair2/RRC/NR/rrc_gNB.c | 63 ++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 43082003df..400be0bd4d 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -197,7 +197,7 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration } char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigurationReq *configuration) { - protocol_ctxt_t ctxt; + protocol_ctxt_t ctxt = { 0 }; gNB_RRC_INST *rrc=RC.nrrrc[gnb_mod_idP]; PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, gnb_mod_idP, GNB_FLAG_YES, NOT_A_RNTI, 0, 0,gnb_mod_idP); LOG_I(NR_RRC, @@ -3030,11 +3030,13 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC static int rrc_process_DU_DL(MessageDef *msg_p, const char *msg_name, instance_t instance) { NRDuDlReq_t * req=&NRDuDlReq(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = req->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; + protocol_ctxt_t ctxt = { + .rnti = req->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, ctxt.rnti); @@ -3285,11 +3287,13 @@ return 0; static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const char *msg_name, instance_t instance){ f1ap_ue_context_setup_t * req=&F1AP_UE_CONTEXT_SETUP_REQ(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = req->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; + protocol_ctxt_t ctxt = { + .rnti = req->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; gNB_MAC_INST *mac = RC.nrmac[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = @@ -3515,11 +3519,13 @@ static void rrc_DU_process_ue_context_setup_request(MessageDef *msg_p, const cha static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, const char *msg_name, instance_t instance){ f1ap_ue_context_setup_t * req=&F1AP_UE_CONTEXT_MODIFICATION_REQ(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = req->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; + protocol_ctxt_t ctxt = { + .rnti = req->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; gNB_MAC_INST *mac = RC.nrmac[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = @@ -3664,11 +3670,13 @@ static void rrc_DU_process_ue_context_modification_request(MessageDef *msg_p, co static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const char *msg_name, instance_t instance){ f1ap_ue_context_setup_t * resp=&F1AP_UE_CONTEXT_SETUP_RESP(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = resp->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; + protocol_ctxt_t ctxt = { + .rnti = resp->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, ctxt.rnti); NR_CellGroupConfig_t *cellGroupConfig = NULL; @@ -3721,12 +3729,13 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, const char *msg_name, instance_t instance){ f1ap_ue_context_setup_t * resp=&F1AP_UE_CONTEXT_SETUP_RESP(msg_p); - protocol_ctxt_t ctxt; - ctxt.rnti = resp->rnti; - ctxt.module_id = instance; - ctxt.instance = instance; - ctxt.enb_flag = 1; - ctxt.eNB_index = instance; + protocol_ctxt_t ctxt = { + .rnti = resp->rnti, + .module_id = instance, + .instance = instance, + .enb_flag = 1, + .eNB_index = instance + }; gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id]; struct rrc_gNB_ue_context_s *ue_context_p = rrc_gNB_get_ue_context(rrc, ctxt.rnti); NR_CellGroupConfig_t *cellGroupConfig = NULL; From 24b651b465f002d8814e20492fa0e8baf6766d1f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sun, 19 Jun 2022 17:31:57 +0200 Subject: [PATCH 50/61] Provide build_oai option UBSan --- cmake_targets/CMakeLists.txt | 6 ++++++ cmake_targets/build_oai | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 25e10931c7..6446ced4bd 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -271,6 +271,12 @@ if (SANITIZE_ADDRESS) # wrong in the pthread library, or something subtly wrong in this CMakeLists.txt. Use Ubuntu 20.04 instead. endif () +add_boolean_option(SANITIZE_UNDEFINED False "enable the undefined behavior sanitizer (UBSan)") +if (SANITIZE_UNDEFINED) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") +endif () + add_definitions("-DASN_DISABLE_OER_SUPPORT") ######################### diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 5a201fcfef..16a0d559dd 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -171,8 +171,12 @@ Options: Skip build for shared libraries to reduce compilation time when building frequently for debugging purposes --ninja Tell cmake to use the Ninja build system. Without, will generate make files +--sanitize + Shortcut for usage of --sanitize-address --sanitize-undefined --sanitize-address | -fsanitize=address - Enable the address sanitizer on all targets + Enable the address sanitizer on all targets +--sanitize-undefined | -fsanitize=undefined + Enable the undefined behavior sanitizer on all targets --ittiSIM Makes the itti simulator -h | --help @@ -451,10 +455,16 @@ function main() { CMAKE_CMD="$CMAKE_CMD -GNinja" MAKE_CMD=ninja shift;; + --sanitize) + CMAKE_CMD="$CMAKE_CMD -DSANITIZE_ADDRESS=True -DSANITIZE_UNDEFINED=True" + shift;; --sanitize-address | -fsanitize=address) grep -sq "Ubuntu 18.04" /etc/os-release && echo_error "Bug in OS with this option, see CMakeLists.txt" CMAKE_CMD="$CMAKE_CMD -DSANITIZE_ADDRESS=True" shift;; + --sanitize-undefined | -fundefined=address) + CMAKE_CMD="$CMAKE_CMD -DSANITIZE_UNDEFINED=True" + shift;; --ittiSIM) ittiSIM=1 CMAKE_CMD="$CMAKE_CMD -DITTI_SIM=True" From b07a167370d5a61fcdd2fd083b386be49ea80c2f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 24 May 2022 14:43:11 +0200 Subject: [PATCH 51/61] Correct indentation in nr_rx_pdsch() --- .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 145 +++++++++--------- 1 file changed, 72 insertions(+), 73 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index eb43d80525..6728f0260c 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -466,88 +466,87 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, if (cpumeas(CPUMEAS_GETSTATE)) LOG_D(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: Channel Combine and zero forcing %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); - start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); + start_meas(&ue->generic_stat_bis[proc->thread_id][slot]); /* Store the valid DL RE's */ - pdsch_vars[gNB_id]->dl_valid_re[symbol-1] = nb_re_pdsch; + pdsch_vars[gNB_id]->dl_valid_re[symbol-1] = nb_re_pdsch; - if(dlsch0_harq->status == ACTIVE) { - startSymbIdx = dlsch0_harq->start_symbol; - nbSymb = dlsch0_harq->nb_symbols; - pduBitmap = dlsch0_harq->pduBitmap; - } - if(dlsch1_harq) { - startSymbIdx = dlsch1_harq->start_symbol; - nbSymb = dlsch1_harq->nb_symbols; - pduBitmap = dlsch1_harq->pduBitmap; - } + if(dlsch0_harq->status == ACTIVE) { + startSymbIdx = dlsch0_harq->start_symbol; + nbSymb = dlsch0_harq->nb_symbols; + pduBitmap = dlsch0_harq->pduBitmap; + } + if(dlsch1_harq) { + startSymbIdx = dlsch1_harq->start_symbol; + nbSymb = dlsch1_harq->nb_symbols; + pduBitmap = dlsch1_harq->pduBitmap; + } - /* Check for PTRS bitmap and process it respectively */ - if((pduBitmap & 0x1) && (type == PDSCH)) { - nr_pdsch_ptrs_processing(ue, - pdsch_vars, - frame_parms, - dlsch0_harq, - dlsch1_harq, - gNB_id, - nr_slot_rx, - symbol, - (nb_rb_pdsch*12), - dlsch[0]->rnti,rx_type); - pdsch_vars[gNB_id]->dl_valid_re[symbol-1] -= pdsch_vars[gNB_id]->ptrs_re_per_slot[0][symbol]; - } + /* Check for PTRS bitmap and process it respectively */ + if((pduBitmap & 0x1) && (type == PDSCH)) { + nr_pdsch_ptrs_processing(ue, + pdsch_vars, + frame_parms, + dlsch0_harq, + dlsch1_harq, + gNB_id, + nr_slot_rx, + symbol, + (nb_rb_pdsch*12), + dlsch[0]->rnti,rx_type); + pdsch_vars[gNB_id]->dl_valid_re[symbol-1] -= pdsch_vars[gNB_id]->ptrs_re_per_slot[0][symbol]; + } - /* at last symbol in a slot calculate LLR's for whole slot */ - if(symbol == (startSymbIdx + nbSymb -1)) { - for(uint8_t i =startSymbIdx; i < (startSymbIdx+nbSymb);i++) { - /* re evaluating the first symbol flag as LLR's are done in symbol loop */ - if(i == startSymbIdx && i < 3) { - first_symbol_flag =1; - } - else { - first_symbol_flag=0; - } - /* Calculate LLR's for each symbol */ - nr_dlsch_llr(pdsch_vars, frame_parms, - rxdataF_comp_ptr, dl_ch_mag_ptr, - dlsch0_harq, dlsch1_harq, - rx_type, harq_pid, - gNB_id, gNB_id_i, - first_symbol_flag, - i, nb_rb_pdsch, - codeword_TB0, codeword_TB1, - pdsch_vars[gNB_id]->dl_valid_re[i-1], - nr_slot_rx, beamforming_mode); + /* at last symbol in a slot calculate LLR's for whole slot */ + if(symbol == (startSymbIdx + nbSymb -1)) { + for(uint8_t i =startSymbIdx; i < (startSymbIdx+nbSymb);i++) { + /* re evaluating the first symbol flag as LLR's are done in symbol loop */ + if(i == startSymbIdx && i < 3) { + first_symbol_flag =1; } - - int dmrs_type = dlsch[0]->harq_processes[harq_pid]->dmrsConfigType; - uint8_t nb_re_dmrs; - uint16_t dmrs_len = get_num_dmrs(dlsch[0]->harq_processes[harq_pid]->dlDmrsSymbPos); - if (dmrs_type==NFAPI_NR_DMRS_TYPE1) { - nb_re_dmrs = 6*dlsch[0]->harq_processes[harq_pid]->n_dmrs_cdm_groups; - } else { - nb_re_dmrs = 4*dlsch[0]->harq_processes[harq_pid]->n_dmrs_cdm_groups; + else { + first_symbol_flag=0; } - dlsch[0]->harq_processes[harq_pid]->G = nr_get_G(dlsch[0]->harq_processes[harq_pid]->nb_rb, - dlsch[0]->harq_processes[harq_pid]->nb_symbols, - nb_re_dmrs, - dmrs_len, - dlsch[0]->harq_processes[harq_pid]->Qm, - dlsch[0]->harq_processes[harq_pid]->Nl); - nr_dlsch_layer_demapping(pdsch_vars[gNB_id]->llr, - dlsch[0]->harq_processes[harq_pid]->Nl, - dlsch[0]->harq_processes[harq_pid]->Qm, - dlsch[0]->harq_processes[harq_pid]->G, - codeword_TB0, - codeword_TB1, - pdsch_vars[gNB_id]->layer_llr); - + /* Calculate LLR's for each symbol */ + nr_dlsch_llr(pdsch_vars, frame_parms, + rxdataF_comp_ptr, dl_ch_mag_ptr, + dlsch0_harq, dlsch1_harq, + rx_type, harq_pid, + gNB_id, gNB_id_i, + first_symbol_flag, + i, nb_rb_pdsch, + codeword_TB0, codeword_TB1, + pdsch_vars[gNB_id]->dl_valid_re[i-1], + nr_slot_rx, beamforming_mode); } - stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]); - if (cpumeas(CPUMEAS_GETSTATE)) - LOG_D(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: LLR Computation %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); + int dmrs_type = dlsch[0]->harq_processes[harq_pid]->dmrsConfigType; + uint8_t nb_re_dmrs; + uint16_t dmrs_len = get_num_dmrs(dlsch[0]->harq_processes[harq_pid]->dlDmrsSymbPos); + if (dmrs_type==NFAPI_NR_DMRS_TYPE1) { + nb_re_dmrs = 6*dlsch[0]->harq_processes[harq_pid]->n_dmrs_cdm_groups; + } else { + nb_re_dmrs = 4*dlsch[0]->harq_processes[harq_pid]->n_dmrs_cdm_groups; + } + dlsch[0]->harq_processes[harq_pid]->G = nr_get_G(dlsch[0]->harq_processes[harq_pid]->nb_rb, + dlsch[0]->harq_processes[harq_pid]->nb_symbols, + nb_re_dmrs, + dmrs_len, + dlsch[0]->harq_processes[harq_pid]->Qm, + dlsch[0]->harq_processes[harq_pid]->Nl); + nr_dlsch_layer_demapping(pdsch_vars[gNB_id]->llr, + dlsch[0]->harq_processes[harq_pid]->Nl, + dlsch[0]->harq_processes[harq_pid]->Qm, + dlsch[0]->harq_processes[harq_pid]->G, + codeword_TB0, + codeword_TB1, + pdsch_vars[gNB_id]->layer_llr); + } -// Please keep it: useful for debugging + stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]); + if (cpumeas(CPUMEAS_GETSTATE)) + LOG_D(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d: LLR Computation %5.2f \n",frame,nr_slot_rx,slot,symbol,ue->generic_stat_bis[proc->thread_id][slot].p_time/(cpuf*1000.0)); + + // Please keep it: useful for debugging #ifdef DEBUG_PDSCH_RX char filename[50]; uint8_t aa = 0; From 6b757c53209bbffa4b3eb58d1d61948969b09037 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 24 May 2022 14:43:49 +0200 Subject: [PATCH 52/61] Correct array sizes in dlsim --- openair1/SIMULATION/LTE_PHY/dlsim.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 231d63cf04..d715423bb1 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -512,12 +512,12 @@ int main(int argc, char **argv) { int re; int s,Kr,Kr_bytes; LTE_DL_FRAME_PARMS *frame_parms; - double s_re0[30720*2],s_im0[30720*2],r_re0[30720*2],r_im0[30720*2]; - double s_re1[30720*2],s_im1[30720*2],r_re1[30720*2],r_im1[30720*2]; - double *s_re[2]= {s_re0,s_re1}; - double *s_im[2]= {s_im0,s_im1}; - double *r_re[2]= {r_re0,r_re1}; - double *r_im[2]= {r_im0,r_im1}; + double s_re0[30720*NB_ANTENNAS_TX],s_im0[30720*NB_ANTENNAS_TX],r_re0[30720*NB_ANTENNAS_RX],r_im0[30720*NB_ANTENNAS_RX]; + double s_re1[30720*NB_ANTENNAS_TX],s_im1[30720*NB_ANTENNAS_TX],r_re1[30720*NB_ANTENNAS_RX],r_im1[30720*NB_ANTENNAS_RX]; + double *s_re[NB_ANTENNAS_TX]= {s_re0,s_re1}; + double *s_im[NB_ANTENNAS_TX]= {s_im0,s_im1}; + double *r_re[NB_ANTENNAS_RX]= {r_re0,r_re1}; + double *r_im[NB_ANTENNAS_RX]= {r_im0,r_im1}; uint8_t transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=2; int eNB_id = 0; unsigned char round; From db7f39ba19e10ec27d05673ab1f1a6a518327af8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 24 May 2022 14:47:30 +0200 Subject: [PATCH 53/61] Use correct structure in sctp_eNB_accept_associations() --- openair3/SCTP/sctp_eNB_task.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index 06e606e36b..df6dde0f99 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -859,7 +859,7 @@ sctp_eNB_accept_associations( struct sctp_cnx_list_elm_s *sctp_cnx) { int client_sd; - struct sockaddr saddr; + struct sockaddr_in6 saddr; socklen_t saddr_size; DevAssert(sctp_cnx != NULL); @@ -868,14 +868,14 @@ sctp_eNB_accept_associations( /* There is a new client connecting. Accept it... */ - if ((client_sd = accept(sctp_cnx->sd, &saddr, &saddr_size)) < 0) { + if ((client_sd = accept(sctp_cnx->sd, (struct sockaddr*)&saddr, &saddr_size)) < 0) { SCTP_ERROR("[%d] accept failed: %s:%d\n", sctp_cnx->sd, strerror(errno), errno); } else { struct sctp_cnx_list_elm_s *new_cnx; uint16_t port; /* This is an ipv6 socket */ - port = ((struct sockaddr_in6*)&saddr)->sin6_port; + port = saddr.sin6_port; /* Contrary to BSD, client socket does not inherit O_NONBLOCK option */ if (fcntl(client_sd, F_SETFL, O_NONBLOCK) < 0) { From 017fd225bcd0716b1856be1584438e7b4c64a3b8 Mon Sep 17 00:00:00 2001 From: laurent Date: Sun, 29 May 2022 14:27:51 +0200 Subject: [PATCH 54/61] fix ubsan detected errors --- common/utils/time_meas.h | 4 +- .../nfapi/public_inc/fapi_nr_ue_interface.h | 2 +- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 2 +- .../CODING/3gpplte_turbo_decoder_sse_8bit.c | 6 +- openair1/PHY/CODING/crc_byte.c | 4 +- .../PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h | 45 ++++--- openair1/PHY/LTE_TRANSPORT/dci_tools_common.c | 116 +++++++++--------- openair1/PHY/LTE_TRANSPORT/dlsch_coding.c | 2 +- .../PHY/LTE_UE_TRANSPORT/transport_proto_ue.h | 8 -- openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h | 2 +- openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c | 47 +++---- openair1/PHY/MODULATION/nr_modulation.c | 7 +- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 5 +- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 3 +- openair1/SIMULATION/LTE_PHY/dlsim.c | 16 ++- openair1/SIMULATION/LTE_PHY/ulsim.c | 14 +-- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- openair2/LAYER2/NR_MAC_UE/config_ue.c | 4 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 7 -- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 22 ++-- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 44 ++++--- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 2 + openair2/RRC/NR_UE/rrc_UE.c | 4 +- 26 files changed, 191 insertions(+), 183 deletions(-) diff --git a/common/utils/time_meas.h b/common/utils/time_meas.h index fded7f1a9c..eb81d09434 100644 --- a/common/utils/time_meas.h +++ b/common/utils/time_meas.h @@ -62,7 +62,7 @@ typedef struct time_stats { oai_cputime_t in; /*!< \brief time at measure starting point */ oai_cputime_t diff; /*!< \brief average difference between time at starting point and time at endpoint*/ oai_cputime_t p_time; /*!< \brief absolute process duration */ - oai_cputime_t diff_square; /*!< \brief process duration square */ + double diff_square; /*!< \brief process duration square */ oai_cputime_t max; /*!< \brief maximum difference between time at starting point and time at endpoint*/ int trials; /*!< \brief number of start point - end point iterations */ int meas_flag; /*!< \brief 1: stop_meas not called (consecutive calls of start_meas) */ @@ -156,7 +156,7 @@ static inline void stop_meas(time_stats_t *ts) { ts->diff += (out-ts->in); /// process duration is the difference between two clock points ts->p_time = (out-ts->in); - ts->diff_square += (out-ts->in)*(out-ts->in); + ts->diff_square += ((double)out-ts->in)*((double)out-ts->in); if ((out-ts->in) > ts->max) ts->max = out-ts->in; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index fd9af01720..10f881bae6 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -87,7 +87,7 @@ typedef struct { // N_CCE is L, or number of CCEs for DCI int N_CCE; uint8_t payloadSize; - uint8_t payloadBits[16]; + uint8_t payloadBits[16] __attribute__((aligned(16))); // will be cast as uint64 //fapi_nr_dci_pdu_rel15_t dci; } fapi_nr_dci_indication_pdu_t; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 8b564a5e37..0e393066c8 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -738,7 +738,7 @@ typedef struct { // The total DCI length (in bits) including padding bits [TS38.212 sec 7.3.1] Range 0->DCI_PAYLOAD_BYTE_LEN*8 uint16_t PayloadSizeBits; // DCI payload, where the actual size is defined by PayloadSizeBits. The bit order is as following bit0-bit7 are mapped to first byte of MSB - LSB - uint8_t Payload[DCI_PAYLOAD_BYTE_LEN]; + uint8_t Payload[DCI_PAYLOAD_BYTE_LEN] __attribute__((aligned(32))); } nfapi_nr_dl_dci_pdu_t; diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index 264b25deca..af02a16054 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -814,7 +814,7 @@ uint8_t phy_threegpplte_turbo_decoder8(int16_t *y, llr_t *s1,*s2,*yp1,*yp2,*yp; unsigned int i,j,iind;//,pi; unsigned char iteration_cnt=0; - unsigned int crc,oldcrc,crc_len; + unsigned int crc, crc_len; uint8_t temp; #if defined(__x86_64__) || defined(__i386__) __m128i *yp128; @@ -1233,8 +1233,8 @@ uint8_t phy_threegpplte_turbo_decoder8(int16_t *y, } // check the CRC - oldcrc= *((unsigned int *)(&decoded_bytes[(n>>3)-crc_len])); - + uint32_t oldcrc; + memcpy(&oldcrc, &decoded_bytes[(n >> 3) - crc_len], crc_len); switch (crc_type) { case CRC24_A: oldcrc&=0x00ffffff; diff --git a/openair1/PHY/CODING/crc_byte.c b/openair1/PHY/CODING/crc_byte.c index 9ad18cc1a6..471b26fe24 100644 --- a/openair1/PHY/CODING/crc_byte.c +++ b/openair1/PHY/CODING/crc_byte.c @@ -244,11 +244,11 @@ crc16 (unsigned char * inptr, int bitlen) while (octetlen-- > 0) { - crc = (crc << 8) ^ (crc16Table[(*inptr++) ^ (crc >> 24)] << 16); + crc = (crc << 8) ^ (((uint32_t)crc16Table[(*inptr++) ^ (crc >> 24)]) << 16); } if (resbit > 0) - crc = (crc << resbit) ^ (crc16Table[((*inptr) >> (8 - resbit)) ^ (crc >> (32 - resbit))] << 16); + crc = (crc << resbit) ^ (((uint32_t)crc16Table[(*inptr) >> (8 - resbit) ^ (crc >> (32 - resbit))]) << 16); return crc; } diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h index f4ea4a9434..f792f993e9 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_cnProc.h @@ -961,7 +961,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1028,7 +1029,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1096,7 +1098,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1163,7 +1166,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1230,7 +1234,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1297,7 +1302,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1364,7 +1370,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1431,7 +1438,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1498,7 +1506,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG1(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1593,7 +1602,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1660,7 +1670,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1727,7 +1738,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1794,7 +1806,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1861,7 +1874,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) @@ -1928,7 +1942,8 @@ static inline uint32_t nrLDPC_cnProcPc_BG2(t_nrLDPC_lut* p_lut, int8_t* cnProcBu // If no error pcRes should be 0 // Only use valid CNs - pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); + if (Mrem) + pcResSum |= (pcRes&(0xFFFFFFFF>>(32-Mrem))); // If PC failed we can stop here if (pcResSum > 0) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c index 64e74ebfbf..cb2f190384 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c @@ -562,9 +562,9 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { case 15: if (vrb<12) { if ((vrb&3) < 2) // even: 0->0, 1->4, 4->1, 5->5, 8->2, 9->6 odd: 0->7, 1->11 - return(((7*odd_slot) + 4*(vrb&3) + (vrb>>2))%14) + 14*(vrb/14); + return(((7*odd_slot) + 4*(vrb&3) + (vrb>>2))%14) + 14*(vrb/14); else if (vrb < 12) // even: 2->7, 3->11, 6->8, 7->12, 10->9, 11->13 - return (((7*odd_slot) + 4*(vrb&3) + (vrb>>2) +13 )%14) + 14*(vrb/14); + return (((7*odd_slot) + 4*(vrb&3) + (vrb>>2) +13 )%14) + 14*(vrb/14); } if (vrb==12) return (3+(7*odd_slot)) % 14; @@ -573,6 +573,8 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { return 14; break; + // Formula in TS 36.211, chap 6.2.3.2 + // Fix me: returns a PRB number > 24 when vrb is 24 case 25: return (((12*odd_slot) + 6*(vrb&3) + (vrb>>2))%24) + 24*(vrb/24); break; @@ -581,43 +583,44 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { if (Ngap==0) { // Nrow=12,Nnull=2,NVRBDL=46,Ngap1= 27 if (vrb>=23) - offset=4; + offset=4; else - offset=0; + offset=0; if (vrb<44) { - if ((vrb&3)>=2) - return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2) + 45)%46; - else - return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2))%46; + if ((vrb&3)>=2) + return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2) + 45)%46; + else + return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2))%46; } if (vrb==44) // even: 44->11, odd: 45->34 - return offset+((23*odd_slot) + 22-12+1); + return offset+((23*odd_slot) + 22-12+1); if (vrb==45) // even: 45->10, odd: 45->33 - return offset+((23*odd_slot) + 22+12); + return offset+((23*odd_slot) + 22+12); if (vrb==46) - return offset+46+((23*odd_slot) + 23-12+1) % 46; + return offset+46+((23*odd_slot) + 23-12+1) % 46; if (vrb==47) - return offset+46+((23*odd_slot) + 23+12) % 46; + return offset+46+((23*odd_slot) + 23+12) % 46; if (vrb==48) - return offset+46+((23*odd_slot) + 23-12+1) % 46; + return offset+46+((23*odd_slot) + 23-12+1) % 46; if (vrb==49) - return offset+46+((23*odd_slot) + 23+12) % 46; + return offset+46+((23*odd_slot) + 23+12) % 46; } else { // Nrow=6,Nnull=6,NVRBDL=18,Ngap1= 27 if (vrb>=9) - offset=18; + offset=18; else - offset=0; + offset=0; if (vrb<12) { - if ((vrb&3)>=2) - return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2) + 17)%18; - else - return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2))%18; + if ((vrb&3)>=2) + return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2) + 17)%18; + else + return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2))%18; } else { - return offset+((9*odd_slot) + 12*(vrb&1)+(vrb>>1) )%18 + 18*(vrb/18); + // Same issue as for 25 PRB: returns larger than 0..49 + return ((9*odd_slot) + 12*(vrb&1) + (vrb>>1))%18 + 18*(vrb/18); } } break; @@ -677,7 +680,7 @@ void generate_RIV_tables(void) // printf("RIV %d (%d) : first_rb %d NBRB %d\n",RIV,localRIV2alloc_LUT25[RIV],RBstart,Lcrbs); localRIV2alloc_LUT6[RIV] = alloc0; - distRIV2alloc_even_LUT6[RIV] = allocdist0_0_even; + distRIV2alloc_even_LUT6[RIV] = allocdist0_0_even; distRIV2alloc_odd_LUT6[RIV] = allocdist0_0_odd; RIV2nb_rb_LUT6[RIV] = Lcrbs; RIV2first_rb_LUT6[RIV] = RBstart; @@ -693,15 +696,14 @@ void generate_RIV_tables(void) nVRB = Lcrbs-1+RBstart; //printf("RBstart %d, len %d --> ",RBstart,Lcrbs); alloc0 |= (1<RIV_max25) - RIV_max25 = RIV;; - + RIV_max25 = RIV; localRIV2alloc_LUT25[RIV] = alloc0; distRIV2alloc_even_LUT25[RIV] = allocdist0_0_even; @@ -730,37 +732,37 @@ void generate_RIV_tables(void) if (nVRB<32) - alloc0 |= (1< nVRB_even_dist %d\n",nVRB,nVRB_even_dist); - if (nVRB_even_dist<32) - allocdist0_0_even |= (1<(%08x.%08x.%08x.%08x)\n", allocdist0_0_even, @@ -845,38 +846,37 @@ void generate_RIV_tables(void) // Distributed Gap1, odd slot nVRB_odd_dist = get_prb(100,1,nVRB,0); if (nVRB_odd_dist<32) - allocdist0_0_odd |= (1<dlsch->harq_processes[harq_pid]; if ( rdata-> round == 0) { - uint8_t tmp[96+12+3+3*6144]; + uint8_t tmp[96+12+3+3*6144] __attribute__((aligned(32))); memset(tmp,LTE_NULL, TURBO_SIMD_SOFTBITS); start_meas(rdata->te_stats); encoder(rdata->input, diff --git a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h index f5b8c6b64a..36da4ccab0 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h +++ b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h @@ -1272,14 +1272,6 @@ uint32_t get_TBS_DL(uint8_t mcs, uint16_t nb_rb); @return Transport block size */ uint32_t get_TBS_UL(uint8_t mcs, uint16_t nb_rb); -/* \brief Return bit-map of resource allocation for a given DCI rballoc (RIV format) and vrb type - @param N_RB_DL number of PRB on DL - @param indicator for even/odd slot - @param vrb vrb index - @param Ngap Gap indicator -*/ -uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap); - /* \brief Return prb for a given vrb index @param vrb_type VRB type (0=localized,1=distributed) @param rb_alloc_dci rballoc field from DCI diff --git a/openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h b/openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h index b4ae44f6ea..5f8763414e 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h +++ b/openair1/PHY/LTE_UE_TRANSPORT/transport_ue.h @@ -90,7 +90,7 @@ typedef struct { /// Redundancy-version of the current sub-frame uint8_t rvidx; /// Turbo-code outputs (36-212 V8.6 2009-03, p.12 - uint8_t d[MAX_NUM_ULSCH_SEGMENTS][(96+3+(3*6144))]; + uint8_t *d[MAX_NUM_ULSCH_SEGMENTS]; /// Sub-block interleaver outputs (36-212 V8.6 2009-03, p.16-17) uint8_t w[MAX_NUM_ULSCH_SEGMENTS][3*6144]; /// Number of code segments (for definition see 36-212 V8.6 2009-03, p.9) diff --git a/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c b/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c index ae3ebbce9d..c04ec160aa 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/ulsch_coding.c @@ -71,6 +71,7 @@ void free_ue_ulsch(LTE_UE_ULSCH_t *ulsch) { for (r=0; rharq_processes[i]->c[r]) { free16(ulsch->harq_processes[i]->c[r],((r==0)?8:0) + 3+768); + free16(ulsch->harq_processes[i]->d[r],0); ulsch->harq_processes[i]->c[r] = NULL; } } @@ -86,7 +87,7 @@ void free_ue_ulsch(LTE_UE_ULSCH_t *ulsch) { LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag) { LTE_UE_ULSCH_t *ulsch; - unsigned char exit_flag = 0,i,j,r; + unsigned char exit_flag = 0; unsigned char bw_scaling =1; switch (N_RB_UL) { @@ -113,7 +114,7 @@ LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag) { memset(ulsch,0,sizeof(LTE_UE_ULSCH_t)); ulsch->Mlimit = 4; - for (i=0; i<8; i++) { + for (int i=0; i<8; i++) { ulsch->harq_processes[i] = (LTE_UL_UE_HARQ_t *)malloc16(sizeof(LTE_UL_UE_HARQ_t)); // printf("ulsch->harq_processes[%d] %p\n",i,ulsch->harq_processes[i]); @@ -129,15 +130,11 @@ LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag) { } if (abstraction_flag==0) { - for (r=0; rharq_processes[i]->c[r] = (unsigned char *)malloc16(((r==0)?8:0) + 3+768); // account for filler in first segment and CRCs for multiple segment case - - if (ulsch->harq_processes[i]->c[r]) - memset(ulsch->harq_processes[i]->c[r],0,((r==0)?8:0) + 3+768); - else { - LOG_E(PHY,"Can't get c\n"); - exit_flag=2; - } + for (int r=0; rharq_processes[i]->c[r] = malloc16_clear(((r==0)?8:0) + 3+768); // account for filler in first segment and CRCs for multiple segment case + AssertFatal(ulsch->harq_processes[i]->c[r], ""); + ulsch->harq_processes[i]->d[r] = malloc16_clear(96+3+(3*6144)); + AssertFatal(ulsch->harq_processes[i]->d[r], ""); } } @@ -148,15 +145,7 @@ LTE_UE_ULSCH_t *new_ue_ulsch(unsigned char N_RB_UL, uint8_t abstraction_flag) { exit_flag=3; } } - - if ((abstraction_flag == 0) && (exit_flag==0)) { - for (i=0; i<8; i++) - for (j=0; j<96; j++) - for (r=0; rharq_processes[i]->d[r][j] = LTE_NULL; - - return(ulsch); - } else if (abstraction_flag==1) + if (!exit_flag) return(ulsch); } @@ -191,7 +180,7 @@ uint32_t ulsch_encoding(uint8_t *a, uint32_t Qprime_ACK=0,Qprime_CQI=0,Qprime_RI=0,len_ACK=0,len_RI=0; // uint32_t E; uint8_t ack_parity; - uint32_t i,q,j,iprime,j2; + uint32_t q,j,iprime,j2; uint16_t o_RCC; uint8_t o_flip[8]; uint32_t wACK_idx; @@ -327,6 +316,8 @@ uint32_t ulsch_encoding(uint8_t *a, #endif // offset=0; start_meas(te_stats); + for (int z=0; z<96; z++) + ulsch->harq_processes[harq_pid]->d[r][z] = LTE_NULL; encoder(ulsch->harq_processes[harq_pid]->c[r], Kr>>3, &ulsch->harq_processes[harq_pid]->d[r][96], @@ -539,8 +530,6 @@ uint32_t ulsch_encoding(uint8_t *a, ulsch->q); } - i=0; - // Do RI coding if (ulsch->O_RI == 1) { switch (Q_m) { @@ -691,7 +680,7 @@ uint32_t ulsch_encoding(uint8_t *a, j=0; - for (i=0; i>2); for (q=0; q>2); for (q=0; qh[j++] = *yptr++; @@ -818,7 +807,7 @@ uint32_t ulsch_encoding(uint8_t *a, break; case 4: - for (i=0; ih[j++] = *yptr++; @@ -830,7 +819,7 @@ uint32_t ulsch_encoding(uint8_t *a, break; case 6: - for (i=0; ih[j++] = *yptr++; diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c index 8ebd70fb92..1b5c4f4af0 100644 --- a/openair1/PHY/MODULATION/nr_modulation.c +++ b/openair1/PHY/MODULATION/nr_modulation.c @@ -226,10 +226,11 @@ void nr_modulation(uint32_t *in, i *= 24; bit_cnt = i * 8; while (bit_cnt < length) { - x = *((uint32_t*)(in_bytes+i)); - x1 = x&4095; + uint32_t xx; + memcpy(&xx, in_bytes+i, sizeof(xx)); + x1 = xx & 4095; out64[j++] = nr_64qam_mod_table[x1]; - x1 = (x>>12)&4095; + x1 = (xx >> 12) & 4095; out64[j++] = nr_64qam_mod_table[x1]; i += 3; bit_cnt += 24; diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index fb56322e54..93bd9587a0 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -119,7 +119,7 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB,int slot, int first_symb,int num_symb measurements->n0_subband_power[aarx][rb]=0; } int offset0 = (slot&3)*(frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size) + (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size; - if ((gNB->rb_mask_ul[s][rb>>5]&(1<<(rb&31))) == 0) { // check that rb was not used in this subframe + if ((gNB->rb_mask_ul[s][rb >> 5] & (1U << (rb & 31))) == 0) { // check that rb was not used in this subframe nb_symb[rb]++; for (int aarx=0; aarxnb_antennas_rx; aarx++) { int offset = offset0 + (s*frame_parms->ofdm_symbol_size); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index d32fd77b03..30dbc39185 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -123,7 +123,6 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, rel15->dlDmrsSymbPos); n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1)/rel15->PTRSFreqDensity; } - int16_t mod_ptrs[n_ptrs<<1] __attribute__ ((aligned(16))); /// CRC, coding, interleaving and rate matching AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n"); @@ -302,12 +301,14 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, /* calculate if current symbol is PTRS symbols */ ptrs_idx = 0; - + int16_t *mod_ptrs = NULL; if(rel15->pduBitmap & 0x1) { ptrs_symbol = is_ptrs_symbol(l,dlPtrsSymPos); if(ptrs_symbol) { /* PTRS QPSK Modulation for each OFDM symbol in a slot */ LOG_D(PHY,"Doing ptrs modulation for symbol %d, n_ptrs %d\n",l,n_ptrs); + int16_t mod_ptrsBuf[n_ptrs<<1] __attribute__ ((aligned(16))); + mod_ptrs =mod_ptrsBuf; nr_modulation(pdsch_dmrs[l][rel15->SCID], (n_ptrs<<1), DMRS_MOD_ORDER, mod_ptrs); } } diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1428987d40..5c44bde4fe 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -569,7 +569,7 @@ void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) { LOG_D(PHY,"symbol %d Filling rb_mask_ul rb_size %d\n",symbol,ulsch_harq->ulsch_pdu.rb_size); for (rb=0; rbulsch_pdu.rb_size; rb++) { rb2 = rb+ulsch_harq->ulsch_pdu.rb_start+ulsch_harq->ulsch_pdu.bwp_start; - gNB->rb_mask_ul[symbol][rb2>>5] |= (1<<(rb2&31)); + gNB->rb_mask_ul[symbol][rb2 >> 5] |= 1U << (rb2 & 31); } } } diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index d366ae9ec1..38fa3880bb 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -1321,8 +1321,7 @@ int is_ssb_in_slot(fapi_nr_config_request_t *config, int frame, int slot, NR_DL_ //uint8_t half_frame_index = fp->half_frame_bit; //uint8_t i_ssb = fp->ssb_index; uint8_t Lmax = fp->Lmax; - - if (!(frame%(1<<(config->ssb_table.ssb_period-1)))){ + if ((config->ssb_table.ssb_period > 0) && !(frame % (1 << (config->ssb_table.ssb_period - 1)))) { if(Lmax <= 8) { if(slot <=3 && (((config->ssb_table.ssb_mask_list[0].ssb_mask << 2*slot)&0x80000000) == 0x80000000 || ((config->ssb_table.ssb_mask_list[0].ssb_mask << (2*slot +1))&0x80000000) == 0x80000000)) diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index d715423bb1..8aff47c86b 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -512,12 +512,16 @@ int main(int argc, char **argv) { int re; int s,Kr,Kr_bytes; LTE_DL_FRAME_PARMS *frame_parms; - double s_re0[30720*NB_ANTENNAS_TX],s_im0[30720*NB_ANTENNAS_TX],r_re0[30720*NB_ANTENNAS_RX],r_im0[30720*NB_ANTENNAS_RX]; - double s_re1[30720*NB_ANTENNAS_TX],s_im1[30720*NB_ANTENNAS_TX],r_re1[30720*NB_ANTENNAS_RX],r_im1[30720*NB_ANTENNAS_RX]; - double *s_re[NB_ANTENNAS_TX]= {s_re0,s_re1}; - double *s_im[NB_ANTENNAS_TX]= {s_im0,s_im1}; - double *r_re[NB_ANTENNAS_RX]= {r_re0,r_re1}; - double *r_im[NB_ANTENNAS_RX]= {r_im0,r_im1}; + double *tmpTX[4], *tmpRX[4] ; + for (int i = 0; i < 4; i++) { + tmpTX[i] = malloc(30720 * NB_ANTENNAS_TX * sizeof(*tmpTX)); + tmpRX[i] = malloc(30720 * NB_ANTENNAS_RX * sizeof(*tmpRX)); + } + double *s_re[NB_ANTENNAS_TX] = {tmpTX[0], tmpTX[1]}; + double *s_im[NB_ANTENNAS_TX] = {tmpTX[2], tmpTX[3]}; + double *r_re[NB_ANTENNAS_RX] = {tmpRX[0], tmpRX[1]}; + double *r_im[NB_ANTENNAS_RX] = {tmpRX[2], tmpRX[3]}; + uint8_t transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=2; int eNB_id = 0; unsigned char round; diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index 0843d00ffd..0f98eb337a 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -358,7 +358,7 @@ int main(int argc, char **argv) { unsigned short input_buffer_length; unsigned int ret; unsigned int coded_bits_per_codeword,nsymb; - unsigned int tx_lev=0,tx_lev_dB=0,trials,errs[5]= {0,0,0,0,0},round_trials[4]= {0,0,0,0}; + unsigned int tx_lev = 0, tx_lev_dB = 0, trials, errs[6] = {0}, round_trials[4] = {0}; FILE *bler_fd=NULL; char bler_fname[512]; FILE *time_meas_fd=NULL; @@ -387,7 +387,6 @@ int main(int argc, char **argv) { double cpu_freq_GHz; int iter_trials; uint32_t UL_alloc_pdu; - int s,Kr,Kr_bytes; int dump_perf=0; static int dump_table =0; double effective_rate=0.0; @@ -1233,20 +1232,21 @@ int main(int argc, char **argv) { if (n_frames==1) { printf("ULSCH errors found o_ACK[0]= %d\n",eNB->ulsch[0]->harq_processes[harq_pid]->o_ACK[0]); - +#ifdef DUMP_EACH_VALUE + int Kr_bytes; for (s=0; sulsch[0]->harq_processes[harq_pid]->C; s++) { if (sulsch[0]->harq_processes[harq_pid]->Cminus) - Kr = eNB->ulsch[0]->harq_processes[harq_pid]->Kminus; + Kr_bytes = eNB->ulsch[0]->harq_processes[harq_pid]->Kminus; else - Kr = eNB->ulsch[0]->harq_processes[harq_pid]->Kplus; - - Kr_bytes = Kr>>3; + Kr_bytes = eNB->ulsch[0]->harq_processes[harq_pid]->Kplus; + Kr_bytes = Kr_bytes >> 3; printf("Decoded_output (Segment %d):\n",s); for (i=0; iulsch[0]->harq_processes[harq_pid]->c[s][i], eNB->ulsch[0]->harq_processes[harq_pid]->c[s][i]^UE->ulsch[0]->harq_processes[harq_pid]->c[s][i]); } +#endif dump_ulsch(eNB,eNB->proc.frame_rx,subframe,0,round); round=5; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 78b253ca2a..8500749fe2 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -1142,7 +1142,7 @@ int main(int argc, char **argv) Sched_INFO.frame = frame; Sched_INFO.slot = slot; Sched_INFO.DL_req = &gNB_mac->DL_req[0]; - Sched_INFO.UL_tti_req = gNB_mac->UL_tti_req_ahead[slot]; + Sched_INFO.UL_tti_req = gNB_mac->UL_tti_req_ahead[0]; Sched_INFO.UL_dci_req = NULL; Sched_INFO.TX_req = &gNB_mac->TX_req[0]; pushNotifiedFIFO(gNB->L1_tx_free,msgL1Tx); diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 072f0e58de..2804a9ec1e 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -190,7 +190,7 @@ void config_common_ue_sa(NR_UE_MAC_INST_t *mac, cfg->ssb_table.ssb_subcarrier_offset = mac->ssb_subcarrier_offset; if (mac->frequency_range == FR1){ - cfg->ssb_table.ssb_mask_list[0].ssb_mask = scc->ssb_PositionsInBurst.inOneGroup.buf[0]<<24; + cfg->ssb_table.ssb_mask_list[0].ssb_mask = ((uint32_t) scc->ssb_PositionsInBurst.inOneGroup.buf[0]) << 24; cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0; } else{ @@ -353,7 +353,7 @@ void config_common_ue(NR_UE_MAC_INST_t *mac, cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0; break; case 2 : - cfg->ssb_table.ssb_mask_list[0].ssb_mask = scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]<<24; + cfg->ssb_table.ssb_mask_list[0].ssb_mask = ((uint32_t) scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]) << 24; cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0; break; case 3 : diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 38f774be76..aa68791466 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -257,13 +257,6 @@ void get_bwp_info(NR_UE_MAC_INST_t *mac, NR_BWP_DownlinkCommon_t *get_bwp_downlink_common(NR_UE_MAC_INST_t *mac, NR_BWP_Id_t dl_bwp_id); -uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, - uint8_t dci_format, - uint8_t dci_length, - uint16_t rnti, - uint64_t *dci_pdu, - dci_pdu_rel15_t *nr_pdci_info_extracted); - NR_PUSCH_TimeDomainResourceAllocationList_t *choose_ul_tda_list(const NR_PUSCH_Config_t *pusch_Config,NR_PUSCH_ConfigCommon_t *pusch_ConfigCommon); NR_PDSCH_TimeDomainResourceAllocationList_t *choose_dl_tda_list(NR_PDSCH_Config_t *pdsch_Config,NR_PDSCH_ConfigCommon_t *pdsch_ConfigCommon); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 6166fc7038..ccb1b4e72a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -134,6 +134,13 @@ const initial_pucch_resource_t initial_pucch_resource[16] = { }; +static uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, + uint8_t dci_format, + uint8_t dci_length, + uint16_t rnti, + uint64_t *dci_pdu, + dci_pdu_rel15_t *nr_pdci_info_extracted); + void nr_ue_init_mac(module_id_t module_idP) { int i; @@ -985,7 +992,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr if (dci->tpc == 3) dlsch_config_pdu_1_0->accumulated_delta_PUCCH = 3; // Sanity check for pucch_resource_indicator value received to check for false DCI. valid = 0; - if (mac->ULbwp[ul_bwp_id-1] && + if (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id-1] && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pucch_Config && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup&& @@ -1512,13 +1520,12 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, NR_BWP_UplinkCommon_t *initialUplinkBWP; if (mac->scc) initialUplinkBWP = mac->scc->uplinkConfigCommon->initialUplinkBWP; else initialUplinkBWP = &mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP; - NR_BWP_Uplink_t *ubwp = mac->ULbwp[bwp_id-1]; - if (mac->cg && ubwp && + if (mac->cg && bwp_id > 1 && mac->ULbwp[bwp_id - 1] && mac->cg->spCellConfig && mac->cg->spCellConfig->spCellConfigDedicated && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { - scs = ubwp->bwp_Common->genericParameters.subcarrierSpacing; + scs = mac->ULbwp[bwp_id - 1]->bwp_Common->genericParameters.subcarrierSpacing; } else scs = initialUplinkBWP->genericParameters.subcarrierSpacing; @@ -2340,17 +2347,16 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, NR_BWP_Id_t bwp_id = mac->UL_BWP_Id; NR_PUCCH_Config_t *pucch_Config = NULL; int scs; - NR_BWP_Uplink_t *ubwp = mac->ULbwp[bwp_id-1]; NR_BWP_UplinkCommon_t *initialUplinkBWP; if (mac->scc) initialUplinkBWP = mac->scc->uplinkConfigCommon->initialUplinkBWP; else initialUplinkBWP = &mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP; - if (mac->cg && ubwp && + if (mac->cg && bwp_id && mac->ULbwp[bwp_id - 1] && mac->cg->spCellConfig && mac->cg->spCellConfig->spCellConfigDedicated && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig && mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) { - scs = ubwp->bwp_Common->genericParameters.subcarrierSpacing; + scs = mac->ULbwp[bwp_id - 1]->bwp_Common->genericParameters.subcarrierSpacing; } else scs = initialUplinkBWP->genericParameters.subcarrierSpacing; @@ -2732,7 +2738,7 @@ int get_n_rb(NR_UE_MAC_INST_t *mac, int rnti_type){ } -uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, +static uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, uint8_t dci_format, uint8_t dci_size, uint16_t rnti, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index f6a42ccaab..49b8e3d05f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -118,12 +118,13 @@ long get_k2(NR_UE_MAC_INST_t *mac, uint8_t time_domain_ind) { NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; // Get K2 from RRC configuration - NR_PUSCH_Config_t *pusch_config=mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : NULL; + NR_PUSCH_Config_t *pusch_config= ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : NULL; NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL; if (pusch_config && pusch_config->pusch_TimeDomainAllocationList) { pusch_TimeDomainAllocationList = pusch_config->pusch_TimeDomainAllocationList->choice.setup; } - else if (mac->ULbwp[ul_bwp_id-1] && + else if (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id-1] && mac->ULbwp[ul_bwp_id-1]->bwp_Common&& mac->ULbwp[ul_bwp_id-1]->bwp_Common->pusch_ConfigCommon&& mac->ULbwp[ul_bwp_id-1]->bwp_Common->pusch_ConfigCommon->choice.setup && @@ -169,7 +170,7 @@ fapi_nr_ul_config_request_t *get_ul_config_request(NR_UE_MAC_INST_t *mac, int sl // Calculate the index of the UL slot in mac->ul_config_request list. This is // based on the TDD pattern (slot configuration period) and number of UL+mixed // slots in the period. TS 38.213 Sec 11.1 - int mu = mac->ULbwp[ul_bwp_id-1] ? + int mu = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Common->genericParameters.subcarrierSpacing : mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.genericParameters.subcarrierSpacing; const int n = nr_slots_per_frame[mu]; @@ -205,7 +206,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con srs_config = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP->srs_Config->choice.setup; } - NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[ul_bwp_id-1] ? + NR_PUSCH_Config_t *pusch_Config = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : (ubwpd? ubwpd->pusch_Config->choice.setup: @@ -361,7 +362,7 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_ mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP) ubwpd = mac->cg->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; - NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : (ubwpd?ubwpd->pusch_Config->choice.setup:NULL); + NR_PUSCH_Config_t *pusch_Config = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup : (ubwpd?ubwpd->pusch_Config->choice.setup:NULL); AssertFatal(pusch_Config!=NULL,"pusch_Config shouldn't be null\n"); long transformPrecoder; @@ -581,7 +582,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, if (rar_grant) { // Note: for Msg3 or MsgA PUSCH transmission the N_PRB_oh is always set to 0 - NR_BWP_Uplink_t *ubwp = mac->ULbwp[ul_bwp_id-1]; + NR_BWP_Uplink_t *ubwp = ul_bwp_id > 0 ? mac->ULbwp[ul_bwp_id - 1] : NULL; NR_BWP_UplinkDedicated_t *ibwp; int scs,abwp_start,abwp_size,startSymbolAndLength,mappingtype; NR_PUSCH_Config_t *pusch_Config=NULL; @@ -839,11 +840,15 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, mappingtype, add_pos, dmrslength, pusch_config_pdu->start_symbol_index, mac->scc ? mac->scc->dmrs_TypeA_Position : mac->mib->dmrs_TypeA_Position); - if (mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) { - if (*dci_format != NR_UL_DCI_FORMAT_0_1) { - pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; - } - } else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || (mac->ULbwp[ul_bwp_id-1] && pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) { + if (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id - 1] && + pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled && + *dci_format != NR_UL_DCI_FORMAT_0_1) { + pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1; + } else if (*dci_format == NR_UL_DCI_FORMAT_0_0 || + (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id-1] && + pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled)) { pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; } @@ -859,7 +864,8 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, else N_PRB_oh = 0; /* PTRS */ - if (mac->ULbwp[ul_bwp_id-1] && + if (ul_bwp_id > 0 && + mac->ULbwp[ul_bwp_id-1] && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config && mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pusch_Config->choice.setup && @@ -1086,9 +1092,10 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in dcireq.dl_config_req = mac->dl_config_request; fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->thread_id, dl_info->phy_data); - if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) + if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) { LOG_D(NR_MAC,"1# scheduled_response transmitted, %d, %d\n", rx_frame, rx_slot); - mac->if_module->scheduled_response(&scheduled_response); + mac->if_module->scheduled_response(&scheduled_response); + } } else { // this is for Msg2/Msg4 @@ -1557,15 +1564,14 @@ int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, int delta = 0; NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id; - NR_BWP_Uplink_t *ubwp = mac->ULbwp[ul_bwp_id-1]; // Get the numerology to calculate the Tx frame and slot - int mu = ubwp ? - ubwp->bwp_Common->genericParameters.subcarrierSpacing : + int mu = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? + mac->ULbwp[ul_bwp_id-1]->bwp_Common->genericParameters.subcarrierSpacing : mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.genericParameters.subcarrierSpacing; - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ubwp ? - ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList: + NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ul_bwp_id > 0 && mac->ULbwp[ul_bwp_id-1] ? + mac->ULbwp[ul_bwp_id-1]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList: mac->scc_SIB->uplinkConfigCommon->initialUplinkBWP.pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; // k2 as per 3GPP TS 38.214 version 15.9.0 Release 15 ch 6.1.2.1.1 // PUSCH time domain resource allocation is higher layer configured from uschTimeDomainAllocationList in either pusch-ConfigCommon diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 218b75b2e8..20ac69ce55 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -366,7 +366,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, int pusch_AntennaPorts, cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0; break; case 2 : - cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]<<24; + cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = ((uint32_t) scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0]) << 24; cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0; break; case 3 : diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index d9a0a50b7e..d32709e731 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1349,6 +1349,8 @@ void nr_schedule_ue_spec(module_id_t module_id, header->L = htons(bufEnd-buf); dlsch_total_bytes += bufEnd-buf; + for (; ((intptr_t)buf) % 4; buf++) + *buf = lrand48() & 0xff; for (; buf < bufEnd - 3; buf += 4) { uint32_t *buf32 = (uint32_t *)buf; *buf32 = lrand48(); diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 078f7f51a1..53817af48e 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1320,11 +1320,11 @@ nr_rrc_ue_process_masterCellGroup( //TODO (perform SCell addition/modification as specified in 5.3.5.5.9) } - if( cellGroupConfig->ext2->bh_RLC_ChannelToReleaseList_r16 != NULL){ + if(cellGroupConfig->ext2 != NULL && cellGroupConfig->ext2->bh_RLC_ChannelToReleaseList_r16 != NULL){ //TODO (perform the BH RLC channel addition/modification as specified in 5.3.5.5.11) } - if( cellGroupConfig->ext2->bh_RLC_ChannelToAddModList_r16 != NULL){ + if(cellGroupConfig->ext2 != NULL && cellGroupConfig->ext2->bh_RLC_ChannelToAddModList_r16 != NULL){ //TODO (perform the BH RLC channel addition/modification as specified in 5.3.5.5.11) } } From ab36474811d591303eb8f7f24db9fe39a0b0bdc8 Mon Sep 17 00:00:00 2001 From: laurent Date: Mon, 4 Jul 2022 19:32:33 +0200 Subject: [PATCH 55/61] dirty workaround in LTE get_prb(): it is not good, but keep safe in memory instead of writing outside the range --- openair1/PHY/LTE_TRANSPORT/dci_tools_common.c | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c index cb2f190384..0addfdf14c 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools_common.c @@ -532,9 +532,12 @@ uint32_t conv_1C_RIV(int32_t rballoc,uint32_t N_RB_DL) { } +// FIXME: this function is compting PRB outside the range, so I FORCED in the range +// I can't understand the 3GPP spec, see below note uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { int offset; + int ret=-1; switch (N_RB_DL) { @@ -545,16 +548,16 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { switch (vrb) { case 0: // even: 0->0, 1->2, odd: 0->3, 1->5 case 1: - return ((3*odd_slot) + 2*(vrb&3))%6; + ret= ((3*odd_slot) + 2*(vrb&3))%6; break; case 2: // even: 2->3, 3->5, odd: 2->0, 3->2 case 3: - return ((3*odd_slot) + 2*(vrb&3) + 5)%6; + ret= ((3*odd_slot) + 2*(vrb&3) + 5)%6; break; case 4: // even: 4->1, odd: 4->4 - return ((3*odd_slot) + 1)%6; + ret= ((3*odd_slot) + 1)%6; case 5: // even: 5->4, odd: 5->1 - return ((3*odd_slot) + 4)%6; + ret= ((3*odd_slot) + 4)%6; break; } break; @@ -562,21 +565,21 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { case 15: if (vrb<12) { if ((vrb&3) < 2) // even: 0->0, 1->4, 4->1, 5->5, 8->2, 9->6 odd: 0->7, 1->11 - return(((7*odd_slot) + 4*(vrb&3) + (vrb>>2))%14) + 14*(vrb/14); + ret= (((7*odd_slot) + 4*(vrb&3) + (vrb>>2))%14) + 14*(vrb/14); else if (vrb < 12) // even: 2->7, 3->11, 6->8, 7->12, 10->9, 11->13 - return (((7*odd_slot) + 4*(vrb&3) + (vrb>>2) +13 )%14) + 14*(vrb/14); + ret= (((7*odd_slot) + 4*(vrb&3) + (vrb>>2) +13 )%14) + 14*(vrb/14); } if (vrb==12) - return (3+(7*odd_slot)) % 14; + ret= (3+(7*odd_slot)) % 14; if (vrb==13) - return (10+(7*odd_slot)) % 14; - return 14; + ret= (10+(7*odd_slot)) % 14; + ret= 14; break; // Formula in TS 36.211, chap 6.2.3.2 // Fix me: returns a PRB number > 24 when vrb is 24 case 25: - return (((12*odd_slot) + 6*(vrb&3) + (vrb>>2))%24) + 24*(vrb/24); + ret= (((12*odd_slot) + 6*(vrb&3) + (vrb>>2))%24) + 24*(vrb/24); break; case 50: // P=3 @@ -588,22 +591,22 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { offset=0; if (vrb<44) { if ((vrb&3)>=2) - return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2) + 45)%46; + ret= offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2) + 45)%46; else - return offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2))%46; + ret= offset+((23*odd_slot) + 12*(vrb&3) + (vrb>>2))%46; } if (vrb==44) // even: 44->11, odd: 45->34 - return offset+((23*odd_slot) + 22-12+1); + ret= offset+((23*odd_slot) + 22-12+1); if (vrb==45) // even: 45->10, odd: 45->33 - return offset+((23*odd_slot) + 22+12); + ret= offset+((23*odd_slot) + 22+12); if (vrb==46) - return offset+46+((23*odd_slot) + 23-12+1) % 46; + ret= offset+46+((23*odd_slot) + 23-12+1) % 46; if (vrb==47) - return offset+46+((23*odd_slot) + 23+12) % 46; + ret= offset+46+((23*odd_slot) + 23+12) % 46; if (vrb==48) - return offset+46+((23*odd_slot) + 23-12+1) % 46; + ret= offset+46+((23*odd_slot) + 23-12+1) % 46; if (vrb==49) - return offset+46+((23*odd_slot) + 23+12) % 46; + ret= offset+46+((23*odd_slot) + 23+12) % 46; } else { // Nrow=6,Nnull=6,NVRBDL=18,Ngap1= 27 @@ -614,39 +617,38 @@ uint32_t get_prb(int N_RB_DL,int odd_slot,int vrb,int Ngap) { if (vrb<12) { if ((vrb&3)>=2) - return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2) + 17)%18; + ret= offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2) + 17)%18; else - return offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2))%18; + ret= offset+((9*odd_slot) + 6*(vrb&3) + (vrb>>2))%18; } else { - // Same issue as for 25 PRB: returns larger than 0..49 - return ((9*odd_slot) + 12*(vrb&1) + (vrb>>1))%18 + 18*(vrb/18); + ret= offset+((9*odd_slot) + 12*(vrb&1)+(vrb>>1) )%18 + 18*(vrb/18); } } break; case 75: // Ngap1 = 32, NVRBRL=64, P=4, Nrow= 16, Nnull=0 if (Ngap ==0) { - return ((32*odd_slot) + 16*(vrb&3) + (vrb>>2))%64 + (vrb/64); + ret= ((32*odd_slot) + 16*(vrb&3) + (vrb>>2))%64 + (vrb/64); } else { // Ngap2 = 16, NVRBDL=32, Nrow=8, Nnull=0 - return ((16*odd_slot) + 8*(vrb&3) + (vrb>>2))%32 + (vrb/32); + ret= ((16*odd_slot) + 8*(vrb&3) + (vrb>>2))%32 + (vrb/32); } break; case 100: // Ngap1 = 48, NVRBDL=96, Nrow=24, Nnull=0 if (Ngap ==0) { - return ((48*odd_slot) + 24*(vrb&3) + (vrb>>2))%96 + (vrb/96); + ret= ((48*odd_slot) + 24*(vrb&3) + (vrb>>2))%96 + (vrb/96); } else { // Ngap2 = 16, NVRBDL=32, Nrow=8, Nnull=0 - return ((16*odd_slot) + 8*(vrb&3) + (vrb>>2))%32 + (vrb/32); + ret= ((16*odd_slot) + 8*(vrb&3) + (vrb>>2))%32 + (vrb/32); } break; default: LOG_E(PHY,"Unknown N_RB_DL %d\n",N_RB_DL); - return 0; + ret= 0; } - return 0; + return ret%N_RB_DL; } From b1a3cbb068eeeac04a0c14ccbba7d6c28cc491bc Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Wed, 20 Jul 2022 12:55:17 +0100 Subject: [PATCH 56/61] Fix segmentation fault when changing BWP --- openair2/RRC/NR/rrc_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 400be0bd4d..648df1a306 100755 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1949,7 +1949,7 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP NULL, NULL, NULL, - NULL, + ue_context_pP, NULL, NULL, NULL, From 667b8e5eed245e55927a92dc15ed976bef51a089 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 21 Jul 2022 09:04:29 +0200 Subject: [PATCH 57/61] nr_pdcp: nia1 implementation We reuse existing code from eia1 for actual computation. Maybe not the most efficient. To be revised if needed. Some hacks in CMakeLists.txt were introduced to compile phy simulators. To be removed at some point. --- cmake_targets/CMakeLists.txt | 8 +++ openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c | 20 ++++-- .../LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c | 66 +++++++++++++++++++ .../LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h | 34 ++++++++++ 4 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c create mode 100644 openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 25e10931c7..ef9e22e7ee 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1804,7 +1804,15 @@ set(NR_PDCP_SRC ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.c + ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c + #hack: include these files to compile the nr phy simulators + #these files should not be here, will be removed at some point when the + #computation is done directly inside nr_pdcp_integrity_nia1.c instead + #of reusing code of osa_stream_eia.c + ${OPENAIR2_DIR}/UTIL/OSA/osa_stream_eia.c + ${OPENAIR2_DIR}/UTIL/OSA/osa_snow3g.c + ${OPENAIR2_DIR}/UTIL/OSA/osa_rijndael.c ) set(NR_SDAP_SRC diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index 7e1ddb62bd..480b651593 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -27,6 +27,7 @@ #include "nr_pdcp_security_nea2.h" #include "nr_pdcp_integrity_nia2.h" +#include "nr_pdcp_integrity_nia1.h" #include "nr_pdcp_sdu.h" #include "LOG/log.h" @@ -240,16 +241,21 @@ static void nr_pdcp_entity_set_security(nr_pdcp_entity_t *entity, } if (integrity_algorithm != 0 && integrity_algorithm != -1) { - if (integrity_algorithm != 2) { - LOG_E(PDCP, "FATAL: only nia2 supported for the moment\n"); - exit(1); - } entity->has_integrity = 1; if (entity->free_integrity != NULL) entity->free_integrity(entity->integrity_context); - entity->integrity_context = nr_pdcp_integrity_nia2_init(entity->integrity_key); - entity->integrity = nr_pdcp_integrity_nia2_integrity; - entity->free_integrity = nr_pdcp_integrity_nia2_free_integrity; + if (integrity_algorithm == 2) { + entity->integrity_context = nr_pdcp_integrity_nia2_init(entity->integrity_key); + entity->integrity = nr_pdcp_integrity_nia2_integrity; + entity->free_integrity = nr_pdcp_integrity_nia2_free_integrity; + } else if (integrity_algorithm == 1) { + entity->integrity_context = nr_pdcp_integrity_nia1_init(entity->integrity_key); + entity->integrity = nr_pdcp_integrity_nia1_integrity; + entity->free_integrity = nr_pdcp_integrity_nia1_free_integrity; + } else { + LOG_E(PDCP, "FATAL: only nia1 and nia2 supported for the moment\n"); + exit(1); + } } if (ciphering_algorithm == 0) { diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c new file mode 100644 index 0000000000..08ec959937 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c @@ -0,0 +1,66 @@ +/* + * 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 + */ + +#include "nr_pdcp_integrity_nia1.h" + +#include +#include +#include +#include + +#include "UTIL/OSA/osa_defs.h" + +int stream_compute_integrity_eia1(stream_cipher_t *stream_cipher, uint8_t out[4]); + +void *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key) +{ + stream_cipher_t *ret; + + ret = calloc(1, sizeof(*ret)); if (ret == NULL) abort(); + ret->key = malloc(16); if (ret->key == NULL) abort(); + memcpy(ret->key, integrity_key, 16); + ret->key_length = 16; /* unused */ + + return ret; +} + +void nr_pdcp_integrity_nia1_integrity(void *integrity_context, + unsigned char *out, + unsigned char *buffer, int length, + int bearer, int count, int direction) +{ + stream_cipher_t *ctx = integrity_context; + + ctx->message = buffer; + ctx->count = count; + ctx->bearer = bearer-1; + ctx->direction = direction; + ctx->blength = length * 8; + + stream_compute_integrity_eia1(ctx, out); +} + +void nr_pdcp_integrity_nia1_free_integrity(void *integrity_context) +{ + stream_cipher_t *ctx = integrity_context; + free(ctx->key); + free(ctx); +} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h new file mode 100644 index 0000000000..5c44bad4a7 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h @@ -0,0 +1,34 @@ +/* + * 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 + */ + +#ifndef _NR_PDCP_INTEGRITY_NIA1_H_ +#define _NR_PDCP_INTEGRITY_NIA1_H_ + +void *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key); + +void nr_pdcp_integrity_nia1_integrity(void *integrity_context, + unsigned char *out, + unsigned char *buffer, int length, + int bearer, int count, int direction); + +void nr_pdcp_integrity_nia1_free_integrity(void *integrity_context); + +#endif /* _NR_PDCP_INTEGRITY_NIA1_H_ */ From 3c2375eadab4a508f85e0fcda7c7524b25b59067 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 21 Jul 2022 17:57:20 +0200 Subject: [PATCH 58/61] CI: do not trigger tests if nothing is tagged NSA The previous version would trigger sub-pipelines (LTE-2x2, ...) if no MR had the NSA tag (without a commit, etc). Of course, this would make all pipelines subsequently fail (as not enough arguments, such as the commit, were given). In this commit, we read the output of `jq` from JSON, which will result in an empty list if no MR is tagged with the NSA label (and the output in the console will be nicer as well). --- ci-scripts/Jenkinsfile-trig-nsa | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ci-scripts/Jenkinsfile-trig-nsa b/ci-scripts/Jenkinsfile-trig-nsa index 3616b2c404..8e81b75e58 100644 --- a/ci-scripts/Jenkinsfile-trig-nsa +++ b/ci-scripts/Jenkinsfile-trig-nsa @@ -20,6 +20,9 @@ * contact@openairinterface.org */ +// necessary for reading JSON +import groovy.json.JsonSlurper + // Template Jenkins Declarative Pipeline script to run Test w/ RF HW // Location of the python executor node shall be in the same subnet as the others servers @@ -37,12 +40,12 @@ pipeline { stages { stage ("Launcher") { steps { - script { - //retrieve MR that are opened nd with tag NSA - MR_LIST= sh returnStdout: true, script: 'curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100&labels=NSA" | jq ".[].iid" || true ' - echo "List of selected MR:\n${MR_LIST}" - def MR_ARRAY = MR_LIST.split('\n') - //for every selected MR, retrieve the branch name and the latest commit + script { + // retrieve MR that are opened nd with tag NSA + MR_LIST = sh returnStdout: true, script: 'curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100&labels=NSA" | jq -cj "[.[].iid]"' + echo "List of selected MRs: ${MR_LIST.trim()}" + def MR_ARRAY = new JsonSlurper().parseText(MR_LIST.trim()) + // for every selected MR, retrieve the branch name and the latest commit for (MR in MR_ARRAY) { SRC_BRANCH=sh returnStdout: true, script: """curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests/${MR}" | jq ".source_branch" || true """ SRC_BRANCH=SRC_BRANCH.trim() From 228bd5f16d86d4ebc8d2a6777379455e22346e39 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 22 Jul 2022 17:01:47 +0200 Subject: [PATCH 59/61] fix for ssb subcarrier offset in case of <3GHz --- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 4daddbf03a..a79748238f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -337,7 +337,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, int pusch_AntennaPorts, // SSB Table Configuration uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); const int scaling_5khz = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000 ? 3 : 1; - int sco = (absolute_diff*scaling_5khz) % 24; + int sco = (absolute_diff/scaling_5khz) % 24; if(frequency_range == FR2) sco >>= 1; // this assumes 120kHz SCS for SSB and subCarrierSpacingCommon (only option supported by OAI for const int scs_scaling = frequency_range == FR2 ? 1 << (*scc->ssbSubcarrierSpacing - 2) : 1 << *scc->ssbSubcarrierSpacing; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index a93d2a8623..ff139c9895 100755 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -230,7 +230,7 @@ uint8_t do_MIB_NR(gNB_RRC_INST *rrc,uint32_t frame) { if (get_softmodem_params()->sa) { uint32_t absolute_diff = (*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); int scs_scaling = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA < 600000 ? 3 : 1; - ssb_subcarrier_offset = (absolute_diff*scs_scaling)%24; + ssb_subcarrier_offset = (absolute_diff/scs_scaling)%24; if(frequency_range == FR2) ssb_subcarrier_offset >>= 1; // this assumes 120kHz SCS for SSB and subCarrierSpacingCommon (only option supported by OAI for now) } From e1798745ef70265baa7fd8809980e31725fc0dcb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 19 Jul 2022 18:21:28 +0200 Subject: [PATCH 60/61] Dynamically build L2sim proxy --- ci-scripts/Jenkinsfile-push-registry | 2 +- ci-scripts/Jenkinsfile-tmp-multi-enb | 187 +++++++++++++++++- ci-scripts/cls_containerize.py | 119 +++++++++++ ci-scripts/main.py | 7 +- ci-scripts/xml_class_list.yml | 1 + .../xml_files/container_5g_l2sim_proxy.xml | 42 ++++ 6 files changed, 354 insertions(+), 4 deletions(-) create mode 100644 ci-scripts/xml_files/container_5g_l2sim_proxy.xml diff --git a/ci-scripts/Jenkinsfile-push-registry b/ci-scripts/Jenkinsfile-push-registry index bc1a80ba61..feb1807c91 100644 --- a/ci-scripts/Jenkinsfile-push-registry +++ b/ci-scripts/Jenkinsfile-push-registry @@ -66,7 +66,7 @@ pipeline { withCredentials([ [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.DH_Credentials}", usernameVariable: 'DH_Username', passwordVariable: 'DH_Password'] ]) { - def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue"] + def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue", "proxy"] sh "docker login -u ${DH_Username} -p ${DH_Password} > /dev/null 2>&1" listOfImages.eachWithIndex { item, iindex -> sh "docker image tag ${item}:develop ${DH_Account}/${item}:develop" diff --git a/ci-scripts/Jenkinsfile-tmp-multi-enb b/ci-scripts/Jenkinsfile-tmp-multi-enb index c3b825ec06..fb52316920 100644 --- a/ci-scripts/Jenkinsfile-tmp-multi-enb +++ b/ci-scripts/Jenkinsfile-tmp-multi-enb @@ -36,6 +36,9 @@ def testStageName = params.pipelineTestStageName // Name of the phone resource def ciSmartPhoneResource = params.smartphonesResource +// Name of the phone resource +def ciEpcResource = params.epcResource + // Global Parameters. Normally they should be populated when the master job // triggers the slave job with parameters def eNB_Repository @@ -51,7 +54,7 @@ pipeline { options { disableConcurrentBuilds() ansiColor('xterm') - lock (ciSmartPhoneResource) + lock(extra: [[resource: ciEpcResource]], resource: ciSmartPhoneResource) } stages { stage ("Verify Parameters") { @@ -216,6 +219,76 @@ pipeline { } } } + stage ("Terminate") { + parallel { + stage('Terminate UE') { + // Bypassing this stage if there are no abd server defined + when { + expression { params.ADB_IPAddress != "none" } + } + steps { + echo '\u2705 \u001B[32mTerminate UE\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.ADB_Credentials}", usernameVariable: 'ADB_Username', passwordVariable: 'ADB_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateUE --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password}" + } + } + } + stage('Terminate eNB') { + steps { + echo '\u2705 \u001B[32mTerminate eNB\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" + } + } + } + stage('Terminate SPGW') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + echo '\u2705 \u001B[32mTerminate SPGW\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateSPGW --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCType=${params.EPC_Type} --EPCSourceCodePath=${params.EPC_SourceCodePath}" + } + } + } + stage('Terminate MME') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + echo '\u2705 \u001B[32mTerminate MME\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateMME --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCType=${params.EPC_Type} --EPCSourceCodePath=${params.EPC_SourceCodePath}" + } + } + } + stage('Terminate HSS') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + echo '\u2705 \u001B[32mTerminate HSS\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateHSS --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCType=${params.EPC_Type} --EPCSourceCodePath=${params.EPC_SourceCodePath}" + } + } + } + } + } stage('Log Collection') { parallel { stage('Log Collection (eNB - Build)') { @@ -242,7 +315,7 @@ pipeline { [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] ]) { echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}" + sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m' sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true" @@ -259,6 +332,116 @@ pipeline { } } } + stage('Log Collection (SPGW)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (SPGW)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectSPGW --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (SPGW)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/spgw.log.zip ./spgw.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("spgw.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "spgw.log.${env.BUILD_ID}.zip" + } + } + } + } + stage('Log Collection (MME)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (MME)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectMME --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (MME)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/mme.log.zip ./mme.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("mme.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "mme.log.${env.BUILD_ID}.zip" + } + } + } + } + stage('Log Collection (HSS)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (HSS)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectHSS --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (HSS)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/hss.log.zip ./hss.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("hss.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "hss.log.${env.BUILD_ID}.zip" + } + } + } + } + stage('Log Collection (Ping)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (Ping)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectPing --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (Ping)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/ping.log.zip ./ping.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("ping.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "ping.log.${env.BUILD_ID}.zip" + } + } + } + } + stage('Log Collection (Iperf)') { + // Bypassing this stage if EPC server is not defined + when { + expression { params.EPC_IPAddress != "none" } + } + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (Iperf)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectIperf --EPCIPAddress=${params.EPC_IPAddress} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --EPCType=${params.EPC_Type}" + + echo '\u2705 \u001B[32mLog Transfer (Iperf)\u001B[0m' + sh "sshpass -p \'${EPC_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${EPC_Username}@${params.EPC_IPAddress}:${EPC_SourceCodePath}/scripts/iperf.log.zip ./iperf.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("iperf.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "iperf.log.${env.BUILD_ID}.zip" + } + } + } + } } } } diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 6abf444a0d..8f992689e2 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -74,6 +74,7 @@ class Containerize(): self.eNB2SourceCodePath = '' self.forcedWorkspaceCleanup = False self.imageKind = '' + self.proxyCommit = None self.eNB_instance = 0 self.eNB_serverId = ['', '', ''] self.yamlPath = ['', '', ''] @@ -421,6 +422,124 @@ class Containerize(): HTML.CreateHtmlTabFooter(False) sys.exit(1) + def BuildProxy(self, HTML): + if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter') + if self.eNB_serverId[self.eNB_instance] == '0': + lIpAddr = self.eNBIPAddress + lUserName = self.eNBUserName + lPassWord = self.eNBPassword + lSourcePath = self.eNBSourceCodePath + elif self.eNB_serverId[self.eNB_instance] == '1': + lIpAddr = self.eNB1IPAddress + lUserName = self.eNB1UserName + lPassWord = self.eNB1Password + lSourcePath = self.eNB1SourceCodePath + elif self.eNB_serverId[self.eNB_instance] == '2': + lIpAddr = self.eNB2IPAddress + lUserName = self.eNB2UserName + lPassWord = self.eNB2Password + lSourcePath = self.eNB2SourceCodePath + if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter') + if self.proxyCommit is None: + HELP.GenericHelp(CONST.Version) + sys.exit('Insufficient Parameter (need proxyCommit for proxy build)') + logging.debug('Building on server: ' + lIpAddr) + mySSH = SSH.SSHConnection() + mySSH.open(lIpAddr, lUserName, lPassWord) + + # Check that we are on Ubuntu + mySSH.command('hostnamectl', '\$', 5) + result = re.search('Ubuntu', mySSH.getBefore()) + self.host = result.group(0) + if self.host != 'Ubuntu': + logging.error('\u001B[1m Can build proxy only on Ubuntu server\u001B[0m') + mySSH.close() + sys.exit(1) + + self.cli = 'docker' + self.cliBuildOptions = '--no-cache' + + # Workaround for some servers, we need to erase completely the workspace + if self.forcedWorkspaceCleanup: + mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15) + + oldRanCommidID = self.ranCommitID + oldRanRepository = self.ranRepository + oldRanAllowMerge = self.ranAllowMerge + self.ranCommitID = self.proxyCommit + self.ranRepository = 'https://github.com/EpiSci/oai-lte-5g-multi-ue-proxy.git' + self.ranAllowMerge = False + self._createWorkspace(mySSH, lPassWord, lSourcePath) + # to prevent accidentally overwriting data that might be used later + self.ranCommitID = oldRanCommidID + self.ranRepository = oldRanRepository + self.ranAllowMerge = oldRanAllowMerge + + # Let's remove any previous run artifacts if still there + mySSH.command(self.cli + ' image prune --force', '\$', 30) + # Remove any previous proxy image + mySSH.command(self.cli + ' image rm oai-lte-multi-ue-proxy:latest || true', '\$', 30) + + tag = self.proxyCommit + logging.debug('building L2sim proxy image for tag ' + tag) + # check if the corresponding proxy image with tag exists. If not, build it + mySSH.command(self.cli + ' image inspect --format=\'Size = {{.Size}} bytes\' proxy:' + tag, '\$', 5) + buildProxy = mySSH.getBefore().count('o such image') != 0 + if buildProxy: + mySSH.command(self.cli + ' build ' + self.cliBuildOptions + ' --target oai-lte-multi-ue-proxy --tag proxy:' + tag + ' --file docker/Dockerfile.ubuntu18.04 . > cmake_targets/log/proxy-build.log 2>&1', '\$', 180) + # Note: at this point, OAI images are flattened, but we cannot do this + # here, as the flatten script is not in the proxy repo + mySSH.command(self.cli + ' image inspect --format=\'Size = {{.Size}} bytes\' proxy:' + tag, '\$', 5) + if mySSH.getBefore().count('o such image') != 0: + logging.error('\u001B[1m Build of L2sim proxy failed\u001B[0m') + mySSH.close() + HTML.CreateHtmlTestRow('commit ' + tag, 'KO', CONST.ALL_PROCESSES_OK) + HTML.CreateHtmlTabFooter(False) + sys.exit(1) + else: + logging.debug('L2sim proxy image for tag ' + tag + ' already exists, skipping build') + + # retag the build images to that we pick it up later + mySSH.command('docker image tag proxy:' + tag + ' oai-lte-multi-ue-proxy:latest', '\$', 5) + + # no merge: is a push to develop, tag the image so we can push it to the registry + if not self.ranAllowMerge: + mySSH.command('docker image tag proxy:' + tag + ' proxy:develop', '\$', 5) + + # we assume that the host on which this is built will also run the proxy. The proxy + # currently requires the following command, and the docker-compose up mechanism of + # the CI does not allow to run arbitrary commands. Note that the following actually + # belongs to the deployment, not the build of the proxy... + logging.warning('the following command belongs to deployment, but no mechanism exists to exec it there!') + mySSH.command('sudo ifconfig lo: 127.0.0.2 netmask 255.0.0.0 up', '\$', 5) + + # Analyzing the logs + if buildProxy: + self.testCase_id = HTML.testCase_id + mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) + mySSH.command('mkdir -p proxy_build_log_' + self.testCase_id, '\$', 5) + mySSH.command('mv log/* ' + 'proxy_build_log_' + self.testCase_id, '\$', 5) + if (os.path.isfile('./proxy_build_log_' + self.testCase_id + '.zip')): + os.remove('./proxy_build_log_' + self.testCase_id + '.zip') + if (os.path.isdir('./proxy_build_log_' + self.testCase_id)): + shutil.rmtree('./proxy_build_log_' + self.testCase_id) + mySSH.command('zip -r -qq proxy_build_log_' + self.testCase_id + '.zip proxy_build_log_' + self.testCase_id, '\$', 5) + mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/build_log_' + self.testCase_id + '.zip', '.') + # don't delete such that we might recover the zips + #mySSH.command('rm -f build_log_' + self.testCase_id + '.zip','\$', 5) + + # Cleaning any created tmp volume + mySSH.command(self.cli + ' volume prune --force || true','\$', 15) + mySSH.close() + + logging.info('\u001B[1m Building L2sim Proxy Image Pass\u001B[0m') + HTML.CreateHtmlTestRow('commit ' + tag, 'OK', CONST.ALL_PROCESSES_OK) + HTML.CreateHtmlNextTabHeaderTestRow(self.collectInfo, self.allImagesSize) + def Copy_Image_to_Test_Server(self, HTML): imageTag = 'develop' if (self.ranAllowMerge): diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 448f2636e3..baed6a6011 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -102,7 +102,7 @@ def AssignParams(params_dict): def GetParametersFromXML(action): - if action == 'Build_eNB' or action == 'Build_Image': + if action == 'Build_eNB' or action == 'Build_Image' or action == 'Build_Proxy': RAN.Build_eNB_args=test.findtext('Build_eNB_args') CONTAINERS.imageKind=test.findtext('kind') forced_workspace_cleanup = test.findtext('forced_workspace_cleanup') @@ -138,6 +138,9 @@ def GetParametersFromXML(action): RAN.backgroundBuild=True else: RAN.backgroundBuild=False + proxy_commit = test.findtext('proxy_commit') + if proxy_commit is not None: + CONTAINERS.proxyCommit = proxy_commit elif action == 'WaitEndBuild_eNB': RAN.Build_eNB_args=test.findtext('Build_eNB_args') @@ -915,6 +918,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re HTML=ldpc.Run_PhySim(HTML,CONST,id) elif action == 'Build_Image': CONTAINERS.BuildImage(HTML) + elif action == 'Build_Proxy': + CONTAINERS.BuildProxy(HTML) elif action == 'Copy_Image_to_Test': CONTAINERS.Copy_Image_to_Test_Server(HTML) elif action == 'Deploy_Object': diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml index b305aff424..2c5f04b11f 100755 --- a/ci-scripts/xml_class_list.yml +++ b/ci-scripts/xml_class_list.yml @@ -1,3 +1,4 @@ + - Build_Proxy - Build_PhySim - Run_PhySim - Build_eNB diff --git a/ci-scripts/xml_files/container_5g_l2sim_proxy.xml b/ci-scripts/xml_files/container_5g_l2sim_proxy.xml new file mode 100644 index 0000000000..af1715d793 --- /dev/null +++ b/ci-scripts/xml_files/container_5g_l2sim_proxy.xml @@ -0,0 +1,42 @@ + + + l2sim-5gnr-proxy-build + Build L2sim proxy image + wrench + 1 + + 000001 + + + + + Build_Proxy + Build L2sim Proxy Image + 1 + 1 + True + 56cfdc0 + + + From b4331bf7f43588fadc90e9504de3894872f14145 Mon Sep 17 00:00:00 2001 From: laurent Date: Thu, 30 Jun 2022 17:57:47 +0200 Subject: [PATCH 61/61] code maintenance: old errors --- executables/nr-softmodem.h | 3 - openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c | 21 ++- openair1/SCHED/ru_procedures.c | 14 +- openair1/SCHED/sched_common_extern.h | 2 + openair1/SIMULATION/LTE_PHY/dlsim.c | 8 +- .../LAYER2/MAC/eNB_scheduler_primitives.c | 16 --- openair2/LAYER2/MAC/eNB_scheduler_ulsch.c | 12 +- openair2/LAYER2/MAC/mac.h | 10 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 11 +- openair2/RRC/LTE/rrc_eNB.c | 124 +++++------------- targets/RT/USER/lte-ru.c | 6 +- targets/RT/USER/lte-softmodem.h | 17 ++- targets/RT/USER/lte-uesoftmodem.c | 1 - 13 files changed, 90 insertions(+), 155 deletions(-) diff --git a/executables/nr-softmodem.h b/executables/nr-softmodem.h index 7d2184f01b..98087ea2bb 100644 --- a/executables/nr-softmodem.h +++ b/executables/nr-softmodem.h @@ -59,9 +59,6 @@ extern void set_function_spec_param(RU_t *ru); extern void reset_opp_meas(void); extern void print_opp_meas(void); - -extern void init_fep_thread(PHY_VARS_gNB *); - void init_gNB_afterRU(void); extern int stop_L1L2(module_id_t gnb_id); diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c index 088e2c0a5e..b5e5b490a3 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c @@ -64,6 +64,12 @@ extern uint16_t beta_cqi[16]; extern uint16_t beta_ri[16]; extern uint16_t beta_ack[16]; +static int errorRB(int rb, char * table, int line) { + LOG_E(PHY,"Received %d rb, impossble in table %s, at line %d\n", rb, table, line); + return 0; +} + +#define rbAllocCheck(RBalL, TabLe) (RBalL) > sizeof(TabLe)/sizeof(*TabLe) ? errorRB(RBalL, #TabLe, __LINE__) : TabLe[RBalL] void extract_dci1A_info(uint8_t N_RB_DL, frame_type_t frame_type, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) { uint8_t harq_pid=0; @@ -974,28 +980,28 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, { switch (N_RB_DL) { case 6: - NPRB = RIV2nb_rb_LUT6[rballoc];//NPRB; + NPRB = rbAllocCheck(rballoc, RIV2nb_rb_LUT6); if(rah) RIV_max = RIV_max6; else RIV_max = 0x3F; break; case 25: - NPRB = RIV2nb_rb_LUT25[rballoc];//NPRB; + NPRB = rbAllocCheck(rballoc,RIV2nb_rb_LUT25); if(rah) RIV_max = RIV_max25; else RIV_max = 0x1FFF; break; case 50: - NPRB = RIV2nb_rb_LUT50[rballoc];//NPRB; + NPRB = rbAllocCheck(rballoc,RIV2nb_rb_LUT50); if(rah) RIV_max = RIV_max50; else RIV_max = 0x1FFFF; break; case 100: - NPRB = RIV2nb_rb_LUT100[rballoc];//NPRB; + NPRB = rbAllocCheck(rballoc,RIV2nb_rb_LUT100); if(rah) RIV_max = RIV_max100; else @@ -1034,9 +1040,14 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, // this is an eNB issue // retransmisison but old and new TBS are different !!! // work around, consider it as a new transmission - LOG_E(PHY,"Format1A Retransmission but TBS are different: consider it as new transmission !!! \n"); + LOG_E(PHY, + "Format1A Retransmission but TBS are different: consider it as new transmission !!!, round %d, mcs 1 %d, NPRB %d \n", + pdlsch0_harq->round, + mcs1, + NPRB); pdlsch0_harq->round = 0; //return(0); // ?? to cross check + return(0); // ?? to cross check } } diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index dc84279a96..443b1c7989 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -71,9 +71,9 @@ #include "common/utils/system.h" #include - -extern int oai_exit; - +#include "openair1/SCHED/sched_common_extern.h" +#include "targets/RT/USER/lte-softmodem.h" +#include "common/ran_context.h" void feptx0(RU_t *ru, int slot) @@ -616,9 +616,11 @@ void init_fep_thread(RU_t *ru, } -extern void kill_fep_thread(RU_t *ru) +void kill_fep_thread(RU_t *ru) { RU_proc_t *proc = &ru->proc; + if (proc->pthread_fep == 0) + return; pthread_mutex_lock( &proc->mutex_fep ); proc->instance_cnt_fep = 0; pthread_cond_signal(&proc->cond_fep); @@ -630,9 +632,11 @@ extern void kill_fep_thread(RU_t *ru) } -extern void kill_feptx_thread(RU_t *ru) +void kill_feptx_thread(RU_t *ru) { RU_proc_t *proc = &ru->proc; + if (proc->pthread_feptx == 0) + return; pthread_mutex_lock( &proc->mutex_feptx ); proc->instance_cnt_feptx = 0; pthread_cond_signal(&proc->cond_feptx); diff --git a/openair1/SCHED/sched_common_extern.h b/openair1/SCHED/sched_common_extern.h index b5edc6f38e..2236c5f31d 100644 --- a/openair1/SCHED/sched_common_extern.h +++ b/openair1/SCHED/sched_common_extern.h @@ -29,4 +29,6 @@ extern int16_t hundred_times_delta_TF[100]; extern uint16_t hundred_times_log10_NPRB[100]; +void kill_fep_thread(RU_t *ru); + #endif /*__SCHED_EXTERN_H__ */ diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 231d63cf04..e5e97733e5 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -514,10 +514,10 @@ int main(int argc, char **argv) { LTE_DL_FRAME_PARMS *frame_parms; double s_re0[30720*2],s_im0[30720*2],r_re0[30720*2],r_im0[30720*2]; double s_re1[30720*2],s_im1[30720*2],r_re1[30720*2],r_im1[30720*2]; - double *s_re[2]= {s_re0,s_re1}; - double *s_im[2]= {s_im0,s_im1}; - double *r_re[2]= {r_re0,r_re1}; - double *r_im[2]= {r_im0,r_im1}; + double *s_re[NB_ANTENNAS_TX]= {s_re0,s_re1}; + double *s_im[NB_ANTENNAS_TX]= {s_im0,s_im1}; + double *r_re[NB_ANTENNAS_RX]= {r_re0,r_re1}; + double *r_im[NB_ANTENNAS_RX]= {r_im0,r_im1}; uint8_t transmission_mode=1,n_tx_port=1,n_tx_phy=1,n_rx=2; int eNB_id = 0; unsigned char round; diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c index 4469d0a3f9..58abbd7a47 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c @@ -2366,22 +2366,6 @@ rrc_mac_remove_ue(module_id_t mod_idP, return 0; } -//------------------------------------------------------------------------------ -/* - * Returns the previous UE_id in the scheduling list in UL or DL - */ -inline int prev(UE_list_t *listP, int nodeP) { - if (nodeP == listP->head) - return -1; /* there is no previous of the head */ - - for (int j = listP->head; j >= 0; j = listP->next[j]) - if (listP->next[j] == nodeP) - return j; - - LOG_E(MAC, "%s(): could not find previous to %d in UE_list\n", __func__, nodeP); - dump_ue_list(listP); - return -1; -} // This has to be updated to include BSR information //------------------------------------------------------------------------------ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index a31b8bdd03..f9218d8511 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -329,17 +329,7 @@ rx_sdu(const module_id_t enb_mod_idP, if (ra->msg3_round >= mac->common_channels[CC_idP].radioResourceConfigCommon->rach_ConfigCommon.maxHARQ_Msg3Tx - 1) { // Release RNTI of LTE PHY when RA does not succeed - UE_free_list_t *free_list = NULL; - pthread_mutex_lock(&lock_ue_freelist); - free_list = &mac->UE_free_list; - free_list->UE_free_ctrl[free_list->tail_freelist].rnti = current_rnti; - free_list->UE_free_ctrl[free_list->tail_freelist].removeContextFlg = 1; - free_list->UE_free_ctrl[free_list->tail_freelist].raFlag = 1; - free_list->num_UEs++; - mac->UE_release_req.ue_release_request_body.ue_release_request_TLVs_list[mac->UE_release_req.ue_release_request_body.number_of_TLVs].rnti = current_rnti; - mac->UE_release_req.ue_release_request_body.number_of_TLVs++; - free_list->tail_freelist = (free_list->tail_freelist + 1) % (NUMBER_OF_UE_MAX+1); - pthread_mutex_unlock(&lock_ue_freelist); + put_UE_in_freelist(enb_mod_idP, current_rnti, true); cancel_ra_proc(enb_mod_idP, CC_idP, frameP, current_rnti); nfapi_hi_dci0_request_t *hi_dci0_req = NULL; diff --git a/openair2/LAYER2/MAC/mac.h b/openair2/LAYER2/MAC/mac.h index 2392c8506b..1fd7182c6f 100644 --- a/openair2/LAYER2/MAC/mac.h +++ b/openair2/LAYER2/MAC/mac.h @@ -1195,14 +1195,6 @@ typedef struct { ///remove RA flag bool raFlag; } UE_free_ctrl_t; -/*! \brief REMOVE UE list used by eNB to order UEs/CC for deleting*/ -typedef struct { - /// deleting control info - UE_free_ctrl_t UE_free_ctrl[NUMBER_OF_UE_MAX+1]; - int num_UEs; - int head_freelist; ///the head position of the delete list - int tail_freelist; ///the tail position of the delete list -} UE_free_list_t; /** * describes contiguous RBs @@ -1443,7 +1435,7 @@ typedef struct eNB_MAC_INST_s { /// processing time of eNB PCH scheduler time_stats_t schedule_pch; - UE_free_list_t UE_free_list; + UE_free_ctrl_t UE_free_ctrl[NUMBER_OF_UE_MAX+1]; /// for scheduling selection SCHEDULER_MODES scheduler_mode; /// Default scheduler: Pre-processor implementation. Algorithms for UL/DL diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 9941437e13..01a574f83c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2437,16 +2437,15 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf sched_ctrl->next_dl_bwp_id = -1; sched_ctrl->next_ul_bwp_id = -1; const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig ? servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList : NULL; - if (ubwpList) - AssertFatal(ubwpList->list.count <= NR_MAX_NUM_BWP, - "uplinkBWP_ToAddModList has %d BWP!\n", - ubwpList->list.count); + AssertFatal(ubwpList == NULL || ubwpList->list.count <= NR_MAX_NUM_BWP, + "uplinkBWP_ToAddModList has %d BWP!\n", + ubwpList->list.count); const int ul_bwp_id = servingCellConfig ? *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id : 0; sched_ctrl->active_ubwp = ubwpList && ul_bwp_id > 0 ? ubwpList->list.array[ul_bwp_id - 1] : NULL; /* get Number of HARQ processes for this UE */ - if (servingCellConfig) - AssertFatal(servingCellConfig->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, + AssertFatal(servingCellConfig == NULL + || servingCellConfig->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, "no pdsch-ServingCellConfig found for UE %04x\n", UE->rnti); const NR_PDSCH_ServingCellConfig_t *pdsch = servingCellConfig ? servingCellConfig->pdsch_ServingCellConfig->choice.setup : NULL; diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index a5d938cdf6..8be30175e1 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -976,28 +976,24 @@ rrc_eNB_free_UE( put_UE_in_freelist(enb_mod_idP, rnti, 1); } -void remove_UE_from_freelist(module_id_t mod_id, rnti_t rnti) { - eNB_MAC_INST *eNB_MAC = RC.mac[mod_id]; - pthread_mutex_lock(&lock_ue_freelist); - UE_free_list_t *free_list = &eNB_MAC->UE_free_list; - free_list->UE_free_ctrl[free_list->head_freelist].rnti = 0; - free_list->head_freelist = (free_list->head_freelist + 1) % (NUMBER_OF_UE_MAX+1); - free_list->num_UEs--; - pthread_mutex_unlock(&lock_ue_freelist); -} - void put_UE_in_freelist(module_id_t mod_id, rnti_t rnti, bool removeFlag) { - UE_free_list_t *free_list = NULL; eNB_MAC_INST *eNB_MAC = RC.mac[mod_id]; pthread_mutex_lock(&lock_ue_freelist); - free_list = &eNB_MAC->UE_free_list; - free_list->UE_free_ctrl[free_list->tail_freelist].rnti = rnti; - free_list->UE_free_ctrl[free_list->tail_freelist].removeContextFlg = removeFlag; - free_list->UE_free_ctrl[free_list->tail_freelist].raFlag = 0; - free_list->num_UEs++; + LOG_I(PHY,"add ue %d in fre list, context flag: %d\n", rnti, removeFlag); + int i; + for (i=0; i < sizeofArray(eNB_MAC->UE_free_ctrl); i++) + if (eNB_MAC->UE_free_ctrl[i].rnti == 0) + break; + if (i==sizeofArray(eNB_MAC->UE_free_ctrl)) { + LOG_E(PHY,"List of UE to free is full\n"); + pthread_mutex_unlock(&lock_ue_freelist); + return; + } + eNB_MAC->UE_free_ctrl[i].rnti = rnti; + eNB_MAC->UE_free_ctrl[i].removeContextFlg = removeFlag; + eNB_MAC->UE_free_ctrl[i].raFlag = 0; eNB_MAC->UE_release_req.ue_release_request_body.ue_release_request_TLVs_list[eNB_MAC->UE_release_req.ue_release_request_body.number_of_TLVs].rnti = rnti; eNB_MAC->UE_release_req.ue_release_request_body.number_of_TLVs++; - free_list->tail_freelist = (free_list->tail_freelist + 1) % (NUMBER_OF_UE_MAX+1); pthread_mutex_unlock(&lock_ue_freelist); } @@ -1007,104 +1003,47 @@ extern void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch); extern void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch); void release_UE_in_freeList(module_id_t mod_id) { - int i, j, CC_id, pdu_number; - protocol_ctxt_t ctxt; - nfapi_ul_config_request_body_t *ul_req_tmp = NULL; PHY_VARS_eNB *eNB_PHY = NULL; - struct rrc_eNB_ue_context_s *ue_context_pP = NULL; eNB_MAC_INST *eNB_MAC = RC.mac[mod_id]; - bool remove_UEContext; - rnti_t rnti; - int head, tail, ue_num; pthread_mutex_lock(&lock_ue_freelist); - head = eNB_MAC->UE_free_list.head_freelist; - tail = eNB_MAC->UE_free_list.tail_freelist; - if(head == tail) { - pthread_mutex_unlock(&lock_ue_freelist); - return; - } - - if(tail < head) { - tail = head + eNB_MAC->UE_free_list.num_UEs; - } - - pthread_mutex_unlock(&lock_ue_freelist); - - for(ue_num = head; ue_num < tail; ue_num++) { - ue_num = ue_num % (NUMBER_OF_UE_MAX+1); - rnti = eNB_MAC->UE_free_list.UE_free_ctrl[ue_num].rnti; + for(int ue_num = 0; ue_num < sizeofArray(eNB_MAC->UE_free_ctrl) ; ue_num++) { + rnti_t rnti = eNB_MAC->UE_free_ctrl[ue_num].rnti; if(rnti != 0) { - remove_UEContext = eNB_MAC->UE_free_list.UE_free_ctrl[ue_num].removeContextFlg; + protocol_ctxt_t ctxt; PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, rnti, 0, 0,mod_id); - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { eNB_PHY = RC.eNB[mod_id][CC_id]; int id; // clean ULSCH entries for rnti - id = find_ulsch(rnti,eNB_PHY,eNB_MAC->UE_free_list.UE_free_ctrl[ue_num].raFlag ? SEARCH_EXIST_RA : SEARCH_EXIST); + id = find_ulsch(rnti,eNB_PHY,eNB_MAC->UE_free_ctrl[ue_num].raFlag ? SEARCH_EXIST_RA : SEARCH_EXIST); if (id>=0) clean_eNb_ulsch(eNB_PHY->ulsch[id]); // clean DLSCH entries for rnti - id = find_dlsch(rnti,eNB_PHY,eNB_MAC->UE_free_list.UE_free_ctrl[ue_num].raFlag ? SEARCH_EXIST_RA : SEARCH_EXIST); + id = find_dlsch(rnti,eNB_PHY,eNB_MAC->UE_free_ctrl[ue_num].raFlag ? SEARCH_EXIST_RA : SEARCH_EXIST); if (id>=0) clean_eNb_dlsch(eNB_PHY->dlsch[id][0]); // clean UCI entries for rnti - for (i=0; iuci_vars[i].rnti == rnti) { LOG_I(MAC, "clean eNb uci_vars[%d] UE %x \n",i, rnti); memset(&eNB_PHY->uci_vars[i],0,sizeof(LTE_eNB_UCI)); } } - /* - for (i=0; iulsch[i]; - - if((ulsch != NULL) && (ulsch->rnti == rnti)) { - void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch); - LOG_I(RRC, "clean_eNb_ulsch ulsch[%d] UE %x\n", i, rnti); - clean_eNb_ulsch(ulsch); - } - - dlsch = eNB_PHY->dlsch[i][0]; - - if((dlsch != NULL) && (dlsch->rnti == rnti)) { - void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch); - LOG_I(RRC, "clean_eNb_dlsch dlsch[%d] UE %x \n", i, rnti); - clean_eNb_dlsch(dlsch); - } - } - - ulsch = eNB_PHY->ulsch[i]; - - if((ulsch != NULL) && (ulsch->rnti == rnti)) { - void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch); - LOG_I(RRC, "clean_eNb_ulsch ulsch[%d] UE %x\n", i, rnti); - clean_eNb_ulsch(ulsch); - } - - for (i=0; iuci_vars[i].rnti == rnti) { - LOG_I(MAC, "clean eNb uci_vars[%d] UE %x \n",i, rnti); - memset(&eNB_PHY->uci_vars[i],0,sizeof(LTE_eNB_UCI)); - } - } - */ - if (flexran_agent_get_rrc_xface(mod_id)) { - flexran_agent_get_rrc_xface(mod_id)->flexran_agent_notify_ue_state_change( - mod_id, rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); + flexran_agent_get_rrc_xface(mod_id)->flexran_agent_notify_ue_state_change( mod_id, rnti, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED); } - for(j = 0; j < 10; j++) { - ul_req_tmp = &eNB_MAC->UL_req_tmp[CC_id][j].ul_config_request_body; + for(int j = 0; j < 10; j++) { + nfapi_ul_config_request_body_t *ul_req_tmp = &eNB_MAC->UL_req_tmp[CC_id][j].ul_config_request_body; if(ul_req_tmp) { - pdu_number = ul_req_tmp->number_of_pdus; + int pdu_number = ul_req_tmp->number_of_pdus; for(int pdu_index = pdu_number-1; pdu_index >= 0; pdu_index--) { if((ul_req_tmp->ul_config_pdu_list[pdu_index].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) || @@ -1126,7 +1065,8 @@ void release_UE_in_freeList(module_id_t mod_id) { } if (!NODE_IS_CU(RC.rrc[mod_id]->node_type)) { - rrc_mac_remove_ue(mod_id,rnti); + if (!eNB_MAC->UE_free_ctrl[ue_num].raFlag) + rrc_mac_remove_ue(mod_id,rnti); rrc_rlc_remove_ue(&ctxt); pdcp_remove_UE(&ctxt); } else { @@ -1139,19 +1079,20 @@ void release_UE_in_freeList(module_id_t mod_id) { itti_send_msg_to_task(TASK_CU_F1, mod_id, m); } - if(remove_UEContext) { - ue_context_pP = rrc_eNB_get_ue_context(RC.rrc[mod_id],rnti); - + if(eNB_MAC->UE_free_ctrl[ue_num].removeContextFlg) { + struct rrc_eNB_ue_context_s *ue_context_pP = rrc_eNB_get_ue_context(RC.rrc[mod_id],rnti); if(ue_context_pP) { + LOG_I(PHY, "remove RNTI %04x\n", rnti); rrc_eNB_remove_ue_context(&ctxt,RC.rrc[mod_id], (struct rrc_eNB_ue_context_s *) ue_context_pP); } } - LOG_I(RRC, "[release_UE_in_freeList] remove UE %x from freeList\n", rnti); - remove_UE_from_freelist(mod_id, rnti); + LOG_I(RRC, "[release_UE_in_freeList] remove UE %x from freeList ra context: %d\n", rnti, eNB_MAC->UE_free_ctrl[ue_num].raFlag); + eNB_MAC->UE_free_ctrl[ue_num].rnti = 0; } } + pthread_mutex_unlock(&lock_ue_freelist); } int rrc_eNB_previous_SRB2(rrc_eNB_ue_context_t *ue_context_pP) { @@ -7246,6 +7187,7 @@ rrc_eNB_decode_ccch( LOG_I(RRC," S-TMSI exists, ue_context_p %p, old rnti %x => %x\n",ue_context_p,ue_context_p->ue_context.rnti,ctxt_pP->rnti); if (!NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) { + LOG_I(PHY, "remove RNTI %04x\n", ue_context_p->ue_context.rnti); rrc_mac_remove_ue(ctxt_pP->module_id, ue_context_p->ue_context.rnti); } else { MessageDef *m = itti_alloc_new_message(TASK_RRC_ENB, 0, F1AP_UE_CONTEXT_RELEASE_CMD); diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c index a7a0d2de32..1d464cb90c 100644 --- a/targets/RT/USER/lte-ru.c +++ b/targets/RT/USER/lte-ru.c @@ -89,7 +89,7 @@ void prach_procedures(PHY_VARS_eNB *eNB,int br_flag); void stop_RU(RU_t **rup,int nb_ru); -void do_ru_synch(RU_t *ru); +static void do_ru_synch(RU_t *ru); void configure_ru(int idx, void *arg); @@ -1059,7 +1059,7 @@ int wakeup_synch(RU_t *ru) { } -void do_ru_synch(RU_t *ru) { +static void do_ru_synch(RU_t *ru) { LTE_DL_FRAME_PARMS *fp = ru->frame_parms; RU_proc_t *proc = &ru->proc; int rxs, ic, ret, i; @@ -1924,7 +1924,7 @@ static void *ru_thread( void *param ) { // This thread run the initial synchronization like a UE -void *ru_thread_synch(void *arg) { +static void *ru_thread_synch(void *arg) { RU_t *ru = (RU_t *)arg; __attribute__((unused)) LTE_DL_FRAME_PARMS *fp = ru->frame_parms; diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h index 1c887dd3c8..38b71238b8 100644 --- a/targets/RT/USER/lte-softmodem.h +++ b/targets/RT/USER/lte-softmodem.h @@ -29,6 +29,7 @@ #include "flexran_agent.h" #include "s1ap_eNB.h" #include "SIMULATION/ETH_TRANSPORT/proto.h" +#include "targets/ARCH/COMMON/common_lib.h" #include "executables/softmodem-common.h" @@ -213,5 +214,19 @@ extern void init_UE_standalone_thread(int ue_idx); extern PHY_VARS_UE *init_ue_vars(LTE_DL_FRAME_PARMS *frame_parms, uint8_t UE_id, uint8_t abstraction_flag); extern void init_bler_table(void); - +void feptx_ofdm_2thread(RU_t *ru, + int frame, + int subframe); +void* ru_thread_control( void* param ); +void wait_eNBs(void); +void kill_feptx_thread(RU_t *ru); +void init_fep_thread(RU_t *ru, pthread_attr_t *attr_fep); +void init_feptx_thread(RU_t *ru, pthread_attr_t *attr_feptx); +void fep_full(RU_t *ru, int subframe); +void configure_ru(int, void *arg); +void configure_rru(int, void *arg); +void ru_fep_full_2thread(RU_t *ru,int subframe); +void feptx_ofdm(RU_t*ru, int frame_tx, int tti_tx); +void feptx_prec(struct RU_t_s *ru, int frame_tx, int tti_tx); +void fill_rf_config(RU_t *ru, char *rf_config_file); #endif diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c index 678b6e0401..05602b63da 100644 --- a/targets/RT/USER/lte-uesoftmodem.c +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -176,7 +176,6 @@ extern char uecap_xer[1024]; char uecap_xer_in=0; int oaisim_flag=0; -//threads_t threads= {-1,-1,-1,-1,-1,-1,-1,-1}; /* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed * this is very hackish - find a proper solution