diff --git a/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf
index 19e4abdcb028166a8c899fdb6d4193fe74c5a8f4..33aae14dac1cb781a814f5d90e0626cbe3e7f000 100755
--- a/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf
@@ -266,7 +266,7 @@ RUs = (
     max_pdschReferenceSignalPower = -27;
     max_rxgain                    = 118;
     eNB_instances  = [0];
-    clock_src      = "external";
+#    clock_src      = "external";
   }
 );  
 
diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf
index 0d9691966bea56f5c2efc3525d21898e47f66f6d..259a2466ad862387335d729315b5c5580011002e 100755
--- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf
@@ -1,6 +1,8 @@
 Active_gNBs = ( "gNB-Eurecom-5GNRBox");
 # Asn1_verbosity, choice in: none, info, annoying
 Asn1_verbosity = "none";
+Num_Threads_PUSCH = 8
+
 
 gNBs =
 (
@@ -21,7 +23,10 @@ gNBs =
 
     ssb_SubcarrierOffset                                      = 31; //0;
     pdsch_AntennaPorts                                        = 1;
-  
+    pusch_TargetSNRx10                                        = 200; 
+    pucch_TargetSNRx10                                        = 200;
+
+ 
     servingCellConfigCommon = (
     {
  #spCellConfigCommon
@@ -260,7 +265,7 @@ RUs = (
          max_pdschReferenceSignalPower = -27;
          max_rxgain                    = 114;
          eNB_instances  = [0];
-         clock_src = "external";
+#         clock_src = "external";
     }
 );  
 
diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 94d55d5fe5073825c0feabcfcdb2693afc2bc6cc..0b9d9250171303ff90e010b54bcdd66f6873dfd4 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1968,6 +1968,7 @@ set(NR_PDCP_SRC
   ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
   ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_entity.c
   ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c
+  ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c
   )
 
 set(L2_SRC
@@ -3434,7 +3435,7 @@ if (${T_TRACER})
         SECU_OSA SECU_CN SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB default_sched remote_sched RAL
         NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_VNF_LIB NFAPI_USER_LIB
         PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX
-        L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_NR MAC_UE_NR
+        L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_NR MAC_UE_NR NGAP_GNB
         CN_UTILS GTPV1U NR_GTPV1U SCTP_CLIENT MME_APP UDP LIB_NAS_UE NB_IoT LFDS LFDS7 SIMU_COMMON SIMU SIMU_ETH OPENAIR0_LIB
         ldpc_orig ldpc_optim ldpc_optim8seg ldpc PROTO_AGENT dfts)
     if (TARGET ${i})
diff --git a/doc/SW_archi.md b/doc/SW_archi.md
index dba884dcec837ed5671e20443d84b4c8c4836fb2..412dad402d90816ad53c5f48428824f6407052dd 100644
--- a/doc/SW_archi.md
+++ b/doc/SW_archi.md
@@ -70,7 +70,7 @@ if the input is a UE RACH detection
     * nr_schedule_msg2()
 {: .func4}
 * handle_nr_uci()  
-????	      
+handles uplink control information, i.e., for the moment HARQ feedback.
 {: .func4}
 * handle_nr_ulsch()  
 handles ulsch data prepared by nr_fill_indication()
@@ -143,7 +143,8 @@ the samples numbers are the future time for these samples emission on-air
 {: .func3}
 
 # Scheduler
-The scheduler is called by the chain: nr_ul_indication()=>gNB_dlsch_ulsch_scheduler()
+
+The main scheduler function  is called by the chain: nr_ul_indication()=>gNB_dlsch_ulsch_scheduler()
 It calls sub functions to process each physical channel (rach, ...)  
 The scheduler uses and internal map of used RB: vrb_map and vrb_map_UL, so each specific channel scheduler can see the already filled RB in each subframe (the function gNB_dlsch_ulsch_scheduler() clears these two arrays when it starts)   
 
@@ -153,16 +154,71 @@ it sends a iiti message to activate the thread for RRC, the answer will be async
 
 Calls schedule_nr_mib() that calls mac_rrc_nr_data_req() to fill MIB,  
 
-Calls each channel allocation: schedule SI, schedule_ul, schedule_dl, ...  
-this is a major entry for "phy-test" mode: in this mode, the allocation is fixed  
-all these channels goes to mac_rrc_nr_data_req() to get the data to transmit  
-
-nr_schedule_ue_spec() is called  
-* calls nr_simple_dlsch_preprocessor()=> mac_rlc_status_ind() mac_rlc_status_ind() locks and checks directly inside rlc data the quantity of waiting data. So, the scheduler can allocate RBs
-* calls nr_update_pucch_scheduling()  
-    * get_pdsch_to_harq_feedback() to schedule retransmission in DL
-
-Calls nr_fill_nfapi_dl_pdu() to actually populate what should be done by the lower layers to make the Tx subframe
+Calls schedule_nr_prach() which schedules the (fixed) PRACH region one frame in
+advance.
+
+Calls nr_csi_meas_reporting() to check when to schedule CSI in PUCCH.
+
+Calls nr_schedule_RA(): checks RA process 0's state. Schedules Msg.2 via
+nr_generate_Msg2() if an RA process is ongoing, and pre-allocates the Msg. 3
+for PUSCH as well.
+
+Calls nr_schedule_ulsch(): It is divided into the "preprocessor" and the
+"postprocessor": the first makes the scheduling decisions, the second fills
+nFAPI structures to indicate to the PHY what it is supposed to do. To signal
+which users have how many resources, the preprocessor populates the
+NR_sched_pusch_t (for values changing every TTI, e.g., frequency domain
+allocation) and NR_sched_pusch_save_t (for values changing less frequently, at
+least in FR1 [to my understanding], e.g., DMRS fields when the time domain
+allocation stays between TTIs) structures. Furthermore, the preprocessor is an
+exchangeable module that might schedule differently, e.g., one user for
+phytest, multiple users in FR1, or maybe FR2: phytest is in
+nr_ul_preprocessor_phytest(), for FR1 is nr_simple_ulsch_preprocessor() [under
+development], for FR2 does not exist yet.
+* calls preprocessor via pre_processor_ul(): the preprocessor is responsible
+  for allocating CCEs (using allocate_nr_CCEs()). Note that we do not yet have
+  scheduling requests or buffer status reports, and only one UE. E.g.,
+  nr_simple_ulsch_preprocessor():
+  1)  check whether the current frame/slot plus K2 is an UL slot, and return if
+      not.
+  2)  Find first free start RB in vrb_map_UL, and as many free consecutive RBs
+      as possible.
+  3)  allocate a CCE for the UE (and return if it is not possible)
+  4)  Calculate DMRS stuff (nr_save_pusch_fields()) and the TBS.
+  5)  Mark used resources in vrb_map_UL.
+* loop through all users: get a free HARQ PID using select_ul_harq_pid() and
+  update statistics. Fill nFAPI structures directly for PUSCH, and call
+  config_uldci() and fill_dci_pdu_rel15() for DCI filling and PDCCH messages.
+
+Calls nr_schedule_ue_spec(). It is divided into the "preprocessor" and the
+"postprocessor": the first makes the scheduling decisions, the second fills
+nFAPI structures to indicate to the PHY what it is supposed to do. To signal
+which users have how many resources, the preprocessor populates the
+NR_UE_sched_ctrl_t structure of affected users. In particular, the field rbSize
+decides whether a user is to be allocated. Furthermore, the preprocessor is an
+exchangeable module that might schedule differently, e.g., one user for
+phytest, multiple users in FR1, or maybe FR2: phytest is in
+nr_preprocessor_phytest(), for FR1 is nr_simple_dlsch_preprocessor() [under
+development], for FR2 does not exist yet.
+* calls preprocessor via pre_processor_dl(): the preprocessor is responsible
+  for allocating CCEs and PUCCH (using allocate_nr_CCEs() and
+  nr_acknack_scheduling()) and deciding on the frequency/time domain
+  allocation. E.g., nr_simple_dlsch_preprocessor():
+  1)  mac_rlc_status_ind() locks and checks directly inside rlc data the
+      quantity of waiting data.
+  2)  return from the preprocessor if there is no data and no timing advance to
+      send,
+  3)  otherwise, allocate a CCE for the UE (and return if it is not possible)
+  4)  find a PUCCH occasion for HARQ
+  5a) check if there is a retransmission: if yes, find free resources to
+      transmit using the same resources, else
+  5b) calculate the necessary RBs needed to get a TBS large enough to hold all
+      data, or until no more resources are available
+  6)  Mark taken resources in the vrb_map
+* loop through all users: check if a new TA is necessary. Then, if a user has
+  allocated resources, compute its TBS, and fill nFAPI structures
+  (nr_fill_nfapi_dl_pdu() to populate what should be done by the lower layers
+  to make the Tx subframe). Update statistics (round, sent bytes).
 
 # RRC
 RRC is a regular thread with itti loop on queue: TASK_RRC_GNB
diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c
index bd4a1a72aa868e14201c2588d284694df1a5ac34..be9261a117828f999f895e152c9cf52cbd4931cb 100644
--- a/executables/nr-gnb.c
+++ b/executables/nr-gnb.c
@@ -72,6 +72,7 @@
 #include "common/utils/LOG/vcd_signal_dumper.h"
 #include "UTIL/OPT/opt.h"
 #include "enb_config.h"
+#include "gnb_paramdef.h"
 
 
 #ifndef OPENAIR2
@@ -101,6 +102,7 @@ extern int transmission_mode;
 
 extern uint16_t sf_ahead;
 extern uint16_t sl_ahead;
+
 //pthread_t                       main_gNB_thread;
 
 time_stats_t softmodem_stats_mt; // main thread
@@ -870,7 +872,18 @@ void init_gNB_proc(int inst) {
 
   gNB->threadPool = (tpool_t*)malloc(sizeof(tpool_t));
   gNB->respDecode = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t));
-  char ul_pool[] = "-1,-1";
+  int numCPU = sysconf(_SC_NPROCESSORS_ONLN);
+  uint32_t num_threads_pusch;
+  paramdef_t PUSCHThreads[] = NUM_THREADS_DESC;
+  config_get( PUSCHThreads,sizeof(PUSCHThreads)/sizeof(paramdef_t),NULL);
+  int threadCnt = min(numCPU, num_threads_pusch);
+  char ul_pool[80];
+  sprintf(ul_pool,"-1");
+  int s_offset = 0;
+  for (int icpu=1; icpu<threadCnt; icpu++) {
+    sprintf(ul_pool+2+s_offset,",-1");
+    s_offset += 3;
+  }
   initTpool(ul_pool, gNB->threadPool, false);
   initNotifiedFIFO(gNB->respDecode);
 }
diff --git a/openair1/PHY/CODING/nr_rate_matching.c b/openair1/PHY/CODING/nr_rate_matching.c
index efa5abdc90004cae6cd8eab61ab899f43c5347aa..e4097ade9d13481bf2935a03c7314c67efa20f4f 100644
--- a/openair1/PHY/CODING/nr_rate_matching.c
+++ b/openair1/PHY/CODING/nr_rate_matching.c
@@ -407,8 +407,16 @@ int nr_rate_matching_ldpc(uint8_t Ilbrm,
 #ifdef RM_DEBUG
   printf("nr_rate_matching_ldpc: E %d, F %d, Foffset %d, k0 %d, Ncb %d, rvidx %d\n", E, F, Foffset,ind, Ncb, rvidx);
 #endif
-  AssertFatal(Foffset <= E,"Foffset %d > E %d\n",Foffset,E); 
-  AssertFatal(Foffset <= Ncb,"Foffset %d > Ncb %d\n",Foffset,Ncb); 
+  AssertFatal(Foffset <= E,
+              "Foffset %d > E %d "
+              "(Ilbrm %d, Tbslbrm %d, Z %d, BG %d, C %d)\n",
+              Foffset, E,
+              Ilbrm, Tbslbrm, Z, BG, C);
+  AssertFatal(Foffset <= Ncb,
+              "Foffset %d > Ncb %d "
+              "(Ilbrm %d, Tbslbrm %d, Z %d, BG %d, C %d)\n",
+              Foffset, Ncb,
+              Ilbrm, Tbslbrm, Z, BG, C);
 
   if (ind >= Foffset && ind < (F+Foffset)) ind = F+Foffset;
 
diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c
index 171980d343d56b56d10c748231ba614da27e33d4..ba4147e5cdbec204adc746698dc37694a49c0c71 100644
--- a/openair1/PHY/INIT/nr_parms.c
+++ b/openair1/PHY/INIT/nr_parms.c
@@ -41,38 +41,32 @@ int nr_get_ssb_start_symbol(NR_DL_FRAME_PARMS *fp)
   int case_E[8] = {8, 12, 16, 20, 32, 36, 40, 44};
 
   switch(mu) {
-
-	case NR_MU_0: // case A
-	    n = i_ssb >> 1;
-	    symbol = case_AC[i_ssb % 2] + 14*n;
-	break;
-
-	case NR_MU_1: 
-	    if (type == 1){ // case B
-		n = i_ssb >> 2;
-	    	symbol = case_BD[i_ssb % 4] + 28*n;
-	    }
-	    if (type == 2){ // case C
-		n = i_ssb >> 1;
-		symbol = case_AC[i_ssb % 2] + 14*n;
-	    }
-	 break;
-
-	 case NR_MU_3: // case D
-	    n_temp = i_ssb >> 2; 
-	    n = n_temp + (n_temp >> 2);
-	    symbol = case_BD[i_ssb % 4] + 28*n;
-	 break;
-
-	 case NR_MU_4:  // case E
-	    n_temp = i_ssb >> 3; 
-	    n = n_temp + (n_temp >> 2);
-	    symbol = case_E[i_ssb % 8] + 56*n;
-	 break;
-
-
-	 default:
-	      AssertFatal(0==1, "Invalid numerology index %d for the synchronization block\n", mu);
+    case NR_MU_0: // case A
+      n = i_ssb >> 1;
+      symbol = case_AC[i_ssb % 2] + 14*n;
+      break;
+    case NR_MU_1:
+      if (type == 1){ // case B
+        n = i_ssb >> 2;
+        symbol = case_BD[i_ssb % 4] + 28*n;
+       }
+       if (type == 2){ // case C
+         n = i_ssb >> 1;
+         symbol = case_AC[i_ssb % 2] + 14*n;
+       }
+       break;
+     case NR_MU_3: // case D
+       n_temp = i_ssb >> 2;
+       n = n_temp + (n_temp >> 2);
+       symbol = case_BD[i_ssb % 4] + 28*n;
+       break;
+     case NR_MU_4:  // case E
+       n_temp = i_ssb >> 3;
+       n = n_temp + (n_temp >> 2);
+       symbol = case_E[i_ssb % 8] + 56*n;
+       break;
+     default:
+       AssertFatal(0==1, "Invalid numerology index %d for the synchronization block\n", mu);
   }
 
   if (half_frame_index)
diff --git a/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c
index a881773910c70a2719fc47cd178d786372e23e93..2d79158920bb821d71e126822e193c7d50f20fcd 100644
--- a/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c
+++ b/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c
@@ -47,6 +47,7 @@ void lte_eNB_I0_measurements(PHY_VARS_eNB *eNB,
   uint32_t rb;
   int32_t *ul_ch;
   int32_t n0_power_tot;
+  int64_t n0_power_tot2;
   int len;
   int offset;
   // noise measurements
@@ -75,43 +76,47 @@ void lte_eNB_I0_measurements(PHY_VARS_eNB *eNB,
 
   }
 
+  n0_power_tot2=0;
+  int nb_rb=0;
   for (rb=0; rb<frame_parms->N_RB_UL; rb++) {
 
-    n0_power_tot=0;
+    n0_power_tot=0; 
+    int offset0= (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size;
+
     if ((rb_mask[rb>>5]&(1<<(rb&31))) == 0) {  // check that rb was not used in this subframe
+      nb_rb++;
       for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
-
+        measurements->n0_subband_power[aarx][rb] = 0;
+        for (int s=0;s<14-(frame_parms->Ncp<<1);s++) {
       // select the 7th symbol in an uplink subframe
-	offset = (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size;
-	offset += (7*frame_parms->ofdm_symbol_size);
-	ul_ch  = &common_vars->rxdataF[aarx][offset];
-	len = 12;
+	  offset = offset0 + (s*frame_parms->ofdm_symbol_size);
+	  ul_ch  = &common_vars->rxdataF[aarx][offset];
+	  len = 12;
 	// just do first half of middle PRB for odd number of PRBs
-	if (((frame_parms->N_RB_UL&1) == 1) && 
-	    (rb==(frame_parms->N_RB_UL>>1))) {
-	  len=6;
-	}
-	if (clear == 1)
-	  measurements->n0_subband_power[aarx][rb]=0;
+	  if (((frame_parms->N_RB_UL&1) == 1) && 
+	      (rb==(frame_parms->N_RB_UL>>1))) {
+	    len=6;
+	  }
 
-	AssertFatal(ul_ch, "RX signal buffer (freq) problem");
+	  AssertFatal(ul_ch, "RX signal buffer (freq) problem");
 
 
-	measurements->n0_subband_power[aarx][rb] = signal_energy_nodc(ul_ch,len);
-	//((k1*(signal_energy_nodc(ul_ch,len))) 
-	  //  + (k2*measurements->n0_subband_power[aarx][rb]));  
+	  measurements->n0_subband_power[aarx][rb] += signal_energy_nodc(ul_ch,len);
 	  
-	measurements->n0_subband_power_dB[aarx][rb] = dB_fixed(measurements->n0_subband_power[aarx][rb]);
-	//		printf("subframe %d (%d): eNB %d, aarx %d, rb %d len %d: energy %d (%d dB)\n",subframe,offset,eNB_id,aarx,rb,len,signal_energy_nodc(ul_ch,len),  
-	//	       measurements->n0_subband_power_dB[aarx][rb]);
-	n0_power_tot += measurements->n0_subband_power[aarx][rb];
+        }
+        measurements->n0_subband_power[aarx][rb]/=(14-(frame_parms->Ncp<<1));
+        measurements->n0_subband_power_dB[aarx][rb] = dB_fixed(measurements->n0_subband_power[aarx][rb]);
+        n0_power_tot += measurements->n0_subband_power[aarx][rb];
+
       }
-      
-      measurements->n0_subband_power_tot_dB[rb] = dB_fixed(n0_power_tot);
+      n0_power_tot/=frame_parms->nb_antennas_rx;
+      n0_power_tot2 += n0_power_tot;
+      measurements->n0_subband_power_tot_dB[rb] = dB_fixed(n0_power_tot/frame_parms->nb_antennas_rx);
       measurements->n0_subband_power_tot_dBm[rb] = measurements->n0_subband_power_tot_dB[rb] - eNB->rx_total_gain_dB - dB_fixed(frame_parms->N_RB_UL);
       
     }
   }
+  if (nb_rb>0) measurements->n0_subband_power_avg_dB = dB_fixed(n0_power_tot2/nb_rb);
 }
 
 void lte_eNB_srs_measurements(PHY_VARS_eNB *eNB,
diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c
index 1e0dd9db1b7af5110b3c30425ec33de7c5755912..f39f3ef872021d12fb73273f7a165e104d59cf75 100644
--- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c
+++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c
@@ -1070,6 +1070,8 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 );
   if (packet_type == IF5_RRH_GW_DL) {    
     if (eth->compression == ALAW_COMPRESS) {
+     AssertFatal(1==0,"IF5 compression needs reworking\n");
+/*
       if (eth->flags == ETH_RAW_MODE) {
         data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES + MAC_HEADER_SIZE_BYTES);
       } else {
@@ -1100,28 +1102,31 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
         LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp));
         VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 0 );
       }
+*/
     } else if (eth->compression == NO_COMPRESS) {
 
-      for (i=0; i < fp->nb_antennas_tx; i++)
-        txp[i] = (void*)&ru->common.txdata[i][subframe*fp->samples_per_tti];
+      for (i=0; i < ru->nb_tx; i++)
+        txp[i] = (int32_t*)&ru->common.txdata[i][subframe*fp->samples_per_tti];
     
       for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) {
-        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 );
-        clock_gettime( CLOCK_MONOTONIC, &start_comp);
-        ru->ifdevice.trx_write_func(&ru->ifdevice,
-				    (proc_timestamp + packet_id*spp_eth),
-				    (void**)txp,
-				    spp_eth,
-				    fp->nb_antennas_tx,
-				    0);
-        clock_gettime( CLOCK_MONOTONIC, &end_comp);
-        LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp));
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 0 );  
-        for (i=0; i < fp->nb_antennas_tx; i++)
-          txp[i] += spp_eth;
+        for (int aid=0; aid<ru->nb_tx;aid++) {
+          //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
+          //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 );
+          clock_gettime( CLOCK_MONOTONIC, &start_comp);
+          ru->ifdevice.trx_write_func2(&ru->ifdevice,
+	  			       (proc_timestamp + packet_id*spp_eth-500)*(30720/spsf),
+				       (void*)txp[aid],
+				       spp_eth,
+				       aid,
+				       0); 
+          LOG_D(HW,"SF %d : packet %d, TS %llu\n",subframe,packet_id,(unsigned long long)(proc_timestamp+packet_id*spp_eth));
+          clock_gettime( CLOCK_MONOTONIC, &end_comp);
+          LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp));
+          //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 0 );  
+	  txp[aid] += spp_eth;
 
-      }
+        }
+     }
     }
   } else if (packet_type == IF5_RRH_GW_UL) {
     if (eth->compression == ALAW_COMPRESS) {
@@ -1131,8 +1136,8 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
         data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES);
       }
       for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) {
-        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 1 );
+        //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 1 );
         clock_gettime( CLOCK_MONOTONIC, &start_comp);
         for (i=0; i < fp->nb_antennas_rx; i++) {
           for (element_id=0; element_id< spp_eth; element_id++){
@@ -1142,8 +1147,8 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
         }
         clock_gettime( CLOCK_MONOTONIC, &end_comp);
         LOG_D(HW,"[SF %d] Compress_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp));
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 0 );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 0 );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 );
         clock_gettime( CLOCK_MONOTONIC, &start_comp);
         ru->ifdevice.trx_write_func(&ru->ifdevice,
                                      (proc_timestamp + packet_id*spp_eth),
@@ -1310,9 +1315,9 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
 void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16_t packet_type) {
 
   LTE_DL_FRAME_PARMS *fp=ru->frame_parms;
-  int32_t *txp[fp->nb_antennas_tx], *rxp[fp->nb_antennas_rx]; 
+  int32_t *txp[ru->nb_tx], *rxp[ru->nb_rx]; 
 
-  uint16_t packet_id=0, i=0, element_id=0;
+  uint16_t packet_id=0, i=0;
 #ifdef DEBUG_UL_MOBIPASS
   //int8_t dummy_buffer_rx[fp->samples_per_tti*2];
   uint8_t rxe;
@@ -1321,11 +1326,12 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
 
   int32_t spp_eth  = (int32_t) ru->ifdevice.openair0_cfg->samples_per_packet;
   int32_t spsf     = (int32_t) ru->ifdevice.openair0_cfg->samples_per_frame/10;
-  void    *alaw_buffer = ru->ifbuffer.rx; 
-  uint16_t *data_block = NULL;
-  uint16_t *j      = NULL;
 
-  openair0_timestamp timestamp[spsf / spp_eth];
+  openair0_timestamp timestamp[ru->nb_rx*spsf / spp_eth];
+  long timein[ru->nb_rx*spsf/spp_eth];
+  long timeout[ru->nb_rx*spsf/spp_eth];
+  struct timespec if_time;
+ 
   memset(timestamp, 0, sizeof(timestamp));
   eth_state_t *eth = (eth_state_t*) (ru->ifdevice.priv);
 
@@ -1333,6 +1339,9 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
   
   if (packet_type == IF5_RRH_GW_DL) {
     if (eth->compression == ALAW_COMPRESS) {
+     AssertFatal(1==0,"IF5 compression needs reworking\n");
+
+/*
       if (eth->flags == ETH_RAW_MODE) {
         data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES + MAC_HEADER_SIZE_BYTES);
       } else {
@@ -1364,13 +1373,14 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
         LOG_D(HW,"[SF %d] Decomperss_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
         VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_DECOMPR_IF, 0 );
       }
+*/
     } else if (eth->compression == NO_COMPRESS) {
       for (i=0; i < fp->nb_antennas_tx; i++)
         txp[i] = (void*)&ru->common.txdata[i][subframe*fp->samples_per_tti];
     
       for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) {
-        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RECV_IF5_PKT_ID, packet_id );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 1 );  
+        //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RECV_IF5_PKT_ID, packet_id );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 1 );  
         clock_gettime( CLOCK_MONOTONIC, &start_decomp);
         ru->ifdevice.trx_read_func(&ru->ifdevice,
 				   &timestamp[packet_id],
@@ -1379,7 +1389,7 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
 				   fp->nb_antennas_tx);
         clock_gettime( CLOCK_MONOTONIC, &end_decomp);
         LOG_D(HW,"[SF %d] IF_Read_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 0 );  
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 0 );  
         for (i=0; i < fp->nb_antennas_tx; i++)
           txp[i] += spp_eth;
 
@@ -1389,6 +1399,8 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
     
   } else if (packet_type == IF5_RRH_GW_UL) { 
     if (eth->compression == ALAW_COMPRESS) {
+     AssertFatal(1==0,"IF5 compression needs reworking\n");
+/*
       if (eth->flags == ETH_RAW_MODE) {
         data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES + MAC_HEADER_SIZE_BYTES);
       } else {
@@ -1419,197 +1431,55 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
         LOG_D(HW,"[SF %d] Decomperss_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
         VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_DECOMPR_IF, 0 );
       }
+*/
     } else if (eth->compression == NO_COMPRESS) {
-      for (i=0; i < fp->nb_antennas_rx; i++)
-        rxp[i] = (void*)&ru->common.rxdata[i][subframe*fp->samples_per_tti];
-    
-      for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) {
-        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 1 );
-        clock_gettime( CLOCK_MONOTONIC, &start_decomp);
-        ru->ifdevice.trx_read_func(&ru->ifdevice,
+      int16_t temp_rx[spp_eth*2] __attribute__((aligned(32))); 
+      for (i=0; i < ru->nb_rx; i++)
+        rxp[i] = &ru->common.rxdata[i][subframe*fp->samples_per_tti];
+      int aid;
+      int firstTS=1;
+      openair0_timestamp oldTS=0;
+
+      for (packet_id=0; packet_id < ru->nb_rx*spsf / spp_eth; packet_id++) {
+        //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 1 );
+        clock_gettime( CLOCK_MONOTONIC, &if_time);
+        timein[packet_id] = if_time.tv_nsec;
+        ru->ifdevice.trx_read_func2(&ru->ifdevice,
 				   &timestamp[packet_id],
-				   (void**)rxp,
+				   (void*)temp_rx,
 				   spp_eth,
-				   fp->nb_antennas_rx);
-        clock_gettime( CLOCK_MONOTONIC, &end_decomp);
-        LOG_D(HW,"[SF %d] IF_Read_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 0 );            
-        for (i=0; i < fp->nb_antennas_rx; i++)
-          rxp[i] += spp_eth;
-
-      }
-    }
-    *proc_timestamp = timestamp[0];
-      
-  } else if (packet_type == IF5_MOBIPASS) {
-    if (ru->if_timing == synch_to_mobipass_standalone) {
-      uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
-      openair0_timestamp timestamp_mobipass[fp->samples_per_tti/db_fulllength];
-      int32_t *rx_buffer=NULL;
-      __m128i *data_block=NULL, *data_block_head=NULL;
-      __m128i *rxp128;
-      __m128i r0;
-
-      unsigned char _rx_buffer[MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t)];
-      rx_buffer = (int32_t *)_rx_buffer;
-      data_block_head = (__m128i *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
-
-      rxp[0] = (void*)&ru->common.rxdata[0][subframe*ru->frame_parms->samples_per_tti];
-      rxp128 = (__m128i *) (rxp[0]);
-
-      packet_id=0;
-      while(packet_id<fp->samples_per_tti/db_fulllength) {
-        data_block = data_block_head;
-
-        ru->ifdevice.trx_read_func(&ru->ifdevice,
-                                         &timestamp_mobipass[packet_id],
-                                         (void**)&rx_buffer,
-                                         db_fulllength,
-                                          1
-                                          );
-
-          //store rxdata and increase packet_id
-          rxp[0] = (void*)&ru->common.rxdata[0][(subframe*ru->frame_parms->samples_per_tti)+packet_id*db_fulllength];
-          rxp128 = (__m128i *) (rxp[0]);
-          for (i=0; i<db_fulllength>>2; i+=2) {
-            r0 = _mm_loadu_si128(data_block++);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
-          }
-          packet_id++;
-      }//end while
-
-      *proc_timestamp = ntohl(timestamp_mobipass[0]);
-    } else {
-      
-      uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
-      openair0_timestamp timestamp_mobipass[fp->samples_per_tti/db_fulllength];
-#ifdef DEBUG_UL_MOBIPASS
-      int lower_offset = 0;
-      int  upper_offset = 70000;
-#endif
-      int subframe_skip = 0;
-      int reset_flag = 0;
-      int32_t *rx_buffer=NULL;
-      __m128i *data_block=NULL, *data_block_head=NULL;
-      __m128i *rxp128;
-      __m128i r0;
-
-      //rx_buffer = memalign(16, MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
-      rx_buffer = malloc(MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
-      IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES);
-      data_block_head = (__m128i *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
-   
-      rxp[0] = (void*)&ru->common.rxdata[0][subframe*ru->frame_parms->samples_per_tti];
-      rxp128 = (__m128i *) (rxp[0]);
-   
-      RU_proc_t *proc = &ru->proc;
-/*
-   //   while(packet_id<fp->samples_per_tti/db_fulllength) {
-        data_block = data_block_head;
-
-        eNB->ifdevice.trx_read_func(&eNB->ifdevice,
-                                         &ts0,
-                                         (void**)&rx_buffer,
-                                         db_fulllength,
-                                          1
-                                          );
+				   &aid);
+        clock_gettime( CLOCK_MONOTONIC, &if_time);
+        timeout[packet_id] = if_time.tv_nsec;
+        timestamp[packet_id] /= (30720/spsf);
+        LOG_D(PHY,"subframe %d: Received packet %d: aid %d, TS %llu, oldTS %llu, diff %lld, \n",subframe,packet_id,aid,(unsigned long long)timestamp[packet_id],(unsigned long long)oldTS,(unsigned long long)(timestamp[packet_id]-timestamp[0]));
+        if (aid==0) {
+           if (firstTS==1) firstTS=0;
+           else if (oldTS + 256 != timestamp[packet_id]) {
+              LOG_I(PHY,"oldTS %llu, newTS %llu, diff %llu, timein %lu, timeout %lu\n",(long long unsigned int)oldTS,(long long unsigned int)timestamp[packet_id],(long long unsigned int)timestamp[packet_id]-oldTS,timein[packet_id],timeout[packet_id]); 
+              for (int i=0;i<=packet_id;i++) LOG_I(PHY,"packet %d TS %llu, timein %lu, timeout %lu\n",i,(long long unsigned int)timestamp[i],timein[i],timeout[i]);
+              AssertFatal(1==0,"fronthaul problem\n");
+           }
 
-        if ((header->seqno == 1)&&(first_packet==1))  { 
-           first_packet = 0;  //ignore the packets before synchnorization
-           packet_id = 0;
-          ts_offset = ntohl(ts0);
-        } 
-        if (first_packet==0) { 
-          packet_cnt++;
-          ts = ntohl(ts0);
-          packet_id = (ts-ts_offset)/db_fulllength;
-          packet_id = packet_id % (fp->samples_per_tti/db_fulllength);
-
-          printf("[IF5_tools]packet_id:%d\n", packet_id);
-          // if (ts_stored == 0) {
-          //   ts_stored = 1;
-          *proc_timestamp = ntohl(ts - (packet_id*db_fulllength));
-          // }
-          rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][(subframe*eNB->frame_parms.samples_per_tti)+packet_id*db_fulllength];
-          rxp128 = (__m128i *) (rxp[0]);
-
-          for (i=0; i<db_fulllength>>2; i+=2) {
-            r0 = _mm_loadu_si128(data_block++);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
-          }
+           oldTS = timestamp[packet_id];
         }
-    //  }//end while
-*/
    
 
-      packet_id=0; 
-      while(packet_id<fp->samples_per_tti/db_fulllength) {
-        data_block = data_block_head;
-
-	
-	ru->ifdevice.trx_read_func(&ru->ifdevice,
-				 &timestamp_mobipass[packet_id],
-				 (void**)&rx_buffer,
-				 db_fulllength,
-				 1
-				 );
-#ifdef DEBUG_UL_MOBIPASS
-        if (((proc->timestamp_tx + lower_offset) > ntohl(timestamp_mobipass[packet_id])) || ((proc->timestamp_tx + upper_offset) < ntohl(timestamp_mobipass[packet_id]))) {
-          //ignore the packet
-          subframe_skip_extra = (subframe_skip_extra + 1)%67;         
-         LOG_D("[Mobipass] ignored packet, id:[%d,%d], proc->timestamp_tx:%llu, proc->timestamp_rx:%llu, seqno:%d\n", packet_id,subframe_skip_extra, proc->timestamp_tx, ntohl(timestamp_mobipass[packet_id]), header->seqno);
-        }             
-#endif
-        //skip SUBFRAME_SKIP_NUM_MOBIPASS additional UL packets
-        if ((start_flag == 1) && (subframe_skip < SUBFRAME_SKIP_NUM_MOBIPASS)){
-          subframe_skip++;
-          offset_cnt = header->seqno;
-        } else {
-          if ((offset_cnt != header->seqno) && (start_flag == 0) && (proc->first_rx > 3)){
-#ifdef DEBUG_UL_MOBIPASS
-             LOG_D(PHY,"[Mobipass] Reset sequence number, offset_cnt:%d, header->seqno:%d, packet_id:%d\n", offset_cnt, header->seqno, packet_id);
-#endif
-             reset_flag=1;
-          }
-          if ((reset_flag == 1) && (proc->first_rx > 3 ) && (start_flag == 0) && (packet_id == 0)) {
-             packet_id = 1;  
-             reset_flag = 0;
-          }
-          start_flag = 0;
-
-          //store rxdata and increase packet_id
-          rxp[0] = (void*)&ru->common.rxdata[0][(subframe*ru->frame_parms->samples_per_tti)+packet_id*db_fulllength];
-          rxp128 = (__m128i *) (rxp[0]);
-          for (i=0; i<db_fulllength>>2; i+=2) {
-            r0 = _mm_loadu_si128(data_block++);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
-          }   
-          packet_id++; 
-          offset_cnt = (header->seqno+1)&255;
-        }
-      }//end while
-    
-        *proc_timestamp = ntohl(timestamp_mobipass[0]); 
-#ifdef DEBUG_UL_MOBIPASS
-	LOG_I(PHY,"[Mobipass][Recv_MOBIPASS] timestamp: %llu\n ",  *proc_timestamp);
-	if (eNB->CC_id>0) {
-	  rxe = dB_fixed(signal_energy(rxp[0],fp->samples_per_tti)); 
-	  if (rxe > 0){
-	    LOG_I(PHY,"[Mobipass] frame:%d, subframe:%d, energy %d\n", (*proc_timestamp/(10*fp->samples_per_tti))&1023,subframe, rxe);
-	    
-	    //    LOG_M("rxsigmb.m","rxs",(void*)dummy_buffer_rx, fp->samples_per_tti,1, 5); 
-	    //    exit(-1);
-	  }
-	}
-#endif
-      free(rx_buffer);
+        // HYPOTHESIS: first packet per subframe has lowest timestamp of subframe
+        // should detect out of order and act accordingly ....
+        AssertFatal(aid==0 || aid==1,"aid %d != 0 or 1\n",aid);
+        //LOG_I(PHY,"rxp[%d] %p, dest %p, offset %d (%lld,%lld)\n",aid,rxp[aid],rxp[aid]+(timestamp[packet_id]-timestamp[0]),(timestamp[packet_id]-timestamp[0]),timestamp[packet_id],timestamp[0]);
+        memcpy((void*)(rxp[aid]+(timestamp[packet_id]-timestamp[0])),
+               (void*)temp_rx,
+               spp_eth<<2);
+        clock_gettime( CLOCK_MONOTONIC, &end_decomp);
+        LOG_D(HW,"[SF %d] IF_Read_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 0 );            
 
-     
+      }
     }
+    *proc_timestamp = timestamp[0];
   } else {
     AssertFatal(1==0, "recv_IF5 - Unknown packet_type %x", packet_type);     
   }  
diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c
index d3ed2ed4391b04a3272107817204edceaae54e5b..31e97741fdb22e36ee2189206357d75a067626b0 100644
--- a/openair1/PHY/LTE_TRANSPORT/prach.c
+++ b/openair1/PHY/LTE_TRANSPORT/prach.c
@@ -89,7 +89,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
   int32_t *prach_ifft=(int32_t *)NULL;
   int32_t **prach_ifftp=(int32_t **)NULL;
   int prach_ifft_cnt=0;
-
+  int exit_flag=0;
   LTE_DL_FRAME_PARMS *fp;
   int nb_rx;
   if(eNB)  {
@@ -177,32 +177,33 @@ void rx_prach0(PHY_VARS_eNB *eNB,
   }
 
   AssertFatal(ru!=NULL,"ru is null\n");
-
+  int8_t dBEn0=0;
   for (aa=0; aa<nb_rx; aa++) {
-    if (ru->if_south == LOCAL_RF) { // set the time-domain signal if we have to use it in this node
+    if (ru->if_south == LOCAL_RF || ru->function == NGFI_RAU_IF5) { // set the time-domain signal if we have to use it in this node
       // DJP - indexing below in subframe zero takes us off the beginning of the array???
       prach[aa] = (int16_t *)&ru->common.rxdata[aa][(subframe*fp->samples_per_tti)-ru->N_TA_offset];
 
       if (LOG_DUMPFLAG(PRACH)) {
         int32_t en0=signal_energy((int32_t *)prach[aa],fp->samples_per_tti);
-        int8_t dbEn0 = dB_fixed(en0);
-        int8_t rach_dBm = dbEn0 - ru->rx_total_gain_dB;
+        dBEn0 = dB_fixed(en0);
+        int8_t rach_dBm = dBEn0 - ru->rx_total_gain_dB;
         char buffer[80];
 
-        if (dbEn0>32 && prach[0]!= NULL) {
+        if (dBEn0>30 && prach[0]!= NULL) {
           static int counter=0;
-          sprintf(buffer, "%s%d", "/tmp/prach_rx",counter);
-          LOG_M(buffer,"prach_rx",prach[0],fp->samples_per_tti,1,13);
+          sprintf(buffer, "%s%d", "/tmp/prach_rx.m",counter);
+          LOG_M(buffer,"prach_rx",prach[0],fp->samples_per_tti,1,1);
+          exit_flag=1;
         }
 
-        if (dB_fixed(en0)>32) {
+        if (dBEn0>30) {
           sprintf(buffer, "rach_dBm:%d",rach_dBm);
 
-          if (prach[0]!= NULL) LOG_M("prach_rx","prach_rx",prach[0],fp->samples_per_tti,1,1);
+          if (prach[0]!= NULL) LOG_M("prach_rx.m","prach_rx",prach[0],fp->samples_per_tti,1,1);
 
           LOG_I(PHY,"RU %d, br_flag %d ce_level %d frame %d subframe %d per_tti:%d prach:%p (energy %d) TA:%d %s rxdata:%p index:%d\n",
                 ru->idx,br_flag,ce_level,frame_prach,subframe,fp->samples_per_tti,
-                prach[aa],dbEn0,ru->N_TA_offset,buffer,ru->common.rxdata[aa],
+                prach[aa],dBEn0,ru->N_TA_offset,buffer,ru->common.rxdata[aa],
                 (subframe*fp->samples_per_tti)-ru->N_TA_offset);
         }
       }
@@ -415,7 +416,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
     if ( LOG_DEBUGFLAG(PRACH)) {
       int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-      if ((en > 60)&&(br_flag==1)) LOG_I(PHY,"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",br_flag,ce_level,n_ra_prb,k,frame_prach,subframe,en);
+      if ((en > 10)&&(br_flag==1)) LOG_I(PHY,"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",br_flag,ce_level,n_ra_prb,k,frame_prach,subframe,en);
     }
   }
 
@@ -454,9 +455,9 @@ void rx_prach0(PHY_VARS_eNB *eNB,
 
   for (preamble_index=0 ; preamble_index<64 ; preamble_index++) {
     if (LOG_DEBUGFLAG(PRACH)) {
-      int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
+    //  int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-      if (en>60) LOG_I(PHY,"frame %d, subframe %d : Trying preamble %d (br_flag %d)\n",frame_prach,subframe,preamble_index,br_flag);
+      if (dBEn0>30) LOG_I(PHY,"frame %d, subframe %d : Trying preamble %d (br_flag %d)\n",frame_prach,subframe,preamble_index,br_flag);
     }
 
     if (restricted_set == 0) {
@@ -539,10 +540,10 @@ void rx_prach0(PHY_VARS_eNB *eNB,
 
     // Compute DFT of RX signal (conjugate input, results in conjugate output) for each new rootSequenceIndex
     if (LOG_DEBUGFLAG(PRACH)) {
-      int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
+      //en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-      if (en>60) LOG_I(PHY,"frame %d, subframe %d : preamble index %d: offset %d, preamble shift %d (br_flag %d, en %d)\n",
-                         frame_prach,subframe,preamble_index,preamble_offset,preamble_shift,br_flag,en);
+      if (dBEn0>30) LOG_I(PHY,"frame %d, subframe %d : preamble index %d: offset %d, preamble shift %d (br_flag %d, en %d)\n",
+                         frame_prach,subframe,preamble_index,preamble_offset,preamble_shift,br_flag,dBEn0);
     }
 
     log2_ifft_size = 10;
@@ -564,13 +565,13 @@ void rx_prach0(PHY_VARS_eNB *eNB,
 
       memset(prachF, 0, sizeof(int16_t)*2*1024 );
 
-      if (LOG_DUMPFLAG(PRACH)) {
+    if (LOG_DUMPFLAG(PRACH)) {
         if (prach[0]!= NULL) LOG_M("prach_rx0.m","prach_rx0",prach[0],6144+792,1,1);
 
         LOG_M("prach_rx1.m","prach_rx1",prach[1],6144+792,1,1);
         LOG_M("prach_rxF0.m","prach_rxF0",rxsigF[0],12288,1,1);
         LOG_M("prach_rxF1.m","prach_rxF1",rxsigF[1],12288,1,1);
-      }
+    }
 
       for (aa=0; aa<nb_rx; aa++) {
         // Do componentwise product with Xu* on each antenna
@@ -633,9 +634,9 @@ void rx_prach0(PHY_VARS_eNB *eNB,
           *max_preamble         = preamble_index;
 
           if (LOG_DEBUGFLAG(PRACH)) {
-            int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
+        //    int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-            if ((en>60) && (br_flag==1))
+            if (dBEn0>30)
               LOG_D(PHY,"frame %d, subframe %d : max_preamble_energy %d, max_preamble_delay %d, max_preamble %d (br_flag %d,ce_level %d, levdB %d, lev %d)\n",
                     frame_prach,subframe,
                     *max_preamble_energy,*max_preamble_delay,
@@ -648,10 +649,10 @@ void rx_prach0(PHY_VARS_eNB *eNB,
 
   *avg_preamble_energy=dB_fixed(avg_en/64);
 
-  if (LOG_DUMPFLAG(PRACH)) {
+  if (exit_flag==1) {
     int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-    if (en>60) {
+    if (en>30) {
       k = (12*n_ra_prb) - 6*fp->N_RB_UL;
 
       if (k<0) k+=fp->ofdm_symbol_size;
@@ -665,19 +666,20 @@ void rx_prach0(PHY_VARS_eNB *eNB,
         LOG_M("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1);
         LOG_M("Xu.m","xu",Xu,N_ZC,1,1);
         LOG_M("prach_ifft0.m","prach_t0",prach_ifft,1024,1,1);
-        exit(-1);
+        LOG_M("SF2_3.m","sf2_3",&ru->common.rxdata[0][2*fp->samples_per_tti],2*fp->samples_per_tti,1,1);
       } else {
         LOG_E(PHY,"Dumping prach (br_flag %d), k = %d (n_ra_prb %d)\n",br_flag,k,n_ra_prb);
         LOG_M("rxsigF_br.m","prach_rxF_br",&rxsigF[0][0],12288,1,1);
         LOG_M("prach_rxF_comp0_br.m","prach_rxF_comp0_br",prachF,1024,1,1);
         LOG_M("Xu_br.m","xu_br",Xu,N_ZC,1,1);
         LOG_M("prach_ifft0_br.m","prach_t0_br",prach_ifft,1024,1,1);
-        exit(-1);
       }
     }
   } /* LOG_DUMPFLAG(PRACH) */
 
   if (eNB) stop_meas(&eNB->rx_prach);
+  AssertFatal(exit_flag==0,"exiting\n");
+
 }
 
 
diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c
index 92aea419af0064e43a0083b208c1183c7008a4fc..2d86b46742449b308ee24c93de1225b5ebe19a66 100644
--- a/openair1/PHY/MODULATION/ofdm_mod.c
+++ b/openair1/PHY/MODULATION/ofdm_mod.c
@@ -90,9 +90,8 @@ void PHY_ofdm_mod(int *input,                       /// pointer to complex input
 
   if(nb_symbols == 0) return;
 
-  short temp[2*2*6144*4] __attribute__((aligned(32)));
-  unsigned short i,j;
-  short k;
+  int16_t temp[2*2*6144*4] __attribute__((aligned(32)));
+  int i,j;
 
   volatile int *output_ptr=(int*)0;
 
@@ -190,18 +189,9 @@ void PHY_ofdm_mod(int *input,                       /// pointer to complex input
       if (fftsize==128) 
 #endif
       {
-        /*for (j=0; j<fftsize ; j++) {
-          output_ptr[j] = temp_ptr[j];
-        }*/
-        memcpy1((void*)output_ptr,(void*)temp_ptr,fftsize<<2);
+        memcpy((void*)output_ptr,(void*)temp_ptr,fftsize<<2);
       }
-
-      j=fftsize;
-
-      for (k=-1; k>=-nb_prefix_samples; k--) {
-        output_ptr[k] = output_ptr[--j];
-      }
-
+      memcpy((void*)&output_ptr[-nb_prefix_samples],(void*)&output_ptr[fftsize-nb_prefix_samples],nb_prefix_samples<<2);
       break;
 
     case CYCLIC_SUFFIX:
diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c
index 143871e2be09839394e1be128ae0055880df67be..4b36180b58f73fd42a7b38c56b52ba54fd877857 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c
@@ -33,12 +33,12 @@
 // last channel estimate of the receiver
 
 void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
-                      PHY_VARS_NR_UE *ue,
-                      module_id_t gNB_id,
-                      uint8_t frame,
-                      uint8_t subframe,
-                      unsigned char clear,
-                      short coef)
+                        PHY_VARS_NR_UE *ue,
+                        module_id_t gNB_id,
+                        uint8_t frame,
+                        uint8_t subframe,
+                        unsigned char clear,
+                        short coef)
 {
 
   static int max_pos_fil = 0;
@@ -47,6 +47,7 @@ void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
   int temp = 0, i, aa, max_val = 0, max_pos = 0;
   int diff;
   short Re,Im,ncoef;
+  uint8_t sync_offset = 0;
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_IN);
 
@@ -80,11 +81,14 @@ void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
   // do not filter to have proactive timing adjustment
   //max_pos_fil = max_pos;
 
-  if(subframe == 0)
-  {
       diff = max_pos_fil - (frame_parms->nb_prefix_samples>>3);
 
-      if ( abs(diff) < SYNCH_HYST )
+      if (frame_parms->freq_range==nr_FR2) 
+		sync_offset = 2;
+      else
+		sync_offset = 0;
+	
+      if ( abs(diff) < (SYNCH_HYST+sync_offset) )
           ue->rx_offset = 0;
       else
           ue->rx_offset = diff;
@@ -134,5 +138,5 @@ void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
       #endif //DEBUG_PHY
 
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_OUT);
-  }
+
 }
diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c
index 4757872c28922cdb190c19aeff69e3c2070f25b9..971db724c6d107d2068fdcd08c198d32e5fc706f 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c
@@ -243,7 +243,7 @@ void nr_ue_rsrp_measurements(PHY_VARS_NR_UE *ue,
 	unsigned int  ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier;
 	if (ssb_offset>= ue->frame_parms.ofdm_symbol_size) ssb_offset-=ue->frame_parms.ofdm_symbol_size;
 	
-	symbol_offset = ue->frame_parms.ofdm_symbol_size*(ue->symbol_offset+1);
+	symbol_offset = ue->frame_parms.ofdm_symbol_size*((ue->symbol_offset+1)%(ue->frame_parms.symbols_per_slot));
 
     ue->measurements.rsrp[eNB_offset] = 0;
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
index fbf17790097f22f025eb07e7d955296ca023d00e..03681a57720fadc351adfbe46022227baacec6ee 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
@@ -375,7 +375,10 @@ void nr_pdcch_extract_rbs_single(int32_t **rxdataF,
     for (int rb=0;rb<coreset_nbr_rb;rb++,c_rb++) {
       c_rb_by6 = c_rb/6;
       // skip zeros in frequency domain bitmap
-      while ((coreset_freq_dom[c_rb_by6>>3] & (1<<(c_rb_by6&7))) == 0) c_rb+=6;
+      while ((coreset_freq_dom[c_rb_by6>>3] & (1<<(7-(c_rb_by6&7)))) == 0) {
+	  c_rb+=6;
+	  c_rb_by6 = c_rb/6;
+	}
 
       LOG_DDD("c_rb=%d\n",c_rb);
       rxF=NULL;
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
index 460dcfadb07648a7a6a946f29f9a7a730a54ea3b..b5ab563c2695b51fe4ba1c35ca79487c3f005ee2 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
@@ -304,8 +304,11 @@ int nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, runmode_t mode,
       if (ret == 0) {
         // sync at symbol ue->symbol_offset
         // computing the offset wrt the beginning of the frame
-        sync_pos_frame = (fp->ofdm_symbol_size + fp->nb_prefix_samples0)+((ue->symbol_offset)-1)*(fp->ofdm_symbol_size + fp->nb_prefix_samples);
-
+        int mu = fp->numerology_index;
+        // number of symbols with different prefix length
+        // every 7*(1<<mu) symbols there is a different prefix length (38.211 5.3.1)
+        int n_symb_prefix0 = (ue->symbol_offset/(7*(1<<mu)))+1;
+        sync_pos_frame = n_symb_prefix0*(fp->ofdm_symbol_size + fp->nb_prefix_samples0)+(ue->symbol_offset-n_symb_prefix0)*(fp->ofdm_symbol_size + fp->nb_prefix_samples);
         if (ue->ssb_offset < sync_pos_frame)
           ue->rx_offset = fp->samples_per_frame - sync_pos_frame + ue->ssb_offset;
         else
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
index 813e737563ad2dd9358744dbeb35d19f0fb386af..4d21fe782bce86371c899ebf9090c18b8571fff9 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
@@ -62,7 +62,7 @@ uint16_t nr_pbch_extract(int **rxdataF,
   unsigned int  rx_offset = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier; //and
 
  // if (rx_offset>= frame_parms->ofdm_symbol_size) rx_offset-=frame_parms->ofdm_symbol_size;
-          rx_offset=(rx_offset)%(frame_parms->ofdm_symbol_size);
+ rx_offset=(rx_offset)%(frame_parms->ofdm_symbol_size);
 
   AssertFatal(symbol>=1 && symbol<5,
               "symbol %d illegal for PBCH extraction\n",
@@ -538,6 +538,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
   M =  NR_POLAR_PBCH_E;
   nushift = (Lmax==4)? i_ssb&3 : i_ssb&7;
   uint32_t unscrambling_mask = (Lmax==64)?0x100006D:0x1000041;
+
   nr_pbch_unscrambling(nr_ue_pbch_vars,frame_parms->Nid_cell,nushift,M,NR_POLAR_PBCH_E,0,0);
   //polar decoding de-rate matching
   const t_nrPolar_params *currentPtr = nr_polar_params( NR_POLAR_PBCH_MESSAGE_TYPE, NR_POLAR_PBCH_PAYLOAD_BITS, NR_POLAR_PBCH_AGGREGATION_LEVEL,1,&ue->polarList);
diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h
index 557b8bfc30e0108105f79f7d3328ee6bf2b05bc7..f1021ead9b2ab9fb2bc36a4e59e051e492aec26a 100644
--- a/openair1/PHY/defs_eNB.h
+++ b/openair1/PHY/defs_eNB.h
@@ -389,6 +389,8 @@ typedef struct {
   short n0_subband_power_tot_dB[100];
   //! estimated avg noise power per RB (dBm)
   short n0_subband_power_tot_dBm[100];
+  //! etimated avg noise power over all RB (dB)
+  short n0_subband_power_avg_dB;
   // eNB measurements (per user)
   //! estimated received spatial signal power (linear)
   unsigned int   rx_spatial_power[NUMBER_OF_UE_MAX][2][2];
diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h
index 8bf585ad934d71d36a62ae6c1c1cbbf4a4682de8..08b54c5c986926fa9861e60b9387faaef35839a5 100644
--- a/openair1/PHY/defs_nr_common.h
+++ b/openair1/PHY/defs_nr_common.h
@@ -229,7 +229,7 @@ typedef struct {
   /// Pointer to Msg3 payload for UL-grant
   uint8_t *Msg3;
   /// Frame of last completed synch
-  uint8_t sync_frame;
+  uint16_t sync_frame;
   /// Flag to indicate that prach is ready to start: it is enabled with an initial delay after the sync
   uint8_t init_msg1;
 } NR_PRACH_RESOURCES_t;
diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c
index 5f0ff6cff09d71602204424d2604f776e3019b41..a37f95bcb341b7d7470d6606003d91e1a08b7d3e 100644
--- a/openair1/SCHED/phy_procedures_lte_eNb.c
+++ b/openair1/SCHED/phy_procedures_lte_eNb.c
@@ -757,8 +757,8 @@ void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int
   //  pdu->rx_ue_information.handle                       = handle;
   pdu->rx_ue_information.tl.tag                       = NFAPI_RX_UE_INFORMATION_TAG;
   pdu->rx_ue_information.rnti                         = rnti;
-  int SNRtimes10 = dB_fixed_times10(stat) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
-  LOG_D(PHY,"stat %d subbandpower %d, SNRtimes10 %d\n", stat, eNB->measurements.n0_subband_power_dB[0][0], SNRtimes10);
+  int SNRtimes10 = dB_fixed_times10(stat) - 10 * eNB->measurements.n0_subband_power_avg_dB;
+  LOG_D(PHY,"stat %d subband n0 %d, SNRtimes10 %d\n", stat, eNB->measurements.n0_subband_power_avg_dB, SNRtimes10);
   pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
 
   if      (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0;
@@ -1604,8 +1604,8 @@ void fill_rx_indication(PHY_VARS_eNB *eNB,
     timing_advance_update = 63;
 
   pdu->rx_indication_rel8.timing_advance = timing_advance_update;
-  // estimate UL_CQI for MAC (from antenna port 0 only)
-  int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0]) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
+  // estimate UL_CQI for MAC 
+  int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0] + ((eNB->frame_parms.nb_antennas_rx>1) ?eNB->pusch_vars[UE_id]->ulsch_power[1] : 0 )) - 10 * eNB->measurements.n0_subband_power_avg_dB;
 
   if (SNRtimes10 < -640)
     pdu->rx_indication_rel8.ul_cqi = 0;
@@ -1614,8 +1614,8 @@ void fill_rx_indication(PHY_VARS_eNB *eNB,
   else
     pdu->rx_indication_rel8.ul_cqi = (640 + SNRtimes10) / 5;
 
-  LOG_D(PHY,"[PUSCH %d] Frame %d Subframe %d Filling RX_indication with SNR %d (%d), timing_advance %d (update %d)\n",
-        harq_pid,frame,subframe,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,pdu->rx_indication_rel8.timing_advance,
+  LOG_D(PHY,"[PUSCH %d] Frame %d Subframe %d Filling RX_indication with SNR %d (%d,%d), timing_advance %d (update %d)\n",
+        harq_pid,frame,subframe,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,eNB->measurements.n0_subband_power_avg_dB,pdu->rx_indication_rel8.timing_advance,
         timing_advance_update);
   eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus++;
   eNB->UL_INFO.rx_ind.sfn_sf = frame<<4 | subframe;
@@ -1919,7 +1919,7 @@ void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, in
   pdu->rx_ue_information.rnti                         = uci->rnti;
   // estimate UL_CQI for MAC (from antenna port 0 only)
   pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
-  int SNRtimes10 = dB_fixed_times10(uci->stat) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
+  int SNRtimes10 = dB_fixed_times10(uci->stat) - 10 * eNB->measurements.n0_subband_power_avg_dB;
 
   if (SNRtimes10 < -100)
     LOG_I (PHY, "uci->stat %d \n", uci->stat);
@@ -2132,17 +2132,17 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
 
   lte_eNB_I0_measurements (eNB, subframe, 0, eNB->first_run_I0_measurements);
   int min_I0=1000,max_I0=0;
-
-  if ((frame==0) && (subframe==4)) {
+  int amin=0,amax=0;
+  if ((frame==0) && (subframe==3)) {
     for (int i=0; i<eNB->frame_parms.N_RB_UL; i++) {
       if (i==(eNB->frame_parms.N_RB_UL>>1) - 1) i+=2;
 
-      if (eNB->measurements.n0_subband_power_tot_dB[i]<min_I0) min_I0 = eNB->measurements.n0_subband_power_tot_dB[i];
+      if (eNB->measurements.n0_subband_power_tot_dB[i]<min_I0) {min_I0 = eNB->measurements.n0_subband_power_tot_dB[i]; amin=i;}
 
-      if (eNB->measurements.n0_subband_power_tot_dB[i]>max_I0) max_I0 = eNB->measurements.n0_subband_power_tot_dB[i];
+      if (eNB->measurements.n0_subband_power_tot_dB[i]>max_I0) {max_I0 = eNB->measurements.n0_subband_power_tot_dB[i]; amax=i;}
     }
 
-    LOG_I (PHY, "max_I0 %d, min_I0 %d\n", max_I0, min_I0);
+    LOG_I (PHY, "max_I0 %d (rb %d), min_I0 %d (rb %d), avg I0 %d\n", max_I0, amax, min_I0, amin, eNB->measurements.n0_subband_power_avg_dB);
   }
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 0 );
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index 5238fb8f97c2a246ae83393894a89083068f4c97..ed8b64f673cf519ca70767eb13bf38a52f9d0e03 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -312,7 +312,6 @@ void nr_ue_pbch_procedures(uint8_t gNB_id,
 {
   //  int i;
   //int pbch_tx_ant=0;
-  //uint8_t pbch_phase;
   int ret = 0;
   //static uint8_t first_run = 1;
   //uint8_t pbch_trials = 0;
@@ -324,7 +323,7 @@ void nr_ue_pbch_procedures(uint8_t gNB_id,
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_IN);
 
-  //LOG_I(PHY,"[UE  %d] Frame %d, Trying PBCH %d (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,pbch_phase,ue->frame_parms.Nid_cell,gNB_id);
+  LOG_D(PHY,"[UE  %d] Frame %d, Trying PBCH (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,ue->frame_parms.Nid_cell,gNB_id);
 
   ret = nr_rx_pbch(ue, proc,
 		   ue->pbch_vars[gNB_id],
@@ -1728,7 +1727,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
   int frame_rx = proc->frame_rx;
   int nr_slot_rx = proc->nr_slot_rx;
   int slot_pbch;
-  //int slot_ssb;
+  int slot_ssb;
   NR_UE_PDCCH *pdcch_vars  = ue->pdcch_vars[proc->thread_id][0];
   fapi_nr_config_request_t *cfg = &ue->nrUE_config;
 
@@ -1752,38 +1751,38 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
 
   if (pdcch_vars->nb_search_space > 0)
     get_coreset_rballoc(pdcch_vars->pdcch_config[0].coreset.frequency_domain_resource,&coreset_nb_rb,&coreset_start_rb);
-  
+
   slot_pbch = is_pbch_in_slot(cfg, frame_rx, nr_slot_rx, fp);
-  //slot_ssb = is_ssb_in_slot(cfg, frame_rx, nr_slot_rx, fp);
+  slot_ssb  = is_ssb_in_slot(cfg, frame_rx, nr_slot_rx, fp);
 
   // looking for pbch only in slot where it is supposed to be
-  if ((ue->decode_MIB == 1) && slot_pbch)
-    {
-      LOG_D(PHY," ------  PBCH ChannelComp/LLR: frame.slot %d.%d ------  \n", frame_rx%1024, nr_slot_rx);
-      for (int i=1; i<4; i++) {
+  if (slot_ssb) {
+    LOG_D(PHY," ------  PBCH ChannelComp/LLR: frame.slot %d.%d ------  \n", frame_rx%1024, nr_slot_rx);
+    for (int i=1; i<4; i++) {
 
-        nr_slot_fep(ue,
-                    proc,
-                    (ue->symbol_offset+i)%(fp->symbols_per_slot),
-                    nr_slot_rx,
-                    0,
-                    0);
+      nr_slot_fep(ue,
+                  proc,
+                  (ue->symbol_offset+i)%(fp->symbols_per_slot),
+                  nr_slot_rx,
+                  0,
+                  0);
 
 #if UE_TIMING_TRACE
-        start_meas(&ue->dlsch_channel_estimation_stats);
+      start_meas(&ue->dlsch_channel_estimation_stats);
 #endif
-        nr_pbch_channel_estimation(ue,proc,0,nr_slot_rx,(ue->symbol_offset+i)%(fp->symbols_per_slot),i-1,(fp->ssb_index)&7,fp->half_frame_bit);
+      nr_pbch_channel_estimation(ue,proc,0,nr_slot_rx,(ue->symbol_offset+i)%(fp->symbols_per_slot),i-1,(fp->ssb_index)&7,fp->half_frame_bit);
 #if UE_TIMING_TRACE
-        stop_meas(&ue->dlsch_channel_estimation_stats);
+      stop_meas(&ue->dlsch_channel_estimation_stats);
 #endif
+    }
 
-      }
-      
-      //if (mac->csirc->reportQuantity.choice.ssb_Index_RSRP){ 
-        nr_ue_rsrp_measurements(ue, proc, nr_slot_rx, 0);
-      //}
-	
+    //if (mac->csirc->reportQuantity.choice.ssb_Index_RSRP){
+    nr_ue_rsrp_measurements(ue,proc,nr_slot_rx,0);
+    //}
+
+    if ((ue->decode_MIB == 1) && slot_pbch) {
 
+      LOG_D(PHY," ------  Decode MIB: frame.slot %d.%d ------  \n", frame_rx%1024, nr_slot_rx);
       nr_ue_pbch_procedures(gNB_id, ue, proc, 0);
 
       if (ue->no_timing_correction==0) {
@@ -1797,6 +1796,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
                            16384);
       }
     }
+  }
 
   if ((frame_rx%64 == 0) && (nr_slot_rx==0)) {
     printf("============================================\n");
@@ -2186,7 +2186,7 @@ void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_IN);
 
-  if (!prach_resources->init_msg1 && (frame_tx == (ue->prach_resources[gNB_id]->sync_frame + 150) % MAX_FRAME_NUMBER)){
+  if (!prach_resources->init_msg1 && ((MAX_FRAME_NUMBER+frame_tx-ue->prach_resources[gNB_id]->sync_frame)% MAX_FRAME_NUMBER)>150){
     ue->prach_cnt = 0;
     prach_resources->init_msg1 = 1;
   }
diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c
index 12aace577c72e1f8aa7b34c7022f46cf71c02706..d3f55785c9f7e9940b70c6d46dc99d1c3bfc009b 100644
--- a/openair1/SIMULATION/LTE_PHY/dlsim.c
+++ b/openair1/SIMULATION/LTE_PHY/dlsim.c
@@ -487,7 +487,7 @@ int n_ch_rlz = 1;
 int rx_sample_offset = 0;
 int xforms=0;
 int dump_table=0;
-int loglvl=OAILOG_WARNING;
+int loglvl=OAILOG_INFO;
 int mcs1=0,mcs2=0,mcs_i=0,dual_stream_UE = 0,awgn_flag=0;
 int two_thread_flag=0;
 int num_rounds = 4;//,fix_rounds=0;
@@ -670,7 +670,7 @@ int main(int argc, char **argv) {
     { "XForms", "Display the soft scope", PARAMFLAG_BOOL, iptr:&xforms,  defintval:0, TYPE_INT, 0 },
     { "Yperfect_ce","Perfect CE", PARAMFLAG_BOOL, iptr:&perfect_ce,  defintval:0, TYPE_INT, 0 },
     { "Zdump", "dump table",PARAMFLAG_BOOL,  iptr:&dump_table, defintval:0, TYPE_INT, 0 },
-    { "Loglvl", "log level",0, iptr:&loglvl,  defintval:OAILOG_DEBUG, TYPE_INT, 0 },
+    { "Loglvl", "log level",0, iptr:&loglvl,  defintval:OAILOG_INFO, TYPE_INT, 0 },
     { "zn_rx", "Number of RX antennas used in UE",0, iptr:NULL,  defintval:2, TYPE_INT, 0 },
     { "gchannel", "[A:M] Use 3GPP 25.814 SCM-A/B/C/D('A','B','C','D') or 36-101 EPA('E'), EVA ('F'),ETU('G') models (ignores delay spread and Ricean factor), Rayghleigh8 ('H'), Rayleigh1('I'), Rayleigh1_corr('J'), Rayleigh1_anticorr ('K'),  Rice8('L'), Rice1('M')",0, strptr:NULL,  defstrval:NULL, TYPE_STRING, 0 },
     { "verbose", "display debug text", PARAMFLAG_BOOL,  iptr:&verbose, defintval:0, TYPE_INT, 0 },
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index 34501aace71f221e2da7fd6878f209e9eda6cf8a..a26a25e6e7af7b052b0ecf761e13865043d2e8df 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -864,7 +864,6 @@ int main(int argc, char **argv)
 
 
         UE_info->UE_sched_ctrl[0].harq_processes[harq_pid].round = round;
-        UE_info->UE_sched_ctrl[0].current_harq_pid = harq_pid;
         gNB->dlsch[0][0]->harq_processes[harq_pid]->round = round;
         for (int i=0; i<MAX_NUM_CORESET; i++)
           gNB_mac->UE_info.num_pdcch_cand[0][i] = 0;
@@ -882,7 +881,7 @@ int main(int argc, char **argv)
         Sched_INFO.frame     = frame;
         Sched_INFO.slot      = slot;
         Sched_INFO.DL_req    = &gNB_mac->DL_req[0];
-        Sched_INFO.UL_tti_req    = &gNB_mac->UL_tti_req[0];
+        Sched_INFO.UL_tti_req    = gNB_mac->UL_tti_req_ahead[slot];
         Sched_INFO.UL_dci_req  = NULL;
         Sched_INFO.TX_req    = &gNB_mac->TX_req[0];
         nr_schedule_response(&Sched_INFO);
diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c
index 9ad41d543241d129322f6f2167b4ae33e061365b..3785ded9e93abbec1098f4ea0f960ec01fa8fd3b 100644
--- a/openair2/GNB_APP/gnb_config.c
+++ b/openair2/GNB_APP/gnb_config.c
@@ -233,8 +233,8 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) {
       scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] |= curr_bit<<i;   
     }
   }else if(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap){
-	  scc->ssb_PositionsInBurst->choice.mediumBitmap.size = 1;
-	  scc->ssb_PositionsInBurst->choice.mediumBitmap.bits_unused = 0;
+    scc->ssb_PositionsInBurst->choice.mediumBitmap.size = 1;
+    scc->ssb_PositionsInBurst->choice.mediumBitmap.bits_unused = 0;
     scc->ssb_PositionsInBurst->choice.mediumBitmap.buf = CALLOC(1,1);
     scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] = 0;
     for (int i=0; i<8; i++)
@@ -244,10 +244,10 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) {
     scc->ssb_PositionsInBurst->choice.longBitmap.bits_unused = 0;
     scc->ssb_PositionsInBurst->choice.longBitmap.buf = CALLOC(1,8);
     for (int j=0; j<8; j++) {
-       scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-j] = 0;
+       scc->ssb_PositionsInBurst->choice.longBitmap.buf[j] = 0;
        curr_bit = (ssbmap>>(j<<3))&(0xff);
        for (int i=0; i<8; i++)
-         scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-j] |= (((curr_bit>>(7-i))&0x01)<<i);
+         scc->ssb_PositionsInBurst->choice.longBitmap.buf[j] |= (((curr_bit>>(7-i))&0x01)<<i);
     }
   }
 
diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h
index 1e8156c23925de1bdfb585cdc79d547e4ae45f0b..981f2ba193d726934ea45921ccefac80f6a71b1a 100644
--- a/openair2/GNB_APP/gnb_paramdef.h
+++ b/openair2/GNB_APP/gnb_paramdef.h
@@ -82,6 +82,7 @@ typedef enum {
 /* global parameters, not under a specific section   */
 #define GNB_CONFIG_STRING_ASN1_VERBOSITY                   "Asn1_verbosity"
 #define GNB_CONFIG_STRING_ACTIVE_GNBS                      "Active_gNBs"
+#define GNB_CONFIG_PUSCH_THREADS                           "Num_Threads_PUSCH"
 /*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/
 /*                                            global configuration parameters                                                                                   */
 /*   optname                                   helpstr   paramflags    XXXptr        defXXXval                                        type           numelt     */
@@ -90,6 +91,11 @@ typedef enum {
 {GNB_CONFIG_STRING_ASN1_VERBOSITY,             NULL,     0,        uptr:NULL,   defstrval:GNB_CONFIG_STRING_ASN1_VERBOSITY_NONE,   TYPE_STRING,      0},   \
 {GNB_CONFIG_STRING_ACTIVE_GNBS,                NULL,     0,        uptr:NULL,   defstrval:NULL, 				   TYPE_STRINGLIST,  0}    \
 }
+
+#define NUM_THREADS_DESC { \
+{GNB_CONFIG_PUSCH_THREADS,                     NULL,     0,        uptr:&num_threads_pusch,   defuintval:1, 				   TYPE_UINT,  0}    \
+}
+
 #define GNB_ASN1_VERBOSITY_IDX                     0
 #define GNB_ACTIVE_GNBS_IDX                        1
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
index 997fc6691e7da517f8430319029e7ef62b8a76f2..b62df74082faa98060dbede5563095dd0cd5b9ed 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
@@ -182,7 +182,7 @@ rx_sdu(const module_id_t enb_mod_idP,
         UE_template_ptr->scheduled_ul_bytes = 0;
       }
     } else {  // sduP == NULL => error
-      LOG_W(MAC, "[eNB %d][PUSCH %d] CC_id %d %d.%d ULSCH in error in round %d, ul_cqi %d, UE_id %d, RNTI %x (len %d)\n",
+      LOG_D(MAC, "[eNB %d][PUSCH %d] CC_id %d %d.%d ULSCH in error in round %d, ul_cqi %d, UE_id %d, RNTI %x (len %d)\n",
             enb_mod_idP,
             harq_pid,
             CC_idP,
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
index 12245a96d0b461cdd2e847cef6339f209ec6c162..bd124a74300c9e4b8dd2b9086dd3126b70984036 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
@@ -1006,14 +1006,22 @@ int64_t table_6_3_3_2_4_prachConfig_Index [256][10] = {
 
 
 int get_format0(uint8_t index,
-                uint8_t unpaired){
+                uint8_t unpaired,
+		frequency_range_t frequency_range){
 
   uint16_t format;
-  if (unpaired)
-    format = table_6_3_3_2_3_prachConfig_Index[index][0];
-  else
-    format = table_6_3_3_2_2_prachConfig_Index[index][0];
-
+  if (unpaired) {
+    if (frequency_range==FR1)
+      format = table_6_3_3_2_3_prachConfig_Index[index][0];
+    else
+      format = table_6_3_3_2_4_prachConfig_Index[index][0];
+  }
+  else {
+    if (frequency_range==FR1)
+      format = table_6_3_3_2_2_prachConfig_Index[index][0];
+    else
+      AssertFatal(0==1,"no paired spectrum for FR2\n");
+  }
   return format;
 }
 
@@ -1471,11 +1479,12 @@ uint16_t table_63313[838] = {
 
 uint8_t compute_nr_root_seq(NR_RACH_ConfigCommon_t *rach_config,
                             uint8_t nb_preambles,
-                            uint8_t unpaired) {
+                            uint8_t unpaired,
+			    frequency_range_t frequency_range) {
 
   uint8_t config_index = rach_config->rach_ConfigGeneric.prach_ConfigurationIndex;
   uint8_t ncs_index = rach_config->rach_ConfigGeneric.zeroCorrelationZoneConfig;
-  uint16_t format0 = get_format0(config_index, unpaired);
+  uint16_t format0 = get_format0(config_index, unpaired, frequency_range);
   uint16_t NCS = get_NCS(ncs_index, format0, rach_config->restrictedSetConfig);
   uint16_t L_ra = (rach_config->prach_RootSequenceIndex.present==NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l139) ? 139 : 839;
   uint16_t r,u,index,q,d_u,n_shift_ra,n_shift_ra_bar,d_start;
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
index e28fb1a231b76dd07886da86a338e18438e919e1..e0bf63a8d30899cfba792be7ad6e19c33a4bc2b6 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
@@ -59,6 +59,11 @@
 #define MAX_TDM (7) // Maximum nb of PRACH occasions TDMed in a slot
 #define MAX_FDM (8) // Maximum nb of PRACH occasions FDMed in a slot
 
+typedef enum frequency_range_e {
+    FR1 = 0, 
+    FR2
+} frequency_range_t;
+
 // PRACH occasion details
 typedef struct prach_occasion_info {
   uint8_t start_symbol; // 0 - 13 (14 symbols in a slot)
@@ -225,11 +230,12 @@ uint8_t get_pusch_mcs_table(long *mcs_Table,
 
 uint8_t compute_nr_root_seq(NR_RACH_ConfigCommon_t *rach_config,
                             uint8_t nb_preambles,
-                            uint8_t unpaired);
+                            uint8_t unpaired,
+			    frequency_range_t);
 
 int ul_ant_bits(NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig,long transformPrecoder);
 
-int get_format0(uint8_t index, uint8_t unpaired);
+int get_format0(uint8_t index, uint8_t unpaired,frequency_range_t);
 
 int64_t *get_prach_config_info(uint32_t pointa,
                                uint8_t index,
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h
index 50918b2e760ae0af59e155468c4f1e413857185e..8f7a726bb8f94dc29b3c17a12f439ba292ee773d 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h
@@ -37,6 +37,8 @@
 
 /*#include "PHY/defs_common.h"*/
 
+extern const uint8_t nr_slots_per_frame[5];
+
 /* extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE];
 extern const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE];
 extern const uint8_t cqi2fmt0_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE];
diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c
index 828b05c9fc42f15179bff5b09639cbb07e5a6d27..49780039a0304c05d1a682353ff53146f55e84ee 100755
--- a/openair2/LAYER2/NR_MAC_UE/config_ue.c
+++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c
@@ -147,7 +147,6 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
   fapi_nr_config_request_t        *cfg = &mac->phy_config.config_req;
   NR_ServingCellConfigCommon_t    *scc = mac->scc;
   int i;
-  lte_frame_type_t frame_type;
 
   mac->phy_config.Mod_id = module_id;
   mac->phy_config.CC_id = cc_idP;
@@ -201,6 +200,10 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
     }
   }
 
+  uint32_t band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
+  frequency_range_t  frequency_range = band<100?FR1:FR2;
+ 
+  lte_frame_type_t frame_type;
   get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing, &frame_type);
 
   // cell config
@@ -236,8 +239,8 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
       cfg->ssb_table.ssb_mask_list[0].ssb_mask = 0;
       cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0;
       for (i=0; i<4; i++) {
-        cfg->ssb_table.ssb_mask_list[0].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]<<i*8);
-        cfg->ssb_table.ssb_mask_list[1].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<<i*8);
+        cfg->ssb_table.ssb_mask_list[0].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[3-i]<<i*8);
+        cfg->ssb_table.ssb_mask_list[1].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-i]<<i*8);
       }
       break;
     default:
@@ -310,7 +313,7 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
 
     cfg->prach_config.num_prach_fd_occasions_list[i].k1 = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FrequencyStart;
     cfg->prach_config.num_prach_fd_occasions_list[i].prach_zero_corr_conf = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig;
-    cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences = compute_nr_root_seq(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup, nb_preambles, frame_type);
+    cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences = compute_nr_root_seq(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup, nb_preambles, frame_type,frequency_range);
     //cfg->prach_config.num_prach_fd_occasions_list[i].num_unused_root_sequences = ???
   }
 
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
index 7bf68f9981961a7ed740cc50f90febe16ff50750..da71f6ed715fb48c5307c8177e150fedcaddc527 100755
--- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
@@ -198,7 +198,7 @@ typedef struct {
   /// Random-access procedure flag
   uint8_t RA_active;
   /// Random-access window counter
-  int8_t RA_window_cnt;
+  int16_t RA_window_cnt;
   /// Random-access Msg3 size in bytes
   uint8_t RA_Msg3_size;
   /// Random-access prachMaskIndex
diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
index 20e73073b9b605e80fcccad687953545944bf059..bbe26a51e2506bcd15c4dec8342324602cf5474c 100644
--- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
+++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
@@ -37,8 +37,6 @@
 #include "assertions.h"
 #include "PHY/types.h"
 #include "PHY/defs_UE.h"
-#include "openair2/LAYER2/RLC/rlc.h"
-#include "openair2/LAYER2/PDCP_v10.1.0/pdcp.h"
 #include "openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h"
 #include "executables/softmodem-common.h"
 
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
index 34b6d801c5752f7852b94d08620c5487f9856ee2..be3d7e9e7505cb241d188463f1481e402f0027f3 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
@@ -63,7 +63,6 @@
 #include "LAYER2/NR_MAC_UE/mac_proto.h"
 
 extern int64_t table_6_3_3_2_3_prachConfig_Index [256][9];
-extern const uint8_t nr_slots_per_frame[5];
 
 //extern uint8_t  nfapi_mode;
 
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index 77782e846c5c4338e39a60ab3191e1f9cc3dc3f2..59a182fba6dc15a35057e84a72d0b4ea6a4f0fb3 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -143,7 +143,6 @@ static ssb_list_info_t ssb_list;
 
 extern int bwp_id;
 extern dci_pdu_rel15_t *def_dci_pdu_rel15;
-extern const uint8_t nr_slots_per_frame[5];
 
 extern void mac_rlc_data_ind     (
 				  const module_id_t         module_idP,
@@ -965,36 +964,30 @@ int8_t nr_ue_decode_mib(module_id_t module_id,
   uint16_t frame_number_4lsb = 0;
   for (int i=0; i<4; i++)
     frame_number_4lsb |= ((extra_bits>>i)&1)<<(3-i);
-  //uint8_t half_frame_bit = ( extra_bits >> 4 ) & 0x1;               //	extra bits[4]
+  uint8_t half_frame_bit = ( extra_bits >> 4 ) & 0x1;               //	extra bits[4]
   uint8_t ssb_subcarrier_offset_msb = ( extra_bits >> 5 ) & 0x1;    //	extra bits[5]
   uint8_t ssb_subcarrier_offset = (uint8_t)mac->mib->ssb_SubcarrierOffset;
 
-  //uint32_t ssb_index = 0;    //  TODO: ssb_index should obtain from L1 in case Lssb != 64
-
   frame = frame << 4;
   frame = frame | frame_number_4lsb;
-
   if(ssb_length == 64){
-    ssb_index = ssb_index & (( extra_bits >> 2 ) & 0x1C );    //	{ extra_bits[5:7], ssb_index[2:0] }
+    for (int i=0; i<3; i++)
+      ssb_index += (((extra_bits>>(7-i))&0x01)<<(3+i));
   }else{
     if(ssb_subcarrier_offset_msb){
       ssb_subcarrier_offset = ssb_subcarrier_offset | 0x10;
     }
   }
 
-#ifdef DEBUG_MIB
-  LOG_I(MAC,"system frame number(6 MSB bits): %d\n",  mac->mib->systemFrameNumber.buf[0]);
-  LOG_I(MAC,"system frame number(with LSB): %d\n", (int)frame);
-  LOG_I(MAC,"subcarrier spacing (0=15or60, 1=30or120): %d\n", (int)mac->mib->subCarrierSpacingCommon);
-  LOG_I(MAC,"ssb carrier offset(with MSB):  %d\n", (int)ssb_subcarrier_offset);
-  LOG_I(MAC,"dmrs type A position (0=pos2,1=pos3): %d\n", (int)mac->mib->dmrs_TypeA_Position);
-  LOG_I(MAC,"pdcch config sib1.controlResourceSetZero: %d\n", (int)mac->mib->pdcch_ConfigSIB1.controlResourceSetZero);
-  LOG_I(MAC,"pdcch config sib1.searchSpaceZero: %d\n", (int)mac->mib->pdcch_ConfigSIB1.searchSpaceZero);
-  LOG_I(MAC,"cell barred (0=barred,1=notBarred): %d\n", (int)mac->mib->cellBarred);
-  LOG_I(MAC,"intra frequency reselection (0=allowed,1=notAllowed): %d\n", (int)mac->mib->intraFreqReselection);
-  //LOG_I(MAC,"half frame bit(extra bits):    %d\n", (int)half_frame_bit);
-  LOG_I(MAC,"ssb index(extra bits):         %d\n", (int)ssb_index);
-#endif
+  LOG_D(MAC,"system frame number(6 MSB bits): %d\n",  mac->mib->systemFrameNumber.buf[0]);
+  LOG_D(MAC,"system frame number(with LSB): %d\n", (int)frame);
+  LOG_D(MAC,"subcarrier spacing (0=15or60, 1=30or120): %d\n", (int)mac->mib->subCarrierSpacingCommon);
+  LOG_D(MAC,"ssb carrier offset(with MSB):  %d\n", (int)ssb_subcarrier_offset);
+  LOG_D(MAC,"dmrs type A position (0=pos2,1=pos3): %d\n", (int)mac->mib->dmrs_TypeA_Position);
+  LOG_D(MAC,"cell barred (0=barred,1=notBarred): %d\n", (int)mac->mib->cellBarred);
+  LOG_D(MAC,"intra frequency reselection (0=allowed,1=notAllowed): %d\n", (int)mac->mib->intraFreqReselection);
+  LOG_D(MAC,"half frame bit(extra bits):    %d\n", (int)half_frame_bit);
+  LOG_D(MAC,"ssb index(extra bits):         %d\n", (int)ssb_index);
 
   get_type0_PDCCH_CSS_config_parameters(&mac->type0_PDCCH_CSS_config, mac->mib, extra_bits, ssb_length, ssb_index,
                                         mac->phy_config.config_req.ssb_table.ssb_offset_point_a);
diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c
index 674d30b7945415c306cc08e40bf7f7871b6847a3..bd6a8f3384186e0cbef47c1c24999c13c0b19db0 100644
--- a/openair2/LAYER2/NR_MAC_gNB/config.c
+++ b/openair2/LAYER2/NR_MAC_gNB/config.c
@@ -124,6 +124,9 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
     }
   }
 
+  uint32_t band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
+  frequency_range_t frequency_range = band<100?FR1:FR2;
+
   lte_frame_type_t frame_type;
   get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing, &frame_type);
   RC.nrmac[Mod_idP]->common_channels[0].frame_type = frame_type;
@@ -213,7 +216,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
     cfg->prach_config.num_prach_fd_occasions_list[i].prach_zero_corr_conf.value = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig;
     cfg->prach_config.num_prach_fd_occasions_list[i].prach_zero_corr_conf.tl.tag = NFAPI_NR_CONFIG_PRACH_ZERO_CORR_CONF_TAG;
     cfg->num_tlv++;
-    cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences.value = compute_nr_root_seq(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup,nb_preambles, frame_type);
+    cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences.value = compute_nr_root_seq(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup,nb_preambles, frame_type, frequency_range);
     cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences.tl.tag = NFAPI_NR_CONFIG_NUM_ROOT_SEQUENCES_TAG;
     cfg->num_tlv++;
     cfg->prach_config.num_prach_fd_occasions_list[i].num_unused_root_sequences.value = 1;
@@ -252,8 +255,8 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
       cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = 0;
       cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0;
       for (i=0; i<4; i++) {
-        cfg->ssb_table.ssb_mask_list[0].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<<i*8);
-        cfg->ssb_table.ssb_mask_list[1].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]<<i*8);
+        cfg->ssb_table.ssb_mask_list[0].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[3-i]<<i*8);
+        cfg->ssb_table.ssb_mask_list[1].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-i]<<i*8);
       }
       break;
     default:
@@ -309,6 +312,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
 
 
 
+extern uint16_t sl_ahead;
 int rrc_mac_config_req_gNB(module_id_t Mod_idP, 
 			   int ssb_SubcarrierOffset,
                            int pdsch_AntennaPorts,
@@ -322,6 +326,30 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
   if (scc != NULL ) {
     AssertFatal((scc->ssb_PositionsInBurst->present > 0) && (scc->ssb_PositionsInBurst->present < 4), "SSB Bitmap type %d is not valid\n",scc->ssb_PositionsInBurst->present);
 
+    /* dimension UL_tti_req_ahead for number of slots in frame */
+    const uint8_t slots_per_frame[5] = {10, 20, 40, 80, 160};
+    const int n = slots_per_frame[*scc->ssbSubcarrierSpacing];
+    RC.nrmac[Mod_idP]->UL_tti_req_ahead[0] = calloc(n, sizeof(nfapi_nr_ul_tti_request_t));
+    AssertFatal(RC.nrmac[Mod_idP]->UL_tti_req_ahead[0],
+                "could not allocate memory for RC.nrmac[]->UL_tti_req_ahead[]\n");
+    /* fill in slot/frame numbers: slot is fixed, frame will be updated by
+     * scheduler */
+    for (int i = 0; i < n; ++i) {
+      nfapi_nr_ul_tti_request_t *req = &RC.nrmac[Mod_idP]->UL_tti_req_ahead[0][i];
+      /* consider that scheduler runs sl_ahead: the first sl_ahead slots are
+       * already "in the past" and thus we put frame 1 instead of 0!  Note that
+       * variable sl_ahead seems to not be correctly initialized, but I leave
+       * it for information purposes here (the fix would always put 0, what
+       * happens now, too) */
+      req->SFN = i < sl_ahead;
+      req->Slot = i;
+    }
+
+    RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL =
+        calloc(n * 275, sizeof(uint16_t));
+    AssertFatal(RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL,
+                "could not allocate memory for RC.nrmac[]->common_channels[0].vrb_map_UL\n");
+
     LOG_I(MAC,"Configuring common parameters from NR ServingCellConfig\n");
 
     config_common(Mod_idP,
@@ -371,6 +399,12 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
                   bwpList->list.count);
       const int bwp_id = 1;
       UE_info->UE_sched_ctrl[UE_id].active_bwp = bwpList->list.array[bwp_id - 1];
+      struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList =
+          secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList;
+      AssertFatal(ubwpList->list.count == 1,
+                  "uplinkBWP_ToAddModList has %d BWP!\n",
+                  ubwpList->list.count);
+      UE_info->UE_sched_ctrl[UE_id].active_ubwp = ubwpList->list.array[bwp_id - 1];
       LOG_I(PHY,"Added new UE_id %d/%x with initial secondaryCellGroup\n",UE_id,rnti);
     } else if (add_ue == 1 && !get_softmodem_params()->phy_test) {
       /* TODO: should check for free RA process */
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
index 45a3b7dd9861f2a0cb7d153bb7a5d5cb280d8da6..e9c8d8c60c7dc8b098c91127c97eaaea79d702d4 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
@@ -32,9 +32,7 @@
 
 #include "assertions.h"
 
-#include "LAYER2/MAC/mac.h"
 #include "NR_MAC_COMMON/nr_mac_extern.h"
-#include "LAYER2/MAC/mac_proto.h"
 #include "NR_MAC_gNB/mac_proto.h"
 
 #include "common/utils/LOG/log.h"
@@ -51,15 +49,10 @@
 #include "openair1/PHY/defs_gNB.h"
 #include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h"
 
-//Agent-related headers
-#include "flexran_agent_extern.h"
-#include "flexran_agent_mac.h"
-
 #include "intertask_interface.h"
 
 #include "executables/softmodem-common.h"
 
-const uint8_t slots_per_frame[5] = {10, 20, 40, 80, 160};
 uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 };
 
 void clear_mac_stats(gNB_MAC_INST *gNB) {
@@ -92,9 +85,12 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
                                 int CC_idP,
                                 frame_t frameP,
                                 sub_frame_t slotP){
+  NR_ServingCellConfigCommon_t *scc = gNB->common_channels->ServingCellConfigCommon;
+  const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
 
   nfapi_nr_dl_tti_request_t    *DL_req = &gNB->DL_req[0];
-  nfapi_nr_ul_tti_request_t    *UL_tti_req = &gNB->UL_tti_req[0];
+  nfapi_nr_ul_tti_request_t    *future_ul_tti_req =
+      &gNB->UL_tti_req_ahead[CC_idP][(slotP + num_slots - 1) % num_slots];
   nfapi_nr_ul_dci_request_t    *UL_dci_req = &gNB->UL_dci_req[0];
   nfapi_nr_tx_data_request_t   *TX_req = &gNB->TX_req[0];
 
@@ -112,12 +108,17 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
     UL_dci_req[CC_idP].Slot                        = slotP;
     UL_dci_req[CC_idP].numPdus                     = 0;
 
-    UL_tti_req[CC_idP].SFN                         = frameP;
-    UL_tti_req[CC_idP].Slot                        = slotP;
-    UL_tti_req[CC_idP].n_pdus                      = 0;
-    UL_tti_req[CC_idP].n_ulsch                     = 0;
-    UL_tti_req[CC_idP].n_ulcch                     = 0;
-    UL_tti_req[CC_idP].n_group                     = 0;
+    /* advance last round's future UL_tti_req to be ahead of current frame/slot */
+    future_ul_tti_req->SFN = (slotP == 0 ? frameP : frameP + 1) % 1024;
+    /* future_ul_tti_req->Slot is fixed! */
+    future_ul_tti_req->n_pdus = 0;
+    future_ul_tti_req->n_ulsch = 0;
+    future_ul_tti_req->n_ulcch = 0;
+    future_ul_tti_req->n_group = 0;
+
+    /* UL_tti_req is a simple pointer into the current UL_tti_req_ahead, i.e.,
+     * it walks over UL_tti_req_ahead in a circular fashion */
+    gNB->UL_tti_req[CC_idP] = &gNB->UL_tti_req_ahead[CC_idP][slotP];
 
     TX_req[CC_idP].Number_of_PDUs                  = 0;
 
@@ -285,58 +286,6 @@ void schedule_nr_SRS(module_id_t module_idP, frame_t frameP, sub_frame_t subfram
 */
 
 
-/*
-void copy_nr_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
-{
-  int CC_id;
-  gNB_MAC_INST *mac = RC.nrmac[module_idP];
-
-  for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
-
-    nfapi_ul_config_request_t *ul_req                 = &mac->UL_tti_req[CC_id];
-
-    *ul_req = *ul_req_tmp;
-
-    // Restore the pointer
-    ul_req->ul_config_request_body.ul_config_pdu_list = ul_req_pdu;
-    ul_req->sfn_sf                                    = (frameP<<7) + slotP;
-    ul_req_tmp->ul_config_request_body.number_of_pdus = 0;
-
-    if (ul_req->ul_config_request_body.number_of_pdus>0)
-      {
-        LOG_D(PHY, "%s() active NOW (frameP:%d slotP:%d) pdus:%d\n", __FUNCTION__, frameP, slotP, ul_req->ul_config_request_body.number_of_pdus);
-      }
-
-    memcpy((void*)ul_req->ul_config_request_body.ul_config_pdu_list,
-     (void*)ul_req_tmp->ul_config_request_body.ul_config_pdu_list,
-     ul_req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t));
-  }
-}
-*/
-
-void nr_schedule_pusch(int Mod_idP,
-                       int UE_id,
-                       int num_slots_per_tdd,
-                       int ul_slots,
-                       frame_t frameP,
-                       sub_frame_t slotP) {
-
-  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
-  NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info;
-  int k = slotP + ul_slots - num_slots_per_tdd;
-  NR_sched_pusch *pusch = &UE_info->UE_sched_ctrl[UE_id].sched_pusch[k];
-  if ((pusch->active == true) && (frameP == pusch->frame) && (slotP == pusch->slot)) {
-    UL_tti_req->SFN = pusch->frame;
-    UL_tti_req->Slot = pusch->slot;
-    UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
-    UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
-    UL_tti_req->pdus_list[UL_tti_req->n_pdus].pusch_pdu = pusch->pusch_pdu;
-    UL_tti_req->n_pdus+=1;
-    memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pusch[k],
-           0, sizeof(NR_sched_pusch));
-  }
-}
-
 bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot) {
   return (bitmap >> slot) & 0x01;
 }
@@ -355,7 +304,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
 
   gNB_MAC_INST *gNB = RC.nrmac[module_idP];
   NR_UE_info_t *UE_info = &gNB->UE_info;
-  NR_UE_sched_ctrl_t *ue_sched_ctl = &UE_info->UE_sched_ctrl[UE_id];
   NR_COMMON_channels_t *cc = gNB->common_channels;
   NR_ServingCellConfigCommon_t        *scc     = cc->ServingCellConfigCommon;
   NR_TDD_UL_DL_Pattern_t *tdd_pattern = &scc->tdd_UL_DL_ConfigurationCommon->pattern1;
@@ -397,7 +345,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
       AssertFatal(1==0,"Undefined tdd period %ld\n", scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity);
   }
 
-  int num_slots_per_tdd = (slots_per_frame[*scc->ssbSubcarrierSpacing])/nb_periods_per_frame;
+  int num_slots_per_tdd = (nr_slots_per_frame[*scc->ssbSubcarrierSpacing])/nb_periods_per_frame;
 
   const int nr_ulmix_slots = tdd_pattern->nrofUplinkSlots + (tdd_pattern->nrofUplinkSymbols!=0);
 
@@ -424,7 +372,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
 
     // clear vrb_maps
     memset(cc[CC_id].vrb_map, 0, sizeof(uint16_t) * 275);
-    memset(cc[CC_id].vrb_map_UL, 0, sizeof(uint16_t) * 275);
+    // clear last scheduled slot's content (only)!
+    const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
+    const int last_slot = (slot + num_slots - 1) % num_slots;
+    uint16_t *vrb_map_UL = cc[CC_id].vrb_map_UL;
+    memset(&vrb_map_UL[last_slot * 275], 0, sizeof(uint16_t) * 275);
 
     clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame, slot);
   }
@@ -434,7 +386,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
 
 
   // This schedules MIB
-  schedule_nr_mib(module_idP, frame, slot, slots_per_frame[*scc->ssbSubcarrierSpacing]);
+  schedule_nr_mib(module_idP, frame, slot, nr_slots_per_frame[*scc->ssbSubcarrierSpacing]);
 
   // This schedules SIB1
   if ( get_softmodem_params()->sa == 1 )
@@ -442,42 +394,40 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
 
 
   // This schedule PRACH if we are not in phy_test mode
-  if (get_softmodem_params()->phy_test == 0)
-    schedule_nr_prach(module_idP, frame, slot);
+  if (get_softmodem_params()->phy_test == 0) {
+    /* we need to make sure that resources for PRACH are free. To avoid that
+       e.g. PUSCH has already been scheduled, make sure we schedule before
+       anything else: below, we simply assume an advance one frame (minus one
+       slot, because otherwise we would allocate the current slot in
+       UL_tti_req_ahead), but be aware that, e.g., K2 is allowed to be larger
+       (schedule_nr_prach will assert if resources are not free). */
+    const sub_frame_t n_slots_ahead = nr_slots_per_frame[*scc->ssbSubcarrierSpacing] - 1;
+    const frame_t f = (frame + (slot + n_slots_ahead) / nr_slots_per_frame[*scc->ssbSubcarrierSpacing]) % 1024;
+    const sub_frame_t s = (slot + n_slots_ahead) % nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
+    schedule_nr_prach(module_idP, f, s);
+  }
 
   // This schedule SR
   // TODO
 
   // This schedule CSI measurement reporting
   if (UE_info->active[UE_id])
-    nr_csi_meas_reporting(module_idP, UE_id, frame, slot, num_slots_per_tdd, nr_ulmix_slots, slots_per_frame[*scc->ssbSubcarrierSpacing]);
+    nr_csi_meas_reporting(module_idP, UE_id, frame, slot, num_slots_per_tdd, nr_ulmix_slots, nr_slots_per_frame[*scc->ssbSubcarrierSpacing]);
 
   // This schedule RA procedure if not in phy_test mode
   // Otherwise already consider 5G already connected
-  RC.nrmac[module_idP]->current_slot=slot;
   if (get_softmodem_params()->phy_test == 0) {
     nr_schedule_RA(module_idP, frame, slot);
-    nr_schedule_reception_msg3(module_idP, 0, frame, slot);
-
   }
 
   // This schedules the DCI for Uplink and subsequently PUSCH
-
-  // The decision about whether to schedule is done for each UE independently
-  // inside
-  if (UE_info->active[UE_id] && slot < 10) {
-
-    int tda = 1; // time domain assignment hardcoded for now
-    schedule_fapi_ul_pdu(module_idP, frame, slot, num_slots_per_tdd, nr_ulmix_slots, tda, ulsch_in_slot_bitmap);
-    nr_schedule_pusch(module_idP, UE_id, num_slots_per_tdd, nr_ulmix_slots, frame, slot);
+  if (slot < 10) {
+    nr_schedule_ulsch(module_idP, frame, slot, num_slots_per_tdd, nr_ulmix_slots, ulsch_in_slot_bitmap);
   }
 
-
-  if (UE_info->active[UE_id]
-      && (is_xlsch_in_slot(dlsch_in_slot_bitmap, slot % num_slots_per_tdd))
+  // This schedules the DCI for Downlink and PDSCH
+  if (is_xlsch_in_slot(dlsch_in_slot_bitmap, slot % num_slots_per_tdd)
       && slot < 10) {
-
-    ue_sched_ctl->current_harq_pid = slot % num_slots_per_tdd;
     nr_schedule_ue_spec(module_idP, frame, slot, num_slots_per_tdd);
   }
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
index 66dcfcff86ba5f2c0f3e470ec8b0f2478f2e1cc8..e15963f35502b9d493eb16d166645d4817f5725f 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
@@ -43,6 +43,7 @@
 
 extern RAN_CONTEXT_t RC;
 extern const uint8_t nr_slots_per_frame[5];
+extern uint16_t sl_ahead;
 
 uint8_t DELTA[4]= {2,3,4,6};
 
@@ -62,19 +63,19 @@ int16_t ssb_index_from_prach(module_id_t module_idP,
   nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0];
 
   uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex;
-	uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
+  uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
   
-	uint8_t total_RApreambles = 64;
-	if( scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles != NULL)
+  uint8_t total_RApreambles = 64;
+  if( scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles != NULL)
     total_RApreambles = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles;	
   
-	float  num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];	
+  float  num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];	
   uint16_t start_symbol_index = 0;
   uint8_t mu,N_dur=0,N_t_slot=0,start_symbol = 0, temp_start_symbol = 0, N_RA_slot=0;
   uint16_t format,RA_sfn_index = -1;
-	uint8_t config_period = 1;
+  uint8_t config_period = 1;
   uint16_t prach_occasion_id = -1;
-	uint8_t num_active_ssb = cc->num_active_ssb;
+  uint8_t num_active_ssb = cc->num_active_ssb;
 
   if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing)
     mu = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing;
@@ -95,45 +96,51 @@ int16_t ssb_index_from_prach(module_id_t module_idP,
 			       &N_RA_slot,
 			       &config_period);
   uint8_t index = 0,slot_index = 0;
-	for (slot_index = 0;slot_index < N_RA_slot; slot_index++) {
+  for (slot_index = 0;slot_index < N_RA_slot; slot_index++) {
     if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
        if((mu == 1) || (mu == 3))
          slot_index = 1;  //For scs = 30khz and 120khz
     }
     for (int i=0; i< N_t_slot; i++) {
       temp_start_symbol = (start_symbol + i * N_dur + 14 * slot_index) % 14;
-		  if(symbol == temp_start_symbol) {
-			  start_symbol_index = i;
-		    break;
-		  }
-	  }
-	}
+      if(symbol == temp_start_symbol) {
+        start_symbol_index = i;
+        break;
+      }
+    }
+  }
   if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
     if((mu == 1) || (mu == 3))
       slot_index = 0;  //For scs = 30khz and 120khz
   }
-  
-//  prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index; 
- prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period)*cc->total_prach_occasions_per_config_period) + (RA_sfn_index + slot_index) * N_t_slot * fdm + start_symbol_index * fdm + freq_index; 
-//one RO is shared by one or more SSB
- if(num_ssb_per_RO <= 1 )
-   index = (int) (prach_occasion_id / (int)(1/num_ssb_per_RO)) % num_active_ssb;
-//one SSB have more than one continuous RO
- else if ( num_ssb_per_RO > 1) {
-	 index = (prach_occasion_id * (int)num_ssb_per_RO)% num_active_ssb ;
-   for(int j = 0;j < num_ssb_per_RO;j++) {
-     if(preamble_index <  (((j+1) * total_RApreambles) / num_ssb_per_RO))
-      index = index + j;
-	  }		
-	}
-
-  LOG_D(MAC, "Frame %d, Slot %d: Prach Occasion id = %d ssb per RO = %f number of active SSB %u index = %d fdm %u symbol index %u freq_index %u total_RApreambles %u\n", frameP, slotP, prach_occasion_id, num_ssb_per_RO, num_active_ssb, index, fdm, start_symbol_index, freq_index, total_RApreambles);
+
+  //  prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index; 
+  prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period)*cc->total_prach_occasions_per_config_period) +
+                      (RA_sfn_index + slot_index) * N_t_slot * fdm + start_symbol_index * fdm + freq_index; 
+
+  //one RO is shared by one or more SSB
+  if(num_ssb_per_RO <= 1 )
+    index = (int) (prach_occasion_id / (int)(1/num_ssb_per_RO)) % num_active_ssb;
+  //one SSB have more than one continuous RO
+  else if ( num_ssb_per_RO > 1) {
+    index = (prach_occasion_id * (int)num_ssb_per_RO)% num_active_ssb ;
+    for(int j = 0;j < num_ssb_per_RO;j++) {
+      if(preamble_index <  (((j+1) * total_RApreambles) / num_ssb_per_RO))
+        index = index + j;
+    }
+  }
+
+  LOG_D(MAC, "Frame %d, Slot %d: Prach Occasion id = %d ssb per RO = %f number of active SSB %u index = %d fdm %u symbol index %u freq_index %u total_RApreambles %u\n", 
+        frameP, slotP, prach_occasion_id, num_ssb_per_RO, num_active_ssb, index, fdm, start_symbol_index, freq_index, total_RApreambles);
+
   return index;
 }
+
+
 //Compute Total active SSBs and RO available
 void find_SSB_and_RO_available(module_id_t module_idP) {
 
-	gNB_MAC_INST *gNB = RC.nrmac[module_idP];
+  gNB_MAC_INST *gNB = RC.nrmac[module_idP];
   NR_COMMON_channels_t *cc = &gNB->common_channels[0];
   NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
   nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0];
@@ -141,7 +148,7 @@ void find_SSB_and_RO_available(module_id_t module_idP) {
   uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex;
   uint8_t mu,N_dur=0,N_t_slot=0,start_symbol=0,N_RA_slot = 0;
   uint16_t format,N_RA_sfn = 0,unused_RA_occasion,repetition = 0;
-	uint8_t num_active_ssb = 0;
+  uint8_t num_active_ssb = 0;
   uint8_t max_association_period = 1;
 
   if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing)
@@ -151,190 +158,190 @@ void find_SSB_and_RO_available(module_id_t module_idP) {
 
   // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4
   get_nr_prach_occasion_info_from_index(config_index,
-                                    scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
-                                    mu,
-                                    cc->frame_type,
-                                    &format,
-                                    &start_symbol,
-                                    &N_t_slot,
-                                    &N_dur,
-                                    &N_RA_slot,
-	                                 &N_RA_sfn,
-                                   &max_association_period);
+                                        scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
+                                        mu,
+                                        cc->frame_type,
+                                        &format,
+                                        &start_symbol,
+                                        &N_t_slot,
+                                        &N_dur,
+                                        &N_RA_slot,
+                                        &N_RA_sfn,
+                                        &max_association_period);
 
   float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];	
-	uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
+  uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
   uint64_t L_ssb = (((uint64_t) cfg->ssb_table.ssb_mask_list[0].ssb_mask.value)<<32) | cfg->ssb_table.ssb_mask_list[1].ssb_mask.value ;
-	uint32_t total_RA_occasions = N_RA_sfn * N_t_slot * N_RA_slot * fdm;
+  uint32_t total_RA_occasions = N_RA_sfn * N_t_slot * N_RA_slot * fdm;
 
-	for(int i = 0;i < 64;i++) {
+  for(int i = 0;i < 64;i++) {
     if ((L_ssb >> (63-i)) & 0x01) { // only if the bit of L_ssb at current ssb index is 1
       cc->ssb_index[num_active_ssb] = i; 
-		  num_active_ssb++;
+      num_active_ssb++;
     }
-	}	
+  }
 
-	for(int i = 1; (1 << (i-1)) <= max_association_period;i++) {
+  for(int i = 1; (1 << (i-1)) <= max_association_period;i++) {
     if(total_RA_occasions >= (int) (num_active_ssb/num_ssb_per_RO)) {
-		  repetition = (uint16_t)((total_RA_occasions * num_ssb_per_RO )/num_active_ssb);
-		  break;
-		} 
-		else { 
-		  total_RA_occasions = total_RA_occasions * i;
-		  cc->max_association_period = i;
-		} 
-	}
+      repetition = (uint16_t)((total_RA_occasions * num_ssb_per_RO )/num_active_ssb);
+      break;
+    }
+    else {
+      total_RA_occasions = total_RA_occasions * i;
+      cc->max_association_period = i;
+    }
+  }
   if(cc->max_association_period == 0)
-			cc->max_association_period = 1;
-
- unused_RA_occasion = total_RA_occasions - (int)((num_active_ssb * repetition)/num_ssb_per_RO);
- cc->total_prach_occasions = total_RA_occasions - unused_RA_occasion;
- cc->num_active_ssb = num_active_ssb;
+    cc->max_association_period = 1;
 
-  LOG_I(MAC, "Total available RO %d, num of active SSB %d: unused RO = %d max_association_period %u N_RA_sfn %u \n", cc->total_prach_occasions, cc->num_active_ssb, unused_RA_occasion, max_association_period, N_RA_sfn);
+  unused_RA_occasion = total_RA_occasions - (int)((num_active_ssb * repetition)/num_ssb_per_RO);
+  cc->total_prach_occasions = total_RA_occasions - unused_RA_occasion;
+  cc->num_active_ssb = num_active_ssb;
 
+  LOG_I(MAC, "Total available RO %d, num of active SSB %d: unused RO = %d max_association_period %u N_RA_sfn %u \n",
+        cc->total_prach_occasions, cc->num_active_ssb, unused_RA_occasion, max_association_period, N_RA_sfn);
 }		
 		
-void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) {
-
+void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
+{
   gNB_MAC_INST *gNB = RC.nrmac[module_idP];
   NR_COMMON_channels_t *cc = gNB->common_channels;
   NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
-  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req[0];
+  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[0][slotP];
   nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0];
 
   if (is_nr_UL_slot(scc,slotP)) {
-  uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex;
-  uint8_t mu,N_dur,N_t_slot,start_symbol = 0,N_RA_slot;
-  uint16_t RA_sfn_index = -1;
-	uint8_t config_period = 1;
-  uint16_t format;
-  int slot_index = 0;
-  uint16_t prach_occasion_id = -1;
-
-  if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing)
-    mu = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing;
-  else
-    mu = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
-
-  uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
-  // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4
-  if ( get_nr_prach_info_from_index(config_index,
-                                    (int)frameP,
-                                    (int)slotP,
-                                    scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
-                                    mu,
-                                    cc->frame_type,
-                                    &format,
-                                    &start_symbol,
-                                    &N_t_slot,
-                                    &N_dur,
-                                    &RA_sfn_index,
-                                    &N_RA_slot,
-																		&config_period) ) {
-    uint16_t format0 = format&0xff;      // first column of format from table
-    uint16_t format1 = (format>>8)&0xff; // second column of format from table
-
-    if (N_RA_slot > 1) { //more than 1 PRACH slot in a subframe
-      if (slotP%2 == 1){
-	      slot_index = 1;
-      }	
-      else {
-	      slot_index = 0;
-			}	
-    }else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
-       slot_index = 0;
-    }
-
+    uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex;
+    uint8_t mu,N_dur,N_t_slot,start_symbol = 0,N_RA_slot;
+    uint16_t RA_sfn_index = -1;
+    uint8_t config_period = 1;
+    uint16_t format;
+    int slot_index = 0;
+    uint16_t prach_occasion_id = -1;
+
+    if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing)
+      mu = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing;
+    else
+      mu = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
+
+    uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
+    // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4
+    if ( get_nr_prach_info_from_index(config_index,
+                                      (int)frameP,
+                                      (int)slotP,
+                                      scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
+                                      mu,
+                                      cc->frame_type,
+                                      &format,
+                                      &start_symbol,
+                                      &N_t_slot,
+                                      &N_dur,
+                                      &RA_sfn_index,
+                                      &N_RA_slot,
+                                      &config_period) ) {
+
+      uint16_t format0 = format&0xff;      // first column of format from table
+      uint16_t format1 = (format>>8)&0xff; // second column of format from table
+
+      if (N_RA_slot > 1) { //more than 1 PRACH slot in a subframe
+        if (slotP%2 == 1)
+          slot_index = 1;
+        else
+          slot_index = 0;
+      }else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
+        slot_index = 0;
+      }
 
-    UL_tti_req->SFN = frameP;
-    UL_tti_req->Slot = slotP;
-    for (int fdm_index=0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion
-    for (int td_index=0; td_index<N_t_slot; td_index++) {
-
-      prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) + (RA_sfn_index + slot_index) * N_t_slot * fdm + td_index * fdm + fdm_index;
-			if((prach_occasion_id < cc->total_prach_occasions) && (td_index == 0)){  
-
-      UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE;
-      UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t);
-      nfapi_nr_prach_pdu_t  *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu;
-      memset(prach_pdu,0,sizeof(nfapi_nr_prach_pdu_t));
-      UL_tti_req->n_pdus+=1;
-
-      // filling the prach fapi structure
-      prach_pdu->phys_cell_id = *scc->physCellId;
-      prach_pdu->num_prach_ocas = N_t_slot;
-      prach_pdu->prach_start_symbol = start_symbol;
-      prach_pdu->num_ra = fdm_index;
-      prach_pdu->num_cs = get_NCS(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig,
-                                  format0,
-                                  scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig);
-      
-      LOG_D(MAC, "Frame %d, Slot %d: Prach Occasion id = %u  fdm index = %u start symbol = %u slot index = %u subframe index = %u \n",
-	    frameP, slotP,
-	    prach_occasion_id, prach_pdu->num_ra,
-	    prach_pdu->prach_start_symbol,
-	    slot_index, RA_sfn_index);
-      // SCF PRACH PDU format field does not consider A1/B1 etc. possibilities
-      // We added 9 = A1/B1 10 = A2/B2 11 A3/B3
-      if (format1!=0xff) {
-        switch(format0) {
-          case 0xa1:
-            prach_pdu->prach_format = 11;
-            break;
-          case 0xa2:
-            prach_pdu->prach_format = 12;
-            break;
-          case 0xa3:
-            prach_pdu->prach_format = 13;
-            break;
-        default:
-          AssertFatal(1==0,"Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
+      UL_tti_req->SFN = frameP;
+      UL_tti_req->Slot = slotP;
+      for (int fdm_index=0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion
+        for (int td_index=0; td_index<N_t_slot; td_index++) {
+
+          prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) +
+                              (RA_sfn_index + slot_index) * N_t_slot * fdm + td_index * fdm + fdm_index;
+
+          if((prach_occasion_id < cc->total_prach_occasions) && (td_index == 0)){
+
+            UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE;
+            UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t);
+            nfapi_nr_prach_pdu_t  *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu;
+            memset(prach_pdu,0,sizeof(nfapi_nr_prach_pdu_t));
+            UL_tti_req->n_pdus+=1;
+
+            // filling the prach fapi structure
+            prach_pdu->phys_cell_id = *scc->physCellId;
+            prach_pdu->num_prach_ocas = N_t_slot;
+            prach_pdu->prach_start_symbol = start_symbol;
+            prach_pdu->num_ra = fdm_index;
+            prach_pdu->num_cs = get_NCS(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig,
+                                        format0,
+                                        scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig);
+
+            LOG_D(MAC, "Frame %d, Slot %d: Prach Occasion id = %u  fdm index = %u start symbol = %u slot index = %u subframe index = %u \n",
+                  frameP, slotP,
+                  prach_occasion_id, prach_pdu->num_ra,
+                  prach_pdu->prach_start_symbol,
+                  slot_index, RA_sfn_index);
+            // SCF PRACH PDU format field does not consider A1/B1 etc. possibilities
+            // We added 9 = A1/B1 10 = A2/B2 11 A3/B3
+            if (format1!=0xff) {
+              switch(format0) {
+                case 0xa1:
+                  prach_pdu->prach_format = 11;
+                  break;
+                case 0xa2:
+                  prach_pdu->prach_format = 12;
+                  break;
+                case 0xa3:
+                  prach_pdu->prach_format = 13;
+                  break;
+              default:
+                AssertFatal(1==0,"Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
+              }
+            }
+            else{
+              switch(format0) {
+                case 0:
+                  prach_pdu->prach_format = 0;
+                  break;
+                case 1:
+                  prach_pdu->prach_format = 1;
+                  break;
+                case 2:
+                  prach_pdu->prach_format = 2;
+                  break;
+                case 3:
+                  prach_pdu->prach_format = 3;
+                  break;
+                case 0xa1:
+                  prach_pdu->prach_format = 4;
+                  break;
+                case 0xa2:
+                  prach_pdu->prach_format = 5;
+                  break;
+                case 0xa3:
+                  prach_pdu->prach_format = 6;
+                  break;
+                case 0xb1:
+                  prach_pdu->prach_format = 7;
+                  break;
+                case 0xb4:
+                  prach_pdu->prach_format = 8;
+                  break;
+                case 0xc0:
+                  prach_pdu->prach_format = 9;
+                  break;
+                case 0xc2:
+                  prach_pdu->prach_format = 10;
+                  break;
+              default:
+                AssertFatal(1==0,"Invalid PRACH format");
+              }
+            }
+          }
         }
       }
-      else{
-        switch(format0) {
-          case 0:
-            prach_pdu->prach_format = 0;
-            break;
-          case 1:
-            prach_pdu->prach_format = 1;
-            break;
-          case 2:
-            prach_pdu->prach_format = 2;
-            break;
-          case 3:
-            prach_pdu->prach_format = 3;
-            break;
-          case 0xa1:
-            prach_pdu->prach_format = 4;
-            break;
-          case 0xa2:
-            prach_pdu->prach_format = 5;
-            break;
-          case 0xa3:
-            prach_pdu->prach_format = 6;
-            break;
-          case 0xb1:
-            prach_pdu->prach_format = 7;
-            break;
-          case 0xb4:
-            prach_pdu->prach_format = 8;
-            break;
-          case 0xc0:
-            prach_pdu->prach_format = 9;
-            break;
-          case 0xc2:
-            prach_pdu->prach_format = 10;
-            break;
-        default:
-          AssertFatal(1==0,"Invalid PRACH format");
-        }
-      }		
-     }
     }
-   }
-  }
   }
 }
 
@@ -363,7 +370,14 @@ void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot,
   uint8_t start_next_period = (rach_slot-(rach_slot%tdd_period_slot)+tdd_period_slot)%nr_slots_per_frame[mu];
   *msg2_slot = start_next_period + last_dl_slot_period; // initializing scheduling of slot to next mixed (or last dl) slot
   *msg2_frame = (*msg2_slot>(rach_slot))? rach_frame : (rach_frame +1);
- 
+
+  // we can't schedule msg2 before sl_ahead since prach
+  int eff_slot = *msg2_slot+(*msg2_frame-rach_frame)*nr_slots_per_frame[mu];
+  if ((eff_slot-rach_slot)<=sl_ahead) {
+    *msg2_slot = (*msg2_slot+tdd_period_slot)%nr_slots_per_frame[mu];
+    *msg2_frame = (*msg2_slot>(rach_slot))? rach_frame : (rach_frame +1);
+  }
+
   switch(response_window){
     case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl1:
       slot_window = 1;
@@ -396,12 +410,11 @@ void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot,
 
   // slot and frame limit to transmit msg2 according to response window
   uint8_t slot_limit = (rach_slot + slot_window)%nr_slots_per_frame[mu];
-  //uint8_t frame_limit = (slot_limit>(rach_slot))? rach_frame : (rach_frame +1);
-
+  uint8_t frame_limit = (slot_limit>(rach_slot))? rach_frame : (rach_frame +1);
 
   // go to previous slot if the current scheduled slot is beyond the response window
   // and if the slot is not among the PDCCH monitored ones (38.213 10.1)
-  while ((*msg2_slot>slot_limit) || ((*msg2_frame*nr_slots_per_frame[mu]+*msg2_slot-monitoring_offset)%monitoring_slot_period !=0))  {
+  while (((*msg2_slot>slot_limit)&&(*msg2_frame>frame_limit)) || ((*msg2_frame*nr_slots_per_frame[mu]+*msg2_slot-monitoring_offset)%monitoring_slot_period !=0))  {
     if((*msg2_slot%tdd_period_slot) > 0)
       (*msg2_slot)--;
     else
@@ -562,7 +575,9 @@ void nr_schedule_RA(module_id_t module_idP, frame_t frameP, sub_frame_t slotP){
   stop_meas(&mac->schedule_ra);
 }
 
-void nr_get_Msg3alloc(NR_ServingCellConfigCommon_t *scc,
+void nr_get_Msg3alloc(module_id_t module_id,
+                      int CC_id,
+                      NR_ServingCellConfigCommon_t *scc,
                       NR_BWP_Uplink_t *ubwp,
                       sub_frame_t current_slot,
                       frame_t current_frame,
@@ -596,27 +611,25 @@ void nr_get_Msg3alloc(NR_ServingCellConfigCommon_t *scc,
     ra->Msg3_frame = current_frame + (temp_slot/nr_slots_per_frame[mu]);
 
   LOG_I(MAC, "[RAPROC] Msg3 slot %d: current slot %u Msg3 frame %u k2 %u Msg3_tda_id %u start symbol index %u\n", ra->Msg3_slot, current_slot, ra->Msg3_frame, k2,ra->Msg3_tda_id, StartSymbolIndex);
-  ra->msg3_nb_rb = 18;
-  ra->msg3_first_rb = 0;
-}
-
-
-void nr_schedule_reception_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t slotP){
-  gNB_MAC_INST                                *mac = RC.nrmac[module_idP];
-  nfapi_nr_ul_tti_request_t                   *ul_req = &mac->UL_tti_req[0];
-  NR_COMMON_channels_t                        *cc = &mac->common_channels[CC_id];
-  NR_RA_t                                     *ra = &cc->ra[0];
-
-  if (ra->state == WAIT_Msg3) {
-    if ((frameP == ra->Msg3_frame) && (slotP == ra->Msg3_slot) ){
-      ul_req->SFN = ra->Msg3_frame;
-      ul_req->Slot = ra->Msg3_slot;
-      ul_req->pdus_list[ul_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
-      ul_req->pdus_list[ul_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
-      ul_req->pdus_list[ul_req->n_pdus].pusch_pdu = ra->pusch_pdu;
-      ul_req->n_pdus+=1;
-    }
+  uint16_t *vrb_map_UL =
+      &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * 275];
+  const uint16_t bwpSize = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, 275);
+  /* search 18 free RBs */
+  int rbSize = 0;
+  int rbStart = 0;
+  while (rbSize < 18) {
+    rbStart += rbSize; /* last iteration rbSize was not enough, skip it */
+    rbSize = 0;
+    while (rbStart < bwpSize && vrb_map_UL[rbStart])
+      rbStart++;
+    AssertFatal(rbStart < bwpSize - 18, "no space to allocate Msg 3 for RA!\n");
+    while (rbStart + rbSize < bwpSize
+           && !vrb_map_UL[rbStart + rbSize]
+           && rbSize < 18)
+      rbSize++;
   }
+  ra->msg3_nb_rb = 18;
+  ra->msg3_first_rb = rbStart;
 }
 
 void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t slotP){
@@ -631,10 +644,32 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t
     return;
   }
 
+  uint16_t *vrb_map_UL =
+      &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * 275];
+  for (int i = 0; i < ra->msg3_nb_rb; ++i) {
+    AssertFatal(!vrb_map_UL[i + ra->msg3_first_rb],
+                "RB %d in %4d.%2d is already taken, cannot allocate Msg3!\n",
+                i + ra->msg3_first_rb,
+                ra->Msg3_frame,
+                ra->Msg3_slot);
+    vrb_map_UL[i + ra->msg3_first_rb] = 1;
+  }
+
   LOG_I(MAC, "[gNB %d][RAPROC] Frame %d, Subframe %d : CC_id %d RA is active, Msg3 in (%d,%d)\n", module_idP, frameP, slotP, CC_id, ra->Msg3_frame, ra->Msg3_slot);
 
-  nfapi_nr_pusch_pdu_t  *pusch_pdu = &ra->pusch_pdu;
+  nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[CC_id][ra->Msg3_slot];
+  AssertFatal(future_ul_tti_req->SFN == ra->Msg3_frame
+              && future_ul_tti_req->Slot == ra->Msg3_slot,
+              "future UL_tti_req's frame.slot %d.%d does not match PUSCH %d.%d\n",
+              future_ul_tti_req->SFN,
+              future_ul_tti_req->Slot,
+              ra->Msg3_frame,
+              ra->Msg3_slot);
+  future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
+  future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
+  nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu;
   memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t));
+  future_ul_tti_req->n_pdus += 1;
 
   AssertFatal(ra->secondaryCellGroup,
               "no secondaryCellGroup for RNTI %04x\n",
@@ -913,7 +948,7 @@ void nr_generate_Msg2(module_id_t module_idP,
     dl_req->nPDUs+=2;
 
     // Program UL processing for Msg3
-    nr_get_Msg3alloc(scc, ubwp, slotP, frameP, ra);
+    nr_get_Msg3alloc(module_idP, CC_id, scc, ubwp, slotP, frameP, ra);
     LOG_I(MAC, "Frame %d, Subframe %d: Setting Msg3 reception for Frame %d Subframe %d\n", frameP, slotP, ra->Msg3_frame, ra->Msg3_slot);
     nr_add_msg3(module_idP, CC_id, frameP, slotP);
     ra->state = WAIT_Msg3;
@@ -990,7 +1025,7 @@ void nr_fill_rar(uint8_t Mod_idP,
                  uint8_t * dlsch_buffer,
                  nfapi_nr_pusch_pdu_t  *pusch_pdu){
 
-  LOG_I(MAC, "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u", ra->Msg2_frame, ra-> Msg2_slot, ra->preamble_index);
+  LOG_I(MAC, "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u\n", ra->Msg2_frame, ra-> Msg2_slot, ra->preamble_index);
   NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) dlsch_buffer;
   NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 1);
   unsigned char csi_req = 0, tpc_command;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
index a9839ed985b91abbaa325713b4d47681e908d62a..5a5e662b13ac4e1d518b7b79d3be43c5c39a2cb7 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
@@ -38,7 +38,6 @@
 #include "NR_MAC_COMMON/nr_mac.h"
 #include "NR_MAC_gNB/nr_mac_gNB.h"
 #include "NR_MAC_COMMON/nr_mac_extern.h"
-#include "LAYER2/MAC/mac.h"
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
 
 /*NFAPI*/
@@ -454,7 +453,8 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id,
   AssertFatal(sched_ctrl->pucch_sched_idx >= 0, "no uplink slot for PUCCH found!\n");
 
   uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map;
-  const int current_harq_pid = sched_ctrl->current_harq_pid;
+  // for now HARQ PID is fixed and should be the same as in post-processor
+  const int current_harq_pid = slot % num_slots_per_tdd;
   NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid];
   NR_UE_ret_info_t *retInfo = &sched_ctrl->retInfo[current_harq_pid];
   const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, 275);
@@ -586,7 +586,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
                        1 /* nrOfLayers */)
         >> 3;
 
-    const int current_harq_pid = sched_ctrl->current_harq_pid;
+    const int current_harq_pid = slot % num_slots_per_tdd;
     NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid];
     NR_sched_pucch *pucch = &sched_ctrl->sched_pucch[sched_ctrl->pucch_sched_idx][sched_ctrl->pucch_occ_idx];
     harq->feedback_slot = pucch->ul_slot;
@@ -639,7 +639,15 @@ void nr_schedule_ue_spec(module_id_t module_id,
               retInfo->numDmrsCdmGrpsNoData);
       /* we do not have to do anything, since we do not require to get data
        * from RLC, encode MAC CEs, or copy data to FAPI structures */
-      LOG_W(MAC, "%d.%2d retransmission UE %d/RNTI %04x\n", frame, slot, UE_id, rnti);
+      LOG_W(MAC,
+            "%d.%2d DL retransmission UE %d/RNTI %04x HARQ PID %d round %d NDI %d\n",
+            frame,
+            slot,
+            UE_id,
+            rnti,
+            current_harq_pid,
+            harq->round,
+            harq->ndi);
     } else { /* initial transmission */
 
       /* reserve space for timing advance of UE if necessary,
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
index e14afacf097e5ce85fa935a3fa68c35a6351b7bd..851540b2f29311af11e2fa12fa8721c18f56bede 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
@@ -258,8 +258,6 @@ void nr_preprocessor_phytest(module_id_t module_id,
                              sub_frame_t slot,
                              int num_slots_per_tdd)
 {
-  if (slot != 1)
-    return; /* only schedule in slot 1 for now */
   NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info;
   const int UE_id = 0;
   const int CC_id = 0;
@@ -317,7 +315,7 @@ void nr_preprocessor_phytest(module_id_t module_id,
   sched_ctrl->coreset = get_coreset(
       sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */);
   const int cid = sched_ctrl->coreset->controlResourceSetId;
-  const uint16_t Y = UE_info->Y[UE_id][cid][RC.nrmac[module_id]->current_slot];
+  const uint16_t Y = UE_info->Y[UE_id][cid][slot];
   const int m = UE_info->num_pdcch_cand[UE_id][cid];
   sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id],
                                   sched_ctrl->active_bwp,
@@ -352,457 +350,131 @@ void nr_preprocessor_phytest(module_id_t module_id,
     vrb_map[rb + sched_ctrl->rbStart] = 1;
 }
 
-void config_uldci(NR_BWP_Uplink_t *ubwp,
-                  nfapi_nr_pusch_pdu_t *pusch_pdu,
-                  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
-                  dci_pdu_rel15_t *dci_pdu_rel15,
-                  int *dci_formats, int *rnti_types,
-                  int time_domain_assignment, uint8_t tpc,
-                  int n_ubwp, int bwp_id) {
-
-  switch(dci_formats[(pdcch_pdu_rel15->numDlDci)-1]) {
-    case NR_UL_DCI_FORMAT_0_0:
-      dci_pdu_rel15->frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size,
-                                                                                         pusch_pdu->rb_start,
-	                                                                                 NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275));
-
-      dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
-      dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
-      dci_pdu_rel15->mcs = 9;
-
-      dci_pdu_rel15->format_indicator = 0;
-      dci_pdu_rel15->ndi = 1;
-      dci_pdu_rel15->rv = 0;
-      dci_pdu_rel15->harq_pid = 0;
-      dci_pdu_rel15->tpc = 1;
-      break;
-    case NR_UL_DCI_FORMAT_0_1:
-      dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator;
-      dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index;
-      dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id;
-      dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
-      dci_pdu_rel15->dai[0].val = 0; //TODO
-      // bwp indicator
-      if (n_ubwp < 4)
-        dci_pdu_rel15->bwp_indicator.val = bwp_id;
-      else
-        dci_pdu_rel15->bwp_indicator.val = bwp_id - 1; // as per table 7.3.1.1.2-1 in 38.212
-      // frequency domain assignment
-      if (ubwp->bwp_Dedicated->pusch_Config->choice.setup->resourceAllocation==NR_PUSCH_Config__resourceAllocation_resourceAllocationType1)
-        dci_pdu_rel15->frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size,
-                                                                                             pusch_pdu->rb_start,
-                                                                                             NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275));
-      else
-        AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n");
-      // time domain assignment
-      dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
-      // mcs
-      dci_pdu_rel15->mcs = pusch_pdu->mcs_index;
-      // tpc command for pusch
-      dci_pdu_rel15->tpc = tpc;
-      // SRS resource indicator
-      if (ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig != NULL) {
-        if (*ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig == NR_PUSCH_Config__txConfig_codebook)
-          dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS
-        else
-          AssertFatal(1==0,"Non Codebook configuration non supported\n");
-      }
-      // Antenna Ports
-      dci_pdu_rel15->antenna_ports.val = 0; // TODO for now it is hardcoded, it should depends on cdm group no data and rank
-      // DMRS sequence initialization
-      dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid;
-      break;
-    default :
-      AssertFatal(1==0,"Valid UL formats are 0_0 and 0_1 \n");
-  }
-
-  LOG_D(MAC, "[gNB scheduler phytest] ULDCI type 0 payload: PDCCH CCEIndex %d, freq_alloc %d, time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n",
-	pdcch_pdu_rel15->dci_pdu.CceIndex[pdcch_pdu_rel15->numDlDci],
-	dci_pdu_rel15->frequency_domain_assignment.val,
-	dci_pdu_rel15->time_domain_assignment.val,
-	dci_pdu_rel15->frequency_hopping_flag.val,
-	dci_pdu_rel15->mcs,
-	dci_pdu_rel15->tpc,
-	dci_pdu_rel15->ndi, 
-	dci_pdu_rel15->rv);
-
-}
-    
-int8_t select_ul_harq_pid(NR_UE_sched_ctrl_t *sched_ctrl) {
-
-  uint8_t hrq_id;
-  uint8_t max_ul_harq_pids = 3; // temp: for testing
-  // schedule active harq processes
-  NR_UE_ul_harq_t cur_harq;
-  for (hrq_id=0; hrq_id < max_ul_harq_pids; hrq_id++) {
-    cur_harq = sched_ctrl->ul_harq_processes[hrq_id];
-    if (cur_harq.state==ACTIVE_NOT_SCHED) {
-#ifdef UL_HARQ_PRINT
-      printf("[SCHED] Found ulharq id %d, scheduling it for retransmission\n",hrq_id);
-#endif
-      return hrq_id;
-    }
-  }
+void nr_ul_preprocessor_phytest(module_id_t module_id,
+                                frame_t frame,
+                                sub_frame_t slot,
+                                int num_slots_per_tdd,
+                                uint64_t ulsch_in_slot_bitmap) {
+  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
+  NR_COMMON_channels_t *cc = nr_mac->common_channels;
+  NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
+  const int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
+  NR_UE_info_t *UE_info = &nr_mac->UE_info;
+
+  AssertFatal(UE_info->num_UEs <= 1,
+              "%s() cannot handle more than one UE, but found %d\n",
+              __func__,
+              UE_info->num_UEs);
+  if (UE_info->num_UEs == 0)
+    return;
 
-  // schedule new harq processes
-  for (hrq_id=0; hrq_id < max_ul_harq_pids; hrq_id++) {
-    cur_harq = sched_ctrl->ul_harq_processes[hrq_id];
-    if (cur_harq.state==INACTIVE) {
-#ifdef UL_HARQ_PRINT
-      printf("[SCHED] Found new ulharq id %d, scheduling it\n",hrq_id);
-#endif
-      return hrq_id;
-    }
-  }
-  LOG_E(MAC,"All UL HARQ processes are busy. Cannot schedule ULSCH\n");
-  return -1;
-}
+  const int UE_id = 0;
+  const int CC_id = 0;
 
-long get_K2(NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu) {
-  DevAssert(ubwp);
-  const NR_PUSCH_TimeDomainResourceAllocation_t *tda_list = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment];
-  if (tda_list->k2)
-    return *tda_list->k2;
-  else if (mu < 2)
-    return 1;
-  else if (mu == 2)
-    return 2;
-  else
-    return 3;
-}
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
 
-void schedule_fapi_ul_pdu(int Mod_idP,
-                          frame_t frameP,
-                          sub_frame_t slotP,
-                          int num_slots_per_tdd,
-                          int ul_slots,
-                          int time_domain_assignment,
-                          uint64_t ulsch_in_slot_bitmap) {
-
-  gNB_MAC_INST                      *nr_mac    = RC.nrmac[Mod_idP];
-  NR_COMMON_channels_t                  *cc    = nr_mac->common_channels;
-  NR_ServingCellConfigCommon_t         *scc    = cc->ServingCellConfigCommon;
-
-  int bwp_id=1;
-  int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
-  int UE_id = 0;
-  NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info;
-  AssertFatal(UE_info->active[UE_id],"Cannot find UE_id %d is not active\n",UE_id);
-
-  NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id];
-  AssertFatal(secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
-	      "downlinkBWP_ToAddModList has %d BWP!\n",
-	      secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count);
-  NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
-  int n_ubwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count;
-  NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1];
-  NR_PUSCH_Config_t *pusch_Config = ubwp->bwp_Dedicated->pusch_Config->choice.setup;
-
-  AssertFatal(time_domain_assignment<ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count,
-              "time_domain_assignment %d>=%d\n",time_domain_assignment,ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count);
-
-  int K2 = get_K2(ubwp, time_domain_assignment,mu);
-  /* check if slot is UL, and for phy test verify that it is in first TDD
-   * period, slot 8 (for K2=2, this is at slot 6 in the gNB; because of UE
+  const int tda = 1;
+  const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList =
+    sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
+  AssertFatal(tda < tdaList->list.count,
+              "time domain assignment %d >= %d\n",
+              tda,
+              tdaList->list.count);
+  int K2 = get_K2(sched_ctrl->active_ubwp, tda, mu);
+  const int sched_frame = frame + (slot + K2 >= num_slots_per_tdd);
+  const int sched_slot = (slot + K2) % num_slots_per_tdd;
+  /* check if slot is UL, and that slot is 8 (assuming K2=6 because of UE
    * limitations).  Note that if K2 or the TDD configuration is changed, below
    * conditions might exclude each other and never be true */
-  const int slot_idx = (slotP + K2) % num_slots_per_tdd;
-  if (is_xlsch_in_slot(ulsch_in_slot_bitmap, slot_idx)
-      && (!get_softmodem_params()->phy_test || slot_idx == 8)) {
-
-    nfapi_nr_ul_dci_request_t *UL_dci_req = &RC.nrmac[Mod_idP]->UL_dci_req[0];
-    UL_dci_req->SFN = frameP;
-    UL_dci_req->Slot = slotP;
-    nfapi_nr_ul_dci_request_pdus_t  *ul_dci_request_pdu;
-
-    AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList!=NULL,"searchPsacesToAddModList is null\n");
-    AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count>0,
-                "searchPsacesToAddModList is empty\n");
-
-    uint16_t rnti = UE_info->rnti[UE_id];
-
-    int first_ul_slot = num_slots_per_tdd - ul_slots;
-    NR_sched_pusch *pusch_sched = &UE_info->UE_sched_ctrl[UE_id].sched_pusch[slotP+K2-first_ul_slot];
-    pusch_sched->frame = frameP;
-    pusch_sched->slot = slotP + K2;
-    pusch_sched->active = true;
-    nfapi_nr_pusch_pdu_t  *pusch_pdu = &pusch_sched->pusch_pdu;
-    memset(pusch_pdu,0,sizeof(nfapi_nr_pusch_pdu_t));
-
-    LOG_D(MAC, "Scheduling UE specific PUSCH\n");
-    //UL_tti_req = &nr_mac->UL_tti_req[CC_id];
-
-    int dci_formats[2];
-    int rnti_types[2];
-
-    NR_SearchSpace_t *ss;
-    int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
-
-    AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList!=NULL,"searchPsacesToAddModList is null\n");
-    AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count>0,
-                "searchPsacesToAddModList is empty\n");
-
-    int found=0;
-
-    for (int i=0;i<bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count;i++) {
-      ss=bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i];
-      AssertFatal(ss->controlResourceSetId != NULL,"ss->controlResourceSetId is null\n");
-      AssertFatal(ss->searchSpaceType != NULL,"ss->searchSpaceType is null\n");
-      if (ss->searchSpaceType->present == target_ss) {
-        found=1;
-        break;
-      }
-    }
-    AssertFatal(found==1,"Couldn't find an adequate searchspace\n");
-
-    if (ss->searchSpaceType->choice.ue_Specific->dci_Formats)
-      dci_formats[0]  = NR_UL_DCI_FORMAT_0_1;
-    else
-      dci_formats[0]  = NR_UL_DCI_FORMAT_0_0;
-
-    rnti_types[0]   = NR_RNTI_C;
-
-    //Resource Allocation in time domain
-    int startSymbolAndLength=0;
-    int StartSymbolIndex,NrOfSymbols,mapping_type;
-
-    startSymbolAndLength = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->startSymbolAndLength;
-    SLIV2SL(startSymbolAndLength,&StartSymbolIndex,&NrOfSymbols);
-    pusch_pdu->start_symbol_index = StartSymbolIndex;
-    pusch_pdu->nr_of_symbols = NrOfSymbols;
-
-    mapping_type = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->mappingType;
-
-    pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA;
-    pusch_pdu->rnti = rnti;
-    pusch_pdu->handle = 0; //not yet used
-  
-    pusch_pdu->bwp_size  = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
-    pusch_pdu->bwp_start = NRRIV2PRBOFFSET(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
-    pusch_pdu->subcarrier_spacing = ubwp->bwp_Common->genericParameters.subcarrierSpacing;
-    pusch_pdu->cyclic_prefix = 0;
-
-    if (pusch_Config->transformPrecoder == NULL) {
-      if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL)
-        pusch_pdu->transform_precoding = 1;
-      else
-        pusch_pdu->transform_precoding = 0;
-    }
-    else
-      pusch_pdu->transform_precoding = *pusch_Config->transformPrecoder;
-    if (pusch_Config->dataScramblingIdentityPUSCH != NULL)
-      pusch_pdu->data_scrambling_id = *pusch_Config->dataScramblingIdentityPUSCH;
-    else
-      pusch_pdu->data_scrambling_id = *scc->physCellId;
-
-    pusch_pdu->mcs_index = 9;
-    if (pusch_pdu->transform_precoding)
-      pusch_pdu->mcs_table = get_pusch_mcs_table(pusch_Config->mcs_Table, 0,
-                                                 dci_formats[0], rnti_types[0], target_ss, false);
-    else
-      pusch_pdu->mcs_table = get_pusch_mcs_table(pusch_Config->mcs_TableTransformPrecoder, 1,
-                                                 dci_formats[0], rnti_types[0], target_ss, false);
-
-    pusch_pdu->target_code_rate = nr_get_code_rate_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table);
-    pusch_pdu->qam_mod_order = nr_get_Qm_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table);
-    if (pusch_Config->tp_pi2BPSK!=NULL) {
-      if(((pusch_pdu->mcs_table==3)&&(pusch_pdu->mcs_index<2)) ||
-         ((pusch_pdu->mcs_table==4)&&(pusch_pdu->mcs_index<6))) {
-        pusch_pdu->target_code_rate = pusch_pdu->target_code_rate>>1;
-        pusch_pdu->qam_mod_order = pusch_pdu->qam_mod_order<<1;
-      }
-    }
-    pusch_pdu->nrOfLayers = 1;
-
-    //Pusch Allocation in frequency domain [TS38.214, sec 6.1.2.2]
-    if (pusch_Config->resourceAllocation==NR_PUSCH_Config__resourceAllocation_resourceAllocationType1) {
-      pusch_pdu->resource_alloc = 1; //type 1
-      pusch_pdu->rb_start = 0;
-      if (get_softmodem_params()->phy_test==1)
-        pusch_pdu->rb_size = min(pusch_pdu->bwp_size,50);
-      else
-        pusch_pdu->rb_size = pusch_pdu->bwp_size;
-    }
-    else
-      AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n");
-
-    pusch_pdu->vrb_to_prb_mapping = 0;
-
-    if (pusch_Config->frequencyHopping==NULL)
-      pusch_pdu->frequency_hopping = 0;
-    else
-      pusch_pdu->frequency_hopping = 1;
-
-    //pusch_pdu->tx_direct_current_location;//The uplink Tx Direct Current location for the carrier. Only values in the value range of this field between 0 and 3299, which indicate the subcarrier index within the carrier corresponding 1o the numerology of the corresponding uplink BWP and value 3300, which indicates "Outside the carrier" and value 3301, which indicates "Undetermined position within the carrier" are used. [TS38.331, UplinkTxDirectCurrentBWP IE]
-    //pusch_pdu->uplink_frequency_shift_7p5khz = 0;
-
-
-    // --------------------
-    // ------- DMRS -------
-    // --------------------
-    NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig;
-    if (mapping_type == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA)
-      NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup;
-    else
-      NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
-    if (NR_DMRS_UplinkConfig->dmrs_Type == NULL)
-      pusch_pdu->dmrs_config_type = 0;
-    else
-      pusch_pdu->dmrs_config_type = 1;
-    pusch_pdu->scid = 0;      // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]
-    if (pusch_pdu->transform_precoding) { // transform precoding disabled
-      long *scramblingid;
-      if (pusch_pdu->scid == 0)
-        scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0;
-      else
-        scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID1;
-      if (scramblingid == NULL)
-        pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
-      else
-        pusch_pdu->ul_dmrs_scrambling_id = *scramblingid;
-    }
-    else {
-      pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
-      if (NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
-        pusch_pdu->pusch_identity = *NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity;
-      else
-        pusch_pdu->pusch_identity = *scc->physCellId;
-    }
-    pusch_dmrs_AdditionalPosition_t additional_pos;
-    if (NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NULL)
-      additional_pos = 2;
-    else {
-      if (*NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos3)
-        additional_pos = 3;
-      else
-        additional_pos = *NR_DMRS_UplinkConfig->dmrs_AdditionalPosition;
-    }
-    pusch_maxLength_t pusch_maxLength;
-    if (NR_DMRS_UplinkConfig->maxLength == NULL)
-      pusch_maxLength = 1;
-    else
-      pusch_maxLength = 2;
-    uint16_t l_prime_mask = get_l_prime(pusch_pdu->nr_of_symbols, mapping_type, additional_pos, pusch_maxLength);
-    pusch_pdu->ul_dmrs_symb_pos = l_prime_mask << pusch_pdu->start_symbol_index;
-
-    pusch_pdu->num_dmrs_cdm_grps_no_data = 1;
-    pusch_pdu->dmrs_ports = 1;
-    // --------------------------------------------------------------------------------------------------------------------------------------------
-
-    // --------------------
-    // ------- PTRS -------
-    // --------------------
-    if (NR_DMRS_UplinkConfig->phaseTrackingRS != NULL) {
-      // TODO to be fixed from RRC config
-      uint8_t ptrs_mcs1 = 2;  // higher layer parameter in PTRS-UplinkConfig
-      uint8_t ptrs_mcs2 = 4;  // higher layer parameter in PTRS-UplinkConfig
-      uint8_t ptrs_mcs3 = 10; // higher layer parameter in PTRS-UplinkConfig
-      uint16_t n_rb0 = 25;    // higher layer parameter in PTRS-UplinkConfig
-      uint16_t n_rb1 = 75;    // higher layer parameter in PTRS-UplinkConfig
-      pusch_pdu->pusch_ptrs.ptrs_time_density = get_L_ptrs(ptrs_mcs1, ptrs_mcs2, ptrs_mcs3, pusch_pdu->mcs_index, pusch_pdu->mcs_table);
-      pusch_pdu->pusch_ptrs.ptrs_freq_density = get_K_ptrs(n_rb0, n_rb1, pusch_pdu->rb_size);
-      pusch_pdu->pusch_ptrs.ptrs_ports_list   = (nfapi_nr_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ptrs_ports_t));
-      pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0;
-
-      pusch_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS; // enable PUSCH PTRS
-    }
-    else{
-      pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
+  if (!(is_xlsch_in_slot(ulsch_in_slot_bitmap, sched_slot) && sched_slot == 8))
+    return;
+
+  const uint16_t rbStart = 0;
+  const uint16_t rbSize = 50; /* due to OAI UE limitations */
+  uint16_t *vrb_map_UL =
+      &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * 275];
+  for (int i = rbStart; i < rbStart + rbSize; ++i) {
+    if (vrb_map_UL[i]) {
+      LOG_E(MAC,
+            "%s(): %4d.%2d RB %d is already reserved, cannot schedule UE\n",
+            __func__,
+            frame,
+            slot,
+            i);
+      return;
     }
+  }
 
-    // --------------------------------------------------------------------------------------------------------------------------------------------
-
-    //Pusch Allocation in frequency domain [TS38.214, sec 6.1.2.2]
-    //Optional Data only included if indicated in pduBitmap
-    int8_t harq_id = select_ul_harq_pid(&UE_info->UE_sched_ctrl[UE_id]);
-    if (harq_id < 0) return;
-    NR_UE_ul_harq_t *cur_harq = &UE_info->UE_sched_ctrl[UE_id].ul_harq_processes[harq_id];
-    pusch_pdu->pusch_data.harq_process_id = harq_id;
-    pusch_pdu->pusch_data.new_data_indicator = cur_harq->ndi;
-    pusch_pdu->pusch_data.rv_index = nr_rv_round_map[cur_harq->round];
-
-    cur_harq->state = ACTIVE_SCHED;
-    cur_harq->last_tx_slot = pusch_sched->slot;
-
-    uint8_t num_dmrs_symb = 0;
-
-    for(int dmrs_counter = pusch_pdu->start_symbol_index; dmrs_counter < pusch_pdu->start_symbol_index + pusch_pdu->nr_of_symbols; dmrs_counter++)
-      num_dmrs_symb += ((pusch_pdu->ul_dmrs_symb_pos >> dmrs_counter) & 1);
-
-    uint8_t N_PRB_DMRS;
-    if (pusch_pdu->dmrs_config_type == 0) {
-      N_PRB_DMRS = pusch_pdu->num_dmrs_cdm_grps_no_data*6;
-    }
-    else {
-      N_PRB_DMRS = pusch_pdu->num_dmrs_cdm_grps_no_data*4;
-    }
+  sched_ctrl->sched_pusch.slot = sched_slot;
+  sched_ctrl->sched_pusch.frame = sched_frame;
 
-    pusch_pdu->pusch_data.tb_size = nr_compute_tbs(pusch_pdu->qam_mod_order,
-                                                   pusch_pdu->target_code_rate,
-                                                   pusch_pdu->rb_size,
-                                                   pusch_pdu->nr_of_symbols,
-                                                   N_PRB_DMRS * num_dmrs_symb,
-                                                   0, //nb_rb_oh
-                                                   0,
-                                                   pusch_pdu->nrOfLayers)>>3;
-
-    UE_info->mac_stats[UE_id].ulsch_rounds[cur_harq->round]++;
-    if (cur_harq->round == 0) UE_info->mac_stats[UE_id].ulsch_total_bytes_scheduled+=pusch_pdu->pusch_data.tb_size;
-
-    pusch_pdu->pusch_data.num_cb = 0; //CBG not supported
-    //pusch_pdu->pusch_data.cb_present_and_position;
-    //pusch_pdu->pusch_uci;
-    //pusch_pdu->pusch_ptrs;
-    //pusch_pdu->dfts_ofdm;
-    //beamforming
-    //pusch_pdu->beamforming; //not used for now
-
-
-    ul_dci_request_pdu = &UL_dci_req->ul_dci_pdu_list[UL_dci_req->numPdus];
-    memset((void*)ul_dci_request_pdu,0,sizeof(nfapi_nr_ul_dci_request_pdus_t));
-    ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE;
-    ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu));
-    nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15;
-    UL_dci_req->numPdus+=1;
-
-
-    LOG_D(MAC,"Configuring ULDCI/PDCCH in %d.%d\n", frameP,slotP);
-
-    uint8_t nr_of_candidates, aggregation_level;
-    find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss);
-    NR_ControlResourceSet_t *coreset = get_coreset(bwp, ss, 1 /* dedicated */);
-    const int cid = coreset->controlResourceSetId;
-    const uint16_t Y = UE_info->Y[UE_id][cid][nr_mac->current_slot];
-    const int m = UE_info->num_pdcch_cand[UE_id][cid];
-    int CCEIndex = allocate_nr_CCEs(nr_mac,
-                                    bwp,
-                                    coreset,
-                                    aggregation_level,
-                                    Y,
-                                    m,
-                                    nr_of_candidates);
-    if (CCEIndex < 0) {
-      LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__);
-      pusch_sched->active = false;
-      return;
-    }
-    else {
-      UE_info->num_pdcch_cand[UE_id][cid]++;
-      nr_configure_pdcch(nr_mac,
-                         pdcch_pdu_rel15,
-                         UE_info->rnti[UE_id],
-                         ss,
-                         coreset,
-                         scc,
-                         bwp,
-                         aggregation_level,
-                         CCEIndex);
-
-      dci_pdu_rel15_t *dci_pdu_rel15 = calloc(MAX_DCI_CORESET,sizeof(dci_pdu_rel15_t));
-      config_uldci(ubwp,pusch_pdu,pdcch_pdu_rel15,&dci_pdu_rel15[0],dci_formats,rnti_types,time_domain_assignment,UE_info->UE_sched_ctrl[UE_id].tpc0,n_ubwp,bwp_id);
-      fill_dci_pdu_rel15(scc,secondaryCellGroup,pdcch_pdu_rel15,dci_pdu_rel15,dci_formats,rnti_types,pusch_pdu->bwp_size,bwp_id);
-      free(dci_pdu_rel15);
-    }
+  const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+  sched_ctrl->search_space = get_searchspace(sched_ctrl->active_bwp, target_ss);
+  uint8_t nr_of_candidates;
+  find_aggregation_candidates(&sched_ctrl->aggregation_level,
+                              &nr_of_candidates,
+                              sched_ctrl->search_space);
+  sched_ctrl->coreset = get_coreset(
+      sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */);
+  const int cid = sched_ctrl->coreset->controlResourceSetId;
+  const uint16_t Y = UE_info->Y[UE_id][cid][slot];
+  const int m = UE_info->num_pdcch_cand[UE_id][cid];
+  sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id],
+                                           sched_ctrl->active_bwp,
+                                           sched_ctrl->coreset,
+                                           sched_ctrl->aggregation_level,
+                                           Y,
+                                           m,
+                                           nr_of_candidates);
+  if (sched_ctrl->cce_index < 0) {
+    LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__);
+    return;
   }
-}
+  UE_info->num_pdcch_cand[UE_id][cid]++;
+
+  sched_ctrl->sched_pusch.time_domain_allocation = tda;
+  const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats;
+  const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0;
+  const uint8_t num_dmrs_cdm_grps_no_data = 1;
+  /* we want to avoid a lengthy deduction of DMRS and other parameters in
+   * every TTI if we can save it, so check whether dci_format, TDA, or
+   * num_dmrs_cdm_grps_no_data has changed and only then recompute */
+  NR_sched_pusch_save_t *ps = &sched_ctrl->pusch_save;
+  if (ps->time_domain_allocation != tda
+      || ps->dci_format != dci_format
+      || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data)
+    nr_save_pusch_fields(scc,
+                         sched_ctrl->active_ubwp,
+                         dci_format,
+                         tda,
+                         num_dmrs_cdm_grps_no_data,
+                         ps);
+
+  const int mcs = 9;
+  NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
+  sched_pusch->mcs = mcs;
+  sched_pusch->rbStart = rbStart;
+  sched_pusch->rbSize = rbSize;
+
+  /* Calculate TBS from MCS */
+  sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table);
+  sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table);
+  if (ps->pusch_Config->tp_pi2BPSK
+      && ((ps->mcs_table == 3 && mcs < 2) || (ps->mcs_table == 4 && mcs < 6))) {
+    sched_pusch->R >>= 1;
+    sched_pusch->Qm <<= 1;
+  }
+  sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm,
+                                        sched_pusch->R,
+                                        sched_pusch->rbSize,
+                                        ps->nrOfSymbols,
+                                        ps->N_PRB_DMRS * ps->num_dmrs_symb,
+                                        0, // nb_rb_oh
+                                        0,
+                                        1 /* NrOfLayers */)
+                         >> 3;
 
+  /* mark the corresponding RBs as used */
+  for (int rb = rbStart; rb < rbStart + rbSize; rb++)
+    vrb_map_UL[rb] = 1;
+}
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index 12d5471deb0d0834cfd220ef28a3c8dde2043417..f97434470d3c53b0f5421a2c7734dbf90ce94e59 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -32,7 +32,6 @@
 
 #include "assertions.h"
 
-#include "LAYER2/MAC/mac.h"
 #include "NR_MAC_gNB/nr_mac_gNB.h"
 #include "NR_MAC_COMMON/nr_mac_extern.h"
 
@@ -48,9 +47,6 @@
 #include "RRC/NR/nr_rrc_extern.h"
 #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
 
-//#include "LAYER2/MAC/pre_processor.c"
-#include "pdcp.h"
-
 #include "intertask_interface.h"
 
 #include "T.h"
@@ -219,6 +215,75 @@ int allocate_nr_CCEs(gNB_MAC_INST *nr_mac,
 
 }
 
+void nr_save_pusch_fields(const NR_ServingCellConfigCommon_t *scc,
+                          const NR_BWP_Uplink_t *ubwp,
+                          long dci_format,
+                          int tda,
+                          uint8_t num_dmrs_cdm_grps_no_data,
+                          NR_sched_pusch_save_t *ps)
+{
+  ps->dci_format = dci_format;
+  ps->time_domain_allocation = tda;
+  ps->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data;
+
+  const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList =
+      ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
+  const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength;
+  SLIV2SL(startSymbolAndLength,
+          &ps->startSymbolIndex,
+          &ps->nrOfSymbols);
+
+  ps->pusch_Config = ubwp->bwp_Dedicated->pusch_Config->choice.setup;
+  if (!ps->pusch_Config->transformPrecoder)
+    ps->transform_precoding = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder;
+  else
+    ps->transform_precoding = *ps->pusch_Config->transformPrecoder;
+  const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+  if (ps->transform_precoding)
+    ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config->mcs_Table,
+                                    0,
+                                    ps->dci_format,
+                                    NR_RNTI_C,
+                                    target_ss,
+                                    false);
+  else
+    ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config->mcs_TableTransformPrecoder,
+                                    1,
+                                    ps->dci_format,
+                                    NR_RNTI_C,
+                                    target_ss,
+                                    false);
+
+  /* DMRS calculations */
+  ps->mapping_type = tdaList->list.array[tda]->mappingType;
+  ps->NR_DMRS_UplinkConfig =
+      ps->mapping_type == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA
+          ? ps->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup
+          : ps->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
+  ps->dmrs_config_type = ps->NR_DMRS_UplinkConfig->dmrs_Type == NULL ? 0 : 1;
+  const pusch_dmrs_AdditionalPosition_t additional_pos =
+      ps->NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NULL
+          ? 2
+          : (*ps->NR_DMRS_UplinkConfig->dmrs_AdditionalPosition ==
+                     NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos3
+                 ? 3
+                 : *ps->NR_DMRS_UplinkConfig->dmrs_AdditionalPosition);
+  const pusch_maxLength_t pusch_maxLength =
+      ps->NR_DMRS_UplinkConfig->maxLength == NULL ? 1 : 2;
+  const uint16_t l_prime_mask = get_l_prime(ps->nrOfSymbols,
+                                            ps->mapping_type,
+                                            additional_pos,
+                                            pusch_maxLength);
+  ps->ul_dmrs_symb_pos = l_prime_mask << ps->startSymbolIndex;
+  uint8_t num_dmrs_symb = 0;
+  for(int i = ps->startSymbolIndex; i < ps->startSymbolIndex + ps->nrOfSymbols; i++)
+    num_dmrs_symb += (ps->ul_dmrs_symb_pos >> i) & 1;
+  ps->num_dmrs_symb = num_dmrs_symb;
+  ps->N_PRB_DMRS = ps->dmrs_config_type == 0
+      ? num_dmrs_cdm_grps_no_data * 6
+      : num_dmrs_cdm_grps_no_data * 4;
+}
+
 void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu,
 				  nr_scs_e scs_common,
 				  nr_scs_e pdcch_scs,
@@ -643,6 +708,81 @@ void nr_fill_nfapi_dl_pdu(int Mod_idP,
   dl_req->nPDUs += 2;
 }
 
+void config_uldci(NR_BWP_Uplink_t *ubwp,
+                  nfapi_nr_pusch_pdu_t *pusch_pdu,
+                  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
+                  dci_pdu_rel15_t *dci_pdu_rel15,
+                  int *dci_formats,
+                  int time_domain_assignment, uint8_t tpc,
+                  int n_ubwp, int bwp_id) {
+  const int bw = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, 275);
+  switch (dci_formats[(pdcch_pdu_rel15->numDlDci) - 1]) {
+    case NR_UL_DCI_FORMAT_0_0:
+      dci_pdu_rel15->frequency_domain_assignment.val =
+          PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, bw);
+
+      dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
+      dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
+      dci_pdu_rel15->mcs = pusch_pdu->mcs_index;
+
+      dci_pdu_rel15->format_indicator = 0;
+      dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator;
+      dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index;
+      dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id;
+      dci_pdu_rel15->tpc = tpc;
+      break;
+    case NR_UL_DCI_FORMAT_0_1:
+      dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator;
+      dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index;
+      dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id;
+      dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
+      dci_pdu_rel15->dai[0].val = 0; //TODO
+      // bwp indicator
+      if (n_ubwp < 4)
+        dci_pdu_rel15->bwp_indicator.val = bwp_id;
+      else
+        dci_pdu_rel15->bwp_indicator.val = bwp_id - 1; // as per table 7.3.1.1.2-1 in 38.212
+      // frequency domain assignment
+      AssertFatal(ubwp->bwp_Dedicated->pusch_Config->choice.setup->resourceAllocation
+                      == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1,
+                  "Only frequency resource allocation type 1 is currently supported\n");
+      dci_pdu_rel15->frequency_domain_assignment.val =
+          PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, bw);
+      // time domain assignment
+      dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
+      // mcs
+      dci_pdu_rel15->mcs = pusch_pdu->mcs_index;
+      // tpc command for pusch
+      dci_pdu_rel15->tpc = tpc;
+      // SRS resource indicator
+      if (ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig != NULL) {
+        AssertFatal(*ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig == NR_PUSCH_Config__txConfig_codebook,
+                    "Non Codebook configuration non supported\n");
+        dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS
+      }
+      // Antenna Ports
+      dci_pdu_rel15->antenna_ports.val = 0; // TODO for now it is hardcoded, it should depends on cdm group no data and rank
+      // DMRS sequence initialization
+      dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid;
+      break;
+    default :
+      AssertFatal(0, "Valid UL formats are 0_0 and 0_1\n");
+  }
+
+  LOG_D(MAC,
+        "%s() ULDCI type 0 payload: PDCCH CCEIndex %d, freq_alloc %d, "
+        "time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n",
+        __func__,
+        pdcch_pdu_rel15->dci_pdu.CceIndex[pdcch_pdu_rel15->numDlDci],
+        dci_pdu_rel15->frequency_domain_assignment.val,
+        dci_pdu_rel15->time_domain_assignment.val,
+        dci_pdu_rel15->frequency_hopping_flag.val,
+        dci_pdu_rel15->mcs,
+        dci_pdu_rel15->tpc,
+        dci_pdu_rel15->ndi,
+        dci_pdu_rel15->rv);
+}
+
 void nr_configure_pdcch(gNB_MAC_INST *nr_mac,
                         nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu,
                         uint16_t rnti,
@@ -1751,20 +1891,17 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){
     UE_info->UE_sched_ctrl[UE_id].ta_update = 31;
     UE_info->UE_sched_ctrl[UE_id].ta_apply = false;
     UE_info->UE_sched_ctrl[UE_id].ul_rssi = 0;
+    /* set illegal time domain allocation to force recomputation of all fields */
+    UE_info->UE_sched_ctrl[UE_id].pusch_save.time_domain_allocation = -1;
     UE_info->UE_sched_ctrl[UE_id].sched_pucch = (NR_sched_pucch **)malloc(num_slots_ul*sizeof(NR_sched_pucch *));
     for (int s=0; s<num_slots_ul;s++)
       UE_info->UE_sched_ctrl[UE_id].sched_pucch[s] = (NR_sched_pucch *)malloc(2*sizeof(NR_sched_pucch));
-    UE_info->UE_sched_ctrl[UE_id].sched_pusch = (NR_sched_pusch *)malloc(num_slots_ul*sizeof(NR_sched_pusch));
 
     for (int k=0; k<num_slots_ul; k++) {
       for (int l=0; l<2; l++)
         memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l],
                0,
                sizeof(NR_sched_pucch));
-
-      memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pusch[k],
-             0,
-             sizeof(NR_sched_pusch));
     }
     LOG_I(MAC, "gNB %d] Add NR UE_id %d : rnti %x\n",
           mod_idP,
@@ -1806,7 +1943,6 @@ void mac_remove_nr_ue(module_id_t mod_id, rnti_t rnti)
     UE_info->rnti[UE_id] = 0;
     remove_nr_ue_list(&UE_info->list, UE_id);
     free(UE_info->UE_sched_ctrl[UE_id].sched_pucch);
-    free(UE_info->UE_sched_ctrl[UE_id].sched_pusch);
     memset((void *) &UE_info->UE_sched_ctrl[UE_id],
            0,
            sizeof(NR_UE_sched_ctrl_t));
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
index 909a3ea540bd21975699832ad702fe870498d49d..ec5195ec5beacf7c19ff9f40ed5f483da4f4e115 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
@@ -39,51 +39,59 @@ void nr_schedule_pucch(int Mod_idP,
                        int nr_ulmix_slots,
                        frame_t frameP,
                        sub_frame_t slotP) {
-
-  uint16_t O_csi, O_ack, O_uci;
-  uint8_t O_sr = 0; // no SR in PUCCH implemented for now
-  NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon;
   NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info;
   AssertFatal(UE_info->active[UE_id],"Cannot find UE_id %d is not active\n",UE_id);
 
-  NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id];
-  int bwp_id=1;
-  NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
-  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
-
-  NR_sched_pucch *curr_pucch;
-
   for (int k=0; k<nr_ulmix_slots; k++) {
     for (int l=0; l<2; l++) {
-      curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l];
-      O_ack = curr_pucch->dai_c;
-      O_csi = curr_pucch->csi_bits;
-      O_uci = O_ack + O_csi + O_sr;
-      if ((O_uci>0) && (frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) {
-        UL_tti_req->SFN = curr_pucch->frame;
-        UL_tti_req->Slot = curr_pucch->ul_slot;
-        UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE;
-        UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t);
-        nfapi_nr_pucch_pdu_t  *pucch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pucch_pdu;
-        memset(pucch_pdu,0,sizeof(nfapi_nr_pucch_pdu_t));
-        UL_tti_req->n_pdus+=1;
-
-        LOG_D(MAC,"Scheduling pucch reception for frame %d slot %d with (%d, %d, %d) (SR ACK, CSI) bits\n",
-              frameP,slotP,O_sr,O_ack,curr_pucch->csi_bits);
-
-        nr_configure_pucch(pucch_pdu,
-                           scc,
-                           ubwp,
-                           UE_info->rnti[UE_id],
-                           curr_pucch->resource_indicator,
-                           O_csi,
-                           O_ack,
-                           O_sr);
-
-        memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l],
-               0,
-               sizeof(NR_sched_pucch));
-      }
+      NR_sched_pucch *curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l];
+      const uint16_t O_ack = curr_pucch->dai_c;
+      const uint16_t O_csi = curr_pucch->csi_bits;
+      const uint8_t O_sr = 0; // no SR in PUCCH implemented for now
+      if (O_ack + O_csi + O_sr == 0
+          || frameP != curr_pucch->frame
+          || slotP != curr_pucch->ul_slot)
+        continue;
+
+      nfapi_nr_ul_tti_request_t *future_ul_tti_req =
+          &RC.nrmac[Mod_idP]->UL_tti_req_ahead[0][curr_pucch->ul_slot];
+      AssertFatal(future_ul_tti_req->SFN == curr_pucch->frame
+                  && future_ul_tti_req->Slot == curr_pucch->ul_slot,
+                  "future UL_tti_req's frame.slot %d.%d does not match PUCCH %d.%d\n",
+                  future_ul_tti_req->SFN,
+                  future_ul_tti_req->Slot,
+                  curr_pucch->frame,
+                  curr_pucch->ul_slot);
+      future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE;
+      future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t);
+      nfapi_nr_pucch_pdu_t *pucch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pucch_pdu;
+      memset(pucch_pdu, 0, sizeof(nfapi_nr_pucch_pdu_t));
+      future_ul_tti_req->n_pdus += 1;
+
+      LOG_D(MAC,
+            "%4d.%2d Scheduling pucch reception in %4d.%2d: bits SR %d, ACK %d, CSI %d, k %d l %d\n",
+            frameP,
+            slotP,
+            curr_pucch->frame,
+            curr_pucch->ul_slot,
+            O_sr,
+            O_ack,
+            O_csi,
+            k, l);
+
+      NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon;
+      nr_configure_pucch(pucch_pdu,
+                         scc,
+                         UE_info->UE_sched_ctrl[UE_id].active_ubwp,
+                         UE_info->rnti[UE_id],
+                         curr_pucch->resource_indicator,
+                         O_csi,
+                         O_ack,
+                         O_sr);
+
+      memset(&UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l],
+             0,
+             sizeof(NR_sched_pucch));
     }
   }
 }
@@ -147,7 +155,7 @@ void compute_csi_bitlen (NR_CellGroupConfig_t *secondaryCellGroup, NR_UE_info_t
                 UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen =0;
               }
 
-              LOG_I (MAC, "UCI: CSI_bit len : ssbri %d, rsrp: %d, diff_rsrp: %d",
+              LOG_I (MAC, "UCI: CSI_bit len : ssbri %d, rsrp: %d, diff_rsrp: %d\n",
                      UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].cri_ssbri_bitlen,
                      UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].rsrp_bitlen,
                      UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen);
@@ -213,7 +221,7 @@ void nr_csi_meas_reporting(int Mod_idP,
     if ( (frame%(period/n_slots_frame)==(offset/n_slots_frame)) && (slot==((sched_slot/slots_per_tdd)*slots_per_tdd))) {
 
       // we are scheduling pucch for csi in the first pucch occasion (this comes before ack/nack)
-      curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[sched_slot-slots_per_tdd+ul_slots][0];
+      curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[(sched_slot%slots_per_tdd)-slots_per_tdd+ul_slots][0];
 
       NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0];
 
@@ -266,15 +274,27 @@ void nr_csi_meas_reporting(int Mod_idP,
 }
 
 
-void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
-                   nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01,
-                   nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234,
-                   NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats) {
+void handle_nr_uci_pucch_0_1(module_id_t mod_id,
+                             frame_t frame,
+                             sub_frame_t slot,
+                             const nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01)
+{
+  int UE_id = find_nr_UE_id(mod_id, uci_01->rnti);
+  if (UE_id < 0) {
+    LOG_E(MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_01->rnti);
+    return;
+  }
+  NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info;
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
+
+  // tpc (power control)
+  sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10,
+                                uci_01->ul_cqi,
+                                30);
 
   // TODO
   int max_harq_rounds = 4; // TODO define macro
-
-  if (uci_01 != NULL) {
+  if (((uci_01->pduBitmap >> 1) & 0x01)) {
     // handle harq
     int harq_idx_s = 0;
 
@@ -283,7 +303,7 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
       // search for the right harq process
       for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES; harq_idx++) {
         // if the gNB received ack with a good confidence
-        if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
+        if ((slot - 1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
           sched_ctrl->harq_processes[harq_idx].feedback_slot = -1;
           if ((uci_01->harq->harq_list[harq_bit].harq_value == 1) &&
               (uci_01->harq->harq_confidence_level == 0)) {
@@ -299,13 +319,13 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
           if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) {
             sched_ctrl->harq_processes[harq_idx].ndi ^= 1;
             sched_ctrl->harq_processes[harq_idx].round = 0;
-            stats->dlsch_errors++;
+            UE_info->mac_stats[UE_id].dlsch_errors++;
           }
           break;
         }
         // if feedback slot processing is aborted
         else if (sched_ctrl->harq_processes[harq_idx].feedback_slot != -1
-                 && (UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot
+                 && (slot - 1) > sched_ctrl->harq_processes[harq_idx].feedback_slot
                  && sched_ctrl->harq_processes[harq_idx].is_waiting) {
           sched_ctrl->harq_processes[harq_idx].feedback_slot = -1;
           sched_ctrl->harq_processes[harq_idx].round++;
@@ -318,9 +338,29 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
       }
     }
   }
+}
+
+void handle_nr_uci_pucch_2_3_4(module_id_t mod_id,
+                               frame_t frame,
+                               sub_frame_t slot,
+                               const nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234)
+{
+  int UE_id = find_nr_UE_id(mod_id, uci_234->rnti);
+  if (UE_id < 0) {
+    LOG_E(MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_234->rnti);
+    return;
+  }
+  NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info;
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
 
+  // tpc (power control)
+  sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10,
+                                uci_234->ul_cqi,
+                                30);
 
-  if (uci_234 != NULL) {
+  // TODO
+  int max_harq_rounds = 4; // TODO define macro
+  if ((uci_234->pduBitmap >> 1) & 0x01) {
     int harq_idx_s = 0;
     int acknack;
 
@@ -329,7 +369,7 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
       acknack = ((uci_234->harq.harq_payload[harq_bit>>3])>>harq_bit)&0x01;
       for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES-1; harq_idx++) {
         // if the gNB received ack with a good confidence or if the max harq rounds was reached
-        if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
+        if ((slot - 1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
           // TODO add some confidence level for when there is no CRC
           sched_ctrl->harq_processes[harq_idx].feedback_slot = -1;
           if ((uci_234->harq.harq_crc != 1) && acknack) {
@@ -345,13 +385,13 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
           if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) {
             sched_ctrl->harq_processes[harq_idx].ndi ^= 1;
             sched_ctrl->harq_processes[harq_idx].round = 0;
-            stats->dlsch_errors++;
+            UE_info->mac_stats[UE_id].dlsch_errors++;
           }
           break;
         }
         // if feedback slot processing is aborted
         else if (sched_ctrl->harq_processes[harq_idx].feedback_slot != -1
-                 && (UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot
+                 && (slot - 1) > sched_ctrl->harq_processes[harq_idx].feedback_slot
                  && sched_ctrl->harq_processes[harq_idx].is_waiting) {
           sched_ctrl->harq_processes[harq_idx].feedback_slot = -1;
           sched_ctrl->harq_processes[harq_idx].round++;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
index 76c9dedf30c64cc387f13bc0cc83df5b70f9db27..91e37cc657ccf85912ffacfe8f81991dce72b3ca 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
@@ -31,7 +31,7 @@
 
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
 #include "executables/softmodem-common.h"
-//#define ENABLE_MAC_PAYLOAD_DEBUG 1
+#include "common/utils/nr/nr_common.h"
 
 
 void nr_process_mac_pdu(
@@ -261,37 +261,58 @@ void nr_process_mac_pdu(
     }
 }
 
-void handle_nr_ul_harq(uint16_t slot, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats, nfapi_nr_crc_t crc_pdu) {
+void handle_nr_ul_harq(module_id_t mod_id,
+                       frame_t frame,
+                       sub_frame_t slot,
+                       const nfapi_nr_crc_t *crc_pdu)
+{
+  int UE_id = find_nr_UE_id(mod_id, crc_pdu->rnti);
+  if (UE_id < 0) {
+    LOG_E(MAC, "%s(): unknown RNTI %04x in PUSCH\n", __func__, crc_pdu->rnti);
+    return;
+  }
+  NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info;
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
 
   int max_harq_rounds = 4; // TODO define macro
-  uint8_t hrq_id = crc_pdu.harq_id;
+  uint8_t hrq_id = crc_pdu->harq_id;
   NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id];
   if (cur_harq->state==ACTIVE_SCHED) {
-    if (!crc_pdu.tb_crc_status) {
+    if (!crc_pdu->tb_crc_status) {
       cur_harq->ndi ^= 1;
       cur_harq->round = 0;
       cur_harq->state = INACTIVE; // passed -> make inactive. can be used by scheduder for next grant
-#ifdef UL_HARQ_PRINT
-      printf("[HARQ HANDLER] Ulharq id %d crc passed, freeing it for scheduler\n",hrq_id);
-#endif
+      LOG_D(MAC,
+            "Ulharq id %d crc passed for RNTI %04x\n",
+            hrq_id,
+            crc_pdu->rnti);
     } else {
       cur_harq->round++;
       cur_harq->state = ACTIVE_NOT_SCHED;
-#ifdef UL_HARQ_PRINT
-      printf("[HARQ HANDLER] Ulharq id %d crc failed, requesting retransmission\n",hrq_id);
-#endif
+      LOG_D(MAC,
+            "Ulharq id %d crc failed for RNTI %04x\n",
+            hrq_id,
+            crc_pdu->rnti);
     }
 
     if (!(cur_harq->round<max_harq_rounds)) {
       cur_harq->ndi ^= 1;
       cur_harq->state = INACTIVE; // failed after 4 rounds -> make inactive
       cur_harq->round = 0;
-      LOG_D(MAC,"[HARQ HANDLER] RNTI %x: Ulharq id %d crc failed in all round, freeing it for scheduler\n",crc_pdu.rnti,hrq_id);
-      stats->ulsch_errors++;
+      LOG_D(MAC,
+            "RNTI %04x: Ulharq id %d crc failed in all rounds\n",
+            crc_pdu->rnti,
+            hrq_id);
+      UE_info->mac_stats[UE_id].ulsch_errors++;
     }
     return;
   } else
-    LOG_W(MAC,"Incorrect ULSCH HARQ process %d or invalid state %d (ignore this warning for RA)\n",hrq_id,cur_harq->state);
+    LOG_W(MAC,
+          "Incorrect ULSCH HARQ PID %d or invalid state %d for RNTI %04x "
+          "(ignore this warning for RA)\n",
+          hrq_id,
+          cur_harq->state,
+          crc_pdu->rnti);
 }
 
 /*
@@ -399,6 +420,11 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
                   bwpList->list.count);
       const int bwp_id = 1;
       UE_info->UE_sched_ctrl[UE_id].active_bwp = bwpList->list.array[bwp_id - 1];
+      struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList;
+      AssertFatal(ubwpList->list.count == 1,
+                  "uplinkBWP_ToAddModList has %d BWP!\n",
+                  ubwpList->list.count);
+      UE_info->UE_sched_ctrl[UE_id].active_ubwp = ubwpList->list.array[bwp_id - 1];
       LOG_I(MAC,
             "[gNB %d][RAPROC] PUSCH with TC_RNTI %x received correctly, "
             "adding UE MAC Context UE_id %d/RNTI %04x\n",
@@ -415,8 +441,389 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
             "reset RA state information for RA-RNTI %04x/index %d\n",
             ra->rnti,
             i);
+
       return;
     }
   }
+}
+
+long get_K2(NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu) {
+  DevAssert(ubwp);
+  const NR_PUSCH_TimeDomainResourceAllocation_t *tda_list = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment];
+  if (tda_list->k2)
+    return *tda_list->k2;
+  else if (mu < 2)
+    return 1;
+  else if (mu == 2)
+    return 2;
+  else
+    return 3;
+}
+
+int8_t select_ul_harq_pid(NR_UE_sched_ctrl_t *sched_ctrl) {
+  const uint8_t max_ul_harq_pids = 3; // temp: for testing
+  // schedule active harq processes
+  for (uint8_t hrq_id = 0; hrq_id < max_ul_harq_pids; hrq_id++) {
+    NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id];
+    if (cur_harq->state == ACTIVE_NOT_SCHED) {
+      LOG_D(MAC, "Found ulharq id %d, scheduling it for retransmission\n", hrq_id);
+      return hrq_id;
+    }
+  }
+
+  // schedule new harq processes
+  for (uint8_t hrq_id=0; hrq_id < max_ul_harq_pids; hrq_id++) {
+    NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id];
+    if (cur_harq->state == INACTIVE) {
+      LOG_D(MAC, "Found new ulharq id %d, scheduling it\n", hrq_id);
+      return hrq_id;
+    }
+  }
+  LOG_E(MAC, "All UL HARQ processes are busy. Cannot schedule ULSCH\n");
+  return -1;
+}
+
+void nr_simple_ulsch_preprocessor(module_id_t module_id,
+                                  frame_t frame,
+                                  sub_frame_t slot,
+                                  int num_slots_per_tdd,
+                                  uint64_t ulsch_in_slot_bitmap) {
+  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
+  NR_COMMON_channels_t *cc = nr_mac->common_channels;
+  NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
+  const int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
+  NR_UE_info_t *UE_info = &nr_mac->UE_info;
+
+  AssertFatal(UE_info->num_UEs <= 1,
+              "%s() cannot handle more than one UE, but found %d\n",
+              __func__,
+              UE_info->num_UEs);
+  if (UE_info->num_UEs == 0)
+    return;
+
+  const int UE_id = 0;
+  const int CC_id = 0;
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
+
+  const int tda = 1;
+  const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList =
+    sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
+  AssertFatal(tda < tdaList->list.count,
+              "time domain assignment %d >= %d\n",
+              tda,
+              tdaList->list.count);
+  int K2 = get_K2(sched_ctrl->active_ubwp, tda, mu);
+  const int sched_frame = frame + (slot + K2 >= num_slots_per_tdd);
+  const int sched_slot = (slot + K2) % num_slots_per_tdd;
+  if (!is_xlsch_in_slot(ulsch_in_slot_bitmap, sched_slot))
+    return;
+
+  /* get first, largest unallocated region */
+  uint16_t *vrb_map_UL =
+      &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * 275];
+  uint16_t rbStart = 0;
+  while (vrb_map_UL[rbStart]) rbStart++;
+  const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+  uint16_t rbSize = 1;
+  while (rbStart + rbSize < bwpSize && !vrb_map_UL[rbStart+rbSize])
+    rbSize++;
+
+  sched_ctrl->sched_pusch.slot = sched_slot;
+  sched_ctrl->sched_pusch.frame = sched_frame;
+
+  const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+  sched_ctrl->search_space = get_searchspace(sched_ctrl->active_bwp, target_ss);
+  uint8_t nr_of_candidates;
+  find_aggregation_candidates(&sched_ctrl->aggregation_level,
+                              &nr_of_candidates,
+                              sched_ctrl->search_space);
+  sched_ctrl->coreset = get_coreset(
+      sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */);
+  const int cid = sched_ctrl->coreset->controlResourceSetId;
+  const uint16_t Y = UE_info->Y[UE_id][cid][slot];
+  const int m = UE_info->num_pdcch_cand[UE_id][cid];
+  sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id],
+                                           sched_ctrl->active_bwp,
+                                           sched_ctrl->coreset,
+                                           sched_ctrl->aggregation_level,
+                                           Y,
+                                           m,
+                                           nr_of_candidates);
+  if (sched_ctrl->cce_index < 0) {
+    LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__);
+    return;
+  }
+  UE_info->num_pdcch_cand[UE_id][cid]++;
+
+  sched_ctrl->sched_pusch.time_domain_allocation = tda;
+  const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats;
+  const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0;
+  const uint8_t num_dmrs_cdm_grps_no_data = 1;
+  /* we want to avoid a lengthy deduction of DMRS and other parameters in
+   * every TTI if we can save it, so check whether dci_format, TDA, or
+   * num_dmrs_cdm_grps_no_data has changed and only then recompute */
+  NR_sched_pusch_save_t *ps = &sched_ctrl->pusch_save;
+  if (ps->time_domain_allocation != tda
+      || ps->dci_format != dci_format
+      || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data)
+    nr_save_pusch_fields(scc,
+                         sched_ctrl->active_ubwp,
+                         dci_format,
+                         tda,
+                         num_dmrs_cdm_grps_no_data,
+                         ps);
+
+  const int mcs = 9;
+  NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
+  sched_pusch->mcs = mcs;
+  sched_pusch->rbStart = rbStart;
+  sched_pusch->rbSize = rbSize;
+
+  /* Calculate TBS from MCS */
+  sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table);
+  sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table);
+  if (ps->pusch_Config->tp_pi2BPSK
+      && ((ps->mcs_table == 3 && mcs < 2) || (ps->mcs_table == 4 && mcs < 6))) {
+    sched_pusch->R >>= 1;
+    sched_pusch->Qm <<= 1;
+  }
+  sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm,
+                                        sched_pusch->R,
+                                        sched_pusch->rbSize,
+                                        ps->nrOfSymbols,
+                                        ps->N_PRB_DMRS * ps->num_dmrs_symb,
+                                        0, // nb_rb_oh
+                                        0,
+                                        1 /* NrOfLayers */)
+                         >> 3;
+
+  /* mark the corresponding RBs as used */
+  for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++)
+    vrb_map_UL[rb + sched_ctrl->sched_pusch.rbStart] = 1;
+}
+
+void nr_schedule_ulsch(module_id_t module_id,
+                       frame_t frame,
+                       sub_frame_t slot,
+                       int num_slots_per_tdd,
+                       int ul_slots,
+                       uint64_t ulsch_in_slot_bitmap) {
+  RC.nrmac[module_id]->pre_processor_ul(
+      module_id, frame, slot, num_slots_per_tdd, ulsch_in_slot_bitmap);
+
+  NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon;
+  NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info;
+  const NR_UE_list_t *UE_list = &UE_info->list;
+  for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
+    NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
+    /* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in
+     * every TTI are pre-populated by the preprocessor and used below */
+    NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
+    if (sched_pusch->rbSize <= 0)
+      continue;
+
+    uint16_t rnti = UE_info->rnti[UE_id];
+
+    int8_t harq_id = select_ul_harq_pid(sched_ctrl);
+    if (harq_id < 0) return;
+    NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[harq_id];
+    cur_harq->state = ACTIVE_SCHED;
+    cur_harq->last_tx_slot = sched_pusch->slot;
+
+    int rnti_types[2] = { NR_RNTI_C, 0 };
+
+    /* pre-computed PUSCH values that only change if time domain allocation,
+     * DCI format, or DMRS parameters change. Updated in the preprocessor
+     * through nr_save_pusch_fields() */
+    NR_sched_pusch_save_t *ps = &sched_ctrl->pusch_save;
+
+    /* Statistics */
+    UE_info->mac_stats[UE_id].ulsch_rounds[cur_harq->round]++;
+    if (cur_harq->round == 0) {
+      UE_info->mac_stats[UE_id].ulsch_total_bytes_scheduled += sched_pusch->tb_size;
+    } else {
+      LOG_W(MAC,
+            "%d.%2d UL retransmission RNTI %04x sched %d.%2d HARQ PID %d round %d NDI %d\n",
+            frame,
+            slot,
+            rnti,
+            sched_pusch->frame,
+            sched_pusch->slot,
+            harq_id,
+            cur_harq->round,
+            cur_harq->ndi);
+    }
 
+    LOG_D(MAC,
+          "%4d.%2d RNTI %04x UL sched %4d.%2d start %d RBS %d MCS %d TBS %d HARQ PID %d round %d NDI %d\n",
+          frame,
+          slot,
+          rnti,
+          sched_pusch->frame,
+          sched_pusch->slot,
+          sched_pusch->rbStart,
+          sched_pusch->rbSize,
+          sched_pusch->mcs,
+          sched_pusch->tb_size,
+          harq_id,
+          cur_harq->round,
+          cur_harq->ndi);
+
+    /* PUSCH in a later slot, but corresponding DCI now! */
+    nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_id]->UL_tti_req_ahead[0][sched_pusch->slot];
+    AssertFatal(future_ul_tti_req->SFN == sched_pusch->frame
+                && future_ul_tti_req->Slot == sched_pusch->slot,
+                "%d.%d future UL_tti_req's frame.slot %d.%d does not match PUSCH %d.%d\n",
+                frame, slot,
+                future_ul_tti_req->SFN,
+                future_ul_tti_req->Slot,
+                sched_pusch->frame,
+                sched_pusch->slot);
+    future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
+    future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
+    nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu;
+    memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t));
+    future_ul_tti_req->n_pdus += 1;
+
+    LOG_D(MAC, "%4d.%2d Scheduling UE specific PUSCH\n", frame, slot);
+
+    pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA;
+    pusch_pdu->rnti = rnti;
+    pusch_pdu->handle = 0; //not yet used
+
+    /* FAPI: BWP */
+    pusch_pdu->bwp_size  = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+    pusch_pdu->bwp_start = NRRIV2PRBOFFSET(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+    pusch_pdu->subcarrier_spacing = sched_ctrl->active_ubwp->bwp_Common->genericParameters.subcarrierSpacing;
+    pusch_pdu->cyclic_prefix = 0;
+
+    /* FAPI: PUSCH information always included */
+    pusch_pdu->target_code_rate = sched_pusch->R;
+    pusch_pdu->qam_mod_order = sched_pusch->Qm;
+    pusch_pdu->mcs_index = sched_pusch->mcs;
+    pusch_pdu->mcs_table = ps->mcs_table;
+    pusch_pdu->transform_precoding = ps->transform_precoding;
+    if (ps->pusch_Config->dataScramblingIdentityPUSCH)
+      pusch_pdu->data_scrambling_id = *ps->pusch_Config->dataScramblingIdentityPUSCH;
+    else
+      pusch_pdu->data_scrambling_id = *scc->physCellId;
+    pusch_pdu->nrOfLayers = 1;
+
+    /* FAPI: DMRS */
+    pusch_pdu->ul_dmrs_symb_pos = ps->ul_dmrs_symb_pos;
+    pusch_pdu->dmrs_config_type = ps->dmrs_config_type;
+    if (pusch_pdu->transform_precoding) { // transform precoding disabled
+      long *scramblingid;
+      if (pusch_pdu->scid == 0)
+        scramblingid = ps->NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0;
+      else
+        scramblingid = ps->NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID1;
+      if (scramblingid == NULL)
+        pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
+      else
+        pusch_pdu->ul_dmrs_scrambling_id = *scramblingid;
+    }
+    else {
+      pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
+      if (ps->NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
+        pusch_pdu->pusch_identity = *ps->NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity;
+      else
+        pusch_pdu->pusch_identity = *scc->physCellId;
+    }
+    pusch_pdu->scid = 0;      // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]
+    pusch_pdu->num_dmrs_cdm_grps_no_data = ps->num_dmrs_cdm_grps_no_data;
+    pusch_pdu->dmrs_ports = 1;
+
+    /* FAPI: Pusch Allocation in frequency domain */
+    AssertFatal(ps->pusch_Config->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1,
+                "Only frequency resource allocation type 1 is currently supported\n");
+    pusch_pdu->resource_alloc = 1; //type 1
+    pusch_pdu->rb_start = sched_pusch->rbStart;
+    pusch_pdu->rb_size = sched_pusch->rbSize;
+    pusch_pdu->vrb_to_prb_mapping = 0;
+    if (ps->pusch_Config->frequencyHopping==NULL)
+      pusch_pdu->frequency_hopping = 0;
+    else
+      pusch_pdu->frequency_hopping = 1;
+
+    /* FAPI: Resource Allocation in time domain */
+    pusch_pdu->start_symbol_index = ps->startSymbolIndex;
+    pusch_pdu->nr_of_symbols = ps->nrOfSymbols;
+
+    /* PUSCH PDU */
+    pusch_pdu->pusch_data.rv_index = nr_rv_round_map[cur_harq->round];
+    pusch_pdu->pusch_data.harq_process_id = harq_id;
+    pusch_pdu->pusch_data.new_data_indicator = cur_harq->ndi;
+    pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size;
+    pusch_pdu->pusch_data.num_cb = 0; //CBG not supported
+
+    /* PUSCH PTRS */
+    if (ps->NR_DMRS_UplinkConfig->phaseTrackingRS != NULL) {
+      // TODO to be fixed from RRC config
+      uint8_t ptrs_mcs1 = 2;  // higher layer parameter in PTRS-UplinkConfig
+      uint8_t ptrs_mcs2 = 4;  // higher layer parameter in PTRS-UplinkConfig
+      uint8_t ptrs_mcs3 = 10; // higher layer parameter in PTRS-UplinkConfig
+      uint16_t n_rb0 = 25;    // higher layer parameter in PTRS-UplinkConfig
+      uint16_t n_rb1 = 75;    // higher layer parameter in PTRS-UplinkConfig
+      pusch_pdu->pusch_ptrs.ptrs_time_density = get_L_ptrs(ptrs_mcs1, ptrs_mcs2, ptrs_mcs3, pusch_pdu->mcs_index, pusch_pdu->mcs_table);
+      pusch_pdu->pusch_ptrs.ptrs_freq_density = get_K_ptrs(n_rb0, n_rb1, pusch_pdu->rb_size);
+      pusch_pdu->pusch_ptrs.ptrs_ports_list   = (nfapi_nr_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ptrs_ports_t));
+      pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0;
+
+      pusch_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS; // enable PUSCH PTRS
+    }
+    else{
+      pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
+    }
+
+    nfapi_nr_ul_dci_request_t *ul_dci_req = &RC.nrmac[module_id]->UL_dci_req[0];
+    ul_dci_req->SFN = frame;
+    ul_dci_req->Slot = slot;
+    nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu = &ul_dci_req->ul_dci_pdu_list[ul_dci_req->numPdus];
+    memset(ul_dci_request_pdu, 0, sizeof(nfapi_nr_ul_dci_request_pdus_t));
+    ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE;
+    ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu));
+    nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15;
+    ul_dci_req->numPdus += 1;
+
+    LOG_D(MAC,"Configuring ULDCI/PDCCH in %d.%d\n", frame,slot);
+
+    nr_configure_pdcch(RC.nrmac[0],
+                       pdcch_pdu_rel15,
+                       rnti,
+                       sched_ctrl->search_space,
+                       sched_ctrl->coreset,
+                       scc,
+                       sched_ctrl->active_bwp,
+                       sched_ctrl->aggregation_level,
+                       sched_ctrl->cce_index);
+
+    dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET];
+    memset(dci_pdu_rel15, 0, sizeof(dci_pdu_rel15));
+    NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id];
+    const int n_ubwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count;
+    // NOTE: below functions assume that dci_formats is an array corresponding
+    // to all UL DCIs in the PDCCH, but for us it is a simple int. So before
+    // having multiple UEs, the below need to be changed (IMO the functions
+    // should fill for one DCI only and not handle all of them).
+    config_uldci(sched_ctrl->active_ubwp,
+                 pusch_pdu,
+                 pdcch_pdu_rel15,
+                 &dci_pdu_rel15[0],
+                 &ps->dci_format,
+                 ps->time_domain_allocation,
+                 UE_info->UE_sched_ctrl[UE_id].tpc0,
+                 n_ubwp,
+                 sched_ctrl->active_bwp->bwp_Id);
+    fill_dci_pdu_rel15(scc,
+                       secondaryCellGroup,
+                       pdcch_pdu_rel15,
+                       dci_pdu_rel15,
+                       &ps->dci_format,
+                       rnti_types,
+                       pusch_pdu->bwp_size,
+                       sched_ctrl->active_bwp->bwp_Id);
+
+    memset(sched_pusch, 0, sizeof(*sched_pusch));
+  }
 }
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index ad5468bb7016a2d4aa553f2279e8a7061166a351..eb54d19a01df30c344c564dffa9b144577f5010f 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -97,6 +97,20 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id,
 
 void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, uint8_t slots_per_frame);
 
+/// uplink scheduler
+void nr_schedule_ulsch(module_id_t module_id,
+                       frame_t frame,
+                       sub_frame_t slot,
+                       int num_slots_per_tdd,
+                       int ul_slots,
+                       uint64_t ulsch_in_slot_bitmap);
+
+void nr_simple_ulsch_preprocessor(module_id_t module_id,
+                                  frame_t frame,
+                                  sub_frame_t slot,
+                                  int num_slots_per_tdd,
+                                  uint64_t ulsch_in_slot_bitmap);
+
 /////// Random Access MAC-PHY interface functions and primitives ///////
 
 void nr_schedule_RA(module_id_t module_idP, frame_t frameP, sub_frame_t slotP);
@@ -116,7 +130,9 @@ void nr_clear_ra_proc(module_id_t module_idP, int CC_id, frame_t frameP);
 
 int nr_allocate_CCEs(int module_idP, int CC_idP, frame_t frameP, sub_frame_t slotP, int test_only);
 
-void nr_get_Msg3alloc(NR_ServingCellConfigCommon_t *scc,
+void nr_get_Msg3alloc(module_id_t module_id,
+                      int CC_id,
+                      NR_ServingCellConfigCommon_t *scc,
                       NR_BWP_Uplink_t *ubwp,
                       sub_frame_t current_subframe,
                       frame_t current_frame,
@@ -145,6 +161,13 @@ void nr_preprocessor_phytest(module_id_t module_id,
                              frame_t frame,
                              sub_frame_t slot,
                              int num_slots_per_tdd);
+/* \brief UL preprocessor for phytest: schedules UE_id 0 with fixed MCS on a
+ * fixed set of resources */
+void nr_ul_preprocessor_phytest(module_id_t module_id,
+                                frame_t frame,
+                                sub_frame_t slot,
+                                int num_slots_per_tdd,
+                                uint64_t ulsch_in_slot_bitmap);
 
 void nr_schedule_css_dlsch_phytest(module_id_t   module_idP,
                                    frame_t       frameP,
@@ -166,26 +189,24 @@ void nr_fill_nfapi_dl_pdu(int Mod_id,
                           int ndi,
                           int round);
 
-void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
-                   nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01,
-                   nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234,
-                   NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats);
+void handle_nr_uci_pucch_0_1(module_id_t mod_id,
+                             frame_t frame,
+                             sub_frame_t slot,
+                             const nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01);
+void handle_nr_uci_pucch_2_3_4(module_id_t mod_id,
+                               frame_t frame,
+                               sub_frame_t slot,
+                               const nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234);
+
 
 void config_uldci(NR_BWP_Uplink_t *ubwp,
                   nfapi_nr_pusch_pdu_t *pusch_pdu,
                   nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
                   dci_pdu_rel15_t *dci_pdu_rel15,
-                  int *dci_formats, int *rnti_types,
+                  int *dci_formats,
                   int time_domain_assignment, uint8_t tpc,
                   int n_ubwp, int bwp_id);
 
-void nr_schedule_pusch(int Mod_idP,
-                       int UE_id,
-                       int num_slots_per_tdd,
-                       int ul_slots,
-                       frame_t       frameP,
-                       sub_frame_t   slotP);
-
 void nr_schedule_pucch(int Mod_idP,
                        int UE_id,
                        int nr_ulmix_slots,
@@ -288,6 +309,15 @@ void find_aggregation_candidates(uint8_t *aggregation_level,
                                  uint8_t *nr_of_candidates,
                                  NR_SearchSpace_t *ss);
 
+long get_K2(NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu);
+
+void nr_save_pusch_fields(const NR_ServingCellConfigCommon_t *scc,
+                          const NR_BWP_Uplink_t *ubwp,
+                          long dci_format,
+                          int tda,
+                          uint8_t num_dmrs_cdm_grps_no_data,
+                          NR_sched_pusch_save_t *ps);
+
 uint8_t nr_get_tpc(int target, uint8_t cqi, int incr);
 
 int get_spf(nfapi_nr_config_request_scf_t *cfg);
@@ -362,16 +392,6 @@ void nr_generate_Msg2(module_id_t module_idP,
                       frame_t frameP,
                       sub_frame_t slotP);
 
-void nr_schedule_reception_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t slotP);
-
-void schedule_fapi_ul_pdu(int Mod_idP,
-                          frame_t frameP,
-                          sub_frame_t slotP,
-                          int num_slots_per_tdd,
-                          int ul_slots,
-                          int time_domain_assignment,
-                          uint64_t ulsch_in_slot_bitmap);
-
 void nr_process_mac_pdu(
     module_id_t module_idP,
     rnti_t rnti,
@@ -407,7 +427,10 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
                const uint8_t ul_cqi,
                const uint16_t rssi);
 
-void handle_nr_ul_harq(uint16_t slot, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats, nfapi_nr_crc_t crc_pdu);
+void handle_nr_ul_harq(module_id_t mod_id,
+                       frame_t frame,
+                       sub_frame_t slot,
+                       const nfapi_nr_crc_t *crc_pdu);
 
 int16_t ssb_index_from_prach(module_id_t module_idP,
                              frame_t frameP,
@@ -418,5 +441,4 @@ int16_t ssb_index_from_prach(module_id_t module_idP,
 
 void find_SSB_and_RO_available(module_id_t module_idP);
 
-void handle_nr_uci(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats, int target_snrx10);
 #endif /*__LAYER2_NR_MAC_PROTO_H__*/
diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c
index b7db1f67aa59ebab45bed359646bb4a06ceeb7bd..78ad9a110bacb773fccb4d55c5cff75a4209f447 100644
--- a/openair2/LAYER2/NR_MAC_gNB/main.c
+++ b/openair2/LAYER2/NR_MAC_gNB/main.c
@@ -34,7 +34,6 @@
 #include "NR_MAC_COMMON/nr_mac_extern.h"
 #include "assertions.h"
 
-#include "LAYER2/PDCP_v10.1.0/pdcp.h"
 #include "LAYER2/nr_pdcp/nr_pdcp_entity.h"
 #include "RRC/NR/nr_rrc_defs.h"
 #include "common/utils/LOG/log.h"
@@ -82,10 +81,13 @@ void mac_top_init_gNB(void)
         
       RC.nrmac[i]->ul_handle = 0;
 
-      if (get_softmodem_params()->phy_test)
+      if (get_softmodem_params()->phy_test) {
         RC.nrmac[i]->pre_processor_dl = nr_preprocessor_phytest;
-      else
+        RC.nrmac[i]->pre_processor_ul = nr_ul_preprocessor_phytest;
+      } else {
         RC.nrmac[i]->pre_processor_dl = nr_simple_dlsch_preprocessor;
+        RC.nrmac[i]->pre_processor_ul = nr_simple_ulsch_preprocessor;
+      }
 
     }//END for (i = 0; i < RC.nb_nr_macrlc_inst; i++)
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 2def264c5ea9deea901d07d54fadbbc6f3d0dabb..3d01906c325da1c950ad43534fef6c22a96b8211 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -142,8 +142,6 @@ typedef struct {
   uint8_t msg3_cqireq;
   /// Round of Msg3 HARQ
   uint8_t msg3_round;
-  /// Msg3 pusch pdu
-  nfapi_nr_pusch_pdu_t pusch_pdu;
   /// TBS used for Msg4
   int msg4_TBsize;
   /// MCS used for Msg4
@@ -192,8 +190,9 @@ typedef struct {
   NR_RA_t ra[NR_NB_RA_PROC_MAX];
   /// VRB map for common channels
   uint16_t vrb_map[275];
-  /// VRB map for common channels and retransmissions by PHICH
-  uint16_t vrb_map_UL[275];
+  /// VRB map for common channels and PUSCH, dynamically allocated because
+  /// length depends on number of slots and RBs
+  uint16_t *vrb_map_UL;
   /// number of subframe allocation pattern available for MBSFN sync area
   uint8_t num_sf_allocation_pattern;
   ///Number of active SSBs
@@ -285,12 +284,49 @@ typedef struct NR_sched_pucch {
   uint8_t resource_indicator;
 } NR_sched_pucch;
 
+/* this struct is a helper: as long as the TDA and DCI format remain the same
+ * over the same uBWP and search space, there is no need to recalculate all
+ * S/L, MCS table, or DMRS-related parameters over and over again. Hence, we
+ * store them in this struct for easy reference. */
+typedef struct NR_sched_pusch_save {
+  int dci_format;
+  int time_domain_allocation;
+  uint8_t num_dmrs_cdm_grps_no_data;
+
+  int startSymbolIndex;
+  int nrOfSymbols;
+
+  NR_PUSCH_Config_t *pusch_Config;
+  uint8_t transform_precoding;
+  uint8_t mcs_table;
+
+  long mapping_type;
+  NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig;
+  uint16_t dmrs_config_type;
+  uint16_t ul_dmrs_symb_pos;
+  uint8_t num_dmrs_symb;
+  uint8_t N_PRB_DMRS;
+} NR_sched_pusch_save_t;
+
 typedef struct NR_sched_pusch {
   int frame;
   int slot;
-  bool active;
-  nfapi_nr_pusch_pdu_t pusch_pdu;
-} NR_sched_pusch;
+
+  /// RB allocation within active uBWP
+  uint16_t rbSize;
+  uint16_t rbStart;
+
+  // time-domain allocation for scheduled RBs
+  int time_domain_allocation;
+
+  /// MCS
+  uint8_t mcs;
+
+  /// TBS-related info
+  uint16_t R;
+  uint8_t Qm;
+  uint32_t tb_size;
+} NR_sched_pusch_t;
 
 typedef struct NR_UE_harq {
   uint8_t is_waiting;
@@ -348,11 +384,15 @@ typedef struct {
 
   /// the currently active BWP in DL
   NR_BWP_Downlink_t *active_bwp;
+  /// the currently active BWP in UL
+  NR_BWP_Uplink_t *active_ubwp;
+
   NR_sched_pucch **sched_pucch;
   /// selected PUCCH index, if scheduled
   int pucch_sched_idx;
   int pucch_occ_idx;
-  NR_sched_pusch *sched_pusch;
+  NR_sched_pusch_save_t pusch_save;
+  NR_sched_pusch_t sched_pusch;
 
   /// CCE index and aggregation, should be coherent with cce_list
   NR_SearchSpace_t *search_space;
@@ -381,7 +421,6 @@ typedef struct {
   uint8_t tpc0;
   uint8_t tpc1;
   uint16_t ul_rssi;
-  uint8_t current_harq_pid;
   NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES];
   NR_UE_ul_harq_t ul_harq_processes[NR_MAX_NB_HARQ_PROCESSES];
   int dummy;
@@ -418,7 +457,6 @@ typedef struct {
 /*! \brief UE list used by gNB to order UEs/CC for scheduling*/
 #define MAX_CSI_REPORTCONFIG 48
 typedef struct {
-  DLSCH_PDU DLSCH_pdu[4][MAX_MOBILES_PER_GNB];
   /// scheduling control info
   nr_csi_report_t csi_report_template[MAX_MOBILES_PER_GNB][MAX_CSI_REPORTCONFIG];
   NR_UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB];
@@ -441,6 +479,11 @@ typedef void (*nr_pp_impl_dl)(module_id_t mod_id,
                               frame_t frame,
                               sub_frame_t slot,
                               int num_slots_per_tdd);
+typedef void (*nr_pp_impl_ul)(module_id_t mod_id,
+                              frame_t frame,
+                              sub_frame_t slot,
+                              int num_slots_per_tdd,
+                              uint64_t ulsch_in_slot_bitmap);
 
 /*! \brief top level eNB MAC structure */
 typedef struct gNB_MAC_INST_s {
@@ -467,8 +510,12 @@ typedef struct gNB_MAC_INST_s {
   nfapi_nr_config_request_scf_t     config[NFAPI_CC_MAX];
   /// NFAPI DL Config Request Structure
   nfapi_nr_dl_tti_request_t         DL_req[NFAPI_CC_MAX];
-  /// NFAPI UL TTI Request Structure (this is from the new SCF specs)
-  nfapi_nr_ul_tti_request_t         UL_tti_req[NFAPI_CC_MAX];
+  /// NFAPI UL TTI Request Structure, simple pointer into structure
+  /// UL_tti_req_ahead for current frame/slot
+  nfapi_nr_ul_tti_request_t        *UL_tti_req[NFAPI_CC_MAX];
+  /// NFAPI UL TTI Request Structure for future TTIs, dynamically allocated
+  /// because length depends on number of slots
+  nfapi_nr_ul_tti_request_t        *UL_tti_req_ahead[NFAPI_CC_MAX];
   /// NFAPI HI/DCI0 Config Request Structure
   nfapi_nr_ul_dci_request_t         UL_dci_req[NFAPI_CC_MAX];
   /// NFAPI DL PDU structure
@@ -502,11 +549,11 @@ typedef struct gNB_MAC_INST_s {
   time_stats_t schedule_pch;
   /// CCE lists
   int cce_list[MAX_NUM_BWP][MAX_NUM_CORESET][MAX_NUM_CCE];
-  /// current slot
-  int current_slot;
 
   /// DL preprocessor for differentiated scheduling
   nr_pp_impl_dl pre_processor_dl;
+  /// UL preprocessor for differentiated scheduling
+  nr_pp_impl_ul pre_processor_ul;
 
   NR_UE_sched_ctrl_t *sched_ctrlCommon;
   NR_CellGroupConfig_t *secondaryCellGroupCommon;
diff --git a/openair2/LAYER2/nr_pdcp/asn1_utils.c b/openair2/LAYER2/nr_pdcp/asn1_utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..264a2815bb201ec046024dd3720a5719746890f8
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/asn1_utils.c
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#include "pdcp.h"
+
+int decode_t_reordering(int v)
+{
+  static int tab[36] = {
+    0, 1, 2, 4, 5, 8, 10, 15, 20, 30, 40, 50, 60, 80, 100, 120, 140, 160, 180,
+    200, 220, 240, 260, 280, 300, 500, 750, 1000, 1250, 1500, 1750, 2000,
+    2250, 2500, 2750, 3000
+  };
+
+  if (v < 0 || v > 35) {
+    LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  return tab[v];
+}
+
+int decode_sn_size_ul(long s)
+{
+  if (s == 0) return 12;
+  if (s == 1) return 18;
+  LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+  exit(1);
+}
+
+int decode_sn_size_dl(long s)
+{
+  if (s == 0) return 12;
+  if (s == 1) return 18;
+  LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+  exit(1);
+}
+
+int decode_discard_timer(long v)
+{
+  static int tab[16] = {
+    10, 20, 30, 40, 50, 60, 75, 100, 150, 200, 250, 300, 500, 750, 1500, -1,
+  };
+
+  if (v < 0 || v > 15) {
+    LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  return tab[v];
+}
diff --git a/openair2/LAYER2/nr_pdcp/asn1_utils.h b/openair2/LAYER2/nr_pdcp/asn1_utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..d525bce287110560d51c2c6e9765c8e00ea41147
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/asn1_utils.h
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#ifndef _OPENAIR2_LAYER2_NR_PDCP_ASN1_UTILS_H_
+#define _OPENAIR2_LAYER2_NR_PDCP_ASN1_UTILS_H_
+
+int decode_t_reordering(int v);
+int decode_sn_size_ul(long s);
+int decode_sn_size_dl(long s);
+int decode_discard_timer(long v);
+
+#endif /* _OPENAIR2_LAYER2_NR_PDCP_ASN1_UTILS_H_ */
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
index e25201c22c4b4d0ba71df92c9994fcee8bd9370c..f3d4b1613099765430c8825047d0686f7cdfde82 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
@@ -44,7 +44,10 @@ nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
     void *deliver_sdu_data,
     void (*deliver_pdu)(void *deliver_pdu_data, struct nr_pdcp_entity_t *entity,
                         char *buf, int size, int sdu_id),
-    void *deliver_pdu_data)
+    void *deliver_pdu_data,
+    int sn_size,
+    int t_reordering,
+    int discard_timer)
 {
   nr_pdcp_entity_drb_am_t *ret;
 
@@ -66,9 +69,12 @@ nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
   ret->common.deliver_pdu = deliver_pdu;
   ret->common.deliver_pdu_data = deliver_pdu_data;
 
-  ret->rb_id = rb_id;
+  ret->rb_id         = rb_id;
+  ret->sn_size       = sn_size;
+  ret->t_reordering  = t_reordering;
+  ret->discard_timer = discard_timer;
 
-  ret->common.maximum_nr_pdcp_sn = 4095;
+  ret->common.maximum_nr_pdcp_sn = (1 << sn_size) - 1;
 
   return (nr_pdcp_entity_t *)ret;
 }
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
index 45555ad6af9374dc2a8c5138bc09f10e12311a1a..b1d37830e9aa76b9d28d78fa9747f34b681feb56 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
@@ -58,7 +58,10 @@ nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
     void *deliver_sdu_data,
     void (*deliver_pdu)(void *deliver_pdu_data, struct nr_pdcp_entity_t *entity,
                         char *buf, int size, int sdu_id),
-    void *deliver_pdu_data);
+    void *deliver_pdu_data,
+    int sn_size,
+    int t_reordering,
+    int discard_timer);
 
 void nr_DRB_preconfiguration(void);
 
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h
index faa8226e93b64ad3b0333254f60de646494e16ed..d7c42e6a629281ddc36253894857e120d95f3e93 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h
@@ -27,6 +27,9 @@
 typedef struct {
   nr_pdcp_entity_t common;
   int rb_id;
+  int sn_size;               /* unit: bits */
+  int t_reordering;          /* unit: ms */
+  int discard_timer;         /* unit: ms, -1 means infinity */
 } nr_pdcp_entity_drb_am_t;
 
 void nr_pdcp_entity_drb_am_recv_pdu(nr_pdcp_entity_t *entity, char *buffer, int size);
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
index ca37026e54f5cfa03276e8f9cd14c502b218b194..51d4e44fabeeb4909253cedd008e6547def72ddf 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
@@ -22,6 +22,7 @@
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
+#include "asn1_utils.h"
 #include "nr_pdcp_ue_manager.h"
 #include "NR_RadioBearerConfig.h"
 #include "NR_RLC-BearerConfig.h"
@@ -595,8 +596,17 @@ static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s)
   nr_pdcp_ue_t *ue;
 
   int drb_id = s->drb_Identity;
-
-printf("\n\n################# rnti %d add drb %d\n\n\n", rnti, drb_id);
+  int t_reordering = decode_t_reordering(*s->pdcp_Config->t_Reordering);
+  int sn_size_ul = decode_sn_size_ul(*s->pdcp_Config->drb->pdcp_SN_SizeUL);
+  int sn_size_dl = decode_sn_size_dl(*s->pdcp_Config->drb->pdcp_SN_SizeDL);
+  int discard_timer = decode_discard_timer(*s->pdcp_Config->drb->discardTimer);
+
+  /* TODO(?): accept different UL and DL SN sizes? */
+  if (sn_size_ul != sn_size_dl) {
+    LOG_E(PDCP, "%s:%d:%s: fatal, bad SN sizes, must be same. ul=%d, dl=%d\n",
+          __FILE__, __LINE__, __FUNCTION__, sn_size_ul, sn_size_dl);
+    exit(1);
+  }
 
   if (drb_id != 1) {
     LOG_E(PDCP, "%s:%d:%s: fatal, bad drb id %d\n",
@@ -610,7 +620,8 @@ printf("\n\n################# rnti %d add drb %d\n\n\n", rnti, drb_id);
     LOG_D(PDCP, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n",
           __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   } else {
-    pdcp_drb = new_nr_pdcp_entity_drb_am(drb_id, deliver_sdu_drb, ue, deliver_pdu_drb, ue);
+    pdcp_drb = new_nr_pdcp_entity_drb_am(drb_id, deliver_sdu_drb, ue, deliver_pdu_drb, ue,
+                                         sn_size_dl, t_reordering, discard_timer);
     nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb);
 
     LOG_D(PDCP, "%s:%d:%s: added drb %d to ue %d\n",
diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
index 4e1a8ae1310f246e8e893691ee4da6f172783813..7f98dd6a3ebf113050d8a557f8ce76c4a17486ee 100644
--- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
@@ -30,12 +30,9 @@
 * \warning
 */
 
-#include "openair1/PHY/defs_eNB.h"
-#include "openair1/PHY/phy_extern.h"
 #include "openair1/SCHED_NR/fapi_nr_l1.h"
 #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h"
 #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
-#include "LAYER2/MAC/mac_proto.h"
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
 #include "common/ran_context.h"
 #include "executables/softmodem-common.h"
@@ -79,35 +76,28 @@ void handle_nr_rach(NR_UL_IND_t *UL_info) {
 }
 
 
-void handle_nr_uci(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats, int target_snrx10) {
-
+void handle_nr_uci(NR_UL_IND_t *UL_info)
+{
+  const module_id_t mod_id = UL_info->module_id;
+  const frame_t frame = UL_info->frame;
+  const sub_frame_t slot = UL_info->slot;
   int num_ucis = UL_info->uci_ind.num_ucis;
   nfapi_nr_uci_t *uci_list = UL_info->uci_ind.uci_list;
 
   for (int i = 0; i < num_ucis; i++) {
     switch (uci_list[i].pdu_type) {
-      case NFAPI_NR_UCI_PUSCH_PDU_TYPE: break;
+      case NFAPI_NR_UCI_PUSCH_PDU_TYPE:
+        LOG_E(MAC, "%s(): unhandled NFAPI_NR_UCI_PUSCH_PDU_TYPE\n", __func__);
+        break;
 
       case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: {
-        nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu = &uci_list[i].pucch_pdu_format_0_1;
-
-        // tpc (power control)
-        sched_ctrl->tpc1 = nr_get_tpc(target_snrx10,uci_pdu->ul_cqi,30);
-
-        if( (uci_pdu->pduBitmap>>1) & 0x01)
-          nr_rx_acknack(NULL,uci_pdu,NULL,UL_info,sched_ctrl,stats);
-
+        const nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu = &uci_list[i].pucch_pdu_format_0_1;
+        handle_nr_uci_pucch_0_1(mod_id, frame, slot, uci_pdu);
         break;
       }
       case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: {
-        nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu = &uci_list[i].pucch_pdu_format_2_3_4;
-
-        // tpc (power control)
-        sched_ctrl->tpc1 = nr_get_tpc(target_snrx10,uci_pdu->ul_cqi,30);
-
-        if( (uci_pdu->pduBitmap>>1) & 0x01)
-          nr_rx_acknack(NULL,NULL,uci_pdu,UL_info,sched_ctrl,stats);
-
+        const nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu = &uci_list[i].pucch_pdu_format_2_3_4;
+        handle_nr_uci_pucch_2_3_4(mod_id, frame, slot, uci_pdu);
         break;
       }
     }
@@ -117,75 +107,62 @@ void handle_nr_uci(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_
 }
 
 
-void handle_nr_ulsch(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats) {
-
-  if(nfapi_mode == 1) {
-    if (UL_info->crc_ind.number_crcs>0) {
-      //LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.number_of_crcs:%d CRC_IND:SFN/SF:%d\n", UL_info->crc_ind.crc_indication_body.number_of_crcs, NFAPI_SFNSF2DEC(UL_info->crc_ind.sfn_sf));
-      //      oai_nfapi_crc_indication(&UL_info->crc_ind);
-
-      UL_info->crc_ind.number_crcs = 0;
-    }
-
-    if (UL_info->rx_ind.number_of_pdus>0) {
-      //LOG_D(PHY,"UL_info->rx_ind.number_of_pdus:%d RX_IND:SFN/SF:%d\n", UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf));
-      //      oai_nfapi_rx_ind(&UL_info->rx_ind);
-      UL_info->rx_ind.number_of_pdus = 0;
-    }
-  } else {
-
-    if (UL_info->rx_ind.number_of_pdus>0 && UL_info->crc_ind.number_crcs>0) {
-      for (int i=0; i<UL_info->rx_ind.number_of_pdus; i++) {
-        for (int j=0; j<UL_info->crc_ind.number_crcs; j++) {
-          // find crc_indication j corresponding rx_indication i
-          LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.crc_pdu_list[%d].rx_ue_information.rnti:%04x UL_info->rx_ind.rx_indication_body.rx_pdu_list[%d].rx_ue_information.rnti:%04x\n", j,
-                UL_info->crc_ind.crc_list[j].rnti, i, UL_info->rx_ind.pdu_list[i].rnti);
-
-          if (UL_info->crc_ind.crc_list[j].rnti ==
-              UL_info->rx_ind.pdu_list[i].rnti) {
-            LOG_D(PHY, "UL_info->crc_ind.crc_indication_body.crc_pdu_list[%d].crc_indication_rel8.crc_flag:%d\n", j, UL_info->crc_ind.crc_list[j].tb_crc_status);
-
-            handle_nr_ul_harq(UL_info->slot, sched_ctrl, stats, UL_info->crc_ind.crc_list[j]);
-
-            if (UL_info->crc_ind.crc_list[j].tb_crc_status == 1) { // CRC error indication
-              LOG_D(MAC,"Frame %d, Slot %d Calling rx_sdu (CRC error) \n",UL_info->frame,UL_info->slot);
-
-              nr_rx_sdu(UL_info->module_id,
-                        UL_info->CC_id,
-                        UL_info->rx_ind.sfn, //UL_info->frame,
-                        UL_info->rx_ind.slot, //UL_info->slot,
-                        UL_info->rx_ind.pdu_list[i].rnti,
-                        (uint8_t *)NULL,
-                        UL_info->rx_ind.pdu_list[i].pdu_length,
-                        UL_info->rx_ind.pdu_list[i].timing_advance,
-                        UL_info->rx_ind.pdu_list[i].ul_cqi,
-                        UL_info->rx_ind.pdu_list[i].rssi);
-            } else {
-              LOG_D(MAC,"Frame %d, Slot %d Calling rx_sdu (CRC ok) \n",UL_info->frame,UL_info->slot);
-              nr_rx_sdu(UL_info->module_id,
-                        UL_info->CC_id,
-                        UL_info->rx_ind.sfn, //UL_info->frame,
-                        UL_info->rx_ind.slot, //UL_info->slot,
-                        UL_info->rx_ind.pdu_list[i].rnti,
-                        UL_info->rx_ind.pdu_list[i].pdu,
-                        UL_info->rx_ind.pdu_list[i].pdu_length,
-                        UL_info->rx_ind.pdu_list[i].timing_advance,
-                        UL_info->rx_ind.pdu_list[i].ul_cqi,
-                        UL_info->rx_ind.pdu_list[i].rssi);
-            }
-            break;
-          }
-        } //    for (j=0;j<UL_info->crc_ind.number_crcs;j++)
-      } //   for (i=0;i<UL_info->rx_ind.number_of_pdus;i++)
-
-      UL_info->crc_ind.number_crcs=0;
-      UL_info->rx_ind.number_of_pdus = 0;
-    }
-    else if (UL_info->rx_ind.number_of_pdus!=0 || UL_info->crc_ind.number_crcs!=0) {
-      LOG_E(PHY,"hoping not to have mis-match between CRC ind and RX ind - hopefully the missing message is coming shortly rx_ind:%d(SFN/SL:%d/%d) crc_ind:%d(SFN/SL:%d/%d) \n",
-            UL_info->rx_ind.number_of_pdus, UL_info->rx_ind.sfn, UL_info->rx_ind.slot,
-            UL_info->crc_ind.number_crcs, UL_info->rx_ind.sfn, UL_info->rx_ind.slot);
-    }
+void handle_nr_ulsch(NR_UL_IND_t *UL_info)
+{
+  if (UL_info->rx_ind.number_of_pdus > 0 && UL_info->crc_ind.number_crcs > 0) {
+    for (int i = 0; i < UL_info->rx_ind.number_of_pdus; i++) {
+      for (int j = 0; j < UL_info->crc_ind.number_crcs; j++) {
+        // find crc_indication j corresponding rx_indication i
+        const nfapi_nr_rx_data_pdu_t *rx = &UL_info->rx_ind.pdu_list[i];
+        const nfapi_nr_crc_t *crc = &UL_info->crc_ind.crc_list[j];
+        LOG_D(PHY,
+              "UL_info->crc_ind.pdu_list[%d].rnti:%04x "
+              "UL_info->rx_ind.pdu_list[%d].rnti:%04x\n",
+              j,
+              crc->rnti,
+              i,
+              rx->rnti);
+
+        if (crc->rnti != rx->rnti)
+          continue;
+
+        LOG_D(MAC,
+              "%4d.%2d Calling rx_sdu (CRC %s/tb_crc_status %d)\n",
+              UL_info->frame,
+              UL_info->slot,
+              crc->tb_crc_status ? "error" : "ok",
+              crc->tb_crc_status);
+
+        /* if CRC passes, pass PDU, otherwise pass NULL as error indication */
+        nr_rx_sdu(UL_info->module_id,
+                  UL_info->CC_id,
+                  UL_info->rx_ind.sfn,
+                  UL_info->rx_ind.slot,
+                  rx->rnti,
+                  crc->tb_crc_status ? NULL : rx->pdu,
+                  rx->pdu_length,
+                  rx->timing_advance,
+                  rx->ul_cqi,
+                  rx->rssi);
+        handle_nr_ul_harq(UL_info->module_id, UL_info->frame, UL_info->slot, crc);
+        break;
+      } //    for (j=0;j<UL_info->crc_ind.number_crcs;j++)
+    } //   for (i=0;i<UL_info->rx_ind.number_of_pdus;i++)
+
+    UL_info->crc_ind.number_crcs = 0;
+    UL_info->rx_ind.number_of_pdus = 0;
+  } else if (UL_info->rx_ind.number_of_pdus != 0
+             || UL_info->crc_ind.number_crcs != 0) {
+    LOG_E(PHY,
+          "hoping not to have mis-match between CRC ind and RX ind - "
+          "hopefully the missing message is coming shortly "
+          "rx_ind:%d(SFN/SL:%d/%d) crc_ind:%d(SFN/SL:%d/%d) \n",
+          UL_info->rx_ind.number_of_pdus,
+          UL_info->rx_ind.sfn,
+          UL_info->rx_ind.slot,
+          UL_info->crc_ind.number_crcs,
+          UL_info->rx_ind.sfn,
+          UL_info->rx_ind.slot);
   }
 }
 
@@ -216,14 +193,12 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
     ifi->CC_mask |= (1<<CC_id);
   }
 
-  // clear DL/UL info for new scheduling round
-  clear_nr_nfapi_information(mac,CC_id,UL_info->frame,UL_info->slot);
   handle_nr_rach(UL_info);
   
-  handle_nr_uci(UL_info,&mac->UE_info.UE_sched_ctrl[0],&mac->UE_info.mac_stats[0],mac->pucch_target_snrx10);
+  handle_nr_uci(UL_info);
   // clear HI prior to handling ULSCH
   mac->UL_dci_req[CC_id].numPdus = 0;
-  handle_nr_ulsch(UL_info, &mac->UE_info.UE_sched_ctrl[0],&mac->UE_info.mac_stats[0]);
+  handle_nr_ulsch(UL_info);
 
   if (nfapi_mode != 1) {
     if (ifi->CC_mask == ((1<<MAX_NUM_CCs)-1)) {
@@ -246,7 +221,7 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
       sched_info->DL_req      = &mac->DL_req[CC_id];
       sched_info->UL_dci_req  = &mac->UL_dci_req[CC_id];
 
-      sched_info->UL_tti_req  = &mac->UL_tti_req[CC_id];
+      sched_info->UL_tti_req  = mac->UL_tti_req[CC_id];
 
       sched_info->TX_req      = &mac->TX_req[CC_id];
 #ifdef DUMP_FAPI
diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c
index ae1b78c8230f15dc17109205d5e60d55317e4990..604ed93c0c62d0bfcbb7fb497915f716ee850821 100644
--- a/openair2/RRC/NR/rrc_gNB_reconfig.c
+++ b/openair2/RRC/NR/rrc_gNB_reconfig.c
@@ -147,9 +147,22 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
   AssertFatal(servingcellconfigcommon!=NULL,"servingcellconfigcommon is null\n");
   AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n");
 
-  if(servingcellconfigcommon->ssb_PositionsInBurst->present !=2)
-    AssertFatal(1==0,"Currenrly implemented only for medium size SSB bitmap\n");
-  uint8_t bitmap = servingcellconfigcommon->ssb_PositionsInBurst->choice.mediumBitmap.buf[0];
+  uint64_t bitmap=0;
+  switch (servingcellconfigcommon->ssb_PositionsInBurst->present) {
+    case 1 :
+      bitmap = ((uint64_t) servingcellconfigcommon->ssb_PositionsInBurst->choice.shortBitmap.buf[0])<<56;
+      break;
+    case 2 :
+      bitmap = ((uint64_t) servingcellconfigcommon->ssb_PositionsInBurst->choice.mediumBitmap.buf[0])<<56;
+      break;
+    case 3 :
+      for (int i=0; i<8; i++) {
+        bitmap |= (((uint64_t) servingcellconfigcommon->ssb_PositionsInBurst->choice.longBitmap.buf[i])<<((7-i)*8));
+      }
+      break;
+    default:
+      AssertFatal(1==0,"SSB bitmap size value %d undefined (allowed values 1,2,3) \n", servingcellconfigcommon->ssb_PositionsInBurst->present);
+  }
 
   memset(secondaryCellGroup,0,sizeof(NR_CellGroupConfig_t));
   secondaryCellGroup->cellGroupId = scg_id;
@@ -341,9 +354,9 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList=calloc(1,sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList));
 
  int n_ssb = 0;
- NR_TCI_State_t *tcic[8];
- for (int i=0;i<8;i++) {
-   if ((bitmap>>(7-i))&0x01){
+ NR_TCI_State_t *tcic[64];
+ for (int i=0;i<64;i++) {
+   if ((bitmap>>(63-i))&0x01){
      tcic[i]=calloc(1,sizeof(*tcic[i]));
      tcic[i]->tci_StateId=n_ssb;
      tcic[i]->qcl_Type1.cell=NULL;
@@ -502,12 +515,21 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->controlResourceSetZero=NULL;
  bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet=calloc(1,sizeof(*bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet));
 
+ int curr_bwp = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+
  NR_ControlResourceSet_t *coreset = calloc(1,sizeof(*coreset));
  coreset->controlResourceSetId=1;
- // frequencyDomainResources '11111111 11111111 00000000 00000000 00000000 00000'B,
+ // frequency domain resources depends on BWP size
+ // options are 24, 48 or 96
  coreset->frequencyDomainResources.buf = calloc(1,6);
- coreset->frequencyDomainResources.buf[0] = 0xff;
- coreset->frequencyDomainResources.buf[1] = 0xff;
+ if (curr_bwp < 48)
+   coreset->frequencyDomainResources.buf[0] = 0xf0;
+ else
+   coreset->frequencyDomainResources.buf[0] = 0xff;
+ if (curr_bwp < 96)
+   coreset->frequencyDomainResources.buf[1] = 0;
+ else
+   coreset->frequencyDomainResources.buf[1] = 0xff;
  coreset->frequencyDomainResources.buf[2] = 0;
  coreset->frequencyDomainResources.buf[3] = 0;
  coreset->frequencyDomainResources.buf[4] = 0;
@@ -519,9 +541,9 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  coreset->precoderGranularity = NR_ControlResourceSet__precoderGranularity_sameAsREG_bundle;
 
  coreset->tci_StatesPDCCH_ToAddList=calloc(1,sizeof(*coreset->tci_StatesPDCCH_ToAddList));
- NR_TCI_StateId_t *tci[8];
- for (int i=0;i<8;i++) {
-   if ((bitmap>>(7-i))&0x01){
+ NR_TCI_StateId_t *tci[64];
+ for (int i=0;i<64;i++) {
+   if ((bitmap>>(63-i))&0x01){
      tci[i]=calloc(1,sizeof(*tci[i]));
      *tci[i] = i;
      ASN_SEQUENCE_ADD(&coreset->tci_StatesPDCCH_ToAddList->list,tci[i]);
@@ -622,7 +644,12 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  ss2->nrofCandidates=calloc(1,sizeof(*ss2->nrofCandidates));
  ss2->nrofCandidates->aggregationLevel1 = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0;
  ss2->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0;
- ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n4;
+ if (curr_bwp < 48)
+   ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1;
+ else if (curr_bwp < 96)
+   ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n2;
+ else
+   ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n4;
  ss2->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0;
  ss2->nrofCandidates->aggregationLevel16 = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0;
  ss2->searchSpaceType=calloc(1,sizeof(*ss2->searchSpaceType));
@@ -744,9 +771,9 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
 
 
  n_ssb = 0;
- NR_TCI_State_t *tcid[8];
- for (int i=0;i<8;i++) {
-   if ((bitmap>>(7-i))&0x01){
+ NR_TCI_State_t *tcid[64];
+ for (int i=0;i<64;i++) {
+   if ((bitmap>>(63-i))&0x01){
      tcid[i]=calloc(1,sizeof(*tcid[i]));
      tcid[i]->tci_StateId=n_ssb;
      tcid[i]->qcl_Type1.cell=NULL;
@@ -1006,7 +1033,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  NR_PUCCH_Resource_t *pucchres2=calloc(1,sizeof(*pucchres2));
  NR_PUCCH_Resource_t *pucchres3=calloc(1,sizeof(*pucchres3));
  pucchres0->pucch_ResourceId=1;
- pucchres0->startingPRB=48;
+ pucchres0->startingPRB=8;
  pucchres0->intraSlotFrequencyHopping=NULL;
  pucchres0->secondHopPRB=NULL;
  pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0;
@@ -1017,7 +1044,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0);
 
  pucchres1->pucch_ResourceId=2;
- pucchres1->startingPRB=48;
+ pucchres1->startingPRB=8;
  pucchres1->intraSlotFrequencyHopping=NULL;
  pucchres1->secondHopPRB=NULL;
  pucchres1->format.present= NR_PUCCH_Resource__format_PR_format0;
@@ -1028,23 +1055,23 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres1);
 
  pucchres2->pucch_ResourceId=3;
- pucchres2->startingPRB=40;
+ pucchres2->startingPRB=0;
  pucchres2->intraSlotFrequencyHopping=NULL;
  pucchres2->secondHopPRB=NULL;
  pucchres2->format.present= NR_PUCCH_Resource__format_PR_format2;
  pucchres2->format.choice.format2=calloc(1,sizeof(*pucchres2->format.choice.format2));
- pucchres2->format.choice.format2->nrofPRBs=4;
+ pucchres2->format.choice.format2->nrofPRBs=8;
  pucchres2->format.choice.format2->nrofSymbols=1;
  pucchres2->format.choice.format2->startingSymbolIndex=13;
  ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres2);
 
  pucchres3->pucch_ResourceId=4;
- pucchres3->startingPRB=40;
+ pucchres3->startingPRB=0;
  pucchres3->intraSlotFrequencyHopping=NULL;
  pucchres3->secondHopPRB=NULL;
  pucchres3->format.present= NR_PUCCH_Resource__format_PR_format2;
  pucchres3->format.choice.format2=calloc(1,sizeof(*pucchres3->format.choice.format2));
- pucchres3->format.choice.format2->nrofPRBs=4;
+ pucchres3->format.choice.format2->nrofPRBs=8;
  pucchres3->format.choice.format2->nrofSymbols=1;
  pucchres3->format.choice.format2->startingSymbolIndex=12;
  ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres3);
@@ -1167,45 +1194,14 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
 
  NR_CSI_SSB_ResourceSet_t *ssbresset0 = calloc(1,sizeof(*ssbresset0));
  ssbresset0->csi_SSB_ResourceSetId=0;
- if ((bitmap>>7)&0x01){
-   NR_SSB_Index_t *ssbresset00=calloc(1,sizeof(*ssbresset00));
-   *ssbresset00=0;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset00);
- }
- if ((bitmap>>6)&0x01) {
-   NR_SSB_Index_t *ssbresset01=calloc(1,sizeof(*ssbresset01));
-   *ssbresset01=1;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset01);
- }
- if ((bitmap>>5)&0x01) {
-   NR_SSB_Index_t *ssbresset02=calloc(1,sizeof(*ssbresset02));
-   *ssbresset02=2;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset02);
- }
- if ((bitmap>>4)&0x01) {
-   NR_SSB_Index_t *ssbresset03=calloc(1,sizeof(*ssbresset03));
-   *ssbresset03=3;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset03);
- }
- if ((bitmap>>3)&0x01) {
-   NR_SSB_Index_t *ssbresset04=calloc(1,sizeof(*ssbresset04));
-   *ssbresset04=4;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset04);
- }
- if ((bitmap>>2)&0x01) {
-   NR_SSB_Index_t *ssbresset05=calloc(1,sizeof(*ssbresset05));
-   *ssbresset05=5;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset05);
- }
- if ((bitmap>>1)&0x01) {
-   NR_SSB_Index_t *ssbresset06=calloc(1,sizeof(*ssbresset06));
-   *ssbresset06=6;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset06);
- }
- if ((bitmap)&0x01) {
-   NR_SSB_Index_t *ssbresset07=calloc(1,sizeof(*ssbresset07));
-   *ssbresset07=7;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset07);
+
+ NR_SSB_Index_t *ssbresset[64];
+ for (int i=0;i<64;i++) {
+   if ((bitmap>>(63-i))&0x01){
+     ssbresset[i]=calloc(1,sizeof(*ssbresset[i]));
+     *ssbresset[i] = i;
+     ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset[i]);
+   }
  }
  ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list,ssbresset0);
 
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.c b/openair2/X2AP/x2ap_eNB_generate_messages.c
index e066535df931cb6b77b1df610d1b3ba46b7433fd..23973328f28d69f98cc5338ed0ebb62bd4664425 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.c
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.c
@@ -1439,7 +1439,7 @@ int x2ap_eNB_generate_ENDC_x2_setup_response(
           }
 
           if (instance_p->frame_type[i] == FDD) {
-                  servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_fDD;
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_fDD;
             servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i];
             servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i];
         	  switch (instance_p->N_RB_DL[i]) {
@@ -1473,12 +1473,98 @@ int x2ap_eNB_generate_ENDC_x2_setup_response(
             }
           }
           else {
-        	  AssertFatal(0,"X2Setupresponse not supported for TDD!");
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_tDD;
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.eARFCN = instance_p->fdd_earfcn_DL[i];
+
+            switch (instance_p->subframeAssignment[i]) {
+            case 0:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa0;
+              break;
+            case 1:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa1;
+              break;
+            case 2:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa2;
+              break;
+            case 3:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa3;
+              break;
+            case 4:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa4;
+              break;
+            case 5:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa5;
+              break;
+            case 6:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa6;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for subframeAssignment");
+              break;
+            }
+            switch (instance_p->specialSubframe[i]) {
+            case 0:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp0;
+              break;
+            case 1:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp1;
+              break;
+            case 2:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp2;
+              break;
+            case 3:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp3;
+              break;
+            case 4:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp4;
+              break;
+            case 5:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp5;
+              break;
+            case 6:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp6;
+              break;
+            case 7:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp7;
+              break;
+            case 8:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp8;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for subframeAssignment");
+              break;
+            }
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixDL=X2AP_CyclicPrefixDL_normal;
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixUL=X2AP_CyclicPrefixUL_normal;
+
+            switch (instance_p->N_RB_DL[i]) {
+            case 6:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
+              break;
+            case 15:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
+              break;
+            case 25:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
+              break;
+            case 50:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
+              break;
+            case 75:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
+              break;
+            case 100:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL");
+              break;
+            }
           }
         }
-        ASN_SEQUENCE_ADD(&ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list, servedCellMember);
+      ASN_SEQUENCE_ADD(&ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list, servedCellMember);
       }
-    }
+  }
   ASN_SEQUENCE_ADD(&ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list, ie_ENB_ENDC);
 
 
diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c
index 3066f0906fd8a193dffc12e257a4a40424124ae9..3a69d4c991f1de68e057875691d718f1433e5d9f 100644
--- a/targets/ARCH/COMMON/common_lib.c
+++ b/targets/ARCH/COMMON/common_lib.c
@@ -112,6 +112,9 @@ int load_lib(openair0_device *device,
 	  else
           deflibname=OAI_RF_LIBNAME;
       shlib_fdesc[0].fname="device_init";
+  } else if (flag == RAU_REMOTE_THIRDPARTY_RADIO_HEAD) {
+    deflibname=OAI_THIRDPARTY_TP_LIBNAME;
+    shlib_fdesc[0].fname="transport_init";
   } else {
 	  deflibname=OAI_TP_LIBNAME;
 	  shlib_fdesc[0].fname="transport_init";
diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h
index 778c8165eb8b5b9198745834231c29fecc7c77af..85ee80ea7cdf443a01559cb27cdc265f09ababa2 100644
--- a/targets/ARCH/COMMON/common_lib.h
+++ b/targets/ARCH/COMMON/common_lib.h
@@ -41,6 +41,8 @@
 #define OAI_RF_LIBNAME        "oai_device"
 /* name of shared library implementing the transport */
 #define OAI_TP_LIBNAME        "oai_transpro"
+/* name of shared library implementing a third-party transport */
+#define OAI_THIRDPARTY_TP_LIBNAME        "thirdparty_transpro"
 /* name of shared library implementing the rf simulator */
 #define OAI_RFSIM_LIBNAME     "rfsimulator"
 /* name of shared library implementing the basic simulator */
@@ -51,10 +53,9 @@
 /* flags for BBU to determine whether the attached radio head is local or remote */
 #define RAU_LOCAL_RADIO_HEAD  0
 #define RAU_REMOTE_RADIO_HEAD 1
-
+#define RAU_REMOTE_THIRDPARTY_RADIO_HEAD 2
 #define MAX_WRITE_THREAD_PACKAGE     10
 #define MAX_WRITE_THREAD_BUFFER_SIZE 8
-
 #ifndef MAX_CARDS
   #define MAX_CARDS 8
 #endif
@@ -367,13 +368,23 @@ struct openair0_device_t {
   /*! \brief Called to send samples to the RF target
       @param device pointer to the device structure specific to the RF hardware target
       @param timestamp The timestamp at whicch the first sample MUST be sent
-      @param buff Buffer which holds the samples
+      @param buff Buffer which holds the samples (2 dimensional)
       @param nsamps number of samples to be sent
-      @param antenna_id index of the antenna if the device has multiple anteannas
+      @param number of antennas 
       @param flags flags must be set to TRUE if timestamp parameter needs to be applied
   */
   int (*trx_write_func)(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id, int flags);
 
+  /*! \brief Called to send samples to the RF target
+      @param device pointer to the device structure specific to the RF hardware target
+      @param timestamp The timestamp at whicch the first sample MUST be sent
+      @param buff Buffer which holds the samples (1 dimensional)
+      @param nsamps number of samples to be sent
+      @param antenna_id index of the antenna if the device has multiple anteannas
+      @param flags flags must be set to TRUE if timestamp parameter needs to be applied
+  */
+  int (*trx_write_func2)(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int antenna_id, int flags);
+
   /*! \brief Receive samples from hardware.
    * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
    * the first channel. *ptimestamp is the time at which the first sample
@@ -382,10 +393,24 @@ struct openair0_device_t {
    * \param[out] ptimestamp the time at which the first sample was received.
    * \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
    * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
-   * \param antenna_id Index of antenna for which to receive samples
+   * \param num_antennas number of antennas from which to receive samples
    * \returns the number of sample read
    */
-  int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int antenna_id);
+
+  int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int num_antennas);
+
+  /*! \brief Receive samples from hardware, this version provides a single antenna at a time and returns.
+   * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
+   * the first channel. *ptimestamp is the time at which the first sample
+   * was received.
+   * \param device the hardware to use
+   * \param[out] ptimestamp the time at which the first sample was received.
+   * \param[out] buff A pointers to a buffer for received samples. The buffer must be large enough to hold the number of samples \ref nsamps.
+   * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
+   * \param antenna_id Index of antenna from which samples were received
+   * \returns the number of sample read
+   */
+  int (*trx_read_func2)(openair0_device *device, openair0_timestamp *ptimestamp, void *buff, int nsamps,int *antenna_id);
 
   /*! \brief print the device statistics
    * \param device the hardware to use
@@ -431,6 +456,25 @@ struct openair0_device_t {
    */
   void (*configure_rru)(int idx, void *arg);
 
+/*! \brief Pointer to generic RRU private information
+   */
+
+  void *thirdparty_priv;
+
+  /*! \brief Callback for Third-party RRU Initialization routine
+     \param device the hardware configuration to use
+   */
+  int (*thirdparty_init)(openair0_device *device);
+  /*! \brief Callback for Third-party RRU Cleanup routine
+     \param device the hardware configuration to use
+   */
+  int (*thirdparty_cleanup)(openair0_device *device);
+
+  /*! \brief Callback for Third-party start streaming routine
+     \param device the hardware configuration to use
+   */
+  int (*thirdparty_startstreaming)(openair0_device *device);
+
   /*! \brief RRU Configuration callback
    * \param idx RU index
    * \param arg pointer to capabilities or configuration
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
index d893c66b526bf2602b80b21f86b556cb92095c4e..9c0a9e3f6530bdd0788d736291ea2bbee6e3786c 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
@@ -102,23 +102,15 @@ int eth_socket_init_raw(openair0_device *device) {
   eth->local_addrd_ll.sll_family   = AF_PACKET;
   eth->local_addrd_ll.sll_ifindex  = eth->if_index.ifr_ifindex;
   /* hear traffic from specific protocol*/
-  if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
-     eth->local_addrd_ll.sll_protocol = htons(0xbffe);
-  } else{ 
-     eth->local_addrc_ll.sll_protocol = htons((short)device->eth_params->my_portc);
-     eth->local_addrd_ll.sll_protocol = htons((short)device->eth_params->my_portd);
-  }
+  eth->local_addrc_ll.sll_protocol = htons((short)device->eth_params->my_portc);
+  eth->local_addrd_ll.sll_protocol = htons((short)device->eth_params->my_portd);
+  
   eth->local_addrc_ll.sll_halen    = ETH_ALEN;
   eth->local_addrc_ll.sll_pkttype  = PACKET_OTHERHOST;
   eth->local_addrd_ll.sll_halen    = ETH_ALEN;
   eth->local_addrd_ll.sll_pkttype  = PACKET_OTHERHOST;
   eth->addr_len = sizeof(struct sockaddr_ll);
   
-  if ((eth->flags != ETH_RAW_IF5_MOBIPASS ) && 
-      (bind(eth->sockfdc,(struct sockaddr *)&eth->local_addrc_ll,eth->addr_len)<0)) {
-    perror("ETHERNET: Cannot bind to socket (control)");
-    exit(0);
-  }
   if (bind(eth->sockfdd,(struct sockaddr *)&eth->local_addrd_ll,eth->addr_len)<0) {
     perror("ETHERNET: Cannot bind to socket (user)");
     exit(0);
@@ -127,12 +119,9 @@ int eth_socket_init_raw(openair0_device *device) {
  /* Construct the Ethernet header */ 
  ether_aton_r(local_mac, (struct ether_addr *)(&(eth->ehd.ether_shost)));
  ether_aton_r(remote_mac, (struct ether_addr *)(&(eth->ehd.ether_dhost)));
- if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
-   eth->ehd.ether_type = htons(0xbffe);
- } else {
-   eth->ehc.ether_type = htons((short)device->eth_params->my_portc);
-   eth->ehd.ether_type = htons((short)device->eth_params->my_portd);
- } 
+ eth->ehc.ether_type = htons((short)device->eth_params->my_portc);
+ eth->ehd.ether_type = htons((short)device->eth_params->my_portd);
+  
  printf("[%s] binding to hardware address %x:%x:%x:%x:%x:%x\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"),eth->ehd.ether_shost[0],eth->ehd.ether_shost[1],eth->ehd.ether_shost[2],eth->ehd.ether_shost[3],eth->ehd.ether_shost[4],eth->ehd.ether_shost[5]);
  
  return 0;
@@ -216,8 +205,6 @@ int trx_eth_write_raw_IF4p5(openair0_device *device, openair0_timestamp timestam
     packet_size = RAW_IF4p5_PULFFT_SIZE_BYTES(nblocks);    
   } else if (flags == IF4p5_PULTICK) {
     packet_size = RAW_IF4p5_PULTICK_SIZE_BYTES;    
-  } else if (flags == IF5_MOBIPASS) {
-    packet_size = RAW_IF5_MOBIPASS_SIZE_BYTES;
   } else {
     packet_size = RAW_IF4p5_PRACH_SIZE_BYTES;
   }
@@ -430,53 +417,6 @@ int trx_eth_read_raw_IF4p5(openair0_device *device, openair0_timestamp *timestam
 }
 
 
-int trx_eth_read_raw_IF5_mobipass(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
-  // Read nblocks info from packet itself
-  
-  int bytes_received=0;
-  eth_state_t *eth = (eth_state_t*)device->priv;
-  int ret;
-
-  ssize_t packet_size =  28; //MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t ;
-//   ssize_t packet_size =  MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + 640*sizeof(int16_t);
- 
-  bytes_received = recv(eth->sockfdd,
-                        buff[0],
-                        packet_size,
-                        MSG_PEEK);
-
-  if (bytes_received ==-1) {
-          eth->num_rx_errors++;
-          perror("[MOBIPASS]ETHERNET IF5 READ (header): ");
-          exit(-1);
-  }
-
-  IF5_mobipass_header_t *test_header = (IF5_mobipass_header_t*)((uint8_t *)buff[0] + MAC_HEADER_SIZE_BYTES);
-  *timestamp = test_header->time_stamp;
-  packet_size =  MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + 640*sizeof(int16_t);
-
-  while(bytes_received < packet_size) {
-    ret = recv(eth->sockfdd,
-	       buff[0],
-	       packet_size,
-	       0);
-    if (bytes_received ==-1) {
-      eth->num_rx_errors++;
-      perror("[MOBIPASS] ETHERNET IF5 READ (payload): ");
-      return(-1);
-    } else {
-      bytes_received+=ret;
-      eth->rx_actual_nsamps = bytes_received>>1;
-      eth->rx_count++;
-    }
-  }
- 
-  eth->rx_nsamps = nsamps;
-  return(bytes_received);
-
-
-}
-
 int eth_set_dev_conf_raw(openair0_device *device) {
 
   eth_state_t *eth = (eth_state_t*)device->priv;
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
index 473d129aafe5151cbcde95774f9c80e05809d5aa..2dfb4a7bf1321c253105a0e0971bd9cdfa60b6d3 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
@@ -47,7 +47,7 @@
 #include "ethernet_lib.h"
 #include "common/ran_context.h"
 
-#define DEBUG 0
+//#define DEBUG 1
 
 // These are for IF5 and must be put into the device structure if multiple RUs in the same RAU !!!!!!!!!!!!!!!!!
 uint16_t pck_seq_num = 1;
@@ -142,8 +142,8 @@ int eth_socket_init_udp(openair0_device *device) {
     perror("ETHERNET: Cannot set SO_REUSEADDR option on socket (control)");
     exit(0);
   }
-  if (setsockopt(eth->sockfdd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))) {
-    perror("ETHERNET: Cannot set SO_REUSEADDR option on socket (user)");
+  if (setsockopt(eth->sockfdd, SOL_SOCKET, SO_NO_CHECK, &enable, sizeof(int))) {
+    perror("ETHERNET: Cannot set SO_NO_CHECK option on socket (user)");
     exit(0);
   }
   
@@ -202,8 +202,9 @@ int trx_eth_read_udp_IF4p5(openair0_device *device, openair0_timestamp *timestam
           goto again;
         }
       } else {
-        perror("ETHERNET IF4p5 READ");
-        printf("(%s):\n", strerror(errno));
+	return(-1);
+        //perror("ETHERNET IF4p5 READ");
+        //printf("(%s):\n", strerror(errno));
       }
     } else {
       *timestamp = test_header->sub_type;
@@ -264,36 +265,82 @@ int trx_eth_write_udp_IF4p5(openair0_device *device, openair0_timestamp timestam
   return (bytes_sent);  	  
 }
 
-int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {	
+int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int cc, int flags) {	
   
   int bytes_sent=0;
   eth_state_t *eth = (eth_state_t*)device->priv;
   int sendto_flag =0;
-  int i=0;
+
   //sendto_flag|=flags;
   eth->tx_nsamps=nsamps;
 
  
 
-  for (i=0;i<cc;i++) {	
-    /* buff[i] points to the position in tx buffer where the payload to be sent is
-       buff2 points to the position in tx buffer where the packet header will be placed */
-    void *buff2 = (void*)(buff[i]- APP_HEADER_SIZE_BYTES); 
+
+  int nsamps2;  // aligned to upper 32 or 16 byte boundary
+  
+#if defined(__x86_64) || defined(__i386__)
+#ifdef __AVX2__
+  nsamps2 = (nsamps+7)>>3;
+  __m256i buff_tx[nsamps2+1];
+  __m256i *buff_tx2=buff_tx+1;
+#else
+  nsamps2 = (nsamps+3)>>2;
+  __m128i buff_tx[nsamps2+2];
+  __m128i *buff_tx2=buff_tx+2;
+#endif
+#elif defined(__arm__) || defined(__aarch64__)
+  nsamps2 = (nsamps+3)>>2;
+  int16x8_t buff_tx[nsamps2+2];
+  int16x8_t *buff_tx2=buff_tx+2;
+#else
+#error Unsupported CPU architecture, ethernet device cannot be built
+#endif
+
     
-    /* we don't want to ovewrite with the header info the previous tx buffer data so we store it*/
-    int32_t temp0 = *(int32_t *)buff2;
-    openair0_timestamp  temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
+    // bring TX data into 12 LSBs for softmodem RX
+  for (int j=0; j<nsamps2; j++) {
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+    buff_tx2[j] = _mm256_slli_epi16(((__m256i *)buff)[j],4);
+#else
+    buff_tx2[j] = _mm_slli_epi16(((__m128i *)buff)[j],4);
+#endif
+#elif defined(__arm__)
+    buff_tx2[j] = vshlq_n_s16(((int16x8_t *)buff)[j],4);
+#endif
+  }
+
+        /* buff[i] points to the position in tx buffer where the payload to be sent is
+       buff2 points to the position in tx buffer where the packet header will be placed */
+    void *buff2 = ((void*)buff_tx2)- APP_HEADER_SIZE_BYTES; 
     
+   
+ 
     bytes_sent = 0;
     
     /* constract application header */
-    // eth->pck_header.seq_num = pck_seq_num;
-    //eth->pck_header.antenna_id = 1+(i<<1);
-    //eth->pck_header.timestamp = timestamp;
-    *(uint16_t *)buff2 = eth->pck_seq_num;
-    *(uint16_t *)(buff2 + sizeof(uint16_t)) = 1+(i<<1);
-    *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = timestamp;
-    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_SEQ_NUM, eth->pck_seq_num);
+    // ECPRI Protocol revision + reserved bits (1 byte)
+    *(uint8_t *)buff2 = ECPRIREV;
+    // ECPRI Message type (1 byte)
+    *(uint8_t *)(buff2 + 1) = 64;
+    // ECPRI Payload Size (2 bytes)
+    AssertFatal(nsamps<16381,"nsamps > 16381\n");
+    *(uint8_t *)(buff2 + 2) = (nsamps<<2)>>8;
+    *(uint8_t *)(buff2 + 3) = (nsamps<<2)&0xff;
+    // ECPRI PC_ID (2 bytes)
+    *(uint16_t *)(buff2 + 4) = cc;
+    // OAI modified SEQ_ID (4 bytes)
+    *(uint64_t *)(buff2 + 6) = ((uint64_t )timestamp)*6;
+
+    /*
+    printf("ECPRI TX (REV %x, MessType %d, Payload size %d, PC_ID %d, TS %llu\n",
+	   *(uint8_t *)buff2,
+	   *(uint8_t *)(buff2+1),
+	   *(uint16_t *)(buff2+2),
+	   *(uint16_t *)(buff2+4),
+	   *(uint64_t *)(buff2+6));
+	   */	   	   
     
     int sent_byte;
     if (eth->compression == ALAW_COMPRESS) {
@@ -311,7 +358,7 @@ int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, voi
 	     bytes_sent);
 #endif
       /* Send packet */
-      bytes_sent += sendto(eth->sockfdd,
+      bytes_sent = sendto(eth->sockfdd,
 			   buff2, 
                            sent_byte,
 			   sendto_flag,
@@ -339,17 +386,13 @@ int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, voi
       }
     //}
                   
-      /* tx buffer values restored */  
-      *(int32_t *)buff2 = temp0;
-      *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
-  }
- 
   return (bytes_sent-APP_HEADER_SIZE_BYTES)>>2;
 }
       
 
+#define NOSHIFT 1
 
-int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
+int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void *buff, int nsamps, int *cc) {
   
   int bytes_received=0;
   eth_state_t *eth = (eth_state_t*)device->priv;
@@ -357,105 +400,98 @@ int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, voi
   int rcvfrom_flag =0;
   int block_cnt=0;
   int again_cnt=0;
-  int i=0;
-
+  static int packet_cnt=0;
+  int payload_size = UDP_PACKET_SIZE_BYTES(nsamps);
+
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+    int nsamps2 = (payload_size>>5)+1;
+  __m256i temp_rx[nsamps2];
+  char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;
+#else
+    int nsamps2 = (payload_size>>4)+1;
+  __m128i temp_rx[nsamps2];
+  char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;  
+#endif
+#elif defined(__arm__) || defined(__aarch64__)
+  int nsamps2 = (payload_size>>4)+1
+  int16x8_t temp_rx[nsamps2];
+  char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;  
+#else
+#error Unsupported CPU architecture device cannot be built
+  int nsamps2 = (payload_size>>2)+1;
+  int32_t temp_rx[payload_size>>2];
+  char* *temp_rx0 = ((char *)&temp_rx[1]) - APP_HEADER_SIZE_BYTES;  
+#endif
+  
   eth->rx_nsamps=nsamps;
 
-  for (i=0;i<cc;i++) {
-    /* buff[i] points to the position in rx buffer where the payload to be received will be placed
-       buff2 points to the position in rx buffer where the packet header will be placed */
-    void *buff2 = (void*)(buff[i]- APP_HEADER_SIZE_BYTES);
-    
-    /* we don't want to ovewrite with the header info the previous rx buffer data so we store it*/
-    int32_t temp0 = *(int32_t *)buff2;
-    openair0_timestamp temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
-    
-    bytes_received=0;
-    block_cnt=0;
-    int receive_bytes;
-    if (eth->compression == ALAW_COMPRESS) {
-      receive_bytes = UDP_PACKET_SIZE_BYTES_ALAW(nsamps);
-    } else {
-      receive_bytes = UDP_PACKET_SIZE_BYTES(nsamps);
-    }
-    
-    while(bytes_received < receive_bytes) {
-    again:
-#if DEBUG   
-	   printf("------- RX------: buff2 current position=%d remaining_bytes=%d  bytes_recv=%d \n",
-		  (void *)(buff2+bytes_received),
-		  receive_bytes - bytes_received,
-		  bytes_received);
-#endif
-      bytes_received +=recvfrom(eth->sockfdd,
-				buff2,
-	                        receive_bytes,
-				rcvfrom_flag,
-				(struct sockaddr *)&eth->dest_addrd,
-				(socklen_t *)&eth->addr_len);
-      
-      if (bytes_received ==-1) {
-	eth->num_rx_errors++;
-	if (errno == EAGAIN) {
-	  again_cnt++;
-	  usleep(10);
-	  if (again_cnt == 1000) {
+  bytes_received=0;
+  block_cnt=0;
+  AssertFatal(eth->compression == NO_COMPRESS, "IF5 compression not supported for now\n");
+  
+  while(bytes_received < payload_size) {
+  again:
+    bytes_received +=recvfrom(eth->sockfdd,
+			      temp_rx0,
+			      payload_size,
+			      rcvfrom_flag,
+			      (struct sockaddr *)&eth->dest_addrd,
+			      (socklen_t *)&eth->addr_len);
+    packet_cnt++;
+    if (bytes_received ==-1) {
+      eth->num_rx_errors++;
+      if (errno == EAGAIN) {
+	again_cnt++;
+	usleep(10);
+	if (again_cnt == 1000) {
 	  perror("ETHERNET READ: ");
 	  exit(-1);
-	  } else {
-	    printf("AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN \n");
-	    goto again;
-	  }	  
-	} else if (errno == EWOULDBLOCK) {
-	     block_cnt++;
-	     usleep(10);	  
-	     if (block_cnt == 1000) {
-      perror("ETHERNET READ: ");
-      exit(-1);
-    } else {
-	    printf("BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK \n");
-	    goto again;
-	  }
+	} else {
+	  bytes_received=0;
+	  goto again;
+	}	  
+      } else if (errno == EWOULDBLOCK) {
+	block_cnt++;
+	usleep(10);	  
+	if (block_cnt == 1000) {
+	  perror("ETHERNET READ: ");
+	  exit(-1);
+	} else {
+	  printf("BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK \n");
+	  goto again;
 	}
-      } else {
-#if DEBUG   
-	   printf("------- RX------: nu=%d an_id=%d ts%d bytes_recv=%d\n",
-		  *(int16_t *)buff2,
-		  *(int16_t *)(buff2 + sizeof(int16_t)),
-		  *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
-		  bytes_received);
-
-	   dump_packet((device->host_type == RAU_HOST)? "RAU":"RRU", buff2, UDP_PACKET_SIZE_BYTES(nsamps),RX_FLAG);	  
-#endif  
-	   
-	   /* store the timestamp value from packet's header */
-	   *timestamp =  *(openair0_timestamp *)(buff2 + sizeof(int32_t));
-	   /* store the sequence number of the previous packet received */    
-	   if (eth->pck_seq_num_cur == 0) {
-	     eth->pck_seq_num_prev = *(uint16_t *)buff2;
-	   } else {
-	     eth->pck_seq_num_prev = eth->pck_seq_num_cur;
-	   }
-	   /* get the packet sequence number from packet's header */
-	   eth->pck_seq_num_cur = *(uint16_t *)buff2;
-	   if ( ( eth->pck_seq_num_cur != (eth->pck_seq_num_prev + 1) ) && !((eth->pck_seq_num_prev==MAX_PACKET_SEQ_NUM(nsamps,device->openair0_cfg->samples_per_frame)) && (eth->pck_seq_num_cur==1 )) && !((eth->pck_seq_num_prev==1) && (eth->pck_seq_num_cur==1))) {	     
-	     //#if DEBUG
-	     printf("Out of order packet received: current_packet=%d previous_packet=%d timestamp=%"PRId64"\n",eth->pck_seq_num_cur,eth->pck_seq_num_prev,*timestamp);
-	     //#endif
-	   }
-	   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM,eth->pck_seq_num_cur);
-	   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM_PRV,eth->pck_seq_num_prev);
-						    eth->rx_actual_nsamps=bytes_received>>2;
-						    eth->rx_count++;
-      }	 
-	     
       }
-      /* tx buffer values restored */  
-      *(int32_t *)buff2 = temp0;
-      *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
-	  
-    }      
-  return (bytes_received-APP_HEADER_SIZE_BYTES)>>2;
+    } else {
+      /* store the timestamp value from packet's header */
+      *timestamp =  *(openair0_timestamp *)(temp_rx0 + ECPRICOMMON_BYTES+ECPRIPCID_BYTES);
+      // convert TS to samples, /3 for 30.72 Ms/s, /6 for 15.36 Ms/s, /12 for 7.68 Ms/s, etc.
+      *timestamp = *timestamp/6;
+      // handle 1.4,3,5,10,15 MHz cases
+      *cc        = *(uint16_t*)(temp_rx0 + ECPRICOMMON_BYTES);
+    }
+    eth->rx_actual_nsamps=payload_size>>2;
+    eth->rx_count++;
+  }	 
+
+#ifdef NOSHIFT
+  memcpy(buff,(void*)(temp_rx+1),payload_size); 
+#else
+  // populate receive buffer in lower 12-bits from 16-bit representation
+  for (int j=1; j<nsamps2; j++) {
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+       ((__m256i *)buff)[j-1] = _mm256_srai_epi16(temp_rx[j],2);
+#else
+       ((__m128i *)buff)[j-1] = _mm_srai_epi16(temp_rx[j],2);
+#endif
+#elif defined(__arm__)
+       ((int16x8_t *)buff)[j] = vshrq_n_s16(temp_rx[i][j],2);
+#endif
+  }
+#endif
+  
+  return (payload_size>>2);
 }
 
 
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
index 1d3c280f0e5d18a6485e5bd9f45cb9f3e0bae916..dce410de47e0fb1dcd49dc8258c7d5606e8b26d3 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
@@ -52,11 +52,20 @@ int num_devices_eth = 0;
 struct sockaddr_in dest_addr[MAX_INST];
 int dest_addr_len[MAX_INST];
 
+int load_lib(openair0_device *device,
+             openair0_config_t *openair0_cfg,
+             eth_params_t *cfg,
+             uint8_t flag);
 
 int trx_eth_start(openair0_device *device)
 {
     eth_state_t *eth = (eth_state_t*)device->priv;
 
+    if (eth->flags == ETH_UDP_IF5_ECPRI_MODE) {
+       AssertFatal(device->thirdparty_init != NULL, "device->thirdparty_init is null\n");
+       AssertFatal(device->thirdparty_init(device) == 0, "third-party init failed\n");
+       device->openair0_cfg->samples_per_packet = 256;
+    }
     /* initialize socket */
     if (eth->flags == ETH_RAW_MODE) {
         printf("Setting ETHERNET to ETH_RAW_IF5_MODE\n");
@@ -121,11 +130,6 @@ int trx_eth_start(openair0_device *device)
 
 
 
-    } else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
-        printf("Setting ETHERNET to RAW_IF5_MODE\n");
-        if (eth_socket_init_raw(device)!=0)   return -1;
-        if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0)  return -1;
-
     } else {
         printf("Setting ETHERNET to UDP_IF5_MODE\n");
         if (eth_socket_init_udp(device)!=0)   return -1;
@@ -137,8 +141,7 @@ int trx_eth_start(openair0_device *device)
           if(eth_get_dev_conf_udp(device)!=0)  return -1;
           }*/
 
-        /* adjust MTU wrt number of samples per packet */
-        if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0)  return -1;
+        //if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0)  return -1;
 
         if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0)  return -1;
     }
@@ -166,9 +169,15 @@ void trx_eth_end(openair0_device *device)
 }
 
 
-int trx_eth_stop(openair0_device *device)
-{
-    return(0);
+
+int trx_eth_stop(openair0_device *device) {
+  eth_state_t *eth = (eth_state_t*)device->priv;
+  
+  if (eth->flags == ETH_UDP_IF5_ECPRI_MODE) {
+    AssertFatal(device->thirdparty_cleanup != NULL, "device->thirdparty_cleanup is null\n");
+    AssertFatal(device->thirdparty_cleanup(device) == 0, "third-party cleanup failed\n");
+  }
+  return(0);
 }
 
 
@@ -387,20 +396,11 @@ int transport_init(openair0_device *device,
     eth_state_t *eth = (eth_state_t*)malloc(sizeof(eth_state_t));
     memset(eth, 0, sizeof(eth_state_t));
 
-    if (eth_params->transp_preference == 1) {
-        eth->flags = ETH_RAW_MODE;
-    } else if (eth_params->transp_preference == 0) {
-        eth->flags = ETH_UDP_MODE;
-    } else if (eth_params->transp_preference == 3) {
-        eth->flags = ETH_RAW_IF4p5_MODE;
-    } else if (eth_params->transp_preference == 2) {
-        eth->flags = ETH_UDP_IF4p5_MODE;
-    } else if (eth_params->transp_preference == 4) {
-        eth->flags = ETH_RAW_IF5_MOBIPASS;
-    } else {
-        printf("transport_init: Unknown transport preference %d - default to RAW", eth_params->transp_preference);
-        eth->flags = ETH_RAW_MODE;
-    }
+    eth->flags = eth_params->transp_preference;
+
+    // load third-party driver
+    if (eth->flags == ETH_UDP_IF5_ECPRI_MODE) load_lib(device,openair0_cfg,eth_params,RAU_REMOTE_THIRDPARTY_RADIO_HEAD);
+
 
     if (eth_params->if_compress == 0) {
         eth->compression = NO_COMPRESS;
@@ -423,12 +423,17 @@ int transport_init(openair0_device *device,
     device->trx_set_gains_func   = trx_eth_set_gains;
     device->trx_write_init       = trx_eth_write_init;
 
-    if (eth->flags == ETH_RAW_MODE) {
+    device->trx_read_func2 = NULL;
+    device->trx_read_func = NULL;
+    device->trx_write_func2 = NULL;
+    device->trx_write_func = NULL;
+
+    if  (eth->flags == ETH_RAW_MODE) {
         device->trx_write_func   = trx_eth_write_raw;
         device->trx_read_func    = trx_eth_read_raw;
-    } else if (eth->flags == ETH_UDP_MODE) {
-        device->trx_write_func   = trx_eth_write_udp;
-        device->trx_read_func    = trx_eth_read_udp;
+    } else if (eth->flags == ETH_UDP_MODE || eth->flags == ETH_UDP_IF5_ECPRI_MODE) {
+        device->trx_write_func2   = trx_eth_write_udp;
+        device->trx_read_func2    = trx_eth_read_udp;
         device->trx_ctlsend_func = trx_eth_ctlsend_udp;
         device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
     } else if (eth->flags == ETH_RAW_IF4p5_MODE) {
@@ -439,9 +444,6 @@ int transport_init(openair0_device *device,
         device->trx_read_func    = trx_eth_read_udp_IF4p5;
         device->trx_ctlsend_func = trx_eth_ctlsend_udp;
         device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
-    } else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
-        device->trx_write_func   = trx_eth_write_raw_IF4p5;
-        device->trx_read_func    = trx_eth_read_raw_IF5_mobipass;
     } else {
         //device->trx_write_func   = trx_eth_write_udp_IF4p5;
         //device->trx_read_func    = trx_eth_read_udp_IF4p5;
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h
index 65b2def60d549e4733c198673d95a5e5511f3e86..ad64ac1a8a3b91120540e391d2bd95e878206616 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h
@@ -49,7 +49,10 @@
 #define RX_FLAG 0
 
 #include "if_defs.h"
-#define APP_HEADER_SIZE_BYTES (sizeof(int32_t) + sizeof(openair0_timestamp))
+#define ECPRICOMMON_BYTES 4
+#define ECPRIPCID_BYTES 2
+#define APP_HEADER_SIZE_BYTES (ECPRICOMMON_BYTES + ECPRIPCID_BYTES + sizeof(openair0_timestamp))
+#define ECPRIREV 1 // ECPRI Version 1, C=0 - single ECPRI message per OAI TX packet
 
 /*!\brief opaque ethernet data structure */
 typedef struct {
@@ -234,8 +237,8 @@ int ethernet_tune(openair0_device *device, unsigned int option, int value);
 * @ingroup  _oai
 */
 int eth_socket_init_udp(openair0_device *device);
-int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags);
-int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc);
+int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int cc, int flags);
+int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void *buff, int nsamps, int *cc);
 
 
 int eth_socket_init_raw(openair0_device *device);
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h b/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h
index 0f2147847a6145230078b8e4f30f16d9c23eef12..47205cf8b8bdc72f6f985860eeafefc9b570f961 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h
@@ -36,15 +36,17 @@
 #include <netinet/ether.h>
 #include <stdint.h>
 
+#ifndef LITE_COMPILATION
 #include "PHY/LTE_TRANSPORT/if4_tools.h"
 #include "PHY/LTE_TRANSPORT/if5_tools.h"
+#endif
 
 // ETH transport preference modes
-#define ETH_UDP_MODE        0
-#define ETH_RAW_MODE        1
+#define ETH_UDP_MODE          0
+#define ETH_RAW_MODE          1
 #define ETH_UDP_IF4p5_MODE    2
 #define ETH_RAW_IF4p5_MODE    3
-#define ETH_RAW_IF5_MOBIPASS    4    
+#define ETH_UDP_IF5_ECPRI_MODE  4    
 
 // COMMOM HEADER LENGTHS
 
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf
index ea38aba1b238bdc1c6e8b038491d5943f920e85a..19d9146f34b88ba720735066ddff997340e1a887 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf
@@ -71,6 +71,11 @@ gNBs =
              initialDLBWPmappingType_2           = 0;
              #this is SS=1,L=12 
              initialDLBWPstartSymbolAndLength_2  = 54;
+
+             initialDLBWPk0_3                    = 0;
+             initialDLBWPmappingType_3           = 0;
+             #this is SS=1,L=4 //5 (4 is for 43, 5 is for 57)
+             initialDLBWPstartSymbolAndLength_3  = 57; //43; //57;
   #uplinkConfigCommon 
      #frequencyInfoUL
       ul_frequencyBand                                                 = 257;
@@ -89,7 +94,7 @@ gNBs =
         initialULBWPsubcarrierSpacing                                           = 3;
       #rach-ConfigCommon
         #rach-ConfigGeneric
-          prach_ConfigurationIndex                                  = 98;
+          prach_ConfigurationIndex                                  = 52;
 #prach_msg1_FDM
 #0 = one, 1=two, 2=four, 3=eight
           prach_msg1_FDM                                            = 0;
@@ -103,12 +108,12 @@ gNBs =
         powerRampingStep                                            = 1;
 #ra_ReponseWindow
 #1,2,4,8,10,20,40,80
-        ra_ResponseWindow                                           = 4;
+        ra_ResponseWindow                                           = 7;
 #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
-#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
+#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen
         ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR                = 4;
 #oneHalf (0..15) 4,8,12,16,...60,64
-        ssb_perRACH_OccasionAndCB_PreamblesPerSSB                   = 15;
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB                   = 7;
 #ra_ContentionResolutionTimer
 #(0..7) 8,16,24,32,40,48,56,64
         ra_ContentionResolutionTimer                                = 7;
@@ -119,22 +124,26 @@ gNBs =
         prach_RootSequenceIndex                                     = 1;
         # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
         #  
-        msg1_SubcarrierSpacing                                      = 1,
+        msg1_SubcarrierSpacing                                      = 3,
 
 # restrictedSetConfig
 # 0=unrestricted, 1=restricted type A, 2=restricted type B
         restrictedSetConfig                                         = 0,
       # pusch-ConfigCommon (up to 16 elements)
-        initialULBWPk2_0                      = 2;
+        initialULBWPk2_0                      = 6;
         initialULBWPmappingType_0             = 1
         # this is SS=0 L=11
         initialULBWPstartSymbolAndLength_0    = 55;
- 	
-	initialULBWPk2_1                      = 2;
+
+        initialULBWPk2_1                      = 6;
         initialULBWPmappingType_1             = 1;
         # this is SS=0 L=12
         initialULBWPstartSymbolAndLength_1    = 69;
 
+        initialULBWPk2_2                      = 7;
+        initialULBWPmappingType_2             = 1;
+        # this is SS=10 L=4
+        initialULBWPstartSymbolAndLength_2    = 52;
 
         msg3_DeltaPreamble                                          = 1;
         p0_NominalWithGrant                                         =-90;
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf
index 82b941ea0eb672a91b2e422e1c905f48777e366b..6681a43a1de917e8fec72d44ad9d060a87e51db4 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf
@@ -47,7 +47,7 @@ gNBs =
         dl_carrierBandwidth                                            = 32;
      #initialDownlinkBWP
       #genericParameters
-        # this is RBstart=0,L=50 (275*(L-1))+RBstart
+        # this is RBstart=0,L=32 (275*(L-1))+RBstart
         initialDLBWPlocationAndBandwidth                                        = 8525;
 # subcarrierSpacing
 # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
@@ -121,8 +121,8 @@ gNBs =
         ra_ContentionResolutionTimer                                = 7;
         rsrp_ThresholdSSB                                           = 19;
 #prach-RootSequenceIndex_PR
-#0 = 839, 1 = 139
-        prach_RootSequenceIndex_PR                                  = 1;
+#1 = 839, 2 = 139
+        prach_RootSequenceIndex_PR                                  = 2;
         prach_RootSequenceIndex                                     = 1;
         # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
         #  
@@ -132,12 +132,12 @@ gNBs =
 # 0=unrestricted, 1=restricted type A, 2=restricted type B
         restrictedSetConfig                                         = 0,
       # pusch-ConfigCommon (up to 16 elements)
-        initialULBWPk2_0                      = 2;
+        initialULBWPk2_0                      = 6;
         initialULBWPmappingType_0             = 1
         # this is SS=0 L=11
         initialULBWPstartSymbolAndLength_0    = 55;
- 	
-	initialULBWPk2_1                      = 2;
+
+        initialULBWPk2_1                      = 6;
         initialULBWPmappingType_1             = 1;
         # this is SS=0 L=12
         initialULBWPstartSymbolAndLength_1    = 69;
@@ -211,7 +211,7 @@ gNBs =
                           );
 
     ///X2
-    enable_x2 = "yes";
+    enable_x2 = "no";
     t_reloc_prep      = 1000;      /* unit: millisecond */
     tx2_reloc_overall = 2000;      /* unit: millisecond */
     t_dc_prep         = 1000;      /* unit: millisecond */
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf
index 56078029af46a4bf216d185f3256621812aaa33b..1cd3b01b6c7aa6bfde7052ce0fb15b11a409f923 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf
@@ -1,6 +1,7 @@
 Active_gNBs = ( "gNB-Eurecom-5GNRBox");
 # Asn1_verbosity, choice in: none, info, annoying
 Asn1_verbosity = "none";
+Num_Threads_PUSCH = 8;
 
 gNBs =
 (
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc_b38_if5_ENDC.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc_b38_if5_ENDC.conf
new file mode 100644
index 0000000000000000000000000000000000000000..9b611b3f07816e9107d316d335b77fbb406671a1
--- /dev/null
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc_b38_if5_ENDC.conf
@@ -0,0 +1,243 @@
+Active_eNBs = ( "eNB_Eurecom_VCO_B38");
+# Asn1_verbosity, choice in: none, info, annoying
+Asn1_verbosity = "none";
+
+eNBs =
+(
+ {
+    # real_time choice in {hard, rt-preempt, no}
+    real_time       =  "no";
+
+    ////////// Identification parameters:
+    eNB_ID    =  0xe00;
+
+    cell_type =  "CELL_MACRO_ENB";
+
+    eNB_name  =  "eNB_Eurecom_VCO_B38";
+
+    // Tracking area code, 0x0000 and 0xfffe are reserved values
+    tracking_area_code = 1;
+
+    plmn_list = ( { mcc = 222; mnc = 01; mnc_length = 2; } );
+
+       ////////// Physical parameters:
+
+    component_carriers = (
+      {
+        node_function                                         = "NGFI_RCC_IF5";
+        node_timing                                           = "synch_to_ext_device";
+        node_synch_ref                                        = 0;
+        frame_type					      = "TDD";
+        tdd_config 					      = 1;
+        tdd_config_s            			      = 0;
+        prefix_type             			      = "NORMAL";
+        eutra_band              			      = 38;
+        downlink_frequency      			      = 2585000000L;
+        uplink_frequency_offset 			      = 0;
+        Nid_cell					      = 0;
+        N_RB_DL                 			      = 100;
+        Nid_cell_mbsfn          			      = 0;
+        nb_antenna_ports          			      = 1;
+        nb_antennas_tx          			      = 1;
+        nb_antennas_rx          			      = 1;
+        tx_gain                                            = 90;
+        rx_gain                                            = 125;
+        prach_root              			      = 0;
+        prach_config_index      			      = 0;
+        prach_high_speed        			      = "DISABLE";
+        prach_zero_correlation  			      = 5;
+        prach_freq_offset       			      = 2;
+        pucch_delta_shift       			      = 1;
+        pucch_nRB_CQI           			      = 1;
+        pucch_nCS_AN            			      = 0;
+        pucch_n1_AN             			      = 0;
+        pdsch_referenceSignalPower 			      = 10;
+        pdsch_p_b                  			      = 0;
+        pusch_n_SB                 			      = 1;
+        pusch_enable64QAM          			      = "DISABLE";
+        pusch_hoppingMode                                  = "interSubFrame";
+        pusch_hoppingOffset                                = 0;
+        pusch_groupHoppingEnabled  			      = "ENABLE";
+        pusch_groupAssignment      			      = 0;
+        pusch_sequenceHoppingEnabled		   	      = "DISABLE";
+        pusch_nDMRS1                                       = 1;
+        phich_duration                                     = "NORMAL";
+        phich_resource                                     = "ONESIXTH";
+        srs_enable                                         = "DISABLE";
+      /*  srs_BandwidthConfig                                =;
+        srs_SubframeConfig                                 =;
+        srs_ackNackST                                      =;
+        srs_MaxUpPts                                       =;*/
+
+        pusch_p0_Nominal                                   = -96;
+        pusch_alpha                                        = "AL1";
+        pucch_p0_Nominal                                   = -106;
+        msg3_delta_Preamble                                = 6;
+        pucch_deltaF_Format1                               = "deltaF2";
+        pucch_deltaF_Format1b                              = "deltaF3";
+        pucch_deltaF_Format2                               = "deltaF0";
+        pucch_deltaF_Format2a                              = "deltaF0";
+        pucch_deltaF_Format2b		    	      = "deltaF0";
+
+        rach_numberOfRA_Preambles                          = 64;
+        rach_preamblesGroupAConfig                         = "DISABLE";
+      /*
+        rach_sizeOfRA_PreamblesGroupA                      = ;
+        rach_messageSizeGroupA                             = ;
+        rach_messagePowerOffsetGroupB                      = ;
+      */
+        rach_powerRampingStep                              = 4;
+        rach_preambleInitialReceivedTargetPower            = -108;
+        rach_preambleTransMax                              = 10;
+        rach_raResponseWindowSize                          = 10;
+        rach_macContentionResolutionTimer                  = 48;
+        rach_maxHARQ_Msg3Tx                                = 4;
+
+        pcch_default_PagingCycle                           = 128;
+        pcch_nB                                            = "oneT";
+        bcch_modificationPeriodCoeff			      = 2;
+        ue_TimersAndConstants_t300			      = 1000;
+        ue_TimersAndConstants_t301			      = 1000;
+        ue_TimersAndConstants_t310			      = 1000;
+        ue_TimersAndConstants_t311			      = 10000;
+        ue_TimersAndConstants_n310			      = 20;
+        ue_TimersAndConstants_n311			      = 1;
+
+	ue_TransmissionMode				      = 1;
+      }
+    );
+
+
+    srb1_parameters :
+    {
+        # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
+        timer_poll_retransmit    = 80;
+
+        # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
+        timer_reordering         = 35;
+
+        # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
+        timer_status_prohibit    = 0;
+
+        # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
+        poll_pdu                 =  4;
+
+        # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
+        poll_byte                =  99999;
+
+        # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
+        max_retx_threshold       =  4;
+    }
+
+    # ------- SCTP definitions
+    SCTP :
+    {
+        # Number of streams to use in input/output
+        SCTP_INSTREAMS  = 2;
+        SCTP_OUTSTREAMS = 2;
+    };
+
+    ////////// MME parameters:
+    mme_ip_address      = ( { ipv4       = "192.168.18.150";
+                              ipv6       = "192:168:30::17";
+                              active     = "yes";
+                              preference = "ipv4";
+                            }
+                          );
+
+    enable_measurement_reports = "no";
+
+    ///X2
+    enable_x2 = "yes";
+    t_reloc_prep      = 1000;      /* unit: millisecond */
+    tx2_reloc_overall = 2000;      /* unit: millisecond */
+    t_dc_prep         = 1000;
+    t_dc_overall      = 2000;
+
+    NETWORK_INTERFACES :
+    {
+        ENB_INTERFACE_NAME_FOR_S1_MME            = "bond0";
+        ENB_IPV4_ADDRESS_FOR_S1_MME              = "192.168.18.203/24";
+        ENB_INTERFACE_NAME_FOR_S1U               = "bond0";
+        ENB_IPV4_ADDRESS_FOR_S1U                 = "192.168.18.203/24";
+        ENB_PORT_FOR_S1U                         = 2152; # Spec 2152
+        ENB_IPV4_ADDRESS_FOR_X2C                 = "192.168.18.203/24";
+        ENB_PORT_FOR_X2C                         = 36422; # Spec 36422
+    };
+
+    log_config :
+    {
+      global_log_level                      ="debug";
+      global_log_verbosity                  ="medium";
+      hw_log_level                          ="info";
+      hw_log_verbosity                      ="medium";
+      phy_log_level                         ="info";
+      phy_log_verbosity                     ="medium";
+      mac_log_level                         ="info";
+      mac_log_verbosity                     ="high";
+      rlc_log_level                         ="info";
+      rlc_log_verbosity                     ="medium";
+      pdcp_log_level                        ="info";
+      pdcp_log_verbosity                    ="medium";
+      rrc_log_level                         ="info";
+      rrc_log_verbosity                     ="medium";
+   };
+
+  }
+);
+MACRLCs = (
+	{
+        num_cc = 1;
+        tr_s_preference = "local_L1";
+        tr_n_preference = "local_RRC";
+        scheduler_mode = "fairRR";
+        puSch10xSnr     =  100;
+        puCch10xSnr     =  100;
+        }  
+);
+
+L1s = (
+    	{
+	num_cc = 1;
+	tr_n_preference = "local_mac";
+        prach_dtx_threshold = 150;
+        }  
+);
+
+RUs = (
+    {		  
+        local_if_name  = "bond0";
+        remote_address = "192.168.18.222";
+        local_address  = "192.168.18.203";
+        local_portc    = 50000;
+        remote_portc   = 55444;
+        local_portd    = 52001;
+        remote_portd   = 52183;
+        local_rf       = "no"
+        tr_preference  = "udp_ecpri_if5"
+        nb_tx          = 1
+        nb_rx          = 1
+        att_tx         = 5 
+        att_rx         = 0;
+        eNB_instances  = [0];
+    }
+);  
+
+THREAD_STRUCT = (
+  {
+    #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
+    parallel_config    = "PARALLEL_RU_L1_TRX_SPLIT";
+    #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
+    worker_config      = "WORKER_ENABLE";
+  }
+);
+
+NETWORK_CONTROLLER :
+{
+    FLEXRAN_ENABLED        = "no";
+    FLEXRAN_INTERFACE_NAME = "lo";
+    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_PORT           = 2210;
+    FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
+    FLEXRAN_AWAIT_RECONF   = "no";
+};
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
index fd1b62fd3dc05e3ec56fb977c1a65ee9a45a60d0..e34b26150092b902660cdf8b9fb43ef7595e82ff 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
@@ -1,6 +1,7 @@
 Active_gNBs = ( "gNB-Eurecom-5GNRBox");
 # Asn1_verbosity, choice in: none, info, annoying
 Asn1_verbosity = "none";
+Num_Threads_PUSCH = 8;
 
 gNBs =
 (
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index 7d6cb9c429121b7329013982cca3b7b979c8ecfc..1347d75fb06939f6b3fbf5526f9f1fbc0c08c09a 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -461,10 +461,9 @@ void eNB_top(PHY_VARS_eNB *eNB,
     L1_proc->subframe_rx  = ru_proc->tti_rx;
     L1_proc->frame_tx     = (L1_proc->subframe_rx > (9-sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx;
     L1_proc->subframe_tx  = (L1_proc->subframe_rx + sf_ahead)%10;
-
+    
     if (rxtx(eNB,L1_proc,string) < 0)
-      LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id);
-
+      LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id);  
     ru_proc->timestamp_tx = L1_proc->timestamp_tx;
     ru_proc->tti_tx  = L1_proc->subframe_tx;
     ru_proc->frame_tx     = L1_proc->frame_tx;
@@ -1168,6 +1167,7 @@ void init_eNB_afterRU(void) {
 
       for (ru_id=0,aa=0; ru_id<eNB->num_RU; ru_id++) {
         eNB->frame_parms.nb_antennas_rx    += eNB->RU_list[ru_id]->nb_rx;
+
         AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL,
                     "RU %d : common.rxdataF is NULL\n",
                     eNB->RU_list[ru_id]->idx);
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
index 4e3a6612736a9ea4e8ed9cf468d55f7c8e8aa50e..56c2cb23dd43114975300a5c41b160c38c6a8551 100644
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -120,6 +120,8 @@ void configure_rru(int idx,
 void reset_proc(RU_t *ru);
 int connect_rau(RU_t *ru);
 
+void wait_eNBs(void);
+
 const char ru_states[6][9] = {"RU_IDLE","RU_CONFIG","RU_READY","RU_RUN","RU_ERROR","RU_SYNC"};
 
 extern uint16_t sf_ahead;
@@ -141,16 +143,12 @@ extern uint16_t sf_ahead;
 static inline void fh_if5_south_out(RU_t *ru,int frame, int subframe, uint64_t timestamp) {
   if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
 
+  ru->south_out_cnt++;
+
   send_IF5(ru, timestamp, subframe, &ru->seqno, IF5_RRH_GW_DL);
 }
 
 
-// southbound IF5 fronthaul for Mobipass packet format
-static inline void fh_if5_mobipass_south_out(RU_t *ru,int frame, int subframe, uint64_t timestamp) {
-  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, timestamp, subframe, &ru->seqno, IF5_MOBIPASS);
-}
 
 
 // southbound IF4p5 fronthaul
@@ -189,11 +187,12 @@ void fh_if5_south_in(RU_t *ru,
   recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL);
   proc->frame_rx    = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
   proc->tti_rx = (proc->timestamp_rx / fp->samples_per_tti)%10;
-
+  
   if (proc->first_rx == 0) {
     if (proc->tti_rx != *subframe) {
-      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*subframe);
-      exit_fun("Exiting");
+      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d), resynching\n",proc->tti_rx,*subframe);
+      *frame=proc->frame_rx;
+      *subframe=proc->tti_rx;
     }
 
     if (proc->frame_rx != *frame) {
@@ -324,48 +323,6 @@ void fh_slave_south_in(RU_t *ru,
 }
 
 
-// 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->tti_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->tti_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->tti_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->tti_rx);
-  } else {
-    if (proc->tti_rx != *subframe) {
-      proc->first_rx++;
-      LOG_E(PHY,"[Mobipass]timestamp:%llu, tti_rx %d is not what we expect %d, first_rx:%d\n",(unsigned long long int)proc->timestamp_rx, proc->tti_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->tti_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,
@@ -456,7 +413,7 @@ void fh_if5_north_asynch_in(RU_t *ru,
   int tti_tx,frame_tx;
   openair0_timestamp timestamp_tx;
   recv_IF5(ru, &timestamp_tx, *subframe, IF5_RRH_GW_DL);
-  //      printf("Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx);
+  //      LOG_I(PHY,"Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx);
   tti_tx = (timestamp_tx/fp->samples_per_tti)%10;
   frame_tx    = (timestamp_tx/(fp->samples_per_tti*10))&1023;
   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
@@ -696,7 +653,7 @@ void rx_rf(RU_t *ru,
     ru->ts_offset = proc->timestamp_rx;
     proc->timestamp_rx = 0;
   } else if (resynch==0 && (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);
+    LOG_D(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;
   }
@@ -761,7 +718,7 @@ void rx_rf(RU_t *ru,
     *subframe = proc->tti_rx;
   }
 
-  //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe);
+  //LOG_I(PHY,"timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_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) {
@@ -929,12 +886,8 @@ static void *ru_thread_asynch_rxtx( void *param ) {
 
       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 (ru->fh_north_asynch_in) {
         if (subframe_select(ru->frame_parms,subframe)!=SF_UL)
           ru->fh_north_asynch_in(ru, &frame, &subframe);
       } else
@@ -1185,21 +1138,22 @@ void wakeup_L1s(RU_t *ru) {
   L1_proc_t *proc         = &eNB->proc;
   struct timespec t;
   LOG_D(PHY, "wakeup_L1s (num %d) for RU %d (%d.%d) ru->eNB_top:%p\n", ru->num_eNB, ru->idx, ru->proc.frame_rx, ru->proc.tti_rx, ru->eNB_top);
-  // call eNB function directly
   char string[20];
   sprintf(string, "Incoming RU %d", ru->idx);
+
+  // call eNB function directly
   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.frame_rx);
   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.tti_rx);
   AssertFatal(0==pthread_mutex_lock(&proc->mutex_RU),"");
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOCK_MUTEX_RU+ru->idx, 1);
-  //printf("wakeup_L1s: Frame %d, Subframe %d: RU %d done (wait_cnt %d),RU_mask[%d] %x\n",
-  //          ru->proc.frame_rx,ru->proc.subframe_rx,ru->idx,ru->wait_cnt,ru->proc.subframe_rx,proc->RU_mask[ru->proc.subframe_rx]);
+  //LOG_I(PHY,"wakeup_L1s: Frame %d, Subframe %d: RU %d done (wait_cnt %d),RU_mask[%d] %x\n",
+  //          ru->proc.frame_rx,ru->proc.tti_rx,ru->idx,ru->wait_cnt,ru->proc.tti_rx,proc->RU_mask[ru->proc.tti_rx]);
   //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.frame_rx);
-  //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.subframe_rx);
+  //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.tti_rx);
   clock_gettime(CLOCK_MONOTONIC, &ru->proc.t[ru->proc.tti_rx]);
 
   if (proc->RU_mask[ru->proc.tti_rx] == 0) {
-    //clock_gettime(CLOCK_MONOTONIC,&proc->t[ru->proc.subframe_rx]);
+    //clock_gettime(CLOCK_MONOTONIC,&proc->t[ru->proc.tti_rx]);
     proc->t[ru->proc.tti_rx] = ru->proc.t[ru->proc.tti_rx];
     //start_meas(&proc->ru_arrival_time);
     LOG_D(PHY,"RU %d starting timer for frame %d subframe %d\n", ru->idx, ru->proc.frame_rx, ru->proc.tti_rx);
@@ -1212,13 +1166,13 @@ void wakeup_L1s(RU_t *ru) {
           eNB->RU_list[i]->idx, eNB->RU_list[i]->proc.frame_rx, eNB->RU_list[i]->proc.tti_rx, ru_states[eNB->RU_list[i]->state]);
 
     if (ru == eNB->RU_list[i] && eNB->RU_list[i]->wait_cnt == 0) {
-      //AssertFatal((proc->RU_mask&(1<<i)) == 0, "eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", eNB->Mod_id,ru->proc.frame_rx,ru->proc.subframe_rx,ru->idx,eNB->num_RU,proc->RU_mask);
+      //AssertFatal((proc->RU_mask&(1<<i)) == 0, "eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", eNB->Mod_id,ru->proc.frame_rx,ru->proc.tti_rx,ru->idx,eNB->num_RU,proc->RU_mask);
       proc->RU_mask[ru->proc.tti_rx] |= (1<<i);
     } else if (/*eNB->RU_list[i]->state == RU_SYNC ||*/(eNB->RU_list[i]->is_slave==1 && eNB->RU_list[i]->wait_cnt>0 && ru!=eNB->RU_list[i] && ru->is_slave==0) ) {
       proc->RU_mask[ru->proc.tti_rx] |= (1<<i);
     }
 
-    //printf("RU %d, RU_mask[%d] %d, i %d, frame %d, slave %d, ru->cnt %d, i->cnt %d\n",ru->idx,ru->proc.subframe_rx,proc->RU_mask[ru->proc.subframe_rx],i,ru->proc.frame_rx,ru->is_slave,ru->wait_cnt,eNB->RU_list[i]->wait_cnt);
+    //LOG_I(PHY,"RU %d, RU_mask[%d] %d, i %d, frame %d, slave %d, ru->cnt %d, i->cnt %d\n",ru->idx,ru->proc.tti_rx,proc->RU_mask[ru->proc.tti_rx],i,ru->proc.frame_rx,ru->is_slave,ru->wait_cnt,eNB->RU_list[i]->wait_cnt);
     VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_MASK_RU, proc->RU_mask[ru->proc.tti_rx]);
 
     if (ru->is_slave == 0 && ( (proc->RU_mask[ru->proc.tti_rx]&(1<<i)) == 1 ) && eNB->RU_list[i]->state == RU_RUN) { //This is master & the RRU has already been received
@@ -1233,21 +1187,21 @@ void wakeup_L1s(RU_t *ru) {
   }
 
   //clock_gettime(CLOCK_MONOTONIC,&t);
-  //LOG_I(PHY,"RU mask is now %x, time is %lu\n",proc->RU_mask[ru->proc.subframe_rx], t.tv_nsec - proc->t[ru->proc.subframe_rx].tv_nsec);
+  //LOG_I(PHY,"RU mask is now %x, time is %lu\n",proc->RU_mask[ru->proc.tti_rx], t.tv_nsec - proc->t[ru->proc.tti_rx].tv_nsec);
 
   if (proc->RU_mask[ru->proc.tti_rx] == (1<<eNB->num_RU)-1) { // all RUs have provided their information so continue on and wakeup eNB top
     LOG_D(PHY,"ru_mask is %d \n ", proc->RU_mask[ru->proc.tti_rx]);
     LOG_D(PHY,"the number of RU is %d, the current ru is RU %d \n ", (1<<eNB->num_RU)-1, ru->idx);
-    LOG_D(PHY,"ru->proc.subframe_rx is %d \n", ru->proc.tti_rx);
+    LOG_D(PHY,"ru->proc.tti_rx is %d \n", ru->proc.tti_rx);
     LOG_D(PHY,"Resetting mask frame %d, subframe %d, this is RU %d\n", ru->proc.frame_rx, ru->proc.tti_rx, ru->idx);
     proc->RU_mask[ru->proc.tti_rx] = 0;
     VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_MASK_RU, proc->RU_mask[ru->proc.tti_rx]);
     clock_gettime(CLOCK_MONOTONIC,&t);
     //stop_meas(&proc->ru_arrival_time);
-    /*AssertFatal(t.tv_nsec < proc->t[ru->proc.subframe_rx].tv_nsec+5000000, "Time difference for subframe %d (Frame %d) => %lu > 5ms, this is RU %d\n",
-                  ru->proc.subframe_rx, ru->proc.frame_rx, t.tv_nsec - proc->t[ru->proc.subframe_rx].tv_nsec, ru->idx);*/
+    /*AssertFatal(t.tv_nsec < proc->t[ru->proc.tti_rx].tv_nsec+5000000, "Time difference for subframe %d (Frame %d) => %lu > 5ms, this is RU %d\n",
+                  ru->proc.tti_rx, ru->proc.frame_rx, t.tv_nsec - proc->t[ru->proc.tti_rx].tv_nsec, ru->idx);*/
     //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.frame_rx);
-    //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.subframe_rx);
+    //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.tti_rx);
     AssertFatal(0==pthread_mutex_unlock(&proc->mutex_RU),"");
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_LOCK_MUTEX_RU+ru->idx, 0 );
     // unlock RUs that are waiting for eNB processing to be completed
@@ -1280,8 +1234,8 @@ void wakeup_L1s(RU_t *ru) {
   }
 
   //      pthread_mutex_unlock(&proc->mutex_RU);
-  //      LOG_D(PHY,"wakeup eNB top for for subframe %d\n", ru->proc.subframe_rx);
-  //      ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string);
+  //      LOG_D(PHY,"wakeup eNB top for for subframe %d\n", ru->proc.tti_rx);
+  //      ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.tti_rx,string);
   ru->proc.emulate_rf_busy = 0;
 }
 
@@ -1350,7 +1304,7 @@ void fill_rf_config(RU_t *ru,
                     char *rf_config_file) {
   LTE_DL_FRAME_PARMS *fp   = ru->frame_parms;
   openair0_config_t *cfg   = &ru->openair0_cfg;
-  //printf("////////////////numerology in config = %d\n",numerology);
+  //LOG_I(PHY,"////////////////numerology in config = %d\n",numerology);
   int numerology = get_softmodem_params()->numerology;
 
   if(fp->N_RB_DL == 100) {
@@ -1377,7 +1331,7 @@ void fill_rf_config(RU_t *ru,
       cfg->tx_bw = 40e6;
       cfg->rx_bw = 40e6;
     } else {
-      printf("Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology);
+      LOG_I(PHY,"Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology);
       cfg->sample_rate=30.72e6;
       cfg->samples_per_frame = 307200;
       cfg->tx_bw = 10e6;
@@ -1416,7 +1370,7 @@ void fill_rf_config(RU_t *ru,
     cfg->tx_gain[i] = (double)ru->att_tx;
     cfg->rx_gain[i] = ru->max_rxgain-(double)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",
+    LOG_I(PHY,"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],
@@ -1437,9 +1391,9 @@ int setup_RU_buffers(RU_t *ru) {
 
   if (ru) {
     frame_parms = ru->frame_parms;
-    printf("setup_RU_buffers: frame_parms = %p\n",frame_parms);
+    LOG_I(PHY,"setup_RU_buffers: frame_parms = %p\n",frame_parms);
   } else {
-    printf("RU not initialized (NULL pointer)\n");
+    LOG_I(PHY,"RU not initialized (NULL pointer)\n");
     return(-1);
   }
 
@@ -1462,7 +1416,7 @@ int setup_RU_buffers(RU_t *ru) {
       ru->sf_extension       /= 4;
       ru->end_of_burst_delay /= 4;
     } else {
-      printf("not handled, todo\n");
+      LOG_I(PHY,"not handled, todo\n");
       exit(1);
     }
   } else {
@@ -1476,13 +1430,13 @@ int setup_RU_buffers(RU_t *ru) {
     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);
+      LOG_I(PHY,"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]);
+      LOG_I(PHY,"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]);
+        LOG_I(PHY,"rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]);
         ru->common.rxdata[i][j] = 16-j;
       }
     }
@@ -1490,13 +1444,13 @@ int setup_RU_buffers(RU_t *ru) {
     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);
+      LOG_I(PHY,"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]);
+      LOG_I(PHY,"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]);
+        LOG_I(PHY,"txbuffer %d: %x\n",j,ru->common.txdata[i][j]);
         ru->common.txdata[i][j] = 16-j;
       }
     }
@@ -1623,7 +1577,7 @@ static void *ru_thread_tx( void *param ) {
       }
 
       if (eNB_proc->RU_mask_tx != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
-        //printf("Not all RUs have provided their info (mask = %d), RU %d, num_RUs %d\n", eNB_proc->RU_mask_tx,ru->idx,eNB->num_RU);
+        //LOG_I(PHY,"Not all RUs have provided their info (mask = %d), RU %d, num_RUs %d\n", eNB_proc->RU_mask_tx,ru->idx,eNB->num_RU);
         AssertFatal((ret=pthread_mutex_unlock(&eNB_proc->mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret);
       } else { // all RUs TX are finished so send the ready signal to eNB processing
         eNB_proc->RU_mask_tx = 0;
@@ -1644,7 +1598,7 @@ static void *ru_thread_tx( void *param ) {
       }
     }
 
-    //printf("ru_thread_tx: Frame %d, Subframe %d: RU %d done (wait_cnt %d),RU_mask_tx %d\n",
+    //LOG_I(PHY,"ru_thread_tx: Frame %d, Subframe %d: RU %d done (wait_cnt %d),RU_mask_tx %d\n",
     //eNB_proc->frame_rx,eNB_proc->subframe_rx,ru->idx,ru->wait_cnt,eNB_proc->RU_mask_tx);
   }
 
@@ -1676,12 +1630,10 @@ static void *ru_thread( void *param ) {
   LOG_I(PHY,"Starting RU %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]);
 
   if(get_softmodem_params()->emulate_rf) {
-    fill_rf_config(ru,ru->rf_config_file);
-    init_frame_parms(ru->frame_parms,1);
     phy_init_RU(ru);
 
     if (setup_RU_buffers(ru)!=0) {
-      printf("Exiting, cannot initialize RU Buffers\n");
+      LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n");
       exit(-1);
     }
 
@@ -1693,24 +1645,20 @@ static void *ru_thread( void *param ) {
     ru->state = RU_RUN;
   } else if (ru->has_ctrl_prt == 0) {
     // There is no control port: start everything here
-    LOG_I(PHY, "RU %d has not ctrl port\n",ru->idx);
+    LOG_I(PHY, "RU %d has no OAI ctrl port\n",ru->idx);
 
-    if (ru->if_south == LOCAL_RF) {
-      fill_rf_config(ru,ru->rf_config_file);
-      init_frame_parms(ru->frame_parms,1);
-      ru->frame_parms->nb_antennas_rx = ru->nb_rx;
-      phy_init_RU(ru);
-      openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
+    fill_rf_config(ru,ru->rf_config_file);
+    init_frame_parms(ru->frame_parms,1);
+    ru->frame_parms->nb_antennas_rx = ru->nb_rx;
 
-      if (setup_RU_buffers(ru)!=0) {
-        printf("Exiting, cannot initialize RU Buffers\n");
-        exit(-1);
-      }
+    if (ru->if_south == LOCAL_RF)       openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
 
-      AssertFatal((ret=pthread_mutex_lock(&RC.ru_mutex))==0,"mutex_lock returns %d\n",ret);
-      RC.ru_mask &= ~(1<<ru->idx);
-      pthread_cond_signal(&RC.ru_cond);
-      AssertFatal((ret=pthread_mutex_unlock(&RC.ru_mutex))==0,"mutex_unlock returns %d\n",ret);
+    phy_init_RU(ru);
+      
+      
+    if (setup_RU_buffers(ru)!=0) {
+        LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n");
+	      exit(-1);
     }
 
     AssertFatal((ret=pthread_mutex_lock(&RC.ru_mutex))==0,"mutex_lock returns %d\n",ret);
@@ -1745,9 +1693,9 @@ static void *ru_thread( void *param ) {
 
       // 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);
+	if (ru->start_rf(ru) != 0)
+	  AssertFatal(1==0,"Could not start the RF device\n");
+	else LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
       } else LOG_D(PHY,"RU %d no rf device\n",ru->idx);
     }
 
@@ -1781,7 +1729,6 @@ static void *ru_thread( void *param ) {
       // 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");
-
 #ifdef PHY_TX_THREAD
 
       if(first_phy_tx == 0) {
@@ -1945,7 +1892,7 @@ static void *ru_thread( void *param ) {
     } // ru->state = RU_RUN
   } // while !oai_exit
 
-  printf( "Exiting ru_thread \n");
+  LOG_I(PHY, "Exiting ru_thread \n");
 
   if (!(get_softmodem_params()->emulate_rf)) {
     if (ru->stop_rf != NULL) {
@@ -2190,6 +2137,12 @@ static void *rf_tx( void *param ) {
 #endif
 
 
+
+int start_streaming(RU_t *ru) {
+  LOG_I(PHY,"Starting streaming on third-party RRU\n");
+  return(ru->ifdevice.thirdparty_startstreaming(&ru->ifdevice));
+}
+
 int start_if(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB) {
   return(ru->ifdevice.trx_start_func(&ru->ifdevice));
 }
@@ -2235,7 +2188,7 @@ void reset_proc(RU_t *ru) {
 
 
 void init_RU_proc(RU_t *ru) {
-  int i=0, ret;
+  int i=0;
   RU_proc_t *proc;
   pthread_attr_t *attr_FH=NULL, *attr_FH1=NULL, *attr_prach=NULL, *attr_asynch=NULL, *attr_synch=NULL, *attr_emulateRF=NULL, *attr_ctrl=NULL, *attr_prach_br=NULL;
   //pthread_attr_t *attr_fep=NULL;
@@ -2304,7 +2257,17 @@ void init_RU_proc(RU_t *ru) {
   attr_prach_br  = &proc->attr_prach_br;
 #endif
 
-  if (ru->function!=eNodeB_3GPP) pthread_create( &proc->pthread_ctrl, attr_ctrl, ru_thread_control, (void *)ru );
+  if (ru->has_ctrl_prt == 1) pthread_create( &proc->pthread_ctrl, attr_ctrl, ru_thread_control, (void*)ru );
+  else {
+    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) wait_eNBs();
+    }
+  }
+
 
   pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void *)ru );
 #if defined(PRE_SCD_THREAD)
@@ -2343,23 +2306,6 @@ void init_RU_proc(RU_t *ru) {
     LOG_I(PHY,"%s() DJP - added creation of pthread_prach\n", __FUNCTION__);
     pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void *)ru );
     ru->state=RU_RUN;
-    if(!get_softmodem_params()->emulate_rf)
-    {
-      fill_rf_config(ru,ru->rf_config_file);
-      init_frame_parms(ru->frame_parms,1);
-      ru->frame_parms->nb_antennas_rx = ru->nb_rx;
-      phy_init_RU(ru);
-      ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
-      if (ret < 0) {
-         LOG_I(PHY,"Exiting, cannot load device. Make sure that your SDR board is connected!\n");
-         exit(1);
-      }
-
-      if (setup_RU_buffers(ru)!=0) {
-        LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n");
-        exit(1);
-      }
-    }
   }
 
   if (get_thread_worker_conf() == WORKER_ENABLE) {
@@ -2368,7 +2314,7 @@ void init_RU_proc(RU_t *ru) {
   }
 
   if (opp_enabled == 1) pthread_create(&ru->ru_stats_thread,NULL,ru_stats_thread,(void *)ru);
-
+/*
   if (ru->function == eNodeB_3GPP) {
     usleep(10000);
     LOG_I(PHY, "Signaling main thread that RU %d (is_slave %d,send_dmrs %d) is ready in state %s\n",ru->idx,ru->is_slave,ru->generate_dmrs_sync,ru_states[ru->state]);
@@ -2377,6 +2323,7 @@ void init_RU_proc(RU_t *ru) {
     pthread_cond_signal(&RC.ru_cond);
     AssertFatal((ret=pthread_mutex_unlock(&RC.ru_mutex))==0,"mutex_unlock returns %d\n",ret);
   }
+  */
 }
 
 
@@ -2539,6 +2486,7 @@ void init_precoding_weights(PHY_VARS_eNB *eNB) {
 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
@@ -2559,10 +2507,10 @@ void set_function_spec_param(RU_t *ru) {
         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);
+        LOG_I(PHY,"NGFI_RRU_IF5: openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
 
         if (ret<0) {
-          printf("Exiting, cannot initialize transport protocol\n");
+          LOG_I(PHY,"Exiting, cannot initialize transport protocol\n");
           exit(-1);
         }
       } else if (ru->function == NGFI_RRU_IF4p5) {
@@ -2583,10 +2531,10 @@ void set_function_spec_param(RU_t *ru) {
         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);
+        LOG_I(PHY,"NGFI_RRU_if4p5 : openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
 
         if (ret<0) {
-          printf("Exiting, cannot initialize transport protocol\n");
+          LOG_I(PHY,"Exiting, cannot initialize transport protocol\n");
           exit(-1);
         }
 
@@ -2606,7 +2554,7 @@ void set_function_spec_param(RU_t *ru) {
       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);
+      LOG_I(PHY,"NFGI_RRU_IF4p5: 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);
@@ -2616,7 +2564,7 @@ void set_function_spec_param(RU_t *ru) {
 
         ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
         if (setup_RU_buffers(ru)!=0) {
-        printf("Exiting, cannot initialize RU Buffers\n");
+        LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n");
         exit(-1);
         }*/
       break;
@@ -2629,25 +2577,22 @@ void set_function_spec_param(RU_t *ru) {
 
       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->start_rf               = ru->eth_params.transp_preference == ETH_UDP_IF5_ECPRI_MODE ? start_streaming : NULL;
       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);
+      LOG_I(PHY,"REMOTE_IF5: openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
 
       if (ret<0) {
-        printf("Exiting, cannot initialize transport protocol\n");
+        LOG_I(PHY,"Exiting, cannot initialize transport protocol\n");
         exit(-1);
       }
 
@@ -2670,10 +2615,10 @@ void set_function_spec_param(RU_t *ru) {
       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);
+      LOG_I(PHY,"REMOTE IF4p5: openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
 
       if (ret<0) {
-        printf("Exiting, cannot initialize transport protocol\n");
+        LOG_I(PHY,"Exiting, cannot initialize transport protocol\n");
         exit(-1);
       }
 
@@ -2687,12 +2632,14 @@ void set_function_spec_param(RU_t *ru) {
       }
 
       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);
@@ -2782,6 +2729,11 @@ void init_RU(char *rf_config_file, int send_dmrssync) {
 
     LOG_I(PHY, "Initializing RRU descriptor %d : (%s,%s,%d)\n", ru_id, ru_if_types[ru->if_south], NB_timing[ru->if_timing], ru->function);
     set_function_spec_param(ru);
+    if (ru->function != NGFI_RRU_IF4p5 && ru->function != NGFI_RRU_IF5) {
+       fill_rf_config(ru,ru->rf_config_file);
+       init_frame_parms(ru->frame_parms,1);
+    }
+
     LOG_I(PHY, "Starting ru_thread %d, is_slave %d, send_dmrs %d\n", ru_id, ru->is_slave, ru->generate_dmrs_sync);
     init_RU_proc(ru);
   } // for ru_id
@@ -2795,7 +2747,7 @@ void stop_ru(RU_t *ru) {
 #if defined(PRE_SCD_THREAD) || defined(PHY_TX_THREAD)
   int *status;
 #endif
-  printf("Stopping RU %p processing threads\n",(void *)ru);
+  LOG_I(PHY,"Stopping RU %p processing threads\n",(void *)ru);
 #if defined(PRE_SCD_THREAD)
 
   if(ru) {
@@ -2849,7 +2801,7 @@ void init_ru_vnf(void) {
   pthread_mutex_init(&RC.ru_mutex,NULL);
   pthread_cond_init(&RC.ru_cond,NULL);
   // read in configuration file)
-  printf("configuring RU from file\n");
+  LOG_I(PHY,"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());
 
@@ -2939,7 +2891,7 @@ void RCconfig_RU(void) {
       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]);
+      LOG_I(PHY,"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)
@@ -2949,7 +2901,7 @@ void RCconfig_RU(void) {
 
       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];
 
-      RC.ru[j]->has_ctrl_prt                        = 1;
+      RC.ru[j]->has_ctrl_prt                        = 0;
 
       if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) {
         RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr));
@@ -2996,7 +2948,7 @@ void RCconfig_RU(void) {
           RC.ru[j]->if_south                        = LOCAL_RF;
           RC.ru[j]->function                        = eNodeB_3GPP;
           RC.ru[j]->state                           = RU_RUN;
-          printf("Setting function for RU %d to eNodeB_3GPP\n",j);
+          LOG_I(PHY,"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));
@@ -3006,42 +2958,43 @@ void RCconfig_RU(void) {
 
           // Check if control port set
           if  (!(config_isparamset(RUParamList.paramarray[j],RU_REMOTE_PORTC_IDX)) ) {
-            printf("Removing control port for RU %d\n",j);
+            LOG_I(PHY,"Removing control port for RU %d\n",j);
             RC.ru[j]->has_ctrl_prt            = 0;
           } else {
             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);
-            printf(" Control port %u \n",RC.ru[j]->eth_params.my_portc);
+            LOG_I(PHY," Control port %u \n",RC.ru[j]->eth_params.my_portc);
           }
 
           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);
+            LOG_I(PHY,"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);
+            LOG_I(PHY,"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);
+            RC.ru[j]->has_ctrl_prt                   =1;
+            LOG_I(PHY,"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);
+            LOG_I(PHY,"Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j);
           }
 
-          printf("RU %d is_slave=%s\n",j,*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr));
+          LOG_I(PHY,"RU %d is_slave=%s\n",j,*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr));
 
           if (strcmp(*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr), "yes") == 0) RC.ru[j]->is_slave=1;
           else RC.ru[j]->is_slave=0;
 
-          printf("RU %d ota_sync_enabled=%s\n",j,*(RUParamList.paramarray[j][RU_OTA_SYNC_ENABLE_IDX].strptr));
+          LOG_I(PHY,"RU %d ota_sync_enabled=%s\n",j,*(RUParamList.paramarray[j][RU_OTA_SYNC_ENABLE_IDX].strptr));
 
           if (strcmp(*(RUParamList.paramarray[j][RU_OTA_SYNC_ENABLE_IDX].strptr), "yes") == 0) RC.ru[j]->ota_sync_enable=1;
           else RC.ru[j]->ota_sync_enable=0;
@@ -3055,8 +3008,8 @@ void RCconfig_RU(void) {
 
         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));
+else {
+        LOG_I(PHY,"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));
@@ -3064,34 +3017,34 @@ void RCconfig_RU(void) {
         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;
+	  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), "udp_ecpri_if5") == 0) {
+	  RC.ru[j]->if_south                     = REMOTE_IF5;
+	  RC.ru[j]->function                     = NGFI_RAU_IF5;
+	  RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF5_ECPRI_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;
+	  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;
+	  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;
+	  RC.ru[j]->has_ctrl_prt                 = 1;
         } 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;
+	  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;
+	
+          if (strcmp(*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr), "yes") == 0) RC.ru[j]->is_slave=1;
+          else RC.ru[j]->is_slave=0;
         }
-
-        if (strcmp(*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr), "yes") == 0) RC.ru[j]->is_slave=1;
-        else RC.ru[j]->is_slave=0;
       }  /* 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);
diff --git a/targets/RT/USER/rcc_if5.gtkw b/targets/RT/USER/rcc_if5.gtkw
index d64a9ca0fb2e0352c5f9f7a584ad2225cd140249..34c6bab5d13b26fb44e8ff1b0a0173ae88577d33 100644
--- a/targets/RT/USER/rcc_if5.gtkw
+++ b/targets/RT/USER/rcc_if5.gtkw
@@ -1,41 +1,67 @@
 [*]
-[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI
-[*] Sun Jul 31 13:30:42 2016
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Tue Sep 24 06:59:08 2019
 [*]
 [dumpfile] "/tmp/openair_dump_eNB.vcd"
-[dumpfile_mtime] "Sun Jul 31 13:21:59 2016"
-[dumpfile_size] 18273240
-[savefile] "/home/fourmi/openairinterface5g/targets/RT/USER/rcc_if5.gtkw"
-[timestart] 24070893000
-[size] 1301 716
-[pos] 309 0
-*-19.793451 29026062100 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-[sst_width] 284
-[signals_width] 262
+[dumpfile_mtime] "Mon Sep 23 20:04:56 2019"
+[dumpfile_size] 1625759
+[savefile] "/home/orange/aw2s/openairinterface5g/targets/RT/USER/rcc_if5.gtkw"
+[timestart] 12600104000
+[size] 1215 1000
+[pos] 0 22
+*-19.506693 12600920638 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 386
+[signals_width] 344
 [sst_expanded] 1
-[sst_vpaned_height] 294
+[sst_vpaned_height] 303
+@29
+functions.send_if5
+@28
+functions.recv_if5
 @24
 variables.trx_ts[63:0]
 variables.trx_tst[63:0]
 @28
-functions.send_if5
-functions.recv_if5
 functions.eNB_thread_rxtx0
 @24
+variables.frame_number_RX0_RU[63:0]
+variables.subframe_number_RX0_RU[63:0]
+variables.frame_number_TX0_RU[63:0]
+variables.subframe_number_TX0_RU[63:0]
+@28
+functions.mac_schedule_dlsch
+functions.macxface_eNB_dlsch_ulsch_scheduler
+functions.macxface_ue_scheduler
+functions.phy_eNB_ofdm_mod_l
+@24
 variables.frame_number_RX0_eNB[63:0]
 variables.subframe_number_RX0_eNB[63:0]
 variables.frame_number_TX0_eNB[63:0]
 variables.subframe_number_TX0_eNB[63:0]
-@28
-functions.eNB_thread_rxtx1
-@24
 variables.frame_number_RX1_eNB[63:0]
 variables.subframe_number_RX1_eNB[63:0]
 variables.frame_number_TX1_eNB[63:0]
 variables.subframe_number_TX1_eNB[63:0]
 @28
+functions.phy_eNB_dlsch_modulation
+functions.phy_eNB_dlsch_encoding
+functions.phy_eNB_dlsch_scrambling
+functions.phy_eNB_beam_precoding
+functions.phy_enb_pdcch_tx
+functions.phy_enb_prach_rx
+functions.phy_procedures_ru_feprx0
+functions.phy_procedures_eNb_rx_uespec0
+functions.phy_procedures_eNb_rx_uespec1
+functions.phy_enb_sfgen
+functions.phy_procedures_eNb_tx0
+functions.phy_procedures_eNb_tx1
+functions.phy_procedures_ru_feprx1
+functions.phy_procedures_ru_feptx_ofdm0
+functions.phy_procedures_ru_feptx_ofdm1
+functions.phy_procedures_ru_feptx_prec0
+functions.phy_procedures_ru_feptx_prec1
+functions.eNB_thread_rxtx1
 functions.phy_enb_sfgen
-functions.phy_eNB_slot_fep
 functions.phy_enb_prach_rx
 @24
 variables.dci_info[63:0]
diff --git a/targets/RT/USER/ru_control.c b/targets/RT/USER/ru_control.c
index 6daf0f4dfac678a831fcfa0d08c7e7545eab5720..7ac6a8913ef3be0d7eea86a16993aa0126a55617 100644
--- a/targets/RT/USER/ru_control.c
+++ b/targets/RT/USER/ru_control.c
@@ -524,7 +524,7 @@ void* ru_thread_control( void* param )
   }
 
   
-  ru->state = (ru->function==eNodeB_3GPP)? RU_RUN : RU_IDLE;
+  ru->state = (ru->function==eNodeB_3GPP || ru->if_south == REMOTE_IF5)? RU_RUN : RU_IDLE;
   LOG_I(PHY,"Control channel ON for RU %d\n", ru->idx);
 
   while (!oai_exit) // Change the cond