From 1440e3c5ad36d8bf6f047b99239b8cca81be0b6f Mon Sep 17 00:00:00 2001
From: Guy De Souza <desouza@eurecom.fr>
Date: Mon, 16 Apr 2018 17:42:17 +0200
Subject: [PATCH] NR RU procedures

---
 cmake_targets/CMakeLists.txt         |   1 +
 openair1/PHY/defs.h                  |   4 +-
 openair1/SCHED_NR/nr_ru_procedures.c | 328 +++++++++++++++++++++++++++
 targets/RT/USER/nr-ru.c              |  10 +-
 4 files changed, 336 insertions(+), 7 deletions(-)
 create mode 100644 openair1/SCHED_NR/nr_ru_procedures.c

diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 5fc5add8c5..22bf239259 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 a5d48e3e39..28184d741a 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 0000000000..e626998967
--- /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 1b5dc34526..0686cc72e8 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
-- 
GitLab