/* * 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_gNB.h" #include "sched_nr.h" #include "PHY/MODULATION/modulation_common.h" #include "PHY/MODULATION/nr_modulation.h" #include "common/utils/LOG/log.h" #include "common/utils/system.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "T.h" #include "assertions.h" #include <time.h> // RU OFDM Modulator gNodeB extern int oai_exit; // OFDM modulation core routine, generates a first_symbol to first_symbol+num_symbols on a particular slot and TX antenna port void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) { NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; unsigned int slot_offset,slot_offsetF; int slot = tti_tx; //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+(first_symbol!=0?1:0) , 1 ); if (aa==0 && first_symbol == 0) start_meas(&ru->ofdm_mod_stats); slot_offset = fp->get_samples_slot_timestamp(slot,fp,0); slot_offsetF = first_symbol*fp->ofdm_symbol_size; int abs_first_symbol = slot*fp->symbols_per_slot; for (uint16_t idx_sym=abs_first_symbol; idx_sym<abs_first_symbol+first_symbol; idx_sym++) slot_offset += (idx_sym%(0x7<<fp->numerology_index)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0; slot_offset += fp->ofdm_symbol_size*first_symbol; LOG_D(PHY,"SFN/SF:RU:TX:%d/%d aa %d Generating slot %d (first_symbol %d num_symbols %d) slot_offset %d, slot_offsetF %d\n",ru->proc.frame_tx, ru->proc.tti_tx,aa,slot,first_symbol,num_symbols,slot_offset,slot_offsetF); if (fp->Ncp == 1) { PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], (int*)&ru->common.txdata[aa][slot_offset], fp->ofdm_symbol_size, num_symbols, fp->nb_prefix_samples, CYCLIC_PREFIX); } else { if (fp->numerology_index != 0) { if (!(slot%(fp->slots_per_subframe/2))&&(first_symbol==0)) { // case where first symbol in slot has longer prefix PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], (int*)&ru->common.txdata[aa][slot_offset], fp->ofdm_symbol_size, 1, fp->nb_prefix_samples0, CYCLIC_PREFIX); PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF+fp->ofdm_symbol_size], (int*)&ru->common.txdata[aa][slot_offset+fp->nb_prefix_samples0+fp->ofdm_symbol_size], fp->ofdm_symbol_size, num_symbols-1, fp->nb_prefix_samples, CYCLIC_PREFIX); } else { // all symbols in slot have shorter prefix PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], (int*)&ru->common.txdata[aa][slot_offset], fp->ofdm_symbol_size, num_symbols, fp->nb_prefix_samples, CYCLIC_PREFIX); } } // numerology_index!=0 else { //numerology_index == 0 for (uint16_t idx_sym=abs_first_symbol; idx_sym<abs_first_symbol+num_symbols; idx_sym++) { if (idx_sym%0x7) { PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], (int*)&ru->common.txdata[aa][slot_offset], fp->ofdm_symbol_size, 1, fp->nb_prefix_samples, CYCLIC_PREFIX); slot_offset += fp->nb_prefix_samples+fp->ofdm_symbol_size; slot_offsetF += fp->ofdm_symbol_size; } else { PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF], (int*)&ru->common.txdata[aa][slot_offset], fp->ofdm_symbol_size, 1, fp->nb_prefix_samples0, CYCLIC_PREFIX); slot_offset += fp->nb_prefix_samples0+fp->ofdm_symbol_size; slot_offsetF += fp->ofdm_symbol_size; } } // for(idx_symbol.. } // numerology 0 } if (aa==0 && first_symbol==0) stop_meas(&ru->ofdm_mod_stats); //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+(first_symbol!=0?1:0), 0); } // RU FEP TX OFDM modulation, single-thread void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) { nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config; NR_DL_FRAME_PARMS *fp=ru->nr_frame_parms; int cyclic_prefix_type = NFAPI_CP_NORMAL; unsigned int aa=0; int slot_sizeF = (fp->ofdm_symbol_size)* ((cyclic_prefix_type == 1) ? 12 : 14); int slot = tti_tx; int *txdata = &ru->common.txdata[aa][fp->get_samples_slot_timestamp(slot,fp,0)]; if (nr_slot_select(cfg,frame_tx,slot) == NR_UPLINK_SLOT) return; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 1 ); // LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot); nr_feptx0(ru,slot,0,NR_NUMBER_OF_SYMBOLS_PER_SLOT,aa); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 0 ); LOG_D(PHY,"feptx_ofdm (TXPATH): frame %d, slot %d: txp (time %p) %d dB, txp (freq) %d dB\n", frame_tx,slot,txdata,dB_fixed(signal_energy((int32_t*)txdata,fp->get_samples_per_slot( slot,fp))),dB_fixed(signal_energy_nodc(ru->common.txdataF_BF[aa],2*slot_sizeF))); } void nr_feptx_prec(RU_t *ru,int frame_tx,int tti_tx) { int l,aa; PHY_VARS_gNB **gNB_list = ru->gNB_list,*gNB; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config; int32_t ***bw; int i=0; int slot_tx = tti_tx; int txdataF_offset = (tti_tx*fp->samples_per_slot_wCP); start_meas(&ru->precoding_stats); AssertFatal(ru->nb_log_antennas > 0,"ru->nb_log_antennas is 0!\n"); if (ru->num_gNB == 1){ gNB = gNB_list[0]; if (nr_slot_select(cfg,frame_tx,slot_tx) == NR_UPLINK_SLOT) return; if (!ru->do_precoding || (ru->nb_tx == 1 && ru->nb_log_antennas == 1)) { for (i = 0; i < ru->nb_log_antennas; ++i) { //ru->common.txdataF_BF[i] = (int32_t *)&gNB->common_vars.txdataF[i][txdataF_offset]; memcpy(ru->common.txdataF_BF[i], &gNB->common_vars.txdataF[i][txdataF_offset], fp->samples_per_slot_wCP*sizeof(int32_t)); } } else { for(i=0; i<ru->nb_log_antennas; ++i) { memcpy((void*)ru->common.txdataF[i], (void*)&gNB->common_vars.txdataF[i][txdataF_offset], fp->samples_per_slot_wCP*sizeof(int32_t)); memcpy((void*)&ru->common.beam_id[i][slot_tx*fp->symbols_per_slot], (void*)&gNB->common_vars.beam_id[i][slot_tx*fp->symbols_per_slot], fp->symbols_per_slot*sizeof(uint8_t)); } bw = ru->beam_weights[0]; for (l=0;l<fp->symbols_per_slot;l++) { for (aa=0;aa<ru->nb_tx;aa++) { nr_beam_precoding((c16_t **)ru->common.txdataF, (c16_t **)ru->common.txdataF_BF, fp, bw, tti_tx, l, aa, ru->nb_log_antennas, 0); }// for (aa=0;aa<ru->nb_tx;aa++) }// for (l=0;l<fp->symbols_per_slot;l++) }// ru->do_precoding }// if (ru->num_gNB == 1) stop_meas(&ru->precoding_stats); } void nr_fep_full(RU_t *ru, int slot) { RU_proc_t *proc = &ru->proc; int l, aa; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; // if ((fp->frame_type == TDD) && // (subframe_select(fp,proc->tti_rx) != NR_UPLINK_SLOT)) return; LOG_D(PHY,"In fep_full for slot = %d\n", proc->tti_rx); start_meas(&ru->ofdm_demod_stats); if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); // remove_7_5_kHz(ru,proc->tti_rx<<1); // remove_7_5_kHz(ru,1+(proc->tti_rx<<1)); int offset = (proc->tti_rx % RU_RX_SLOT_DEPTH) * (fp->symbols_per_slot * fp->ofdm_symbol_size); for (l = 0; l < fp->symbols_per_slot; l++) { for (aa = 0; aa < fp->nb_antennas_rx; aa++) { nr_slot_fep_ul(fp, ru->common.rxdata[aa], &ru->common.rxdataF[aa][offset], l, proc->tti_rx, ru->N_TA_offset); } } if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 0 ); stop_meas(&ru->ofdm_demod_stats); } // core routine for FEP TX, called from threads in RU TX thread-pool void nr_feptx(void *arg) { feptx_cmd_t *feptx = (feptx_cmd_t *)arg; RU_t *ru = feptx->ru; int slot = feptx->slot; int aa = feptx->aid; int startSymbol = feptx->startSymbol; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; int numSymbols = feptx->numSymbols; int numSamples = feptx->numSymbols*fp->ofdm_symbol_size; int txdataF_offset = (slot*fp->samples_per_slot_wCP) + startSymbol*fp->ofdm_symbol_size; int txdataF_BF_offset = startSymbol*fp->ofdm_symbol_size; ////////////precoding//////////// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 1); if (aa==0) start_meas(&ru->precoding_stats); if (ru->do_precoding == 1) { for(int i=0; i<ru->nb_log_antennas; ++i) { memcpy((void*) &ru->common.beam_id[i][slot*fp->symbols_per_slot], (void*) &ru->gNB_list[0]->common_vars.beam_id[i][slot*fp->symbols_per_slot], (fp->symbols_per_slot)*sizeof(uint8_t)); } } if (ru->nb_tx == 1 && ru->nb_log_antennas == 1) { memcpy((void*)&ru->common.txdataF_BF[0][txdataF_BF_offset], (void*)&ru->gNB_list[0]->common_vars.txdataF[0][txdataF_offset], numSamples*sizeof(int32_t)); } else if (ru->do_precoding == 0) { int gNB_tx = ru->gNB_list[0]->frame_parms.nb_antennas_tx; memcpy((void*)&ru->common.txdataF_BF[aa][txdataF_BF_offset], (void*)&ru->gNB_list[0]->common_vars.txdataF[aa%gNB_tx][txdataF_offset], numSamples*sizeof(int32_t)); } else { AssertFatal(1==0,"This needs to be fixed, do not use beamforming.\n"); int32_t ***bw = ru->beam_weights[0]; for(int i=0; i<fp->symbols_per_slot; ++i){ nr_beam_precoding((c16_t **)ru->gNB_list[0]->common_vars.txdataF, (c16_t **)ru->common.txdataF_BF, fp, bw, slot, i, aa, ru->nb_log_antennas, txdataF_offset);//here } } if (aa==0) stop_meas(&ru->precoding_stats); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 0); ////////////FEPTX//////////// nr_feptx0(ru,slot,startSymbol,numSymbols,aa); } // RU FEP TX using thread-pool void nr_feptx_tp(RU_t *ru, int frame_tx, int slot) { nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config; int nbfeptx=0; if (nr_slot_select(cfg,frame_tx,slot) == NR_UPLINK_SLOT) return; // for (int aa=0; aa<ru->nb_tx; aa++) memset(ru->common.txdataF[aa],0,ru->nr_frame_parms->samples_per_slot_wCP*sizeof(int32_t)); if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM, 1 ); start_meas(&ru->ofdm_total_stats); for (int aid=0;aid<ru->nb_tx;aid++) { notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(feptx_cmd_t), 2000 + aid,ru->respfeptx,nr_feptx); feptx_cmd_t *feptx_cmd=(feptx_cmd_t*)NotifiedFifoData(req); feptx_cmd->aid = aid; feptx_cmd->ru = ru; feptx_cmd->slot = slot; feptx_cmd->startSymbol = 0; feptx_cmd->numSymbols = (ru->half_slot_parallelization>0)?ru->nr_frame_parms->symbols_per_slot>>1:ru->nr_frame_parms->symbols_per_slot; pushTpool(ru->threadPool,req); nbfeptx++; if (ru->half_slot_parallelization>0) { notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(feptx_cmd_t), 2000 + aid + ru->nb_tx,ru->respfeptx,nr_feptx); feptx_cmd_t *feptx_cmd=(feptx_cmd_t*)NotifiedFifoData(req); feptx_cmd->aid = aid; feptx_cmd->ru = ru; feptx_cmd->slot = slot; feptx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot>>1; feptx_cmd->numSymbols = ru->nr_frame_parms->symbols_per_slot>>1; pushTpool(ru->threadPool,req); nbfeptx++; } } while (nbfeptx>0) { notifiedFIFO_elt_t *req=pullTpool(ru->respfeptx, ru->threadPool); delNotifiedFIFO_elt(req); nbfeptx--; } stop_meas(&ru->ofdm_total_stats); if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM, 0 ); } // core RX FEP routine, called by threads in RU thread-pool void nr_fep(void* arg) { feprx_cmd_t *feprx_cmd = (feprx_cmd_t *)arg; RU_t *ru = feprx_cmd->ru; int aid = feprx_cmd->aid; int tti_rx = feprx_cmd->slot; int startSymbol = feprx_cmd->startSymbol; int endSymbol = feprx_cmd->endSymbol; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; LOG_D(PHY,"In nr_fep for aid %d, slot = %d, startSymbol %d, endSymbol %d\n", aid, tti_rx,startSymbol,endSymbol); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 1); int offset = (tti_rx % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size; for (int l = startSymbol; l <= endSymbol; l++) nr_slot_fep_ul(fp, ru->common.rxdata[aid], &ru->common.rxdataF[aid][offset], l, tti_rx, ru->N_TA_offset); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 0); } // RU RX FEP using thread-pool void nr_fep_tp(RU_t *ru, int slot) { int nbfeprx=0; if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); start_meas(&ru->ofdm_demod_stats); for (int aid=0;aid<ru->nb_rx;aid++) { notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(feprx_cmd_t), 1000 + aid,ru->respfeprx,nr_fep); feprx_cmd_t *feprx_cmd=(feprx_cmd_t*)NotifiedFifoData(req); feprx_cmd->aid = aid; feprx_cmd->ru = ru; feprx_cmd->slot = ru->proc.tti_rx; feprx_cmd->startSymbol = 0; feprx_cmd->endSymbol = (ru->half_slot_parallelization > 0)?(ru->nr_frame_parms->symbols_per_slot>>1)-1:(ru->nr_frame_parms->symbols_per_slot-1); pushTpool(ru->threadPool,req); nbfeprx++; if (ru->half_slot_parallelization>0) { notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(feprx_cmd_t), 1000 + aid + ru->nb_rx,ru->respfeprx,nr_fep); feprx_cmd_t *feprx_cmd=(feprx_cmd_t*)NotifiedFifoData(req); feprx_cmd->aid = aid; feprx_cmd->ru = ru; feprx_cmd->slot = ru->proc.tti_rx; feprx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot>>1; feprx_cmd->endSymbol = ru->nr_frame_parms->symbols_per_slot-1; pushTpool(ru->threadPool,req); nbfeprx++; } } while (nbfeprx>0) { notifiedFIFO_elt_t *req=pullTpool(ru->respfeprx, ru->threadPool); delNotifiedFIFO_elt(req); nbfeprx--; } stop_meas(&ru->ofdm_demod_stats); if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 0 ); }