diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index c92f65a60570d0871f1a2e06f42f921d1eb2a97a..2d620093daeb52819a72a307694bada1f0106c11 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -2139,14 +2139,24 @@ target_link_libraries (lte-uesoftmodem-nos1 ${T_LIB}) ################################################### add_executable(nr-softmodem - #${rrc_h} - #${s1ap_h} + ${rrc_h} + ${s1ap_h} + ${OPENAIR_BIN_DIR}/messages_xml.h + ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c + ${OPENAIR_TARGETS}/RT/USER/nr-gnb.c + ${OPENAIR_TARGETS}/RT/USER/nr-ru.c ${OPENAIR_TARGETS}/RT/USER/nr-softmodem.c + ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c + ${OPENAIR_TARGETS}/COMMON/create_tasks.c + ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ${OPENAIR2_DIR}/RRC/NAS/nas_config.c + ${OPENAIR2_DIR}/RRC/NAS/rb_config.c + ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/system.c - #${GTPU_need_ITTI} - #${XFORMS_SOURCE} - #${XFORMS_SOURCE_SOFTMODEM} + ${GTPU_need_ITTI} + ${XFORMS_SOURCE} + ${XFORMS_SOURCE_SOFTMODEM} ${T_SOURCE} ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} @@ -2154,9 +2164,9 @@ add_executable(nr-softmodem target_link_libraries (nr-softmodem -Wl,--start-group - UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY_NR LFDS GTPV1U SECU_CN SECU_OSA + UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY_NR PHY LFDS GTPV1U SECU_CN SECU_OSA ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} - #RRC_LIB S1AP_LIB S1AP_ENB L2 + RRC_LIB S1AP_LIB S1AP_ENB L2 NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -Wl,--end-group z dl) diff --git a/common/ran_context.h b/common/ran_context.h index 4380dc65f12f167a5b2dc99a6a0b98590e74a1de..8d6b02a31ea7f8fd671a4c4b6aa1cb4e2a8f5869 100644 --- a/common/ran_context.h +++ b/common/ran_context.h @@ -77,6 +77,8 @@ typedef struct { flexran_agent_info_t **flexran; /// eNB context variables struct PHY_VARS_eNB_s ***eNB; + /// gNB context variables + struct PHY_VARS_gNB_s ***gNB; /// NB_IoT L1 context variables struct PHY_VARS_eNB_NB_IoT_s **L1_NB_IoT; /// RRC context variables diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h index f665d11c8916f2ce82cea65080f3fad005284e4c..fcfb7e7b25c5ea6971d0adeac1550a0a30e8d51b 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h @@ -1,12 +1,12 @@ /* * Copyright 2017 Cisco Systems, Inc. - * + * * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * + * * 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. @@ -15,7 +15,8 @@ */ -#ifndef _NFAPI_INTERFACE_H_ +#ifndef _NFAPI_INTERFACE_NR_EXTENSION_H_ +#define _NFAPI_INTERFACE_NR_EXTENSION_H_ #define _NFAPI_INTERFACE_H_ #include "stddef.h" @@ -30,7 +31,7 @@ // These may be changed if desired. They are used in the encoder to make sure // that the user has not specified a 'count' larger than the max array, and also // used by the decoder when decode an array. If the 'count' received is larger -// than the array it is to be stored in the decode fails. +// than the array it is to be stored in the decode fails. #define NFAPI_MAX_NUM_ANTENNAS 8 #define NFAPI_MAX_NUM_SUBBANDS 13 #define NFAPI_MAX_BF_VECTORS 8 @@ -338,7 +339,8 @@ typedef enum { NFAPI_3GPP_REL_SUPPORTED_9 = 1, NFAPI_3GPP_REL_SUPPORTED_10 = 2, NFAPI_3GPP_REL_SUPPORTED_11 = 4, - NFAPI_3GPP_REL_SUPPORTED_12 = 8 + NFAPI_3GPP_REL_SUPPORTED_12 = 8, + NFAPI_3GPP_REL_SUPPORTED_15 = 64 } nfapi_3gpp_release_supported_e; @@ -357,7 +359,8 @@ typedef enum { NFAPI_RAT_TYPE_LTE = 0, NFAPI_RAT_TYPE_UTRAN = 1, NFAPI_RAT_TYPE_GERAN = 2, - NFAPI_RAT_TYPE_NB_IOT = 3 + NFAPI_RAT_TYPE_NB_IOT = 3, + NFAPI_RAT_TYPE_NR = 4 } nfapi_rat_type_e; typedef enum { @@ -534,6 +537,16 @@ typedef struct { } nfapi_pnf_phy_rel13_nb_iot_t; #define NFAPI_PNF_PHY_REL13_NB_IOT_TAG 0x100E +typedef struct { + uint16_t phy_config_index; +} nfapi_pnf_phy_rel15_info_t; + +typedef struct { + nfapi_tl_t tl; + uint16_t number_of_phys; + nfapi_pnf_phy_rel15_info_t phy[NFAPI_MAX_PNF_PHY]; +} nfapi_pnf_phy_rel15_t; +#define NFAPI_PNF_PHY_REL15_TAG 0x100H typedef struct { @@ -619,6 +632,7 @@ typedef struct { #define NFAPI_L23_CONFIG_SFNSF_TAG 0x00F1 typedef struct { + nfapi_uint16_tlv_t numerology_index_mu; nfapi_uint16_tlv_t duplex_mode; nfapi_uint16_tlv_t pcfich_power_offset; nfapi_uint16_tlv_t pb; @@ -631,6 +645,7 @@ typedef struct { #define NFAPI_SUBFRAME_CONFIG_PB_TAG 0x0003 #define NFAPI_SUBFRAME_CONFIG_DL_CYCLIC_PREFIX_TYPE_TAG 0x0004 #define NFAPI_SUBFRAME_CONFIG_UL_CYCLIC_PREFIX_TYPE_TAG 0x0005 +#define NFAPI_SUBFRAME_CONFIG_NUMEROLOGY_INDEX_MU_TAG 0x0006 typedef struct { nfapi_uint16_tlv_t dl_channel_bandwidth; @@ -656,15 +671,30 @@ typedef struct { #define NFAPI_PHICH_CONFIG_PHICH_DURATION_TAG 0x0015 #define NFAPI_PHICH_CONFIG_PHICH_POWER_OFFSET_TAG 0x0016 +typedef enum { + NFAPI_HALF_FRAME_INDEX_FIRST_HALF = 0, + NFAPI_HALF_FRAME_INDEX_SECOND_HALF = 1 +} nfapi_half_frame_index_e; + typedef struct { nfapi_uint16_tlv_t primary_synchronization_signal_epre_eprers; nfapi_uint16_tlv_t secondary_synchronization_signal_epre_eprers; nfapi_uint16_tlv_t physical_cell_id; + nfapi_half_frame_index_e half_frame_index; + nfapi_uint16_tlv_t ssb_subcarrier_offset; + nfapi_uint16_tlv_t ssb_position_in_burst; + nfapi_uint16_tlv_t ssb_periodicity; + nfapi_uint16_tlv_t ss_pbch_block_power; } nfapi_sch_config_t; #define NFAPI_SCH_CONFIG_PRIMARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG 0x001E #define NFAPI_SCH_CONFIG_SECONDARY_SYNCHRONIZATION_SIGNAL_EPRE_EPRERS_TAG 0x001F #define NFAPI_SCH_CONFIG_PHYSICAL_CELL_ID_TAG 0x0020 +#define NFAPI_SCH_CONFIG_HALF_FRAME_INDEX_TAG 0x0021 +#define NFAPI_SCH_CONFIG_SSB_SUBCARRIER_OFFSET_TAG 0x0022 +#define NFAPI_SCH_CONFIG_SSB_POSITION_IN_BURST 0x0023 +#define NFAPI_SCH_CONFIG_SSB_PERIODICITY 0x0024 +#define NFAPI_SCH_CONFIG_SS_PBCH_BLOCK_POWER 0x0025 typedef struct { nfapi_uint16_tlv_t configuration_index; @@ -1038,6 +1068,7 @@ typedef struct { nfapi_pnf_phy_rel12_t pnf_phy_rel12; nfapi_pnf_phy_rel13_t pnf_phy_rel13; nfapi_pnf_phy_rel13_nb_iot_t pnf_phy_rel13_nb_iot; + nfapi_pnf_phy_rel15_t pnf_phy_rel15; nfapi_vendor_extension_tlv_t vendor_extension; } nfapi_pnf_param_response_t; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface_nr_extension.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface_nr_extension.h index 7a04ffc7e4c10fa128d347dccabdf0fc81b064ff..fcfb7e7b25c5ea6971d0adeac1550a0a30e8d51b 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface_nr_extension.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface_nr_extension.h @@ -1,12 +1,12 @@ /* * Copyright 2017 Cisco Systems, Inc. - * + * * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * + * * 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. @@ -15,7 +15,8 @@ */ -#ifndef _NFAPI_INTERFACE_H_ +#ifndef _NFAPI_INTERFACE_NR_EXTENSION_H_ +#define _NFAPI_INTERFACE_NR_EXTENSION_H_ #define _NFAPI_INTERFACE_H_ #include "stddef.h" @@ -30,7 +31,7 @@ // These may be changed if desired. They are used in the encoder to make sure // that the user has not specified a 'count' larger than the max array, and also // used by the decoder when decode an array. If the 'count' received is larger -// than the array it is to be stored in the decode fails. +// than the array it is to be stored in the decode fails. #define NFAPI_MAX_NUM_ANTENNAS 8 #define NFAPI_MAX_NUM_SUBBANDS 13 #define NFAPI_MAX_BF_VECTORS 8 diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index c47f2b4bbfaa0719e51a8cc73f55f0a182611af7..a8fc34de9438b8869b8f07533f2cb54f8014b5cc 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -20,18 +20,519 @@ */ #include "../defs_NR.h" +#include "SCHED/defs.h" +#include "PHY/extern.h" +#include "SIMULATION/TOOLS/defs.h" +#include "RadioResourceConfigCommonSIB.h" +#include "RadioResourceConfigDedicated.h" +#include "TDD-Config.h" +#include "LAYER2/MAC/extern.h" +#include "MBSFN-SubframeConfigList.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "assertions.h" +#include <math.h> -int phy_init_nr_gNB(nfapi_config_request_t *config) +extern uint32_t from_earfcn(int eutra_bandP,uint32_t dl_earfcn); +extern int32_t get_uldl_offset(int eutra_bandP); + +int l1_north_init_gNB() { + + int i,j; + + if (RC.nb_L1_inst > 0 && RC.nb_L1_CC != NULL && RC.gNB != NULL) + { + AssertFatal(RC.nb_L1_inst>0,"nb_L1_inst=%d\n",RC.nb_L1_inst); + AssertFatal(RC.nb_L1_CC!=NULL,"nb_L1_CC is null\n"); + AssertFatal(RC.gNB!=NULL,"RC.gNB is null\n"); + + LOG_I(PHY,"%s() RC.nb_L1_inst:%d\n", __FUNCTION__, RC.nb_L1_inst); + + for (i=0;i<RC.nb_L1_inst;i++) { + AssertFatal(RC.gNB[i]!=NULL,"RC.gNB[%d] is null\n",i); + AssertFatal(RC.nb_L1_CC[i]>0,"RC.nb_L1_CC[%d]=%d\n",i,RC.nb_L1_CC[i]); + + LOG_I(PHY,"%s() RC.nb_L1_CC[%d]:%d\n", __FUNCTION__, i, RC.nb_L1_CC[i]); + + for (j=0;j<RC.nb_L1_CC[i];j++) { + AssertFatal(RC.gNB[i][j]!=NULL,"RC.gNB[%d][%d] is null\n",i,j); + + if ((RC.gNB[i][j]->if_inst = IF_Module_init(i))<0) return(-1); + + LOG_I(PHY,"%s() RC.gNB[%d][%d] installing callbacks\n", __FUNCTION__, i, j); + + RC.gNB[i][j]->if_inst->PHY_config_req = phy_config_request; + RC.gNB[i][j]->if_inst->schedule_response = schedule_response; + } + } + } + else + { + LOG_I(PHY,"%s() Not installing PHY callbacks - RC.nb_L1_inst:%d RC.nb_L1_CC:%p RC.gNB:%p\n", __FUNCTION__, RC.nb_L1_inst, RC.nb_L1_CC, RC.gNB); + } + return(0); +} + + +int phy_init_nr_gNB(PHY_VARS_gNB *gNB, + unsigned char is_secondary_gNB, + unsigned char abstraction_flag) { - config->subframe_config.numerology_index_mu.value =1; - config->subframe_config.duplex_mode.value = 1; //FDD - config->subframe_config.dl_cyclic_prefix_type.value = 0; //NORMAL - config->rf_config.dl_channel_bandwidth.value = 106; - config->rf_config.ul_channel_bandwidth.value = 106; - config->rf_config.tx_antenna_ports.value = 1; + // shortcuts + NR_DL_FRAME_PARMS* const fp = &gNB->frame_parms; + nfapi_config_request_t* cfg = &gNB->gNB_config; + NR_gNB_COMMON* const common_vars = &gNB->common_vars; + LTE_eNB_PUSCH** const pusch_vars = gNB->pusch_vars; + LTE_eNB_SRS* const srs_vars = gNB->srs_vars; + LTE_eNB_PRACH* const prach_vars = &gNB->prach_vars; + + int i, UE_id; + + LOG_I(PHY,"[gNB %d] %s() About to wait for gNB to be configured", gNB->Mod_id, __FUNCTION__); + + gNB->total_dlsch_bitrate = 0; + gNB->total_transmitted_bits = 0; + gNB->total_system_throughput = 0; + gNB->check_for_MUMIMO_transmissions=0; + + while(gNB->configured == 0) usleep(10000); +/* + LOG_I(PHY,"[gNB %"PRIu8"] Initializing DL_FRAME_PARMS : N_RB_DL %"PRIu8", PHICH Resource %d, PHICH Duration %d nb_antennas_tx:%u nb_antennas_rx:%u PRACH[rootSequenceIndex:%u prach_Config_enabled:%u configIndex:%u highSpeed:%u zeroCorrelationZoneConfig:%u freqOffset:%u]\n", + gNB->Mod_id, + fp->N_RB_DL,fp->phich_config_common.phich_resource, + fp->phich_config_common.phich_duration, + fp->nb_antennas_tx, fp->nb_antennas_rx, + fp->prach_config_common.rootSequenceIndex, + fp->prach_config_common.prach_Config_enabled, + fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex, + fp->prach_config_common.prach_ConfigInfo.highSpeedFlag, + fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset + );*/ + LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_gNB][MOD %02"PRIu8"][]\n", gNB->Mod_id); + +/* + lte_gold(fp,gNB->lte_gold_table,fp->Nid_cell); + generate_pcfich_reg_mapping(fp); + generate_phich_reg_mapping(fp);*/ + + for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { + gNB->first_run_timing_advance[UE_id] = + 1; ///This flag used to be static. With multiple gNBs this does no longer work, hence we put it in the structure. However it has to be initialized with 1, which is performed here. + + // clear whole structure + bzero( &gNB->UE_stats[UE_id], sizeof(LTE_eNB_UE_stats) ); + + gNB->physicalConfigDedicated[UE_id] = NULL; + } + + gNB->first_run_I0_measurements = 1; ///This flag used to be static. With multiple gNBs this does no longer work, hence we put it in the structure. However it has to be initialized with 1, which is performed here. + + + common_vars->rxdata = (int32_t **)NULL; + common_vars->txdataF = (int32_t **)malloc16(NB_ANTENNA_PORTS_ENB*sizeof(int32_t*)); + common_vars->rxdataF = (int32_t **)malloc16(64*sizeof(int32_t*)); + + LOG_D(PHY,"[INIT] NB_ANTENNA_PORTS_ENB:%d fp->nb_antenna_ports_gNB:%d\n", NB_ANTENNA_PORTS_ENB, cfg->rf_config.tx_antenna_ports.value); + + for (i=0; i<NB_ANTENNA_PORTS_ENB; i++) { + if (i<cfg->rf_config.tx_antenna_ports.value || i==5) { + common_vars->txdataF[i] = (int32_t*)malloc16_clear(fp->samples_per_frame_wCP*sizeof(int32_t) ); + + LOG_D(PHY,"[INIT] common_vars->txdataF[%d] = %p (%lu bytes)\n", + i,common_vars->txdataF[i], + fp->samples_per_frame_wCP*sizeof(int32_t)); + } + } + + + // Channel estimates for SRS + for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { + + srs_vars[UE_id].srs_ch_estimates = (int32_t**)malloc16( 64*sizeof(int32_t*) ); + srs_vars[UE_id].srs_ch_estimates_time = (int32_t**)malloc16( 64*sizeof(int32_t*) ); + + for (i=0; i<64; i++) { + srs_vars[UE_id].srs_ch_estimates[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size ); + srs_vars[UE_id].srs_ch_estimates_time[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2 ); + } + } //UE_id + + + /*generate_ul_ref_sigs_rx(); + + init_ulsch_power_LUT();*/ + + // SRS + for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { + srs_vars[UE_id].srs = (int32_t*)malloc16_clear(2*fp->ofdm_symbol_size*sizeof(int32_t)); + } + + // PRACH + prach_vars->prachF = (int16_t*)malloc16_clear( 1024*2*sizeof(int16_t) ); + + // assume maximum of 64 RX antennas for PRACH receiver + prach_vars->prach_ifft[0] = (int32_t**)malloc16_clear(64*sizeof(int32_t*)); + for (i=0;i<64;i++) prach_vars->prach_ifft[0][i] = (int32_t*)malloc16_clear(1024*2*sizeof(int32_t)); + + prach_vars->rxsigF[0] = (int16_t**)malloc16_clear(64*sizeof(int16_t*)); + + for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { + + //FIXME + pusch_vars[UE_id] = (LTE_eNB_PUSCH*)malloc16_clear( NUMBER_OF_UE_MAX*sizeof(LTE_eNB_PUSCH) ); + + pusch_vars[UE_id]->rxdataF_ext = (int32_t**)malloc16( 2*sizeof(int32_t*) ); + pusch_vars[UE_id]->rxdataF_ext2 = (int32_t**)malloc16( 2*sizeof(int32_t*) ); + pusch_vars[UE_id]->drs_ch_estimates = (int32_t**)malloc16( 2*sizeof(int32_t*) ); + pusch_vars[UE_id]->drs_ch_estimates_time = (int32_t**)malloc16( 2*sizeof(int32_t*) ); + pusch_vars[UE_id]->rxdataF_comp = (int32_t**)malloc16( 2*sizeof(int32_t*) ); + pusch_vars[UE_id]->ul_ch_mag = (int32_t**)malloc16( 2*sizeof(int32_t*) ); + pusch_vars[UE_id]->ul_ch_magb = (int32_t**)malloc16( 2*sizeof(int32_t*) ); + + for (i=0; i<2; i++) { + // RK 2 times because of output format of FFT! + // FIXME We should get rid of this + pusch_vars[UE_id]->rxdataF_ext[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_channel_bandwidth.value*12*fp->symbols_per_slot ); + pusch_vars[UE_id]->rxdataF_ext2[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_channel_bandwidth.value*12*fp->symbols_per_slot ); + pusch_vars[UE_id]->drs_ch_estimates[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_channel_bandwidth.value*12*fp->symbols_per_slot ); + pusch_vars[UE_id]->drs_ch_estimates_time[i] = (int32_t*)malloc16_clear( 2*sizeof(int32_t)*fp->ofdm_symbol_size ); + pusch_vars[UE_id]->rxdataF_comp[i] = (int32_t*)malloc16_clear( sizeof(int32_t)*cfg->rf_config.ul_channel_bandwidth.value*12*fp->symbols_per_slot ); + pusch_vars[UE_id]->ul_ch_mag[i] = (int32_t*)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_channel_bandwidth.value*12 ); + pusch_vars[UE_id]->ul_ch_magb[i] = (int32_t*)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*cfg->rf_config.ul_channel_bandwidth.value*12 ); + } + + pusch_vars[UE_id]->llr = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); + } //UE_id + + + for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) + gNB->UE_stats_ptr[UE_id] = &gNB->UE_stats[UE_id]; + + gNB->pdsch_config_dedicated->p_a = dB0; //defaul value until overwritten by RRCConnectionReconfiguration + + + return (0); + +} + +/* + +void phy_config_request(PHY_Config_t *phy_config) { + + uint8_t Mod_id = phy_config->Mod_id; + int CC_id = phy_config->CC_id; + nfapi_config_request_t *cfg = phy_config->cfg; + + + LTE_DL_FRAME_PARMS *fp; + PHICH_RESOURCE_t phich_resource_table[4]={oneSixth,half,one,two}; + int eutra_band = cfg->nfapi_config.rf_bands.rf_band[0]; + int dl_Bandwidth = cfg->rf_config.dl_channel_bandwidth.value; + int ul_Bandwidth = cfg->rf_config.ul_channel_bandwidth.value; + int Nid_cell = cfg->sch_config.physical_cell_id.value; + int Ncp = cfg->subframe_config.dl_cyclic_prefix_type.value; + int p_eNB = cfg->rf_config.tx_antenna_ports.value; + uint32_t dl_CarrierFreq = cfg->nfapi_config.earfcn.value; + + LOG_I(PHY,"Configuring MIB for instance %d, CCid %d : (band %d,N_RB_DL %d, N_RB_UL %d, Nid_cell %d,eNB_tx_antenna_ports %d,Ncp %d,DL freq %u,phich_config.resource %d, phich_config.duration %d)\n", + Mod_id, CC_id, eutra_band, dl_Bandwidth, ul_Bandwidth, Nid_cell, p_eNB,Ncp,dl_CarrierFreq, + cfg->phich_config.phich_resource.value, + cfg->phich_config.phich_duration.value); + + AssertFatal(RC.eNB != NULL, "PHY instance pointer doesn't exist\n"); + AssertFatal(RC.eNB[Mod_id] != NULL, "PHY instance %d doesn't exist\n",Mod_id); + AssertFatal(RC.eNB[Mod_id][CC_id] != NULL, "PHY instance %d, CCid %d doesn't exist\n",Mod_id,CC_id); + + + if (RC.eNB[Mod_id][CC_id]->configured == 1) + { + LOG_E(PHY,"Already eNB already configured, do nothing\n"); + return; + } + + RC.eNB[Mod_id][CC_id]->mac_enabled = 1; + + fp = &RC.eNB[Mod_id][CC_id]->frame_parms; + + fp->N_RB_DL = dl_Bandwidth; + fp->N_RB_UL = ul_Bandwidth; + fp->Nid_cell = Nid_cell; + fp->nushift = fp->Nid_cell%6; + fp->eutra_band = eutra_band; + fp->Ncp = Ncp; + fp->Ncp_UL = Ncp; + fp->nb_antenna_ports_eNB = p_eNB; + + fp->threequarter_fs = 0; + + AssertFatal(cfg->phich_config.phich_resource.value<4, "Illegal phich_Resource\n"); + + fp->phich_config_common.phich_resource = phich_resource_table[cfg->phich_config.phich_resource.value]; + fp->phich_config_common.phich_duration = cfg->phich_config.phich_duration.value; + // Note: "from_earfcn" has to be in a common library with MACRLC + fp->dl_CarrierFreq = from_earfcn(eutra_band,dl_CarrierFreq); + fp->ul_CarrierFreq = fp->dl_CarrierFreq - (get_uldl_offset(eutra_band)*100000); + + fp->tdd_config = 0; + fp->tdd_config_S = 0; - config->sch_config.physical_cell_id.value = 0; + if (fp->dl_CarrierFreq==fp->ul_CarrierFreq) + fp->frame_type = TDD; + else + fp->frame_type = FDD; - return 0; + init_frame_parms(fp,1); + init_lte_top(fp); + + if (cfg->subframe_config.duplex_mode.value == 0) { + fp->tdd_config = cfg->tdd_frame_structure_config.subframe_assignment.value; + fp->tdd_config_S = cfg->tdd_frame_structure_config.special_subframe_patterns.value; + fp->frame_type = TDD; + } + else { + fp->frame_type = FDD; + } + + fp->prach_config_common.rootSequenceIndex = cfg->prach_config.root_sequence_index.value; + LOG_I(PHY,"prach_config_common.rootSequenceIndex = %d\n",cfg->prach_config.root_sequence_index.value); + + fp->prach_config_common.prach_Config_enabled=1; + + fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex =cfg->prach_config.configuration_index.value; + LOG_I(PHY,"prach_config_common.prach_ConfigInfo.prach_ConfigIndex = %d\n",cfg->prach_config.configuration_index.value); + + fp->prach_config_common.prach_ConfigInfo.highSpeedFlag =cfg->prach_config.high_speed_flag.value; + LOG_I(PHY,"prach_config_common.prach_ConfigInfo.highSpeedFlag = %d\n",cfg->prach_config.high_speed_flag.value); + fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig =cfg->prach_config.zero_correlation_zone_configuration.value; + LOG_I(PHY,"prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig = %d\n",cfg->prach_config.zero_correlation_zone_configuration.value); + fp->prach_config_common.prach_ConfigInfo.prach_FreqOffset =cfg->prach_config.frequency_offset.value; + LOG_I(PHY,"prach_config_common.prach_ConfigInfo.prach_FreqOffset = %d\n",cfg->prach_config.frequency_offset.value); + + init_prach_tables(839); + compute_prach_seq(fp->prach_config_common.rootSequenceIndex, + fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex, + fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + RC.eNB[Mod_id][CC_id]->X_u); + +#ifdef Rel14 + fp->prach_emtc_config_common.prach_Config_enabled=1; + + fp->prach_emtc_config_common.rootSequenceIndex = cfg->emtc_config.prach_catm_root_sequence_index.value; + + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag = cfg->emtc_config.prach_catm_high_speed_flag.value; + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig = cfg->emtc_config.prach_catm_zero_correlation_zone_configuration.value; + + // CE Level 3 parameters + fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[3] = cfg->emtc_config.prach_ce_level_3_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[3] = cfg->emtc_config.prach_ce_level_3_starting_subframe_periodicity.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[3] = cfg->emtc_config.prach_ce_level_3_number_of_repetitions_per_attempt.value; + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[3]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[3], + "prach_starting_subframe_periodicity[3] < prach_numPetitionPerPreambleAttempt[3]\n"); + + + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3] = cfg->emtc_config.prach_ce_level_3_configuration_index.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[3] = cfg->emtc_config.prach_ce_level_3_frequency_offset.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[3] = cfg->emtc_config.prach_ce_level_3_hopping_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[3] = cfg->emtc_config.prach_ce_level_3_hopping_offset.value; + if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[3] == 1) + compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + RC.eNB[Mod_id][CC_id]->X_u_br[3]); + + // CE Level 2 parameters + fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[2] = cfg->emtc_config.prach_ce_level_2_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[2] = cfg->emtc_config.prach_ce_level_2_starting_subframe_periodicity.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[2] = cfg->emtc_config.prach_ce_level_2_number_of_repetitions_per_attempt.value; + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[2]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[2], + "prach_starting_subframe_periodicity[2] < prach_numPetitionPerPreambleAttempt[2]\n"); + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[2] = cfg->emtc_config.prach_ce_level_2_configuration_index.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[2] = cfg->emtc_config.prach_ce_level_2_frequency_offset.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[2] = cfg->emtc_config.prach_ce_level_2_hopping_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[2] = cfg->emtc_config.prach_ce_level_2_hopping_offset.value; + if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[2] == 1) + compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + RC.eNB[Mod_id][CC_id]->X_u_br[2]); + + // CE Level 1 parameters + fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[1] = cfg->emtc_config.prach_ce_level_1_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[1] = cfg->emtc_config.prach_ce_level_1_starting_subframe_periodicity.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[1] = cfg->emtc_config.prach_ce_level_1_number_of_repetitions_per_attempt.value; + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[1]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[1], + "prach_starting_subframe_periodicity[1] < prach_numPetitionPerPreambleAttempt[1]\n"); + + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[1] = cfg->emtc_config.prach_ce_level_1_configuration_index.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[1] = cfg->emtc_config.prach_ce_level_1_frequency_offset.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[1] = cfg->emtc_config.prach_ce_level_1_hopping_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[1] = cfg->emtc_config.prach_ce_level_1_hopping_offset.value; + if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[1] == 1) + compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + RC.eNB[Mod_id][CC_id]->X_u_br[1]); + + // CE Level 0 parameters + fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] = cfg->emtc_config.prach_ce_level_0_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0] = cfg->emtc_config.prach_ce_level_0_starting_subframe_periodicity.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0] = cfg->emtc_config.prach_ce_level_0_number_of_repetitions_per_attempt.value; + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0]>=fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0], + "prach_starting_subframe_periodicity[0] %d < prach_numPetitionPerPreambleAttempt[0] %d\n", + fp->prach_emtc_config_common.prach_ConfigInfo.prach_starting_subframe_periodicity[0], + fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0]); +#if 0 + AssertFatal(fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0] > 0, + "prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0]==0\n"); +#else + LOG_E(PHY,"***DJP*** removed assert on preamble fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0]:%d expecting >0 %s:%d\n\n\n", fp->prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[0], __FILE__, __LINE__); +#endif + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[0] = cfg->emtc_config.prach_ce_level_0_configuration_index.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[0] = cfg->emtc_config.prach_ce_level_0_frequency_offset.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_enable[0] = cfg->emtc_config.prach_ce_level_0_hopping_enable.value; + fp->prach_emtc_config_common.prach_ConfigInfo.prach_hopping_offset[0] = cfg->emtc_config.prach_ce_level_0_hopping_offset.value; + if (fp->prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) + compute_prach_seq(fp->prach_emtc_config_common.rootSequenceIndex, + fp->prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[3], + fp->prach_emtc_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig, + fp->prach_emtc_config_common.prach_ConfigInfo.highSpeedFlag, + fp->frame_type, + RC.eNB[Mod_id][CC_id]->X_u_br[0]); +#endif + + + + fp->pucch_config_common.deltaPUCCH_Shift = 1+cfg->pucch_config.delta_pucch_shift.value; + fp->pucch_config_common.nRB_CQI = cfg->pucch_config.n_cqi_rb.value; + fp->pucch_config_common.nCS_AN = cfg->pucch_config.n_an_cs.value; + fp->pucch_config_common.n1PUCCH_AN = cfg->pucch_config.n1_pucch_an.value; + + fp->pdsch_config_common.referenceSignalPower = cfg->rf_config.reference_signal_power.value; + fp->pdsch_config_common.p_b = cfg->subframe_config.pb.value; + + fp->pusch_config_common.n_SB = cfg->pusch_config.number_of_subbands.value; + LOG_I(PHY,"pusch_config_common.n_SB = %d\n",fp->pusch_config_common.n_SB ); + + fp->pusch_config_common.hoppingMode = cfg->pusch_config.hopping_mode.value; + LOG_I(PHY,"pusch_config_common.hoppingMode = %d\n",fp->pusch_config_common.hoppingMode); + + fp->pusch_config_common.pusch_HoppingOffset = cfg->pusch_config.hopping_offset.value; + LOG_I(PHY,"pusch_config_common.pusch_HoppingOffset = %d\n",fp->pusch_config_common.pusch_HoppingOffset); + + fp->pusch_config_common.enable64QAM = 0;//radioResourceConfigCommon->pusch_ConfigCommon.pusch_ConfigBasic.enable64QAM; + LOG_I(PHY,"pusch_config_common.enable64QAM = %d\n",fp->pusch_config_common.enable64QAM ); + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0; + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0; + if (cfg->uplink_reference_signal_config.uplink_rs_hopping.value == 1) + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 1; + if (cfg->uplink_reference_signal_config.uplink_rs_hopping.value == 2) + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 1; + LOG_I(PHY,"pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = %d\n",fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled); + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = cfg->uplink_reference_signal_config.group_assignment.value; + LOG_I(PHY,"pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = %d\n",fp->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH); + + LOG_I(PHY,"pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = %d\n",fp->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled); + + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = dmrs1_tab[cfg->uplink_reference_signal_config.cyclic_shift_1_for_drms.value]; + LOG_I(PHY,"pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = %d\n",fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift); + + init_ul_hopping(fp); + + fp->soundingrs_ul_config_common.enabled_flag = 0;// 1; Don't know how to turn this off in NFAPI + fp->soundingrs_ul_config_common.srs_BandwidthConfig = cfg->srs_config.bandwidth_configuration.value; + fp->soundingrs_ul_config_common.srs_SubframeConfig = cfg->srs_config.srs_subframe_configuration.value; + fp->soundingrs_ul_config_common.ackNackSRS_SimultaneousTransmission = cfg->srs_config.srs_acknack_srs_simultaneous_transmission.value; + fp->soundingrs_ul_config_common.srs_MaxUpPts = cfg->srs_config.max_up_pts.value; + + fp->num_MBSFN_config = 0; + + init_ncs_cell(fp,RC.eNB[Mod_id][CC_id]->ncs_cell); + + + init_ul_hopping(fp); + RC.eNB[Mod_id][CC_id]->configured = 1; + LOG_I(PHY,"eNB %d/%d configured\n",Mod_id,CC_id); +} + +*/ + + +void phy_free_nr_gNB(PHY_VARS_gNB *gNB) +{ +// NR_DL_FRAME_PARMS* const fp = &gNB->frame_parms; + nfapi_config_request_t *cfg = &gNB->gNB_config; + NR_gNB_COMMON* const common_vars = &gNB->common_vars; + LTE_eNB_PUSCH** const pusch_vars = gNB->pusch_vars; + LTE_eNB_SRS* const srs_vars = gNB->srs_vars; + LTE_eNB_PRACH* const prach_vars = &gNB->prach_vars; + + int i, UE_id; + + for (i = 0; i < NB_ANTENNA_PORTS_ENB; i++) { + if (i < cfg->rf_config.tx_antenna_ports.value || i == 5) { + free_and_zero(common_vars->txdataF[i]); + /* rxdataF[i] is not allocated -> don't free */ + } + } + free_and_zero(common_vars->txdataF); + free_and_zero(common_vars->rxdataF); + + // Channel estimates for SRS + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) { + for (i=0; i<64; i++) { + free_and_zero(srs_vars[UE_id].srs_ch_estimates[i]); + free_and_zero(srs_vars[UE_id].srs_ch_estimates_time[i]); + } + free_and_zero(srs_vars[UE_id].srs_ch_estimates); + free_and_zero(srs_vars[UE_id].srs_ch_estimates_time); + } //UE_id + + free_ul_ref_sigs(); + + for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) free_and_zero(srs_vars[UE_id].srs); + + free_and_zero(prach_vars->prachF); + + for (i = 0; i < 64; i++) free_and_zero(prach_vars->prach_ifft[0][i]); + free_and_zero(prach_vars->prach_ifft[0]); + + free_and_zero(prach_vars->rxsigF[0]); + + for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { + for (i = 0; i < 2; i++) { + free_and_zero(pusch_vars[UE_id]->rxdataF_ext[i]); + free_and_zero(pusch_vars[UE_id]->rxdataF_ext2[i]); + free_and_zero(pusch_vars[UE_id]->drs_ch_estimates[i]); + free_and_zero(pusch_vars[UE_id]->drs_ch_estimates_time[i]); + free_and_zero(pusch_vars[UE_id]->rxdataF_comp[i]); + free_and_zero(pusch_vars[UE_id]->ul_ch_mag[i]); + free_and_zero(pusch_vars[UE_id]->ul_ch_magb[i]); + } + free_and_zero(pusch_vars[UE_id]->rxdataF_ext); + free_and_zero(pusch_vars[UE_id]->rxdataF_ext2); + free_and_zero(pusch_vars[UE_id]->drs_ch_estimates); + free_and_zero(pusch_vars[UE_id]->drs_ch_estimates_time); + free_and_zero(pusch_vars[UE_id]->rxdataF_comp); + free_and_zero(pusch_vars[UE_id]->ul_ch_mag); + free_and_zero(pusch_vars[UE_id]->ul_ch_magb); + free_and_zero(pusch_vars[UE_id]->llr); + free_and_zero(pusch_vars[UE_id]); + } //UE_id + + for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++) gNB->UE_stats_ptr[UE_id] = NULL; +} + +void install_schedule_handlers(IF_Module_t *if_inst) +{ + if_inst->PHY_config_req = phy_config_request; + if_inst->schedule_response = schedule_response; } diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index 7cc1318c9cafde6b77398ae40bcd7a66b3845d74..82f9b7bfccc84996b234bdd6fe43b4094aeb63c0 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -24,6 +24,7 @@ /// Subcarrier spacings in Hz indexed by numerology index uint32_t nr_subcarrier_spacing[MAX_NUM_SUBCARRIER_SPACING] = {15e3, 30e3, 60e3, 120e3, 240e3}; +uint16_t nr_slots_per_subframe[MAX_NUM_SUBCARRIER_SPACING] = {1, 2, 4, 16, 32}; int nr_init_frame_parms(nfapi_config_request_t config, NR_DL_FRAME_PARMS *frame_parms) @@ -36,8 +37,7 @@ int nr_init_frame_parms(nfapi_config_request_t config, #if DISABLE_LOG_X printf("Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, N_RB, Ncp); #else - //LOG_I(PHY,"Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, N_RB, Ncp); - printf("Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, N_RB, Ncp); + LOG_I(PHY,"Initializing frame parms for mu %d, N_RB %d, Ncp %d\n",mu, N_RB, Ncp); #endif if (Ncp == 1) //EXTENDED, to be modified after lte defs are properly linked @@ -47,10 +47,12 @@ int nr_init_frame_parms(nfapi_config_request_t config, case NR_MU_0: //15kHz scs frame_parms->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_0]; + frame_parms->slots_per_subframe = nr_slots_per_subframe[NR_MU_0]; break; case NR_MU_1: //30kHz scs frame_parms->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_1]; + frame_parms->slots_per_subframe = nr_slots_per_subframe[NR_MU_1]; switch(N_RB){ case 11: @@ -62,7 +64,7 @@ int nr_init_frame_parms(nfapi_config_request_t config, case 106: //40 MHz frame_parms->ofdm_symbol_size = 2048; - frame_parms->samples_per_tti = 30720; + //frame_parms->samples_per_tti = 30720; frame_parms->first_carrier_offset = 1412; //2048 - 636 frame_parms->nb_prefix_samples0 = 160; frame_parms->nb_prefix_samples = 144; @@ -75,14 +77,14 @@ int nr_init_frame_parms(nfapi_config_request_t config, case 217: //80 MHz if (frame_parms->threequarter_fs) { frame_parms->ofdm_symbol_size = 3072; - frame_parms->samples_per_tti = 46080; + //frame_parms->samples_per_tti = 46080; frame_parms->first_carrier_offset = 1770; //3072 - 1302 frame_parms->nb_prefix_samples0 = 240; frame_parms->nb_prefix_samples = 216; } else { frame_parms->ofdm_symbol_size = 4096; - frame_parms->samples_per_tti = 61440; + //frame_parms->samples_per_tti = 61440; frame_parms->first_carrier_offset = 2794; //4096 - 1302 frame_parms->nb_prefix_samples0 = 320; frame_parms->nb_prefix_samples = 288; @@ -98,6 +100,7 @@ int nr_init_frame_parms(nfapi_config_request_t config, case NR_MU_2: //60kHz scs frame_parms->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_2]; + frame_parms->slots_per_subframe = nr_slots_per_subframe[NR_MU_2]; switch(N_RB){ //FR1 bands only case 11: @@ -119,29 +122,32 @@ int nr_init_frame_parms(nfapi_config_request_t config, case NR_MU_3: frame_parms->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_3]; + frame_parms->slots_per_subframe = nr_slots_per_subframe[NR_MU_3]; break; case NR_MU_4: frame_parms->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_4]; + frame_parms->slots_per_subframe = nr_slots_per_subframe[NR_MU_4]; break; default: AssertFatal(1==0,"Invalid numerology index %d", mu); } + frame_parms->samples_per_subframe_wCP = frame_parms->ofdm_symbol_size * ((Ncp == 0)? 14 : 12) * frame_parms->slots_per_subframe; + frame_parms->samples_per_frame_wCP = 10 * frame_parms->samples_per_subframe_wCP; + + return 0; } void nr_dump_frame_parms(NR_DL_FRAME_PARMS *frame_parms) { - /*LOG_I(PHY,"frame_parms->scs=%d\n",frame_parms->subcarrier_spacing); + LOG_I(PHY,"frame_parms->scs=%d\n",frame_parms->subcarrier_spacing); LOG_I(PHY,"frame_parms->ofdm_symbol_size=%d\n",frame_parms->ofdm_symbol_size); - LOG_I(PHY,"frame_parms->samples_per_tti=%d\n",frame_parms->samples_per_tti); LOG_I(PHY,"frame_parms->nb_prefix_samples0=%d\n",frame_parms->nb_prefix_samples0); - LOG_I(PHY,"frame_parms->nb_prefix_samples=%d\n",frame_parms->nb_prefix_samples);*/ - printf("frame_parms->scs=%d\n",frame_parms->subcarrier_spacing); - printf("frame_parms->ofdm_symbol_size=%d\n",frame_parms->ofdm_symbol_size); - printf("frame_parms->samples_per_tti=%d\n",frame_parms->samples_per_tti); - printf("frame_parms->nb_prefix_samples0=%d\n",frame_parms->nb_prefix_samples0); - printf("frame_parms->nb_prefix_samples=%d\n",frame_parms->nb_prefix_samples); + LOG_I(PHY,"frame_parms->nb_prefix_samples=%d\n",frame_parms->nb_prefix_samples); + LOG_I(PHY,"frame_parms->slots_per_subframe=%d\n",frame_parms->slots_per_subframe); + LOG_I(PHY,"frame_parms->samples_per_subframe_wCP=%d\n",frame_parms->samples_per_subframe_wCP); + LOG_I(PHY,"frame_parms->samples_per_frame_wCP=%d\n",frame_parms->samples_per_frame_wCP); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_pss.c b/openair1/PHY/NR_TRANSPORT/nr_pss.c index 5909abd25a24894460663add5f03287abff8ca89..28d3d0ad3f645dd64af53536d059883c57006a79 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_pss.c +++ b/openair1/PHY/NR_TRANSPORT/nr_pss.c @@ -23,26 +23,24 @@ #define NR_PSS_DEBUG -short nr_mod_table[MOD_TABLE_SIZE_SHORT] = {0,0,768,768,-768,-768}; +//short nr_mod_table[MOD_TABLE_SIZE_SHORT] = {0,0,768,768,-768,-768}; int nr_generate_pss( int16_t *d_pss, int32_t **txdataF, int16_t amp, - int16_t ssb_first_subcarrier, - uint8_t slot_offset, + int16_t ssb_start_subcarrier, + uint8_t ssb_start_symbol, nfapi_config_request_t config, NR_DL_FRAME_PARMS *frame_parms) { - int i,n,m,k; + int i,m,k,l; int16_t a, aa; int16_t x[NR_PSS_LENGTH]; - int16_t pss_mod[2* NR_PSS_LENGTH]; const int x_initial[7] = {0, 1, 1 , 0, 1, 1, 1}; uint8_t Nid2 = config.sch_config.physical_cell_id.value % 3; - uint8_t Nsymb = (config.subframe_config.dl_cyclic_prefix_type.value == 0)? 14 : 12; - // Binary sequence generation + /// Sequence generation for (i=0; i < 7; i++) x[i] = x_initial[i]; @@ -50,28 +48,24 @@ int nr_generate_pss( int16_t *d_pss, x[i+7] = (x[i + 4] + x[i]) %2; } - for (n=0; n < NR_PSS_LENGTH; n++) { - m = (n + 43*Nid2)%(NR_PSS_LENGTH); - d_pss[n] = x[m]; // 1 - 2*x[m] is taken into account in the mod_table (binary input) + for (i=0; i < NR_PSS_LENGTH; i++) { + m = (i + 43*Nid2)%(NR_PSS_LENGTH); + d_pss[i] = (1 - 2*x[m]) * 32767; } - // BPSK modulation and resource mapping + /// Resource mapping a = (config.rf_config.tx_antenna_ports.value == 1) ? amp : (amp*ONE_OVER_SQRT2_Q15)>>15; - for (i = 0; i < NR_PSS_LENGTH; i++) - { - pss_mod[2*i] = nr_mod_table[ 2 * (MOD_TABLE_BPSK_OFFSET + d_pss[i]) ]; - pss_mod[2*i + 1] = nr_mod_table[ 2 * (MOD_TABLE_BPSK_OFFSET + d_pss[i]) + 1]; - } for (aa = 0; aa < config.rf_config.tx_antenna_ports.value; aa++) { - // PSS occupies a predefined position (symbol 0, subcarriers 56-182) within the SSB block starting from - k = frame_parms->first_carrier_offset + ssb_first_subcarrier + 56; // to be retrieved from ssb scheduling function + // PSS occupies a predefined position (subcarriers 56-182, symbol 0) within the SSB block starting from + k = frame_parms->first_carrier_offset + ssb_start_subcarrier + 56; //and + l = ssb_start_symbol; for (m = 0; m < NR_PSS_LENGTH; m++) { - ((int16_t*)txdataF[aa])[2*(slot_offset*Nsymb*frame_parms->ofdm_symbol_size + k)] = (a * pss_mod[2*m]) >> 15; - ((int16_t*)txdataF[aa])[2*(slot_offset*Nsymb*frame_parms->ofdm_symbol_size + k) + 1] = (a * pss_mod[2*m + 1]) >> 15; + ((int16_t*)txdataF[aa])[2*(l*frame_parms->ofdm_symbol_size + k)] = (a * d_pss[m]) >> 15; + //((int16_t*)txdataF[aa])[2*(l*frame_parms->ofdm_symbol_size + k) + 1] = (a * pss_mod[2*m + 1]) >> 15; k+=1; if (k >= frame_parms->ofdm_symbol_size) { diff --git a/openair1/PHY/NR_TRANSPORT/nr_sss.c b/openair1/PHY/NR_TRANSPORT/nr_sss.c index 8aa87aa66b821d63a11b25542551f2c30ff6b0e3..3c2a90dfe3851a06a2aa86a9276f9412f498b3a2 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_sss.c +++ b/openair1/PHY/NR_TRANSPORT/nr_sss.c @@ -28,23 +28,20 @@ extern short nr_mod_table[MOD_TABLE_SIZE_SHORT]; int nr_generate_sss( int16_t *d_sss, int32_t **txdataF, int16_t amp, - int16_t ssb_first_subcarrier, - uint8_t slot_offset, + int16_t ssb_start_subcarrier, + uint8_t ssb_start_symbol, nfapi_config_request_t config, NR_DL_FRAME_PARMS *frame_parms) { - int i,m,k; + int i,m,k,l; int m0, m1; int Nid, Nid1, Nid2; int16_t a, aa; int16_t x0[NR_SSS_LENGTH], x1[NR_SSS_LENGTH]; - int16_t sss_mod[2* NR_SSS_LENGTH]; const int x0_initial[7] = { 1, 0, 0, 0, 0, 0, 0 }; const int x1_initial[7] = { 1, 0, 0, 0, 0, 0, 0 }; - uint8_t Nsymb = (config.subframe_config.dl_cyclic_prefix_type.value == 0)? 14 : 12; - - // Binary sequence generation + /// Sequence generation Nid = config.sch_config.physical_cell_id.value; Nid2 = Nid % 3; Nid1 = (Nid - Nid2)/3; @@ -63,28 +60,22 @@ int nr_generate_sss( int16_t *d_sss, m1 = Nid1 % 112; for (i = 0; i < NR_SSS_LENGTH ; i++) { - d_sss[i] = (1 - 2*x0[(i + m0) % NR_SSS_LENGTH] ) * (1 - 2*x1[(i + m1) % NR_SSS_LENGTH] ); - if (d_sss[i] == -1) // This step -1 -> 0 is necessary to use nr_mod_table for the next step - d_sss[i] = 0; + d_sss[i] = (1 - 2*x0[(i + m0) % NR_SSS_LENGTH] ) * (1 - 2*x1[(i + m1) % NR_SSS_LENGTH] ) * 32767; } - // BPSK modulation and resource mapping + /// Resource mapping a = (config.rf_config.tx_antenna_ports.value == 1) ? amp : (amp*ONE_OVER_SQRT2_Q15)>>15; - for (i = 0; i < NR_SSS_LENGTH; i++) - { - sss_mod[2*i] = nr_mod_table[ 2 * (MOD_TABLE_BPSK_OFFSET + d_sss[i]) ]; - sss_mod[2*i + 1] = nr_mod_table[ 2 * (MOD_TABLE_BPSK_OFFSET + d_sss[i]) + 1]; - } for (aa = 0; aa < config.rf_config.tx_antenna_ports.value; aa++) { - // SSS occupies a predefined position (symbol 2, subcarriers 56-182) within the SSB block starting from - k = frame_parms->first_carrier_offset + ssb_first_subcarrier + 56; // to be retrieved from ssb scheduling function + // SSS occupies a predefined position (subcarriers 56-182, symbol 2) within the SSB block starting from + k = frame_parms->first_carrier_offset + ssb_start_subcarrier + 56; //and + l = ssb_start_symbol + 2; for (m = 0; m < NR_SSS_LENGTH; m++) { - ((int16_t*)txdataF[aa])[2*(slot_offset*Nsymb*frame_parms->ofdm_symbol_size + 2*frame_parms->ofdm_symbol_size + k)] = (a * sss_mod[2*m]) >> 15; - ((int16_t*)txdataF[aa])[2*(slot_offset*Nsymb*frame_parms->ofdm_symbol_size + 2*frame_parms->ofdm_symbol_size + k) + 1] = (a * sss_mod[2*m + 1]) >> 15; + ((int16_t*)txdataF[aa])[2*(l*frame_parms->ofdm_symbol_size + k)] = (a * d_sss[2*m]) >> 15; + //((int16_t*)txdataF[aa])[2*(l*frame_parms->ofdm_symbol_size + k) + 1] = (a * sss_mod[2*m + 1]) >> 15; k+=1; if (k >= frame_parms->ofdm_symbol_size) { diff --git a/openair1/PHY/defs_NR.h b/openair1/PHY/defs_NR.h index 2fde50548312c59c9b7ab5472b5eee9c24e63f7f..e10c881ece9ed61770605ad93f4fd3676e66b1f2 100644 --- a/openair1/PHY/defs_NR.h +++ b/openair1/PHY/defs_NR.h @@ -41,12 +41,14 @@ #include <math.h> #include "types.h" -#include "../nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface_nr_extension.h" +#include "defs.h" #include "assertions.h" #include "impl_defs_nr.h" #define MAX_NUM_SUBCARRIER_SPACING 5 +#define NR_SYMBOLS_PER_SLOT 14 + #define NR_PSS_LENGTH 127 #define NR_SSS_LENGTH 127 @@ -76,12 +78,412 @@ typedef struct { uint16_t nb_prefix_samples0; /// Carrier offset in FFT buffer for first RE in PRB0 uint16_t first_carrier_offset; - /// Number of samples in a subframe - uint32_t samples_per_tti; /// Number of OFDM/SC-FDMA symbols in one slot uint16_t symbols_per_slot; /// Number of slots per subframe uint16_t slots_per_subframe; + /// Number of samples in a subframe + uint32_t samples_per_subframe; + /// Number of samples in a radio frame + uint32_t samples_per_frame; + /// Number of samples in a subframe without CP + uint32_t samples_per_subframe_wCP; + /// Number of samples in a radio frame without CP + uint32_t samples_per_frame_wCP; + } NR_DL_FRAME_PARMS; + +/// Context data structure for RX/TX portion of subframe processing +typedef struct { + /// Component Carrier index + uint8_t CC_id; + /// timestamp transmitted to HW + openair0_timestamp timestamp_tx; + /// subframe to act upon for transmission + int subframe_tx; + /// subframe to act upon for reception + int subframe_rx; + /// frame to act upon for transmission + int frame_tx; + /// frame to act upon for reception + int frame_rx; + /// \brief Instance count for RXn-TXnp4 processing thread. + /// \internal This variable is protected by \ref mutex_rxtx. + int instance_cnt_rxtx; + /// pthread structure for RXn-TXnp4 processing thread + pthread_t pthread_rxtx; + /// pthread attributes for RXn-TXnp4 processing thread + pthread_attr_t attr_rxtx; + /// condition variable for tx processing thread + pthread_cond_t cond_rxtx; + /// mutex for RXn-TXnp4 processing thread + pthread_mutex_t mutex_rxtx; + /// scheduling parameters for RXn-TXnp4 thread + struct sched_param sched_param_rxtx; +} gNB_rxtx_proc_t; + + +/// Context data structure for eNB subframe processing +typedef struct gNB_proc_t_s { + /// Component Carrier index + uint8_t CC_id; + /// thread index + int thread_index; + /// timestamp received from HW + openair0_timestamp timestamp_rx; + /// timestamp to send to "slave rru" + openair0_timestamp timestamp_tx; + /// subframe to act upon for reception + int subframe_rx; + /// subframe to act upon for PRACH + int subframe_prach; + /// frame to act upon for reception + int frame_rx; + /// frame to act upon for transmission + int frame_tx; + /// frame to act upon for PRACH + int frame_prach; + /// \internal This variable is protected by \ref mutex_td. + int instance_cnt_td; + /// \internal This variable is protected by \ref mutex_te. + int instance_cnt_te; + /// \internal This variable is protected by \ref mutex_prach. + int instance_cnt_prach; + + // instance count for over-the-air gNB synchronization + int instance_cnt_synch; + /// \internal This variable is protected by \ref mutex_asynch_rxtx. + int instance_cnt_asynch_rxtx; + /// pthread structure for eNB single processing thread + pthread_t pthread_single; + /// pthread structure for asychronous RX/TX processing thread + pthread_t pthread_asynch_rxtx; + /// flag to indicate first RX acquisition + int first_rx; + /// flag to indicate first TX transmission + int first_tx; + /// pthread attributes for parallel turbo-decoder thread + pthread_attr_t attr_td; + /// pthread attributes for parallel turbo-encoder thread + pthread_attr_t attr_te; + /// pthread attributes for single eNB processing thread + pthread_attr_t attr_single; + /// pthread attributes for prach processing thread + pthread_attr_t attr_prach; + /// pthread attributes for asynchronous RX thread + pthread_attr_t attr_asynch_rxtx; + /// scheduling parameters for parallel turbo-decoder thread + struct sched_param sched_param_td; + /// scheduling parameters for parallel turbo-encoder thread + struct sched_param sched_param_te; + /// scheduling parameters for single eNB thread + struct sched_param sched_param_single; + /// scheduling parameters for prach thread + struct sched_param sched_param_prach; + /// scheduling parameters for asynch_rxtx thread + struct sched_param sched_param_asynch_rxtx; + /// pthread structure for parallel turbo-decoder thread + pthread_t pthread_td; + /// pthread structure for parallel turbo-encoder thread + pthread_t pthread_te; + /// pthread structure for PRACH thread + pthread_t pthread_prach; + /// condition variable for parallel turbo-decoder thread + pthread_cond_t cond_td; + /// condition variable for parallel turbo-encoder thread + pthread_cond_t cond_te; + /// condition variable for PRACH processing thread; + pthread_cond_t cond_prach; + /// condition variable for asynch RX/TX thread + pthread_cond_t cond_asynch_rxtx; + /// mutex for parallel turbo-decoder thread + pthread_mutex_t mutex_td; + /// mutex for parallel turbo-encoder thread + pthread_mutex_t mutex_te; + /// mutex for PRACH thread + pthread_mutex_t mutex_prach; + /// mutex for asynch RX/TX thread + pthread_mutex_t mutex_asynch_rxtx; + /// mutex for RU access to eNB processing (PDSCH/PUSCH) + pthread_mutex_t mutex_RU; + /// mutex for RU access to eNB processing (PRACH) + pthread_mutex_t mutex_RU_PRACH; + /// mutex for RU access to eNB processing (PRACH BR) + pthread_mutex_t mutex_RU_PRACH_br; + /// mask for RUs serving eNB (PDSCH/PUSCH) + int RU_mask; + /// mask for RUs serving eNB (PRACH) + int RU_mask_prach; + /// parameters for turbo-decoding worker thread + td_params tdp; + /// parameters for turbo-encoding worker thread + te_params tep; + /// set of scheduling variables RXn-TXnp4 threads + gNB_rxtx_proc_t proc_rxtx[2]; +} gNB_proc_t; + +typedef struct { + // common measurements + //! estimated noise power (linear) + unsigned int n0_power[MAX_NUM_RU_PER_eNB]; + //! estimated noise power (dB) + unsigned short n0_power_dB[MAX_NUM_RU_PER_eNB]; + //! total estimated noise power (linear) + unsigned int n0_power_tot; + //! estimated avg noise power (dB) + unsigned short n0_power_tot_dB; + //! estimated avg noise power (dB) + short n0_power_tot_dBm; + //! estimated avg noise power per RB per RX ant (lin) + unsigned short n0_subband_power[MAX_NUM_RU_PER_eNB][100]; + //! estimated avg noise power per RB per RX ant (dB) + unsigned short n0_subband_power_dB[MAX_NUM_RU_PER_eNB][100]; + //! estimated avg noise power per RB (dB) + short n0_subband_power_tot_dB[100]; + //! estimated avg noise power per RB (dBm) + short n0_subband_power_tot_dBm[100]; + // gNB measurements (per user) + //! estimated received spatial signal power (linear) + unsigned int rx_spatial_power[NUMBER_OF_UE_MAX][2][2]; + //! estimated received spatial signal power (dB) + unsigned short rx_spatial_power_dB[NUMBER_OF_UE_MAX][2][2]; + //! estimated rssi (dBm) + short rx_rssi_dBm[NUMBER_OF_UE_MAX]; + //! estimated correlation (wideband linear) between spatial channels (computed in dlsch_demodulation) + int rx_correlation[NUMBER_OF_UE_MAX][2]; + //! estimated correlation (wideband dB) between spatial channels (computed in dlsch_demodulation) + int rx_correlation_dB[NUMBER_OF_UE_MAX][2]; + + /// Wideband CQI (= SINR) + int wideband_cqi[NUMBER_OF_UE_MAX][MAX_NUM_RU_PER_eNB]; + /// Wideband CQI in dB (= SINR dB) + int wideband_cqi_dB[NUMBER_OF_UE_MAX][MAX_NUM_RU_PER_eNB]; + /// Wideband CQI (sum of all RX antennas, in dB) + char wideband_cqi_tot[NUMBER_OF_UE_MAX]; + /// Subband CQI per RX antenna and RB (= SINR) + int subband_cqi[NUMBER_OF_UE_MAX][MAX_NUM_RU_PER_eNB][100]; + /// Total Subband CQI and RB (= SINR) + int subband_cqi_tot[NUMBER_OF_UE_MAX][100]; + /// Subband CQI in dB and RB (= SINR dB) + int subband_cqi_dB[NUMBER_OF_UE_MAX][MAX_NUM_RU_PER_eNB][100]; + /// Total Subband CQI and RB + int subband_cqi_tot_dB[NUMBER_OF_UE_MAX][100]; + /// PRACH background noise level + int prach_I0; +} PHY_MEASUREMENTS_gNB; + + +/// Top-level PHY Data Structure for gNB +typedef struct PHY_VARS_gNB_s { + /// Module ID indicator for this instance + module_id_t Mod_id; + uint8_t CC_id; + uint8_t configured; + gNB_proc_t proc; + int single_thread_flag; + int abstraction_flag; + int num_RU; + RU_t *RU_list[MAX_NUM_RU_PER_eNB]; + /// Ethernet parameters for northbound midhaul interface + eth_params_t eth_params_n; + /// Ethernet parameters for fronthaul interface + eth_params_t eth_params; + int rx_total_gain_dB; + int (*td)(struct PHY_VARS_gNB_s *eNB,int UE_id,int harq_pid,int llr8_flag); + int (*te)(struct PHY_VARS_gNB_s *,uint8_t *,uint8_t,LTE_eNB_DLSCH_t *,int,uint8_t,time_stats_t *,time_stats_t *,time_stats_t *); + int (*start_if)(struct RU_t_s *ru,struct PHY_VARS_gNB_s *eNB); + uint8_t local_flag; + nfapi_config_request_t gNB_config; + NR_DL_FRAME_PARMS frame_parms; + PHY_MEASUREMENTS_gNB measurements; + IF_Module_t *if_inst; + UL_IND_t UL_INFO; + pthread_mutex_t UL_INFO_mutex; + /// NFAPI RX ULSCH information + nfapi_rx_indication_pdu_t rx_pdu_list[NFAPI_RX_IND_MAX_PDU]; + /// NFAPI RX ULSCH CRC information + nfapi_crc_indication_pdu_t crc_pdu_list[NFAPI_CRC_IND_MAX_PDU]; + /// NFAPI HARQ information + nfapi_harq_indication_pdu_t harq_pdu_list[NFAPI_HARQ_IND_MAX_PDU]; + /// NFAPI SR information + nfapi_sr_indication_pdu_t sr_pdu_list[NFAPI_SR_IND_MAX_PDU]; + /// NFAPI CQI information + nfapi_cqi_indication_pdu_t cqi_pdu_list[NFAPI_CQI_IND_MAX_PDU]; + /// NFAPI CQI information (raw component) + nfapi_cqi_indication_raw_pdu_t cqi_raw_pdu_list[NFAPI_CQI_IND_MAX_PDU]; + /// NFAPI PRACH information + nfapi_preamble_pdu_t preamble_list[MAX_NUM_RX_PRACH_PREAMBLES]; + + Sched_Rsp_t Sched_INFO; + LTE_eNB_PDCCH pdcch_vars[2]; + LTE_eNB_PHICH phich_vars[2]; + + NR_gNB_COMMON common_vars; + LTE_eNB_UCI uci_vars[NUMBER_OF_UE_MAX]; + LTE_eNB_SRS srs_vars[NUMBER_OF_UE_MAX]; + LTE_eNB_PBCH pbch; + LTE_eNB_PUSCH *pusch_vars[NUMBER_OF_UE_MAX]; + LTE_eNB_PRACH prach_vars; + LTE_eNB_DLSCH_t *dlsch[NUMBER_OF_UE_MAX][2]; // Nusers times two spatial streams + LTE_eNB_ULSCH_t *ulsch[NUMBER_OF_UE_MAX+1]; // Nusers + number of RA + LTE_eNB_DLSCH_t *dlsch_SI,*dlsch_ra,*dlsch_p; + LTE_eNB_DLSCH_t *dlsch_MCH; + LTE_eNB_DLSCH_t *dlsch_PCH; + LTE_eNB_UE_stats UE_stats[NUMBER_OF_UE_MAX]; + LTE_eNB_UE_stats *UE_stats_ptr[NUMBER_OF_UE_MAX]; + + uint8_t pbch_configured; + uint8_t pbch_pdu[4]; //PBCH_PDU_SIZE + char gNB_generate_rar; + + /// Indicator set to 0 after first SR + uint8_t first_sr[NUMBER_OF_UE_MAX]; + + uint32_t max_peak_val; + + /// \brief sinr for all subcarriers of the current link (used only for abstraction). + /// first index: ? [0..N_RB_DL*12[ + double *sinr_dB; + + /// N0 (used for abstraction) + double N0; + + unsigned char first_run_timing_advance[NUMBER_OF_UE_MAX]; + unsigned char first_run_I0_measurements; + + + unsigned char is_secondary_gNB; // primary by default + unsigned char is_init_sync; /// Flag to tell if initial synchronization is performed. This affects how often the secondary eNB will listen to the PSS from the primary system. + unsigned char has_valid_precoder; /// Flag to tell if secondary eNB has channel estimates to create NULL-beams from, and this B/F vector is created. + unsigned char PgNB_id; /// id of Primary eNB + + /// hold the precoder for NULL beam to the primary user + int **dl_precoder_SgNB[3]; + char log2_maxp; /// holds the maximum channel/precoder coefficient + + /// if ==0 enables phy only test mode + int mac_enabled; + /// counter to average prach energh over first 100 prach opportunities + int prach_energy_counter; + + // PDSCH Varaibles + PDSCH_CONFIG_DEDICATED pdsch_config_dedicated[NUMBER_OF_UE_MAX]; + + // PUSCH Varaibles + PUSCH_CONFIG_DEDICATED pusch_config_dedicated[NUMBER_OF_UE_MAX]; + + // PUCCH variables + PUCCH_CONFIG_DEDICATED pucch_config_dedicated[NUMBER_OF_UE_MAX]; + + // UL-POWER-Control + UL_POWER_CONTROL_DEDICATED ul_power_control_dedicated[NUMBER_OF_UE_MAX]; + + // TPC + TPC_PDCCH_CONFIG tpc_pdcch_config_pucch[NUMBER_OF_UE_MAX]; + TPC_PDCCH_CONFIG tpc_pdcch_config_pusch[NUMBER_OF_UE_MAX]; + + // CQI reporting + CQI_REPORT_CONFIG cqi_report_config[NUMBER_OF_UE_MAX]; + + // SRS Variables + SOUNDINGRS_UL_CONFIG_DEDICATED soundingrs_ul_config_dedicated[NUMBER_OF_UE_MAX]; + uint8_t ncs_cell[20][7]; + + // Scheduling Request Config + SCHEDULING_REQUEST_CONFIG scheduling_request_config[NUMBER_OF_UE_MAX]; + + // Transmission mode per UE + uint8_t transmission_mode[NUMBER_OF_UE_MAX]; + + /// cba_last successful reception for each group, used for collision detection + uint8_t cba_last_reception[4]; + + // Pointers for active physicalConfigDedicated to be applied in current subframe + struct PhysicalConfigDedicated *physicalConfigDedicated[NUMBER_OF_UE_MAX]; + + + uint32_t rb_mask_ul[4]; + + /// Information regarding TM5 + MU_MIMO_mode mu_mimo_mode[NUMBER_OF_UE_MAX]; + + + /// target_ue_dl_mcs : only for debug purposes + uint32_t target_ue_dl_mcs; + /// target_ue_ul_mcs : only for debug purposes + uint32_t target_ue_ul_mcs; + /// target_ue_dl_rballoc : only for debug purposes + uint32_t ue_dl_rb_alloc; + /// target ul PRBs : only for debug + uint32_t ue_ul_nb_rb; + + ///check for Total Transmissions + uint32_t check_for_total_transmissions; + + ///check for MU-MIMO Transmissions + uint32_t check_for_MUMIMO_transmissions; + + ///check for SU-MIMO Transmissions + uint32_t check_for_SUMIMO_transmissions; + + ///check for FULL MU-MIMO Transmissions + uint32_t FULL_MUMIMO_transmissions; + + /// Counter for total bitrate, bits and throughput in downlink + uint32_t total_dlsch_bitrate; + uint32_t total_transmitted_bits; + uint32_t total_system_throughput; + + int hw_timing_advance; + + time_stats_t phy_proc; + time_stats_t phy_proc_tx; + time_stats_t phy_proc_rx; + time_stats_t rx_prach; + + time_stats_t ofdm_mod_stats; + time_stats_t dlsch_encoding_stats; + time_stats_t dlsch_modulation_stats; + time_stats_t dlsch_scrambling_stats; + time_stats_t dlsch_rate_matching_stats; + time_stats_t dlsch_turbo_encoding_stats; + time_stats_t dlsch_interleaving_stats; + + time_stats_t rx_dft_stats; + time_stats_t ulsch_channel_estimation_stats; + time_stats_t ulsch_freq_offset_estimation_stats; + time_stats_t ulsch_decoding_stats; + time_stats_t ulsch_demodulation_stats; + time_stats_t ulsch_rate_unmatching_stats; + time_stats_t ulsch_turbo_decoding_stats; + time_stats_t ulsch_deinterleaving_stats; + time_stats_t ulsch_demultiplexing_stats; + time_stats_t ulsch_llr_stats; + time_stats_t ulsch_tc_init_stats; + time_stats_t ulsch_tc_alpha_stats; + time_stats_t ulsch_tc_beta_stats; + time_stats_t ulsch_tc_gamma_stats; + time_stats_t ulsch_tc_ext_stats; + time_stats_t ulsch_tc_intl1_stats; + time_stats_t ulsch_tc_intl2_stats; + +#ifdef LOCALIZATION + /// time state for localization + time_stats_t localization_stats; +#endif + + int32_t pucch1_stats_cnt[NUMBER_OF_UE_MAX][10]; + int32_t pucch1_stats[NUMBER_OF_UE_MAX][10*1024]; + int32_t pucch1_stats_thres[NUMBER_OF_UE_MAX][10*1024]; + int32_t pucch1ab_stats_cnt[NUMBER_OF_UE_MAX][10]; + int32_t pucch1ab_stats[NUMBER_OF_UE_MAX][2*10*1024]; + int32_t pusch_stats_rb[NUMBER_OF_UE_MAX][10240]; + int32_t pusch_stats_round[NUMBER_OF_UE_MAX][10240]; + int32_t pusch_stats_mcs[NUMBER_OF_UE_MAX][10240]; + int32_t pusch_stats_bsr[NUMBER_OF_UE_MAX][10240]; + int32_t pusch_stats_BO[NUMBER_OF_UE_MAX][10240]; +} PHY_VARS_gNB; + + #endif diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h new file mode 100644 index 0000000000000000000000000000000000000000..e5be713484b3dca6bb894df66edecb9a5776e4c0 --- /dev/null +++ b/openair1/PHY/defs_common.h @@ -0,0 +1,115 @@ +/* + * 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 + */ + +/*! \file PHY/defs.h + \brief Top-level defines and structure definitions + \author R. Knopp, F. Kaltenberger + \date 2011 + \version 0.1 + \company Eurecom + \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr + \note + \warning +*/ +#ifndef __PHY_DEFS_COMMON__H__ +#define __PHY_DEFS_COMMON__H__ + +#define MAX_NUM_RU_PER_eNB 64 +#define MAX_NUM_RU_PER_gNB 64 + +#define NUMBER_OF_SUBBANDS_MAX 13 +#define NUMBER_OF_HARQ_PID_MAX 8 + +#define MAX_FRAME_NUMBER 0x400 + + +#define NUMBER_OF_RN_MAX 3 +typedef enum {no_relay=1,unicast_relay_type1,unicast_relay_type2, multicast_relay} relaying_type_t; + + + +#define MCS_COUNT 28 +#define MCS_TABLE_LENGTH_MAX 64 + + +#define NUM_DCI_MAX 32 + +#define NUMBER_OF_eNB_SECTORS_MAX 3 + +#define NB_BANDS_MAX 8 + +#define MAX_BANDS_PER_RRU 4 + + +#ifdef OCP_FRAMEWORK +#include <enums.h> +#else +typedef enum {normal_txrx=0,rx_calib_ue=1,rx_calib_ue_med=2,rx_calib_ue_byp=3,debug_prach=4,no_L2_connect=5,calib_prach_tx=6,rx_dump_frame=7,loop_through_memory=8} runmode_t; + +/*! \brief Extension Type */ +typedef enum { + CYCLIC_PREFIX, + CYCLIC_SUFFIX, + ZEROS, + NONE +} Extension_t; + +enum transmission_access_mode { + NO_ACCESS=0, + POSTPONED_ACCESS, + CANCELED_ACCESS, + UNKNOWN_ACCESS, + SCHEDULED_ACCESS, + CBA_ACCESS}; + +typedef enum { + eNodeB_3GPP=0, // classical eNodeB function + NGFI_RAU_IF5, // RAU with NGFI IF5 + NGFI_RAU_IF4p5, // RAU with NFGI IF4p5 + NGFI_RRU_IF5, // NGFI_RRU (NGFI remote radio-unit,IF5) + NGFI_RRU_IF4p5, // NGFI_RRU (NGFI remote radio-unit,IF4p5) + MBP_RRU_IF5 // Mobipass RRU +} node_function_t; + +typedef enum { + + synch_to_ext_device=0, // synch to RF or Ethernet device + synch_to_other, // synch to another source_(timer, other RU) + synch_to_mobipass_standalone // special case for mobipass in standalone mode +} node_timing_t; +#endif + +typedef struct { + struct PHY_VARS_eNB_s *eNB; + int UE_id; + int harq_pid; + int llr8_flag; + int ret; +} td_params; + +typedef struct { + struct PHY_VARS_eNB_s *eNB; + LTE_eNB_DLSCH_t *dlsch; + int G; + int harq_pid; +} te_params; + +#endif diff --git a/openair1/PHY/impl_defs_nr.h b/openair1/PHY/impl_defs_nr.h index 14fce1ae63cc0b6ec8f2a47916cff1a6ca290670..55e0f28a770417b2a62837e483514ad425404d11 100644 --- a/openair1/PHY/impl_defs_nr.h +++ b/openair1/PHY/impl_defs_nr.h @@ -19,16 +19,11 @@ * contact@openairinterface.org */ -#ifndef __PHY_IMPLEMENTATION_DEFS_LTE_H__ -#define __PHY_IMPLEMENTATION_DEFS_LTE_H__ - - -#include "types.h" -//#include "nfapi_interface.h" -//#include "defs.h" -#include "openair2/COMMON/platform_types.h" +#ifndef __PHY_IMPLEMENTATION_DEFS_NR_H__ +#define __PHY_IMPLEMENTATION_DEFS_NR_H__ +#include "impl_defs_lte.h" typedef struct { diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 8d48ecc432798377761bb9b92dcec291dc9f4c8e..5fdc8278c10737b001eda5472664a12793f81824 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -20,11 +20,11 @@ */ #include "PHY/defs_NR.h" -//#include "PHY/extern.h" +#include "PHY/extern.h" #include "SCHED/defs.h" #include "SCHED/extern.h" -//#include "nfapi_interface.h" -//#include "fapi_l1.h" +#include "nfapi_interface.h" +#include "fapi_l1.h" #include "UTIL/LOG/log.h" #include "UTIL/LOG/vcd_signal_dumper.h" diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c index 03313146df30ab2dc486fc10ab494f48e7650226..59775a2c0d5eec07fb5b2d3cf7fd1b911cd9774d 100644 --- a/targets/RT/USER/lte-softmodem.c +++ b/targets/RT/USER/lte-softmodem.c @@ -47,7 +47,7 @@ #include "PHY/types.h" -#include "PHY/defs.h" +//#include "PHY/defs.h" #include "common/ran_context.h" #include "common/config/config_userapi.h" #include "common/utils/load_module_shlib.h" diff --git a/targets/RT/USER/nr-gnb.c b/targets/RT/USER/nr-gnb.c new file mode 100644 index 0000000000000000000000000000000000000000..c1044aba8f8fa9b061645b63264e18b246f85ab5 --- /dev/null +++ b/targets/RT/USER/nr-gnb.c @@ -0,0 +1,967 @@ +/* + * 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 + */ + +/*! \file lte-enb.c + * \brief Top-level threads for eNodeB + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ + +#define _GNU_SOURCE +#include <pthread.h> + +#include "time_utils.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "rt_wrapper.h" + +#include "assertions.h" + + +#include "PHY/types.h" + +#include "PHY/defs_NR.h" +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "../../ARCH/COMMON/common_lib.h" + +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/LTE_TRANSPORT/if5_tools.h" + +#include "PHY/extern.h" +#include "SCHED/extern.h" +#include "LAYER2/MAC/extern.h" + +#include "../../SIMU/USER/init_lte.h" + +#include "LAYER2/MAC/defs.h" +#include "LAYER2/MAC/extern.h" +#include "LAYER2/MAC/proto.h" +#include "RRC/LITE/extern.h" +#include "PHY_INTERFACE/extern.h" +#include "PHY_INTERFACE/defs.h" +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif +#include "UTIL/LOG/log_extern.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" +//#include "PHY/TOOLS/time_meas.h" + +#ifndef OPENAIR2 +#include "UTIL/OTG/otg_extern.h" +#endif + +#if defined(ENABLE_ITTI) +# if defined(ENABLE_USE_MME) +# include "s1ap_eNB.h" +#ifdef PDCP_USE_NETLINK +# include "SIMULATION/ETH_TRANSPORT/proto.h" +#endif +# endif +#endif + +#include "T.h" + +//#define DEBUG_THREADS 1 + +//#define USRP_DEBUG 1 +struct timing_info_t { + //unsigned int frame, hw_slot, last_slot, next_slot; + RTIME time_min, time_max, time_avg, time_last, time_now; + //unsigned int mbox0, mbox1, mbox2, mbox_target; + unsigned int n_samples; +} timing_info; + +// Fix per CC openair rf/if device update +// extern openair0_device openair0; + + +#if defined(ENABLE_ITTI) +extern volatile int start_gNB; +extern volatile int start_UE; +#endif +extern volatile int oai_exit; + +extern openair0_config_t openair0_cfg[MAX_CARDS]; + +extern int transmission_mode; + +uint16_t sf_ahead=4; + +//pthread_t main_gNB_thread; + +time_stats_t softmodem_stats_mt; // main thread +time_stats_t softmodem_stats_hw; // hw acquisition +time_stats_t softmodem_stats_rxtx_sf; // total tx time +time_stats_t nfapi_meas; // total tx time +time_stats_t softmodem_stats_rx_sf; // total rx time + +/* mutex, cond and variable to serialize phy proc TX calls + * (this mechanism may be relaxed in the future for better + * performances) + */ +static struct { + pthread_mutex_t mutex_phy_proc_tx; + pthread_cond_t cond_phy_proc_tx; + volatile uint8_t phy_proc_CC_id; +} sync_phy_proc; + +extern double cpuf; + +void exit_fun(const char* s); + +void init_gNB(int,int); +void stop_gNB(int nb_inst); + + +void wakeup_prach_gNB(PHY_VARS_gNB *gNB,RU_t *ru,int frame,int subframe); + +extern uint8_t nfapi_mode; +extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); +extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset); + +//#define TICK_TO_US(ts) (ts.diff) +#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials) + + +static inline int rxtx(PHY_VARS_gNB *gNB,gNB_rxtx_proc_t *proc, char *thread_name) { + start_meas(&softmodem_stats_rxtx_sf); + + // ******************************************************************* + + if (nfapi_mode == 1) { + + // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick + uint16_t frame = proc->frame_rx; + uint16_t subframe = proc->subframe_rx; + + //add_subframe(&frame, &subframe, 4); + + //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); + //LOG_D(PHY, "oai_subframe_ind(frame:%u, subframe:%d) - NOT CALLED ********\n", frame, subframe); + start_meas(&nfapi_meas); + oai_subframe_ind(frame, subframe); + stop_meas(&nfapi_meas); + + if (gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus|| + gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs || + gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs || + gNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles || + gNB->UL_INFO.cqi_ind.number_of_cqis + ) { + LOG_D(PHY, "UL_info[rx_ind:%05d:%d harqs:%05d:%d crcs:%05d:%d preambles:%05d:%d cqis:%d] RX:%04d%d TX:%04d%d num_pdcch_symbols:%d\n", + NFAPI_SFNSF2DEC(gNB->UL_INFO.rx_ind.sfn_sf), gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus, + NFAPI_SFNSF2DEC(gNB->UL_INFO.harq_ind.sfn_sf), gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs, + NFAPI_SFNSF2DEC(gNB->UL_INFO.crc_ind.sfn_sf), gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, + NFAPI_SFNSF2DEC(gNB->UL_INFO.rach_ind.sfn_sf), gNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles, + gNB->UL_INFO.cqi_ind.number_of_cqis, + proc->frame_rx, proc->subframe_rx, + proc->frame_tx, proc->subframe_tx, gNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols); + } + } + + if (nfapi_mode == 1 && gNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0) { + LOG_E(PHY, "gNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0"); + return 0; + } + /// NR disabling +/* + // **************************************** + // Common RX procedures subframe n + + T(T_gNB_PHY_DL_TICK, T_INT(gNB->Mod_id), T_INT(proc->frame_tx), T_INT(proc->subframe_tx)); + + // if this is IF5 or 3GPP_gNB + if (gNB && gNB->RU_list && gNB->RU_list[0] && gNB->RU_list[0]->function < NGFI_RAU_IF4p5) { + wakeup_prach_gNB(gNB,NULL,proc->frame_rx,proc->subframe_rx); + } + + // UE-specific RX processing for subframe n + if (nfapi_mode == 0 || nfapi_mode == 1) { + phy_procedures_gNB_uespec_RX(gNB, proc, no_relay ); + } + + pthread_mutex_lock(&gNB->UL_INFO_mutex); + + gNB->UL_INFO.frame = proc->frame_rx; + gNB->UL_INFO.subframe = proc->subframe_rx; + gNB->UL_INFO.module_id = gNB->Mod_id; + gNB->UL_INFO.CC_id = gNB->CC_id; + + gNB->if_inst->UL_indication(&gNB->UL_INFO); + + pthread_mutex_unlock(&gNB->UL_INFO_mutex); +*/ +/// end + // ***************************************** + // TX processing for subframe n+sf_ahead + // run PHY TX procedures the one after the other for all CCs to avoid race conditions + // (may be relaxed in the future for performance reasons) + // ***************************************** + //if (wait_CCs(proc)<0) return(-1); + + if (oai_exit) return(-1); +/// To call after common signals for NR + //phy_procedures_gNB_TX(gNB, proc, no_relay, NULL, 1); + + stop_meas( &softmodem_stats_rxtx_sf ); + + LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, proc->frame_rx, proc->subframe_rx, proc->frame_tx, proc->subframe_tx); + +#if 0 + LOG_D(PHY, "rxtx:%lld nfapi:%lld phy:%lld tx:%lld rx:%lld prach:%lld ofdm:%lld ", + softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now, + TICK_TO_US(gNB->phy_proc), + TICK_TO_US(gNB->phy_proc_tx), + TICK_TO_US(gNB->phy_proc_rx), + TICK_TO_US(gNB->rx_prach), + TICK_TO_US(gNB->ofdm_mod_stats), + softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now); + LOG_D(PHY, + "dlsch[enc:%lld mod:%lld scr:%lld rm:%lld t:%lld i:%lld] rx_dft:%lld ", + TICK_TO_US(gNB->dlsch_encoding_stats), + TICK_TO_US(gNB->dlsch_modulation_stats), + TICK_TO_US(gNB->dlsch_scrambling_stats), + TICK_TO_US(gNB->dlsch_rate_matching_stats), + TICK_TO_US(gNB->dlsch_turbo_encoding_stats), + TICK_TO_US(gNB->dlsch_interleaving_stats), + TICK_TO_US(gNB->rx_dft_stats)); + + LOG_D(PHY," ulsch[ch:%lld freq:%lld dec:%lld demod:%lld ru:%lld ", + TICK_TO_US(gNB->ulsch_channel_estimation_stats), + TICK_TO_US(gNB->ulsch_freq_offset_estimation_stats), + TICK_TO_US(gNB->ulsch_decoding_stats), + TICK_TO_US(gNB->ulsch_demodulation_stats), + TICK_TO_US(gNB->ulsch_rate_unmatching_stats)); + + LOG_D(PHY, "td:%lld dei:%lld dem:%lld llr:%lld tci:%lld ", + TICK_TO_US(gNB->ulsch_turbo_decoding_stats), + TICK_TO_US(gNB->ulsch_deinterleaving_stats), + TICK_TO_US(gNB->ulsch_demultiplexing_stats), + TICK_TO_US(gNB->ulsch_llr_stats), + TICK_TO_US(gNB->ulsch_tc_init_stats)); + LOG_D(PHY, "tca:%lld tcb:%lld tcg:%lld tce:%lld l1:%lld l2:%lld]\n\n", + TICK_TO_US(gNB->ulsch_tc_alpha_stats), + TICK_TO_US(gNB->ulsch_tc_beta_stats), + TICK_TO_US(gNB->ulsch_tc_gamma_stats), + TICK_TO_US(gNB->ulsch_tc_ext_stats), + TICK_TO_US(gNB->ulsch_tc_intl1_stats), + TICK_TO_US(gNB->ulsch_tc_intl2_stats) + ); +#endif + + return(0); +} + + +/*! + * \brief The RX UE-specific and TX thread of gNB. + * \param param is a \ref gNB_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ + +static void* gNB_thread_rxtx( void* param ) { + + static int gNB_thread_rxtx_status; + + gNB_rxtx_proc_t *proc = (gNB_rxtx_proc_t*)param; + PHY_VARS_gNB *gNB = RC.gNB[0][proc->CC_id]; + + char thread_name[100]; + + + // set default return value + gNB_thread_rxtx_status = 0; + + + sprintf(thread_name,"RXn_TXnp4_%d",&gNB->proc.proc_rxtx[0] == proc ? 0 : 1); + thread_top_init(thread_name,1,850000L,1000000L,2000000L); + + while (!oai_exit) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); + + if (wait_on_condition(&proc->mutex_rxtx,&proc->cond_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) break; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 ); + + if (oai_exit) break; + + if (gNB->CC_id==0) + { + if (rxtx(gNB,proc,thread_name) < 0) break; + + } + + if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) break; + + } // while !oai_exit + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); + + LOG_D(PHY, " *** Exiting gNB thread RXn_TXnp4\n"); + + gNB_thread_rxtx_status = 0; + return &gNB_thread_rxtx_status; +} + + +#if 0 //defined(ENABLE_ITTI) && defined(ENABLE_USE_MME) +// Wait for gNB application initialization to be complete (gNB registration to MME) +static void wait_system_ready (char *message, volatile int *start_flag) { + + static char *indicator[] = {". ", ".. ", "... ", ".... ", ".....", + " ....", " ...", " ..", " .", " "}; + int i = 0; + + while ((!oai_exit) && (*start_flag == 0)) { + LOG_N(EMU, message, indicator[i]); + fflush(stdout); + i = (i + 1) % (sizeof(indicator) / sizeof(indicator[0])); + usleep(200000); + } + + LOG_D(EMU,"\n"); +} +#endif + + + + + +void gNB_top(PHY_VARS_gNB *gNB, int frame_rx, int subframe_rx, char *string) +{ + gNB_proc_t *proc = &gNB->proc; + gNB_rxtx_proc_t *proc_rxtx = &proc->proc_rxtx[0]; + + proc->frame_rx = frame_rx; + proc->subframe_rx = subframe_rx; + + if (!oai_exit) { + T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx)); + + proc_rxtx->subframe_rx = proc->subframe_rx; + proc_rxtx->frame_rx = proc->frame_rx; + proc_rxtx->subframe_tx = (proc->subframe_rx+sf_ahead)%10; + proc_rxtx->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (1+proc->frame_rx)&1023 : proc->frame_rx; + proc->frame_tx = proc_rxtx->frame_tx; + proc_rxtx->timestamp_tx = proc->timestamp_tx; + + if (rxtx(gNB,proc_rxtx,string) < 0) LOG_E(PHY,"gNB %d CC_id %d failed during execution\n",gNB->Mod_id,gNB->CC_id); + } +} + + +int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { + + gNB_proc_t *proc=&gNB->proc; + + gNB_rxtx_proc_t *proc_rxtx=&proc->proc_rxtx[proc->frame_rx&1]; + + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + + int i; + struct timespec wait; + + pthread_mutex_lock(&proc->mutex_RU); + for (i=0;i<gNB->num_RU;i++) { + if (ru == gNB->RU_list[i]) { + if ((proc->RU_mask&(1<<i)) > 0) + LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", + gNB->Mod_id,proc->frame_rx,proc->subframe_rx,ru->idx,gNB->num_RU,proc->RU_mask); + proc->RU_mask |= (1<<i); + } + } + if (proc->RU_mask != (1<<gNB->num_RU)-1) { // not all RUs have provided their information so return + LOG_E(PHY,"Not all RUs have provided their info\n"); + pthread_mutex_unlock(&proc->mutex_RU); + return(0); + } + else { // all RUs have provided their information so continue on and wakeup gNB processing + proc->RU_mask = 0; + pthread_mutex_unlock(&proc->mutex_RU); + } + + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + /* accept some delay in processing - up to 5ms */ + for (i = 0; i < 10 && proc_rxtx->instance_cnt_rxtx == 0; i++) { + LOG_W( PHY,"[gNB] Frame %d Subframe %d, gNB RXn-TXnp4 thread busy!! (cnt_rxtx %i)\n", proc_rxtx->frame_tx, proc_rxtx->subframe_tx, proc_rxtx->instance_cnt_rxtx); + usleep(500); + } + if (proc_rxtx->instance_cnt_rxtx == 0) { + exit_fun( "TX thread busy" ); + return(-1); + } + + // wake up TX for subframe n+sf_ahead + // lock the TX mutex and make sure the thread is ready + if (pthread_mutex_timedlock(&proc_rxtx->mutex_rxtx,&wait) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_mutex_lock for gNB RXTX thread %d (IC %d)\n", proc_rxtx->subframe_rx&1,proc_rxtx->instance_cnt_rxtx ); + exit_fun( "error locking mutex_rxtx" ); + return(-1); + } + + ++proc_rxtx->instance_cnt_rxtx; + + // We have just received and processed the common part of a subframe, say n. + // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired + // transmitted timestamp of the next TX slot (first). + // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, + // we want to generate subframe (n+sf_ahead), so TS_tx = TX_rx+sf_ahead*samples_per_tti, + // and proc->subframe_tx = proc->subframe_rx+sf_ahead + proc_rxtx->timestamp_tx = proc->timestamp_rx + (sf_ahead*fp->samples_per_subframe); + proc_rxtx->frame_rx = proc->frame_rx; + proc_rxtx->subframe_rx = proc->subframe_rx; + proc_rxtx->frame_tx = (proc_rxtx->subframe_rx > (9-sf_ahead)) ? (proc_rxtx->frame_rx+1)&1023 : proc_rxtx->frame_rx; + proc_rxtx->subframe_tx = (proc_rxtx->subframe_rx + sf_ahead)%10; + + // the thread can now be woken up + if (pthread_cond_signal(&proc_rxtx->cond_rxtx) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB RXn-TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + pthread_mutex_unlock( &proc_rxtx->mutex_rxtx ); + + return(0); +} +/* +void wakeup_prach_gNB(PHY_VARS_gNB *gNB,RU_t *ru,int frame,int subframe) { + + gNB_proc_t *proc = &gNB->proc; + LTE_DL_FRAME_PARMS *fp=&gNB->frame_parms; + int i; + + if (ru!=NULL) { + pthread_mutex_lock(&proc->mutex_RU_PRACH); + for (i=0;i<gNB->num_RU;i++) { + if (ru == gNB->RU_list[i]) { + LOG_D(PHY,"frame %d, subframe %d: RU %d for gNB %d signals PRACH (mask %x, num_RU %d)\n",frame,subframe,i,gNB->Mod_id,proc->RU_mask_prach,gNB->num_RU); + if ((proc->RU_mask_prach&(1<<i)) > 0) + LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information (PRACH) from RU %d (num_RU %d, mask %x) has not been served yet!\n", + gNB->Mod_id,frame,subframe,ru->idx,gNB->num_RU,proc->RU_mask_prach); + proc->RU_mask_prach |= (1<<i); + } + } + if (proc->RU_mask_prach != (1<<gNB->num_RU)-1) { // not all RUs have provided their information so return + pthread_mutex_unlock(&proc->mutex_RU_PRACH); + return; + } + else { // all RUs have provided their information so continue on and wakeup gNB processing + proc->RU_mask_prach = 0; + pthread_mutex_unlock(&proc->mutex_RU_PRACH); + } + } + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe); + if (proc->instance_cnt_prach == 0) { + LOG_W(PHY,"[gNB] Frame %d Subframe %d, dropping PRACH\n", frame,subframe); + return; + } + + // wake up thread for PRACH RX + if (pthread_mutex_lock(&proc->mutex_prach) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_mutex_lock for gNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach); + exit_fun( "error locking mutex_prach" ); + return; + } + + ++proc->instance_cnt_prach; + // set timing for prach thread + proc->frame_prach = frame; + proc->subframe_prach = subframe; + + // the thread can now be woken up + if (pthread_cond_signal(&proc->cond_prach) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB PRACH thread %d\n", proc->thread_index); + exit_fun( "ERROR pthread_cond_signal" ); + return; + } + + pthread_mutex_unlock( &proc->mutex_prach ); + } + +}*/ + +/*! + * \brief The prach receive thread of gNB. + * \param param is a \ref gNB_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ + /* +static void* gNB_thread_prach( void* param ) { + static int gNB_thread_prach_status; + + + PHY_VARS_gNB *gNB= (PHY_VARS_gNB *)param; + gNB_proc_t *proc = &gNB->proc; + + // set default return value + gNB_thread_prach_status = 0; + + thread_top_init("gNB_thread_prach",1,500000L,1000000L,20000000L); + + + while (!oai_exit) { + + if (oai_exit) break; + + + if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"gNB_prach_thread") < 0) break; + + LOG_D(PHY,"Running gNB prach procedures\n"); + prach_procedures(gNB +#ifdef Rel14 + ,0 +#endif + ); + + if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"gNB_prach_thread") < 0) break; + } + + LOG_I(PHY, "Exiting gNB thread PRACH\n"); + + gNB_thread_prach_status = 0; + return &gNB_thread_prach_status; +} +*/ + +extern void init_td_thread(PHY_VARS_gNB *, pthread_attr_t *); +extern void init_te_thread(PHY_VARS_gNB *, pthread_attr_t *); + +void init_gNB_proc(int inst) { + + int i=0; + int CC_id; + PHY_VARS_gNB *gNB; + gNB_proc_t *proc; + gNB_rxtx_proc_t *proc_rxtx; + pthread_attr_t *attr0=NULL,*attr1=NULL,*attr_prach=NULL; + + LOG_I(PHY,"%s(inst:%d) RC.nb_CC[inst]:%d \n",__FUNCTION__,inst,RC.nb_CC[inst]); + + for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) { + gNB = RC.gNB[inst][CC_id]; +#ifndef OCP_FRAMEWORK + LOG_I(PHY,"Initializing gNB processes instance:%d CC_id %d \n",inst,CC_id); +#endif + proc = &gNB->proc; + + proc_rxtx = proc->proc_rxtx; + proc_rxtx[0].instance_cnt_rxtx = -1; + proc_rxtx[1].instance_cnt_rxtx = -1; + proc->instance_cnt_prach = -1; + proc->instance_cnt_asynch_rxtx = -1; + proc->CC_id = CC_id; + + proc->first_rx=1; + proc->first_tx=1; + proc->RU_mask=0; + proc->RU_mask_prach=0; + + pthread_mutex_init( &gNB->UL_INFO_mutex, NULL); + pthread_mutex_init( &proc_rxtx[0].mutex_rxtx, NULL); + pthread_mutex_init( &proc_rxtx[1].mutex_rxtx, NULL); + pthread_cond_init( &proc_rxtx[0].cond_rxtx, NULL); + pthread_cond_init( &proc_rxtx[1].cond_rxtx, NULL); + + pthread_mutex_init( &proc->mutex_prach, NULL); + pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); + pthread_mutex_init( &proc->mutex_RU,NULL); + pthread_mutex_init( &proc->mutex_RU_PRACH,NULL); + + pthread_cond_init( &proc->cond_prach, NULL); + pthread_cond_init( &proc->cond_asynch_rxtx, NULL); + + pthread_attr_init( &proc->attr_prach); + pthread_attr_init( &proc->attr_asynch_rxtx); + // pthread_attr_init( &proc->attr_td); + // pthread_attr_init( &proc->attr_te); + pthread_attr_init( &proc_rxtx[0].attr_rxtx); + pthread_attr_init( &proc_rxtx[1].attr_rxtx); +#ifndef DEADLINE_SCHEDULER + attr0 = &proc_rxtx[0].attr_rxtx; + attr1 = &proc_rxtx[1].attr_rxtx; + attr_prach = &proc->attr_prach; + + // attr_td = &proc->attr_td; + // attr_te = &proc->attr_te; +#endif + + LOG_I(PHY,"gNB->single_thread_flag:%d\n", gNB->single_thread_flag); + + if (gNB->single_thread_flag==0) { + pthread_create( &proc_rxtx[0].pthread_rxtx, attr0, gNB_thread_rxtx, &proc_rxtx[0] ); + pthread_create( &proc_rxtx[1].pthread_rxtx, attr1, gNB_thread_rxtx, &proc_rxtx[1] ); + } + //pthread_create( &proc->pthread_prach, attr_prach, gNB_thread_prach, gNB ); + + char name[16]; + if (gNB->single_thread_flag==0) { + snprintf( name, sizeof(name), "RXTX0 %d", i ); + pthread_setname_np( proc_rxtx[0].pthread_rxtx, name ); + snprintf( name, sizeof(name), "RXTX1 %d", i ); + pthread_setname_np( proc_rxtx[1].pthread_rxtx, name ); + } + + AssertFatal(proc->instance_cnt_prach == -1,"instance_cnt_prach = %d\n",proc->instance_cnt_prach); + + + } + + /* setup PHY proc TX sync mechanism */ + pthread_mutex_init(&sync_phy_proc.mutex_phy_proc_tx, NULL); + pthread_cond_init(&sync_phy_proc.cond_phy_proc_tx, NULL); + sync_phy_proc.phy_proc_CC_id = 0; +} + + + +/*! + * \brief Terminate gNB TX and RX threads. + */ +void kill_gNB_proc(int inst) { + + int *status; + PHY_VARS_gNB *gNB; + gNB_proc_t *proc; + gNB_rxtx_proc_t *proc_rxtx; + for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + gNB=RC.gNB[inst][CC_id]; + + proc = &gNB->proc; + proc_rxtx = &proc->proc_rxtx[0]; + + LOG_I(PHY, "Killing TX CC_id %d inst %d\n", CC_id, inst ); + + if (gNB->single_thread_flag==0) { + pthread_mutex_lock(&proc_rxtx[0].mutex_rxtx); + proc_rxtx[0].instance_cnt_rxtx = 0; + pthread_mutex_unlock(&proc_rxtx[0].mutex_rxtx); + pthread_mutex_lock(&proc_rxtx[1].mutex_rxtx); + proc_rxtx[1].instance_cnt_rxtx = 0; + pthread_mutex_unlock(&proc_rxtx[1].mutex_rxtx); + } + proc->instance_cnt_prach = 0; + pthread_cond_signal( &proc->cond_prach ); + + pthread_cond_signal( &proc->cond_asynch_rxtx ); + pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx); + + LOG_D(PHY, "joining pthread_prach\n"); + pthread_join( proc->pthread_prach, (void**)&status ); + + LOG_I(PHY, "Destroying prach mutex/cond\n"); + pthread_mutex_destroy( &proc->mutex_prach ); + pthread_cond_destroy( &proc->cond_prach ); + + LOG_I(PHY, "Destroying UL_INFO mutex\n"); + pthread_mutex_destroy(&gNB->UL_INFO_mutex); + int i; + if (gNB->single_thread_flag==0) { + for (i=0;i<2;i++) { + LOG_I(PHY, "Joining rxtx[%d] mutex/cond\n",i); + pthread_join( proc_rxtx[i].pthread_rxtx, (void**)&status ); + LOG_I(PHY, "Destroying rxtx[%d] mutex/cond\n",i); + pthread_mutex_destroy( &proc_rxtx[i].mutex_rxtx ); + pthread_cond_destroy( &proc_rxtx[i].cond_rxtx ); + } + } + } +} + + + + +void reset_opp_meas(void) { + + int sfn; + reset_meas(&softmodem_stats_mt); + reset_meas(&softmodem_stats_hw); + + for (sfn=0; sfn < 10; sfn++) { + reset_meas(&softmodem_stats_rxtx_sf); + reset_meas(&softmodem_stats_rx_sf); + } +} + + +void print_opp_meas(void) { + + int sfn=0; + print_meas(&softmodem_stats_mt, "Main gNB Thread", NULL, NULL); + print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL); + + for (sfn=0; sfn < 10; sfn++) { + print_meas(&softmodem_stats_rxtx_sf,"[gNB][total_phy_proc_rxtx]",NULL, NULL); + print_meas(&softmodem_stats_rx_sf,"[gNB][total_phy_proc_rx]",NULL,NULL); + } +} +/* +void free_transport(PHY_VARS_gNB *gNB) +{ + int i; + int j; + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + LOG_I(PHY, "Freeing Transport Channel Buffers for DLSCH, UE %d\n",i); + for (j=0; j<2; j++) free_gNB_dlsch(gNB->dlsch[i][j]); + + LOG_I(PHY, "Freeing Transport Channel Buffer for ULSCH, UE %d\n",i); + free_gNB_ulsch(gNB->ulsch[1+i]); + } + free_gNB_ulsch(gNB->ulsch[0]); +}*/ + +/* +void init_transport(PHY_VARS_gNB *gNB) { + + int i; + int j; + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + + LOG_I(PHY, "Initialise transport\n"); + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + LOG_I(PHY,"Allocating Transport Channel Buffers for DLSCH, UE %d\n",i); + for (j=0; j<2; j++) { + gNB->dlsch[i][j] = new_gNB_dlsch(1,8,NSOFT,fp->N_RB_DL,0,fp); + if (!gNB->dlsch[i][j]) { + LOG_E(PHY,"Can't get gNB dlsch structures for UE %d \n", i); + exit(-1); + } else { + gNB->dlsch[i][j]->rnti=0; + LOG_D(PHY,"dlsch[%d][%d] => %p rnti:%d\n",i,j,gNB->dlsch[i][j], gNB->dlsch[i][j]->rnti); + } + } + + LOG_I(PHY,"Allocating Transport Channel Buffer for ULSCH, UE %d\n",i); + gNB->ulsch[1+i] = new_gNB_ulsch(MAX_TURBO_ITERATIONS,fp->N_RB_UL, 0); + + if (!gNB->ulsch[1+i]) { + LOG_E(PHY,"Can't get gNB ulsch structures\n"); + exit(-1); + } + + // this is the transmission mode for the signalling channels + // this will be overwritten with the real transmission mode by the RRC once the UE is connected + gNB->transmission_mode[i] = fp->nb_antenna_ports_gNB==1 ? 1 : 2; + } + // ULSCH for RA + gNB->ulsch[0] = new_gNB_ulsch(MAX_TURBO_ITERATIONS, fp->N_RB_UL, 0); + + if (!gNB->ulsch[0]) { + LOG_E(PHY,"Can't get gNB ulsch structures\n"); + exit(-1); + } + gNB->dlsch_SI = new_gNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp); + LOG_D(PHY,"gNB %d.%d : SI %p\n",gNB->Mod_id,gNB->CC_id,gNB->dlsch_SI); + gNB->dlsch_ra = new_gNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp); + LOG_D(PHY,"gNB %d.%d : RA %p\n",gNB->Mod_id,gNB->CC_id,gNB->dlsch_ra); + gNB->dlsch_MCH = new_gNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp); + LOG_D(PHY,"gNB %d.%d : MCH %p\n",gNB->Mod_id,gNB->CC_id,gNB->dlsch_MCH); + + + gNB->rx_total_gain_dB=130; + + for(i=0; i<NUMBER_OF_UE_MAX; i++) + gNB->mu_mimo_mode[i].dl_pow_off = 2; + + gNB->check_for_total_transmissions = 0; + + gNB->check_for_MUMIMO_transmissions = 0; + + gNB->FULL_MUMIMO_transmissions = 0; + + gNB->check_for_SUMIMO_transmissions = 0; + + fp->pucch_config_common.deltaPUCCH_Shift = 1; + +} */ + +void init_gNB_afterRU(void) { + + int inst,CC_id,ru_id,i,aa; + PHY_VARS_gNB *gNB; + + LOG_I(PHY,"%s() RC.nb_inst:%d\n", __FUNCTION__, RC.nb_inst); + + for (inst=0;inst<RC.nb_inst;inst++) { + LOG_I(PHY,"RC.nb_CC[inst]:%d\n", RC.nb_CC[inst]); + for (CC_id=0;CC_id<RC.nb_CC[inst];CC_id++) { + + LOG_I(PHY,"RC.nb_CC[inst:%d][CC_id:%d]:%p\n", inst, CC_id, RC.gNB[inst][CC_id]); + + gNB = RC.gNB[inst][CC_id]; + phy_init_nr_gNB(gNB,0,0); + // map antennas and PRACH signals to gNB RX + if (0) AssertFatal(gNB->num_RU>0,"Number of RU attached to gNB %d is zero\n",gNB->Mod_id); + LOG_I(PHY,"Mapping RX ports from %d RUs to gNB %d\n",gNB->num_RU,gNB->Mod_id); + gNB->gNB_config.rf_config.tx_antenna_ports.value = 0; + + //LOG_I(PHY,"Overwriting gNB->prach_vars.rxsigF[0]:%p\n", gNB->prach_vars.rxsigF[0]); + + gNB->prach_vars.rxsigF[0] = (int16_t**)malloc16(64*sizeof(int16_t*)); + + LOG_I(PHY,"gNB->num_RU:%d\n", gNB->num_RU); + + for (ru_id=0,aa=0;ru_id<gNB->num_RU;ru_id++) { + gNB->gNB_config.rf_config.tx_antenna_ports.value += gNB->RU_list[ru_id]->nb_rx; + + AssertFatal(gNB->RU_list[ru_id]->common.rxdataF!=NULL, + "RU %d : common.rxdataF is NULL\n", + gNB->RU_list[ru_id]->idx); + + AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF!=NULL, + "RU %d : prach_rxsigF is NULL\n", + gNB->RU_list[ru_id]->idx); + + for (i=0;i<gNB->RU_list[ru_id]->nb_rx;aa++,i++) { + LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n",gNB->RU_list[ru_id]->idx,i,aa); + gNB->prach_vars.rxsigF[0][aa] = gNB->RU_list[ru_id]->prach_rxsigF[i]; + gNB->common_vars.rxdataF[aa] = gNB->RU_list[ru_id]->common.rxdataF[i]; + } + } + + + + /* TODO: review this code, there is something wrong. + * In monolithic mode, we come here with nb_antennas_rx == 0 + * (not tested in other modes). + */ + if (gNB->gNB_config.rf_config.tx_antenna_ports.value < 1) + { + LOG_I(PHY, "%s() ************* DJP ***** gNB->gNB_config.rf_config.tx_antenna_ports:%d - GOING TO HARD CODE TO 1", __FUNCTION__, gNB->gNB_config.rf_config.tx_antenna_ports.value); + gNB->gNB_config.rf_config.tx_antenna_ports.value = 1; + } + else + { + //LOG_I(PHY," Delete code\n"); + } + + if (gNB->gNB_config.rf_config.tx_antenna_ports.value < 1) + { + LOG_I(PHY, "%s() ************* DJP ***** gNB->gNB_config.rf_config.tx_antenna_ports:%d - GOING TO HARD CODE TO 1", __FUNCTION__, gNB->gNB_config.rf_config.tx_antenna_ports.value); + gNB->gNB_config.rf_config.tx_antenna_ports.value = 1; + } + else + { + //LOG_I(PHY," Delete code\n"); + } + + AssertFatal(gNB->gNB_config.rf_config.tx_antenna_ports.value >0, + "inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,gNB->gNB_config.rf_config.tx_antenna_ports.value); + LOG_I(PHY,"inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,gNB->gNB_config.rf_config.tx_antenna_ports.value); +/// Transport init necessary for NR synchro + //init_transport(gNB); + //init_precoding_weights(RC.gNB[inst][CC_id]); + } + init_gNB_proc(inst); + } + + for (ru_id=0;ru_id<RC.nb_RU;ru_id++) { + + AssertFatal(RC.ru[ru_id]!=NULL,"ru_id %d is null\n",ru_id); + + RC.ru[ru_id]->wakeup_rxtx = wakeup_rxtx; +// RC.ru[ru_id]->wakeup_prach_eNB = wakeup_prach_gNB; + RC.ru[ru_id]->eNB_top = gNB_top; + } +} + +void init_gNB(int single_thread_flag,int wait_for_sync) { + + int CC_id; + int inst; + PHY_VARS_gNB *gNB; + + LOG_I(PHY,"[nr-softmodem.c] gNB structure about to allocated RC.nb_L1_inst:%d RC.nb_L1_CC[0]:%d\n",RC.nb_L1_inst,RC.nb_L1_CC[0]); + + if (RC.gNB == NULL) RC.gNB = (PHY_VARS_gNB***) malloc(RC.nb_L1_inst*sizeof(PHY_VARS_gNB **)); + LOG_I(PHY,"[lte-softmodem.c] gNB structure RC.gNB allocated\n"); + for (inst=0;inst<RC.nb_L1_inst;inst++) { + if (RC.gNB[inst] == NULL) RC.gNB[inst] = (PHY_VARS_gNB**) malloc(RC.nb_CC[inst]*sizeof(PHY_VARS_gNB *)); + for (CC_id=0;CC_id<RC.nb_L1_CC[inst];CC_id++) { + if (RC.gNB[inst][CC_id] == NULL) RC.gNB[inst][CC_id] = (PHY_VARS_gNB*) malloc(sizeof(PHY_VARS_gNB)); + gNB = RC.gNB[inst][CC_id]; + gNB->abstraction_flag = 0; + gNB->single_thread_flag = single_thread_flag; + + + LOG_I(PHY,"Initializing gNB %d CC_id %d single_thread_flag:%d\n",inst,CC_id,single_thread_flag); +#ifndef OCP_FRAMEWORK + LOG_I(PHY,"Initializing gNB %d CC_id %d\n",inst,CC_id); +#endif + +/* + gNB->td = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data; + gNB->te = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding;*/ + + + LOG_I(PHY,"Registering with MAC interface module\n"); + AssertFatal((gNB->if_inst = IF_Module_init(inst))!=NULL,"Cannot register interface"); + gNB->if_inst->schedule_response = schedule_response; + gNB->if_inst->PHY_config_req = phy_config_request; + memset((void*)&gNB->UL_INFO,0,sizeof(gNB->UL_INFO)); + memset((void*)&gNB->Sched_INFO,0,sizeof(gNB->Sched_INFO)); + LOG_I(PHY,"Setting indication lists\n"); + gNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = gNB->rx_pdu_list; + gNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = gNB->crc_pdu_list; + gNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = gNB->sr_pdu_list; + gNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = gNB->harq_pdu_list; + gNB->UL_INFO.cqi_ind.cqi_pdu_list = gNB->cqi_pdu_list; + gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list; + gNB->prach_energy_counter = 0; + } + + } + + LOG_I(PHY,"[nr-softmodem.c] gNB structure allocated\n"); +} + + +void stop_gNB(int nb_inst) { + + for (int inst=0;inst<nb_inst;inst++) { + LOG_I(PHY,"Killing gNB %d processing threads\n",inst); + kill_gNB_proc(inst); + } +} diff --git a/targets/RT/USER/nr-ru.c b/targets/RT/USER/nr-ru.c new file mode 100644 index 0000000000000000000000000000000000000000..2b80cf938302e7c1dd29a77e1f3e0410defa08c1 --- /dev/null +++ b/targets/RT/USER/nr-ru.c @@ -0,0 +1,2408 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2014 Eurecom + + OpenAirInterface is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + + OpenAirInterface is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OpenAirInterface.The full GNU General Public License is + included in this distribution in the file called "COPYING". If not, + see <http://www.gnu.org/licenses/>. + + Contact Information + OpenAirInterface Admin: openair_admin@eurecom.fr + OpenAirInterface Tech : openair_tech@eurecom.fr + OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file lte-enb.c + * \brief Top-level threads for eNodeB + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sched.h> +#include <linux/sched.h> +#include <signal.h> +#include <execinfo.h> +#include <getopt.h> +#include <sys/sysinfo.h> +#include "rt_wrapper.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "assertions.h" +#include "msc.h" + +#include "PHY/types.h" + +#include "PHY/defs_NR.h" +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + + +#include "../../ARCH/COMMON/common_lib.h" +#include "../../ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" + +#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/LTE_TRANSPORT/if5_tools.h" + +#include "PHY/extern.h" +#include "SCHED/extern.h" +#include "LAYER2/MAC/extern.h" + +#include "../../SIMU/USER/init_lte.h" + +#include "LAYER2/MAC/defs.h" +#include "LAYER2/MAC/extern.h" +#include "LAYER2/MAC/proto.h" +#include "RRC/LITE/extern.h" +#include "PHY_INTERFACE/extern.h" + +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif +#include "UTIL/LOG/log_extern.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" +//#include "PHY/TOOLS/time_meas.h" + +/* these variables have to be defined before including ENB_APP/enb_paramdef.h */ +static int DEFBANDS[] = {7}; +static int DEFENBS[] = {0}; + +#include "ENB_APP/enb_paramdef.h" +#include "common/config/config_userapi.h" + +#ifndef OPENAIR2 +#include "UTIL/OTG/otg_extern.h" +#endif + +#if defined(ENABLE_ITTI) +# if defined(ENABLE_USE_MME) +# include "s1ap_eNB.h" +#ifdef PDCP_USE_NETLINK +# include "SIMULATION/ETH_TRANSPORT/proto.h" +#endif +# endif +#endif + +#include "T.h" +#include "nfapi_interface.h" + +extern volatile int oai_exit; + + +extern void phy_init_RU(RU_t*); +extern void phy_free_RU(RU_t*); + +void init_RU(char*); +void stop_RU(int nb_ru); +void do_ru_sync(RU_t *ru); + +void configure_ru(int idx, + void *arg); + +void configure_rru(int idx, + void *arg); + +int attach_rru(RU_t *ru); + +int connect_rau(RU_t *ru); + +extern uint16_t sf_ahead; + +/*************************************************************/ +/* Functions to attach and configure RRU */ + +extern void wait_gNBs(void); + +int attach_rru(RU_t *ru) { + + ssize_t msg_len,len; + RRU_CONFIG_msg_t rru_config_msg; + int received_capabilities=0; + + wait_gNBs(); + // Wait for capabilities + while (received_capabilities==0) { + + memset((void*)&rru_config_msg,0,sizeof(rru_config_msg)); + rru_config_msg.type = RAU_tick; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; + LOG_I(PHY,"Sending RAU tick to RRU %d\n",ru->idx); + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d cannot access remote radio\n",ru->idx); + + msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); + + // wait for answer with timeout + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + msg_len))<0) { + LOG_I(PHY,"Waiting for RRU %d\n",ru->idx); + } + else if (rru_config_msg.type == RRU_capabilities) { + AssertFatal(rru_config_msg.len==msg_len,"Received capabilities with incorrect length (%d!=%d)\n",(int)rru_config_msg.len,(int)msg_len); + LOG_I(PHY,"Received capabilities from RRU %d (len %d/%d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",ru->idx, + (int)rru_config_msg.len,(int)msg_len, + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->num_bands, + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->max_pdschReferenceSignalPower[0], + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->max_rxgain[0], + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->nb_tx[0], + ((RRU_capabilities_t*)&rru_config_msg.msg[0])->nb_rx[0]); + received_capabilities=1; + } + else { + LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx); + } + } + configure_ru(ru->idx, + (RRU_capabilities_t *)&rru_config_msg.msg[0]); + + rru_config_msg.type = RRU_config; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + LOG_I(PHY,"Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",ru->idx, + ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, + ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); + + + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d failed send configuration to remote radio\n",ru->idx); + + return 0; +} + +int connect_rau(RU_t *ru) { + + RRU_CONFIG_msg_t rru_config_msg; + ssize_t msg_len; + int tick_received = 0; + int configuration_received = 0; + RRU_capabilities_t *cap; + int i; + int len; + + // wait for RAU_tick + while (tick_received == 0) { + + msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; + + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + msg_len))<0) { + LOG_I(PHY,"Waiting for RAU\n"); + } + else { + if (rru_config_msg.type == RAU_tick) { + LOG_I(PHY,"Tick received from RAU\n"); + tick_received = 1; + } + else LOG_E(PHY,"Received erroneous message (%d)from RAU, expected RAU_tick\n",rru_config_msg.type); + } + } + + // send capabilities + + rru_config_msg.type = RRU_capabilities; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); + cap = (RRU_capabilities_t*)&rru_config_msg.msg[0]; + LOG_I(PHY,"Sending Capabilities (len %d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n", + (int)rru_config_msg.len,ru->num_bands,ru->max_pdschReferenceSignalPower,ru->max_rxgain,ru->nb_tx,ru->nb_rx); + switch (ru->function) { + case NGFI_RRU_IF4p5: + cap->FH_fmt = OAI_IF4p5_only; + break; + case NGFI_RRU_IF5: + cap->FH_fmt = OAI_IF5_only; + break; + case MBP_RRU_IF5: + cap->FH_fmt = MBP_IF5; + break; + default: + AssertFatal(1==0,"RU_function is unknown %d\n",RC.ru[0]->function); + break; + } + cap->num_bands = ru->num_bands; + for (i=0;i<ru->num_bands;i++) { + LOG_I(PHY,"Band %d: nb_rx %d nb_tx %d pdschReferenceSignalPower %d rxgain %d\n", + ru->band[i],ru->nb_rx,ru->nb_tx,ru->max_pdschReferenceSignalPower,ru->max_rxgain); + cap->band_list[i] = ru->band[i]; + cap->nb_rx[i] = ru->nb_rx; + cap->nb_tx[i] = ru->nb_tx; + cap->max_pdschReferenceSignalPower[i] = ru->max_pdschReferenceSignalPower; + cap->max_rxgain[i] = ru->max_rxgain; + } + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d failed send capabilities to RAU\n",ru->idx); + + // wait for configuration + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + while (configuration_received == 0) { + + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + rru_config_msg.len))<0) { + LOG_I(PHY,"Waiting for configuration from RAU\n"); + } + else { + LOG_I(PHY,"Configuration received from RAU (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n", + ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, + ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); + + configure_rru(ru->idx, + (void*)&rru_config_msg.msg[0]); + configuration_received = 1; + } + } + return 0; +} +/*************************************************************/ +/* Southbound Fronthaul functions, RCC/RAU */ + +// southbound IF5 fronthaul for 16-bit OAI format +static inline void fh_if5_south_out(RU_t *ru) { + if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); + send_IF5(ru, ru->proc.timestamp_tx, ru->proc.subframe_tx, &ru->seqno, IF5_RRH_GW_DL); +} + +// southbound IF5 fronthaul for Mobipass packet format +static inline void fh_if5_mobipass_south_out(RU_t *ru) { + if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); + send_IF5(ru, ru->proc.timestamp_tx, ru->proc.subframe_tx, &ru->seqno, IF5_MOBIPASS); +} + +// southbound IF4p5 fronthaul +static inline void fh_if4p5_south_out(RU_t *ru) { + if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); + LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.subframe_tx); + if (subframe_select(&ru->frame_parms,ru->proc.subframe_tx)!=SF_UL) + send_IF4p5(ru,ru->proc.frame_tx, ru->proc.subframe_tx, IF4p5_PDLFFT); +} + +/*************************************************************/ +/* Input Fronthaul from south RCC/RAU */ + +// Synchronous if5 from south +void fh_if5_south_in(RU_t *ru,int *frame, int *subframe) { + + NR_DL_FRAME_PARMS *fp = &ru->frame_parms; + //nfapi_config_request_t *cfg + RU_proc_t *proc = &ru->proc; + + recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); + + proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; + proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; + + if (proc->first_rx == 0) { + if (proc->subframe_rx != *subframe){ + LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",proc->subframe_rx,*subframe); + exit_fun("Exiting"); + } + + if (proc->frame_rx != *frame) { + LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame); + exit_fun("Exiting"); + } + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *subframe = proc->subframe_rx; + } + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); + +} + +// Synchronous if4p5 from south +void fh_if4p5_south_in(RU_t *ru,int *frame,int *subframe) { + + NR_DL_FRAME_PARMS *fp = &ru->frame_parms; + RU_proc_t *proc = &ru->proc; + int f,sf; + + + uint16_t packet_type; + uint32_t symbol_number=0; + uint32_t symbol_mask_full; + + if ((fp->frame_type == TDD) && (subframe_select(fp,*subframe)==SF_S)) + symbol_mask_full = (1<<fp->ul_symbols_in_S_subframe)-1; + else + symbol_mask_full = (1<<fp->symbols_per_tti)-1; + + AssertFatal(proc->symbol_mask[*subframe]==0,"rx_fh_if4p5: proc->symbol_mask[%d] = %x\n",*subframe,proc->symbol_mask[*subframe]); + do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! + recv_IF4p5(ru, &f, &sf, &packet_type, &symbol_number); + + if (packet_type == IF4p5_PULFFT) proc->symbol_mask[sf] = proc->symbol_mask[sf] | (1<<symbol_number); + else if (packet_type == IF4p5_PULTICK) { + if ((proc->first_rx==0) && (f!=*frame)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received frame %d != expected %d\n",f,*frame); + if ((proc->first_rx==0) && (sf!=*subframe)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n",sf,*subframe,proc->first_rx); + break; + + } else if (packet_type == IF4p5_PRACH) { + // nothing in RU for RAU + } + LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*subframe,proc->symbol_mask[*subframe]); + } while(proc->symbol_mask[*subframe] != symbol_mask_full); + + //caculate timestamp_rx, timestamp_tx based on frame and subframe + proc->subframe_rx = sf; + proc->frame_rx = f; + proc->timestamp_rx = ((proc->frame_rx * 10) + proc->subframe_rx ) * fp->samples_per_tti ; + // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_tti); + proc->subframe_tx = (sf+sf_ahead)%10; + proc->frame_tx = (sf>(9-sf_ahead)) ? (f+1)&1023 : f; + + if (proc->first_rx == 0) { + if (proc->subframe_rx != *subframe){ + LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",proc->subframe_rx,*subframe); + exit_fun("Exiting"); + } + if (proc->frame_rx != *frame) { + LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame); + exit_fun("Exiting"); + } + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *subframe = proc->subframe_rx; + } + + if (ru == RC.ru[0]) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, f ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, sf ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_RU, proc->subframe_tx ); + } + + proc->symbol_mask[sf] = 0; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); + LOG_D(PHY,"RU %d: fh_if4p5_south_in sleeping ...\n",ru->idx); + usleep(100); +} + +// Dummy FH from south for getting synchronization from master RU +void fh_slave_south_in(RU_t *ru,int *frame,int *subframe) { + // This case is for synchronization to another thread + // it just waits for an external event. The actual rx_fh is handle by the asynchronous RX thread + RU_proc_t *proc=&ru->proc; + + if (wait_on_condition(&proc->mutex_FH,&proc->cond_FH,&proc->instance_cnt_FH,"fh_slave_south_in") < 0) + return; + + release_thread(&proc->mutex_FH,&proc->instance_cnt_FH,"rx_fh_slave_south_in"); + + +} + +// asynchronous inbound if5 fronthaul from south (Mobipass) +void fh_if5_south_asynch_in_mobipass(RU_t *ru,int *frame,int *subframe) { + + RU_proc_t *proc = &ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + + recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_MOBIPASS); + pthread_mutex_lock(&proc->mutex_asynch_rxtx); + int offset_mobipass = 40120; + pthread_mutex_lock(&proc->mutex_asynch_rxtx); + proc->subframe_rx = ((proc->timestamp_rx-offset_mobipass)/fp->samples_per_tti)%10; + proc->frame_rx = ((proc->timestamp_rx-offset_mobipass)/(fp->samples_per_tti*10))&1023; + + proc->subframe_rx = (proc->timestamp_rx/fp->samples_per_tti)%10; + proc->frame_rx = (proc->timestamp_rx/(10*fp->samples_per_tti))&1023; + + if (proc->first_rx == 1) { + proc->first_rx =2; + *subframe = proc->subframe_rx; + *frame = proc->frame_rx; + LOG_E(PHY,"[Mobipass]timestamp_rx:%llu, frame_rx %d, subframe: %d\n",(unsigned long long int)proc->timestamp_rx,proc->frame_rx,proc->subframe_rx); + } + else { + if (proc->subframe_rx != *subframe) { + proc->first_rx++; + LOG_E(PHY,"[Mobipass]timestamp:%llu, subframe_rx %d is not what we expect %d, first_rx:%d\n",(unsigned long long int)proc->timestamp_rx, proc->subframe_rx,*subframe, proc->first_rx); + //exit_fun("Exiting"); + } + if (proc->frame_rx != *frame) { + proc->first_rx++; + LOG_E(PHY,"[Mobipass]timestamp:%llu, frame_rx %d is not what we expect %d, first_rx:%d\n",(unsigned long long int)proc->timestamp_rx,proc->frame_rx,*frame, proc->first_rx); + // exit_fun("Exiting"); + } + // temporary solution + *subframe = proc->subframe_rx; + *frame = proc->frame_rx; + } + + pthread_mutex_unlock(&proc->mutex_asynch_rxtx); + + +} // eNodeB_3GPP_BBU + +// asynchronous inbound if4p5 fronthaul from south +void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *subframe) { + + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + RU_proc_t *proc = &ru->proc; + + uint16_t packet_type; + uint32_t symbol_number,symbol_mask,prach_rx; + uint32_t got_prach_info=0; + + symbol_number = 0; + symbol_mask = (1<<fp->symbols_per_tti)-1; + prach_rx = 0; + + do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! + recv_IF4p5(ru, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number); + // grab first prach information for this new subframe + if (got_prach_info==0) { + prach_rx = is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx); + got_prach_info = 1; + } + if (proc->first_rx != 0) { + *frame = proc->frame_rx; + *subframe = proc->subframe_rx; + proc->first_rx = 0; + } + else { + if (proc->frame_rx != *frame) { + LOG_E(PHY,"frame_rx %d is not what we expect %d\n",proc->frame_rx,*frame); + exit_fun("Exiting"); + } + if (proc->subframe_rx != *subframe) { + LOG_E(PHY,"subframe_rx %d is not what we expect %d\n",proc->subframe_rx,*subframe); + exit_fun("Exiting"); + } + } + if (packet_type == IF4p5_PULFFT) symbol_mask &= (~(1<<symbol_number)); + else if (packet_type == IF4p5_PRACH) prach_rx &= (~0x1); +#ifdef Rel14 + else if (packet_type == IF4p5_PRACH_BR_CE0) prach_rx &= (~0x2); + else if (packet_type == IF4p5_PRACH_BR_CE1) prach_rx &= (~0x4); + else if (packet_type == IF4p5_PRACH_BR_CE2) prach_rx &= (~0x8); + else if (packet_type == IF4p5_PRACH_BR_CE3) prach_rx &= (~0x10); +#endif + } while( (symbol_mask > 0) || (prach_rx >0)); // haven't received all PUSCH symbols and PRACH information +} + + + + + +/*************************************************************/ +/* Input Fronthaul from North RRU */ + +// RRU IF4p5 TX fronthaul receiver. Assumes an if_device on input and if or rf device on output +// receives one subframe's worth of IF4p5 OFDM symbols and OFDM modulates +void fh_if4p5_north_in(RU_t *ru,int *frame,int *subframe) { + + uint32_t symbol_number=0; + uint32_t symbol_mask, symbol_mask_full; + uint16_t packet_type; + + + /// **** incoming IF4p5 from remote RCC/RAU **** /// + symbol_number = 0; + symbol_mask = 0; + symbol_mask_full = (1<<ru->frame_parms.symbols_per_tti)-1; + + do { + recv_IF4p5(ru, frame, subframe, &packet_type, &symbol_number); + symbol_mask = symbol_mask | (1<<symbol_number); + } while (symbol_mask != symbol_mask_full); + + // dump VCD output for first RU in list + if (ru == RC.ru[0]) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, *frame ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_RU, *subframe ); + } +} + +void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { + + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + RU_proc_t *proc = &ru->proc; + int subframe_tx,frame_tx; + openair0_timestamp timestamp_tx; + + recv_IF5(ru, ×tamp_tx, *subframe, IF5_RRH_GW_DL); + // printf("Received subframe %d (TS %llu) from RCC\n",subframe_tx,timestamp_tx); + + subframe_tx = (timestamp_tx/fp->samples_per_tti)%10; + frame_tx = (timestamp_tx/(fp->samples_per_tti*10))&1023; + + if (proc->first_tx != 0) { + *subframe = subframe_tx; + *frame = frame_tx; + proc->first_tx = 0; + } + else { + AssertFatal(subframe_tx == *subframe, + "subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe); + AssertFatal(frame_tx == *frame, + "frame_tx %d is not what we expect %d\n",frame_tx,*frame); + } +} + +void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) { + + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + RU_proc_t *proc = &ru->proc; + + uint16_t packet_type; + uint32_t symbol_number,symbol_mask,symbol_mask_full; + int subframe_tx,frame_tx; + + LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru); + symbol_number = 0; + symbol_mask = 0; + symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<<fp->dl_symbols_in_S_subframe) : (1<<fp->symbols_per_tti))-1; + do { + recv_IF4p5(ru, &frame_tx, &subframe_tx, &packet_type, &symbol_number); + if ((subframe_select(fp,subframe_tx) == SF_DL) && (symbol_number == 0)) start_meas(&ru->rx_fhaul); + LOG_D(PHY,"subframe %d (%d): frame %d, subframe %d, symbol %d\n", + *subframe,subframe_select(fp,*subframe),frame_tx,subframe_tx,symbol_number); + if (proc->first_tx != 0) { + *frame = frame_tx; + *subframe = subframe_tx; + proc->first_tx = 0; + symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<<fp->dl_symbols_in_S_subframe) : (1<<fp->symbols_per_tti))-1; + } + else { + AssertFatal(frame_tx == *frame, + "frame_tx %d is not what we expect %d\n",frame_tx,*frame); + AssertFatal(subframe_tx == *subframe, + "subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe); + } + if (packet_type == IF4p5_PDLFFT) { + symbol_mask = symbol_mask | (1<<symbol_number); + } + else AssertFatal(1==0,"Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n",packet_type); + } while (symbol_mask != symbol_mask_full); + + if (subframe_select(fp,subframe_tx) == SF_DL) stop_meas(&ru->rx_fhaul); + + proc->subframe_tx = subframe_tx; + proc->frame_tx = frame_tx; + + if ((frame_tx == 0)&&(subframe_tx == 0)) proc->frame_tx_unwrap += 1024; + + proc->timestamp_tx = ((((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * 10) + (uint64_t)subframe_tx) * (uint64_t)fp->samples_per_tti; + + LOG_D(PHY,"RU %d/%d TST %llu, frame %d, subframe %d\n",ru->idx,0,(long long unsigned int)proc->timestamp_tx,frame_tx,subframe_tx); + // dump VCD output for first RU in list + if (ru == RC.ru[0]) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame_tx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_RU, subframe_tx ); + } + + if (ru->feptx_ofdm) ru->feptx_ofdm(ru); + if (ru->fh_south_out) ru->fh_south_out(ru); +} + +void fh_if5_north_out(RU_t *ru) { + + RU_proc_t *proc=&ru->proc; + uint8_t seqno=0; + + /// **** send_IF5 of rxdata to BBU **** /// + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 ); + send_IF5(ru, proc->timestamp_rx, proc->subframe_rx, &seqno, IF5_RRH_GW_UL); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 ); + +} + +// RRU IF4p5 northbound interface (RX) +void fh_if4p5_north_out(RU_t *ru) { + + RU_proc_t *proc=&ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + const int subframe = proc->subframe_rx; + if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, proc->subframe_rx ); + + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) { + /// **** in TDD during DL send_IF4 of ULTICK to RCC **** /// + send_IF4p5(ru, proc->frame_rx, proc->subframe_rx, IF4p5_PULTICK); + return; + } + + start_meas(&ru->tx_fhaul); + send_IF4p5(ru, proc->frame_rx, proc->subframe_rx, IF4p5_PULFFT); + stop_meas(&ru->tx_fhaul); + +} + +void rx_rf(RU_t *ru,int *frame,int *subframe) { + + RU_proc_t *proc = &ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + void *rxp[ru->nb_rx]; + unsigned int rxs; + int i; + openair0_timestamp ts,old_ts; + + for (i=0; i<ru->nb_rx; i++) + rxp[i] = (void*)&ru->common.rxdata[i][*subframe*fp->samples_per_tti]; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); + + old_ts = proc->timestamp_rx; + + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &ts, + rxp, + fp->samples_per_tti, + ru->nb_rx); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); + + proc->timestamp_rx = ts-ru->ts_offset; + + //AssertFatal(rxs == fp->samples_per_tti, + //"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs); + if (rxs != fp->samples_per_tti) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs); + + if (proc->first_rx == 1) { + ru->ts_offset = proc->timestamp_rx; + proc->timestamp_rx = 0; + } + else { + if (proc->timestamp_rx - old_ts != fp->samples_per_tti) { + LOG_I(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - fp->samples_per_tti,ru->ts_offset); + ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti); + proc->timestamp_rx = ts-ru->ts_offset; + } + + } + proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023; + proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10; + // synchronize first reception to frame 0 subframe 0 + + proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti); + proc->subframe_tx = (proc->subframe_rx+sf_ahead)%10; + proc->frame_tx = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + + LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, subframe %d\n", + ru->idx, + 0, + (unsigned long long int)proc->timestamp_rx, + (int)ru->ts_offset,proc->frame_rx,proc->subframe_rx); + + // dump VCD output for first RU in list + if (ru == RC.ru[0]) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, proc->frame_rx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, proc->subframe_rx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_RU, proc->subframe_tx ); + } + + if (proc->first_rx == 0) { + if (proc->subframe_rx != *subframe){ + LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",(long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe); + exit_fun("Exiting"); + } + + if (proc->frame_rx != *frame) { + LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",(long long unsigned int)proc->timestamp_rx,proc->frame_rx,*frame); + exit_fun("Exiting"); + } + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *subframe = proc->subframe_rx; + } + + //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->subframe_rx,subframe); + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); + + if (rxs != fp->samples_per_tti) + { + //exit_fun( "problem receiving samples" ); + LOG_E(PHY, "problem receiving samples"); + } +} + + +void tx_rf(RU_t *ru) { + + RU_proc_t *proc = &ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + void *txp[ru->nb_tx]; + unsigned int txs; + int i; + + T(T_ENB_PHY_OUTPUT_SIGNAL, T_INT(0), T_INT(0), T_INT(proc->frame_tx), T_INT(proc->subframe_tx), + T_INT(0), T_BUFFER(&ru->common.txdata[0][proc->subframe_tx * fp->samples_per_tti], fp->samples_per_tti * 4)); + + lte_subframe_t SF_type = subframe_select(fp,proc->subframe_tx%10); + lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10); + lte_subframe_t nextSF_type = subframe_select(fp,(proc->subframe_tx+1)%10); + int sf_extension = 0; + + if ((SF_type == SF_DL) || + (SF_type == SF_S)) { + + int siglen=fp->samples_per_tti,flags=1; + + if (SF_type == SF_S) { + siglen = fp->dl_symbols_in_S_subframe*(fp->ofdm_symbol_size+fp->nb_prefix_samples0); + flags=3; // end of burst + } + if ((fp->frame_type == TDD) && + (SF_type == SF_DL)&& + (prevSF_type == SF_UL) && + (nextSF_type == SF_DL)) { + flags = 2; // start of burst + sf_extension = ru->N_TA_offset<<1; + } + + if ((fp->frame_type == TDD) && + (SF_type == SF_DL)&& + (prevSF_type == SF_UL) && + (nextSF_type == SF_UL)) { + flags = 4; // start of burst and end of burst (only one DL SF between two UL) + sf_extension = ru->N_TA_offset<<1; + } + + for (i=0; i<ru->nb_tx; i++) + txp[i] = (void*)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension]; + + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (proc->timestamp_tx-ru->openair0_cfg.tx_sample_advance)&0xffffffff ); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); + // prepare tx buffer pointers + + txs = ru->rfdevice.trx_write_func(&ru->rfdevice, + proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, + txp, + siglen+sf_extension, + ru->nb_tx, + flags); + + LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, + (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); + + + AssertFatal(txs == siglen+sf_extension,"TX : Timeout (sent %d/%d)\n",txs, siglen); + + } +} + + +/*! + * \brief The Asynchronous RX/TX FH thread of RAU/RCC/eNB/RRU. + * This handles the RX FH for an asynchronous RRU/UE + * \param param is a \ref eNB_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ +static void* ru_thread_asynch_rxtx( void* param ) { + + static int ru_thread_asynch_rxtx_status; + + RU_t *ru = (RU_t*)param; + RU_proc_t *proc = &ru->proc; + + + + int subframe=0, frame=0; + + thread_top_init("ru_thread_asynch_rxtx",1,870000L,1000000L,1000000L); + + // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe + + wait_sync("ru_thread_asynch_rxtx"); + + // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe + printf( "waiting for devices (ru_thread_asynch_rx)\n"); + + wait_on_condition(&proc->mutex_asynch_rxtx,&proc->cond_asynch_rxtx,&proc->instance_cnt_asynch_rxtx,"thread_asynch"); + + printf( "devices ok (ru_thread_asynch_rx)\n"); + + + while (!oai_exit) { + + if (oai_exit) break; + + if (subframe==9) { + subframe=0; + frame++; + frame&=1023; + } else { + subframe++; + } + LOG_D(PHY,"ru_thread_asynch_rxtx: Waiting on incoming fronthaul\n"); + // asynchronous receive from south (Mobipass) + if (ru->fh_south_asynch_in) ru->fh_south_asynch_in(ru,&frame,&subframe); + // asynchronous receive from north (RRU IF4/IF5) + else if (ru->fh_north_asynch_in) { + if (subframe_select(&ru->frame_parms,subframe)!=SF_UL) + ru->fh_north_asynch_in(ru,&frame,&subframe); + } + else AssertFatal(1==0,"Unknown function in ru_thread_asynch_rxtx\n"); + } + + ru_thread_asynch_rxtx_status=0; + return(&ru_thread_asynch_rxtx_status); +} + + + + +void wakeup_slaves(RU_proc_t *proc) { + + int i; + struct timespec wait; + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + for (i=0;i<proc->num_slaves;i++) { + RU_proc_t *slave_proc = proc->slave_proc[i]; + // wake up slave FH thread + // lock the FH mutex and make sure the thread is ready + if (pthread_mutex_timedlock(&slave_proc->mutex_FH,&wait) != 0) { + LOG_E( PHY, "ERROR pthread_mutex_lock for RU %d slave %d (IC %d)\n",proc->ru->idx,slave_proc->ru->idx,slave_proc->instance_cnt_FH); + exit_fun( "error locking mutex_rxtx" ); + break; + } + + int cnt_slave = ++slave_proc->instance_cnt_FH; + slave_proc->frame_rx = proc->frame_rx; + slave_proc->subframe_rx = proc->subframe_rx; + slave_proc->timestamp_rx = proc->timestamp_rx; + slave_proc->timestamp_tx = proc->timestamp_tx; + + pthread_mutex_unlock( &slave_proc->mutex_FH ); + + if (cnt_slave == 0) { + // the thread was presumably waiting where it should and can now be woken up + if (pthread_cond_signal(&slave_proc->cond_FH) != 0) { + LOG_E( PHY, "ERROR pthread_cond_signal for RU %d, slave RU %d\n",proc->ru->idx,slave_proc->ru->idx); + exit_fun( "ERROR pthread_cond_signal" ); + break; + } + } else { + LOG_W( PHY,"[RU] Frame %d, slave %d thread busy!! (cnt_FH %i)\n",slave_proc->frame_rx,slave_proc->ru->idx, cnt_slave); + exit_fun( "FH thread busy" ); + break; + } + } +} + +/*! + * \brief The prach receive thread of RU. + * \param param is a \ref RU_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ +static void* ru_thread_prach( void* param ) { + + static int ru_thread_prach_status; + + RU_t *ru = (RU_t*)param; + RU_proc_t *proc = (RU_proc_t*)&ru->proc; + + // set default return value + ru_thread_prach_status = 0; + + thread_top_init("ru_thread_prach",1,500000L,1000000L,20000000L); + + while (RC.ru_mask>0) { + usleep(1e6); + LOG_I(PHY,"%s() RACH waiting for RU to be configured\n", __FUNCTION__); + } + LOG_I(PHY,"%s() RU configured - RACH processing thread running\n", __FUNCTION__); + + while (!oai_exit) { + + if (oai_exit) break; + if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); + if (ru->eNB_list[0]){ + prach_procedures( + ru->eNB_list[0] +#ifdef Rel14 + ,0 +#endif + ); + } + else { + rx_prach(NULL, + ru, + NULL, + NULL, + NULL, + proc->frame_prach, + 0 +#ifdef Rel14 + ,0 +#endif + ); + } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 ); + if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break; + } + + LOG_I(PHY, "Exiting RU thread PRACH\n"); + + ru_thread_prach_status = 0; + return &ru_thread_prach_status; +} + +#ifdef Rel14 +static void* ru_thread_prach_br( void* param ) { + + static int ru_thread_prach_status; + + RU_t *ru = (RU_t*)param; + RU_proc_t *proc = (RU_proc_t*)&ru->proc; + + // set default return value + ru_thread_prach_status = 0; + + thread_top_init("ru_thread_prach_br",1,500000L,1000000L,20000000L); + + while (!oai_exit) { + + if (oai_exit) break; + if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"ru_prach_thread_br") < 0) break; + rx_prach(NULL, + ru, + NULL, + NULL, + NULL, + proc->frame_prach_br, + 0, + 1); + if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"ru_prach_thread_br") < 0) break; + } + + LOG_I(PHY, "Exiting RU thread PRACH BR\n"); + + ru_thread_prach_status = 0; + return &ru_thread_prach_status; +} +#endif + +int wakeup_synch(RU_t *ru){ + + struct timespec wait; + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + // wake up synch thread + // lock the synch mutex and make sure the thread is ready + if (pthread_mutex_timedlock(&ru->proc.mutex_synch,&wait) != 0) { + LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU synch thread (IC %d)\n", ru->proc.instance_cnt_synch ); + exit_fun( "error locking mutex_synch" ); + return(-1); + } + + ++ru->proc.instance_cnt_synch; + + // the thread can now be woken up + if (pthread_cond_signal(&ru->proc.cond_synch) != 0) { + LOG_E( PHY, "[RU] ERROR pthread_cond_signal for RU synch thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + pthread_mutex_unlock( &ru->proc.mutex_synch ); + + return(0); +} + +void do_ru_synch(RU_t *ru) { + + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + RU_proc_t *proc = &ru->proc; + int i; + void *rxp[2],*rxp2[2]; + int32_t dummy_rx[ru->nb_rx][fp->samples_per_tti] __attribute__((aligned(32))); + int rxs; + int ic; + + // initialize the synchronization buffer to the common_vars.rxdata + for (int i=0;i<ru->nb_rx;i++) + rxp[i] = &ru->common.rxdata[i][0]; + + double temp_freq1 = ru->rfdevice.openair0_cfg->rx_freq[0]; + double temp_freq2 = ru->rfdevice.openair0_cfg->tx_freq[0]; + for (i=0;i<4;i++) { + ru->rfdevice.openair0_cfg->rx_freq[i] = ru->rfdevice.openair0_cfg->tx_freq[i]; + ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq1; + } + ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0); + + while ((ru->in_synch ==0)&&(!oai_exit)) { + // read in frame + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &(proc->timestamp_rx), + rxp, + fp->samples_per_tti*10, + ru->nb_rx); + if (rxs != fp->samples_per_tti*10) LOG_E(PHY,"requested %d samples, got %d\n",fp->samples_per_tti*10,rxs); + + // wakeup synchronization processing thread + wakeup_synch(ru); + ic=0; + + while ((ic>=0)&&(!oai_exit)) { + // continuously read in frames, 1ms at a time, + // until we are done with the synchronization procedure + + for (i=0; i<ru->nb_rx; i++) + rxp2[i] = (void*)&dummy_rx[i][0]; + for (i=0;i<10;i++) + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &(proc->timestamp_rx), + rxp2, + fp->samples_per_tti, + ru->nb_rx); + pthread_mutex_lock(&ru->proc.mutex_synch); + ic = ru->proc.instance_cnt_synch; + pthread_mutex_unlock(&ru->proc.mutex_synch); + } // ic>=0 + } // in_synch==0 + // read in rx_offset samples + LOG_I(PHY,"Resynchronizing by %d samples\n",ru->rx_offset); + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &(proc->timestamp_rx), + rxp, + ru->rx_offset, + ru->nb_rx); + for (i=0;i<4;i++) { + ru->rfdevice.openair0_cfg->rx_freq[i] = temp_freq1; + ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq2; + } + + ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0); + +} + + + +void wakeup_eNBs(RU_t *ru) { + + int i; + PHY_VARS_eNB **eNB_list = ru->eNB_list; + + LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top); + + if (ru->num_eNB==1 && ru->eNB_top!=0) { + // call eNB function directly + + char string[20]; + sprintf(string,"Incoming RU %d",ru->idx); + LOG_D(PHY,"RU %d Call eNB_top\n",ru->idx); + ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string); + } + else { + + LOG_D(PHY,"ru->num_eNB:%d\n", ru->num_eNB); + + for (i=0;i<ru->num_eNB;i++) + { + LOG_D(PHY,"ru->wakeup_rxtx:%p\n", ru->wakeup_rxtx); + + if (ru->wakeup_rxtx!=0 && ru->wakeup_rxtx(eNB_list[i],ru) < 0) + { + LOG_E(PHY,"could not wakeup eNB rxtx process for subframe %d\n", ru->proc.subframe_rx); + } + } + } +} + +static inline int wakeup_prach_ru(RU_t *ru) { + + struct timespec wait; + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + if (pthread_mutex_timedlock(&ru->proc.mutex_prach,&wait) !=0) { + LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread (IC %d)\n", ru->proc.instance_cnt_prach); + exit_fun( "error locking mutex_rxtx" ); + return(-1); + } + if (ru->proc.instance_cnt_prach==-1) { + ++ru->proc.instance_cnt_prach; + ru->proc.frame_prach = ru->proc.frame_rx; + ru->proc.subframe_prach = ru->proc.subframe_rx; + + // DJP - think prach_procedures() is looking at eNB frame_prach + if (ru->eNB_list[0]) { + ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx; + ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx; + } + LOG_I(PHY,"RU %d: waking up PRACH thread\n",ru->idx); + // the thread can now be woken up + AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n"); + } + else LOG_W(PHY,"RU prach thread busy, skipping\n"); + pthread_mutex_unlock( &ru->proc.mutex_prach ); + + return(0); +} + +#ifdef Rel14 +static inline int wakeup_prach_ru_br(RU_t *ru) { + + struct timespec wait; + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + if (pthread_mutex_timedlock(&ru->proc.mutex_prach_br,&wait) !=0) { + LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread BR (IC %d)\n", ru->proc.instance_cnt_prach_br); + exit_fun( "error locking mutex_rxtx" ); + return(-1); + } + if (ru->proc.instance_cnt_prach_br==-1) { + ++ru->proc.instance_cnt_prach_br; + ru->proc.frame_prach_br = ru->proc.frame_rx; + ru->proc.subframe_prach_br = ru->proc.subframe_rx; + + LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx); + // the thread can now be woken up + AssertFatal(pthread_cond_signal(&ru->proc.cond_prach_br) == 0, "ERROR pthread_cond_signal for RU prach thread BR\n"); + } + else LOG_W(PHY,"RU prach thread busy, skipping\n"); + pthread_mutex_unlock( &ru->proc.mutex_prach_br ); + + return(0); +} +#endif + +// this is for RU with local RF unit +void fill_rf_config(RU_t *ru, char *rf_config_file) { + + int i; + + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + openair0_config_t *cfg = &ru->openair0_cfg; + + if(fp->N_RB_DL == 100) { + if (fp->threequarter_fs) { + cfg->sample_rate=23.04e6; + cfg->samples_per_frame = 230400; + cfg->tx_bw = 10e6; + cfg->rx_bw = 10e6; + } + else { + cfg->sample_rate=30.72e6; + cfg->samples_per_frame = 307200; + cfg->tx_bw = 10e6; + cfg->rx_bw = 10e6; + } + } else if(fp->N_RB_DL == 50) { + cfg->sample_rate=15.36e6; + cfg->samples_per_frame = 153600; + cfg->tx_bw = 5e6; + cfg->rx_bw = 5e6; + } else if (fp->N_RB_DL == 25) { + cfg->sample_rate=7.68e6; + cfg->samples_per_frame = 76800; + cfg->tx_bw = 2.5e6; + cfg->rx_bw = 2.5e6; + } else if (fp->N_RB_DL == 6) { + cfg->sample_rate=1.92e6; + cfg->samples_per_frame = 19200; + cfg->tx_bw = 1.5e6; + cfg->rx_bw = 1.5e6; + } + else AssertFatal(1==0,"Unknown N_RB_DL %d\n",fp->N_RB_DL); + + if (fp->frame_type==TDD) + cfg->duplex_mode = duplex_mode_TDD; + else //FDD + cfg->duplex_mode = duplex_mode_FDD; + + cfg->Mod_id = 0; + cfg->num_rb_dl=fp->N_RB_DL; + cfg->tx_num_channels=ru->nb_tx; + cfg->rx_num_channels=ru->nb_rx; + + for (i=0; i<ru->nb_tx; i++) { + + cfg->tx_freq[i] = (double)fp->dl_CarrierFreq; + cfg->rx_freq[i] = (double)fp->ul_CarrierFreq; + + cfg->tx_gain[i] = ru->att_tx; + cfg->rx_gain[i] = ru->max_rxgain-ru->att_rx; + + cfg->configFilename = rf_config_file; + printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n", + i, cfg->tx_gain[i], + cfg->rx_gain[i], + cfg->tx_freq[i], + cfg->rx_freq[i]); + } +} + +/* this function maps the RU tx and rx buffers to the available rf chains. + Each rf chain is is addressed by the card number and the chain on the card. The + rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple + antennas are mapped to successive RF chains on the same card. */ +int setup_RU_buffers(RU_t *ru) { + + int i,j; + int card,ant; + + //uint16_t N_TA_offset = 0; + + LTE_DL_FRAME_PARMS *frame_parms; + + if (ru) { + frame_parms = &ru->frame_parms; + printf("setup_RU_buffers: frame_parms = %p\n",frame_parms); + } else { + printf("RU[%d] not initialized\n", ru->idx); + return(-1); + } + + + if (frame_parms->frame_type == TDD) { + if (frame_parms->N_RB_DL == 100) ru->N_TA_offset = 624; + else if (frame_parms->N_RB_DL == 50) ru->N_TA_offset = 624/2; + else if (frame_parms->N_RB_DL == 25) ru->N_TA_offset = 624/4; + } + if (ru->openair0_cfg.mmapped_dma == 1) { + // replace RX signal buffers with mmaped HW versions + + for (i=0; i<ru->nb_rx; i++) { + card = i/4; + ant = i%4; + printf("Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); + free(ru->common.rxdata[i]); + ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant]; + + printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]); + for (j=0; j<16; j++) { + printf("rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]); + ru->common.rxdata[i][j] = 16-j; + } + } + + for (i=0; i<ru->nb_tx; i++) { + card = i/4; + ant = i%4; + printf("Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); + free(ru->common.txdata[i]); + ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant]; + + printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]); + + for (j=0; j<16; j++) { + printf("txbuffer %d: %x\n",j,ru->common.txdata[i][j]); + ru->common.txdata[i][j] = 16-j; + } + } + } + else { // not memory-mapped DMA + //nothing to do, everything already allocated in lte_init + } + return(0); +} + +static void* ru_stats_thread(void* param) { + + RU_t *ru = (RU_t*)param; + + wait_sync("ru_stats_thread"); + + while (!oai_exit) { + sleep(1); + if (opp_enabled == 1) { + if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx",NULL,NULL); + if (ru->feptx_ofdm) print_meas(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL); + if (ru->fh_north_asynch_in) print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL); + if (ru->fh_north_out) { + print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL); + print_meas(&ru->compression,"compression",NULL,NULL); + print_meas(&ru->transport,"transport",NULL,NULL); + } + } + } + return(NULL); +} + +static void* ru_thread( void* param ) { + + static int ru_thread_status; + + RU_t *ru = (RU_t*)param; + RU_proc_t *proc = &ru->proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + int ret; + int subframe =9; + int frame =1023; + + // set default return value + ru_thread_status = 0; + + + // set default return value + thread_top_init("ru_thread",0,870000,1000000,1000000); + + LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]); + + + // Start IF device if any + if (ru->start_if) { + LOG_I(PHY,"Starting IF interface for RU %d\n",ru->idx); + AssertFatal(ru->start_if(ru,NULL) == 0, "Could not start the IF device\n"); + if (ru->if_south == LOCAL_RF) ret = connect_rau(ru); + else ret = attach_rru(ru); + AssertFatal(ret==0,"Cannot connect to radio\n"); + } + if (ru->if_south == LOCAL_RF) { // configure RF parameters only + fill_rf_config(ru,ru->rf_config_file); + init_frame_parms(&ru->frame_parms,1); + phy_init_RU(ru); + + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + } + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + } + + LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); + pthread_mutex_lock(&RC.ru_mutex); + RC.ru_mask &= ~(1<<ru->idx); + pthread_cond_signal(&RC.ru_cond); + pthread_mutex_unlock(&RC.ru_mutex); + + wait_sync("ru_thread"); + + + + + // Start RF device if any + if (ru->start_rf) { + if (ru->start_rf(ru) != 0) + LOG_E(HW,"Could not start the RF device\n"); + else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); + } + else LOG_I(PHY,"RU %d no rf device\n",ru->idx); + + + // if an asnych_rxtx thread exists + // wakeup the thread because the devices are ready at this point + + if ((ru->fh_south_asynch_in)||(ru->fh_north_asynch_in)) { + pthread_mutex_lock(&proc->mutex_asynch_rxtx); + proc->instance_cnt_asynch_rxtx=0; + pthread_mutex_unlock(&proc->mutex_asynch_rxtx); + pthread_cond_signal(&proc->cond_asynch_rxtx); + } + else LOG_I(PHY,"RU %d no asynch_south interface\n",ru->idx); + + // if this is a slave RRU, try to synchronize on the DL frequency + if ((ru->is_slave) && (ru->if_south == LOCAL_RF)) do_ru_synch(ru); + + + // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices + while (!oai_exit) { + + // these are local subframe/frame counters to check that we are in synch with the fronthaul timing. + // They are set on the first rx/tx in the underly FH routines. + if (subframe==9) { + subframe=0; + frame++; + frame&=1023; + } else { + subframe++; + } + + // synchronization on input FH interface, acquire signals/data and block + if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&subframe); + else AssertFatal(1==0, "No fronthaul interface at south port"); + +/* + LOG_D(PHY,"AFTER fh_south_in - SFN/SF:%d%d RU->proc[RX:%d%d TX:%d%d] RC.eNB[0][0]:[RX:%d%d TX(SFN):%d]\n", + frame,subframe, + proc->frame_rx,proc->subframe_rx, + proc->frame_tx,proc->subframe_tx, + RC.eNB[0][0]->proc.frame_rx,RC.eNB[0][0]->proc.subframe_rx, + RC.eNB[0][0]->proc.frame_tx); + + LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n", + ru->do_prach, + is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx), + proc->frame_rx,proc->subframe_rx); +*/ + if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) { + wakeup_prach_ru(ru); + } +#ifdef Rel14 + else if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>1)) { + wakeup_prach_ru_br(ru); + } +#endif + + // adjust for timing offset between RU + if (ru->idx!=0) proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023; + + + // do RX front-end processing (frequency-shift, dft) if needed + if (ru->feprx) ru->feprx(ru); + + // At this point, all information for subframe has been received on FH interface + // If this proc is to provide synchronization, do so + wakeup_slaves(proc); + + // wakeup all eNB processes waiting for this RU + if (ru->num_eNB>0) wakeup_eNBs(ru); + + // wait until eNBs are finished subframe RX n and TX n+sf_ahead + wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread"); + + + // do TX front-end processing if needed (precoding and/or IDFTs) + if (ru->feptx_prec) ru->feptx_prec(ru); + + // do OFDM if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + + if (ru->fh_north_out) ru->fh_north_out(ru); + } + + + printf( "Exiting ru_thread \n"); + + if (ru->stop_rf != NULL) { + if (ru->stop_rf(ru) != 0) + LOG_E(HW,"Could not stop the RF device\n"); + else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); + } + + ru_thread_status = 0; + return &ru_thread_status; + +} + + +// This thread run the initial synchronization like a UE +void *ru_thread_synch(void *arg) { + + RU_t *ru = (RU_t*)arg; + LTE_DL_FRAME_PARMS *fp=&ru->frame_parms; + int32_t sync_pos,sync_pos2; + uint32_t peak_val; + uint32_t sync_corr[307200] __attribute__((aligned(32))); + static int ru_thread_synch_status; + + + thread_top_init("ru_thread_synch",0,5000000,10000000,10000000); + + wait_sync("ru_thread_synch"); + + // initialize variables for PSS detection + lte_sync_time_init(&ru->frame_parms); + + while (!oai_exit) { + + // wait to be woken up + if (wait_on_condition(&ru->proc.mutex_synch,&ru->proc.cond_synch,&ru->proc.instance_cnt_synch,"ru_thread_synch")<0) break; + + // if we're not in synch, then run initial synch + if (ru->in_synch == 0) { + // run intial synch like UE + LOG_I(PHY,"Running initial synchronization\n"); + + sync_pos = lte_sync_time_eNB(ru->common.rxdata, + fp, + fp->samples_per_tti*5, + &peak_val, + sync_corr); + LOG_I(PHY,"RU synch: %d, val %d\n",sync_pos,peak_val); + + if (sync_pos >= 0) { + if (sync_pos >= fp->nb_prefix_samples) + sync_pos2 = sync_pos - fp->nb_prefix_samples; + else + sync_pos2 = sync_pos + (fp->samples_per_tti*10) - fp->nb_prefix_samples; + + if (fp->frame_type == FDD) { + + // PSS is hypothesized in last symbol of first slot in Frame + int sync_pos_slot = (fp->samples_per_tti>>1) - fp->ofdm_symbol_size - fp->nb_prefix_samples; + + if (sync_pos2 >= sync_pos_slot) + ru->rx_offset = sync_pos2 - sync_pos_slot; + else + ru->rx_offset = (fp->samples_per_tti*10) + sync_pos2 - sync_pos_slot; + } + else { + + } + + LOG_I(PHY,"Estimated sync_pos %d, peak_val %d => timing offset %d\n",sync_pos,peak_val,ru->rx_offset); + + /* + if ((peak_val > 300000) && (sync_pos > 0)) { + // if (sync_pos++ > 3) { + write_output("ru_sync.m","sync",(void*)&sync_corr[0],fp->samples_per_tti*5,1,2); + write_output("ru_rx.m","rxs",(void*)ru->ru_time.rxdata[0][0],fp->samples_per_tti*10,1,1); + exit(-1); + } + */ + ru->in_synch=1; + } + } + + if (release_thread(&ru->proc.mutex_synch,&ru->proc.instance_cnt_synch,"ru_synch_thread") < 0) break; + } // oai_exit + + ru_thread_synch_status = 0; + return &ru_thread_synch_status; + +} + + + +int start_if(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB) { + return(ru->ifdevice.trx_start_func(&ru->ifdevice)); +} + +int start_rf(RU_t *ru) { + return(ru->rfdevice.trx_start_func(&ru->rfdevice)); +} + +int stop_rf(RU_t *ru) +{ + ru->rfdevice.trx_end_func(&ru->rfdevice); + return 0; +} + +extern void fep_full(RU_t *ru); +extern void ru_fep_full_2thread(RU_t *ru); +extern void feptx_ofdm(RU_t *ru); +extern void feptx_ofdm_2thread(RU_t *ru); +extern void feptx_prec(RU_t *ru); +extern void init_fep_thread(RU_t *ru,pthread_attr_t *attr); +extern void init_feptx_thread(RU_t *ru,pthread_attr_t *attr); + +void init_RU_proc(RU_t *ru) { + + int i=0; + RU_proc_t *proc; + pthread_attr_t *attr_FH=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_synch=NULL; + //pthread_attr_t *attr_fep=NULL; +#ifdef Rel14 + pthread_attr_t *attr_prach_br=NULL; +#endif + char name[100]; + +#ifndef OCP_FRAMEWORK + LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]); +#endif + proc = &ru->proc; + memset((void*)proc,0,sizeof(RU_proc_t)); + + proc->ru = ru; + proc->instance_cnt_prach = -1; + proc->instance_cnt_synch = -1; ; + proc->instance_cnt_FH = -1; + proc->instance_cnt_asynch_rxtx = -1; + proc->first_rx = 1; + proc->first_tx = 1; + proc->frame_offset = 0; + proc->num_slaves = 0; + proc->frame_tx_unwrap = 0; + + for (i=0;i<10;i++) proc->symbol_mask[i]=0; + + pthread_mutex_init( &proc->mutex_prach, NULL); + pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); + pthread_mutex_init( &proc->mutex_synch,NULL); + pthread_mutex_init( &proc->mutex_FH,NULL); + pthread_mutex_init( &proc->mutex_eNBs, NULL); + + pthread_cond_init( &proc->cond_prach, NULL); + pthread_cond_init( &proc->cond_FH, NULL); + pthread_cond_init( &proc->cond_asynch_rxtx, NULL); + pthread_cond_init( &proc->cond_synch,NULL); + pthread_cond_init( &proc->cond_eNBs, NULL); + + pthread_attr_init( &proc->attr_FH); + pthread_attr_init( &proc->attr_prach); + pthread_attr_init( &proc->attr_synch); + pthread_attr_init( &proc->attr_asynch_rxtx); + pthread_attr_init( &proc->attr_fep); + +#ifdef Rel14 + proc->instance_cnt_prach_br = -1; + pthread_mutex_init( &proc->mutex_prach_br, NULL); + pthread_cond_init( &proc->cond_prach_br, NULL); + pthread_attr_init( &proc->attr_prach_br); +#endif + +#ifndef DEADLINE_SCHEDULER + attr_FH = &proc->attr_FH; + attr_prach = &proc->attr_prach; + attr_synch = &proc->attr_synch; + attr_asynch = &proc->attr_asynch_rxtx; +#ifdef Rel14 + attr_prach_br = &proc->attr_prach_br; +#endif +#endif + + pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void*)ru ); + + if (ru->function == NGFI_RRU_IF4p5) { + pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru ); +#ifdef Rel14 + pthread_create( &proc->pthread_prach_br, attr_prach_br, ru_thread_prach_br, (void*)ru ); +#endif + if (ru->is_slave == 1) pthread_create( &proc->pthread_synch, attr_synch, ru_thread_synch, (void*)ru); + + + if ((ru->if_timing == synch_to_other) || + (ru->function == NGFI_RRU_IF5) || + (ru->function == NGFI_RRU_IF4p5)) pthread_create( &proc->pthread_asynch_rxtx, attr_asynch, ru_thread_asynch_rxtx, (void*)ru ); + + snprintf( name, sizeof(name), "ru_thread_FH %d", ru->idx ); + pthread_setname_np( proc->pthread_FH, name ); + + } + else if (ru->function == eNodeB_3GPP && ru->if_south == LOCAL_RF) { // DJP - need something else to distinguish between monolithic and PNF + LOG_I(PHY,"%s() DJP - added creation of pthread_prach\n", __FUNCTION__); + pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru ); + } + + if (get_nprocs()>=2) { + if (ru->feprx) init_fep_thread(ru,NULL); + if (ru->feptx_ofdm) init_feptx_thread(ru,NULL); + } + if (opp_enabled == 1) pthread_create(&ru->ru_stats_thread,NULL,ru_stats_thread,(void*)ru); + +} + +void kill_RU_proc(int inst) +{ + RU_t *ru = RC.ru[inst]; + RU_proc_t *proc = &ru->proc; + + pthread_mutex_lock(&proc->mutex_FH); + proc->instance_cnt_FH = 0; + pthread_mutex_unlock(&proc->mutex_FH); + pthread_cond_signal(&proc->cond_FH); + + pthread_mutex_lock(&proc->mutex_prach); + proc->instance_cnt_prach = 0; + pthread_mutex_unlock(&proc->mutex_prach); + pthread_cond_signal(&proc->cond_prach); + +#ifdef Rel14 + pthread_mutex_lock(&proc->mutex_prach_br); + proc->instance_cnt_prach_br = 0; + pthread_mutex_unlock(&proc->mutex_prach_br); + pthread_cond_signal(&proc->cond_prach_br); +#endif + + pthread_mutex_lock(&proc->mutex_synch); + proc->instance_cnt_synch = 0; + pthread_mutex_unlock(&proc->mutex_synch); + pthread_cond_signal(&proc->cond_synch); + + pthread_mutex_lock(&proc->mutex_eNBs); + proc->instance_cnt_eNBs = 0; + pthread_mutex_unlock(&proc->mutex_eNBs); + pthread_cond_signal(&proc->cond_eNBs); + + pthread_mutex_lock(&proc->mutex_asynch_rxtx); + proc->instance_cnt_asynch_rxtx = 0; + pthread_mutex_unlock(&proc->mutex_asynch_rxtx); + pthread_cond_signal(&proc->cond_asynch_rxtx); + + LOG_D(PHY, "Joining pthread_FH\n"); + pthread_join(proc->pthread_FH, NULL); + if (ru->function == NGFI_RRU_IF4p5) { + LOG_D(PHY, "Joining pthread_prach\n"); + pthread_join(proc->pthread_prach, NULL); +#ifdef Rel14 + LOG_D(PHY, "Joining pthread_prach_br\n"); + pthread_join(proc->pthread_prach_br, NULL); +#endif + if (ru->is_slave) { + LOG_D(PHY, "Joining pthread_\n"); + pthread_join(proc->pthread_synch, NULL); + } + + if ((ru->if_timing == synch_to_other) || + (ru->function == NGFI_RRU_IF5) || + (ru->function == NGFI_RRU_IF4p5)) { + LOG_D(PHY, "Joining pthread_asynch_rxtx\n"); + pthread_join(proc->pthread_asynch_rxtx, NULL); + } + } + if (get_nprocs() >= 2) { + if (ru->feprx) { + pthread_mutex_lock(&proc->mutex_fep); + proc->instance_cnt_fep = 0; + pthread_mutex_unlock(&proc->mutex_fep); + pthread_cond_signal(&proc->cond_fep); + LOG_D(PHY, "Joining pthread_fep\n"); + pthread_join(proc->pthread_fep, NULL); + pthread_mutex_destroy(&proc->mutex_fep); + pthread_cond_destroy(&proc->cond_fep); + } + if (ru->feptx_ofdm) { + pthread_mutex_lock(&proc->mutex_feptx); + proc->instance_cnt_feptx = 0; + pthread_mutex_unlock(&proc->mutex_feptx); + pthread_cond_signal(&proc->cond_feptx); + LOG_D(PHY, "Joining pthread_feptx\n"); + pthread_join(proc->pthread_feptx, NULL); + pthread_mutex_destroy(&proc->mutex_feptx); + pthread_cond_destroy(&proc->cond_feptx); + } + } + if (opp_enabled) { + LOG_D(PHY, "Joining ru_stats_thread\n"); + pthread_join(ru->ru_stats_thread, NULL); + } + + pthread_mutex_destroy(&proc->mutex_prach); + pthread_mutex_destroy(&proc->mutex_asynch_rxtx); + pthread_mutex_destroy(&proc->mutex_synch); + pthread_mutex_destroy(&proc->mutex_FH); + pthread_mutex_destroy(&proc->mutex_eNBs); + + pthread_cond_destroy(&proc->cond_prach); + pthread_cond_destroy(&proc->cond_FH); + pthread_cond_destroy(&proc->cond_asynch_rxtx); + pthread_cond_destroy(&proc->cond_synch); + pthread_cond_destroy(&proc->cond_eNBs); + + pthread_attr_destroy(&proc->attr_FH); + pthread_attr_destroy(&proc->attr_prach); + pthread_attr_destroy(&proc->attr_synch); + pthread_attr_destroy(&proc->attr_asynch_rxtx); + pthread_attr_destroy(&proc->attr_fep); + +#ifdef Rel14 + pthread_mutex_destroy(&proc->mutex_prach_br); + pthread_cond_destroy(&proc->cond_prach_br); + pthread_attr_destroy(&proc->attr_prach_br); +#endif +} + +int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) { + + FH_fmt_options_t fmt = cap->FH_fmt; + + int i; + int found_band=0; + + LOG_I(PHY,"RRU %d, num_bands %d, looking for band %d\n",ru->idx,cap->num_bands,ru->frame_parms.eutra_band); + for (i=0;i<cap->num_bands;i++) { + LOG_I(PHY,"band %d on RRU %d\n",cap->band_list[i],ru->idx); + if (ru->frame_parms.eutra_band == cap->band_list[i]) { + found_band=1; + break; + } + } + + if (found_band == 0) { + LOG_I(PHY,"Couldn't find target EUTRA band %d on RRU %d\n",ru->frame_parms.eutra_band,ru->idx); + return(-1); + } + + switch (ru->if_south) { + case LOCAL_RF: + AssertFatal(1==0, "This RU should not have a local RF, exiting\n"); + return(0); + break; + case REMOTE_IF5: + if (fmt == OAI_IF5_only || fmt == OAI_IF5_and_IF4p5) return(0); + break; + case REMOTE_IF4p5: + if (fmt == OAI_IF4p5_only || fmt == OAI_IF5_and_IF4p5) return(0); + break; + case REMOTE_MBP_IF5: + if (fmt == MBP_IF5) return(0); + break; + default: + LOG_I(PHY,"No compatible Fronthaul interface found for RRU %d\n", ru->idx); + return(-1); + } + + return(-1); +} + + +char rru_format_options[4][20] = {"OAI_IF5_only","OAI_IF4p5_only","OAI_IF5_and_IF4p5","MBP_IF5"}; + +char rru_formats[3][20] = {"OAI_IF5","MBP_IF5","OAI_IF4p5"}; +char ru_if_formats[4][20] = {"LOCAL_RF","REMOTE_OAI_IF5","REMOTE_MBP_IF5","REMOTE_OAI_IF4p5"}; + +void configure_ru(int idx, + void *arg) { + + RU_t *ru = RC.ru[idx]; + RRU_config_t *config = (RRU_config_t *)arg; + RRU_capabilities_t *capabilities = (RRU_capabilities_t*)arg; + int ret; + + LOG_I(PHY, "Received capabilities from RRU %d\n",idx); + + + if (capabilities->FH_fmt < MAX_FH_FMTs) LOG_I(PHY, "RU FH options %s\n",rru_format_options[capabilities->FH_fmt]); + + AssertFatal((ret=check_capabilities(ru,capabilities)) == 0, + "Cannot configure RRU %d, check_capabilities returned %d\n", idx,ret); + // take antenna capabilities of RRU + ru->nb_tx = capabilities->nb_tx[0]; + ru->nb_rx = capabilities->nb_rx[0]; + + // Pass configuration to RRU + LOG_I(PHY, "Using %s fronthaul (%d), band %d \n",ru_if_formats[ru->if_south],ru->if_south,ru->frame_parms.eutra_band); + // wait for configuration + config->FH_fmt = ru->if_south; + config->num_bands = 1; + config->band_list[0] = ru->frame_parms.eutra_band; + config->tx_freq[0] = ru->frame_parms.dl_CarrierFreq; + config->rx_freq[0] = ru->frame_parms.ul_CarrierFreq; + config->tdd_config[0] = ru->frame_parms.tdd_config; + config->tdd_config_S[0] = ru->frame_parms.tdd_config_S; + config->att_tx[0] = ru->att_tx; + config->att_rx[0] = ru->att_rx; + config->N_RB_DL[0] = ru->frame_parms.N_RB_DL; + config->N_RB_UL[0] = ru->frame_parms.N_RB_UL; + config->threequarter_fs[0] = ru->frame_parms.threequarter_fs; + if (ru->if_south==REMOTE_IF4p5) { + config->prach_FreqOffset[0] = ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset; + config->prach_ConfigIndex[0] = ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex; + LOG_I(PHY,"REMOTE_IF4p5: prach_FrequOffset %d, prach_ConfigIndex %d\n", + config->prach_FreqOffset[0],config->prach_ConfigIndex[0]); + +#ifdef Rel14 + int i; + for (i=0;i<4;i++) { + config->emtc_prach_CElevel_enable[0][i] = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i]; + config->emtc_prach_FreqOffset[0][i] = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[i]; + config->emtc_prach_ConfigIndex[0][i] = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i]; + } +#endif + } + + init_frame_parms(&ru->frame_parms,1); + phy_init_RU(ru); +} + +void configure_rru(int idx, + void *arg) { + + RRU_config_t *config = (RRU_config_t *)arg; + RU_t *ru = RC.ru[idx]; + + ru->frame_parms.eutra_band = config->band_list[0]; + ru->frame_parms.dl_CarrierFreq = config->tx_freq[0]; + ru->frame_parms.ul_CarrierFreq = config->rx_freq[0]; + if (ru->frame_parms.dl_CarrierFreq == ru->frame_parms.ul_CarrierFreq) { + ru->frame_parms.frame_type = TDD; + ru->frame_parms.tdd_config = config->tdd_config[0]; + ru->frame_parms.tdd_config_S = config->tdd_config_S[0]; + } + else + ru->frame_parms.frame_type = FDD; + ru->att_tx = config->att_tx[0]; + ru->att_rx = config->att_rx[0]; + ru->frame_parms.N_RB_DL = config->N_RB_DL[0]; + ru->frame_parms.N_RB_UL = config->N_RB_UL[0]; + ru->frame_parms.threequarter_fs = config->threequarter_fs[0]; + ru->frame_parms.pdsch_config_common.referenceSignalPower = ru->max_pdschReferenceSignalPower-config->att_tx[0]; + if (ru->function==NGFI_RRU_IF4p5) { + ru->frame_parms.att_rx = ru->att_rx; + ru->frame_parms.att_tx = ru->att_tx; + + LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d, att (%d,%d)\n", + config->prach_FreqOffset[0],config->prach_ConfigIndex[0],ru->att_tx,ru->att_rx); + ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset = config->prach_FreqOffset[0]; + ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex = config->prach_ConfigIndex[0]; +#ifdef Rel14 + for (int i=0;i<4;i++) { + ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i] = config->emtc_prach_CElevel_enable[0][i]; + ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[i] = config->emtc_prach_FreqOffset[0][i]; + ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i] = config->emtc_prach_ConfigIndex[0][i]; + } +#endif + } + + init_frame_parms(&ru->frame_parms,1); + + fill_rf_config(ru,ru->rf_config_file); + + + phy_init_RU(ru); + +} + +void init_precoding_weights(PHY_VARS_eNB *eNB) { + + int layer,ru_id,aa,re,ue,tb; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + RU_t *ru; + LTE_eNB_DLSCH_t *dlsch; + + // init precoding weigths + for (ue=0;ue<NUMBER_OF_UE_MAX;ue++) { + for (tb=0;tb<2;tb++) { + dlsch = eNB->dlsch[ue][tb]; + for (layer=0; layer<4; layer++) { + int nb_tx=0; + for (ru_id=0;ru_id<RC.nb_RU;ru_id++) { + ru = RC.ru[ru_id]; + nb_tx+=ru->nb_tx; + } + dlsch->ue_spec_bf_weights[layer] = (int32_t**)malloc16(nb_tx*sizeof(int32_t*)); + + for (aa=0; aa<nb_tx; aa++) { + dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t)); + for (re=0;re<fp->ofdm_symbol_size; re++) { + dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; + } + } + } + } + } +} + +void set_function_spec_param(RU_t *ru) +{ + int ret; + + switch (ru->if_south) { + case LOCAL_RF: // this is an RU with integrated RF (RRU, eNB) + if (ru->function == NGFI_RRU_IF5) { // IF5 RRU + ru->do_prach = 0; // no prach processing in RU + ru->fh_north_in = NULL; // no shynchronous incoming fronthaul from north + ru->fh_north_out = fh_if5_north_out; // need only to do send_IF5 reception + ru->fh_south_out = tx_rf; // send output to RF + ru->fh_north_asynch_in = fh_if5_north_asynch_in; // TX packets come asynchronously + ru->feprx = NULL; // nothing (this is a time-domain signal) + ru->feptx_ofdm = NULL; // nothing (this is a time-domain signal) + ru->feptx_prec = NULL; // nothing (this is a time-domain signal) + ru->start_if = start_if; // need to start the if interface for if5 + ru->ifdevice.host_type = RRU_HOST; + ru->rfdevice.host_type = RRU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + reset_meas(&ru->rx_fhaul); + reset_meas(&ru->tx_fhaul); + reset_meas(&ru->compression); + reset_meas(&ru->transport); + + ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + } + else if (ru->function == NGFI_RRU_IF4p5) { + ru->do_prach = 1; // do part of prach processing in RU + ru->fh_north_in = NULL; // no synchronous incoming fronthaul from north + ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception + ru->fh_south_out = tx_rf; // send output to RF + ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously + ru->feprx = (get_nprocs()<=2) ? fep_full :ru_fep_full_2thread; // RX DFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft only (no precoding in RRU) + ru->feptx_prec = NULL; + ru->start_if = start_if; // need to start the if interface for if4p5 + ru->ifdevice.host_type = RRU_HOST; + ru->rfdevice.host_type = RRU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + reset_meas(&ru->rx_fhaul); + reset_meas(&ru->tx_fhaul); + reset_meas(&ru->compression); + reset_meas(&ru->transport); + + ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + malloc_IF4p5_buffer(ru); + } + else if (ru->function == eNodeB_3GPP) { + ru->do_prach = 0; // no prach processing in RU + ru->feprx = (get_nprocs()<=2) ? fep_full : ru_fep_full_2thread; // RX DFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft and precoding + ru->feptx_prec = feptx_prec; // this is fep with idft and precoding + ru->fh_north_in = NULL; // no incoming fronthaul from north + ru->fh_north_out = NULL; // no outgoing fronthaul to north + ru->start_if = NULL; // no if interface + ru->rfdevice.host_type = RAU_HOST; + } + ru->fh_south_in = rx_rf; // local synchronous RF RX + ru->fh_south_out = tx_rf; // local synchronous RF TX + ru->start_rf = start_rf; // need to start the local RF interface + ru->stop_rf = stop_rf; + printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf); +/* + if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise + fill_rf_config(ru,rf_config_file); + init_frame_parms(&ru->frame_parms,1); + phy_init_RU(ru); + } + + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + }*/ + break; + + case REMOTE_IF5: // the remote unit is IF5 RRU + ru->do_prach = 0; + ru->feprx = (get_nprocs()<=2) ? fep_full : fep_full; // this is frequency-shift + DFTs + ru->feptx_prec = feptx_prec; // need to do transmit Precoding + IDFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread; // need to do transmit Precoding + IDFTs + if (ru->if_timing == synch_to_other) { + ru->fh_south_in = fh_slave_south_in; // synchronize to master + ru->fh_south_out = fh_if5_mobipass_south_out; // use send_IF5 for mobipass + ru->fh_south_asynch_in = fh_if5_south_asynch_in_mobipass; // UL is asynchronous + } + else { + ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception + ru->fh_south_out = fh_if5_south_out; // synchronous IF5 transmission + ru->fh_south_asynch_in = NULL; // no asynchronous UL + } + ru->start_rf = NULL; // no local RF + ru->stop_rf = NULL; + ru->start_if = start_if; // need to start if interface for IF5 + ru->ifdevice.host_type = RAU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + ru->ifdevice.configure_rru = configure_ru; + + ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + break; + + case REMOTE_IF4p5: + ru->do_prach = 0; + ru->feprx = NULL; // DFTs + ru->feptx_prec = feptx_prec; // Precoding operation + ru->feptx_ofdm = NULL; // no OFDM mod + ru->fh_south_in = fh_if4p5_south_in; // synchronous IF4p5 reception + ru->fh_south_out = fh_if4p5_south_out; // synchronous IF4p5 transmission + ru->fh_south_asynch_in = (ru->if_timing == synch_to_other) ? fh_if4p5_south_in : NULL; // asynchronous UL if synch_to_other + ru->fh_north_out = NULL; + ru->fh_north_asynch_in = NULL; + ru->start_rf = NULL; // no local RF + ru->stop_rf = NULL; + ru->start_if = start_if; // need to start if interface for IF4p5 + ru->ifdevice.host_type = RAU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + ru->ifdevice.configure_rru = configure_ru; + + ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + + malloc_IF4p5_buffer(ru); + + break; + + default: + LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); + break; + } // switch on interface type +} + +extern void RCconfig_RU(void); + +void init_RU(char *rf_config_file) { + + int ru_id; + RU_t *ru; + PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL; + int i; + int CC_id; + + // create status mask + RC.ru_mask = 0; + pthread_mutex_init(&RC.ru_mutex,NULL); + pthread_cond_init(&RC.ru_cond,NULL); + + // read in configuration file) + printf("configuring RU from file\n"); + RCconfig_RU(); + LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs()); + + if (RC.nb_CC != 0) + for (i=0;i<RC.nb_L1_inst;i++) + for (CC_id=0;CC_id<RC.nb_CC[i];CC_id++) RC.eNB[i][CC_id]->num_RU=0; + + LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU); + for (ru_id=0;ru_id<RC.nb_RU;ru_id++) { + LOG_D(PHY,"Process RC.ru[%d]\n",ru_id); + ru = RC.ru[ru_id]; + ru->rf_config_file = rf_config_file; + ru->idx = ru_id; + ru->ts_offset = 0; + // use eNB_list[0] as a reference for RU frame parameters + // NOTE: multiple CC_id are not handled here yet! + + if (ru->num_eNB > 0) { + LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file); + + if (ru->eNB_list[0] == 0) + { + LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", __FUNCTION__); + ru->eNB_list[0] = RC.eNB[0][0]; + ru->num_eNB=1; + // + // DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU + // + } + else + { + LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__); + } + } + eNB0 = ru->eNB_list[0]; + LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); + LOG_D(PHY, "eNB0:%p\n", eNB0); + if (eNB0) + { + if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5)) + AssertFatal(eNB0!=NULL,"eNB0 is null!\n"); + + if (eNB0) { + LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx); + memcpy((void*)&ru->frame_parms,(void*)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS)); + + // attach all RU to all eNBs in its list/ + LOG_D(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU); + for (i=0;i<ru->num_eNB;i++) { + eNB0 = ru->eNB_list[i]; + eNB0->RU_list[eNB0->num_RU++] = ru; + } + } + } + // LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function); + + set_function_spec_param(ru); + LOG_I(PHY,"Starting ru_thread %d\n",ru_id); + + init_RU_proc(ru); + + + + } // for ru_id + + // sleep(1); + LOG_D(HW,"[lte-softmodem.c] RU threads created\n"); + + +} + + + + +void stop_RU(int nb_ru) +{ + for (int inst = 0; inst < nb_ru; inst++) { + LOG_I(PHY, "Stopping RU %d processing threads\n", inst); + kill_RU_proc(inst); + } +} + + +/* --------------------------------------------------------*/ +/* from here function to use configuration module */ +void RCconfig_RU(void) { + + int j = 0; + int i = 0; + + + paramdef_t RUParams[] = RUPARAMS_DESC; + paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; + + + config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL); + + + if ( RUParamList.numelt > 0) { + + RC.ru = (RU_t**)malloc(RC.nb_RU*sizeof(RU_t*)); + + + + + RC.ru_mask=(1<<NB_RU) - 1; + printf("Set RU mask to %lx\n",RC.ru_mask); + + for (j = 0; j < RC.nb_RU; j++) { + + RC.ru[j] = (RU_t*)malloc(sizeof(RU_t)); + memset((void*)RC.ru[j],0,sizeof(RU_t)); + RC.ru[j]->idx = j; + + printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]); + + RC.ru[j]->if_timing = synch_to_ext_device; + if (RC.nb_L1_inst >0) + RC.ru[j]->num_eNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt; + else + RC.ru[j]->num_eNB = 0; + for (i=0;i<RC.ru[j]->num_eNB;i++) RC.ru[j]->eNB_list[i] = RC.eNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0]; + + + if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) { + if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = eNodeB_3GPP; + printf("Setting function for RU %d to eNodeB_3GPP\n",j); + } + else { + RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); + + if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF5 (udp)\n",j); + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF5 (raw)\n",j); + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n",j); + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j); + } + } + RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; + RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); + RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; + for (i=0;i<RC.ru[j]->num_bands;i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; + } //strcmp(local_rf, "yes") == 0 + else { + printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr)); + + RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); + if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { + RC.ru[j]->if_south = REMOTE_IF4p5; + RC.ru[j]->function = NGFI_RAU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { + RC.ru[j]->if_south = REMOTE_IF4p5; + RC.ru[j]->function = NGFI_RAU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if5_mobipass") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->if_timing = synch_to_other; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF5_MOBIPASS; + } + } /* strcmp(local_rf, "yes") != 0 */ + + RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr); + RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); + + RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); + RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); + }// j=0..num_rus + } else { + RC.nb_RU = 0; + } // setting != NULL + + return; + +} diff --git a/targets/RT/USER/nr-softmodem.c b/targets/RT/USER/nr-softmodem.c index 809f330b4c32bc1b3890cd4867fc8d3a18c97834..a29b8916ae65f8a17935cdf1d379f219fc6fa8c7 100644 --- a/targets/RT/USER/nr-softmodem.c +++ b/targets/RT/USER/nr-softmodem.c @@ -19,11 +19,317 @@ * contact@openairinterface.org */ -#include "nr-softmodem.h" +#if 0 +//Temporary main function +int main( int argc, char **argv ) +{ + nfapi_config_request_t config; + NR_DL_FRAME_PARMS* frame_parms = malloc(sizeof(NR_DL_FRAME_PARMS)); + int16_t amp; + + int16_t** txdataF = (int16_t **)malloc(2048*2*14*2*2* sizeof(int16_t)); + int16_t* d_pss = malloc(NR_PSS_LENGTH * sizeof(int16_t)); + int16_t *d_sss = malloc(NR_SSS_LENGTH * sizeof(int16_t)); + + //logInit(); + + phy_init_nr_gNB(&config); + nr_init_frame_parms(config, frame_parms); + nr_dump_frame_parms(frame_parms); + + amp = 32767; //1_Q_15 + nr_generate_pss(d_pss, txdataF, amp, 0, 0, config, frame_parms); + nr_generate_sss(d_sss, txdataF, amp, 0, 0, config, frame_parms); + + free(txdataF); + free(d_pss); + free(d_sss); + + return 0; +} +#endif + + +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <sched.h> +#include "T.h" +#include "rt_wrapper.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "assertions.h" +#include "msc.h" + +#include "common/ran_context.h" +#include "common/config/config_userapi.h" +#include "common/utils/load_module_shlib.h" +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "../../ARCH/COMMON/common_lib.h" +#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h" + +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + #include "PHY/types.h" #include "PHY/defs_NR.h" +#include "PHY/vars.h" +#include "SCHED/vars.h" +#include "LAYER2/MAC/vars.h" + +#include "../../SIMU/USER/init_lte.h" + +#include "LAYER2/MAC/defs.h" +#include "LAYER2/MAC/vars.h" +#include "LAYER2/MAC/proto.h" +#include "RRC/LITE/vars.h" +#include "PHY_INTERFACE/vars.h" + +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif +#include "UTIL/LOG/log_extern.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" +#include "PHY/TOOLS/time_meas.h" + +#ifndef OPENAIR2 +#include "UTIL/OTG/otg_vars.h" +#endif + +#if defined(ENABLE_ITTI) +#include "intertask_interface_init.h" +#include "create_tasks.h" +#endif + +#include "system.h" + +#ifdef XFORMS +#include "PHY/TOOLS/lte_phy_scope.h" +#include "stats.h" +#endif +#include "nr-softmodem.h" + +#ifdef XFORMS +// current status is that every UE has a DL scope for a SINGLE eNB (gnb_id=0) +// at eNB 0, an UL scope for every UE +/* +FD_lte_phy_scope_ue *form_ue[NUMBER_OF_UE_MAX]; +FD_lte_phy_scope_enb *form_enb[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +FD_stats_form *form_stats=NULL,*form_stats_l2=NULL; +char title[255]; +unsigned char scope_enb_num_ue = 2; +static pthread_t forms_thread; //xforms +*/ +#endif //XFORMS + +pthread_cond_t nfapi_sync_cond; +pthread_mutex_t nfapi_sync_mutex; +int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex + +uint8_t nfapi_mode = 0; // Default to monolithic mode + +pthread_cond_t sync_cond; +pthread_mutex_t sync_mutex; +int sync_var=-1; //!< protected by mutex \ref sync_mutex. +int config_sync_var=-1; + +uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] +uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] + +#if defined(ENABLE_ITTI) +volatile int start_gNB = 0; +#endif +volatile int oai_exit = 0; + +static clock_source_t clock_source = internal; +static int wait_for_sync = 0; + +unsigned int mmapped_dma=0; +int single_thread_flag=1; + +static int8_t threequarter_fs=0; + +uint32_t downlink_frequency[MAX_NUM_CCs][4]; +int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; + +//Temp fix for inexisting NR upper layer +unsigned char NB_gNB_INST = 1; + +#if defined(ENABLE_ITTI) +static char *itti_dump_file = NULL; +#endif + +int UE_scan = 1; +int UE_scan_carrier = 0; +runmode_t mode = normal_txrx; + +FILE *input_fd=NULL; + + +#if MAX_NUM_CCs == 1 +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}}; +#else +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}}; +#endif + +double rx_gain_off = 0.0; + +double sample_rate=30.72e6; +double bw = 10.0e6; + +static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/; + +char rf_config_file[1024]; + +int chain_offset=0; +int phy_test = 0; +uint8_t usim_test = 0; + +uint8_t dci_Format = 0; +uint8_t agregation_Level =0xFF; + +uint8_t nb_antenna_tx = 1; +uint8_t nb_antenna_rx = 1; + +char ref[128] = "internal"; +char channels[128] = "0"; + +int rx_input_level_dBm; + +#ifdef XFORMS +extern int otg_enabled; +static char do_forms=0; +#else +int otg_enabled; +#endif +//int number_of_cards = 1; + + +static NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; +static nfapi_config_request_t *config[MAX_NUM_CCs]; +uint32_t target_dl_mcs = 28; //maximum allowed mcs +uint32_t target_ul_mcs = 20; +uint32_t timing_advance = 0; +uint8_t exit_missed_slots=1; +uint64_t num_missed_slots=0; // counter for the number of missed slots + + +extern void reset_opp_meas(void); +extern void print_opp_meas(void); + +///extern void init_eNB_afterRU(void); + +int transmission_mode=1; + + + +/* struct for ethernet specific parameters given in eNB conf file */ +eth_params_t *eth_params; + +openair0_config_t openair0_cfg[MAX_CARDS]; + +double cpuf; + +extern char uecap_xer[1024]; +char uecap_xer_in=0; + +threads_t threads= {-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 + */ +uint8_t abstraction_flag=0; + +/* forward declarations */ +void set_default_frame_parms(nfapi_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); + +/*---------------------BMC: timespec helpers -----------------------------*/ + +struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; +struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + +struct timespec clock_difftime(struct timespec start, struct timespec end) { + struct timespec temp; + if ((end.tv_nsec-start.tv_nsec)<0) { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } else { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + return temp; +} + +void print_difftimes(void) { +#ifdef DEBUG + printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#else + LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#endif +} + +void update_difftimes(struct timespec start, struct timespec end) { + struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + int changed = 0; + diff_time = clock_difftime(start, end); + if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { + min_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { + max_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } +#if 1 + if (changed) print_difftimes(); +#endif +} + +/*------------------------------------------------------------------------*/ + +unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { + return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); +} +unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { + return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); +} + +#if !defined(ENABLE_ITTI) +void signal_handler(int sig) { + void *array[10]; + size_t size; + + if (sig==SIGSEGV) { + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, 2); + exit(-1); + } else { + printf("trying to exit gracefully...\n"); + oai_exit = 1; + } +} +#endif +#define KNRM "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KBLU "\x1B[34m" +#define RESET "\033[0m" + -//Temporary main function void exit_fun(const char* s) { @@ -34,7 +340,7 @@ void exit_fun(const char* s) printf("%s %s() Exiting OAI softmodem: %s\n",__FILE__, __FUNCTION__, s); } - /*oai_exit = 1; + oai_exit = 1; if (RC.ru == NULL) @@ -44,32 +350,970 @@ void exit_fun(const char* s) RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func) RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); - }*/ + } + + +#if defined(ENABLE_ITTI) + sleep(1); //allow lte-softmodem threads to exit first + itti_terminate_tasks (TASK_UNKNOWN); +#endif + + +} + +#ifdef XFORMS + + +void reset_stats(FL_OBJECT *button, long arg) +{ + int i,j,k; + PHY_VARS_gNB *phy_vars_gNB = RC.gNB[0][0]; + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + for (k=0; k<8; k++) { //harq_processes + for (j=0; j<phy_vars_gNB->dlsch[i][0]->Mlimit; j++) { + phy_vars_gNB->UE_stats[i].dlsch_NAK[k][j]=0; + phy_vars_gNB->UE_stats[i].dlsch_ACK[k][j]=0; + phy_vars_gNB->UE_stats[i].dlsch_trials[k][j]=0; + } + + phy_vars_gNB->UE_stats[i].dlsch_l2_errors[k]=0; + phy_vars_gNB->UE_stats[i].ulsch_errors[k]=0; + phy_vars_gNB->UE_stats[i].ulsch_consecutive_errors=0; + + + phy_vars_gNB->UE_stats[i].dlsch_sliding_cnt=0; + phy_vars_gNB->UE_stats[i].dlsch_NAK_round0=0; + phy_vars_gNB->UE_stats[i].dlsch_mcs_offset=0; + } + } +} +/* +static void *scope_thread(void *arg) { + +# ifdef ENABLE_XFORMS_WRITE_STATS + FILE *gNB_stats; +# endif + struct sched_param sched_param; + int UE_id, CC_id; + int ue_cnt=0; + + sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; + sched_setscheduler(0, SCHED_FIFO,&sched_param); + + printf("Scope thread has priority %d\n",sched_param.sched_priority); + +# ifdef ENABLE_XFORMS_WRITE_STATS + + gNB_stats = fopen("gNB_stats.txt", "w"); + +#endif + + while (!oai_exit) { + + ue_cnt=0; + for(UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + if ((ue_cnt<scope_enb_num_ue)) { + phy_scope_eNB(form_enb[CC_id][ue_cnt], + RC.gNB[0][CC_id], + UE_id); + ue_cnt++; + } + } + } + sleep(1); + } + + // printf("%s",stats_buffer); + +# ifdef ENABLE_XFORMS_WRITE_STATS + + if (eNB_stats) { + rewind (gNB_stats); + fwrite (stats_buffer, 1, len, gNB_stats); + fclose (gNB_stats); + } + +# endif + + pthread_exit((void*)arg); +}*/ +#endif + + + + +#if defined(ENABLE_ITTI) +void *l2l1_task(void *arg) { + MessageDef *message_p = NULL; + int result; + + itti_set_task_real_time(TASK_L2L1); + itti_mark_task_ready(TASK_L2L1); + + /* Wait for the initialize message */ + printf("Wait for the ITTI initialize message\n"); + do { + if (message_p != NULL) { + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } + + itti_receive_msg (TASK_L2L1, &message_p); + + switch (ITTI_MSG_ID(message_p)) { + case INITIALIZE_MESSAGE: + /* Start eNB thread */ + LOG_D(EMU, "L2L1 TASK received %s\n", ITTI_MSG_NAME(message_p)); + start_gNB = 1; + break; + + case TERMINATE_MESSAGE: + printf("received terminate message\n"); + oai_exit=1; + start_gNB = 0; + itti_exit_task (); + break; + + default: + LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); + break; + } + } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE); + + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); +/* ???? no else but seems to be UE only ??? + do { + // Wait for a message + itti_receive_msg (TASK_L2L1, &message_p); + + switch (ITTI_MSG_ID(message_p)) { + case TERMINATE_MESSAGE: + oai_exit=1; + itti_exit_task (); + break; + + case ACTIVATE_MESSAGE: + start_UE = 1; + break; + + case DEACTIVATE_MESSAGE: + start_UE = 0; + break; + + case MESSAGE_TEST: + LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p)); + break; + + default: + LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } while(!oai_exit); +*/ + return NULL; +} +#endif + + +static void get_options(void) { + + int tddflag, nonbiotflag; + + + uint32_t online_log_messages; + uint32_t glog_level, glog_verbosity; + uint32_t start_telnetsrv; + + paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ; + paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ; + + config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL); + + if (strlen(in_path) > 0) { + opt_type = OPT_PCAP; + opt_enabled=1; + printf("Enabling OPT for PCAP with the following file %s \n",in_path); + } + if (strlen(in_ip) > 0) { + opt_enabled=1; + opt_type = OPT_WIRESHARK; + printf("Enabling OPT for wireshark for local interface"); + } + + config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL); + if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) { + set_glog_onlinelog(online_log_messages); + } + if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) { + set_glog(glog_level, -1); + } + if(config_isparamset(cmdline_logparams,CMDLINE_GLOGVERBO_IDX)) { + set_glog(-1, glog_verbosity); + } + if (start_telnetsrv) { + load_module_shlib("telnetsrv",NULL,0); + } + +#if T_TRACER + paramdef_t cmdline_ttraceparams[] =CMDLINE_TTRACEPARAMS_DESC ; + config_process_cmdline( cmdline_ttraceparams,sizeof(cmdline_ttraceparams)/sizeof(paramdef_t),NULL); +#endif + + if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) { + memset((void*)&RC,0,sizeof(RC)); + /* Read RC configuration file */ + RCConfig(); + NB_gNB_INST = RC.nb_inst; + NB_RU = RC.nb_RU; + printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_gNB_INST,RC.nb_L1_inst,NB_RU); + } +} + + +#if T_TRACER +int T_nowait = 0; /* by default we wait for the tracer */ +int T_port = 2021; /* default port to listen to to wait for the tracer */ +int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */ +#endif + + + +void set_default_frame_parms(nfapi_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { + + int CC_id; + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + frame_parms[CC_id] = (NR_DL_FRAME_PARMS*) malloc(sizeof(NR_DL_FRAME_PARMS)); + config[CC_id] = (nfapi_config_request_t*) malloc(sizeof(nfapi_config_request_t)); + config[CC_id]->subframe_config.numerology_index_mu.value =1; + config[CC_id]->subframe_config.duplex_mode.value = 1; //FDD + config[CC_id]->subframe_config.dl_cyclic_prefix_type.value = 0; //NORMAL + config[CC_id]->rf_config.dl_channel_bandwidth.value = 106; + config[CC_id]->rf_config.ul_channel_bandwidth.value = 106; + config[CC_id]->rf_config.tx_antenna_ports.value = 1; + config[CC_id]->rf_config.rx_antenna_ports.value = 1; + config[CC_id]->sch_config.physical_cell_id.value = 0; + ///dl frequency to be filled in + +/* //Set some default values that may be overwritten while reading options + frame_parms[CC_id]->frame_type = FDD; + frame_parms[CC_id]->tdd_config = 3; + frame_parms[CC_id]->tdd_config_S = 0; + frame_parms[CC_id]->N_RB_DL = 100; + frame_parms[CC_id]->N_RB_UL = 100; + frame_parms[CC_id]->Ncp = NORMAL; + frame_parms[CC_id]->Ncp_UL = NORMAL; + frame_parms[CC_id]->Nid_cell = 0; + frame_parms[CC_id]->num_MBSFN_config = 0; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; + frame_parms[CC_id]->nb_antennas_tx = 1; + frame_parms[CC_id]->nb_antennas_rx = 1; + + frame_parms[CC_id]->nushift = 0; + + frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth; + frame_parms[CC_id]->phich_config_common.phich_duration = normal; + // UL RS Config + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 0;//n_DMRS1 set to 0 + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0; + + frame_parms[CC_id]->prach_config_common.rootSequenceIndex=22; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0; + +// downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31. +// downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0]; +// downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0]; +// downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0]; + //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]); + frame_parms[CC_id]->dl_CarrierFreq=downlink_frequency[CC_id][0]; +*/ + } + +} + + +void init_openair0(void) { + + int card; + int i; + + for (card=0; card<MAX_CARDS; card++) { + + openair0_cfg[card].mmapped_dma=mmapped_dma; + openair0_cfg[card].configFilename = NULL; + + if(config[0]->rf_config.dl_channel_bandwidth.value == 100) { + if (frame_parms[0]->threequarter_fs) { + openair0_cfg[card].sample_rate=23.04e6; + openair0_cfg[card].samples_per_frame = 230400; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } else { + openair0_cfg[card].sample_rate=30.72e6; + openair0_cfg[card].samples_per_frame = 307200; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } + } else if(config[0]->rf_config.dl_channel_bandwidth.value == 50) { + openair0_cfg[card].sample_rate=15.36e6; + openair0_cfg[card].samples_per_frame = 153600; + openair0_cfg[card].tx_bw = 5e6; + openair0_cfg[card].rx_bw = 5e6; + } else if (config[0]->rf_config.dl_channel_bandwidth.value == 25) { + openair0_cfg[card].sample_rate=7.68e6; + openair0_cfg[card].samples_per_frame = 76800; + openair0_cfg[card].tx_bw = 2.5e6; + openair0_cfg[card].rx_bw = 2.5e6; + } else if (config[0]->rf_config.dl_channel_bandwidth.value == 6) { + openair0_cfg[card].sample_rate=1.92e6; + openair0_cfg[card].samples_per_frame = 19200; + openair0_cfg[card].tx_bw = 1.5e6; + openair0_cfg[card].rx_bw = 1.5e6; + } + + + if (config[0]->subframe_config.duplex_mode.value==TDD) + openair0_cfg[card].duplex_mode = duplex_mode_TDD; + else //FDD + openair0_cfg[card].duplex_mode = duplex_mode_FDD; + + printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card, + RC.eNB[0][0]->frame_parms.nb_antennas_tx , + RC.eNB[0][0]->frame_parms.nb_antennas_rx ); + openair0_cfg[card].Mod_id = 0; + + openair0_cfg[card].num_rb_dl=config[0]->rf_config.dl_channel_bandwidth.value; + + openair0_cfg[card].clock_source = clock_source; + + + openair0_cfg[card].tx_num_channels=min(2,RC.eNB[0][0]->frame_parms.nb_antennas_tx ); + openair0_cfg[card].rx_num_channels=min(2,RC.eNB[0][0]->frame_parms.nb_antennas_rx ); + + for (i=0; i<4; i++) { + + if (i<openair0_cfg[card].tx_num_channels) + openair0_cfg[card].tx_freq[i] = downlink_frequency[0][i] ; + else + openair0_cfg[card].tx_freq[i]=0.0; + + if (i<openair0_cfg[card].rx_num_channels) + openair0_cfg[card].rx_freq[i] =downlink_frequency[0][i] + uplink_frequency_offset[0][i] ; + else + openair0_cfg[card].rx_freq[i]=0.0; + + openair0_cfg[card].autocal[i] = 1; + openair0_cfg[card].tx_gain[i] = tx_gain[0][i]; + openair0_cfg[card].rx_gain[i] = RC.eNB[0][0]->rx_total_gain_dB; + + + openair0_cfg[card].configFilename = rf_config_file; + printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", + card,i, openair0_cfg[card].tx_gain[i], + openair0_cfg[card].rx_gain[i], + openair0_cfg[card].tx_freq[i], + openair0_cfg[card].rx_freq[i]); + } + } /* for loop on cards */ +} + + +void wait_RUs(void) { + + LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask); + + // wait for all RUs to be configured over fronthaul + pthread_mutex_lock(&RC.ru_mutex); + while (RC.ru_mask>0) { + pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex); + printf("RC.ru_mask:%02lx\n", RC.ru_mask); + } + pthread_mutex_unlock(&RC.ru_mutex); + + LOG_I(PHY,"RUs configured\n"); +} + +void wait_gNBs(void) { + + int i,j; + int waiting=1; + + + while (waiting==1) { + printf("Waiting for gNB L1 instances to all get configured ... sleeping 50ms (nb_L1_inst %d)\n",RC.nb_L1_inst); + usleep(50*1000); + waiting=0; + for (i=0;i<RC.nb_L1_inst;i++) { + + printf("RC.nb_L1_CC[%d]:%d\n", i, RC.nb_L1_CC[i]); + + for (j=0;j<RC.nb_L1_CC[i];j++) { + if (RC.eNB[i][j]->configured==0) { ///gNB + waiting=1; + break; + } + } + } + } + printf("gNB L1 are configured\n"); +} + +#if defined(ENABLE_ITTI) +/* + * helper function to terminate a certain ITTI task + */ +void terminate_task(task_id_t task_id, module_id_t mod_id) +{ + LOG_I(ENB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id); + MessageDef *msg; + msg = itti_alloc_new_message (ENB_APP, TERMINATE_MESSAGE); + itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); +} + +//extern void free_transport(PHY_VARS_gNB *); +extern void phy_free_RU(RU_t*); + +int stop_L1L2(module_id_t gnb_id) +{ + LOG_W(ENB_APP, "stopping lte-softmodem\n"); + oai_exit = 1; + + if (!RC.ru) { + LOG_F(ENB_APP, "no RU configured\n"); + return -1; + } + + /* stop trx devices, multiple carrier currently not supported by RU */ + if (RC.ru[gnb_id]) { + if (RC.ru[gnb_id]->rfdevice.trx_stop_func) { + RC.ru[gnb_id]->rfdevice.trx_stop_func(&RC.ru[gnb_id]->rfdevice); + LOG_I(ENB_APP, "turned off RU rfdevice\n"); + } else { + LOG_W(ENB_APP, "can not turn off rfdevice due to missing trx_stop_func callback, proceding anyway!\n"); + } + if (RC.ru[gnb_id]->ifdevice.trx_stop_func) { + RC.ru[gnb_id]->ifdevice.trx_stop_func(&RC.ru[gnb_id]->ifdevice); + LOG_I(ENB_APP, "turned off RU ifdevice\n"); + } else { + LOG_W(ENB_APP, "can not turn off ifdevice due to missing trx_stop_func callback, proceding anyway!\n"); + } + } else { + LOG_W(ENB_APP, "no RU found for index %d\n", gnb_id); + return -1; + } + + /* these tasks need to pick up new configuration */ + terminate_task(TASK_RRC_ENB, gnb_id); + terminate_task(TASK_L2L1, gnb_id); + LOG_I(ENB_APP, "calling kill_eNB_proc() for instance %d\n", gnb_id); + kill_gNB_proc(gnb_id); + LOG_I(ENB_APP, "calling kill_RU_proc() for instance %d\n", gnb_id); + kill_RU_proc(gnb_id); + oai_exit = 0; + for (int cc_id = 0; cc_id < RC.nb_CC[gnb_id]; cc_id++) { + //free_transport(RC.eNB[gnb_id][cc_id]); + phy_free_nr_gNB(RC.gNB[gnb_id][cc_id]); + } + phy_free_RU(RC.ru[gnb_id]); + free_lte_top(); + return 0; +} + +/* + * Restart the lte-softmodem after it has been soft-stopped with stop_L1L2() + */ +int restart_L1L2(module_id_t gnb_id) +{ + RU_t *ru = RC.ru[gnb_id]; + int cc_id; + MessageDef *msg_p = NULL; + + LOG_W(ENB_APP, "restarting lte-softmodem\n"); + + /* block threads */ + sync_var = -1; + + for (cc_id = 0; cc_id < RC.nb_L1_CC[gnb_id]; cc_id++) { + RC.gNB[gnb_id][cc_id]->configured = 0; + } + + RC.ru_mask |= (1 << ru->idx); + /* copy the changed frame parameters to the RU */ + /* TODO this should be done for all RUs associated to this eNB */ + memcpy(&ru->frame_parms, &RC.gNB[gnb_id][0]->frame_parms, sizeof(NR_DL_FRAME_PARMS)); + set_function_spec_param(RC.ru[gnb_id]); + + LOG_I(ENB_APP, "attempting to create ITTI tasks\n"); + if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) { + LOG_E(RRC, "Create task for RRC eNB failed\n"); + return -1; + } else { + LOG_I(RRC, "Re-created task for RRC eNB successfully\n"); + } + if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { + LOG_E(PDCP, "Create task for L2L1 failed\n"); + return -1; + } else { + LOG_I(PDCP, "Re-created task for L2L1 successfully\n"); + } + + /* pass a reconfiguration request which will configure everything down to + * RC.eNB[i][j]->frame_parms, too */ + msg_p = itti_alloc_new_message(TASK_ENB_APP, RRC_CONFIGURATION_REQ); + RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[gnb_id]->configuration; + itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(gnb_id), msg_p); + /* TODO XForms might need to be restarted, but it is currently (09/02/18) + * broken, so we cannot test it */ + + wait_eNBs(); + init_RU_proc(ru); + ru->rf_map.card = 0; + ru->rf_map.chain = 0; /* CC_id + chain_offset;*/ + wait_RUs(); + init_eNB_afterRU(); + + printf("Sending sync to all threads\n"); + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + + return 0; +} +#endif + +static void wait_nfapi_init(char *thread_name) { + + printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name); + pthread_mutex_lock( &nfapi_sync_mutex ); + + while (nfapi_sync_var<0) + pthread_cond_wait( &nfapi_sync_cond, &nfapi_sync_mutex ); + + pthread_mutex_unlock(&nfapi_sync_mutex); + + printf( "NFAPI: got sync (%s)\n", thread_name); } int main( int argc, char **argv ) { - nfapi_config_request_t config; - NR_DL_FRAME_PARMS* frame_parms = malloc(sizeof(NR_DL_FRAME_PARMS)); - int16_t amp; - //malloc to move - int16_t** txdataF = (int16_t **)malloc(2048*2*14*2*2* sizeof(int16_t)); - int16_t* d_pss = malloc(NR_PSS_LENGTH * sizeof(int16_t)); - int16_t *d_sss = malloc(NR_SSS_LENGTH * sizeof(int16_t)); + int i; +#if defined (XFORMS) + void *status; +#endif - //logInit(); + int CC_id; + int ru_id; +#if defined (XFORMS) + int ret; +#endif - phy_init_nr_gNB(&config); - nr_init_frame_parms(config, frame_parms); - nr_dump_frame_parms(frame_parms); + start_background_system(); + ///static configuration for NR at the moment + if ( load_configmodule(argc,argv) == NULL) { + exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); + } + +#ifdef DEBUG_CONSOLE + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif - amp = 32767; //1_Q_15 - //nr_generate_pss(d_pss, txdataF, amp, 0, 0, config, frame_parms); - nr_generate_sss(d_sss, txdataF, amp, 0, 0, config, frame_parms); + mode = normal_txrx; + memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS); - free(txdataF); - free(d_pss); - free(d_sss); + memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs); + + set_latency_target(); + + logInit(); + + printf("Reading in command-line options\n"); + + get_options (); + if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) { + fprintf(stderr,"Getting configuration failed\n"); + exit(-1); + } + + +#if T_TRACER + T_init(T_port, 1-T_nowait, T_dont_fork); +#endif + + + + //randominit (0); + set_taus_seed (0); + + printf("configuring for RAU/RRU\n"); + + + if (ouput_vcd) { + VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_eNB.vcd"); + } + + if (opp_enabled ==1) { + reset_opp_meas(); + } + cpuf=get_cpu_freq_GHz(); + +#if defined(ENABLE_ITTI) + log_set_instance_type (LOG_INSTANCE_ENB); + + printf("ITTI init\n"); + itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file); + + // initialize mscgen log after ITTI + MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); +#endif + + if (opt_type != OPT_NONE) { + radio_type_t radio_type; + + if (config[0]->subframe_config.duplex_mode.value == FDD) + radio_type = RADIO_TYPE_FDD; + else + radio_type = RADIO_TYPE_TDD; + + if (init_opt(in_path, in_ip, NULL, radio_type) == -1) + LOG_E(OPT,"failed to run OPT \n"); + } + +#ifdef PDCP_USE_NETLINK + printf("PDCP netlink\n"); + netlink_init(); +#if defined(PDCP_USE_NETLINK_QUEUES) + pdcp_netlink_init(); +#endif +#endif + +#if !defined(ENABLE_ITTI) + // to make a graceful exit when ctrl-c is pressed + signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); +#endif + + + check_clock(); + +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" +#endif + + LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); + + + + + printf("Before CC \n"); + + printf("Runtime table\n"); + fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx); + + +#ifndef DEADLINE_SCHEDULER + + printf("NO deadline scheduler\n"); + /* Currently we set affinity for UHD to CPU 0 for eNB/UE and only if number of CPUS >2 */ + + cpu_set_t cpuset; + int s; + char cpu_affinity[1024]; + CPU_ZERO(&cpuset); +#ifdef CPU_AFFINITY + if (get_nprocs() > 2) { + CPU_SET(0, &cpuset); + s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_setaffinity_np"); + exit_fun("Error setting processor affinity"); + } + LOG_I(HW, "Setting the affinity of main function to CPU 0, for device library to use CPU 0 only!\n"); + } +#endif + + /* Check the actual affinity mask assigned to the thread */ + s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_getaffinity_np"); + exit_fun("Error getting processor affinity "); + } + memset(cpu_affinity, 0 , sizeof(cpu_affinity)); + for (int j = 0; j < CPU_SETSIZE; j++) { + if (CPU_ISSET(j, &cpuset)) { + char temp[1024]; + sprintf(temp, " CPU_%d ", j); + strcat(cpu_affinity, temp); + } + } + LOG_I(HW, "CPU Affinity of main() function is... %s\n", cpu_affinity); +#endif + + + + +#if defined(ENABLE_ITTI) + if (RC.nb_inst > 0) { + + // don't create if node doesn't connect to RRC/S1/GTP + if (create_tasks(1) < 0) { + printf("cannot create ITTI tasks\n"); + exit(-1); // need a softer mode + } + printf("ITTI tasks created\n"); + } + else { + printf("No ITTI, Initializing L1\n"); + RCconfig_L1(); + } +#endif + + /* Start the agent. If it is turned off in the configuration, it won't start */ + RCconfig_flexran(); + for (i = 0; i < RC.nb_L1_inst; i++) { + flexran_agent_start(i); + } + + // init UE_PF_PO and mutex lock + pthread_mutex_init(&ue_pf_po_mutex, NULL); + memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs); + + mlockall(MCL_CURRENT | MCL_FUTURE); + + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); + +#ifdef XFORMS +/* + int UE_id; + + printf("XFORMS\n"); + + if (do_forms==1) { + fl_initialize (&argc, argv, NULL, 0, 0); + + form_stats_l2 = create_form_stats_form(); + fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats"); + form_stats = create_form_stats_form(); + fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); + + for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + form_enb[CC_id][UE_id] = create_lte_phy_scope_enb(); + sprintf (title, "LTE UL SCOPE eNB for CC_id %d, UE %d",CC_id,UE_id); + fl_show_form (form_enb[CC_id][UE_id]->lte_phy_scope_enb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); + + if (otg_enabled) { + fl_set_button(form_enb[CC_id][UE_id]->button_0,1); + fl_set_object_label(form_enb[CC_id][UE_id]->button_0,"DL Traffic ON"); + } else { + fl_set_button(form_enb[CC_id][UE_id]->button_0,0); + fl_set_object_label(form_enb[CC_id][UE_id]->button_0,"DL Traffic OFF"); + } + } // CC_id + } // UE_id + + ret = pthread_create(&forms_thread, NULL, scope_thread, NULL); + + if (ret == 0) + pthread_setname_np( forms_thread, "xforms" ); + + printf("Scope thread created, ret=%d\n",ret); + } +*/ +#endif + + rt_sleep_ns(10*100000000ULL); + + if (nfapi_mode) { + + printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n"); + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); + } + + const char *nfapi_mode_str = "<UNKNOWN>"; + + switch(nfapi_mode) { + case 0: + nfapi_mode_str = "MONOLITHIC"; + break; + case 1: + nfapi_mode_str = "PNF"; + break; + case 2: + nfapi_mode_str = "VNF"; + break; + default: + nfapi_mode_str = "<UNKNOWN NFAPI MODE>"; + break; + } + printf("NFAPI MODE:%s\n", nfapi_mode_str); + + if (nfapi_mode==2) // VNF + wait_nfapi_init("main?"); + + printf("START MAIN THREADS\n"); + + // start the main threads + + number_of_cards = 1; + printf("RC.nb_L1_inst:%d\n", RC.nb_L1_inst); + if (RC.nb_L1_inst > 0) { + printf("Initializing gNB threads single_thread_flag:%d wait_for_sync:%d\n", single_thread_flag,wait_for_sync); + init_eNB(single_thread_flag,wait_for_sync); + } + + printf("wait_gNBs()\n"); + wait_eNBs(); + + printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); + if (RC.nb_RU >0) { + printf("Initializing RU threads\n"); + init_RU(rf_config_file); + for (ru_id=0;ru_id<RC.nb_RU;ru_id++) { + RC.ru[ru_id]->rf_map.card=0; + RC.ru[ru_id]->rf_map.chain=CC_id+chain_offset; + } + } + + config_sync_var=0; + + if (nfapi_mode==1) { // PNF + wait_nfapi_init("main?"); + } + + printf("wait RUs\n"); + wait_RUs(); + printf("ALL RUs READY!\n"); + printf("RC.nb_RU:%d\n", RC.nb_RU); + // once all RUs are ready initialize the rest of the gNBs ((dependence on final RU parameters after configuration) + printf("ALL RUs ready - init eNBs\n"); + + if (nfapi_mode != 1 && nfapi_mode != 2) + { + printf("Not NFAPI mode - call init_eNB_afterRU()\n"); + init_eNB_afterRU(); + } + else + { + printf("NFAPI mode - DO NOT call init_eNB_afterRU()\n"); + } + + printf("ALL RUs ready - ALL eNBs ready\n"); + + + // connect the TX/RX buffers + + + printf("Sending sync to all threads\n"); + + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + printf("About to call end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); + end_configmodule(); + printf("Called end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); + + // wait for end of program + printf("TYPE <CTRL-C> TO TERMINATE\n"); + //getchar(); + +#if defined(ENABLE_ITTI) + printf("Entering ITTI signals handler\n"); + itti_wait_tasks_end(); + printf("Returned from ITTI signal handler\n"); + oai_exit=1; + printf("oai_exit=%d\n",oai_exit); +#else + + while (oai_exit==0) + rt_sleep_ns(100000000ULL); + printf("Terminating application - oai_exit=%d\n",oai_exit); + +#endif + + // stop threads +#ifdef XFORMS +/* + printf("waiting for XFORMS thread\n"); + + if (do_forms==1) { + pthread_join(forms_thread,&status); + fl_hide_form(form_stats->stats_form); + fl_free_form(form_stats->stats_form); + + fl_hide_form(form_stats_l2->stats_form); + fl_free_form(form_stats_l2->stats_form); + + for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + fl_hide_form(form_enb[CC_id][UE_id]->lte_phy_scope_enb); + fl_free_form(form_enb[CC_id][UE_id]->lte_phy_scope_enb); + } + } + } +*/ +#endif + + printf("stopping MODEM threads\n"); + + // cleanup + stop_gNB(NB_gNB_INST); + stop_RU(NB_RU); + /* release memory used by the RU/gNB threads (incomplete), after all + * threads have been stopped (they partially use the same memory) */ + for (int inst = 0; inst < NB_gNB_INST; inst++) { + for (int cc_id = 0; cc_id < RC.nb_CC[inst]; cc_id++) { + free_transport(RC.gNB[inst][cc_id]); + phy_free_nr_gNB(RC.gNB[inst][cc_id]); + } + } + for (int inst = 0; inst < NB_RU; inst++) { + phy_free_RU(RC.ru[inst]); + } + free_lte_top(); + + + pthread_cond_destroy(&sync_cond); + pthread_mutex_destroy(&sync_mutex); + + pthread_cond_destroy(&nfapi_sync_cond); + pthread_mutex_destroy(&nfapi_sync_mutex); + + pthread_mutex_destroy(&ue_pf_po_mutex); + + // *** Handle per CC_id openair0 + + for(ru_id=0; ru_id<NB_RU; ru_id++) { + if (RC.ru[ru_id]->rfdevice.trx_end_func) + RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); + if (RC.ru[ru_id]->ifdevice.trx_end_func) + RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); + + } + if (ouput_vcd) + VCD_SIGNAL_DUMPER_CLOSE(); + + if (opt_enabled == 1) + terminate_opt(); + + logClean(); + printf("Bye.\n"); + return 0; } diff --git a/targets/RT/USER/nr-softmodem.h b/targets/RT/USER/nr-softmodem.h index 52ff1e1e3acd7a6839f326ca7a3b3508e8a3bd31..ce69697d536309a1383070487805be4ed06cd8de 100644 --- a/targets/RT/USER/nr-softmodem.h +++ b/targets/RT/USER/nr-softmodem.h @@ -1,4 +1,264 @@ -#ifndef LTE_SOFTMODEM_H -#define LTE_SOFTMODEM_H +#ifndef NR_SOFTMODEM_H +#define NR_SOFTMODEM_H + +#define _GNU_SOURCE +#include <execinfo.h> +#include <fcntl.h> +#include <getopt.h> +#include <linux/sched.h> +#include "rt_wrapper.h" +#include <sched.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syscall.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/sysinfo.h> +#include <sys/types.h> +#include <unistd.h> + +#include <sys/sysinfo.h> +#include "rt_wrapper.h" +#include "../../ARCH/COMMON/common_lib.h" +#undef MALLOC +#include "assertions.h" +#include "msc.h" +#include "PHY/types.h" + +#include "flexran_agent.h" + +#if defined(ENABLE_ITTI) +#if defined(ENABLE_USE_MME) +#include "s1ap_eNB.h" +#ifdef PDCP_USE_NETLINK +#include "SIMULATION/ETH_TRANSPORT/proto.h" +#endif +#endif +#endif + +/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ +#define CONFIG_HLP_RFCFGF "Configuration file for front-end (e.g. LMS7002M)\n" +#define CONFIG_HLP_ULMAXE "set the eNodeB max ULSCH erros\n" +#define CONFIG_HLP_CALUER "set UE RX calibration\n" +#define CONFIG_HLP_CALUERM "" +#define CONFIG_HLP_CALUERB "" +#define CONFIG_HLP_DBGUEPR "UE run normal prach power ramping, but don't continue random-access\n" +#define CONFIG_HLP_CALPRACH "UE run normal prach with maximum power, but don't continue random-access\n" +#define CONFIG_HLP_NOL2CN "bypass L2 and upper layers\n" +#define CONFIG_HLP_UERXG "set UE RX gain\n" +#define CONFIG_HLP_UERXGOFF "external UE amplifier offset\n" +#define CONFIG_HLP_UETXG "set UE TX gain\n" +#define CONFIG_HLP_UENANTR "set UE number of rx antennas\n" +#define CONFIG_HLP_UENANTT "set UE number of tx antennas\n" +#define CONFIG_HLP_UESCAN "set UE to scan around carrier\n" +#define CONFIG_HLP_DUMPFRAME "dump UE received frame to rxsig_frame0.dat and exit\n" +#define CONFIG_HLP_DLSHIFT "dynamic shift for LLR compuation for TM3/4 (default 0)\n" +#define CONFIG_HLP_UELOOP "get softmodem (UE) to loop through memory instead of acquiring from HW\n" +#define CONFIG_HLP_PHYTST "test UE phy layer, mac disabled\n" +#define CONFIG_HLP_DMAMAP "sets flag for improved EXMIMO UE performance\n" +#define CONFIG_HLP_EXCCLK "tells hardware to use an external clock reference\n" +#define CONFIG_HLP_USIM "use XOR autentication algo in case of test usim mode\n" +#define CONFIG_HLP_NOSNGLT "Disables single-thread mode in lte-softmodem\n" +#define CONFIG_HLP_TADV "Set timing_advance\n" +#define CONFIG_HLP_DLF "Set the downlink frequency for all component carriers\n" +#define CONFIG_HLP_CHOFF "Channel id offset\n" +#define CONFIG_HLP_SOFTS "Enable soft scope and L1 and L2 stats (Xforms)\n" +#define CONFIG_HLP_EXMCAL "Calibrate the EXMIMO borad, available files: exmimo2_2arxg.lime exmimo2_2brxg.lime \n" +#define CONFIG_HLP_ITTIL "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n" +#define CONFIG_HLP_DLMCS "Set the maximum downlink MCS\n" +#define CONFIG_HLP_STMON "Enable processing timing measurement of lte softmodem on per subframe basis \n" +#define CONFIG_HLP_PRB "Set the PRB, valid values: 6, 25, 50, 100 \n" +#define CONFIG_HLP_MSLOTS "Skip the missed slots/subframes \n" +#define CONFIG_HLP_ULMCS "Set the maximum uplink MCS\n" +#define CONFIG_HLP_TDD "Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n" +#define CONFIG_HLP_UE "Set the lte softmodem as a UE\n" +#define CONFIG_HLP_L2MONW "Enable L2 wireshark messages on localhost \n" +#define CONFIG_HLP_L2MONP "Enable L2 pcap messages on localhost \n" +#define CONFIG_HLP_VCD "Enable VCD (generated file will is named openair_dump_eNB.vcd, read it with target/RT/USER/eNB.gtkw\n" +#define CONFIG_HLP_TQFS "Apply three-quarter of sampling frequency, 23.04 Msps to reduce the data rate on USB/PCIe transfers (only valid for 20 MHz)\n" +#define CONFIG_HLP_TPORT "tracer port\n" +#define CONFIG_HLP_NOTWAIT "don't wait for tracer, start immediately\n" +#define CONFIG_HLP_TNOFORK "to ease debugging with gdb\n" +#define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n" + +/***************************************************************************************************************************************/ +/* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument + when calling config_get or config_getlist functions */ + + +/*------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters defining UE running mode */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CMDLINE_UEMODEPARAMS_DESC { \ +{"calib-ue-rx", CONFIG_HLP_CALUER, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \ +{"calib-ue-rx-med", CONFIG_HLP_CALUERM, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \ +{"calib-ue-rx-byp", CONFIG_HLP_CALUERB, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \ +{"debug-ue-prach", CONFIG_HLP_DBGUEPR, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ +{"no-L2-connect", CONFIG_HLP_NOL2CN, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ +{"calib-prach-tx", CONFIG_HLP_CALPRACH, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ +{"loop-memory", CONFIG_HLP_UELOOP, 0, strptr:&loopfile, defstrval:"iqs.in", TYPE_STRING,0}, \ +{"ue-dump-frame", CONFIG_HLP_DUMPFRAME, PARAMFLAG_BOOL, iptr:&dumpframe, defintval:0, TYPE_INT, 0}, \ +} +#define CMDLINE_CALIBUERX_IDX 0 +#define CMDLINE_CALIBUERXMED_IDX 1 +#define CMDLINE_CALIBUERXBYP_IDX 2 +#define CMDLINE_DEBUGUEPRACH_IDX 3 +#define CMDLINE_NOL2CONNECT_IDX 4 +#define CMDLINE_CALIBPRACHTX_IDX 5 +#define CMDLINE_MEMLOOP_IDX 6 +#define CMDLINE_DUMPMEMORY_IDX 7 +/*------------------------------------------------------------------------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters specific to UE */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*--------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CMDLINE_UEPARAMS_DESC { \ +{"ue-rxgain", CONFIG_HLP_UERXG, 0, dblptr:&(rx_gain[0][0]), defdblval:0, TYPE_DOUBLE, 0}, \ +{"ue-rxgain-off", CONFIG_HLP_UERXGOFF, 0, dblptr:&rx_gain_off, defdblval:0, TYPE_DOUBLE, 0}, \ +{"ue-txgain", CONFIG_HLP_UETXG, 0, dblptr:&(tx_gain[0][0]), defdblval:0, TYPE_DOUBLE, 0}, \ +{"ue-nb-ant-rx", CONFIG_HLP_UENANTR, 0, u8ptr:&nb_antenna_rx, defuintval:1, TYPE_UINT8, 0}, \ +{"ue-nb-ant-tx", CONFIG_HLP_UENANTT, 0, u8ptr:&nb_antenna_tx, defuintval:1, TYPE_UINT8, 0}, \ +{"ue-scan-carrier", CONFIG_HLP_UESCAN, PARAMFLAG_BOOL, iptr:&UE_scan_carrier, defintval:0, TYPE_INT, 0}, \ +{"ue-max-power", NULL, 0, iptr:&(tx_max_power[0]), defintval:90, TYPE_INT, 0}, \ +{"r" , CONFIG_HLP_PRB, 0, u8ptr:&(frame_parms[0]->N_RB_DL), defintval:25, TYPE_UINT8, 0}, \ +{"dlsch-demod-shift", CONFIG_HLP_DLSHIFT, 0, iptr:(int32_t *)&dlsch_demod_shift, defintval:0, TYPE_INT, 0}, \ +} + +#define DEFAULT_DLF 2680000000 + +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters common to eNodeB and UE */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CMDLINE_PARAMS_DESC { \ +{"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&rf_config_file, defstrval:NULL, TYPE_STRING, sizeof(rf_config_file)}, \ +{"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \ +{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&phy_test, defintval:0, TYPE_INT, 0}, \ +{"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&usim_test, defintval:0, TYPE_UINT8, 0}, \ +{"mmapped-dma", CONFIG_HLP_DMAMAP, PARAMFLAG_BOOL, uptr:&mmapped_dma, defintval:0, TYPE_INT, 0}, \ +{"external-clock", CONFIG_HLP_EXCCLK, PARAMFLAG_BOOL, uptr:&clock_source, defintval:0, TYPE_INT, 0}, \ +{"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&wait_for_sync, defintval:0, TYPE_INT, 0}, \ +{"single-thread-disable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&single_thread_flag, defintval:1, TYPE_INT, 0}, \ +{"threadIQ", NULL, 0, iptr:&(threads.iq), defintval:1, TYPE_INT, 0}, \ +{"threadOneSubframe", NULL, 0, iptr:&(threads.one), defintval:1, TYPE_INT, 0}, \ +{"threadTwoSubframe", NULL, 0, iptr:&(threads.two), defintval:1, TYPE_INT, 0}, \ +{"threadThreeSubframe", NULL, 0, iptr:&(threads.three), defintval:1, TYPE_INT, 0}, \ +{"threadSlot1ProcOne", NULL, 0, iptr:&(threads.slot1_proc_one), defintval:1, TYPE_INT, 0}, \ +{"threadSlot1ProcTwo", NULL, 0, iptr:&(threads.slot1_proc_two), defintval:1, TYPE_INT, 0}, \ +{"A" , CONFIG_HLP_TADV, 0, uptr:&timing_advance, defintval:0, TYPE_UINT, 0}, \ +{"C" , CONFIG_HLP_DLF, 0, uptr:&(downlink_frequency[0][0]), defuintval:DEFAULT_DLF, TYPE_UINT, 0}, \ +{"a" , CONFIG_HLP_CHOFF, 0, iptr:&chain_offset, defintval:0, TYPE_INT, 0}, \ +{"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&do_forms, defintval:0, TYPE_INT8, 0}, \ +{"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, i8ptr:&threequarter_fs, defintval:0, TYPE_INT8, 0}, \ +{"K" , CONFIG_HLP_ITTIL, PARAMFLAG_NOFREE, strptr:&itti_dump_file, defstrval:"/tmp/itti.dump", TYPE_STRING, 0}, \ +{"m" , CONFIG_HLP_DLMCS, 0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \ +{"t" , CONFIG_HLP_ULMCS, 0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \ +{"W" , CONFIG_HLP_L2MONW, 0, strptr:(char **)&in_ip, defstrval:"127.0.0.1", TYPE_STRING, sizeof(in_ip)}, \ +{"P" , CONFIG_HLP_L2MONP, 0, strptr:(char **)&in_path, defstrval:"/tmp/oai_opt.pcap", TYPE_STRING, sizeof(in_path)}, \ +{"V" , CONFIG_HLP_VCD, PARAMFLAG_BOOL, iptr:&ouput_vcd, defintval:0, TYPE_INT, 0}, \ +{"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \ +{"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \ +{"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, \ +{"nbiot-disable", CONFIG_HLP_DISABLNBIOT,PARAMFLAG_BOOL, iptr:&nonbiotflag, defintval:0, TYPE_INT, 0} \ +} + +#define CONFIG_HLP_FLOG "Enable online log \n" +#define CONFIG_HLP_LOGL "Set the global log level, valide options: (9:trace, 8/7:debug, 6:info, 4:warn, 3:error)\n" +#define CONFIG_HLP_LOGV "Set the global log verbosity \n" +#define CONFIG_HLP_TELN "Start embedded telnet server \n" +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters for LOG utility */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CMDLINE_LOGPARAMS_DESC { \ +{"R" , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \ +{"g" , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \ +{"G" , CONFIG_HLP_LOGV, 0, uptr:&glog_verbosity, defintval:0, TYPE_UINT16, 0}, \ +{"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \ +} +#define CMDLINE_ONLINELOG_IDX 0 +#define CMDLINE_GLOGLEVEL_IDX 1 +#define CMDLINE_GLOGVERBO_IDX 2 +#define CMDLINE_STARTTELN_IDX 3 + + +extern int T_port; +extern int T_nowait; +extern int T_dont_fork; + +/*------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters for TTRACE utility */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CMDLINE_TTRACEPARAMS_DESC { \ +{"T_port", CONFIG_HLP_TPORT, 0, iptr:&T_port, defintval:0, TYPE_INT, 0}, \ +{"T_nowait", CONFIG_HLP_NOTWAIT, PARAMFLAG_BOOL, iptr:&T_nowait, defintval:0, TYPE_INT, 0}, \ +{"T_dont_fork", CONFIG_HLP_TNOFORK, PARAMFLAG_BOOL, iptr:&T_dont_fork, defintval:1, TYPE_INT, 0}, \ +} + + +/***************************************************************************************************************************************/ +/* */ +extern pthread_cond_t sync_cond; +extern pthread_mutex_t sync_mutex; +extern int sync_var; + + +extern uint32_t downlink_frequency[MAX_NUM_CCs][4]; +extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; + +extern int rx_input_level_dBm; +extern uint8_t exit_missed_slots; +extern uint64_t num_missed_slots; // counter for the number of missed slots + +extern int oaisim_flag; +extern volatile int oai_exit; + +extern openair0_config_t openair0_cfg[MAX_CARDS]; +extern pthread_cond_t sync_cond; +extern pthread_mutex_t sync_mutex; +extern int sync_var; +extern int transmission_mode; +extern double cpuf; + +#if defined(ENABLE_ITTI) +extern volatile int start_gNB; +#endif + +#include "threads_t.h" +extern threads_t threads; + +extern void exit_fun(const char* s); +// In nr-gnb.c +extern void init_gNB(int single_thread_flag,int wait_for_sync); +extern void stop_gNB(int); +extern void kill_gNB_proc(int inst); + +// In nr-ru.c +extern void init_RU(const char*); +extern void init_RU_proc(RU_t *ru); +extern void stop_RU(int nb_ru); +extern void kill_RU_proc(int inst); +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 *, pthread_attr_t *); +extern void init_td_thread(PHY_VARS_gNB *, pthread_attr_t *); +extern void init_te_thread(PHY_VARS_gNB *, pthread_attr_t *); + +void init_gNB_afterRU(void); + +extern int stop_L1L2(module_id_t gnb_id); +extern int restart_L1L2(module_id_t gnb_id); #endif + diff --git a/targets/RT/USER/nr-ue.c b/targets/RT/USER/nr-ue.c new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391