diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 5fc5add8c539a0b4e029763a82f96f178e59c2b8..22bf239259e9dee2f6d0dad8fff6664a53e69ff2 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -989,6 +989,7 @@ add_library(SCHED_LIB ${SCHED_SRC}) set(SCHED_NR_SRC ${OPENAIR1_DIR}/SCHED_NR/phy_procedures_nr_common.c ${OPENAIR1_DIR}/SCHED_NR/phy_procedures_nr_gNB.c + ${OPENAIR1_DIR}/SCHED_NR/nr_ru_procedures.c ) add_library(SCHED_NR_LIB ${SCHED_NR_SRC}) diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h index a5d48e3e3971ff6a47680b022f6a15b5346f16ff..28184d741a58f5d25e92662b4f6da15698a9983b 100644 --- a/openair1/PHY/defs.h +++ b/openair1/PHY/defs.h @@ -798,10 +798,10 @@ typedef struct RU_t_s{ void (*feptx_prec)(struct RU_t_s *ru); /// function pointer to wakeup routine in lte-enb/nr-gnb. int (*wakeup_rxtx)(struct PHY_VARS_eNB_s *eNB, struct RU_t_s *ru); - int (*nr_wakeup_rxtx)(struct PHY_VARS_gNB_s *eNB, struct RU_t_s *ru); + int (*nr_wakeup_rxtx)(struct PHY_VARS_gNB_s *gNB, struct RU_t_s *ru); /// function pointer to wakeup routine in lte-enb/nr-gnb. void (*wakeup_prach_eNB)(struct PHY_VARS_eNB_s *eNB,struct RU_t_s *ru,int frame,int subframe); - void (*wakeup_prach_gNB)(struct PHY_VARS_gNB_s *eNB,struct RU_t_s *ru,int frame,int subframe); + void (*wakeup_prach_gNB)(struct PHY_VARS_gNB_s *gNB,struct RU_t_s *ru,int frame,int subframe); #ifdef Rel14 /// function pointer to wakeup routine in lte-enb. void (*wakeup_prach_eNB_br)(struct PHY_VARS_eNB_s *eNB,struct RU_t_s *ru,int frame,int subframe); diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c new file mode 100644 index 0000000000000000000000000000000000000000..e6269989678a6f8fa0ec655401b5bb820dae8b92 --- /dev/null +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -0,0 +1,328 @@ +/* + * 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 ru_procedures.c + * \brief Implementation of RU procedures + * \author R. Knopp, F. Kaltenberger, N. Nikaein, X. Foukas + * \date 2011 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr, x.foukas@sms.ed.ac.uk + * \note + * \warning + */ + +#include "PHY/defs.h" +#include "PHY/extern.h" +#include "SCHED/defs.h" +#include "SCHED/extern.h" + +#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/LTE_TRANSPORT/if5_tools.h" + +#include "LAYER2/MAC/extern.h" +#include "LAYER2/MAC/defs.h" +#include "UTIL/LOG/log.h" +#include "UTIL/LOG/vcd_signal_dumper.h" + +#include "T.h" + +#include "assertions.h" +#include "msc.h" + +#include <time.h> + +#include "targets/RT/USER/rt_wrapper.h" + +// RU OFDM Modulator gNodeB + +extern openair0_config_t openair0_cfg[MAX_CARDS]; + +extern int oai_exit; + +void nr_feptx0(RU_t *ru,int slot) { + + NR_DL_FRAME_PARMS *fp = &ru->nr_frame_parms; + nfapi_config_request_t *cfg = &ru->gNB_list[0]->gNB_config; + + unsigned int aa,slot_offset; + int i, tx_offset; + int slot_sizeF = (fp->ofdm_symbol_size)* + ((cfg->subframe_config.dl_cyclic_prefix_type.value == 1) ? 12 : 14); + int subframe = ru->proc.subframe_tx; + + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+slot , 1 ); + + slot_offset = subframe*fp->samples_per_subframe + (slot*(fp->samples_per_subframe / fp->slots_per_subframe)); + + LOG_I(PHY,"SFN/SF:RU:TX:%d/%d Generating slot %d\n",ru->proc.frame_tx, ru->proc.subframe_tx,slot); + + for (aa=0; aa<ru->nb_tx; aa++) { + if (cfg->subframe_config.dl_cyclic_prefix_type.value == 1) PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot*slot_sizeF], + (int*)&ru->common.txdata[aa][slot_offset], + fp->ofdm_symbol_size, + 12, + fp->nb_prefix_samples, + CYCLIC_PREFIX); + else normal_prefix_mod(&ru->common.txdataF_BF[aa][slot*slot_sizeF], + (int*)&ru->common.txdata[aa][slot_offset], + 14, + fp); + + /* + len = fp->samples_per_subframe / fp->slots_per_subframe; + + + if ((slot_offset+len)>(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_subframe)) { + tx_offset = (int)slot_offset; + txdata = (int16_t*)&ru->common.txdata[aa][tx_offset]; + len2 = -tx_offset+LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_tti; + for (i=0; i<(len2<<1); i++) { + txdata[i] = ((int16_t*)dummy_tx_b)[i]; + } + txdata = (int16_t*)&ru->common.txdata[aa][0]; + for (j=0; i<(len<<1); i++,j++) { + txdata[j++] = ((int16_t*)dummy_tx_b)[i]; + } + } + else { + tx_offset = (int)slot_offset; + txdata = (int16_t*)&ru->common.txdata[aa][tx_offset]; + memcpy((void*)txdata,(void*)dummy_tx_b,len<<2); + } +*/ + // TDD: turn on tx switch N_TA_offset before by setting buffer in these samples to 0 + /*if ((slot == 0) && + (fp->frame_type == TDD) && + ((fp->tdd_config==0) || + (fp->tdd_config==1) || + (fp->tdd_config==2) || + (fp->tdd_config==6)) && + ((subframe==0) || (subframe==5))) { + for (i=0; i<ru->N_TA_offset; i++) { + tx_offset = (int)slot_offset+i-ru->N_TA_offset/2; + if (tx_offset<0) + tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_tti; + + if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_tti)) + tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_tti; + + ru->common.txdata[aa][tx_offset] = 0x00000000; + } + }*/ + } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+slot , 0); +} + +void nr_feptx_ofdm_2thread(RU_t *ru) { + + NR_DL_FRAME_PARMS *fp=&ru->nr_frame_parms; + RU_proc_t *proc = &ru->proc; + struct timespec wait; + int subframe = ru->proc.subframe_tx; + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + start_meas(&ru->ofdm_mod_stats); + + if (nr_subframe_select(fp,subframe) == SF_UL) return; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 1 ); + + if (nr_subframe_select(fp,subframe)==SF_DL) { + // If this is not an S-subframe + if (pthread_mutex_timedlock(&proc->mutex_feptx,&wait) != 0) { + printf("[RU] ERROR pthread_mutex_lock for feptx thread (IC %d)\n", proc->instance_cnt_feptx); + exit_fun( "error locking mutex_feptx" ); + return; + } + + if (proc->instance_cnt_feptx==0) { + printf("[RU] FEPtx thread busy\n"); + exit_fun("FEPtx thread busy"); + pthread_mutex_unlock( &proc->mutex_feptx ); + return; + } + + ++proc->instance_cnt_feptx; + + + if (pthread_cond_signal(&proc->cond_feptx) != 0) { + printf("[RU] ERROR pthread_cond_signal for feptx thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return; + } + + pthread_mutex_unlock( &proc->mutex_feptx ); + } + + // call first slot in this thread + nr_feptx0(ru,0); + wait_on_busy_condition(&proc->mutex_feptx,&proc->cond_feptx,&proc->instance_cnt_feptx,"feptx thread"); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 0 ); + + stop_meas(&ru->ofdm_mod_stats); + +} + + +void nr_feptx_ofdm(RU_t *ru) { + + NR_DL_FRAME_PARMS *fp=&ru->nr_frame_parms; + nfapi_config_request_t *cfg = &ru->gNB_list[0]->gNB_config; + + unsigned int aa,slot_offset, slot_offset_F; + int dummy_tx_b[7680*4] __attribute__((aligned(32))); + int i,j, tx_offset; + int slot_sizeF = (fp->ofdm_symbol_size)* + ((cfg->subframe_config.dl_cyclic_prefix_type.value == 1) ? 12 : 14); + int len,len2; + int16_t *txdata; + int subframe = ru->proc.subframe_tx; + +// int CC_id = ru->proc.CC_id; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 1 ); + + slot_offset_F = 0; + + slot_offset = subframe*fp->samples_per_subframe; + + if ((nr_subframe_select(fp,subframe)==SF_DL)|| + ((nr_subframe_select(fp,subframe)==SF_S))) { + // LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot); + + start_meas(&ru->ofdm_mod_stats); + + for (aa=0; aa<ru->nb_tx; aa++) { + if (cfg->subframe_config.dl_cyclic_prefix_type.value == 1) { + PHY_ofdm_mod(&ru->common.txdataF_BF[aa][0], + dummy_tx_b, + fp->ofdm_symbol_size, + 12, + fp->nb_prefix_samples, + CYCLIC_PREFIX); + PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_sizeF], + dummy_tx_b+(fp->samples_per_subframe / fp->slots_per_subframe), + fp->ofdm_symbol_size, + 12, + fp->nb_prefix_samples, + CYCLIC_PREFIX); + } else { + normal_prefix_mod(&ru->common.txdataF_BF[aa][slot_offset_F], + dummy_tx_b, + 14, + fp); + // if S-subframe generate first slot only + if (subframe_select(fp,subframe) == SF_DL) + normal_prefix_mod(&ru->common.txdataF_BF[aa][slot_offset_F+slot_sizeF], + dummy_tx_b+(fp->samples_per_subframe / fp->slots_per_subframe), + 14, + fp); + } + + // if S-subframe generate first slot only + if (subframe_select(fp,subframe) == SF_S) + len = fp->samples_per_subframe / fp->slots_per_subframe; + else + len = fp->samples_per_subframe; + /* + for (i=0;i<len;i+=4) { + dummy_tx_b[i] = 0x100; + dummy_tx_b[i+1] = 0x01000000; + dummy_tx_b[i+2] = 0xff00; + dummy_tx_b[i+3] = 0xff000000; + }*/ + + if (slot_offset<0) { + txdata = (int16_t*)&ru->common.txdata[aa][(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_subframe)+tx_offset]; + len2 = -(slot_offset); + len2 = (len2>len) ? len : len2; + for (i=0; i<(len2<<1); i++) { + txdata[i] = ((int16_t*)dummy_tx_b)[i]; + } + if (len2<len) { + txdata = (int16_t*)&ru->common.txdata[aa][0]; + for (j=0; i<(len<<1); i++,j++) { + txdata[j++] = ((int16_t*)dummy_tx_b)[i]; + } + } + } + else if ((slot_offset+len)>(fp->samples_per_frame)) { + tx_offset = (int)slot_offset; + txdata = (int16_t*)&ru->common.txdata[aa][tx_offset]; + len2 = -tx_offset + fp->samples_per_frame; + for (i=0; i<(len2<<1); i++) { + txdata[i] = ((int16_t*)dummy_tx_b)[i]; + } + txdata = (int16_t*)&ru->common.txdata[aa][0]; + for (j=0; i<(len<<1); i++,j++) { + txdata[j++] = ((int16_t*)dummy_tx_b)[i]; + } + } + else { + //LOG_D(PHY,"feptx_ofdm: Writing to position %d\n",slot_offset); + tx_offset = (int)slot_offset; + txdata = (int16_t*)&ru->common.txdata[aa][tx_offset]; + + for (i=0; i<(len<<1); i++) { + txdata[i] = ((int16_t*)dummy_tx_b)[i]; + } + } + + // if S-subframe switch to RX in second subframe + /* + if (subframe_select(fp,subframe) == SF_S) { + for (i=0; i<len; i++) { + ru->common_vars.txdata[0][aa][tx_offset++] = 0x00010001; + } + } + */ + /*if ((fp->frame_type == TDD) && + ((fp->tdd_config==0) || + (fp->tdd_config==1) || + (fp->tdd_config==2) || + (fp->tdd_config==6)) && + ((subframe==0) || (subframe==5))) { + // turn on tx switch N_TA_offset before + //LOG_D(HW,"subframe %d, time to switch to tx (N_TA_offset %d, slot_offset %d) \n",subframe,ru->N_TA_offset,slot_offset); + for (i=0; i<ru->N_TA_offset; i++) { + tx_offset = (int)slot_offset+i-ru->N_TA_offset/2; + if (tx_offset<0) + tx_offset += fp->samples_per_frame; + + if (tx_offset>=(fp->samples_per_frame)) + tx_offset -= fp->samples_per_frame; + + ru->common.txdata[aa][tx_offset] = 0x00000000; + } + }*/ + stop_meas(&ru->ofdm_mod_stats); + LOG_D(PHY,"feptx_ofdm (TXPATH): frame %d, subframe %d: txp (time %p) %d dB, txp (freq) %d dB\n", + ru->proc.frame_tx,subframe,txdata,dB_fixed(signal_energy((int32_t*)txdata,fp->samples_per_subframe)), + dB_fixed(signal_energy_nodc(ru->common.txdataF_BF[aa],2*slot_sizeF))); + } + } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 0 ); +} diff --git a/targets/RT/USER/nr-ru.c b/targets/RT/USER/nr-ru.c index 1b5dc345266455a2ba5fa6245266ca0399cfae42..0686cc72e857c1f0ad2684ed050b17c247e2c59e 100644 --- a/targets/RT/USER/nr-ru.c +++ b/targets/RT/USER/nr-ru.c @@ -1587,8 +1587,8 @@ int stop_rf(RU_t *ru) 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 nr_feptx_ofdm(RU_t *ru); +extern void nr_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); @@ -1976,7 +1976,7 @@ void set_function_spec_param(RU_t *ru) 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_ofdm = (get_nprocs()<=2) ? nr_feptx_ofdm : nr_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; @@ -1998,7 +1998,7 @@ void set_function_spec_param(RU_t *ru) else if (ru->function == gNodeB_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_ofdm = (get_nprocs()<=2) ? nr_feptx_ofdm : nr_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 @@ -2028,7 +2028,7 @@ void set_function_spec_param(RU_t *ru) 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 + ru->feptx_ofdm = (get_nprocs()<=2) ? nr_feptx_ofdm : nr_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