diff --git a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf
index d92804ae44426aa2bcbf96bdde5d2adb47b23722..36e93ba14eb588e942ee3606ccc30751ff4b2696 100644
--- a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf
+++ b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf
@@ -71,6 +71,12 @@ 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
+             initialDLBWPstartSymbolAndLength_3  = 57;
+
   #uplinkConfigCommon 
      #frequencyInfoUL
       ul_frequencyBand                                                 = 78;
@@ -105,8 +111,8 @@ gNBs =
 #1,2,4,8,10,20,40,80
         ra_ResponseWindow                                           = 4;
 #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
-#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen
-        ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR                = 3;
+#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR                = 4;
 #oneHalf (0..15) 4,8,12,16,...60,64
         ssb_perRACH_OccasionAndCB_PreamblesPerSSB                   = 15;
 #ra_ContentionResolutionTimer
@@ -114,8 +120,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
         #  
@@ -135,7 +141,11 @@ gNBs =
         # 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;
 
@@ -235,8 +245,10 @@ RUs = (
          att_rx         = 0;
          bands          = [7];
          max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 114;
+         max_rxgain                    = 75;
          eNB_instances  = [0];
+         #beamforming 1x4 matrix:
+         bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000];
 	 sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
          clock_src = "external";
     }
diff --git a/ci-scripts/cppcheck_suppressions.list b/ci-scripts/cppcheck_suppressions.list
index 727fd22e745ceb031a0c65938827efc49cab13dc..4b9fb97427e78afbdb41071a272dafa6c76e03df 100644
--- a/ci-scripts/cppcheck_suppressions.list
+++ b/ci-scripts/cppcheck_suppressions.list
@@ -83,6 +83,10 @@ nullPointer:common/utils/T/tracer/multi.c:265
 // the tests
 arrayIndexOutOfBounds:openair2/LAYER2/rlc_v2/tests/test.c:401
 //
+//-----------------------------------------------------------------------------
+// cppcheck does not understand the different lengths of arrays
+arrayIndexOutOfBounds:openair1/SIMULATION/TOOLS/random_channel.c:705
+arrayIndexOutOfBounds:openair1/SIMULATION/TOOLS/random_channel.c:706
 //*****************************************************************************
 //
 // True problems we don't know how to fix, Suppression is commented out,
diff --git a/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml
index c51093c1785b26267a71bd3a03a3d42580dd1560..a344cb6a7f8ac30f8210104a5025b4a4d0348eeb 100644
--- a/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml
+++ b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml
@@ -52,7 +52,7 @@
         <testCase id="090102">
                 <class>Initialize_OAI_UE</class>
                 <desc>Initialize NR UE USRP</desc>
-		<Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --threadoffset 16 --rrc_config_path .</Initialize_OAI_UE_args>
+		<Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --ue-rxgain 75 --threadoffset 16 --rrc_config_path .</Initialize_OAI_UE_args>
 		<air_interface>NR</air_interface>
         </testCase>
 
diff --git a/ci-scripts/xml_files/gnb_nr_ue_usrp_run_multi_thread.xml b/ci-scripts/xml_files/gnb_nr_ue_usrp_run_multi_thread.xml
index b4290ae6a3da69eae76ad7e8359a3df1272483b7..9e5e0a2bac25951101b2d58dcb8462e1475e787c 100644
--- a/ci-scripts/xml_files/gnb_nr_ue_usrp_run_multi_thread.xml
+++ b/ci-scripts/xml_files/gnb_nr_ue_usrp_run_multi_thread.xml
@@ -52,7 +52,7 @@
         <testCase id="090104">
                 <class>Initialize_OAI_UE</class>
                 <desc>Initialize NR UE USRP</desc>
-		<Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --threadoffset 16 --rrc_config_path .</Initialize_OAI_UE_args>
+		<Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --ue-rxgain 75 --threadoffset 16 --rrc_config_path .</Initialize_OAI_UE_args>
 		<air_interface>NR</air_interface>
         </testCase>
 
diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index a1e9cebc89889a015cdfe9676ea9383f5fa5af4a..0977f6c0d9971cf10f29b6bc15b36ef586fd4cec 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -763,6 +763,42 @@ set(HWLIB_TCP_BRIDGE_OAI_SOURCE
 add_library(tcp_bridge_oai MODULE ${HWLIB_TCP_BRIDGE_OAI_SOURCE} )
 set_target_properties(tcp_bridge_oai PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
 
+# Benetel 4G library
+######################################################################
+
+set(HWLIB_BENETEL_4G_SOURCE
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/benetel.c
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/shared_buffers.c
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/low.c
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/low_dpdk.c
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/4g/dpdk_driver.c
+  )
+add_library(benetel_4g MODULE ${HWLIB_BENETEL_4G_SOURCE} )
+
+set_target_properties(benetel_4g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native -I$ENV{RTE_SDK}/$ENV{RTE_TARGET}/include")
+
+SET(DPDK_LIBS "-Wl,-rpath,$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -Wl,--whole-archive -L$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -ldpdk -Wl,--no-whole-archive")
+TARGET_LINK_LIBRARIES(benetel_4g ${DPDK_LIBS})
+TARGET_LINK_LIBRARIES(benetel_4g pthread dl rt m numa)
+
+# Benetel 5G library
+######################################################################
+
+set(HWLIB_BENETEL_5G_SOURCE
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/benetel.c
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/shared_buffers.c
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/low.c
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/low_dpdk.c
+  ${OPENAIR_TARGETS}/ARCH/ETHERNET/benetel/5g/dpdk_driver.c
+  )
+add_library(benetel_5g MODULE ${HWLIB_BENETEL_5G_SOURCE} )
+
+set_target_properties(benetel_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native -I$ENV{RTE_SDK}/$ENV{RTE_TARGET}/include")
+
+SET(DPDK_LIBS "-Wl,-rpath,$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -Wl,--whole-archive -L$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -ldpdk -Wl,--no-whole-archive")
+TARGET_LINK_LIBRARIES(benetel_5g ${DPDK_LIBS})
+TARGET_LINK_LIBRARIES(benetel_5g pthread dl rt m numa)
+
 ##########################################################
 
 include_directories ("${OPENAIR_TARGETS}/ARCH/COMMON")
@@ -1552,7 +1588,7 @@ set(PHY_SRC_UE
   ${OPENAIR1_DIR}/PHY/NR_REFSIG/ptrs_nr.c
   ${OPENAIR1_DIR}/PHY/NR_UE_ESTIMATION/filt16a_32.c
   ${OPENAIR1_DIR}/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
-  ${OPENAIR1_DIR}/PHY/NR_ESTIMATION/nr_adjust_sync_gNB.c
+  ${OPENAIR1_DIR}/PHY/NR_ESTIMATION/nr_measurements_gNB.c
   ${OPENAIR1_DIR}/PHY/TOOLS/file_output.c
   ${OPENAIR1_DIR}/PHY/TOOLS/cadd_vv.c
   #${OPENAIR1_DIR}/PHY/TOOLS/lte_dfts.c
@@ -1746,9 +1782,15 @@ set(NR_RLC_SRC
   ${OPENAIR2_DIR}/LAYER2/nr_rlc/nr_rlc_sdu.c
   ${OPENAIR2_DIR}/LAYER2/nr_rlc/nr_rlc_ue_manager.c
   )
+  
+set(NR_PDCP_SRC
+  ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+  ${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
+  )
 
 set(L2_SRC
-  ${OPENAIR2_DIR}/LAYER2/openair2_proc.c
   ${PDCP_DIR}/pdcp.c
   ${PDCP_DIR}/pdcp_fifo.c
   ${PDCP_DIR}/pdcp_sequence_manager.c
@@ -1756,6 +1798,7 @@ set(L2_SRC
   ${PDCP_DIR}/pdcp_util.c
   ${PDCP_DIR}/pdcp_security.c
   ${PDCP_DIR}/pdcp_netlink.c
+  ${OPENAIR2_DIR}/LAYER2/openair2_proc.c
 #  ${RRC_DIR}/rrc_UE.c
   ${RRC_DIR}/rrc_eNB.c
   ${RRC_DIR}/rrc_eNB_endc.c
@@ -1767,6 +1810,20 @@ set(L2_SRC
   ${RRC_DIR}/L2_interface_common.c
   ${RRC_DIR}/L2_interface_ue.c
   )
+  
+set(L2_RRC_SRC
+  ${OPENAIR2_DIR}/LAYER2/openair2_proc.c
+  #  ${RRC_DIR}/rrc_UE.c
+  ${RRC_DIR}/rrc_eNB.c
+  ${RRC_DIR}/rrc_eNB_endc.c
+  ${RRC_DIR}/rrc_eNB_S1AP.c
+  ${RRC_DIR}/rrc_eNB_M2AP.c
+  ${RRC_DIR}/rrc_eNB_UE_context.c
+  ${RRC_DIR}/rrc_common.c
+  ${RRC_DIR}/L2_interface.c
+  ${RRC_DIR}/L2_interface_common.c
+  ${RRC_DIR}/L2_interface_ue.c
+  )
 
 set(L2_LTE_SRC
   ${RLC_V2}
@@ -1774,6 +1831,7 @@ set(L2_LTE_SRC
 
 set(L2_NR_SRC
   ${NR_RLC_SRC}
+  ${NR_PDCP_SRC}
   ${NR_RRC_DIR}/rrc_gNB.c
   ${NR_RRC_DIR}/nr_rrc_common.c
   ${NR_RRC_DIR}/L2_nr_interface.c
@@ -1798,19 +1856,16 @@ set(L2_SRC_UE
   ${RRC_DIR}/L2_interface_ue.c
   )
   
-set(LTE_NR_L2_SRC_UE
-  ${PDCP_DIR}/pdcp.c
-  ${PDCP_DIR}/pdcp_fifo.c
-  ${PDCP_DIR}/pdcp_sequence_manager.c
-  ${PDCP_DIR}/pdcp_primitives.c
-  ${PDCP_DIR}/pdcp_util.c
-  ${PDCP_DIR}/pdcp_security.c
-  ${PDCP_DIR}/pdcp_netlink.c
-  ${RLC_V2}
-  )
-
+set(L2_RRC_SRC_UE
+  ${RRC_DIR}/rrc_UE.c
+  ${RRC_DIR}/rrc_common.c
+  ${RRC_DIR}/L2_interface_common.c
+  ${RRC_DIR}/L2_interface_ue.c
+  )  
+  
 set(NR_L2_SRC_UE
   ${NR_RLC_SRC}
+  ${NR_PDCP_SRC}
   ${NR_UE_RRC_DIR}/L2_interface_ue.c
   ${NR_UE_RRC_DIR}/main_ue.c
   ${NR_UE_RRC_DIR}/rrc_UE.c
@@ -1920,6 +1975,14 @@ add_library(L2_NR
   ${MAC_NR_SRC}
   ${GNB_APP_SRC}
   )
+
+add_library(L2_LTE_NR
+  ${L2_RRC_SRC}
+  ${MAC_SRC}
+  ${ENB_APP_SRC}
+  ${MCE_APP_SRC}
+)
+  
 add_dependencies(L2_NR rrc_flag nr_rrc_flag s1ap_flag x2_flag)
 
 add_library(L2_UE
@@ -1927,6 +1990,11 @@ add_library(L2_UE
   ${MAC_SRC_UE}
 )
 
+add_library(L2_UE_LTE_NR
+  ${L2_RRC_SRC_UE}
+  ${MAC_SRC_UE}
+)
+
 if (NOT ${NOS1})
 target_compile_definitions(L2_UE PUBLIC -DPDCP_USE_NETLINK)
 endif()
@@ -2748,7 +2816,7 @@ target_link_libraries (nr-softmodem
   -Wl,--start-group
   UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_NR_COMMON PHY_RU LFDS NR_GTPV1U SECU_CN SECU_OSA
   ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} RRC_LIB NR_RRC_LIB 
-  S1AP_LIB S1AP_ENB L2 L2_NR MAC_NR_COMMON NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
+  S1AP_LIB S1AP_ENB L2_LTE_NR L2_NR MAC_NR_COMMON NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
   X2AP_LIB X2AP_ENB F1AP_LIB F1AP M2AP_LIB M2AP_ENB M3AP_LIB M3AP_ENB ${PROTO_AGENT_LIB} ${FSPT_MSG_LIB}
   -Wl,--end-group z dl)
 
@@ -2790,7 +2858,7 @@ add_executable(nr-uesoftmodem
 target_link_libraries (nr-uesoftmodem
   -Wl,--start-group
   RRC_LIB NR_RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB
-  PHY_COMMON PHY_NR_COMMON PHY_UE PHY_NR_UE PHY_RU LFDS NR_L2_UE L2_UE MAC_NR_COMMON NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB
+  PHY_COMMON PHY_NR_COMMON PHY_UE PHY_NR_UE PHY_RU LFDS NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB
   NFAPI_USER_LIB S1AP_LIB S1AP_ENB
   ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 ${ATLAS_LIBRARIES} 
   -Wl,--end-group z dl)
@@ -2909,6 +2977,7 @@ add_executable(nr_dlschsim
   ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlschsim.c 
   ${OPENAIR_DIR}/common/utils/system.c
   ${OPENAIR_DIR}/common/utils/nr/nr_common.c
+  ${OPENAIR_DIR}/common/utils/utils.c
   ${UTIL_SRC}
   ${T_SOURCE}
   ${SHLIB_LOADER_SOURCES}
@@ -2922,6 +2991,7 @@ add_executable(nr_pbchsim
   ${OPENAIR1_DIR}/SIMULATION/NR_PHY/pbchsim.c 
   ${OPENAIR_DIR}/common/utils/system.c
   ${OPENAIR_DIR}/common/utils/nr/nr_common.c
+  ${OPENAIR_DIR}/common/utils/utils.c
   ${UTIL_SRC}
   ${T_SOURCE}
   ${SHLIB_LOADER_SOURCES}
@@ -2937,6 +3007,7 @@ add_executable(nr_pucchsim
   ${OPENAIR_DIR}/common/utils/backtrace.c
   ${OPENAIR_DIR}/common/utils/nr/nr_common.c
   ${OPENAIR_DIR}/common/utils/system.c
+  ${OPENAIR_DIR}/common/utils/utils.c
   ${UTIL_SRC}
   ${T_SOURCE}
   ${SHLIB_LOADER_SOURCES}
@@ -2948,6 +3019,7 @@ target_link_libraries(nr_pucchsim
 
 add_executable(nr_dlsim
   ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlsim.c
+  ${OPENAIR_DIR}/common/utils/utils.c
   ${OPENAIR_DIR}/common/utils/system.c
   ${OPENAIR_DIR}/common/utils/nr/nr_common.c
   ${OPENAIR_DIR}/executables/softmodem-common.c
@@ -2963,6 +3035,7 @@ target_compile_definitions(nr_dlsim PUBLIC -DPHYSICAL_SIMULATOR)
 
 add_executable(nr_prachsim
   ${OPENAIR1_DIR}/SIMULATION/NR_PHY/prachsim.c 
+  ${OPENAIR_DIR}/common/utils/utils.c
   ${OPENAIR_DIR}/common/utils/system.c
   ${OPENAIR_DIR}/common/utils/nr/nr_common.c
   ${OPENAIR1_DIR}/SCHED_NR/phy_procedures_nr_common.c
@@ -2974,6 +3047,7 @@ target_link_libraries(nr_prachsim
 
 add_executable(nr_ulschsim
   ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulschsim.c
+  ${OPENAIR_DIR}/common/utils/utils.c
   ${OPENAIR_DIR}/common/utils/system.c
   ${OPENAIR_DIR}/common/utils/nr/nr_common.c
   ${UTIL_SRC}
@@ -2987,6 +3061,7 @@ target_link_libraries(nr_ulschsim
 
 add_executable(nr_ulsim
   ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulsim.c
+  ${OPENAIR_DIR}/common/utils/utils.c
   ${OPENAIR_DIR}/common/utils/system.c
   ${OPENAIR_DIR}/common/utils/nr/nr_common.c
   ${OPENAIR_DIR}/executables/softmodem-common.c
@@ -3007,6 +3082,7 @@ foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim pr
     ${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c
     ${OPENAIR_DIR}/common/utils/backtrace.c
     ${OPENAIR_DIR}/common/utils/system.c
+    ${OPENAIR_DIR}/common/utils/utils.c
     ${XFORMS_SOURCE}
     ${T_SOURCE}
     ${CONFIG_SOURCES}
@@ -3093,7 +3169,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_UE NR_L2_UE MAC_NR_COMMON MAC_NR MAC_UE_NR
+        L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE MAC_NR_COMMON MAC_NR MAC_UE_NR
         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/common/utils/utils.c b/common/utils/utils.c
index a807a27096f661002d87ab5023291aa62b34fe89..7f7aafc94a498f1dd53b006b98c1fc83e37d4e43 100644
--- a/common/utils/utils.c
+++ b/common/utils/utils.c
@@ -105,3 +105,9 @@ char *itoa(int i) {
   return strdup(buffer);
 }
 
+void *memcpy1(void *dst,const void *src,size_t n) {
+
+  void *ret=dst;
+  asm volatile("rep movsb" : "+D" (dst) : "c"(n), "S"(src) : "cc","memory");
+  return(ret);
+}
diff --git a/common/utils/utils.h b/common/utils/utils.h
index 11db07056e0f81b8440ec7888b86005f13633363..da7c453b0375d25165350b0bb4bcd474e14a7579 100644
--- a/common/utils/utils.h
+++ b/common/utils/utils.h
@@ -15,6 +15,9 @@ int hex_char_to_hex_value (char c);
 // Converts an hexadecimal ASCII coded string into its value.**
 int hex_string_to_hex_value (uint8_t *hex_value, const char *hex_string, int size);
 
+void *memcpy1(void *dst,const void *src,size_t n);
+
+
 char *itoa(int i);
 
 #define findInList(keY, result, list, element_type) {\
diff --git a/doc/BUILD.md b/doc/BUILD.md
index 97f904759695aeb3c43f659ab3fbbc079df71821..a15083dc323bf57b0f74bfd27133a54d47ffb83e 100644
--- a/doc/BUILD.md
+++ b/doc/BUILD.md
@@ -33,7 +33,7 @@ The main oai binaries, which are tested by the Continuous Integration process ar
 
 Running the  [build_oai](../cmake_targets/build_oai) script also generates some utilities required to build and/or run the oai softmodem binaries:
 
-- `con2uedata`: a binary used to build the UE data from a configuration file. The created file emulates the sim card  of a 3GPP compliant phone.
+- `conf2uedata`: a binary used to build the UE data from a configuration file. The created file emulates the sim card  of a 3GPP compliant phone.
 - `nvram`: a binary used to build UE (IMEI...) and EMM (IMSI, registered PLMN) non volatile data. 
 - `rb_tool`: radio bearer utility 
 - `genids` T Tracer utility, used at build time to generate T_IDs.h include file. This binary is located in the [T Tracer source file directory](../common/utils/T) .
diff --git a/executables/nr-ru.c b/executables/nr-ru.c
index 969ad21b8eecad6ab51b79efbd7dc47c5d145580..a0f5710128d6270fa8a52b720e99f923973b90f6 100644
--- a/executables/nr-ru.c
+++ b/executables/nr-ru.c
@@ -180,6 +180,17 @@ int attach_rru(RU_t *ru)
         ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]);
   AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
               "RU %d failed send configuration to remote radio\n",ru->idx);
+
+  if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
+             &rru_config_msg,
+             msg_len))<0) {
+    LOG_I(PHY,"Waiting for RRU %d\n",ru->idx);
+  } else if (rru_config_msg.type == RRU_config_ok) {
+    LOG_I(PHY, "RRU_config_ok received\n");
+  } else {
+    LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx);
+  }
+
   return 0;
 }
 
@@ -1442,6 +1453,8 @@ 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]);
 
+  memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config));
+
   if(emulate_rf) {
     fill_rf_config(ru,ru->rf_config_file);
     nr_init_frame_parms(&ru->config, fp);
@@ -1464,8 +1477,6 @@ void *ru_thread( void *param ) {
       AssertFatal(ret==0,"Cannot connect to remote radio\n");
     }
 
-    memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config));
-
     if (ru->if_south == LOCAL_RF) { // configure RF parameters only
       nr_init_frame_parms(&ru->config, fp);
       nr_dump_frame_parms(fp);
@@ -1571,7 +1582,8 @@ void *ru_thread( void *param ) {
     if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
     //if (proc->tti_rx==8) {
 
-      if (ru->feprx) ru->feprx(ru,proc->tti_rx);
+      if (ru->feprx) {
+      ru->feprx(ru,proc->tti_rx);
       //LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1);
 
       LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx);
@@ -1591,6 +1603,7 @@ void *ru_thread( void *param ) {
 		       proc->frame_rx,proc->tti_rx);
 	free_nr_ru_prach_entry(ru,prach_id);
       }
+      }
     }
 
     // At this point, all information for subframe has been received on FH interface
@@ -2131,26 +2144,29 @@ void set_function_spec_param(RU_t *ru) {
         ru->fh_north_out         = NULL;                    // no outgoing fronthaul to north
         ru->nr_start_if          = NULL;                    // no if interface
         ru->rfdevice.host_type   = RAU_HOST;
+
+	// FK this here looks messed up. The following lines should be part of the  if (ru->function == gNodeB_3GPP), shouldn't they?
+
+	ru->fh_south_in            = rx_rf;                               // local synchronous RF RX
+	ru->fh_south_out           = tx_rf;                               // local synchronous RF TX
+	ru->start_rf               = start_rf;                            // need to start the local RF interface
+	ru->stop_rf                = stop_rf;
+	ru->start_write_thread     = start_write_thread;                  // starting RF TX in different thread
+	printf("configuring ru_id %u (start_rf %p)\n", ru->idx, start_rf);
       }
 
-      ru->fh_south_in            = rx_rf;                               // local synchronous RF RX
-      ru->fh_south_out           = tx_rf;                               // local synchronous RF TX
-      ru->start_rf               = start_rf;                            // need to start the local RF interface
-      ru->stop_rf                = stop_rf;
-      ru->start_write_thread     = start_write_thread;                  // starting RF TX in different thread
-      printf("configuring ru_id %u (start_rf %p)\n", ru->idx, start_rf);
       /*
-          if (ru->function == gNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise
-            fill_rf_config(ru,rf_config_file);
-            init_frame_parms(&ru->frame_parms,1);
-            nr_phy_init_RU(ru);
-          }
-
-          ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
-          if (setup_RU_buffers(ru)!=0) {
-            printf("Exiting, cannot initialize RU Buffers\n");
-            exit(-1);
-          }*/
+	printf("configuring ru_id %u (start_rf %p)\n", ru->idx, start_rf);
+	fill_rf_config(ru,rf_config_file);
+	init_frame_parms(&ru->frame_parms,1);
+	nr_phy_init_RU(ru);
+
+	ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
+	if (setup_RU_buffers(ru)!=0) {
+	   printf("Exiting, cannot initialize RU Buffers\n");
+	   exit(-1);
+	}
+      */
       break;
 
     case REMOTE_IF5: // the remote unit is IF5 RRU
@@ -2203,6 +2219,15 @@ void set_function_spec_param(RU_t *ru) {
         exit(-1);
       }
 
+      if (ru->ifdevice.get_internal_parameter != NULL) {
+        void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in");
+        if (t != NULL)
+          ru->fh_south_in = t;
+        t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out");
+        if (t != NULL)
+          ru->fh_south_out = t;
+      }
+
       malloc_IF4p5_buffer(ru);
       break;
 
diff --git a/executables/nr-ue.c b/executables/nr-ue.c
index 4b7ff204613081ceda45f7738eac6c58ead36751..1600d8add0daed40f4a10be9370ee9f6f7805d7f 100644
--- a/executables/nr-ue.c
+++ b/executables/nr-ue.c
@@ -364,8 +364,6 @@ static void UE_synch(void *arg) {
 }
 
 void processSlotTX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
-
-
   fapi_nr_config_request_t *cfg = &UE->nrUE_config;
   int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_tti_tx);
   uint8_t gNB_id = 0;
@@ -473,21 +471,22 @@ void UE_processing(void *arg) {
   UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
   PHY_VARS_NR_UE    *UE   = rxtxD->UE;
 
-  uint8_t gNB_id = 0;
-
-  // params for UL time alignment procedure
-  NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &UE->ul_time_alignment[gNB_id];
-  uint8_t numerology = UE->frame_parms.numerology_index;
-  uint16_t bwp_ul_NB_RB = UE->frame_parms.N_RB_UL;
-  int slot_tx = proc->nr_tti_tx;
-  int frame_tx = proc->frame_tx;
+  processSlotRX(UE, proc);
+  processSlotTX(UE, proc);
 
   /* UL time alignment
   // If the current tx frame and slot match the TA configuration in ul_time_alignment
   // then timing advance is processed and set to be applied in the next UL transmission */
   if (UE->mac_enabled == 1) {
+    uint8_t gNB_id = 0;
+    NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &UE->ul_time_alignment[gNB_id];
+    int slot_tx = proc->nr_tti_tx;
+    int frame_tx = proc->frame_tx;
 
     if (frame_tx == ul_time_alignment->ta_frame && slot_tx == ul_time_alignment->ta_slot) {
+      uint8_t numerology = UE->frame_parms.numerology_index;
+      uint16_t bwp_ul_NB_RB = UE->frame_parms.N_RB_UL;
+
       LOG_D(PHY,"Applying timing advance -- frame %d -- slot %d\n", frame_tx, slot_tx);
 
       //if (nfapi_mode!=3){
@@ -497,9 +496,6 @@ void UE_processing(void *arg) {
       //}
     }
   }
-
-  processSlotRX(UE, proc);
-  processSlotTX(UE, proc);
 }
 
 void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
@@ -624,6 +620,7 @@ void *UE_thread(void *arg) {
   notifiedFIFO_t freeBlocks;
   initNotifiedFIFO_nothreadSafe(&freeBlocks);
   NR_UE_MAC_INST_t *mac = get_mac_inst(0);
+  int timing_advance = UE->timing_advance;
 
   for (int i=0; i<RX_NB_TH+1; i++)  // RX_NB_TH working + 1 we are making to be pushed
     pushNotifiedFIFO_nothreadSafe(&freeBlocks,
@@ -728,21 +725,26 @@ void *UE_thread(void *arg) {
 
     for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
       txp[i] = (void *)&UE->common_vars.txdata[i][UE->frame_parms.get_samples_slot_timestamp(
-               ((curMsg->proc.nr_tti_rx + DURATION_RX_TO_TX -2)%nb_slot_frame),&UE->frame_parms,0)];
+               ((slot_nr + DURATION_RX_TO_TX - RX_NB_TH)%nb_slot_frame),&UE->frame_parms,0)];
 
     int readBlockSize, writeBlockSize;
 
     if (slot_nr<(nb_slot_frame - 1)) {
       readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms);
-      writeBlockSize=UE->frame_parms.get_samples_per_slot(curMsg->proc.nr_tti_tx,&UE->frame_parms);
+      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms);
     } else {
       UE->rx_offset_diff = computeSamplesShift(UE);
       readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) -
                     UE->rx_offset_diff;
-      writeBlockSize=UE->frame_parms.get_samples_per_slot(curMsg->proc.nr_tti_tx,&UE->frame_parms) -
+      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms)-
                      UE->rx_offset_diff;
     }
 
+    if (UE->timing_advance != timing_advance) {
+      writeBlockSize -= UE->timing_advance - timing_advance;
+      timing_advance = UE->timing_advance;
+    }
+
     AssertFatal(readBlockSize ==
                 UE->rfdevice.trx_read_func(&UE->rfdevice,
                                            &timestamp,
@@ -750,29 +752,19 @@ void *UE_thread(void *arg) {
                                            readBlockSize,
                                            UE->frame_parms.nb_antennas_rx),"");
 
-    AssertFatal( writeBlockSize ==
-                 UE->rfdevice.trx_write_func(&UE->rfdevice,
-                     timestamp+
-                     UE->frame_parms.get_samples_slot_timestamp(slot_nr,
-                     &UE->frame_parms,DURATION_RX_TO_TX -2) - firstSymSamp -
-                     openair0_cfg[0].tx_sample_advance,
-                     txp,
-                     writeBlockSize,
-                     UE->frame_parms.nb_antennas_tx,
-                     1),"");
-
     if( slot_nr==(nb_slot_frame-1)) {
       // read in first symbol of next frame and adjust for timing drift
       int first_symbols=UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0; // first symbol of every frames
 
-      if ( first_symbols > 0 )
+      if ( first_symbols > 0 ) {
+        openair0_timestamp ignore_timestamp;
         AssertFatal(first_symbols ==
                     UE->rfdevice.trx_read_func(&UE->rfdevice,
-                                               &timestamp,
+                                               &ignore_timestamp,
                                                (void **)UE->common_vars.rxdata,
                                                first_symbols,
                                                UE->frame_parms.nb_antennas_rx),"");
-      else
+      } else
         LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols);
     }
 
@@ -783,18 +775,15 @@ void *UE_thread(void *arg) {
     notifiedFIFO_elt_t *res;
 
     while (nbSlotProcessing >= RX_NB_TH) {
-      if ( (res=tryPullTpool(&nf, Tpool)) != NULL ) {
-        nbSlotProcessing--;
-        processingData_t *tmp=(processingData_t *)res->msgData;
-
-        if (tmp->proc.decoded_frame_rx != -1)
-          decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
-          //decoded_frame_rx=tmp->proc.decoded_frame_rx;
+      res=pullTpool(&nf, Tpool);
+      nbSlotProcessing--;
+      processingData_t *tmp=(processingData_t *)res->msgData;
 
-        pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
-      }
+      if (tmp->proc.decoded_frame_rx != -1)
+        decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
+        //decoded_frame_rx=tmp->proc.decoded_frame_rx;
 
-      usleep(200);
+      pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
     }
 
     if (  (decoded_frame_rx != curMsg->proc.frame_rx) &&
@@ -803,6 +792,20 @@ void *UE_thread(void *arg) {
       LOG_E(PHY,"Decoded frame index (%d) is not compatible with current context (%d), UE should go back to synch mode\n",
             decoded_frame_rx, curMsg->proc.frame_rx  );
 
+    AssertFatal( writeBlockSize ==
+                 UE->rfdevice.trx_write_func(&UE->rfdevice,
+                     timestamp+
+                     UE->frame_parms.get_samples_slot_timestamp(slot_nr,
+                     &UE->frame_parms,DURATION_RX_TO_TX - RX_NB_TH) - firstSymSamp -
+                     openair0_cfg[0].tx_sample_advance - UE->N_TA_offset - UE->timing_advance,
+                     txp,
+                     writeBlockSize,
+                     UE->frame_parms.nb_antennas_tx,
+                     1),"");
+
+    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
+      memset(txp[i], 0, writeBlockSize);
+
     nbSlotProcessing++;
     msgToPush->key=slot_nr;
     pushTpool(Tpool, msgToPush);
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
index 2fbea2bbfb40a1376f1a26cb1aa9e4d431859bf0..e6d644453caf598423959182ae8408c8ec827218 100644
--- a/executables/nr-uesoftmodem.c
+++ b/executables/nr-uesoftmodem.c
@@ -38,7 +38,7 @@
 #include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h"
 
 //#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
-
+#include "openair1/PHY/MODULATION/nr_modulation.h"
 #include "PHY/phy_vars_nr_ue.h"
 #include "PHY/LTE_TRANSPORT/transport_vars.h"
 #include "SCHED/sched_common_vars.h"
@@ -584,7 +584,7 @@ void init_pdcp(void) {
     LOG_I(RLC, "Problem at RLC initiation \n");
   }
   pdcp_layer_init();
-  nr_ip_over_LTE_DRB_preconfiguration();*/
+  nr_DRB_preconfiguration();*/
   pdcp_module_init(pdcp_initmask);
   pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t) rlc_data_req);
   pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) pdcp_data_ind);
@@ -685,11 +685,14 @@ int main( int argc, char **argv ) {
 
     fapi_nr_config_request_t *nrUE_config = &UE[CC_id]->nrUE_config;
     nr_init_frame_parms_ue(frame_parms[CC_id],nrUE_config,NORMAL);
-    
+
     // Overwrite DL frequency (for FR2 testing)
-    if (downlink_frequency[0][0]!=0)
+    if (downlink_frequency[0][0]!=0) {
       frame_parms[CC_id]->dl_CarrierFreq = downlink_frequency[0][0];
+      frame_parms[CC_id]->ul_CarrierFreq = downlink_frequency[0][0];
+    }
    
+    init_symbol_rotation(frame_parms[CC_id],frame_parms[CC_id]->dl_CarrierFreq);
     init_nr_ue_vars(UE[CC_id],frame_parms[CC_id],0,abstraction_flag);
 
     UE[CC_id]->mac_enabled = 1;
@@ -766,13 +769,7 @@ int main( int argc, char **argv ) {
   for(int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
     PHY_vars_UE_g[0][CC_id]->rf_map.card=0;
     PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+chain_offset;
-#if defined(OAI_USRP) || defined(OAI_ADRV9371_ZC706)
-    PHY_vars_UE_g[0][CC_id]->hw_timing_advance = timing_advance;
     PHY_vars_UE_g[0][CC_id]->timing_advance = timing_advance;
-#else
-    PHY_vars_UE_g[0][CC_id]->hw_timing_advance = 160;
-#endif
-
   }
 
   init_NR_UE_threads(1);
diff --git a/openair1/PHY/CODING/nr_rate_matching.c b/openair1/PHY/CODING/nr_rate_matching.c
index 5294e79b9f33a96709d3e994e4cb1792ea2ea351..a16a8d100f4e912ecfe972f2cbe7548265e8df0c 100644
--- a/openair1/PHY/CODING/nr_rate_matching.c
+++ b/openair1/PHY/CODING/nr_rate_matching.c
@@ -236,13 +236,12 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f)
     }
     */
 
-  int j2=0;
   fp=f;
   switch (Qm) {
   case 2:
     e0=e;
     e1=e0+EQm;
-    for (int j = 0; j< EQm; j++,j2+=2){
+    for (int j = 0, j2 = 0; j< EQm; j++,j2+=2){
       fp=&f[j2];
       fp[0] = e0[j];
       fp[1] = e1[j];
@@ -253,7 +252,7 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f)
     e1=e0+EQm;
     e2=e1+EQm;
     e3=e2+EQm;
-    for (int j = 0; j< EQm; j++,j2+=4){
+    for (int j = 0, j2 = 0; j< EQm; j++,j2+=4){
       fp=&f[j2];
       fp[0] = e0[j];
       fp[1] = e1[j];
@@ -287,7 +286,7 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f)
     e5=e4+EQm;
     e6=e5+EQm;
     e7=e6+EQm;
-    for (int j = 0; j< EQm; j++,j2+=8){
+    for (int j = 0, j2 = 0; j< EQm; j++,j2+=8){
       fp=&f[j2];
       fp[0] = e0[j];
       fp[1] = e1[j];
@@ -310,15 +309,67 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f)
 void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f)
 {
 
-  uint32_t EQm;
-
-  EQm = E/Qm;
-
-  for (int j = 0; j< EQm; j++){
-	  for (int i = 0; i< Qm; i++){
-		  e[(i*EQm + j)] = f[(i+j*Qm)];
-	  }
+  int16_t *e1,*e2,*e3,*e4,*e5,*e6,*e7;
+  switch(Qm) {
+  case 2:
+    e1=e+(E/2);
+    for (int j = 0,j2=0; j< E/2; j+=2,j2+=4){
+      e[j]  = f[j2];
+      e1[j] = f[j2+1];
+      e[j+1]  = f[j2+2];
+      e1[j+1] = f[j2+3];
+    }
+    break;
+  case 4:
+    e1=e+(E/4);
+    e2=e1+(E/4);
+    e3=e2+(E/4);
+    for (int j = 0,j2=0; j< E/4; j++,j2+=4){
+      e[j]  = f[j2];
+      e1[j] = f[j2+1];
+      e2[j] = f[j2+2];
+      e3[j] = f[j2+3];
+    }
+    break;
+  case 6:
+    e1=e+(E/6);
+    e2=e1+(E/6);
+    e3=e2+(E/6);
+    e4=e3+(E/6);
+    e5=e4+(E/6);
+    for (int j = 0,j2=0; j< E/6; j++,j2+=6){
+      e[j]  = f[j2];
+      e1[j] = f[j2+1];
+      e2[j] = f[j2+2];
+      e3[j] = f[j2+3];
+      e4[j] = f[j2+4];
+      e5[j] = f[j2+5];
+    }
+    break;
+  case 8:
+    e1=e+(E/6);
+    e2=e1+(E/6);
+    e3=e2+(E/6);
+    e4=e3+(E/6);
+    e5=e4+(E/6);
+    e6=e5+(E/6);
+    e7=e6+(E/6);
+    for (int j = 0,j2=0; j< E/8; j++,j2+=8){
+      e[j]  = f[j2];
+      e1[j] = f[j2+1];
+      e2[j] = f[j2+2];
+      e3[j] = f[j2+3];
+      e4[j] = f[j2+4];
+      e5[j] = f[j2+5];
+      e6[j] = f[j2+6];
+      e7[j] = f[j2+7];
+    }
+    break;
+  default:
+    AssertFatal(1==0,"Should not get here : Qm %d\n",Qm);
+    break;
   }
+
 }
 
 
diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c
index ad648f12be767a122f915832c5046f622edd66f6..057d259baad6cf52b0597d4c4d741fb20c0279f9 100644
--- a/openair1/PHY/INIT/nr_init.c
+++ b/openair1/PHY/INIT/nr_init.c
@@ -27,6 +27,7 @@
 #include "PHY/CODING/nrPolar_tools/nr_polar_pbch_defs.h"
 #include "PHY/NR_TRANSPORT/nr_transport_proto.h"
 #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
+#include "openair1/PHY/MODULATION/nr_modulation.h"
 /*#include "RadioResourceConfigCommonSIB.h"
 #include "RadioResourceConfigDedicated.h"
 #include "TDD-Config.h"
@@ -200,6 +201,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
     common_vars->rxdataF[i] = (int32_t*)malloc16_clear(fp->samples_per_frame_wCP*sizeof(int32_t));
     common_vars->rxdata[i] = (int32_t*)malloc16_clear(fp->samples_per_frame*sizeof(int32_t));
   }
+  common_vars->debugBuff = (int32_t*)malloc16_clear(fp->samples_per_frame*sizeof(int32_t)*100);	
+  common_vars->debugBuff_sample_offset = 0; 
 
 
   // Channel estimates for SRS
@@ -500,6 +503,9 @@ void nr_phy_config_request(NR_PHY_Config_t *phy_config) {
   compute_nr_prach_seq(short_sequence, num_sequences, rootSequenceIndex, RC.gNB[Mod_id]->X_u);
 
   RC.gNB[Mod_id]->configured     = 1;
+
+  init_symbol_rotation(fp,fp->dl_CarrierFreq);
+
   LOG_I(PHY,"gNB %d configured\n",Mod_id);
 }
 
@@ -511,6 +517,15 @@ void init_nr_transport(PHY_VARS_gNB *gNB) {
   LOG_I(PHY, "Initialise nr transport\n");
   uint16_t grid_size = cfg->carrier_config.dl_grid_size[fp->numerology_index].value;
 
+  memset(gNB->num_pdsch_rnti, 0, sizeof(uint16_t)*80);
+
+  for (i=0; i <NUMBER_OF_NR_PDCCH_MAX; i++) {
+    LOG_I(PHY,"Initializing PDCCH list for PDCCH %d/%d\n",i,NUMBER_OF_NR_PDCCH_MAX);
+    gNB->pdcch_pdu[i].frame=-1;
+    LOG_I(PHY,"Initializing UL PDCCH list for UL PDCCH %d/%d\n",i,NUMBER_OF_NR_PDCCH_MAX);
+    gNB->ul_pdcch_pdu[i].frame=-1;
+  }
+    
   for (i=0; i<NUMBER_OF_NR_PUCCH_MAX; i++) {
     LOG_I(PHY,"Allocating Transport Channel Buffers for PUCCH %d/%d\n",i,NUMBER_OF_NR_PUCCH_MAX);
     gNB->pucch[i] = new_gNB_pucch();
diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c
index fed58dea12ddbbe5da86228ab7caecfbef8dfa40..39e99e6ec3e0cfce6437ec0df76ba08224b711b7 100644
--- a/openair1/PHY/INIT/nr_init_ue.c
+++ b/openair1/PHY/INIT/nr_init_ue.c
@@ -643,10 +643,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
   // create shortcuts
   NR_DL_FRAME_PARMS *const fp            = &ue->frame_parms;
   NR_UE_COMMON *const common_vars        = &ue->common_vars;
-  NR_UE_PDSCH **const pdsch_vars_SI      = ue->pdsch_vars_SI;
-  NR_UE_PDSCH **const pdsch_vars_ra      = ue->pdsch_vars_ra;
-  NR_UE_PDSCH **const pdsch_vars_p       = ue->pdsch_vars_p;
-  NR_UE_PDSCH **const pdsch_vars_mch     = ue->pdsch_vars_MCH;
   NR_UE_PBCH  **const pbch_vars          = ue->pbch_vars;
   NR_UE_PRACH **const prach_vars         = ue->prach_vars;
   int i,j,k,l,slot,symb,q;
@@ -799,10 +795,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
       ue->pdcch_vars[th_id][eNB_id] = (NR_UE_PDCCH *)malloc16_clear(sizeof(NR_UE_PDCCH));
     }
 
-    pdsch_vars_SI[eNB_id]  = (NR_UE_PDSCH *)malloc16_clear(sizeof(NR_UE_PDSCH));
-    pdsch_vars_ra[eNB_id]  = (NR_UE_PDSCH *)malloc16_clear(sizeof(NR_UE_PDSCH));
-    pdsch_vars_p[eNB_id]   = (NR_UE_PDSCH *)malloc16_clear(sizeof(NR_UE_PDSCH));
-    pdsch_vars_mch[eNB_id] = (NR_UE_PDSCH *)malloc16_clear(sizeof(NR_UE_PDSCH));
     prach_vars[eNB_id]     = (NR_UE_PRACH *)malloc16_clear(sizeof(NR_UE_PRACH));
     pbch_vars[eNB_id]      = (NR_UE_PBCH *)malloc16_clear(sizeof(NR_UE_PBCH));
 
@@ -864,11 +856,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
         }
       }
 
-      phy_init_nr_ue__PDSCH( pdsch_vars_SI[eNB_id], fp );
-      phy_init_nr_ue__PDSCH( pdsch_vars_ra[eNB_id], fp );
-      phy_init_nr_ue__PDSCH( pdsch_vars_p[eNB_id], fp );
-      phy_init_nr_ue__PDSCH( pdsch_vars_mch[eNB_id], fp );
-
       // 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE
       for (th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
         ue->pdcch_vars[th_id][eNB_id]->llr   = (int16_t *)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
@@ -932,10 +919,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
     ue->pdsch_vars[th_id][eNB_id]     = (NR_UE_PDSCH *)malloc16_clear( sizeof(NR_UE_PDSCH) );
   }
 
-  pdsch_vars_SI[eNB_id]  = (NR_UE_PDSCH *)malloc16_clear( sizeof(NR_UE_PDSCH) );
-  pdsch_vars_ra[eNB_id]  = (NR_UE_PDSCH *)malloc16_clear( sizeof(NR_UE_PDSCH) );
-  pdsch_vars_p[eNB_id]   = (NR_UE_PDSCH *)malloc16_clear( sizeof(NR_UE_PDSCH) );
-
   if (abstraction_flag == 0) {
     for (th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
       //phy_init_lte_ue__PDSCH( ue->pdsch_vars[th_id][eNB_id], fp );
diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c
index 764b02065f70de8421e65cb1609a114a68ba59d5..652421f77c031295780169d8525493dd653a26b4 100644
--- a/openair1/PHY/MODULATION/nr_modulation.c
+++ b/openair1/PHY/MODULATION/nr_modulation.c
@@ -500,3 +500,37 @@ void nr_dft(int32_t *z, int32_t *d, uint32_t Msc_PUSCH)
     z[i] = dft_out0[ip];
   }
 }
+
+
+void init_symbol_rotation(NR_DL_FRAME_PARMS *fp,uint64_t CarrierFreq) {
+
+  const int nsymb = fp->symbols_per_slot * fp->slots_per_frame/10;
+  const double Tc=(1/480e3/4096);
+  const double Nu=2048*64*.5;
+  const double f0= (double)CarrierFreq;
+  const double Ncp0=16*64 + (144*64*.5);
+  const double Ncp1=(144*64*.5);
+  double tl=0,poff,exp_re,exp_im;
+  double Ncp,Ncpm1=Ncp0;
+
+  poff = 2*M_PI*((Ncp0*Tc))*f0;
+  exp_re = cos(poff);
+  exp_im = sin(-poff);
+  fp->symbol_rotation[0]=(int16_t)floor(exp_re*32767);
+  fp->symbol_rotation[1]=(int16_t)floor(exp_im*32767);
+  LOG_I(PHY,"Doing symbol rotation calculation for gNB TX/RX, f0 %f Hz, Nsymb %d\n",f0,nsymb);
+  LOG_I(PHY,"Symbol rotation %d/%d => (%d,%d)\n",0,nsymb,fp->symbol_rotation[0],fp->symbol_rotation[1]);
+  for (int l=1;l<nsymb;l++) {
+    if (l==(7*(1<<fp->numerology_index))) Ncp=Ncp0;
+    else Ncp=Ncp1;
+    tl += (Nu+Ncpm1)*Tc;					     
+    poff = 2*M_PI*(tl + (Ncp*Tc))*f0;
+    exp_re = cos(poff);
+    exp_im = sin(-poff);
+    fp->symbol_rotation[l<<1]=(int16_t)floor(exp_re*32767);
+    fp->symbol_rotation[1+(l<<1)]=(int16_t)floor(exp_im*32767);
+    LOG_I(PHY,"Symbol rotation %d/%d => tl %f (%d,%d) (%f)\n",l,nsymb,tl,fp->symbol_rotation[l<<1],fp->symbol_rotation[1+(l<<1)],
+	  (poff/2/M_PI)-floor(poff/2/M_PI));
+    Ncpm1=Ncp;
+  }
+}
diff --git a/openair1/PHY/MODULATION/nr_modulation.h b/openair1/PHY/MODULATION/nr_modulation.h
index 706b4dc113bbb23b9a7390c820614ee72034cf6c..31d8754768591e4f9eb90afc070dd345607d7d5d 100644
--- a/openair1/PHY/MODULATION/nr_modulation.h
+++ b/openair1/PHY/MODULATION/nr_modulation.h
@@ -103,4 +103,13 @@ int nr_beam_precoding(int32_t **txdataF,
                       int nb_antenna_ports
 );
 
+void apply_nr_rotation(NR_DL_FRAME_PARMS *fp,
+		       int16_t* txdata,
+		       int slot,
+		       int first_symbol,
+		       int nsymb,
+		       int length);
+
+void init_symbol_rotation(NR_DL_FRAME_PARMS *fp,uint64_t CarrierFreq);
+
 #endif
diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c
index e1d21af9b9fb14de87f2cb1f1d6bbec055af400e..92aea419af0064e43a0083b208c1183c7008a4fc 100644
--- a/openair1/PHY/MODULATION/ofdm_mod.c
+++ b/openair1/PHY/MODULATION/ofdm_mod.c
@@ -27,6 +27,7 @@
 This section deals with basic functions for OFDM Modulation.
 
 
+
 */
 
 #include "PHY/defs_eNB.h"
@@ -47,6 +48,7 @@ void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRA
   PHY_ofdm_mod(txdataF,        // input
 	       txdata,         // output
 	       frame_parms->ofdm_symbol_size,                
+
 	       1,                 // number of symbols
 	       frame_parms->nb_prefix_samples0,               // number of prefix samples
 	       CYCLIC_PREFIX);
@@ -191,7 +193,7 @@ void PHY_ofdm_mod(int *input,                       /// pointer to complex input
         /*for (j=0; j<fftsize ; j++) {
           output_ptr[j] = temp_ptr[j];
         }*/
-        memcpy((void*)output_ptr,(void*)temp_ptr,fftsize<<2);
+        memcpy1((void*)output_ptr,(void*)temp_ptr,fftsize<<2);
       }
 
       j=fftsize;
@@ -306,60 +308,23 @@ void do_OFDM_mod(int32_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t ne
 
 }
 
-/*
-// OFDM modulation for each symbol
-void do_OFDM_mod_symbol(LTE_eNB_COMMON *eNB_common_vars, RU_COMMON *common, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms,int do_precoding)
-{
-
-  int aa, l, slot_offset, slot_offsetF;
-  int32_t **txdataF    = eNB_common_vars->txdataF;
-  int32_t **txdataF_BF = common->txdataF_BF;
-  int32_t **txdata     = common->txdata;
-
-  slot_offset  = (next_slot)*(frame_parms->samples_per_tti>>1);
-  slot_offsetF = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==EXTENDED) ? 6 : 7);
-  //printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc());
-  for (l=0; l<frame_parms->symbols_per_tti>>1; l++) {
-  
-    for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
-
-      //printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES);
-      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,1);
-      if (do_precoding==1) beam_precoding(txdataF,txdataF_BF,frame_parms,eNB_common_vars->beam_weights,next_slot,l,aa);
-      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,0);
-
-      //PMCH case not implemented... 
-
-      if (frame_parms->Ncp == EXTENDED)
-        PHY_ofdm_mod((do_precoding == 1)?txdataF_BF[aa]:&txdataF[aa][slot_offsetF+l*frame_parms->ofdm_symbol_size],         // input
-                     &txdata[aa][slot_offset+l*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES],            // output
-                     frame_parms->ofdm_symbol_size,       
-                     1,                                   // number of symbols
-                     frame_parms->nb_prefix_samples,      // number of prefix samples
-                     CYCLIC_PREFIX);
-      else {
-        if (l==0) {
-          PHY_ofdm_mod((do_precoding==1)?txdataF_BF[aa]:&txdataF[aa][slot_offsetF+l*frame_parms->ofdm_symbol_size],        // input
-                       &txdata[aa][slot_offset],           // output
-                       frame_parms->ofdm_symbol_size,      
-                       1,                                  // number of symbols
-                       frame_parms->nb_prefix_samples0,    // number of prefix samples
-                       CYCLIC_PREFIX);
-           
-        } else {
-	  PHY_ofdm_mod((do_precoding==1)?txdataF_BF[aa]:&txdataF[aa][slot_offsetF+l*frame_parms->ofdm_symbol_size],        // input
-                       &txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES],           // output
-                       frame_parms->ofdm_symbol_size,      
-                       1,                                  // number of symbols
-                       frame_parms->nb_prefix_samples,     // number of prefix samples
-                       CYCLIC_PREFIX);
-
-          //printf("txdata[%d][%d]=%d\n",aa,slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES,txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES]);
- 
-        }
-      }
-    }
+void apply_nr_rotation(NR_DL_FRAME_PARMS *fp,
+		       int16_t* trxdata,
+		       int slot,
+		       int first_symbol,
+		       int nsymb,
+		       int length) {
+  int symb_offset = (slot%fp->slots_per_subframe)*fp->symbols_per_slot;
+
+  for (int sidx=0;sidx<nsymb;sidx++) {
+    LOG_D(PHY,"Rotating symbol %d, slot %d, symbol_subframe_index %d, length %d (%d,%d)\n",
+	  first_symbol+sidx,slot,sidx+first_symbol+symb_offset,length,
+	  fp->symbol_rotation[2*(sidx+first_symbol+symb_offset)],fp->symbol_rotation[1+2*(sidx+first_symbol+symb_offset)]);
+    rotate_cpx_vector(trxdata+(sidx*length*2),
+		      &fp->symbol_rotation[2*(sidx+first_symbol+symb_offset)],
+		      trxdata+(sidx*length*2),
+		      length,
+		      15);
   }
-
 }
-*/
+		       
diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c
index cf0a50a0186dc19601385b2f496f8d88c523cd7a..2ffdb013a50b92d05d062c6ed410caa65dcd7b60 100644
--- a/openair1/PHY/MODULATION/slot_fep_nr.c
+++ b/openair1/PHY/MODULATION/slot_fep_nr.c
@@ -133,8 +133,8 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
 
 #ifdef DEBUG_FEP
       //  if (ue->frame <100)
-    /*LOG_I(PHY,*/printf("slot_fep: frame %d: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, slot_offset %u, sample_offset %d,rx_offset %u, frame_length_samples %u\n",
-    		ue->proc.proc_rxtx[(Ns)&1].frame_rx, Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples);
+    /*LOG_I(PHY,*/printf("slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, slot_offset %u, sample_offset %d,rx_offset %u, frame_length_samples %u\n",
+			 Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples);
 #endif
 
     abs_symbol = Ns * frame_parms->symbols_per_slot + symbol;
@@ -198,12 +198,22 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
 
     }
 
-    #ifdef DEBUG_FEP
-        //  if (ue->frame <100)
-        printf("slot_fep: frame %d: symbol %d rx_offset %u\n", ue->proc.proc_rxtx[(Ns)&1].frame_rx, symbol, rx_offset);
-    #endif
+#ifdef DEBUG_FEP
+    //  if (ue->frame <100)
+    printf("slot_fep: symbol %d rx_offset %u\n", symbol, rx_offset);
+#endif
+    
+    int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot;
+    int32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation)[symbol+symb_offset];
+    ((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1];
+    rotate_cpx_vector((int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
+		      (int16_t*)&rot2,
+		      (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
+		      frame_parms->ofdm_symbol_size,
+		      15);
+    
   }
-
+  
 
 #ifdef DEBUG_FEP
   printf("slot_fep: done\n");
@@ -308,8 +318,8 @@ int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
 
 #ifdef DEBUG_FEP
       //  if (ue->frame <100)
-    /*LOG_I(PHY,*/printf("slot_fep: frame %d: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, slot_offset %u, sample_offset %d,rx_offset %u, frame_length_samples %u\n",
-    		ue->proc.proc_rxtx[(Ns)&1].frame_rx, Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples);
+    /*LOG_I(PHY,*/printf("slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, slot_offset %u, sample_offset %d,rx_offset %u, frame_length_samples %u\n",
+    		Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples);
 #endif
 
     abs_symbol = Ns * frame_parms->symbols_per_slot + symbol;
@@ -373,10 +383,22 @@ int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
 
     }
 
-    #ifdef DEBUG_FEP
-        //  if (ue->frame <100)
-        printf("slot_fep: frame %d: symbol %d rx_offset %u\n", ue->proc.proc_rxtx[(Ns)&1].frame_rx, symbol, rx_offset);
-    #endif
+    int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot;
+    int32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation)[symbol+symb_offset];
+    ((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1];
+
+#ifdef DEBUG_FEP
+    //  if (ue->frame <100)
+    printf("slot_fep: slot %d, symbol %d rx_offset %u, rotation symbol %d %d.%d\n", Ns,symbol, rx_offset,
+	   symbol+symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]);
+#endif
+
+    rotate_cpx_vector((int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
+		      (int16_t*)&rot2,
+		      (int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
+		      frame_parms->ofdm_symbol_size,
+		      15);
+    
   }
 
 
@@ -450,11 +472,11 @@ int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms,
     rxdata_offset = slot_offset + nb_prefix_samples0 + (symbol * (frame_parms->ofdm_symbol_size + nb_prefix_samples)) - SOFFSET;
 
   if(sample_offset>rxdata_offset) {
-    memcpy((void *)tmp_dft_in,
+    memcpy1((void *)tmp_dft_in,
            (void *) &rxdata[frame_parms->samples_per_frame-sample_offset+rxdata_offset],
            (sample_offset-rxdata_offset)*sizeof(int));
 
-    memcpy((void *)&tmp_dft_in[sample_offset-rxdata_offset],
+    memcpy1((void *)&tmp_dft_in[sample_offset-rxdata_offset],
            (void *) &rxdata[0],
            (frame_parms->ofdm_symbol_size-sample_offset+rxdata_offset)*sizeof(int));
 
@@ -468,5 +490,14 @@ int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms,
   // clear DC carrier from OFDM symbols
   rxdataF[symbol * frame_parms->ofdm_symbol_size] = 0;
 
+  int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot;
+  uint32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation)[symbol+symb_offset];
+  ((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1];
+  LOG_D(PHY,"slot %d, symb_offset %d rotating by %d.%d\n",Ns,symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]);
+  rotate_cpx_vector((int16_t *)&rxdataF[frame_parms->ofdm_symbol_size*symbol],
+		    (int16_t*)&rot2,
+		    (int16_t *)&rxdataF[frame_parms->ofdm_symbol_size*symbol],
+		    frame_parms->ofdm_symbol_size,
+		    15);
   return(0);
 }
diff --git a/openair1/PHY/NR_ESTIMATION/nr_adjust_sync_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c
similarity index 63%
rename from openair1/PHY/NR_ESTIMATION/nr_adjust_sync_gNB.c
rename to openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c
index 9c4d1fcc93b350a1e287bed978b04f4efeac4ba1..ec55eabf313378d49dc68a57d70c3e55e4dae520 100644
--- a/openair1/PHY/NR_ESTIMATION/nr_adjust_sync_gNB.c
+++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c
@@ -19,7 +19,7 @@
  *      contact@openairinterface.org
  */
 
-/*! \file PHY/NR_ESTIMATION/nr_adjust_sync_gNB.c
+/*! \file PHY/NR_ESTIMATION/nr_measurements_gNB.c
 * \brief TA estimation for TA updates
 * \author Ahmed Hussein
 * \date 2019
@@ -69,3 +69,37 @@ int nr_est_timing_advance_pusch(PHY_VARS_gNB* gNB, int UE_id)
   return max_pos - sync_pos;
 }
 
+
+void gNB_I0_measurements(PHY_VARS_gNB *gNB) {
+
+  NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
+  NR_gNB_COMMON *common_vars = &gNB->common_vars;
+  PHY_MEASUREMENTS_gNB *measurements = &gNB->measurements;
+  uint32_t *rb_mask = gNB->rb_mask_ul;
+  int symbol = gNB->ulmask_symb;
+  int rb, offset, nb_rb;
+  uint32_t n0_power_tot, n0_subband_power_temp=0;
+  int32_t *ul_ch;
+
+  if (symbol>-1) {
+    n0_power_tot = 0;
+    for (int aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
+      nb_rb = 0;
+      for (rb=0; rb<frame_parms->N_RB_UL; rb++) {
+        if ((rb_mask[rb>>5]&(1<<(rb&31))) == 0) {  // check that rb was not used in this subframe
+          nb_rb++;
+          offset = (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size;
+          offset += (symbol*frame_parms->ofdm_symbol_size);
+          ul_ch  = &common_vars->rxdataF[aarx][offset];
+          //TODO what about DC?
+          n0_subband_power_temp += signal_energy_nodc(ul_ch,12);
+        }
+      }
+      measurements->n0_power[aarx] = n0_subband_power_temp/nb_rb;
+      measurements->n0_power_dB[aarx] = dB_fixed(measurements->n0_power[aarx]);
+      n0_power_tot += measurements->n0_power[aarx];
+    }
+    measurements->n0_power_tot_dB = dB_fixed(n0_power_tot);
+  }
+}
+
diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
index 6eafad088d1cd5720ddf0aae2c69274c63bebb74..b6388fb903d50be7b0ecae827c47c42183dd6146 100644
--- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
+++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
@@ -32,10 +32,13 @@
 //#define DEBUG_CH
 //#define DEBUG_PUSCH
 
+#define dBc(x,y) (dB_fixed(((int32_t)(x))*(x) + ((int32_t)(y))*(y)))
+
 int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
                                 unsigned char Ns,
                                 unsigned short p,
                                 unsigned char symbol,
+                                int ul_id,
                                 unsigned short bwp_start_subcarrier,
                                 nfapi_nr_pusch_pdu_t *pusch_pdu) {
 
@@ -45,8 +48,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
   unsigned int pilot_cnt,re_cnt;
   int16_t ch[2],ch_r[2],ch_l[2],*pil,*rxF,*ul_ch;
   int16_t *fl,*fm,*fr,*fml,*fmr,*fmm,*fdcl,*fdcr,*fdclh,*fdcrh;
-  int ch_offset,symbol_offset, UE_id = 0;
-  int32_t **ul_ch_estimates_time =  gNB->pusch_vars[UE_id]->ul_ch_estimates_time;
+  int ch_offset,symbol_offset ;
+  int32_t **ul_ch_estimates_time =  gNB->pusch_vars[ul_id]->ul_ch_estimates_time;
   __m128i *ul_ch_128;
 
 #ifdef DEBUG_CH
@@ -57,7 +60,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
   //uint16_t Nid_cell = (eNB_offset == 0) ? gNB->frame_parms.Nid_cell : gNB->measurements.adj_cell_id[eNB_offset-1];
 
   uint8_t nushift;
-  int **ul_ch_estimates  = gNB->pusch_vars[UE_id]->ul_ch_estimates;
+  int **ul_ch_estimates  = gNB->pusch_vars[ul_id]->ul_ch_estimates;
   int **rxdataF = gNB->common_vars.rxdataF;
 
   nushift = (p>>1)&1;
@@ -124,7 +127,10 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
     nr_pusch_dmrs_rx(gNB, Ns, gNB->nr_gold_pusch_dmrs[pusch_pdu->scid][Ns][symbol], &pilot[0], 1000, 0, nb_rb_pusch, 0, pusch_pdu->dmrs_config_type);
 
   //------------------------------------------------//
-
+#ifdef DEBUG_PUSCH
+  for (int i=0;i<(6*nb_rb_pusch);i++)
+    printf("%d+j*(%d)\n",((int16_t*)pilot)[2*i],((int16_t*)pilot)[1+(2*i)]);
+#endif
   for (aarx=0; aarx<gNB->frame_parms.nb_antennas_rx; aarx++) {
 
     pil   = (int16_t *)&pilot[0];
@@ -136,7 +142,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
 #ifdef DEBUG_PUSCH
     printf("symbol_offset %d, nushift %d\n",symbol_offset,nushift);
     printf("ch est pilot addr %p RB_DL %d\n",&pilot[0], gNB->frame_parms.N_RB_UL);
-    printf("bwp_start_subcarrier %d, k %d, first_carrier %d\n",bwp_start_subcarrier,k,gNB->frame_parms.first_carrier_offset);
+    printf("bwp_start_subcarrier %d, k %d, first_carrier %d, nb_rb_pusch %d\n",bwp_start_subcarrier,k,gNB->frame_parms.first_carrier_offset,nb_rb_pusch);
     printf("rxF addr %p p %d\n", rxF,p);
     printf("ul_ch addr %p nushift %d\n",ul_ch,nushift);
 #endif
@@ -150,8 +156,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
 
 #ifdef DEBUG_PUSCH
       printf("ch 0 %d\n",((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1]));
-      printf("pilot 0 : rxF - > (%d,%d) addr %p  ch -> (%d,%d), pil -> (%d,%d) \n",rxF[0],rxF[1],&rxF[0],ch[0],ch[1],pil[0],pil[1]);
-      printf("data 0 : rxF - > (%d,%d)\n",rxF[2],rxF[3]);
+      printf("pilot 0 : rxF - > (%d,%d) (%d)  ch -> (%d,%d) (%d), pil -> (%d,%d) \n",rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]);
+      printf("data 0 : rxF - > (%d,%d) (%d)\n",rxF[2],rxF[3],dBc(rxF[2],rxF[3]));
 #endif
 
       multadd_real_vector_complex_scalar(fl,
@@ -168,8 +174,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
       ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15);
 
 #ifdef DEBUG_PUSCH
-      printf("pilot 1 : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]);
-      printf("data 1 : rxF - > (%d,%d)\n",rxF[2],rxF[3]);
+      printf("pilot 1 : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]);
+      printf("data 1 : rxF - > (%d,%d) (%d)\n",rxF[2],rxF[3],dBc(rxF[2],rxF[3]));
 #endif
       multadd_real_vector_complex_scalar(fml,
                                          ch,
@@ -184,8 +190,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
       ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15);
 
 #ifdef DEBUG_PUSCH
-      printf("pilot 2 : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]);
-      printf("data 2 : rxF - > (%d,%d)\n",rxF[2],rxF[3]);
+      printf("pilot 2 : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]);
+      printf("data 2 : rxF - > (%d,%d) (%d)\n",rxF[2],rxF[3],dBc(rxF[2],rxF[3]));
 #endif
       multadd_real_vector_complex_scalar(fmm,
                                          ch,
@@ -206,8 +212,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
         ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15);
 
   #ifdef DEBUG_PUSCH
-        printf("pilot %u : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]);
-	printf("data %u : rxF - > (%d,%d)\n",pilot_cnt,rxF[2],rxF[3]);
+        printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]);
+	printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt,rxF[2],rxF[3],dBc(rxF[2],rxF[3]));
   #endif
         multadd_real_vector_complex_scalar(fml,
                                            ch,
@@ -222,8 +228,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
         ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15);
 
   #ifdef DEBUG_PUSCH
-        printf("pilot %u : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt+1,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]);
-	printf("data %u : rxF - > (%d,%d)\n",pilot_cnt+1,rxF[2],rxF[3]);
+        printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt+1,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]);
+	printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt+1,rxF[2],rxF[3],dBc(rxF[2],rxF[3]));
   #endif
         multadd_real_vector_complex_scalar(fmm,
                                            ch,
@@ -244,8 +250,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
       ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15);
       ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15);
 #ifdef DEBUG_PUSCH
-      printf("pilot %u : rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]);
-      printf("data %u : rxF - > (%d,%d)\n",pilot_cnt,rxF[2],rxF[3]);
+      printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]);
+      printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt,rxF[2],rxF[3],dBc(rxF[2],rxF[3]));
 #endif
       multadd_real_vector_complex_scalar(fm,
                                          ch,
@@ -263,8 +269,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
       ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15);
 #ifdef DEBUG_PUSCH
       printf("ch 0 %d\n",((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1]));
-      printf("pilot %u: rxF - > (%d,%d) addr %p  ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt+1,rxF[0],rxF[1],&rxF[0],ch[0],ch[1],pil[0],pil[1]);
-      printf("data %u : rxF - > (%d,%d)\n",pilot_cnt+1,rxF[2],rxF[3]);
+      printf("pilot %u : rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt+1,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]);
+      printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt+1,rxF[2],rxF[3],dBc(rxF[2],rxF[3]));
 #endif
       multadd_real_vector_complex_scalar(fmr,
                                          ch,
@@ -279,8 +285,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
       ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15);
       ch[1] = (int16_t)(((int32_t)pil[0]*rxF[1] + (int32_t)pil[1]*rxF[0])>>15);
 #ifdef DEBUG_PUSCH
-      printf("pilot %u: rxF - > (%d,%d) ch -> (%d,%d), pil -> (%d,%d) \n",pilot_cnt+2,rxF[0],rxF[1],ch[0],ch[1],pil[0],pil[1]);
-      printf("data %u : rxF - > (%d,%d)\n",pilot_cnt+2,rxF[2],rxF[3]);
+      printf("pilot %u: rxF - > (%d,%d) (%d) ch -> (%d,%d) (%d), pil -> (%d,%d) \n",pilot_cnt+2,rxF[0],rxF[1],dBc(rxF[0],rxF[1]),ch[0],ch[1],dBc(ch[0],ch[1]),pil[0],pil[1]);
+      printf("data %u : rxF - > (%d,%d) (%d)\n",pilot_cnt+2,rxF[2],rxF[3],dBc(rxF[2],rxF[3]));
 #endif
       multadd_real_vector_complex_scalar(fr,
                                          ch,
@@ -340,7 +346,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
                                              8);
         }
       }
-#ifdef DEBUG_PDSCH
+#ifdef DEBUG_PUSCH
       ul_ch = (int16_t *)&ul_ch_estimates[aarx][ch_offset];
       for(uint16_t idxP=0; idxP<ceil((float)nb_rb_pusch*12/8); idxP++) {
         for(uint8_t idxI=0; idxI<16; idxI+=2) {
diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h
index 33ce319d8011230fc53c55c0c5f585fd8adf6244..0f71487e36366b740f3ee49a25ff2ec58dea2d89 100644
--- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h
+++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h
@@ -43,9 +43,12 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
                                 unsigned char Ns,
                                 unsigned short p,
                                 unsigned char symbol,
+                                int ul_id,
                                 unsigned short bwp_start_subcarrier,
                                 nfapi_nr_pusch_pdu_t *pusch_pdu);
 
+void gNB_I0_measurements(PHY_VARS_gNB *gNB);
+
 int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id);
 
 
diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h
index de0befd7dff8ef2bd2f92152c7de34a7dafb4e29..ced7f9eb667b69d14ef8ec532bc24bc5bba0fed9 100644
--- a/openair1/PHY/NR_REFSIG/nr_refsig.h
+++ b/openair1/PHY/NR_REFSIG/nr_refsig.h
@@ -60,5 +60,6 @@ void nr_generate_modulation_table(void);
 
 extern __m64 byte2m64_re[256];
 extern __m64 byte2m64_im[256];
+extern __m128i byte2m128i[256];
 
 #endif
diff --git a/openair1/PHY/NR_REFSIG/scrambling_luts.c b/openair1/PHY/NR_REFSIG/scrambling_luts.c
index 790d3f771966262ebc8f08287a5ed2cefd427038..3509291e42d918443f0f5e4934ec72e06b2e5346 100644
--- a/openair1/PHY/NR_REFSIG/scrambling_luts.c
+++ b/openair1/PHY/NR_REFSIG/scrambling_luts.c
@@ -32,6 +32,8 @@
 __m64 byte2m64_re[256];
 __m64 byte2m64_im[256];
 
+__m128i byte2m128i[256];
+
 void init_byte2m64(void) {
 
   for (int s=0;s<256;s++) {
@@ -54,10 +56,24 @@ void init_byte2m64(void) {
   }
 }
 
+void init_byte2m128i(void) {
+
+  for (int s=0;s<256;s++) {
+    byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*(s&1)),0);
+    byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>1)&1)),1);
+    byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>2)&1)),2);
+    byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>3)&1)),3);
+    byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>4)&1)),4);
+    byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>5)&1)),5);
+    byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>6)&1)),6);
+    byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>7)&1)),7);
+  }
+}
+
 void init_scrambling_luts(void) {
 
   init_byte2m64();
-
+  init_byte2m128i();
 }
 
 #endif
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c
index 3a44ebc49a0c589ef13d1c45b3ea95c7b6bca970..ebcf4116d2a0d071af97c08f1f96779434409221 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dci.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c
@@ -154,8 +154,10 @@ void nr_pdcch_scrambling(uint32_t *in,
 }
 
 
-uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
-			    nfapi_nr_ul_dci_request_pdus_t *ul_dci_pdu,
+
+uint8_t nr_generate_dci_top(PHY_VARS_gNB *gNB,
+			    nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
+			    nfapi_nr_dl_tti_pdcch_pdu *ul_dci_pdu,
                             uint32_t **gold_pdcch_dmrs,
                             int32_t *txdataF,
                             int16_t amp,
@@ -180,15 +182,17 @@ uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
 
 
   if (pdcch_pdu) pdcch_pdu_rel15 = &pdcch_pdu->pdcch_pdu_rel15;
-  else if (ul_dci_pdu) pdcch_pdu_rel15 = &ul_dci_pdu->pdcch_pdu.pdcch_pdu_rel15;
+  else if (ul_dci_pdu) pdcch_pdu_rel15 = &ul_dci_pdu->pdcch_pdu_rel15;
+
+  nr_fill_cce_list(gNB,0,pdcch_pdu_rel15);
 
   get_coreset_rballoc(pdcch_pdu_rel15->FreqDomainResource,&n_rb,&rb_offset);
 
   // compute rb_offset and n_prb based on frequency allocation
 
   if (pdcch_pdu_rel15->CoreSetType == NFAPI_NR_CSET_CONFIG_MIB_SIB1) {
-    cset_start_sc = frame_parms.first_carrier_offset + (frame_parms.ssb_start_subcarrier/NR_NB_SC_PER_RB +
-							rb_offset)*NR_NB_SC_PER_RB;
+    cset_start_sc = frame_parms.first_carrier_offset + 
+      (frame_parms.ssb_start_subcarrier/NR_NB_SC_PER_RB + rb_offset)*NR_NB_SC_PER_RB;
   } else
     cset_start_sc = frame_parms.first_carrier_offset + rb_offset*NR_NB_SC_PER_RB;
 
@@ -324,6 +328,7 @@ uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
 	  k -= frame_parms.ofdm_symbol_size;
       } // m
     } // reg_idx
+    
   } // for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++)
   return 0;
 }
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.h b/openair1/PHY/NR_TRANSPORT/nr_dci.h
index 047139aa63376756d93d560c50da28120d379898..288f52521967b33acb1342b7e0570587aadee804 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dci.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_dci.h
@@ -29,9 +29,10 @@ uint16_t nr_get_dci_size(nfapi_nr_dci_format_e format,
                          nfapi_nr_rnti_type_e rnti_type,
                          uint16_t N_RB);
 
-uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
-			    nfapi_nr_ul_dci_request_pdus_t *ul_dci_pdu,
-                            uint32_t **gold_pdcch_dmrs,
+uint8_t nr_generate_dci_top(PHY_VARS_gNB *gNB,
+			    nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
+			    nfapi_nr_dl_tti_pdcch_pdu *ul_pdcch_pdu,
+			    uint32_t **gold_pdcch_dmrs,
                             int32_t *txdataF,
                             int16_t amp,
                             NR_DL_FRAME_PARMS frame_parms);
@@ -42,15 +43,21 @@ void nr_pdcch_scrambling(uint32_t *in,
                          uint32_t n_RNTI,
                          uint32_t *out);
 
+int16_t find_nr_pdcch(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type);
+
 void nr_fill_dci(PHY_VARS_gNB *gNB,
                  int frame,
-                 int slot);
+                 int slot,
+		 nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu);
+
+int16_t find_nr_ul_dci(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type);
 
 void nr_fill_ul_dci(PHY_VARS_gNB *gNB,
 		    int frame,
-		    int slot);
+		    int slot,
+		    nfapi_nr_ul_dci_request_pdus_t *pdcch_pdu);
 
-void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m);
+void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m,nfapi_nr_dl_tti_pdcch_pdu_rel15_t *);
 
 void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset);
 
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c
index 02ecfc44044fa5bb09a58f6bc2edff4fea11419f..2b64a3062cc6f449ad126c5a80cf91e7c2f3bbaf 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c
@@ -118,11 +118,11 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint16_t n_shift, uint8_t m) {
 
 */
 
-void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m) {
+void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m,  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15) {
 
   nr_cce_t* cce;
   nr_reg_t* reg;
-  nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu_rel15 = &gNB->pdcch_pdu->pdcch_pdu_rel15;
+
   int bsize = pdcch_pdu_rel15->RegBundleSize;
   int R = pdcch_pdu_rel15->InterleaverSize;
   int n_shift = pdcch_pdu_rel15->ShiftIndex;
@@ -139,6 +139,8 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m) {
   int N_reg = n_rb * pdcch_pdu_rel15->DurationSymbols;
   int C=-1;
 
+  AssertFatal(N_reg > 0,"N_reg cannot be 0\n");
+
   for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++) {
     int  L = pdcch_pdu_rel15->dci_pdu.AggregationLevel[d];
 
@@ -200,14 +202,38 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m) {
     ret |= ((field>>i)&1)<<(size-i-1);
   return ret;
 }*/
+int16_t find_nr_pdcch(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type) {
+
+  uint16_t i;
+  int16_t first_free_index=-1;
+
+  AssertFatal(gNB!=NULL,"gNB is null\n");
+  for (i=0; i<NUMBER_OF_NR_PDCCH_MAX; i++) {
+    LOG_D(PHY,"searching for frame.slot %d.%d : pdcch_index %d frame.slot %d.%d, first_free_index %d\n", frame,slot,i,gNB->pdcch_pdu[i].frame,gNB->pdcch_pdu[i].slot,first_free_index);
+    if ((gNB->pdcch_pdu[i].frame == frame) &&
+        (gNB->pdcch_pdu[i].slot==slot))       return i;
+    else if ( gNB->pdcch_pdu[i].frame==-1 && first_free_index==-1) first_free_index=i;
+  }
+  if (type == SEARCH_EXIST) return -1;
+
+  return first_free_index;
+}
+
 
 void nr_fill_dci(PHY_VARS_gNB *gNB,
                  int frame,
-                 int slot) {
+                 int slot,
+		 nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu) {
 
-  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &gNB->pdcch_pdu->pdcch_pdu_rel15;
+  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &pdcch_pdu->pdcch_pdu_rel15;
   NR_gNB_DLSCH_t *dlsch; 
 
+  int pdcch_id = find_nr_pdcch(frame,slot,gNB,SEARCH_EXIST_OR_FREE);
+  AssertFatal(pdcch_id>=0 && pdcch_id<NUMBER_OF_NR_PDCCH_MAX,"Cannot find space for PDCCH, exiting\n");
+  memcpy((void*)&gNB->pdcch_pdu[pdcch_id].pdcch_pdu,(void*)pdcch_pdu,sizeof(*pdcch_pdu));
+  gNB->pdcch_pdu[pdcch_id].frame = frame;
+  gNB->pdcch_pdu[pdcch_id].slot  = slot;
+
   for (int i=0;i<pdcch_pdu_rel15->numDlDci;i++) {
 
     //uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu.Payload[i];
@@ -230,7 +256,7 @@ void nr_fill_dci(PHY_VARS_gNB *gNB,
     dlsch->harq_mask                |= (1<<harq_pid);
     dlsch->rnti                      = pdcch_pdu_rel15->dci_pdu.RNTI[i];
     
-    nr_fill_cce_list(gNB,0);  
+    //    nr_fill_cce_list(gNB,0);  
     /*
     LOG_D(PHY, "DCI PDU: [0]->0x%lx \t [1]->0x%lx \n",dci_pdu[0], dci_pdu[1]);
     LOG_D(PHY, "DCI type %d payload (size %d) generated on candidate %d\n", dci_alloc->pdcch_params.dci_format, dci_alloc->size, cand_idx);
@@ -239,19 +265,45 @@ void nr_fill_dci(PHY_VARS_gNB *gNB,
   }
 
 }
+
+
+int16_t find_nr_ul_dci(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type) {
+
+  uint16_t i;
+  int16_t first_free_index=-1;
+
+  AssertFatal(gNB!=NULL,"gNB is null\n");
+  for (i=0; i<NUMBER_OF_NR_PDCCH_MAX; i++) {
+    LOG_D(PHY,"searching for frame.slot %d.%d : ul_pdcch_index %d frame.slot %d.%d, first_free_index %d\n", frame,slot,i,gNB->ul_pdcch_pdu[i].frame,gNB->ul_pdcch_pdu[i].slot,first_free_index);
+    if ((gNB->ul_pdcch_pdu[i].frame == frame) &&
+        (gNB->ul_pdcch_pdu[i].slot==slot))       return i;
+    else if (gNB->ul_pdcch_pdu[i].frame==-1 && first_free_index==-1) first_free_index=i;
+  }
+  if (type == SEARCH_EXIST) return -1;
+
+  return first_free_index;
+}
+
+
 void nr_fill_ul_dci(PHY_VARS_gNB *gNB,
 		    int frame,
-		    int slot) {
+		    int slot,
+		    nfapi_nr_ul_dci_request_pdus_t *pdcch_pdu) {
 
-  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &gNB->ul_dci_pdu->pdcch_pdu.pdcch_pdu_rel15;
+  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15;
 
+  int pdcch_id = find_nr_ul_dci(frame,slot,gNB,SEARCH_EXIST_OR_FREE);
+  AssertFatal(pdcch_id>=0 && pdcch_id<NUMBER_OF_NR_PDCCH_MAX,"Cannot find space for UL PDCCH, exiting\n");
+  memcpy((void*)&gNB->ul_pdcch_pdu[pdcch_id].pdcch_pdu,(void*)pdcch_pdu,sizeof(*pdcch_pdu));
+  gNB->ul_pdcch_pdu[pdcch_id].frame = frame;
+  gNB->ul_pdcch_pdu[pdcch_id].slot  = slot;
 
   for (int i=0;i<pdcch_pdu_rel15->numDlDci;i++) {
 
     //uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu.Payload[i];
 
     // if there's no DL DCI then generate CCE list
-    if (gNB->pdcch_pdu) nr_fill_cce_list(gNB,0);  
+    //    nr_fill_cce_list(gNB,0);  
     /*
     LOG_D(PHY, "DCI PDU: [0]->0x%lx \t [1]->0x%lx \n",dci_pdu[0], dci_pdu[1]);
     LOG_D(PHY, "DCI type %d payload (size %d) generated on candidate %d\n", dci_alloc->pdcch_params.dci_format, dci_alloc->size, cand_idx);
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c
index 2849986833b2311bbc7ffe7d21e45dc145597120..4461edb33ba88c0aa9cba3af019b6ff890c5ca21 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c
@@ -109,220 +109,255 @@ void nr_pdsch_codeword_scrambling_optim(uint8_t *in,
 }
 
 
-uint8_t nr_generate_pdsch(NR_gNB_DLSCH_t *dlsch,
-                          uint32_t ***pdsch_dmrs,
-                          int32_t** txdataF,
-                          int16_t amp,
-                          int     frame,
-                          uint8_t slot,
-                          NR_DL_FRAME_PARMS *frame_parms,
-			  int xOverhead,
-                          time_stats_t *dlsch_encoding_stats,
-                          time_stats_t *dlsch_scrambling_stats,
-                          time_stats_t *dlsch_modulation_stats,
-			  time_stats_t *tinput,
-			  time_stats_t *tprep,
-			  time_stats_t *tparity,
-			  time_stats_t *toutput,
-			  time_stats_t *dlsch_rate_matching_stats,
-			  time_stats_t *dlsch_interleaving_stats,
-			  time_stats_t *dlsch_segmentation_stats) {
-
-  int harq_pid = dlsch->harq_ids[frame%2][slot];
-  NR_DL_gNB_HARQ_t *harq = dlsch->harq_processes[harq_pid];
-  nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
-  uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5];
-  int16_t **mod_symbs = (int16_t**)dlsch->mod_symbs;
-  int16_t **tx_layers = (int16_t**)dlsch->txdataF;
-  int8_t Wf[2], Wt[2], l0, l_prime[2], delta;
-  uint8_t dmrs_Type = rel15->dmrsConfigType;
-  int nb_re_dmrs;
-  uint16_t n_dmrs;
-  if (rel15->dmrsConfigType==NFAPI_NR_DMRS_TYPE1) {
-    nb_re_dmrs = 6*rel15->numDmrsCdmGrpsNoData;
-    n_dmrs = ((rel15->rbSize+rel15->rbStart)*6)<<1;
-  }
-  else {
-    nb_re_dmrs = 4*rel15->numDmrsCdmGrpsNoData;
-    n_dmrs = ((rel15->rbSize+rel15->rbStart)*4)<<1;
-  }
-  uint16_t nb_re;
-  nb_re = ((12*rel15->NrOfSymbols)-nb_re_dmrs-xOverhead)*rel15->rbSize*rel15->NrOfCodewords;
-  uint8_t Qm = rel15->qamModOrder[0];
-  uint32_t encoded_length = nb_re*Qm;
-  int16_t mod_dmrs[n_dmrs<<1] __attribute__ ((aligned(16)));
-
-  /// CRC, coding, interleaving and rate matching
-  AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n");
-  start_meas(dlsch_encoding_stats);
-  nr_dlsch_encoding(harq->pdu, frame, slot, dlsch, frame_parms,tinput,tprep,tparity,toutput,
-		    dlsch_rate_matching_stats,
-		    dlsch_interleaving_stats,
-		    dlsch_segmentation_stats);
-  stop_meas(dlsch_encoding_stats);
-#ifdef DEBUG_DLSCH
-  printf("PDSCH encoding:\nPayload:\n");
-  for (int i=0; i<harq->B>>7; i++) {
-    for (int j=0; j<16; j++)
-      printf("0x%02x\t", harq->pdu[(i<<4)+j]);
-    printf("\n");
-  }
-  printf("\nEncoded payload:\n");
-  for (int i=0; i<encoded_length>>3; i++) {
-    for (int j=0; j<8; j++)
-      printf("%d", harq->f[(i<<3)+j]);
-    printf("\t");
-  }
-  printf("\n");
-#endif
+uint8_t nr_generate_pdsch(PHY_VARS_gNB *gNB,
+			  int frame,
+			  int slot) {
 
+  NR_gNB_DLSCH_t *dlsch;
+  uint32_t ***pdsch_dmrs = gNB->nr_gold_pdsch_dmrs[slot];
+  int32_t** txdataF = gNB->common_vars.txdataF;
+  int16_t amp = AMP;
+  NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
+  int xOverhead = 0;
+  time_stats_t *dlsch_encoding_stats=&gNB->dlsch_encoding_stats;
+  time_stats_t *dlsch_scrambling_stats=&gNB->dlsch_scrambling_stats;
+  time_stats_t *dlsch_modulation_stats=&gNB->dlsch_modulation_stats;
+  time_stats_t *tinput=&gNB->tinput;
+  time_stats_t *tprep=&gNB->tprep;
+  time_stats_t *tparity=&gNB->tparity;
+  time_stats_t *toutput=&gNB->toutput;
+  time_stats_t *dlsch_rate_matching_stats=&gNB->dlsch_rate_matching_stats;
+  time_stats_t *dlsch_interleaving_stats=&gNB->dlsch_interleaving_stats;
+  time_stats_t *dlsch_segmentation_stats=&gNB->dlsch_segmentation_stats;
 
+  for (int dlsch_id=0;dlsch_id<NUMBER_OF_NR_DLSCH_MAX;dlsch_id++) {
+    dlsch = gNB->dlsch[dlsch_id][0];
+    if (dlsch->slot_tx[slot] == 0) continue;
 
-  /// scrambling
-  start_meas(dlsch_scrambling_stats);
-  for (int q=0; q<rel15->NrOfCodewords; q++)
-    memset((void*)scrambled_output[q], 0, (encoded_length>>5)*sizeof(uint32_t));
-  for (int q=0; q<rel15->NrOfCodewords; q++)
-    nr_pdsch_codeword_scrambling_optim(harq->f,
-				       encoded_length,
-				       q,
-				       rel15->dlDmrsScramblingId,
-				       rel15->rnti,
-				       scrambled_output[q]);
-  
-  stop_meas(dlsch_scrambling_stats);
+    int harq_pid = dlsch->harq_ids[frame%2][slot];
+    NR_DL_gNB_HARQ_t *harq = dlsch->harq_processes[harq_pid];
+    nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
+    uint32_t scrambled_output[NR_MAX_NB_CODEWORDS][NR_MAX_PDSCH_ENCODED_LENGTH>>5];
+    int16_t **mod_symbs = (int16_t**)dlsch->mod_symbs;
+    int16_t **tx_layers = (int16_t**)dlsch->txdataF;
+    int8_t Wf[2], Wt[2], l0, l_prime[2], delta;
+    uint8_t dmrs_Type = rel15->dmrsConfigType;
+    int nb_re_dmrs;
+    uint16_t n_dmrs;
+    if (rel15->dmrsConfigType==NFAPI_NR_DMRS_TYPE1) {
+      nb_re_dmrs = 6*rel15->numDmrsCdmGrpsNoData;
+      n_dmrs = ((rel15->rbSize+rel15->rbStart)*6)<<1;
+    }
+    else {
+      nb_re_dmrs = 4*rel15->numDmrsCdmGrpsNoData;
+      n_dmrs = ((rel15->rbSize+rel15->rbStart)*4)<<1;
+    }
+    uint16_t nb_re;
+    nb_re = ((12*rel15->NrOfSymbols)-nb_re_dmrs-xOverhead)*rel15->rbSize*rel15->NrOfCodewords;
+    uint8_t Qm = rel15->qamModOrder[0];
+    uint32_t encoded_length = nb_re*Qm;
+    int16_t mod_dmrs[n_dmrs<<1] __attribute__ ((aligned(16)));
+    
+    
+    /// CRC, coding, interleaving and rate matching
+    AssertFatal(harq->pdu!=NULL,"harq->pdu is null\n");
+    start_meas(dlsch_encoding_stats);
+    nr_dlsch_encoding(gNB,
+		      harq->pdu, frame, slot, dlsch, frame_parms,tinput,tprep,tparity,toutput,
+		      dlsch_rate_matching_stats,
+		      dlsch_interleaving_stats,
+		      dlsch_segmentation_stats);
+    stop_meas(dlsch_encoding_stats);
 #ifdef DEBUG_DLSCH
-  printf("PDSCH scrambling:\n");
-  for (int i=0; i<encoded_length>>8; i++) {
-    for (int j=0; j<8; j++)
-      printf("0x%08x\t", scrambled_output[0][(i<<3)+j]);
+    printf("PDSCH encoding:\nPayload:\n");
+    for (int i=0; i<harq->B>>7; i++) {
+      for (int j=0; j<16; j++)
+	printf("0x%02x\t", harq->pdu[(i<<4)+j]);
+      printf("\n");
+    }
+    printf("\nEncoded payload:\n");
+    for (int i=0; i<encoded_length>>3; i++) {
+      for (int j=0; j<8; j++)
+	printf("%d", harq->f[(i<<3)+j]);
+      printf("\t");
+    }
     printf("\n");
-  }
 #endif
- 
-  /// Modulation
-  start_meas(dlsch_modulation_stats);
-  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 1);
-  for (int q=0; q<rel15->NrOfCodewords; q++)
-    nr_modulation(scrambled_output[q],
-                         encoded_length,
-                         Qm,
-                         mod_symbs[q]);
-  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 0);
-  stop_meas(dlsch_modulation_stats);
+    
+    
+    
+    /// scrambling
+    start_meas(dlsch_scrambling_stats);
+    for (int q=0; q<rel15->NrOfCodewords; q++)
+      memset((void*)scrambled_output[q], 0, (encoded_length>>5)*sizeof(uint32_t));
+    for (int q=0; q<rel15->NrOfCodewords; q++)
+      nr_pdsch_codeword_scrambling_optim(harq->f,
+					 encoded_length,
+					 q,
+					 rel15->dlDmrsScramblingId,
+					 rel15->rnti,
+					 scrambled_output[q]);
+    
+    stop_meas(dlsch_scrambling_stats);
 #ifdef DEBUG_DLSCH
-  printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_re);
-  for (int i=0; i<nb_re>>3; i++) {
-    for (int j=0; j<8; j++) {
-      printf("%d %d\t", mod_symbs[0][((i<<3)+j)<<1], mod_symbs[0][(((i<<3)+j)<<1)+1]);
+    printf("PDSCH scrambling:\n");
+    for (int i=0; i<encoded_length>>8; i++) {
+      for (int j=0; j<8; j++)
+	printf("0x%08x\t", scrambled_output[0][(i<<3)+j]);
+      printf("\n");
     }
-    printf("\n");
-  }
 #endif
-
-
-  /// Layer mapping
-  nr_layer_mapping(mod_symbs,
-		   rel15->nrOfLayers,
-		   nb_re,
-		   tx_layers);
+    
+    /// Modulation
+    start_meas(dlsch_modulation_stats);
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 1);
+    for (int q=0; q<rel15->NrOfCodewords; q++)
+      nr_modulation(scrambled_output[q],
+		    encoded_length,
+		    Qm,
+		    mod_symbs[q]);
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PDSCH_MODULATION, 0);
+    stop_meas(dlsch_modulation_stats);
 #ifdef DEBUG_DLSCH
-  printf("Layer mapping (%d layers):\n", rel15->nrOfLayers);
-  for (int l=0; l<rel15->nrOfLayers; l++)
-    for (int i=0; i<(nb_re/rel15->nrOfLayers)>>3; i++) {
-      printf("layer %d, Re %d..%d : ",l,i<<3,(i<<3)+7);
+    printf("PDSCH Modulation: Qm %d(%d)\n", Qm, nb_re);
+    for (int i=0; i<nb_re>>3; i++) {
       for (int j=0; j<8; j++) {
-	printf("l%d %d\t", tx_layers[l][((i<<3)+j)<<1], tx_layers[l][(((i<<3)+j)<<1)+1]);
+	printf("%d %d\t", mod_symbs[0][((i<<3)+j)<<1], mod_symbs[0][(((i<<3)+j)<<1)+1]);
       }
       printf("\n");
     }
 #endif
-
-  /// Antenna port mapping
-  //to be moved to init phase potentially, for now tx_layers 1-8 are mapped on antenna ports 1000-1007
-  
-  /// DMRS QPSK modulation
-  
-  
-  l0 = get_l0(rel15->dlDmrsSymbPos);
-  nr_modulation(pdsch_dmrs[l0][0], n_dmrs, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated
-  
+    
+    
+    /// Layer mapping
+    nr_layer_mapping(mod_symbs,
+		     rel15->nrOfLayers,
+		     nb_re,
+		     tx_layers);
+#ifdef DEBUG_DLSCH
+    printf("Layer mapping (%d layers):\n", rel15->nrOfLayers);
+    for (int l=0; l<rel15->nrOfLayers; l++)
+      for (int i=0; i<(nb_re/rel15->nrOfLayers)>>3; i++) {
+	printf("layer %d, Re %d..%d : ",l,i<<3,(i<<3)+7);
+	for (int j=0; j<8; j++) {
+	  printf("l%d %d\t", tx_layers[l][((i<<3)+j)<<1], tx_layers[l][(((i<<3)+j)<<1)+1]);
+	}
+	printf("\n");
+      }
+#endif
+    
+    /// Antenna port mapping
+    //to be moved to init phase potentially, for now tx_layers 1-8 are mapped on antenna ports 1000-1007
+    
+    /// DMRS QPSK modulation
+    
+    
+    l0 = get_l0(rel15->dlDmrsSymbPos);
+    nr_modulation(pdsch_dmrs[l0][0], n_dmrs, DMRS_MOD_ORDER, mod_dmrs); // currently only codeword 0 is modulated. Qm = 2 as DMRS is QPSK modulated
+    
 #ifdef DEBUG_DLSCH
-  printf("DMRS modulation (single symbol %d, %d symbols, type %d):\n", l0, n_dmrs>>1, dmrs_Type);
-  for (int i=0; i<n_dmrs>>4; i++) {
-    for (int j=0; j<8; j++) {
-      printf("%d %d\t", mod_dmrs[((i<<3)+j)<<1], mod_dmrs[(((i<<3)+j)<<1)+1]);
+    printf("DMRS modulation (single symbol %d, %d symbols, type %d):\n", l0, n_dmrs>>1, dmrs_Type);
+    for (int i=0; i<n_dmrs>>4; i++) {
+      for (int j=0; j<8; j++) {
+	printf("%d %d\t", mod_dmrs[((i<<3)+j)<<1], mod_dmrs[(((i<<3)+j)<<1)+1]);
+      }
+      printf("\n");
     }
-    printf("\n");
-  }
 #endif
-  
-  
-  /// Resource mapping
-  
-  // Non interleaved VRB to PRB mapping
-  uint16_t start_sc = frame_parms->first_carrier_offset + rel15->rbStart*NR_NB_SC_PER_RB;
-  if (start_sc >= frame_parms->ofdm_symbol_size)
-    start_sc -= frame_parms->ofdm_symbol_size;
-
+    
+    
+    /// Resource mapping
+    
+    // Non interleaved VRB to PRB mapping
+    uint16_t start_sc = frame_parms->first_carrier_offset + rel15->rbStart*NR_NB_SC_PER_RB;
+    if (start_sc >= frame_parms->ofdm_symbol_size)
+      start_sc -= frame_parms->ofdm_symbol_size;
+    
 #ifdef DEBUG_DLSCH_MAPPING
-  printf("PDSCH resource mapping started (start SC %d\tstart symbol %d\tN_PRB %d\tnb_re %d,nb_layers %d)\n",
-	 start_sc, rel15->StartSymbolIndex, rel15->rbSize, nb_re,rel15->nrOfLayers);
+    printf("PDSCH resource mapping started (start SC %d\tstart symbol %d\tN_PRB %d\tnb_re %d,nb_layers %d)\n",
+	   start_sc, rel15->StartSymbolIndex, rel15->rbSize, nb_re,rel15->nrOfLayers);
 #endif
-  for (int ap=0; ap<rel15->nrOfLayers; ap++) {
-
-    // DMRS params for this ap
-    get_Wt(Wt, ap, dmrs_Type);
-    get_Wf(Wf, ap, dmrs_Type);
-    delta = get_delta(ap, dmrs_Type);
-    l_prime[0] = 0; // single symbol ap 0
-    uint8_t dmrs_symbol = l0+l_prime[0];
+    for (int ap=0; ap<rel15->nrOfLayers; ap++) {
+      
+      // DMRS params for this ap
+      get_Wt(Wt, ap, dmrs_Type);
+      get_Wf(Wf, ap, dmrs_Type);
+      delta = get_delta(ap, dmrs_Type);
+      l_prime[0] = 0; // single symbol ap 0
+      uint8_t dmrs_symbol = l0+l_prime[0];
 #ifdef DEBUG_DLSCH_MAPPING
-    printf("DMRS Type %d params for ap %d: Wt %d %d \t Wf %d %d \t delta %d \t l_prime %d \t l0 %d\tDMRS symbol %d\n",
-	   1+dmrs_Type,ap, Wt[0], Wt[1], Wf[0], Wf[1], delta, l_prime[0], l0, dmrs_symbol);
+      printf("DMRS Type %d params for ap %d: Wt %d %d \t Wf %d %d \t delta %d \t l_prime %d \t l0 %d\tDMRS symbol %d\n",
+	     1+dmrs_Type,ap, Wt[0], Wt[1], Wf[0], Wf[1], delta, l_prime[0], l0, dmrs_symbol);
 #endif
-    uint8_t k_prime=0;
-    uint16_t m=0, n=0, dmrs_idx=0, k=0;
-
-    int txdataF_offset = (slot%2)*frame_parms->samples_per_slot_wCP;
-    if (dmrs_Type == NFAPI_NR_DMRS_TYPE1) // another if condition to be included to check pdsch config type (reference of k)
-      dmrs_idx = rel15->rbStart*6;
-    else
-      dmrs_idx = rel15->rbStart*4;
-
-    for (int l=rel15->StartSymbolIndex; l<rel15->StartSymbolIndex+rel15->NrOfSymbols; l++) {
-      k = start_sc;
-      for (int i=0; i<rel15->rbSize*NR_NB_SC_PER_RB; i++) {
-        if ((l == dmrs_symbol) && (k == ((start_sc+get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type))%(frame_parms->ofdm_symbol_size)))) {
-          ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)] = (Wt[l_prime[0]]*Wf[k_prime]*amp*mod_dmrs[dmrs_idx<<1]) >> 15;
-          ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)] = (Wt[l_prime[0]]*Wf[k_prime]*amp*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15;
+      uint8_t k_prime=0;
+      uint16_t m=0, n=0, dmrs_idx=0, k=0;
+      
+      int txdataF_offset = (slot%2)*frame_parms->samples_per_slot_wCP;
+      if (dmrs_Type == NFAPI_NR_DMRS_TYPE1) // another if condition to be included to check pdsch config type (reference of k)
+	dmrs_idx = rel15->rbStart*6;
+      else
+	dmrs_idx = rel15->rbStart*4;
+      
+      for (int l=rel15->StartSymbolIndex; l<rel15->StartSymbolIndex+rel15->NrOfSymbols; l++) {
+	k = start_sc;
+	for (int i=0; i<rel15->rbSize*NR_NB_SC_PER_RB; i++) {
+	  if ((l == dmrs_symbol) && (k == ((start_sc+get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type))%(frame_parms->ofdm_symbol_size)))) {
+	    ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)] = (Wt[l_prime[0]]*Wf[k_prime]*amp*mod_dmrs[dmrs_idx<<1]) >> 15;
+	    ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)] = (Wt[l_prime[0]]*Wf[k_prime]*amp*mod_dmrs[(dmrs_idx<<1) + 1]) >> 15;
 #ifdef DEBUG_DLSCH_MAPPING
-	  printf("dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d\n",
-		 dmrs_idx, l, k, k_prime, n, ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)],
-		 ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)]);
+	    printf("dmrs_idx %d\t l %d \t k %d \t k_prime %d \t n %d \t txdataF: %d %d\n",
+		   dmrs_idx, l, k, k_prime, n, ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)],
+		   ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)]);
 #endif
-          dmrs_idx++;
-          k_prime++;
-          k_prime&=1;
-          n+=(k_prime)?0:1;
-        }
-
-        else {
-          if( (l != dmrs_symbol) || allowed_xlsch_re_in_dmrs_symbol(k,start_sc,rel15->numDmrsCdmGrpsNoData,dmrs_Type)) {
-            ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)] = (amp * tx_layers[ap][m<<1]) >> 15;
-            ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)] = (amp * tx_layers[ap][(m<<1) + 1]) >> 15;
+	    dmrs_idx++;
+	    k_prime++;
+	    k_prime&=1;
+	    n+=(k_prime)?0:1;
+	  }
+	  
+	  else {
+	    if( (l != dmrs_symbol) || allowed_xlsch_re_in_dmrs_symbol(k,start_sc,rel15->numDmrsCdmGrpsNoData,dmrs_Type)) {
+	      ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)] = (amp * tx_layers[ap][m<<1]) >> 15;
+	      ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)] = (amp * tx_layers[ap][(m<<1) + 1]) >> 15;
 #ifdef DEBUG_DLSCH_MAPPING
-	    printf("m %d\t l %d \t k %d \t txdataF: %d %d\n",
-                   m, l, k, ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)],
-		   ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)]);
+	      printf("m %d\t l %d \t k %d \t txdataF: %d %d\n",
+		     m, l, k, ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + (2*txdataF_offset)],
+		     ((int16_t*)txdataF[ap])[((l*frame_parms->ofdm_symbol_size + k)<<1) + 1 + (2*txdataF_offset)]);
 #endif
-            m++;
-          }
-        }
-        if (++k >= frame_parms->ofdm_symbol_size)
-          k -= frame_parms->ofdm_symbol_size;
-      }
-    }
-  }
+	      m++;
+	    }
+	  }
+	  if (++k >= frame_parms->ofdm_symbol_size)
+	    k -= frame_parms->ofdm_symbol_size;
+	} //RE loop
+      } // symbol loop
+    }// layer loop
+    dlsch->slot_tx[slot]=0;
+  }// dlsch loop
   return 0;
 }
+
+void dump_pdsch_stats(PHY_VARS_gNB *gNB) {
+
+  for (int i=0;i<NUMBER_OF_NR_SCH_STATS_MAX;i++)
+    if (gNB->dlsch_stats[i].rnti > 0)
+      LOG_I(PHY,"DLSCH RNTI %x: round_trials %d(%1.1e):%d(%1.1e):%d(%1.1e):%d, current_Qm %d, current_RI %d, total_bytes TX %d\n",
+	    gNB->dlsch_stats[i].rnti,
+	    gNB->dlsch_stats[i].round_trials[0],
+	    (double)gNB->dlsch_stats[i].round_trials[1]/gNB->dlsch_stats[i].round_trials[0],
+	    gNB->dlsch_stats[i].round_trials[1],
+	    (double)gNB->dlsch_stats[i].round_trials[2]/gNB->dlsch_stats[i].round_trials[0],
+	    gNB->dlsch_stats[i].round_trials[2],
+	    (double)gNB->dlsch_stats[i].round_trials[3]/gNB->dlsch_stats[i].round_trials[0],
+	    gNB->dlsch_stats[i].round_trials[3],
+	    gNB->dlsch_stats[i].current_Qm,
+	    gNB->dlsch_stats[i].current_RI,
+	    gNB->dlsch_stats[i].total_bytes_tx);
+
+}
+
+void clear_pdsch_stats(PHY_VARS_gNB *gNB) {
+
+  for (int i=0;i<NUMBER_OF_NR_DLSCH_MAX;i++)
+    memset((void*)&gNB->dlsch_stats[i],0,sizeof(gNB->dlsch_stats[i]));
+}
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h
index 3a6851ee8fa69dad1e9b451ec616e5b3d212ef4c..23ec75653186f82bdeed21d8804a3a6887749ea6 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.h
@@ -69,27 +69,9 @@ void nr_fill_dlsch(PHY_VARS_gNB *gNB,
                    nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu,
                    unsigned char *sdu); 
 
-uint8_t nr_generate_pdsch(NR_gNB_DLSCH_t *dlsch,
-                          uint32_t ***pdsch_dmrs,
-                          int32_t** txdataF,
-                          int16_t amp,
-                          int frame,
-                          uint8_t slot,
-                          NR_DL_FRAME_PARMS *frame_parms,
-			  int xOverhead,
-                          time_stats_t *dlsch_encoding_stats,
-                          time_stats_t *dlsch_scrambling_stats,
-                          time_stats_t *dlsch_modulation_stats,
-			  time_stats_t *tinput,
-			  time_stats_t *tprep,
-			  time_stats_t *tparity,
-			  time_stats_t *toutput,
-			  time_stats_t *dlsch_rate_matching_stats,
-			  time_stats_t *dlsch_interleaving_stats,
-			  time_stats_t *dlsch_segmentation_stats);
-
-
-
+uint8_t nr_generate_pdsch(PHY_VARS_gNB *gNB,
+			  int frame,
+			  int slot);
 void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr, uint16_t N_RB);
 
 void clean_gNB_dlsch(NR_gNB_DLSCH_t *dlsch);
@@ -98,7 +80,10 @@ void clean_gNB_ulsch(NR_gNB_ULSCH_t *ulsch);
 
 int16_t find_nr_dlsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type);
 
-int nr_dlsch_encoding(unsigned char *a,int frame,
+NR_gNB_SCH_STATS_t *find_nr_dlsch_stats(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type);
+
+int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
+		      unsigned char *a,int frame,
 		      uint8_t slot,
 		      NR_gNB_DLSCH_t *dlsch,
 		      NR_DL_FRAME_PARMS* frame_parms,
@@ -113,4 +98,8 @@ int nr_dlsch_encoding(unsigned char *a,int frame,
 
 void nr_emulate_dlsch_payload(uint8_t* payload, uint16_t size);
 
+void dump_pdsch_stats(PHY_VARS_gNB *gNB);
+
+void clear_pdsch_stats(PHY_VARS_gNB *gNB);
+
 #endif
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
index 52377ac9453292efb508403bcceb2169117a915e..e5841d326286b69d263bda5b452da055aa0d469b 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
@@ -61,7 +61,7 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr, uint16_t N_RB)
 
     if (N_RB != 273) {
       a_segments = a_segments*N_RB;
-      a_segments = a_segments/273;
+      a_segments = a_segments/273 +1;
     }  
 
 
@@ -150,7 +150,7 @@ NR_gNB_DLSCH_t *new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms,
 
   if (N_RB != 273) {
     a_segments = a_segments*N_RB;
-    a_segments = (a_segments + 272) / 273;
+    a_segments = a_segments/273 +1;
   }  
 
   uint16_t dlsch_bytes = a_segments*1056;  // allocated bytes per segment
@@ -309,7 +309,8 @@ void clean_gNB_dlsch(NR_gNB_DLSCH_t *dlsch)
   }
 }
 
-int nr_dlsch_encoding(unsigned char *a,
+int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
+		      unsigned char *a,
                       int frame,
                       uint8_t slot,
                       NR_gNB_DLSCH_t *dlsch,
@@ -326,7 +327,8 @@ int nr_dlsch_encoding(unsigned char *a,
   nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->harq_processes[harq_pid]->pdsch_pdu.pdsch_pdu_rel15;
   uint16_t nb_rb = rel15->rbSize;
   uint8_t nb_symb_sch = rel15->NrOfSymbols;
-  uint32_t A, Z, Kb, F=0;
+  uint32_t A, Kb, F=0;
+  static uint32_t Z = 0;
   uint32_t *Zc = &Z;
   uint8_t mod_order = rel15->qamModOrder[0];
   uint16_t Kr=0,r;
@@ -347,10 +349,34 @@ int nr_dlsch_encoding(unsigned char *a,
   float Coderate = 0.0;
   uint8_t Nl = 4;
 
+  dlsch->harq_processes[harq_pid]->round = nr_rv_round_map[rel15->rvIndex[0]];
+
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_IN);
 
   A = rel15->TBSize[0]<<3;
 
+  NR_gNB_SCH_STATS_t *stats=NULL;
+  int first_free=-1;
+  for (int i=0;i<NUMBER_OF_NR_SCH_STATS_MAX;i++) {
+    if (gNB->dlsch_stats[i].rnti == 0 && first_free == -1) {
+      first_free = i;
+      stats=&gNB->dlsch_stats[i];
+    }
+    if (gNB->dlsch_stats[i].rnti == dlsch->rnti) {
+      stats=&gNB->dlsch_stats[i];
+      break;
+    }
+  }
+
+  if (stats) {
+    stats->round_trials[dlsch->harq_processes[harq_pid]->round]++;
+    stats->rnti = dlsch->rnti;
+    if (dlsch->harq_processes[harq_pid]->round == 0){
+      stats->total_bytes_tx += rel15->TBSize[0];
+      stats->current_RI   = rel15->nrOfLayers;
+      stats->current_Qm   = rel15->qamModOrder[0];
+    }
+  }
   G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs,mod_order,rel15->nrOfLayers);
 
   LOG_D(PHY,"dlsch coding A %d G %d mod_order %d\n", A,G, mod_order);
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c
index 7702d770ee63be176e31f8d5ace7d08c742e124d..5ce2c45a7dd94f4dcd4a133190fe2fdbd37b5416 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_tools.c
@@ -255,27 +255,28 @@ void nr_emulate_dlsch_payload(uint8_t* pdu, uint16_t size) {
 }
 
 int16_t find_nr_dlsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type) {
-
-  uint16_t i;
-  int16_t first_free_index=-1;
-
-  AssertFatal(gNB!=NULL,"gNB is null\n");
-  for (i=0; i<NUMBER_OF_NR_DLSCH_MAX; i++) {
-    AssertFatal(gNB->dlsch[i]!=NULL,"gNB->dlsch[%d] is null\n",i);
-    AssertFatal(gNB->dlsch[i][0]!=NULL,"gNB->dlsch[%d][0] is null\n",i);
-    LOG_D(PHY,"searching for rnti %x : dlsch_index %d=> harq_mask %x, rnti %x, first_free_index %d\n", rnti,i,gNB->dlsch[i][0]->harq_mask,gNB->dlsch[i][0]->rnti,first_free_index);
-    if ((gNB->dlsch[i][0]->harq_mask >0) &&
-        (gNB->dlsch[i][0]->rnti==rnti))       return i;
-    else if ((gNB->dlsch[i][0]->harq_mask == 0) && (first_free_index==-1)) first_free_index=i;
-  }
-  if (type == SEARCH_EXIST) return -1;
-  if (first_free_index != -1)
-    gNB->dlsch[first_free_index][0]->rnti = 0;
-  return first_free_index;
+ 
+   uint16_t i;
+   int16_t first_free_index=-1;
+ 
+   AssertFatal(gNB!=NULL,"gNB is null\n");
+   for (i=0; i<NUMBER_OF_NR_DLSCH_MAX; i++) {
+     AssertFatal(gNB->dlsch[i]!=NULL,"gNB->dlsch[%d] is null\n",i);
+     AssertFatal(gNB->dlsch[i][0]!=NULL,"gNB->dlsch[%d][0] is null\n",i);
+     LOG_D(PHY,"searching for rnti %x : dlsch_index %d=> harq_mask %x, rnti %x, first_free_index %d\n", rnti,i,
+	   gNB->dlsch[i][0]->harq_mask,gNB->dlsch[i][0]->rnti,first_free_index);
+     if ((gNB->dlsch[i][0]->harq_mask >0) &&
+	 (gNB->dlsch[i][0]->rnti==rnti))       return i;
+     else if ((gNB->dlsch[i][0]->harq_mask == 0) && (first_free_index==-1)) first_free_index=i;
+   }
+   if (type == SEARCH_EXIST) return -1;
+   if (first_free_index != -1)
+     gNB->dlsch[first_free_index][0]->rnti = 0;
+   return first_free_index;
+   
 }
 
 
-
 void nr_fill_dlsch(PHY_VARS_gNB *gNB,
                    int frame,
                    int slot,
@@ -291,7 +292,7 @@ void nr_fill_dlsch(PHY_VARS_gNB *gNB,
   NR_DL_gNB_HARQ_t **harq  = dlsch->harq_processes;
   /// DLSCH struct
   memcpy((void*)&harq[dlsch->harq_ids[frame%2][slot]]->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu));
-  gNB->num_pdsch_rnti++;
+  gNB->num_pdsch_rnti[slot]++;
   AssertFatal(sdu!=NULL,"sdu is null\n");
   harq[dlsch->harq_ids[frame%2][slot]]->pdu = sdu;
 
diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
index e33532fa657f25792cf84c75342c38941ff29011..8cb7ad45e7444935c1b5a23c22614af213147b35 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h
@@ -342,6 +342,11 @@ void nr_decode_pucch1(int32_t **rxdataF,
                       uint8_t timeDomainOCC,
                       uint8_t nr_bit);
 
+void nr_decode_pucch2(PHY_VARS_gNB *gNB,
+                      int slot,
+                      nfapi_nr_uci_pucch_pdu_format_2_3_4_t* uci_pdu,
+                      nfapi_nr_pucch_pdu_t* pucch_pdu);
+
 void nr_decode_pucch0(PHY_VARS_gNB *gNB,
                       int slot,
                       nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu,
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c
index 3622e61b615772bb037b9285aee5e72deaf49748..0040f015445ac40edec1723fac14353dfac93abc 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c
@@ -33,7 +33,7 @@
 #include <stdint.h>
 #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
 #include "PHY/NR_TRANSPORT/nr_ulsch.h"
-#include "PHY/LTE_REFSIG/lte_refsig.h"
+#include "PHY/NR_REFSIG/nr_refsig.h"
 
 int16_t find_nr_ulsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type) {
 
@@ -103,3 +103,62 @@ void nr_ulsch_unscrambling(int16_t* llr,
       llr[i] = -llr[i];
   }
 }
+
+void nr_ulsch_unscrambling_optim(int16_t* llr,
+				 uint32_t size,
+				 uint8_t q,
+				 uint32_t Nid,
+				 uint32_t n_RNTI) {
+  
+#if defined(__x86_64__) || defined(__i386__)
+  uint32_t x1, x2, s=0;
+
+  x2 = (n_RNTI<<15) + Nid;
+
+  uint8_t *s8=(uint8_t *)&s;
+  __m128i *llr128 = (__m128i*)llr;
+  int j=0;
+  s = lte_gold_generic(&x1, &x2, 1);
+
+  for (int i=0; i<((size>>5)+((size&0x1f) > 0 ? 1 : 0)); i++,j+=4) {
+    llr128[j]   = _mm_mullo_epi16(llr128[j],byte2m128i[s8[0]]);
+    llr128[j+1] = _mm_mullo_epi16(llr128[j+1],byte2m128i[s8[1]]);
+    llr128[j+2] = _mm_mullo_epi16(llr128[j+2],byte2m128i[s8[2]]);
+    llr128[j+3] = _mm_mullo_epi16(llr128[j+3],byte2m128i[s8[3]]);
+    s = lte_gold_generic(&x1, &x2, 0);
+  }
+#else
+
+    nr_ulsch_unscrambling(llr,
+                          size,
+                          q,
+                          Nid,
+                          n_RNTI);
+#endif
+}
+
+void dump_pusch_stats(PHY_VARS_gNB *gNB) {
+
+  for (int i=0;i<NUMBER_OF_NR_ULSCH_MAX;i++)
+    if (gNB->ulsch_stats[i].rnti>0) 
+      LOG_I(PHY,"ULSCH RNTI %x: round_trials %d(%1.1e):%d(%1.1e):%d(%1.1e):%d, current_Qm %d, current_RI %d, total_bytes RX/SCHED %d/%d\n",
+	    gNB->ulsch_stats[i].rnti,
+	    gNB->ulsch_stats[i].round_trials[0],
+	    (double)gNB->ulsch_stats[i].round_trials[1]/gNB->ulsch_stats[i].round_trials[0],
+	    gNB->ulsch_stats[i].round_trials[1],
+	    (double)gNB->ulsch_stats[i].round_trials[2]/gNB->ulsch_stats[i].round_trials[0],
+	    gNB->ulsch_stats[i].round_trials[2],
+	    (double)gNB->ulsch_stats[i].round_trials[3]/gNB->ulsch_stats[i].round_trials[0],
+	    gNB->ulsch_stats[i].round_trials[3],
+	    gNB->ulsch_stats[i].current_Qm,
+	    gNB->ulsch_stats[i].current_RI,
+	    gNB->ulsch_stats[i].total_bytes_rx,
+	    gNB->ulsch_stats[i].total_bytes_tx);
+  
+}
+
+void clear_pusch_stats(PHY_VARS_gNB *gNB) {
+
+  for (int i=0;i<NUMBER_OF_NR_ULSCH_MAX;i++)
+    memset((void*)&gNB->ulsch_stats[i],0,sizeof(gNB->ulsch_stats[i]));
+}
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h
index 7ff52ae69252ff5d799cfff36f2a836386786592..a9845b6bbb44557e5b93f54203a2eaa9bc36de17 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h
@@ -75,9 +75,19 @@ void nr_ulsch_unscrambling(int16_t* llr,
                          uint32_t n_RNTI);
 
 
+void nr_ulsch_unscrambling_optim(int16_t* llr,
+				 uint32_t size,
+				 uint8_t q,
+				 uint32_t Nid,
+				 uint32_t n_RNTI);
+
 void nr_ulsch_procedures(PHY_VARS_gNB *gNB,
                          int frame_rx,
                          int slot_rx,
                          int UE_id,
                          uint8_t harq_pid);
 int16_t find_nr_ulsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type);
+
+void dump_pusch_stats(PHY_VARS_gNB *gNB);
+
+void clear_pusch_stats(PHY_VARS_gNB *gNB);
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
index 8ca3071e061d4ba36e9028a21876edebf3be474a..7980206eb4075191d057fdf2181e0920920022e2 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
@@ -67,7 +67,7 @@ void free_gNB_ulsch(NR_gNB_ULSCH_t **ulschptr,uint8_t N_RB_UL)
   if (ulsch) {
     if (N_RB_UL != 273) {
       a_segments = a_segments*N_RB_UL;
-      a_segments = a_segments/273;
+      a_segments = a_segments/273 +1;
     }  
 
 
@@ -119,11 +119,10 @@ NR_gNB_ULSCH_t *new_gNB_ulsch(uint8_t max_ldpc_iterations,uint16_t N_RB_UL, uint
 
   if (N_RB_UL != 273) {
     a_segments = a_segments*N_RB_UL;
-    a_segments = a_segments/273;
+    a_segments = a_segments/273 +1;
   }
 
   uint16_t ulsch_bytes = a_segments*1056;  // allocated bytes per segment
-
   ulsch = (NR_gNB_ULSCH_t *)malloc16(sizeof(NR_gNB_ULSCH_t));
 
   if (ulsch) {
@@ -209,8 +208,6 @@ void clean_gNB_ulsch(NR_gNB_ULSCH_t *ulsch)
     ulsch->Mlimit = 0;
     ulsch->max_ldpc_iterations = 0;
     ulsch->last_iteration_cnt = 0;
-    ulsch->num_active_cba_groups = 0;
-    for (i=0;i<NUM_MAX_CBA_GROUP;i++) ulsch->cba_rnti[i] = 0;
     for (i=0;i<NR_MAX_SLOTS_PER_FRAME;i++) ulsch->harq_process_id[i] = 0;
 
     for (i=0; i<NR_MAX_ULSCH_HARQ_PROCESSES; i++) {
@@ -226,7 +223,6 @@ void clean_gNB_ulsch(NR_gNB_ULSCH_t *ulsch)
         ulsch->harq_processes[i]->rar_alloc=0;
         ulsch->harq_processes[i]->status=NR_SCH_IDLE;
         ulsch->harq_processes[i]->subframe_scheduling_flag=0;
-        ulsch->harq_processes[i]->subframe_cba_scheduling_flag=0;
         ulsch->harq_processes[i]->phich_active=0;
         ulsch->harq_processes[i]->phich_ACK=0;
         ulsch->harq_processes[i]->previous_first_rb=0;
@@ -290,7 +286,7 @@ void clean_gNB_ulsch(NR_gNB_ULSCH_t *ulsch)
   static uint32_t prnt_crc_cnt = 0;
 #endif
 
-uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
+uint32_t nr_ulsch_decoding(PHY_VARS_gNB *gNB,
                            uint8_t UE_id,
                            short *ulsch_llr,
                            NR_DL_FRAME_PARMS *frame_parms,
@@ -312,7 +308,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 #endif
   
 
-  NR_gNB_ULSCH_t                       *ulsch                 = phy_vars_gNB->ulsch[UE_id][0];
+  NR_gNB_ULSCH_t                       *ulsch                 = gNB->ulsch[UE_id][0];
   NR_UL_gNB_HARQ_t                     *harq_process          = ulsch->harq_processes[harq_pid];
   
   t_nrLDPC_dec_params decParams;
@@ -360,28 +356,21 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_ULSCH_DECODING,1);
   harq_process->TBS = pusch_pdu->pusch_data.tb_size;
+  harq_process->round = nr_rv_round_map[pusch_pdu->pusch_data.rv_index];
 
   A   = (harq_process->TBS)<<3;
   ret = ulsch->max_ldpc_iterations + 1;
 
   LOG_D(PHY,"ULSCH Decoding, harq_pid %d TBS %d G %d mcs %d Nl %d nb_rb %d, Qm %d, n_layers %d\n",harq_pid,A,G, mcs, n_layers, nb_rb, Qm, n_layers);
 
-  if (harq_process->round == 0) {
-
-    // This is a new packet, so compute quantities regarding segmentation
-    if (A > 3824)
-      harq_process->B = A+24;
-    else
-      harq_process->B = A+16;
-
-    if (R<1024)
-      Coderate = (float) R /(float) 1024;
-    else
-      Coderate = (float) R /(float) 2048;
-
-    if ((A <=292) || ((A<=3824) && (Coderate <= 0.6667)) || Coderate <= 0.25){
-      p_decParams->BG = 2;
-      if (Coderate < 0.3333) {
+  if (R<1024)
+    Coderate = (float) R /(float) 1024;
+  else
+    Coderate = (float) R /(float) 2048;
+  
+  if ((A <=292) || ((A<=3824) && (Coderate <= 0.6667)) || Coderate <= 0.25){
+    p_decParams->BG = 2;
+    if (Coderate < 0.3333) {
       p_decParams->R = 15;
       kc = 52;
     }
@@ -408,6 +397,34 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
       kc = 27;
     }
   }
+  
+  NR_gNB_SCH_STATS_t *stats=NULL;
+  int first_free=-1;
+  for (int i=0;i<NUMBER_OF_NR_SCH_STATS_MAX;i++) {
+    if (gNB->ulsch_stats[i].rnti == 0 && first_free == -1) {
+      first_free = i;
+      stats=&gNB->ulsch_stats[i];
+    }
+    if (gNB->ulsch_stats[i].rnti == ulsch->rnti) {
+      stats=&gNB->ulsch_stats[i];
+      break;
+    }
+  }
+  if (stats) {
+    stats->rnti = ulsch->rnti;
+    stats->round_trials[harq_process->round]++;
+  }
+  if (harq_process->round == 0) {
+    if (stats) {
+      stats->current_Qm = Qm;
+      stats->current_RI = n_layers;
+      stats->total_bytes_tx += harq_process->TBS;
+    }
+    // This is a new packet, so compute quantities regarding segmentation
+    if (A > 3824)
+      harq_process->B = A+24;
+    else
+      harq_process->B = A+16;
 
   // [hna] Perform nr_segmenation with input and output set to NULL to calculate only (B, C, K, Z, F)
   nr_segmentation(NULL,
@@ -438,7 +455,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 
   if (nb_rb != 273) {
     a_segments = a_segments*nb_rb;
-    a_segments = a_segments/273;
+    a_segments = a_segments/273 +1;
   }
 
   if (harq_process->C > a_segments) {
@@ -460,7 +477,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
     E = nr_get_E(G, harq_process->C, Qm, n_layers, r);
 
 
-    start_meas(&phy_vars_gNB->ulsch_deinterleaving_stats);
+    start_meas(&gNB->ulsch_deinterleaving_stats);
 
     ////////////////////////////////////////////////////////////////////////////////////////////
     ///////////////////////////////// nr_deinterleaving_ldpc ///////////////////////////////////
@@ -476,11 +493,10 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
     //for (int i =0; i<16; i++)
     //          printf("rx output deinterleaving w[%d]= %d r_offset %d\n", i,harq_process->w[r][i], r_offset);
 
-    stop_meas(&phy_vars_gNB->ulsch_deinterleaving_stats);
+    stop_meas(&gNB->ulsch_deinterleaving_stats);
 
 
-#ifdef DEBUG_ULSCH_DECODING
-    LOG_D(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rv %d, round %d)...\n",
+    LOG_D(PHY,"HARQ_PID %d Rate Matching Segment %d (coded bits %d,unpunctured/repeated bits %d, TBS %d, mod_order %d, nb_rb %d, Nl %d, rvidx %d, round %d)...\n",
           harq_pid,r, G,
           Kr*3,
           harq_process->TBS,
@@ -489,7 +505,6 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
           n_layers,
           pusch_pdu->pusch_data.rv_index,
           harq_process->round);
-#endif
     //////////////////////////////////////////////////////////////////////////////////////////
 
 
@@ -499,7 +514,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 
     ///////////////////////// harq_process->e =====> harq_process->d /////////////////////////
 
-    start_meas(&phy_vars_gNB->ulsch_rate_unmatching_stats);
+    start_meas(&gNB->ulsch_rate_unmatching_stats);
 
     Tbslbrm = nr_compute_tbslbrm(0,nb_rb,n_layers,harq_process->C);
 
@@ -516,12 +531,12 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 				 harq_process->F,
 				 Kr-harq_process->F-2*(p_decParams->Z))==-1) {
 
-      stop_meas(&phy_vars_gNB->ulsch_rate_unmatching_stats);
+      stop_meas(&gNB->ulsch_rate_unmatching_stats);
 
       LOG_E(PHY,"ulsch_decoding.c: Problem in rate_matching\n");
       return (ulsch->max_ldpc_iterations + 1);
     } else {
-      stop_meas(&phy_vars_gNB->ulsch_rate_unmatching_stats);
+      stop_meas(&gNB->ulsch_rate_unmatching_stats);
     }
 
     r_offset += E;
@@ -559,7 +574,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 
     if (err_flag == 0) {
 
-      start_meas(&phy_vars_gNB->ulsch_ldpc_decoding_stats);
+      start_meas(&gNB->ulsch_ldpc_decoding_stats);
 
       //LOG_E(PHY,"AbsSubframe %d.%d Start LDPC segment %d/%d A %d ",frame%1024,nr_tti_rx,r,harq_process->C-1, A);
 
@@ -573,7 +588,6 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 
       AssertFatal(kc!=255,"");
       j+=(harq_process->F>>3);
-      //      for (i=Kr_bytes,j=K_bytes_F-((2*p_decParams->Z)>>3); i < ((kc*p_decParams->Z)>>3); i++, j++) {
       for (i=Kr_bytes; i < ((kc*p_decParams->Z)>>3); i++, j++) {
         pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j]));
       }
@@ -628,7 +642,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
       //write_output("dec_output.m","dec0",harq_process->c[0],Kr_bytes,1,4);
 #endif
 
-      stop_meas(&phy_vars_gNB->ulsch_ldpc_decoding_stats);
+      stop_meas(&gNB->ulsch_ldpc_decoding_stats);
     }
 
     if ((err_flag == 0) && (ret >= (ulsch->max_ldpc_iterations + 1))) {
@@ -651,7 +665,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 
 #ifdef gNB_DEBUG_TRACE
     LOG_I(PHY,"[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, status %d, round %d, TBS %d) Kr %d r %d\n",
-          phy_vars_gNB->Mod_id, frame, nr_tti_rx, harq_pid,harq_process->status, harq_process->round,harq_process->TBS,Kr,r);
+          gNB->Mod_id, frame, nr_tti_rx, harq_pid,harq_process->status, harq_process->round,harq_process->TBS,Kr,r);
 #endif
 
     // harq_process->harq_ack.ack = 0;
@@ -668,7 +682,7 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
     }
 
     //   LOG_D(PHY,"[gNB %d] ULSCH: Setting NACK for nr_tti_rx %d (pid %d, pid status %d, round %d/Max %d, TBS %d)\n",
-    //         phy_vars_gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->status,harq_process->round,ulsch->Mlimit,harq_process->TBS);
+    //         gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->status,harq_process->round,ulsch->Mlimit,harq_process->TBS);
 
     harq_process->handled  = 1;
     ret = ulsch->max_ldpc_iterations + 1;
@@ -677,18 +691,18 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 
 #ifdef gNB_DEBUG_TRACE
     LOG_I(PHY,"[gNB %d] ULSCH: Setting ACK for nr_tti_rx %d TBS %d\n",
-          phy_vars_gNB->Mod_id,nr_tti_rx,harq_process->TBS);
+          gNB->Mod_id,nr_tti_rx,harq_process->TBS);
 #endif
 
     harq_process->status = SCH_IDLE;
     harq_process->round  = 0;
     // harq_process->handled  = 0;
-    ulsch->harq_mask  &= ~(1 << harq_pid);
+    ulsch->harq_mask &= ~(1 << harq_pid);
     // harq_process->harq_ack.ack = 1;
     // harq_process->harq_ack.harq_id = harq_pid;
     // harq_process->harq_ack.send_harq_status = 1;
 
-    //  LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for nr_tti_rx %d (pid %d, round %d, TBS %d)\n",phy_vars_gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->round,harq_process->TBS);
+    //  LOG_D(PHY,"[gNB %d] ULSCH: Setting ACK for nr_tti_rx %d (pid %d, round %d, TBS %d)\n",gNB->Mod_id,nr_tti_rx,harq_pid,harq_process->round,harq_process->TBS);
 
 
     // Reassembly of Transport block here
@@ -711,11 +725,12 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
 #endif
       
     }
+    if (stats) stats->total_bytes_rx += harq_process->TBS;
   }
 
 #ifdef DEBUG_ULSCH_DECODING
-  LOG_I(PHY, "Decoder output (payload) at SFN/SF: %d/%d \n", frame, nr_tti_rx);
-  for (i = 0; i < harq_process->TBS ; i++) {
+  LOG_I(PHY, "Decoder output (payload) at SFN/SF: %d/%d TBS: %d\n", frame, nr_tti_rx,harq_process->TBS);
+  for (i = 0; i < harq_process->TBS; i++) {
 	  //harq_process_ul_ue->a[i] = (unsigned char) rand();
 	  //printf("a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]);
 	  printf("%02x ",harq_process->b[i]);
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
index 905260753520e8eed77c3fd8520be720619855e5..3fd7966ce74d7fba7732442a452c0d5e68a3a552 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
@@ -236,7 +236,7 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF,
   uint32_t ul_ch0_ext_index = 0;
   uint32_t ul_ch0_index = 0;
   uint8_t k_prime;
-  uint16_t n=0;
+  uint16_t n;
   int16_t *rxF,*rxF_ext;
   int *ul_ch0,*ul_ch0_ext;
   uint8_t delta = 0;
@@ -251,46 +251,68 @@ void nr_ulsch_extract_rbs_single(int32_t **rxdataF,
   uint8_t is_dmrs_re;
   start_re = (frame_parms->first_carrier_offset + (pusch_pdu->rb_start * NR_NB_SC_PER_RB))%frame_parms->ofdm_symbol_size;
   nb_re_pusch = NR_NB_SC_PER_RB * pusch_pdu->rb_size;
+#ifdef __AVX2__
+  int nb_re_pusch2 = nb_re_pusch + (nb_re_pusch&7);
+#else
+  int nb_re_pusch2 = nb_re_pusch;
+#endif
 
   for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
 
     rxF       = (int16_t *)&rxdataF[aarx][symbol * frame_parms->ofdm_symbol_size];
-    rxF_ext   = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6
+    rxF_ext   = (int16_t *)&pusch_vars->rxdataF_ext[aarx][symbol * nb_re_pusch2]; // [hna] rxdataF_ext isn't contiguous in order to solve an alignment problem ib llr computation in case of mod_order = 4, 6
 
     ul_ch0     = &pusch_vars->ul_ch_estimates[aarx][pusch_vars->dmrs_symbol*frame_parms->ofdm_symbol_size]; // update channel estimates if new dmrs symbol are available
 
-    ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aarx][symbol*nb_re_pusch];
+    ul_ch0_ext = &pusch_vars->ul_ch_estimates_ext[aarx][symbol*nb_re_pusch2];
 
     n = 0;
     k_prime = 0;
 
-    for (re = 0; re < nb_re_pusch; re++) {
+    if (is_dmrs_symbol == 0) {
+      //
+      //rxF[ ((start_re + re)*2)      % (frame_parms->ofdm_symbol_size*2)]);
+      if (start_re + nb_re_pusch < frame_parms->ofdm_symbol_size) {
+        memcpy1((void*)rxF_ext,
+                (void*)&rxF[start_re*2],
+                nb_re_pusch*sizeof(int32_t));
+      } else {
+	int neg_length = frame_parms->ofdm_symbol_size-start_re;
+	int pos_length = nb_re_pusch-neg_length;
+
+	memcpy1((void*)rxF_ext,(void*)&rxF[start_re*2],neg_length*sizeof(int32_t));
+	memcpy1((void*)&rxF_ext[2*neg_length],(void*)rxF,pos_length*sizeof(int32_t));
+      }
+      memcpy1((void*)ul_ch0_ext,(void*)ul_ch0,nb_re_pusch*sizeof(int32_t));
+    }
+    else {
+      for (re = 0; re < nb_re_pusch; re++) {
 
-      if (is_dmrs_symbol)
         is_dmrs_re = (re == get_dmrs_freq_idx_ul(n, k_prime, delta, pusch_pdu->dmrs_config_type));
-      else
-        is_dmrs_re = 0;
 
-      /* save only data and respective channel estimates */
-      if ( is_dmrs_re == 0) {
+#ifdef DEBUG_RB_EXT
+        printf("re = %d, kprime %d, n %d, is_dmrs_symbol = %d, symbol = %d\n", re, k_prime, n, is_dmrs_symbol, symbol);
+#endif
 
-        rxF_ext[rxF_ext_index]       = (rxF[ ((start_re + re)*2)      % (frame_parms->ofdm_symbol_size*2)]);
-        rxF_ext[rxF_ext_index + 1]   = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]);
-        ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index];
+        /* save only data and respective channel estimates */
+        if (is_dmrs_re == 0) {
+          rxF_ext[rxF_ext_index]     = (rxF[ ((start_re + re)*2)      % (frame_parms->ofdm_symbol_size*2)]);
+          rxF_ext[rxF_ext_index + 1] = (rxF[(((start_re + re)*2) + 1) % (frame_parms->ofdm_symbol_size*2)]);
+          ul_ch0_ext[ul_ch0_ext_index] = ul_ch0[ul_ch0_index];
 
 #ifdef DEBUG_RB_EXT
-        printf("rxF_ext[%d] = (%d,%d)\n", rxF_ext_index>>1, rxF_ext[rxF_ext_index],rxF_ext[rxF_ext_index+1]);
+          printf("dmrs symb %d: rxF_ext[%d] = (%d,%d), ul_ch0_ext[%d] = (%d,%d)\n",
+                 is_dmrs_symbol,rxF_ext_index>>1, rxF_ext[rxF_ext_index],rxF_ext[rxF_ext_index+1],
+                 ul_ch0_ext_index,  ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[0],  ((int16_t*)&ul_ch0_ext[ul_ch0_ext_index])[1]);
 #endif
-
-        ul_ch0_ext_index++;
-        rxF_ext_index +=2;
-      } else
-      {
-        k_prime++;
-        k_prime&=1;
-        n+=(k_prime)?0:1;
+          ul_ch0_ext_index++;
+          rxF_ext_index +=2;
+        } else {
+          n += k_prime;
+          k_prime ^= 1;
+        }
+        ul_ch0_index++;
       }
-      ul_ch0_index++;
     }
   }
 }
@@ -319,10 +341,16 @@ void nr_ulsch_scale_channel(int **ul_ch_estimates_ext,
 
   ch_amp128 = _mm_set1_epi16(ch_amp); // Q3.13
 
+#ifdef __AVX2__
+  int off = ((nb_rb&1) == 1)? 4:0;
+#else
+  int off = 0;
+#endif
+
   for (aatx=0; aatx < frame_parms->nb_antenna_ports_gNB; aatx++) {
     for (aarx=0; aarx < frame_parms->nb_antennas_rx; aarx++) {
 
-      ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*nb_rb*NR_NB_SC_PER_RB];
+      ul_ch128 = (__m128i *)&ul_ch_estimates_ext[aarx][symbol*(off+(nb_rb*NR_NB_SC_PER_RB))];
 
       if (is_dmrs_symbol==1){
         if (pusch_dmrs_type == pusch_dmrs_type1)
@@ -371,12 +399,18 @@ void nr_ulsch_channel_level(int **ul_ch_estimates_ext,
   int16_t x = factor2(len);
   int16_t y = (len)>>x;
 
+#ifdef __AVX2__
+  int off = ((nb_rb&1) == 1)? 4:0;
+#else
+  int off = 0;
+#endif
+
   for (aatx = 0; aatx < frame_parms->nb_antennas_tx; aatx++)
     for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
       //clear average level
       avg128U = _mm_setzero_si128();
 
-      ul_ch128=(__m128i *)&ul_ch_estimates_ext[(aatx<<1)+aarx][symbol*nb_rb*12];
+      ul_ch128=(__m128i *)&ul_ch_estimates_ext[(aatx<<1)+aarx][symbol*(off+(nb_rb*12))];
 
       for (rb = 0; rb < len/12; rb++) {
         avg128U = _mm_add_epi32(avg128U, _mm_srai_epi32(_mm_madd_epi16(ul_ch128[0], ul_ch128[0]), x));
@@ -464,13 +498,13 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext,
                                    unsigned short nb_rb,
                                    unsigned char output_shift) {
 
+
 #ifdef DEBUG_CH_COMP
   int16_t *rxF, *ul_ch;
   int prnt_idx;
 
-
-  rxF   = (int16_t *)&rxdataF_ext[0][(symbol*nb_rb*12)];
-  ul_ch = (int16_t *)&ul_ch_estimates_ext[0][symbol*nb_rb*12];
+  rxF   = (int16_t *)&rxdataF_ext[0][symbol*(off+(nb_rb*12))];
+  ul_ch = (int16_t *)&ul_ch_estimates_ext[0][symbol*(off+(nb_rb*1))2];
 
   printf("--------------------symbol = %d, mod_order = %d, output_shift = %d-----------------------\n", symbol, mod_order, output_shift);
   printf("----------------Before compensation------------------\n");
@@ -489,7 +523,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext,
   int print_idx;
 
 
-  ch_mag   = (int16_t *)&ul_ch_mag[0][(symbol*nb_rb*12)];
+  ch_mag   = (int16_t *)&ul_ch_mag[0][symbol*(off+(nb_rb*12))];
 
   printf("--------------------symbol = %d, mod_order = %d-----------------------\n", symbol, mod_order);
   printf("----------------Before computation------------------\n");
@@ -502,7 +536,13 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext,
 
 #endif
 
-#if defined(__i386) || defined(__x86_64)
+#ifdef __AVX2__
+  int off = ((nb_rb&1) == 1)? 4:0;
+#else
+  int off = 0;
+#endif
+
+#if defined(__i386) || defined(__x86_64__)
 
   unsigned short rb;
   unsigned char aatx,aarx;
@@ -524,11 +564,11 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext,
 
     for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
 
-      ul_ch128          = (__m128i *)&ul_ch_estimates_ext[(aatx<<1)+aarx][symbol*nb_rb*12];
-      ul_ch_mag128      = (__m128i *)&ul_ch_mag[(aatx<<1)+aarx][symbol*nb_rb*12];
-      ul_ch_mag128b     = (__m128i *)&ul_ch_magb[(aatx<<1)+aarx][symbol*nb_rb*12];
-      rxdataF128        = (__m128i *)&rxdataF_ext[aarx][symbol*nb_rb*12];
-      rxdataF_comp128   = (__m128i *)&rxdataF_comp[(aatx<<1)+aarx][symbol*nb_rb*12];
+      ul_ch128          = (__m128i *)&ul_ch_estimates_ext[(aatx<<1)+aarx][symbol*(off+(nb_rb*12))];
+      ul_ch_mag128      = (__m128i *)&ul_ch_mag[(aatx<<1)+aarx][symbol*(off+(nb_rb*12))];
+      ul_ch_mag128b     = (__m128i *)&ul_ch_magb[(aatx<<1)+aarx][symbol*(off+(nb_rb*12))];
+      rxdataF128        = (__m128i *)&rxdataF_ext[aarx][symbol*(off+(nb_rb*12))];
+      rxdataF_comp128   = (__m128i *)&rxdataF_comp[(aatx<<1)+aarx][symbol*(off+(nb_rb*12))];
 
 
       for (rb=0; rb<nb_rb; rb++) {
@@ -944,7 +984,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext,
 
 #ifdef DEBUG_CH_COMP
 
-  rxF   = (int16_t *)&rxdataF_comp[0][(symbol*nb_rb*12)];
+  rxF   = (int16_t *)&rxdataF_comp[0][(symbol*(off+(nb_rb*12)))];
 
   printf("----------------After compansation------------------\n");
 
@@ -959,7 +999,7 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext,
 #ifdef DEBUG_CH_MAG
 
 
-  ch_mag   = (int16_t *)&ul_ch_mag[0][(symbol*nb_rb*12)];
+  ch_mag   = (int16_t *)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))];
 
   printf("----------------After computation------------------\n");
 
@@ -973,6 +1013,67 @@ void nr_ulsch_channel_compensation(int **rxdataF_ext,
 
 }
 
+void nr_ulsch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms,
+			    int32_t **rxdataF_comp,
+			    int32_t **ul_ch_mag,
+			    int32_t **ul_ch_magb,
+			    uint8_t symbol,
+			    uint16_t nb_rb) {
+  int n_rx = frame_parms->nb_antennas_rx;
+#if defined(__x86_64__) || defined(__i386__)
+  __m128i *rxdataF_comp128[1+n_rx],*ul_ch_mag128[1+n_rx],*ul_ch_mag128b[1+n_rx];
+#elif defined(__arm__)
+  int16x8_t *rxdataF_comp128_0,*ul_ch_mag128_0,*ul_ch_mag128_0b;
+  int16x8_t *rxdataF_comp128_1,*ul_ch_mag128_1,*ul_ch_mag128_1b;
+#endif
+  int32_t i;
+
+#ifdef __AVX2__
+  int off = ((nb_rb&1) == 1)? 4:0;
+#else
+  int off = 0;
+#endif
+
+  if (frame_parms->nb_antennas_rx>1) {
+#if defined(__x86_64__) || defined(__i386__)
+    int nb_re = nb_rb*12;
+    for (int aa=0;aa<frame_parms->nb_antennas_rx;aa++) {
+      rxdataF_comp128[aa]   = (__m128i *)&rxdataF_comp[aa][(symbol*(nb_re + off))];
+      ul_ch_mag128[aa]      = (__m128i *)&ul_ch_mag[aa][(symbol*(nb_re + off))];
+      ul_ch_mag128b[aa]     = (__m128i *)&ul_ch_magb[aa][(symbol*(nb_re + off))];
+      
+      // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
+      for (i=0; i<nb_rb*3; i++) {
+	rxdataF_comp128[0][i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128[aa][i],1),_mm_srai_epi16(rxdataF_comp128[aa][i],1));
+	ul_ch_mag128[0][i]    = _mm_adds_epi16(_mm_srai_epi16(ul_ch_mag128[aa][i],1),_mm_srai_epi16(ul_ch_mag128[aa][i],1));
+	ul_ch_mag128b[0][i]   = _mm_adds_epi16(_mm_srai_epi16(ul_ch_mag128b[aa][i],1),_mm_srai_epi16(ul_ch_mag128b[aa][i],1));
+	//	rxdataF_comp128[0][i] = _mm_add_epi16(rxdataF_comp128_0[i],(*(__m128i *)&jitterc[0]));
+      }
+    }
+#elif defined(__arm__)
+    rxdataF_comp128_0   = (int16x8_t *)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
+    rxdataF_comp128_1   = (int16x8_t *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12];
+    ul_ch_mag128_0      = (int16x8_t *)&ul_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
+    ul_ch_mag128_1      = (int16x8_t *)&ul_ch_mag[1][symbol*frame_parms->N_RB_DL*12];
+    ul_ch_mag128_0b     = (int16x8_t *)&ul_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
+    ul_ch_mag128_1b     = (int16x8_t *)&ul_ch_magb[1][symbol*frame_parms->N_RB_DL*12];
+      
+    // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
+    for (i=0; i<nb_rb*3; i++) {
+      rxdataF_comp128_0[i] = vhaddq_s16(rxdataF_comp128_0[i],rxdataF_comp128_1[i]);
+      ul_ch_mag128_0[i]    = vhaddq_s16(ul_ch_mag128_0[i],ul_ch_mag128_1[i]);
+      ul_ch_mag128_0b[i]   = vhaddq_s16(ul_ch_mag128_0b[i],ul_ch_mag128_1b[i]);
+      rxdataF_comp128_0[i] = vqaddq_s16(rxdataF_comp128_0[i],(*(int16x8_t *)&jitterc[0]));
+    }
+#endif
+  }
+
+#if defined(__x86_64__) || defined(__i386__)
+  _mm_empty();
+  _m_empty();
+#endif
+}
+
 int nr_rx_pusch(PHY_VARS_gNB *gNB,
                 uint8_t ulsch_id,
                 uint32_t frame,
@@ -991,15 +1092,18 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
   dmrs_symbol_flag = 0;
 
   if(symbol == rel15_ul->start_symbol_index){
-    gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset = 0;
     gNB->pusch_vars[ulsch_id]->dmrs_symbol = 0;
     gNB->pusch_vars[ulsch_id]->cl_done = 0;
   }
 
+
   bwp_start_subcarrier = (rel15_ul->rb_start*NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size;
 
   dmrs_symbol_flag = ((rel15_ul->ul_dmrs_symb_pos)>>symbol)&0x01;
 
+  LOG_D(PHY,"symbol %d bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n",symbol,bwp_start_subcarrier,rel15_ul->rb_start,frame_parms->first_carrier_offset);
+  LOG_D(PHY,"ul_dmrs_symb_pos %x\n",rel15_ul->ul_dmrs_symb_pos);
+
   if (dmrs_symbol_flag == 1){
     if (((rel15_ul->ul_dmrs_symb_pos)>>((symbol+1)%frame_parms->symbols_per_slot))&0x01)
       AssertFatal(1==0,"Double DMRS configuration is not yet supported\n");
@@ -1012,6 +1116,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
     else {
       nb_re_pusch = rel15_ul->rb_size *(12 - (rel15_ul->num_dmrs_cdm_grps_no_data*4));
     }
+    LOG_D(PHY,"dmrs_symbol: nb_re_pusch %d\n",nb_re_pusch);
     gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol;
   } else {
     nb_re_pusch = rel15_ul->rb_size * NR_NB_SC_PER_RB;
@@ -1021,13 +1126,22 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
   //--------------------- Channel estimation ---------------------
   //----------------------------------------------------------
   start_meas(&gNB->ulsch_channel_estimation_stats);
-  if (dmrs_symbol_flag == 1)
+  if (dmrs_symbol_flag == 1) {
     nr_pusch_channel_estimation(gNB,
                                 nr_tti_rx,
                                 0, // p
                                 symbol,
+                                ulsch_id,
                                 bwp_start_subcarrier,
                                 rel15_ul);
+
+    for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
+      gNB->pusch_vars[ulsch_id]->ulsch_power[aarx] = signal_energy(&gNB->pusch_vars[ulsch_id]->ul_ch_estimates[aarx][symbol*frame_parms->ofdm_symbol_size],
+                                                                   rel15_ul->rb_size*12);
+      if (gNB->pusch_vars[ulsch_id]->ulsch_power[aarx]==1) return (1);
+    }
+
+  }
   stop_meas(&gNB->ulsch_channel_estimation_stats);
   //----------------------------------------------------------
   //--------------------- RBs extraction ---------------------
@@ -1074,7 +1188,7 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
         for (aarx=0;aarx<frame_parms->nb_antennas_rx;aarx++)
           avgs = cmax(avgs,avg[(aatx<<1)+aarx]);
 
-      gNB->pusch_vars[ulsch_id]->log2_maxh = (log2_approx(avgs)/2)+1;
+      gNB->pusch_vars[ulsch_id]->log2_maxh = (log2_approx(avgs)/2)+3;
       gNB->pusch_vars[ulsch_id]->cl_done = 1;
     }
 
@@ -1097,18 +1211,19 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
                                   gNB->pusch_vars[ulsch_id]->log2_maxh);
     stop_meas(&gNB->ulsch_channel_compensation_stats);
 
-
-    int rxsig = signal_energy(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][(symbol*rel15_ul->rb_size*12)],
-                              rel15_ul->rb_size*12);
-
-    if (rxsig==1) return (rxsig);
-
+    start_meas(&gNB->ulsch_mrc_stats);
+    nr_ulsch_detection_mrc(frame_parms,
+			   gNB->pusch_vars[ulsch_id]->rxdataF_comp,
+			   gNB->pusch_vars[ulsch_id]->ul_ch_mag,
+			   gNB->pusch_vars[ulsch_id]->ul_ch_magb,
+			   symbol,
+			   rel15_ul->rb_size);
+    stop_meas(&gNB->ulsch_mrc_stats);
 #ifdef NR_SC_FDMA
     nr_idft(&((uint32_t*)gNB->pusch_vars[ulsch_id]->rxdataF_ext[0])[symbol * rel15_ul->rb_size * NR_NB_SC_PER_RB], nb_re_pusch);
 #endif
 
 
-
     //----------------------------------------------------------
     //--------------------- PTRS Processing --------------------
     //----------------------------------------------------------
@@ -1136,20 +1251,25 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
     /*-----------------------------------------------------------------------------------------------------*/
     if(symbol == (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols -1))
     {
-      for(uint8_t i =rel15_ul->start_symbol_index; i< (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols);i++)
-        {
-          start_meas(&gNB->ulsch_llr_stats);
-          nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][i * (rel15_ul->rb_size * NR_NB_SC_PER_RB)],
-                               gNB->pusch_vars[ulsch_id]->ul_ch_mag0,
-                               gNB->pusch_vars[ulsch_id]->ul_ch_magb0,
-                               &gNB->pusch_vars[ulsch_id]->llr[gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset * rel15_ul->qam_mod_order],
-                               rel15_ul->rb_size,
-                               gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i],
-                               i,
-                               rel15_ul->qam_mod_order);
-          stop_meas(&gNB->ulsch_llr_stats);
-          gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset = gNB->pusch_vars[ulsch_id]->rxdataF_ext_offset +  gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i];
-        }// symbol loop
+#ifdef __AVX2__
+      int off = ((rel15_ul->rb_size&1) == 1)? 4:0;
+#else
+      int off = 0;
+#endif
+      uint32_t rxdataF_ext_offset = 0;
+      for(uint8_t i =rel15_ul->start_symbol_index; i< (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols);i++) {
+        start_meas(&gNB->ulsch_llr_stats);
+        nr_ulsch_compute_llr(&gNB->pusch_vars[ulsch_id]->rxdataF_comp[0][i * (off + rel15_ul->rb_size * NR_NB_SC_PER_RB)],
+                             gNB->pusch_vars[ulsch_id]->ul_ch_mag0,
+                             gNB->pusch_vars[ulsch_id]->ul_ch_magb0,
+                             &gNB->pusch_vars[ulsch_id]->llr[rxdataF_ext_offset * rel15_ul->qam_mod_order],
+                             rel15_ul->rb_size,
+                             gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i],
+                             i,
+                             rel15_ul->qam_mod_order);
+        stop_meas(&gNB->ulsch_llr_stats);
+        rxdataF_ext_offset += gNB->pusch_vars[ulsch_id]->ul_valid_re_per_slot[i];
+      }// symbol loop
     }// last symbol check
   }
   return (0);
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c
index 233ecd8de7dd4f709129a58c72318a82383f480a..bf96a761060489ece5b08afb9419a45343a60d71 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c
@@ -34,9 +34,6 @@
 #include "PHY/sse_intrin.h"
 #include "PHY/impl_defs_top.h"
 
-__m128i  xmm0 __attribute__ ((aligned(32)));
-__m128i  xmm1 __attribute__ ((aligned(32)));
-__m128i  xmm2 __attribute__ ((aligned(32)));
 
 
 //----------------------------------------------------------------------------------------------
@@ -47,20 +44,19 @@ void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp,
                       uint32_t nb_re,
                       uint8_t  symbol)
 {
-  int i;
-
   uint32_t *rxF   = (uint32_t*)rxdataF_comp;
   uint32_t *llr32 = (uint32_t*)ulsch_llr;
 
   if (!llr32) {
     LOG_E(PHY,"nr_ulsch_qpsk_llr: llr is null, symbol %d, llr32 = %p\n",symbol, llr32);
   }
-
+  /*
   for (i = 0; i < nb_re; i++) {
     *llr32 = *rxF;
     rxF++;
     llr32++;
-  }
+    }*/
+  memcpy1((void*)llr32,(void*)rxF,nb_re<<2);
 }
 
 //----------------------------------------------------------------------------------------------
@@ -76,9 +72,17 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp,
 {
 
 #if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+  __m256i *rxF = (__m256i*)rxdataF_comp;
+  __m256i *ch_mag;
+  __m256i llr256[2];
+  register __m256i xmm0;
+#else
   __m128i *rxF = (__m128i*)rxdataF_comp;
   __m128i *ch_mag;
   __m128i llr128[2];
+  register __m128i xmm0;
+#endif
   uint32_t *llr32;
 
 #elif defined(__arm__)
@@ -90,7 +94,12 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp,
 
 
   int i;
-  unsigned char len_mod4 = 0;
+
+#ifdef __AVX2__
+  int off = ((nb_rb&1) == 1)? 4:0;
+#else
+  int off = 0;
+#endif
 
 
 #if defined(__x86_64__) || defined(__i386__)
@@ -100,22 +109,69 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp,
 #endif
 
 #if defined(__x86_64__) || defined(__i386__)
-  ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*nb_rb*12)];
+#ifdef __AVX2__
+    ch_mag = (__m256i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))];
+#else
+    ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))];
+#endif
 #elif defined(__arm__)
   ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*nb_rb*12)];
 #endif
 
-  len_mod4 = nb_re&3;
+#ifdef __AVX2__
+  unsigned char len_mod8 = nb_re&7;
+  nb_re >>= 3;  // length in quad words (4 REs)
+  nb_re += (len_mod8 == 0 ? 0 : 1);
+#else
+  unsigned char len_mod4 = nb_re&3;
   nb_re >>= 2;  // length in quad words (4 REs)
   nb_re += (len_mod4 == 0 ? 0 : 1);
+#endif
 
   for (i=0; i<nb_re; i++) {
-
 #if defined(__x86_64__) || defined(__i386)
+#ifdef __AVX2__
+    xmm0 = _mm256_abs_epi16(rxF[i]); // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I|
+    xmm0 = _mm256_subs_epi16(ch_mag[i],xmm0); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2
+ 
+    llr256[0] = _mm256_unpacklo_epi32(rxF[i],xmm0); // llr128[0] contains the llrs of the 1st,2nd,5th and 6th REs
+    llr256[1] = _mm256_unpackhi_epi32(rxF[i],xmm0); // llr128[1] contains the llrs of the 3rd, 4th, 7th and 8th REs
+    
+    // 1st RE
+    llr32[0] = _mm256_extract_epi32(llr256[0],0); // llr32[0] low 16 bits-> y_R        , high 16 bits-> y_I
+    llr32[1] = _mm256_extract_epi32(llr256[0],1); // llr32[1] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2
+
+    // 2nd RE
+    llr32[2] = _mm256_extract_epi32(llr256[0],2); // llr32[2] low 16 bits-> y_R        , high 16 bits-> y_I
+    llr32[3] = _mm256_extract_epi32(llr256[0],3); // llr32[3] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2
+
+    // 3rd RE
+    llr32[4] = _mm256_extract_epi32(llr256[1],0); // llr32[4] low 16 bits-> y_R        , high 16 bits-> y_I
+    llr32[5] = _mm256_extract_epi32(llr256[1],1); // llr32[5] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2
+
+    // 4th RE
+    llr32[6] = _mm256_extract_epi32(llr256[1],2); // llr32[6] low 16 bits-> y_R        , high 16 bits-> y_I
+    llr32[7] = _mm256_extract_epi32(llr256[1],3); // llr32[7] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2
+
+    // 5th RE
+    llr32[8] = _mm256_extract_epi32(llr256[0],4); // llr32[8] low 16 bits-> y_R        , high 16 bits-> y_I
+    llr32[9] = _mm256_extract_epi32(llr256[0],5); // llr32[9] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2
 
+    // 6th RE
+    llr32[10] = _mm256_extract_epi32(llr256[0],6); // llr32[10] low 16 bits-> y_R        , high 16 bits-> y_I
+    llr32[11] = _mm256_extract_epi32(llr256[0],7); // llr32[11] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2
+
+    // 7th RE
+    llr32[12] = _mm256_extract_epi32(llr256[1],4); // llr32[12] low 16 bits-> y_R        , high 16 bits-> y_I
+    llr32[13] = _mm256_extract_epi32(llr256[1],5); // llr32[13] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2
+
+    // 8th RE
+    llr32[14] = _mm256_extract_epi32(llr256[1],6); // llr32[14] low 16 bits-> y_R        , high 16 bits-> y_I
+    llr32[15] = _mm256_extract_epi32(llr256[1],7); // llr32[15] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2
+
+    llr32+=16;
+#else
     xmm0 = _mm_abs_epi16(rxF[i]); // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I|
-    
-    
     xmm0 = _mm_subs_epi16(ch_mag[i],xmm0); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2
 
     llr128[0] = _mm_unpacklo_epi32(rxF[i],xmm0); // llr128[0] contains the llrs of the 1st and 2nd REs
@@ -138,6 +194,7 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp,
     llr32[7] = _mm_extract_epi32(llr128[1],3); // llr32[7] low 16 bits-> |h|-|y_R|^2, high 16 bits-> |h|-|y_I|^2
 
     llr32+=8;
+#endif
 #elif defined(__arm__)
     xmm0 = vabsq_s16(rxF[i]);
     xmm0 = vqsubq_s16((*(__m128i*)&ones[0]),xmm0);
@@ -182,40 +239,69 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp,
                         uint8_t  symbol)
 {
 
+#ifdef __AVX2__
+  int off = ((nb_rb&1) == 1)? 4:0;
+#else
+  int off = 0;
+#endif
+
 #if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+  __m256i *rxF = (__m256i*)rxdataF_comp;
+  __m256i *ch_mag,*ch_magb;
+  register __m256i xmm0,xmm1,xmm2;
+#else
   __m128i *rxF = (__m128i*)rxdataF_comp;
   __m128i *ch_mag,*ch_magb;
+  register __m128i xmm0,xmm1,xmm2;
+#endif
 #elif defined(__arm__)
   int16x8_t *rxF = (int16x8_t*)&rxdataF_comp;
   int16x8_t *ch_mag,*ch_magb; // [hna] This should be uncommented once channel estimation is implemented
-  int16x8_t xmm1,xmm2;
+  int16x8_t xmm0,xmm1,xmm2;
 #endif
 
   int i;
-  unsigned char len_mod4;
 
 #if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+  ch_mag = (__m256i*)&ul_ch_mag[0][(symbol*(off+(nb_rb*12)))];
+  ch_magb = (__m256i*)&ul_ch_magb[0][(symbol*(off+(nb_rb*12)))];
+#else
   ch_mag = (__m128i*)&ul_ch_mag[0][(symbol*nb_rb*12)];
   ch_magb = (__m128i*)&ul_ch_magb[0][(symbol*nb_rb*12)];
+#endif
 #elif defined(__arm__)
   ch_mag = (int16x8_t*)&ul_ch_mag[0][(symbol*nb_rb*12)];
   ch_magb = (int16x8_t*)&ul_ch_magb[0][(symbol*nb_rb*12)];
 #endif
 
-  len_mod4 = nb_re&3;
+#ifdef __AVX2__
+  int len_mod8 = nb_re&7;
+  nb_re    = nb_re>>3;  // length in quad words (4 REs)
+  nb_re   += ((len_mod8 == 0) ? 0 : 1);
+#else
+  int len_mod4 = nb_re&3;
   nb_re    = nb_re>>2;  // length in quad words (4 REs)
   nb_re   += ((len_mod4 == 0) ? 0 : 1);
-
+#endif
 
   for (i=0; i<nb_re; i++) {
-
+    xmm0 = rxF[i];
 #if defined(__x86_64__) || defined(__i386__)
-    xmm1 = _mm_abs_epi16(rxF[i]);
+#ifdef __AVX2__
+    xmm1 = _mm256_abs_epi16(xmm0);
+    xmm1 = _mm256_subs_epi16(ch_mag[i],xmm1);
+    xmm2 = _mm256_abs_epi16(xmm1);
+    xmm2 = _mm256_subs_epi16(ch_magb[i],xmm2);
+#else
+    xmm1 = _mm_abs_epi16(xmm0);
     xmm1 = _mm_subs_epi16(ch_mag[i],xmm1);
     xmm2 = _mm_abs_epi16(xmm1);
     xmm2 = _mm_subs_epi16(ch_magb[i],xmm2);
+#endif
 #elif defined(__arm__)
-    xmm1 = vabsq_s16(rxF[i]);
+    xmm1 = vabsq_s16(xmm0);
     xmm1 = vsubq_s16(ch_mag[i],xmm1);
     xmm2 = vabsq_s16(xmm1);
     xmm2 = vsubq_s16(ch_magb[i],xmm2);
@@ -224,14 +310,25 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp,
     // ---------------------------------------
     // 1st RE
     // ---------------------------------------
-    ulsch_llr[0] = ((short *)&rxF[i])[0];
-    ulsch_llr[1] = ((short *)&rxF[i])[1];
 #if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+    ulsch_llr[0] = _mm256_extract_epi16(xmm0,0);
+    ulsch_llr[1] = _mm256_extract_epi16(xmm0,1);
+    ulsch_llr[2] = _mm256_extract_epi16(xmm1,0);
+    ulsch_llr[3] = _mm256_extract_epi16(xmm1,1);
+    ulsch_llr[4] = _mm256_extract_epi16(xmm2,0);
+    ulsch_llr[5] = _mm256_extract_epi16(xmm2,1);
+#else
+    ulsch_llr[0] = _mm_extract_epi16(xmm0,0);
+    ulsch_llr[1] = _mm_extract_epi16(xmm0,1);
     ulsch_llr[2] = _mm_extract_epi16(xmm1,0);
     ulsch_llr[3] = _mm_extract_epi16(xmm1,1);
     ulsch_llr[4] = _mm_extract_epi16(xmm2,0);
     ulsch_llr[5] = _mm_extract_epi16(xmm2,1);
+#endif
 #elif defined(__arm__)
+    ulsch_llr[0] = vgetq_lane_s16(xmm0,0);
+    ulsch_llr[1] = vgetq_lane_s16(xmm0,1);
     ulsch_llr[2] = vgetq_lane_s16(xmm1,0);
     ulsch_llr[3] = vgetq_lane_s16(xmm1,1);
     ulsch_llr[4] = vgetq_lane_s16(xmm2,0);
@@ -244,14 +341,25 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp,
     // ---------------------------------------
     // 2nd RE
     // ---------------------------------------
-    ulsch_llr[0] = ((short *)&rxF[i])[2];
-    ulsch_llr[1] = ((short *)&rxF[i])[3];
 #if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+    ulsch_llr[0] = _mm256_extract_epi16(xmm0,2);
+    ulsch_llr[1] = _mm256_extract_epi16(xmm0,3);
+    ulsch_llr[2] = _mm256_extract_epi16(xmm1,2);
+    ulsch_llr[3] = _mm256_extract_epi16(xmm1,3);
+    ulsch_llr[4] = _mm256_extract_epi16(xmm2,2);
+    ulsch_llr[5] = _mm256_extract_epi16(xmm2,3);
+#else
+    ulsch_llr[0] = _mm_extract_epi16(xmm0,2);
+    ulsch_llr[1] = _mm_extract_epi16(xmm0,3);
     ulsch_llr[2] = _mm_extract_epi16(xmm1,2);
     ulsch_llr[3] = _mm_extract_epi16(xmm1,3);
     ulsch_llr[4] = _mm_extract_epi16(xmm2,2);
     ulsch_llr[5] = _mm_extract_epi16(xmm2,3);
+#endif
 #elif defined(__arm__)
+    ulsch_llr[2] = vgetq_lane_s16(xmm0,2);
+    ulsch_llr[3] = vgetq_lane_s16(xmm0,3);
     ulsch_llr[2] = vgetq_lane_s16(xmm1,2);
     ulsch_llr[3] = vgetq_lane_s16(xmm1,3);
     ulsch_llr[4] = vgetq_lane_s16(xmm2,2);
@@ -264,14 +372,25 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp,
     // ---------------------------------------
     // 3rd RE
     // ---------------------------------------
-    ulsch_llr[0] = ((short *)&rxF[i])[4];
-    ulsch_llr[1] = ((short *)&rxF[i])[5];
 #if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+    ulsch_llr[0] = _mm256_extract_epi16(xmm0,4);
+    ulsch_llr[1] = _mm256_extract_epi16(xmm0,5);
+    ulsch_llr[2] = _mm256_extract_epi16(xmm1,4);
+    ulsch_llr[3] = _mm256_extract_epi16(xmm1,5);
+    ulsch_llr[4] = _mm256_extract_epi16(xmm2,4);
+    ulsch_llr[5] = _mm256_extract_epi16(xmm2,5);
+#else
+    ulsch_llr[0] = _mm_extract_epi16(xmm0,4);
+    ulsch_llr[1] = _mm_extract_epi16(xmm0,5);
     ulsch_llr[2] = _mm_extract_epi16(xmm1,4);
     ulsch_llr[3] = _mm_extract_epi16(xmm1,5);
     ulsch_llr[4] = _mm_extract_epi16(xmm2,4);
     ulsch_llr[5] = _mm_extract_epi16(xmm2,5);
+#endif
 #elif defined(__arm__)
+    ulsch_llr[0] = vgetq_lane_s16(xmm0,4);
+    ulsch_llr[1] = vgetq_lane_s16(xmm0,5);
     ulsch_llr[2] = vgetq_lane_s16(xmm1,4);
     ulsch_llr[3] = vgetq_lane_s16(xmm1,5);
     ulsch_llr[4] = vgetq_lane_s16(xmm2,4);
@@ -284,14 +403,25 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp,
     // ---------------------------------------
     // 4th RE
     // ---------------------------------------
-    ulsch_llr[0] = ((short *)&rxF[i])[6];
-    ulsch_llr[1] = ((short *)&rxF[i])[7];
 #if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+    ulsch_llr[0] = _mm256_extract_epi16(xmm0,6);
+    ulsch_llr[1] = _mm256_extract_epi16(xmm0,7);
+    ulsch_llr[2] = _mm256_extract_epi16(xmm1,6);
+    ulsch_llr[3] = _mm256_extract_epi16(xmm1,7);
+    ulsch_llr[4] = _mm256_extract_epi16(xmm2,6);
+    ulsch_llr[5] = _mm256_extract_epi16(xmm2,7);
+#else
+    ulsch_llr[0] = _mm_extract_epi16(xmm0,6);
+    ulsch_llr[1] = _mm_extract_epi16(xmm0,7);
     ulsch_llr[2] = _mm_extract_epi16(xmm1,6);
     ulsch_llr[3] = _mm_extract_epi16(xmm1,7);
     ulsch_llr[4] = _mm_extract_epi16(xmm2,6);
     ulsch_llr[5] = _mm_extract_epi16(xmm2,7);
+#endif
 #elif defined(__arm__)
+    ulsch_llr[0] = vgetq_lane_s16(xmm0,6);
+    ulsch_llr[1] = vgetq_lane_s16(xmm0,7);
     ulsch_llr[2] = vgetq_lane_s16(xmm1,6);
     ulsch_llr[3] = vgetq_lane_s16(xmm1,7);
     ulsch_llr[4] = vgetq_lane_s16(xmm2,6);
@@ -300,6 +430,37 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp,
     // ---------------------------------------
 
     ulsch_llr+=6;
+#ifdef __AVX2__
+    ulsch_llr[0] = _mm256_extract_epi16(xmm0,8);
+    ulsch_llr[1] = _mm256_extract_epi16(xmm0,9);
+    ulsch_llr[2] = _mm256_extract_epi16(xmm1,8);
+    ulsch_llr[3] = _mm256_extract_epi16(xmm1,9);
+    ulsch_llr[4] = _mm256_extract_epi16(xmm2,8);
+    ulsch_llr[5] = _mm256_extract_epi16(xmm2,9);
+
+    ulsch_llr[6] = _mm256_extract_epi16(xmm0,10);
+    ulsch_llr[7] = _mm256_extract_epi16(xmm0,11);
+    ulsch_llr[8] = _mm256_extract_epi16(xmm1,10);
+    ulsch_llr[9] = _mm256_extract_epi16(xmm1,11);
+    ulsch_llr[10] = _mm256_extract_epi16(xmm2,10);
+    ulsch_llr[11] = _mm256_extract_epi16(xmm2,11);
+
+    ulsch_llr[12] = _mm256_extract_epi16(xmm0,12);
+    ulsch_llr[13] = _mm256_extract_epi16(xmm0,13);
+    ulsch_llr[14] = _mm256_extract_epi16(xmm1,12);
+    ulsch_llr[15] = _mm256_extract_epi16(xmm1,13);
+    ulsch_llr[16] = _mm256_extract_epi16(xmm2,12);
+    ulsch_llr[17] = _mm256_extract_epi16(xmm2,13);
+
+    ulsch_llr[18] = _mm256_extract_epi16(xmm0,14);
+    ulsch_llr[19] = _mm256_extract_epi16(xmm0,15);
+    ulsch_llr[20] = _mm256_extract_epi16(xmm1,14);
+    ulsch_llr[21] = _mm256_extract_epi16(xmm1,15);
+    ulsch_llr[22] = _mm256_extract_epi16(xmm2,14);
+    ulsch_llr[23] = _mm256_extract_epi16(xmm2,15);
+
+    ulsch_llr+=24;
+#endif
   }
 
 #if defined(__x86_64__) || defined(__i386__)
diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c
index c41752cffb09a51f35eb431b38df9a46e9b91bb7..71132b64c55a282221ad841d3bab04b3cedeb8ff 100644
--- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c
+++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c
@@ -315,7 +315,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB,
   int16_t xr[24]  __attribute__((aligned(32)));
   //int16_t xrt[24] __attribute__((aligned(32)));
   int32_t xrtmag=0;
-  int maxpos=0;
+  uint8_t maxpos=0;
   int n2=0;
   uint8_t index=0;
   memset((void*)xr,0,24*sizeof(int16_t));
@@ -339,7 +339,8 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB,
 #endif
     }
   }
-  int32_t corr_re,corr_im,temp;
+  int32_t corr_re,corr_im,temp,no_corr=0;
+  int32_t av_corr=0;
   int seq_index;
 
   for(i=0;i<nr_sequences;i++){
@@ -359,63 +360,81 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB,
 #ifdef DEBUG_NR_PUCCH_RX
     printf("PUCCH IDFT[%d/%d] = (%d,%d)=>%f\n",mcs[i],seq_index,corr_re,corr_im,10*log10(corr_re*corr_re + corr_im*corr_im));
 #endif
-    if ((temp=corr_re*corr_re + corr_im*corr_im)>xrtmag) {
+    temp=corr_re*corr_re + corr_im*corr_im;
+    av_corr+=temp;
+    if (temp>xrtmag) {
       xrtmag=temp;
       maxpos=i;
     }
   }
+  if(nr_sequences>1)
+    no_corr=(av_corr-xrtmag)/(nr_sequences-1);
+  av_corr/=nr_sequences;
 
   uint8_t xrtmag_dB = dB_fixed(xrtmag);
-  
-//#ifdef DEBUG_NR_PUCCH_RX
+ 
+#ifdef DEBUG_NR_PUCCH_RX
   printf("PUCCH 0 : maxpos %d\n",maxpos);
-//#endif
+#endif
 
   index=maxpos;
 #endif
+
+  // estimate CQI for MAC (from antenna port 0 only)
+  int SNRtimes10 = dB_fixed_times10(signal_energy(&rxdataF[0][pucch_pdu->start_symbol_index*frame_parms->ofdm_symbol_size+re_offset],12)) - (10*gNB->measurements.n0_power_tot_dB);
+  int cqi;
+  if (SNRtimes10 < -640) cqi=0;
+  else if (SNRtimes10 >  635) cqi=255;
+  else cqi=(640+SNRtimes10)/5;
+
+  bool no_conf=false;
+  if (nr_sequences>1) {
+    if ((xrtmag_dB<(11+dB_fixed(no_corr))) || (dB_fixed(av_corr)<(13+gNB->measurements.n0_power_tot_dB))) //TODO  these are temporary threshold based on measurments with the phone
+      no_conf=true;
+  }
   // first bit of bitmap for sr presence and second bit for acknack presence
   uci_pdu->pduBitmap = pucch_pdu->sr_flag | ((pucch_pdu->bit_len_harq>0)<<1);
   uci_pdu->pucch_format = 0; // format 0
-  uci_pdu->ul_cqi = 0xff; // currently not valid
+  uci_pdu->ul_cqi = cqi; // currently not valid
   uci_pdu->timing_advance = 0xffff; // currently not valid
-  uci_pdu->rssi = 0xffff; // currently not valid
-
+  uci_pdu->rssi = 1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(signal_energy(&rxdataF[0][pucch_pdu->start_symbol_index*frame_parms->ofdm_symbol_size+re_offset],12)));
   if (pucch_pdu->bit_len_harq==0) {
     uci_pdu->harq = NULL;
     uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr));
-    if (xrtmag_dB>(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres)) {
+    uci_pdu->sr->sr_confidence_level = (xrtmag_dB<(13+gNB->measurements.n0_power_tot_dB)) ? 1 : 0;
+    if (xrtmag_dB>(gNB->measurements.n0_power_tot_dB)) {
       uci_pdu->sr->sr_indication = 1;
-      uci_pdu->sr->sr_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
     } else {
       uci_pdu->sr->sr_indication = 0;
-      uci_pdu->sr->sr_confidence_level = (gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres)-xrtmag_dB;
     }
   }
   else if (pucch_pdu->bit_len_harq==1) {
     uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq));
     uci_pdu->harq->num_harq = 1;
-    uci_pdu->harq->harq_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
+    uci_pdu->harq->harq_confidence_level = (no_conf) ? 1 : 0;
     uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(1);
     uci_pdu->harq->harq_list[0].harq_value = index&0x01;
+    LOG_I(PHY, "HARQ value %d with confidence level (0 is good, 1 is bad) %d\n",
+          uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level);
     if (pucch_pdu->sr_flag == 1) {
       uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr));
       uci_pdu->sr->sr_indication = (index>1) ? 1 : 0;
-      uci_pdu->sr->sr_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
+      uci_pdu->sr->sr_confidence_level = (no_conf) ? 1 : 0;
     }
   }
   else {
     uci_pdu->harq = calloc(1,sizeof(*uci_pdu->harq));
     uci_pdu->harq->num_harq = 2;
-    uci_pdu->harq->harq_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
+    uci_pdu->harq->harq_confidence_level = (no_conf) ? 1 : 0;
     uci_pdu->harq->harq_list = (nfapi_nr_harq_t*)malloc(2);
-
     uci_pdu->harq->harq_list[1].harq_value = index&0x01;
     uci_pdu->harq->harq_list[0].harq_value = (index>>1)&0x01;
-
+    LOG_I(PHY, "HARQ values %d and %d with confidence level (0 is good, 1 is bad) %d\n",
+          uci_pdu->harq->harq_list[1].harq_value,uci_pdu->harq->harq_list[0].harq_value,uci_pdu->harq->harq_confidence_level);
     if (pucch_pdu->sr_flag == 1) {
       uci_pdu->sr = calloc(1,sizeof(*uci_pdu->sr));
       uci_pdu->sr->sr_indication = (index>3) ? 1 : 0;
-      uci_pdu->sr->sr_confidence_level = xrtmag_dB-(gNB->measurements.n0_subband_power_tot_dB[pucch_pdu->prb_start]+gNB->pucch0_thres);
+      uci_pdu->sr->sr_confidence_level = (no_conf) ? 1 : 0;
     }
   }
 }
@@ -1058,7 +1077,7 @@ void init_pucch2_luts() {
 	  ((int16_t *)lut_num_i)[5],
 	  ((int16_t *)lut_num_i)[6],
 	  ((int16_t *)lut_num_i)[7]);
-#endif 
+#endif
   }
 }
 
@@ -1421,56 +1440,60 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB,
       }
       printf("\n");
 #endif
-      // do complex correlation
-      for (int aa=0;aa<Prx;aa++) {
-	prod_re[aa] = _mm256_srai_epi16(_mm256_adds_epi16(_mm256_mullo_epi16(pucch2_lut[nb_bit-3][cw<<1],rp_re[aa][0]),
-							  _mm256_mullo_epi16(pucch2_lut[nb_bit-3][(cw<<1)+1],rp_im[aa][0])),5);
-	prod_im[aa] = _mm256_srai_epi16(_mm256_subs_epi16(_mm256_mullo_epi16(pucch2_lut[nb_bit-3][cw<<1],rp2_im[aa][0]),
-							  _mm256_mullo_epi16(pucch2_lut[nb_bit-3][(cw<<1)+1],rp2_re[aa][0])),5);
-#ifdef DEBUG_NR_PUCCH_RX
-	printf("prod_re[%d] => (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",aa,
-	       ((int16_t*)&prod_re[aa])[0],((int16_t*)&prod_re[aa])[1],((int16_t*)&prod_re[aa])[2],((int16_t*)&prod_re[aa])[3],
-	       ((int16_t*)&prod_re[aa])[4],((int16_t*)&prod_re[aa])[5],((int16_t*)&prod_re[aa])[6],((int16_t*)&prod_re[aa])[7],
-	       ((int16_t*)&prod_re[aa])[8],((int16_t*)&prod_re[aa])[9],((int16_t*)&prod_re[aa])[10],((int16_t*)&prod_re[aa])[11],
-	       ((int16_t*)&prod_re[aa])[12],((int16_t*)&prod_re[aa])[13],((int16_t*)&prod_re[aa])[14],((int16_t*)&prod_re[aa])[15]);
-	printf("prod_im[%d] => (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",aa,
-	       ((int16_t*)&prod_im[aa])[0],((int16_t*)&prod_im[aa])[1],((int16_t*)&prod_im[aa])[2],((int16_t*)&prod_im[aa])[3],
-	       ((int16_t*)&prod_im[aa])[4],((int16_t*)&prod_im[aa])[5],((int16_t*)&prod_im[aa])[6],((int16_t*)&prod_im[aa])[7],
-	       ((int16_t*)&prod_im[aa])[8],((int16_t*)&prod_im[aa])[9],((int16_t*)&prod_im[aa])[10],((int16_t*)&prod_im[aa])[11],
-	       ((int16_t*)&prod_im[aa])[12],((int16_t*)&prod_im[aa])[13],((int16_t*)&prod_im[aa])[14],((int16_t*)&prod_im[aa])[15]);
+      int64_t corr_tmp = 0;
 
+      for (int group=0;group<ngroup;group++) {
+	// do complex correlation
+	for (int aa=0;aa<Prx;aa++) {
+	  prod_re[aa] = _mm256_srai_epi16(_mm256_adds_epi16(_mm256_mullo_epi16(pucch2_lut[nb_bit-3][cw<<1],rp_re[aa][group]),
+							    _mm256_mullo_epi16(pucch2_lut[nb_bit-3][(cw<<1)+1],rp_im[aa][group])),5);
+	  prod_im[aa] = _mm256_srai_epi16(_mm256_subs_epi16(_mm256_mullo_epi16(pucch2_lut[nb_bit-3][cw<<1],rp2_im[aa][group]),
+							    _mm256_mullo_epi16(pucch2_lut[nb_bit-3][(cw<<1)+1],rp2_re[aa][group])),5);
+#ifdef DEBUG_NR_PUCCH_RX
+	  printf("prod_re[%d] => (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",aa,
+		 ((int16_t*)&prod_re[aa])[0],((int16_t*)&prod_re[aa])[1],((int16_t*)&prod_re[aa])[2],((int16_t*)&prod_re[aa])[3],
+		 ((int16_t*)&prod_re[aa])[4],((int16_t*)&prod_re[aa])[5],((int16_t*)&prod_re[aa])[6],((int16_t*)&prod_re[aa])[7],
+		 ((int16_t*)&prod_re[aa])[8],((int16_t*)&prod_re[aa])[9],((int16_t*)&prod_re[aa])[10],((int16_t*)&prod_re[aa])[11],
+		 ((int16_t*)&prod_re[aa])[12],((int16_t*)&prod_re[aa])[13],((int16_t*)&prod_re[aa])[14],((int16_t*)&prod_re[aa])[15]);
+	  printf("prod_im[%d] => (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",aa,
+		 ((int16_t*)&prod_im[aa])[0],((int16_t*)&prod_im[aa])[1],((int16_t*)&prod_im[aa])[2],((int16_t*)&prod_im[aa])[3],
+		 ((int16_t*)&prod_im[aa])[4],((int16_t*)&prod_im[aa])[5],((int16_t*)&prod_im[aa])[6],((int16_t*)&prod_im[aa])[7],
+		 ((int16_t*)&prod_im[aa])[8],((int16_t*)&prod_im[aa])[9],((int16_t*)&prod_im[aa])[10],((int16_t*)&prod_im[aa])[11],
+		 ((int16_t*)&prod_im[aa])[12],((int16_t*)&prod_im[aa])[13],((int16_t*)&prod_im[aa])[14],((int16_t*)&prod_im[aa])[15]);
+	  
 #endif
-	prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1
-	prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
-	prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3
-	prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
-	prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7
-	prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
-	prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15
-	prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
-      }
-      int64_t corr_re=0,corr_im=0;
-      
-      int64_t corr_tmp = 0;
-      for (int aa=0;aa<Prx;aa++) {
-	LOG_D(PHY,"pucch2 cw %d aa %d: (%d,%d)+(%d,%d) = (%d,%d)\n",cw,aa,
-	      corr32_re[0][aa],corr32_im[0][aa],
-	      ((int16_t*)(&prod_re[aa]))[0],
-	      ((int16_t*)(&prod_im[aa]))[0],
-	      corr32_re[0][aa]+((int16_t*)(&prod_re[0]))[0],
-	      corr32_im[0][aa]+((int16_t*)(&prod_im[0]))[0]);
+	  prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1
+	  prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
+	  prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3
+	  prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
+	  prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7
+	  prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
+	  prod_re[aa] = _mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15
+	  prod_im[aa] = _mm256_hadds_epi16(prod_im[aa],prod_im[aa]);
+	}
+	int64_t corr_re=0,corr_im=0;
 	
-	corr_re = ( corr32_re[0][aa]+((int16_t*)(&prod_re[0]))[0]);
-	corr_im = ( corr32_im[0][aa]+((int16_t*)(&prod_im[0]))[0]);
-
-	corr_tmp += corr_re*corr_re + corr_im*corr_im;	
-      }
+	
+	for (int aa=0;aa<Prx;aa++) {
+	  LOG_D(PHY,"pucch2 cw %d group %d aa %d: (%d,%d)+(%d,%d) = (%d,%d)\n",cw,group,aa,
+		corr32_re[group][aa],corr32_im[0][aa],
+		((int16_t*)(&prod_re[aa]))[0],
+		((int16_t*)(&prod_im[aa]))[0],
+		corr32_re[group][aa]+((int16_t*)(&prod_re[aa]))[0],
+		corr32_im[group][aa]+((int16_t*)(&prod_im[aa]))[0]);
+	  
+	  corr_re = ( corr32_re[group][aa]+((int16_t*)(&prod_re[aa]))[0]);
+	  corr_im = ( corr32_im[group][aa]+((int16_t*)(&prod_im[aa]))[0]);
+	  
+	  corr_tmp += corr_re*corr_re + corr_im*corr_im;	
+	} // aa loop
+      }// group loop
 
       if (corr_tmp > corr) {
 	corr = corr_tmp;
 	cw_ML=cw;
       }
-    }
+    } // cw loop
     corr_dB = dB_fixed64((uint64_t)corr);
     LOG_D(PHY,"cw_ML %d, metric %d dB\n",cw_ML,corr_dB);
     decodedPayload[0]=(uint64_t)cw_ML;
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
index 3a2cb3f4361c257252168c4fafbda56f91cbe6ee..36bcb2f3793d228865353c7281b8abfd09f4046f 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
@@ -68,7 +68,7 @@ void free_nr_ue_dlsch(NR_UE_DLSCH_t **dlschptr,uint8_t N_RB_DL)
   if (dlsch) {
     if (N_RB_DL != 273) {
       a_segments = a_segments*N_RB_DL;
-      a_segments = a_segments/273;
+      a_segments = a_segments/273 +1;
     }  
  
 
@@ -283,7 +283,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
   __m128i *pl = (__m128i*)&l;
   
     vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_IN);
-
+  
   //NR_DL_UE_HARQ_t *harq_process = dlsch->harq_processes[0];
 
   if (!dlsch_llr) {
@@ -415,7 +415,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
 
   if (nb_rb != 273) {
     a_segments = a_segments*nb_rb;
-    a_segments = (a_segments + 272) / 273;
+    a_segments = a_segments/273 +1;
   }  
 
   if (harq_process->C > a_segments) {
@@ -590,6 +590,9 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
       // Fixme: correct type is unsigned, but nrLDPC_decoder and all called behind use signed int
       if (check_crc((uint8_t*)llrProcBuf,length_dec,harq_process->F,crc_type)) {
         LOG_D(PHY,"Segment %u CRC OK\n\033[0m",r);
+	if (r==0)
+	  for (int i=0;i<10;i++) LOG_D(PHY,"byte %d : %x\n",i,((uint8_t*)llrProcBuf)[i]);
+
         //Temporary hack
         no_iteration_ldpc = dlsch->max_ldpc_iterations;
         ret = no_iteration_ldpc;
@@ -663,9 +666,8 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
     harq_process->harq_ack.harq_id = harq_pid;
     harq_process->harq_ack.send_harq_status = 1;
     harq_process->errors[harq_process->round]++;
-    // harq_process->round++; // [hna] uncomment this line when HARQ is implemented
 
-    //    printf("Rate: [UE %d] DLSCH: Setting NACK for subframe %d (pid %d, round %d)\n",phy_vars_ue->Mod_id,subframe,harq_pid,harq_process->round);
+    //    printf("Rate: [UE %d] DLSCH: Setting NACK for slot %d (pid %d, round %d)\n",phy_vars_ue->Mod_id,nr_tti_rx,harq_pid,harq_process->round);
     if (harq_process->round >= dlsch->Mlimit) {
       harq_process->status = SCH_IDLE;
       harq_process->round  = 0;
@@ -958,7 +960,7 @@ uint32_t  nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue,
 
   if (nb_rb != 273) {
     a_segments = a_segments*nb_rb;
-    a_segments = a_segments/273;
+    a_segments = a_segments/273 +1;
   }  
 
   if (harq_process->C > a_segments) {
@@ -1536,7 +1538,7 @@ void nr_dlsch_decoding_process(void *arg)
 
   if (nb_rb != 273) {
     a_segments = a_segments*nb_rb;
-    a_segments = a_segments/273;
+    a_segments = a_segments/273 +1;
   }  
 
   if (harq_process->C > a_segments) {
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
index ab3cf4ae90f7cdfe12b75baf484167e3460e27ee..7aa0e357aa060ec0e123bfddb037264aa1123259 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
@@ -159,20 +159,17 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
 
   switch (type) {
   case SI_PDSCH:
-    pdsch_vars = ue->pdsch_vars_SI;
+    pdsch_vars = ue->pdsch_vars[ue->current_thread_id[nr_tti_rx]];
     dlsch = &ue->dlsch_SI[eNB_id];
     dlsch0_harq = dlsch[0]->harq_processes[harq_pid];
 
     break;
 
   case RA_PDSCH:
-    pdsch_vars = ue->pdsch_vars_ra;
+    pdsch_vars = ue->pdsch_vars[ue->current_thread_id[nr_tti_rx]];
     dlsch = &ue->dlsch_ra[eNB_id];
     dlsch0_harq = dlsch[0]->harq_processes[harq_pid];
 
-    // WIP TBR Hotfix
-    memcpy((void*)&pdsch_vars[eNB_id]->dl_ch_estimates[0][ue->frame_parms.ofdm_symbol_size*2], (void*)&ue->pdsch_vars[ue->current_thread_id[nr_tti_rx]][0]->dl_ch_estimates[0][ue->frame_parms.ofdm_symbol_size*2], ue->frame_parms.ofdm_symbol_size*sizeof(int32_t));
-
     break;
 
   case PDSCH:
@@ -189,7 +186,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
     break;
   }
 
-  if (dlsch1_harq){
+  if (dlsch0_harq && dlsch1_harq){
 
     //printf("status TB0 = %d, status TB1 = %d \n", dlsch[0]->harq_processes[harq_pid]->status, dlsch[1]->harq_processes[harq_pid]->status);
     LOG_D(PHY,"AbsSubframe %d.%d / Sym %d harq_pid %d, harq status %d.%d \n", frame, nr_tti_rx, symbol, harq_pid, dlsch0_harq->status, dlsch1_harq->status);
@@ -230,19 +227,18 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
       return(-1);
     }
   } else if (dlsch0_harq) {
-    if (dlsch0_harq->status == ACTIVE)
+    if (dlsch0_harq->status == ACTIVE) {
       codeword_TB0 = dlsch0_harq->codeword;
       dlsch0_harq = dlsch[0]->harq_processes[harq_pid];
 
       #ifdef DEBUG_HARQ
         printf("[DEMOD] I am assuming only TB0 is active\n");
       #endif
+    } else {
+      LOG_E(PHY,"[UE][FATAL] nr_tti_rx %d: no active DLSCH\n", nr_tti_rx);
+      return (-1);
+    }
   } else {
-    LOG_E(PHY,"[UE][FATAL] nr_tti_rx %d: no active DLSCH\n", nr_tti_rx);
-    return (-1);
-  }
-
-  if (dlsch0_harq == NULL) {
     LOG_E(PHY, "Done\n");
     return -1;
   }
@@ -347,9 +343,9 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                                        dlsch0_harq->pmi_alloc,
                                        pdsch_vars[eNB_id_i]->pmi_ext,
                                        symbol,
-									   pilots,
-									   start_rb,
-									   nb_rb_pdsch,
+                                       pilots,
+                                       start_rb,
+                                       nb_rb_pdsch,
                                        nr_tti_rx,
                                        ue->high_speed_flag,
                                        frame_parms,
@@ -362,9 +358,9 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                                        dlsch0_harq->pmi_alloc,
                                        pdsch_vars[eNB_id_i]->pmi_ext,
                                        symbol,
-									   pilots,
-									   start_rb,
-									   nb_rb_pdsch,
+                                       pilots,
+                                       start_rb,
+                                       nb_rb_pdsch,
                                        nr_tti_rx,
                                        ue->high_speed_flag,
                                        frame_parms,
@@ -524,7 +520,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                                (aatx>1) ? pdsch_vars[eNB_id]->rho : NULL,
                                frame_parms,
                                symbol,
-							   pilots,
+                               pilots,
                                first_symbol_flag,
                                dlsch0_harq->Qm,
                                nb_rb,
@@ -1155,7 +1151,7 @@ void nr_dlsch_channel_compensation(int **rxdataF_ext,
                                 int **rho,
                                 NR_DL_FRAME_PARMS *frame_parms,
                                 unsigned char symbol,
-								uint8_t pilots,
+				uint8_t pilots,
                                 uint8_t first_symbol_flag,
                                 unsigned char mod_order,
                                 unsigned short nb_rb,
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c
index ce1c0df156add5da56b988ce642c8cb68a891cb2..e0b24a033a1c8cbef832bb186d7b97ae324c4f9b 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c
@@ -786,16 +786,16 @@ void nr_dlsch_16qam_llr(NR_DL_FRAME_PARMS *frame_parms,
 //----------------------------------------------------------------------------------------------
 
 void nr_dlsch_64qam_llr(NR_DL_FRAME_PARMS *frame_parms,
-                     int32_t **rxdataF_comp,
-                     int16_t *dlsch_llr,
-                     int32_t **dl_ch_mag,
-                     int32_t **dl_ch_magb,
-                     uint8_t symbol,
-					 uint32_t len,
-                     uint8_t first_symbol_flag,
-                     uint16_t nb_rb,
-                     uint32_t llr_offset,
-                     uint8_t beamforming_mode)
+			int32_t **rxdataF_comp,
+			int16_t *dlsch_llr,
+			int32_t **dl_ch_mag,
+			int32_t **dl_ch_magb,
+			uint8_t symbol,
+			uint32_t len,
+			uint8_t first_symbol_flag,
+			uint16_t nb_rb,
+			uint32_t llr_offset,
+			uint8_t beamforming_mode)
 {
 #if defined(__x86_64__) || defined(__i386__)
   __m128i *rxF = (__m128i*)&rxdataF_comp[0][(symbol*nb_rb*12)];
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c
index e4cab0b9a660245ba882d11079ae88763223e059..29841c3186df3f13fc8df75292a374e7fde87a34 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c
@@ -71,7 +71,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
   int16_t prach_tmp[98304*2*4] __attribute__((aligned(32)));
 
   int16_t Ncp = 0, amp, *prach, *prach2, *prachF, *Xu;
-  int32_t Xu_re, Xu_im, samp_count;
+  int32_t Xu_re, Xu_im;
   int prach_start, prach_sequence_length, i, prach_len, dftlen, mu, kbar, K, n_ra_prb, k;
   //int restricted_Type;
 
@@ -103,22 +103,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
                        nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index,
                        ue->X_u);
 
-  if (mu == 0)
-    samp_count = fp->samples_per_subframe;
-  else
-    samp_count = (slot%(fp->slots_per_subframe/2)) ? fp->samples_per_slotN0 : fp->samples_per_slot0;
-
-  #ifdef OAI_USRP
-    prach_start = (ue->rx_offset + slot*samp_count - ue->hw_timing_advance - ue->N_TA_offset);
-  #else //normal case (simulation)
-    prach_start = slot*samp_count - ue->N_TA_offset;
-  #endif
-
-  if (prach_start<0)
-    prach_start += (fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME);
-
-  if (prach_start >= (fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME))
-    prach_start -= (fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME);
+  prach_start = fp->get_samples_slot_timestamp(slot, fp, 0);
 
   // First compute physical root sequence
   /************************************************************************
@@ -796,40 +781,16 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
   }
 
   #ifdef NR_PRACH_DEBUG
-    LOG_I(PHY, "PRACH [UE %d] N_RB_UL %d prach_start %d, prach_len %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", Mod_id,
+    LOG_I(PHY, "PRACH [UE %d] N_RB_UL %d prach_start %d, prach_len %d\n", Mod_id,
       fp->N_RB_UL,
       prach_start,
-      prach_len,
-      ue->rx_offset,
-      ue->hw_timing_advance,
-      ue->N_TA_offset);
+      prach_len);
   #endif
 
-  #if defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
-    int j, overflow = prach_start + prach_len - NR_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_subframe;
-
-    #ifdef NR_PRACH_DEBUG
-      LOG_I( PHY, "PRACH [UE %d] overflow = %d\n", Mod_id, overflow);
-    #endif
-
-    // prach_start=414.730, overflow=-39470 prach_len=6600 fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME 460.800 prach_start+prach_len 421.330 fp->samples_per_subframe 46080
-
-    // from prach_start=414.730 to prach_start+prach_len 421.330
-    for (i = prach_start, j = 0; i < min(fp->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME, prach_start + prach_len); i++, j++) {
-      ((int16_t*)ue->common_vars.txdata[0])[2*i] = prach[2*j];
-      ((int16_t*)ue->common_vars.txdata[0])[2*i+1] = prach[2*j+1];
-    }
-
-    for (i = 0; i < overflow; i++,j++) {
-      ((int16_t*)ue->common_vars.txdata[0])[2*i] = prach[2*j];
-      ((int16_t*)ue->common_vars.txdata[0])[2*i+1] = prach[2*j+1];
-    }
-  #else // simulators
-    for (i=0; i<prach_len; i++) {
-      ((int16_t*)(&ue->common_vars.txdata[0][prach_start]))[2*i] = prach[2*i];
-      ((int16_t*)(&ue->common_vars.txdata[0][prach_start]))[2*i+1] = prach[2*i+1];
-    }
-  #endif
+  for (i=0; i<prach_len; i++) {
+    ((int16_t*)(&ue->common_vars.txdata[0][prach_start]))[2*i] = prach[2*i];
+    ((int16_t*)(&ue->common_vars.txdata[0][prach_start]))[2*i+1] = prach[2*i+1];
+  }
 
   //printf("----------------------\n");
   //for(int ii = prach_start; ii<2*(prach_start + prach_len); ii++){
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
index ee957965cdb814a066a9ac1d1a8d7426d869d992..845eace8b607609eac43b9307024675953953ec7 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
@@ -1074,11 +1074,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
 */
 
 uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
-                                      uint8_t harq_pid,
                                       uint8_t slot,
-                                      uint8_t thread_id,
-                                      uint8_t gNB_id,
-                                      NR_DL_FRAME_PARMS *frame_parms);
+                                      NR_DL_FRAME_PARMS *frame_parms,
+                                      uint8_t Nl);
 
 
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
index 4b36f91e69af639f81d32444956bed823412f82e..6f5fba78129097ae6336296fe4c0264680706545 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
@@ -57,7 +57,7 @@ void free_nr_ue_ulsch(NR_UE_ULSCH_t **ulschptr,unsigned char N_RB_UL)
 
   if (N_RB_UL != 273) {
     a_segments = a_segments*N_RB_UL;
-    a_segments = a_segments/273;
+    a_segments = a_segments/273 +1;
   }  
 
 
@@ -114,7 +114,7 @@ NR_UE_ULSCH_t *new_nr_ue_ulsch(uint16_t N_RB_UL,
 
   if (N_RB_UL != 273) {
     a_segments = a_segments*N_RB_UL;
-    a_segments = a_segments/273;
+    a_segments = a_segments/273 +1;
   }  
 
   uint16_t ulsch_bytes = a_segments*1056;  // allocated bytes per segment
@@ -225,8 +225,9 @@ int nr_ulsch_encoding(NR_UE_ULSCH_t *ulsch,
   unsigned int crc;
   NR_UL_UE_HARQ_t *harq_process; 
   uint16_t nb_rb ;
-  uint32_t A, Z, F;
-  uint32_t *pz; 
+  uint32_t A, F;
+  static uint32_t Z = 0;
+  uint32_t *pz = &Z; 
   uint8_t mod_order; 
   uint16_t Kr,r;
   uint32_t r_offset;
@@ -258,6 +259,7 @@ int nr_ulsch_encoding(NR_UE_ULSCH_t *ulsch,
   Ilbrm = 0;
   Tbslbrm = 950984; //max tbs
   Coderate = 0.0;
+  harq_process->round = nr_rv_round_map_ue[harq_process->pusch_pdu.pusch_data.rv_index];
 
 ///////////
 /////////////////////////////////////////////////////////////////////////////////////////  
@@ -409,6 +411,8 @@ int nr_ulsch_encoding(NR_UE_ULSCH_t *ulsch,
 ///////////////////////////////////////////////////////////////////////////////
 
   }
+  F = harq_process->F;
+  Kr = harq_process->K;
 
   for (r=0; r<harq_process->C; r++) { // looping over C segments
 
@@ -420,19 +424,15 @@ int nr_ulsch_encoding(NR_UE_ULSCH_t *ulsch,
             }
     }
 
-#ifdef DEBUG_DLSCH_CODING
-    printf("Rate Matching, Code segment %d (coded bits (G) %u, unpunctured/repeated bits per code segment %d, mod_order %d, nb_rb %d)...\n",
-        r,
-        G,
-        Kr*3,
-        mod_order,nb_rb);
-#endif
 
-    //start_meas(rm_stats);
-#ifdef DEBUG_DLSCH_CODING
-  printf("rvidx in encoding = %d\n", harq_process->pusch_pdu.pusch_data.rv_index);
-#endif
+    LOG_D(PHY,"Rate Matching, Code segment %d (coded bits (G) %u, unpunctured/repeated bits per code segment %d, mod_order %d, nb_rb %d, rvidx %d)...\n",
+	  r,
+	  G,
+	  Kr*3,
+	  mod_order,nb_rb,
+	  harq_process->pusch_pdu.pusch_data.rv_index);
 
+    //start_meas(rm_stats);
 ///////////////////////// d---->| Rate matching bit selection |---->e /////////////////////////
 ///////////
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
index ece301db81cfd3595d7101965b01712505b597fc..c85a7691f6f39f447ba0d314db727ffb044dd785 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c
@@ -425,31 +425,18 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
 
 
 uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
-                                      uint8_t harq_pid,
                                       uint8_t slot,
-                                      uint8_t thread_id,
-                                      uint8_t gNB_id,
-                                      NR_DL_FRAME_PARMS *frame_parms) {
+                                      NR_DL_FRAME_PARMS *frame_parms,
+                                      uint8_t Nl) {
 
   int tx_offset, ap;
   int32_t **txdata;
   int32_t **txdataF;
-  int timing_advance;
-  uint8_t Nl = UE->ulsch[thread_id][gNB_id][0]->harq_processes[harq_pid]->pusch_pdu.nrOfLayers; // cw 0
 
   /////////////////////////IFFT///////////////////////
   ///////////
 
-#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)  || defined(OAI_ADRV9371_ZC706)
-  timing_advance = UE->timing_advance;
-#else
-  timing_advance = 0;
-#endif
-
-  tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0) - timing_advance;
-
-  if (tx_offset < 0)
-    tx_offset += frame_parms->samples_per_frame;
+  tx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
 
   // clear the transmit data array for the current subframe
   /*for (int aa=0; aa<UE->frame_parms.nb_antennas_tx; aa++) {
@@ -461,49 +448,32 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
   txdata = UE->common_vars.txdata;
   txdataF = UE->common_vars.txdataF;
 
-  if(UE->N_TA_offset > tx_offset) {
-    int32_t *tmp_idft_out = (int32_t*)malloc16(frame_parms->get_samples_per_slot(slot, frame_parms) * sizeof(int32_t));
-
-    for(ap = 0; ap < Nl; ap++) {
-      if (frame_parms->Ncp == 1) { // extended cyclic prefix
-        PHY_ofdm_mod(txdataF[ap],
-                     tmp_idft_out,
-                     frame_parms->ofdm_symbol_size,
-                     12,
-                     frame_parms->nb_prefix_samples,
-                     CYCLIC_PREFIX);
-      } else { // normal cyclic prefix
-        nr_normal_prefix_mod(txdataF[ap],
-                             tmp_idft_out,
-                             14,
-                             frame_parms);
-      }
-
-      memcpy((void *) &txdata[ap][frame_parms->samples_per_frame - UE->N_TA_offset + tx_offset],
-             (void *) tmp_idft_out,
-             (UE->N_TA_offset - tx_offset) * sizeof(int32_t));
-
-      memcpy((void *) &txdata[ap][0],
-             (void *) &tmp_idft_out[UE->N_TA_offset - tx_offset],
-             (frame_parms->get_samples_per_slot(slot, frame_parms) - UE->N_TA_offset + tx_offset) * sizeof(int32_t));
+  int symb_offset = (slot%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot;
+  for(ap = 0; ap < Nl; ap++) {
+    for (int s=0;s<NR_NUMBER_OF_SYMBOLS_PER_SLOT;s++){
+      LOG_D(PHY,"rotating txdataF symbol %d (%d) => (%d.%d)\n",
+	    s,s+symb_offset,frame_parms->symbol_rotation[2*(s+symb_offset)],frame_parms->symbol_rotation[1+(2*(s+symb_offset))]);
+      rotate_cpx_vector((int16_t *)&txdataF[ap][frame_parms->ofdm_symbol_size*s],
+			&frame_parms->symbol_rotation[2*(s+symb_offset)],
+			(int16_t *)&txdataF[ap][frame_parms->ofdm_symbol_size*s],
+			frame_parms->ofdm_symbol_size,
+			15);
     }
+  }
 
-    free(tmp_idft_out);
-  } else { // UE->N_TA_offset <= tx_offset
-    for (ap = 0; ap < Nl; ap++) {
-      if (frame_parms->Ncp == 1) { // extended cyclic prefix
-        PHY_ofdm_mod(txdataF[ap],
-                     &txdata[ap][tx_offset-UE->N_TA_offset],
-                     frame_parms->ofdm_symbol_size,
-                     12,
-                     frame_parms->nb_prefix_samples,
-                     CYCLIC_PREFIX);
-      } else { // normal cyclic prefix
-        nr_normal_prefix_mod(txdataF[ap],
-                             &txdata[ap][tx_offset-UE->N_TA_offset],
-                             14,
-                             frame_parms);
-      }
+  for (ap = 0; ap < Nl; ap++) {
+    if (frame_parms->Ncp == 1) { // extended cyclic prefix
+      PHY_ofdm_mod(txdataF[ap],
+                   &txdata[ap][tx_offset],
+                   frame_parms->ofdm_symbol_size,
+                   12,
+                   frame_parms->nb_prefix_samples,
+                   CYCLIC_PREFIX);
+    } else { // normal cyclic prefix
+      nr_normal_prefix_mod(txdataF[ap],
+                           &txdata[ap][tx_offset],
+                           14,
+                           frame_parms);
     }
   }
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c
index c977118df3188bd8cee268e1c935aab183f03aab..cf0fc716f91d31624d46cf86654467c3117a7ca0 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c
@@ -270,7 +270,6 @@ void generate_pss_nr(NR_DL_FRAME_PARMS *fp,int N_ID_2)
   if (k>= fp->ofdm_symbol_size) k-=fp->ofdm_symbol_size;
 
 
-
   for (int i=0; i < LENGTH_PSS_NR; i++) {
     synchroF_tmp[2*k] = primary_synchro[2*i];
     synchroF_tmp[2*k+1] = primary_synchro[2*i+1];
diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c
index 65bb2edaca82b274ac12949df3531980e2df0176..0b8111fc32897f7440e48d3d5291e107dd5edb99 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c
@@ -113,7 +113,7 @@ void nr_generate_pucch0(PHY_VARS_NR_UE *ue,
     // if frequency hopping is enabled n_hop = 1 for second hop. Not sure frequency hopping concerns format 0. FIXME!!!
     // if ((PUCCH_Frequency_Hopping == 1)&&(l == (nrofSymbols-1))) n_hop = 1;
     nr_group_sequence_hopping(pucch_GroupHopping,hoppingId,n_hop,nr_tti_tx,&u,&v); // calculating u and v value
-    alpha = nr_cyclic_shift_hopping(ue->pucch_config_common_nr->hoppingId,m0,mcs,l,startingSymbolIndex,nr_tti_tx);
+    alpha = nr_cyclic_shift_hopping(hoppingId,m0,mcs,l,startingSymbolIndex,nr_tti_tx);
 #ifdef DEBUG_NR_PUCCH_TX
     printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \t(for symbol l=%d)\n",u,v,alpha,l);
 #endif
@@ -928,7 +928,17 @@ void nr_uci_encoding(uint64_t payload,
   if (A<=11) {
     // procedure in subclause 6.3.1.2.2 (UCI encoded by channel coding of small block lengths -> subclause 6.3.1.3.2)
     // CRC bits are not attached, and coding small block lengths (subclause 5.3.3)
-    b[0] = encodeSmallBlock((uint16_t*)&payload,A);
+    uint64_t b0= encodeSmallBlock((uint16_t*)&payload,A);
+    // repetition for rate-matching up to 16 PRB
+    b[0] = b0 | (b0<<32);
+    b[1] = b[0];
+    b[2] = b[0];
+    b[3] = b[0];
+    b[4] = b[0];
+    b[5] = b[0];
+    b[6] = b[0];
+    b[7] = b[0];
+    AssertFatal(nrofPRB<=16,"Number of PRB >16\n");
   } else if (A>=12) {
     AssertFatal(A<65,"Polar encoding not supported yet for UCI with more than 64 bits\n");
     t_nrPolar_params *currentPtr = nr_polar_params(NR_POLAR_UCI_PUCCH_MESSAGE_TYPE, 
diff --git a/openair1/PHY/TOOLS/nr_phy_scope.c b/openair1/PHY/TOOLS/nr_phy_scope.c
index 44d7b93ae209ae8a27e26207355097b9268dbe29..78e34036a32c9dcda8aedfb8beac4096d58bbfa9 100644
--- a/openair1/PHY/TOOLS/nr_phy_scope.c
+++ b/openair1/PHY/TOOLS/nr_phy_scope.c
@@ -525,32 +525,25 @@ static void uePcchLLR  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_
   if (!phy_vars_ue->pdcch_vars[0][eNB_id]->llr)
     return;
 
-  NR_DL_FRAME_PARMS *frame_parms = &phy_vars_ue->frame_parms;
-  uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx;
-  uint8_t nb_antennas_tx = frame_parms->nb_antennas_tx;
-  scopeSample_t **chest_f = (scopeSample_t **) phy_vars_ue->pbch_vars[eNB_id]->dl_ch_estimates;
-  int ind = 0;
-  float chest_f_abs[frame_parms->ofdm_symbol_size];
-  float freq[frame_parms->ofdm_symbol_size];
+  int num_re = 4*273*12; // 12*frame_parms->N_RB_DL*num_pdcch_symbols
+  int Qm = 2;
+  int coded_bits_per_codeword = num_re*Qm;
+  localBuff(llr,coded_bits_per_codeword*RX_NB_TH_MAX);
+  localBuff(bit,coded_bits_per_codeword*RX_NB_TH_MAX);
+  int base=0;
 
-  for (int atx=0; atx<nb_antennas_tx; atx++) {
-    for (int arx=0; arx<nb_antennas_rx; arx++) {
-      if (chest_f[(atx<<1)+arx] != NULL) {
-        for (int k=0; k<frame_parms->ofdm_symbol_size; k++) {
-          freq[ind] = (float)ind;
-          chest_f_abs[ind] = (short)10*log10(1.0+SquaredNorm(chest_f[(atx<<1)+arx][6144+k]));
-          ind++;
-        }
-      }
+  for (int thr=0 ; thr < RX_NB_TH_MAX ; thr ++ ) {
+    int16_t *pdcch_llr = (int16_t *) phy_vars_ue->pdcch_vars[thr][eNB_id]->llr;
+
+    for (int i=0; i<coded_bits_per_codeword; i++) {
+      llr[base+i] = (float) pdcch_llr[i];
+      bit[base+i] = (float) base+i;
     }
+
+    base+=coded_bits_per_codeword;
   }
 
-  // tx antenna 0
-  //fl_set_xyplot_xbounds(form->chest_f,0,nb_antennas_rx*nb_antennas_tx*nsymb_ce);
-  //fl_set_xyplot_xtics(form->chest_f,nb_antennas_rx*nb_antennas_tx*frame_parms->symbols_per_tti,2);
-  //        fl_set_xyplot_xtics(form->chest_f,nb_antennas_rx*nb_antennas_tx*2,2);
-  //fl_set_xyplot_xgrid(form->chest_f,FL_GRID_MAJOR);
-  oai_xygraph(graph,freq,chest_f_abs,frame_parms->ofdm_symbol_size,0,10);
+  oai_xygraph(graph,bit,llr,base,0,10);
 }
 
 static void uePcchIQ  (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
diff --git a/openair1/PHY/defs_UE.h b/openair1/PHY/defs_UE.h
index 9163fc13b6189f4015641220b6c0c199bc7d34c3..e17b752e7b77781d4cd1207a5ba69aceba484488 100644
--- a/openair1/PHY/defs_UE.h
+++ b/openair1/PHY/defs_UE.h
@@ -452,55 +452,6 @@ typedef struct {
   uint32_t llr_length[14];
 } LTE_UE_PDSCH;
 
-typedef struct {
-  /// \brief Received frequency-domain signal after extraction.
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  int32_t **rxdataF_ext;
-  /// \brief Received frequency-domain signal after extraction and channel compensation.
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  double **rxdataF_comp;
-  /// \brief Downlink channel estimates extracted in PRBS.
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  int32_t **dl_ch_estimates_ext;
-  ///  \brief Downlink cross-correlation of MIMO channel estimates (unquantized PMI) extracted in PRBS.
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  double **dl_ch_rho_ext;
-  /// \brief Downlink PMIs extracted in PRBS and grouped in subbands.
-  /// - first index: ressource block [0..N_RB_DL[
-  uint8_t *pmi_ext;
-  /// \brief Magnitude of Downlink Channel (16QAM level/First 64QAM level).
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  double **dl_ch_mag;
-  /// \brief Magnitude of Downlink Channel (2nd 64QAM level).
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  double **dl_ch_magb;
-  /// \brief Cross-correlation of two eNB signals.
-  /// - first index: rx antenna [0..nb_antennas_rx[
-  /// - second index: ? [0..]
-  double **rho;
-  /// never used... always send dl_ch_rho_ext instead...
-  double **rho_i;
-  /// \brief Pointers to llr vectors (2 TBs).
-  /// - first index: ? [0..1] (hard coded)
-  /// - second index: ? [0..1179743] (hard coded)
-  int16_t *llr[2];
-  /// \f$\log_2(\max|H_i|^2)\f$
-  uint8_t log2_maxh;
-  /// \brief Pointers to llr vectors (128-bit alignment).
-  /// - first index: ? [0..0] (hard coded)
-  /// - second index: ? [0..]
-  int16_t **llr128;
-  //uint32_t *rb_alloc;
-  //uint8_t Qm[2];
-  //MIMO_mode_t mimo_mode;
-} LTE_UE_PDSCH_FLP;
-
 typedef struct {
   /// \brief Pointers to extracted PDCCH symbols in frequency-domain.
   /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
@@ -667,7 +618,6 @@ typedef struct {
   uint8_t current_thread_id[10];
 
   LTE_UE_PDSCH     *pdsch_vars[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_eNB_MAX+1]; // two RxTx Threads
-  LTE_UE_PDSCH_FLP *pdsch_vars_flp[NUMBER_OF_CONNECTED_eNB_MAX+1];
   LTE_UE_PDSCH     *pdsch_vars_SI[NUMBER_OF_CONNECTED_eNB_MAX+1];
   LTE_UE_PDSCH     *pdsch_vars_ra[NUMBER_OF_CONNECTED_eNB_MAX+1];
   LTE_UE_PDSCH     *pdsch_vars_p[NUMBER_OF_CONNECTED_eNB_MAX+1];
diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h
index 75b2d54dc6933ffa507d3df7544f68f4ceb14b3b..27765a854810ba30733b5cc6ffef7ac9f640c5ac 100644
--- a/openair1/PHY/defs_common.h
+++ b/openair1/PHY/defs_common.h
@@ -1094,5 +1094,4 @@ static inline int release_thread(pthread_mutex_t *mutex,
   return(0);
 }
 
-
 #endif //  __PHY_DEFS_COMMON_H__
diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h
index fd2305f4591eedc7e6d88d139c38633a3a0e4952..179ca0331f5e9fd4064a696c5c229157a5f1fb1a 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -112,6 +112,26 @@ typedef struct {
   uint32_t F;
 } NR_DL_gNB_HARQ_t;
 
+typedef struct {
+  int frame;
+  int slot;
+  nfapi_nr_dl_tti_pdcch_pdu pdcch_pdu;
+} NR_gNB_PDCCH_t;
+
+typedef struct {
+  int frame;
+  int slot;
+  nfapi_nr_ul_dci_request_pdus_t pdcch_pdu;
+} NR_gNB_UL_PDCCH_t;
+
+typedef struct {
+  uint16_t rnti;
+  int round_trials[8];
+  int total_bytes_tx;
+  int total_bytes_rx;
+  int current_Qm;
+  int current_RI;
+} NR_gNB_SCH_STATS_t;
 
 typedef struct {
   /// Pointers to 16 HARQ processes for the DLSCH
@@ -158,6 +178,8 @@ typedef struct {
   int16_t sqrt_rho_b;
 } NR_gNB_DLSCH_t;
 
+
+
 typedef struct {
   int frame;
   int slot;
@@ -334,10 +356,6 @@ typedef struct {
   uint8_t max_ldpc_iterations;
   /// number of iterations used in last LDPC decoding
   uint8_t last_iteration_cnt;  
-  /// num active cba group
-  uint8_t num_active_cba_groups;
-  /// num active cba group
-  uint16_t cba_rnti[NUM_MAX_CBA_GROUP];
 } NR_gNB_ULSCH_t;
 
 typedef struct {
@@ -365,6 +383,8 @@ typedef struct {
   /// - second index: tx antenna [0..14[ where 14 is the total supported antenna ports.
   /// - third index: sample [0..]
   int32_t **txdataF;
+  int32_t *debugBuff;
+  int32_t debugBuff_sample_offset;
 } NR_gNB_COMMON;
 
 
@@ -377,8 +397,6 @@ typedef struct {
   /// - first index: rx antenna id [0..nb_antennas_rx[
   /// - second index (definition from phy_init_lte_eNB()): ? [0..12*N_RB_UL*frame_parms->symbols_per_tti[
   int32_t **rxdataF_ext2;
-  /// \brief Offset for calculating the index of rxdataF_ext for the current symbol
-  uint32_t rxdataF_ext_offset;
   /// \brief Hold the channel estimates in time domain based on DRS.
   /// - first index: rx antenna id [0..nb_antennas_rx[
   /// - second index: ? [0..4*ofdm_symbol_size[
@@ -681,21 +699,28 @@ typedef struct PHY_VARS_gNB_s {
   nfapi_nr_ul_tti_request_t     UL_tti_req;
   nfapi_nr_uci_indication_t uci_indication;
   
-  nfapi_nr_dl_tti_pdcch_pdu    *pdcch_pdu;
-  nfapi_nr_ul_dci_request_pdus_t  *ul_dci_pdu;
+  //  nfapi_nr_dl_tti_pdcch_pdu    *pdcch_pdu;
+  //  nfapi_nr_ul_dci_request_pdus_t  *ul_dci_pdu;
   nfapi_nr_dl_tti_ssb_pdu      ssb_pdu;
 
-  int num_pdsch_rnti;
+  uint16_t num_pdsch_rnti[80];
   NR_gNB_PBCH         pbch;
   nr_cce_t           cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL];
   NR_gNB_COMMON      common_vars;
   NR_gNB_PRACH       prach_vars;
   NR_gNB_PUSCH       *pusch_vars[NUMBER_OF_NR_ULSCH_MAX];
   NR_gNB_PUCCH_t     *pucch[NUMBER_OF_NR_PUCCH_MAX];
+  NR_gNB_PDCCH_t     pdcch_pdu[NUMBER_OF_NR_PDCCH_MAX];
+  NR_gNB_UL_PDCCH_t  ul_pdcch_pdu[NUMBER_OF_NR_PDCCH_MAX];
   NR_gNB_DLSCH_t     *dlsch[NUMBER_OF_NR_DLSCH_MAX][2];    // Nusers times two spatial streams
   NR_gNB_ULSCH_t     *ulsch[NUMBER_OF_NR_ULSCH_MAX][2];  // [Nusers times][2 codewords] 
   NR_gNB_DLSCH_t     *dlsch_SI,*dlsch_ra,*dlsch_p;
   NR_gNB_DLSCH_t     *dlsch_PCH;
+  /// statistics for DLSCH measurement collection
+  NR_gNB_SCH_STATS_t dlsch_stats[NUMBER_OF_NR_SCH_STATS_MAX];
+  /// statistics for ULSCH measurement collection
+  NR_gNB_SCH_STATS_t ulsch_stats[NUMBER_OF_NR_SCH_STATS_MAX];
+
   t_nrPolar_params    *uci_polarParams;
 
   uint8_t pbch_configured;
@@ -722,6 +747,10 @@ typedef struct PHY_VARS_gNB_s {
   /// PUSCH DMRS
   uint32_t ****nr_gold_pusch_dmrs;
 
+  // Mask of occupied RBs
+  uint32_t rb_mask_ul[9];
+  int ulmask_symb;
+
   /// Indicator set to 0 after first SR
   uint8_t first_sr[NUMBER_OF_NR_SR_MAX];
 
@@ -776,6 +805,7 @@ typedef struct PHY_VARS_gNB_s {
   time_stats_t dlsch_interleaving_stats;
   time_stats_t dlsch_segmentation_stats;
 
+  time_stats_t rx_pusch_stats;
   time_stats_t ulsch_decoding_stats;
   time_stats_t ulsch_rate_unmatching_stats;
   time_stats_t ulsch_ldpc_decoding_stats;
@@ -785,6 +815,7 @@ typedef struct PHY_VARS_gNB_s {
   time_stats_t ulsch_ptrs_processing_stats;
   time_stats_t ulsch_channel_compensation_stats;
   time_stats_t ulsch_rbs_extraction_stats;
+  time_stats_t ulsch_mrc_stats;
   time_stats_t ulsch_llr_stats;
 
   /*
diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h
index 9bdf892ceb41e3e95dccb7e21a358ef3345ebf2b..62ffeaaea89b2d6e1ac63dd1b12204b3e248714d 100644
--- a/openair1/PHY/defs_nr_UE.h
+++ b/openair1/PHY/defs_nr_UE.h
@@ -416,55 +416,6 @@ typedef struct {
   uint32_t llr_length[14];
 } NR_UE_PDSCH;
 
-typedef struct {
-  /// \brief Received frequency-domain signal after extraction.
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  int32_t **rxdataF_ext;
-  /// \brief Received frequency-domain signal after extraction and channel compensation.
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  double **rxdataF_comp;
-  /// \brief Downlink channel estimates extracted in PRBS.
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  int32_t **dl_ch_estimates_ext;
-  ///  \brief Downlink cross-correlation of MIMO channel estimates (unquantized PMI) extracted in PRBS.
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  double **dl_ch_rho_ext;
-  /// \brief Downlink PMIs extracted in PRBS and grouped in subbands.
-  /// - first index: ressource block [0..N_RB_DL[
-  uint8_t *pmi_ext;
-  /// \brief Magnitude of Downlink Channel (16QAM level/First 64QAM level).
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  double **dl_ch_mag;
-  /// \brief Magnitude of Downlink Channel (2nd 64QAM level).
-  /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
-  /// - second index: ? [0..]
-  double **dl_ch_magb;
-  /// \brief Cross-correlation of two eNB signals.
-  /// - first index: rx antenna [0..nb_antennas_rx[
-  /// - second index: ? [0..]
-  double **rho;
-  /// never used... always send dl_ch_rho_ext instead...
-  double **rho_i;
-  /// \brief Pointers to llr vectors (2 TBs).
-  /// - first index: ? [0..1] (hard coded)
-  /// - second index: ? [0..1179743] (hard coded)
-  int16_t *llr[2];
-  /// \f$\log_2(\max|H_i|^2)\f$
-  uint8_t log2_maxh;
-  /// \brief Pointers to llr vectors (128-bit alignment).
-  /// - first index: ? [0..0] (hard coded)
-  /// - second index: ? [0..]
-  int16_t **llr128;
-  //uint32_t *rb_alloc;
-  //uint8_t Qm[2];
-  //MIMO_mode_t mimo_mode;
-} NR_UE_PDSCH_FLP;
-
 #define NR_PDCCH_DEFS_NR_UE
 #define NR_NBR_CORESET_ACT_BWP      3  // The number of CoreSets per BWP is limited to 3 (including initial CORESET: ControlResourceId 0)
 #define NR_NBR_SEARCHSPACE_ACT_BWP  10 // The number of SearchSpaces per BWP is limited to 10 (including initial SEARCHSPACE: SearchSpaceId 0)
@@ -902,11 +853,6 @@ typedef struct {
 
   t_nrPolar_params *polarList;
   NR_UE_PDSCH     *pdsch_vars[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_eNB_MAX+1]; // two RxTx Threads
-  NR_UE_PDSCH_FLP *pdsch_vars_flp[NUMBER_OF_CONNECTED_eNB_MAX+1];
-  NR_UE_PDSCH     *pdsch_vars_SI[NUMBER_OF_CONNECTED_eNB_MAX+1];
-  NR_UE_PDSCH     *pdsch_vars_ra[NUMBER_OF_CONNECTED_eNB_MAX+1];
-  NR_UE_PDSCH     *pdsch_vars_p[NUMBER_OF_CONNECTED_eNB_MAX+1];
-  NR_UE_PDSCH     *pdsch_vars_MCH[NUMBER_OF_CONNECTED_eNB_MAX];
   NR_UE_PBCH      *pbch_vars[NUMBER_OF_CONNECTED_eNB_MAX];
   NR_UE_PDCCH     *pdcch_vars[RX_NB_TH_MAX][NUMBER_OF_CONNECTED_eNB_MAX];
   NR_UE_PRACH     *prach_vars[NUMBER_OF_CONNECTED_eNB_MAX];
@@ -1022,7 +968,6 @@ typedef struct {
   /// Timing Advance updates variables
   /// Timing advance update computed from the TA command signalled from gNB
   int                      timing_advance;
-  int                      hw_timing_advance;
   int                      N_TA_offset; ///timing offset used in TDD
   NR_UL_TIME_ALIGNMENT_t   ul_time_alignment[NUMBER_OF_CONNECTED_gNB_MAX];
 
diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h
index 584962c55c6234486acd0d09d9318dc9a2faaf50..a21af3fa03254396dfe731c08be89884cd1a9a90 100644
--- a/openair1/PHY/defs_nr_common.h
+++ b/openair1/PHY/defs_nr_common.h
@@ -111,6 +111,9 @@
 #define MAX_NUM_NR_CHANNEL_BITS (14*273*12*8)  // 14 symbols, 273 RB
 #define MAX_NUM_NR_RE (14*273*12)
 
+extern const uint8_t nr_rv_round_map[4]; 
+extern const uint8_t nr_rv_round_map_ue[4]; 
+
 typedef enum {
   NR_MU_0=0,
   NR_MU_1,
@@ -319,6 +322,8 @@ struct NR_DL_FRAME_PARMS {
   uint8_t nb_antenna_ports_gNB;
   /// Cyclic Prefix for DL (0=Normal CP, 1=Extended CP)
   lte_prefix_type_t Ncp;
+  /// sequence which is computed based on carrier frequency and numerology to rotate/derotate each OFDM symbol according to Section 5.3 in 38.211
+  int16_t symbol_rotation[224*2];
   /// shift of pilot position in one RB
   uint8_t nushift;
   /// SRS configuration from TS 38.331 RRC
diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c
index 2870f1d42e0594bbe198afa0e9e91861886dc938..84490bfad451fb82fad288d0fdcba7088a87ea99 100644
--- a/openair1/SCHED_NR/fapi_nr_l1.c
+++ b/openair1/SCHED_NR/fapi_nr_l1.c
@@ -94,9 +94,9 @@ void handle_nfapi_nr_pdcch_pdu(PHY_VARS_gNB *gNB,
   LOG_D(PHY,"Frame %d, Slot %d: DCI processing - proc:slot_tx:%d pdcch_pdu_rel15->numDlDci:%d\n",frame,slot, slot, pdcch_pdu->pdcch_pdu_rel15.numDlDci);
 
   // copy dci configuration into gNB structure
-  gNB->pdcch_pdu = pdcch_pdu;
+  //  gNB->pdcch_pdu = pdcch_pdu;
 
-  nr_fill_dci(gNB,frame,slot);
+  nr_fill_dci(gNB,frame,slot,pdcch_pdu);
 
 
 
@@ -109,9 +109,9 @@ void handle_nfapi_nr_ul_dci_pdu(PHY_VARS_gNB *gNB,
   LOG_D(PHY,"Frame %d, Slot %d: UL DCI processing - proc:slot_tx:%d pdcch_pdu_rel15->numDlDci:%d\n",frame,slot, slot, ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15.numDlDci);
 
   // copy dci configuration into gNB structure
-  gNB->ul_dci_pdu = ul_dci_request_pdu;
+  //  gNB->ul_dci_pdu = ul_dci_request_pdu;
 
-  nr_fill_ul_dci(gNB,frame,slot);
+  nr_fill_ul_dci(gNB,frame,slot,ul_dci_request_pdu);
 
 }
 
@@ -154,13 +154,12 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){
 	  number_ul_dci_pdu,number_ul_tti_pdu);
 
   int pdcch_received=0;
-  gNB->num_pdsch_rnti=0;
+  gNB->num_pdsch_rnti[slot]=0;
   for (int i=0; i<NUMBER_OF_NR_DLSCH_MAX; i++) {
     gNB->dlsch[i][0]->rnti=0;
     gNB->dlsch[i][0]->harq_mask=0;
   }
-  gNB->pdcch_pdu = NULL;
-  gNB->ul_dci_pdu = NULL;
+
   gNB->pbch_configured=0;
 
   for (int i=0;i<number_dl_pdu;i++) {
@@ -219,7 +218,7 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){
         LOG_D(PHY,"frame %d, slot %d, Got NFAPI_NR_UL_TTI_PRACH_PDU_TYPE for %d.%d\n", frame, slot, UL_tti_req->SFN, UL_tti_req->Slot);
         nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu;
         nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
-        nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
+        if (gNB->RU_list[0]->if_south == LOCAL_RF) nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
         break;
     }
   }
diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c
index 560f47059afb29c7f2e7ce7daff6d6494f07fb39..9723b2f99e1b9ba77a5d38a555cdbdb762f00b3d 100644
--- a/openair1/SCHED_NR/nr_ru_procedures.c
+++ b/openair1/SCHED_NR/nr_ru_procedures.c
@@ -87,14 +87,29 @@ void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) {
                  CYCLIC_PREFIX);
   else {
     if (fp->numerology_index != 0) {
+      
+      if (!(slot%(fp->slots_per_subframe/2))&&(first_symbol==0)) { // case where first symbol in slot has longer prefix
+	apply_nr_rotation(fp,
+			  (int16_t*)&ru->common.txdataF_BF[aa][slot_offsetF],
+			  slot,
+			  0,
+			  1,
+			  fp->ofdm_symbol_size);
 
-      if (!(slot%(fp->slots_per_subframe/2))&&(first_symbol==0)) {
         PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF],
                      (int*)&ru->common.txdata[aa][slot_offset],
                      fp->ofdm_symbol_size,
                      1,
                      fp->nb_prefix_samples0,
                      CYCLIC_PREFIX);
+
+	apply_nr_rotation(fp,
+			  (int16_t*)&ru->common.txdataF_BF[aa][slot_offsetF+fp->ofdm_symbol_size],
+			  slot,
+			  1,
+			  num_symbols-1,
+			  fp->ofdm_symbol_size);
+
         PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF+fp->ofdm_symbol_size],
                      (int*)&ru->common.txdata[aa][slot_offset+fp->nb_prefix_samples0+fp->ofdm_symbol_size],
                      fp->ofdm_symbol_size,
@@ -102,7 +117,13 @@ void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) {
                      fp->nb_prefix_samples,
                      CYCLIC_PREFIX);
       }
-      else {
+      else { // all symbols in slot have shorter prefix
+	apply_nr_rotation(fp,
+			  (int16_t*)&ru->common.txdataF_BF[aa][slot_offsetF],
+			  slot,
+			  first_symbol,
+			  num_symbols,
+			  fp->ofdm_symbol_size);
         PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF],
                      (int*)&ru->common.txdata[aa][slot_offset],
                      fp->ofdm_symbol_size,
@@ -110,9 +131,8 @@ void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) {
                      fp->nb_prefix_samples,
                      CYCLIC_PREFIX);
       }
-    }
-
-    else {
+    } // numerology_index!=0
+    else { //numerology_index == 0
       for (uint16_t idx_sym=abs_first_symbol; idx_sym<abs_first_symbol+num_symbols; idx_sym++) {
         if (idx_sym%0x7) {
           PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF],
@@ -121,6 +141,12 @@ void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) {
                        1,
                        fp->nb_prefix_samples,
                        CYCLIC_PREFIX);
+	  apply_nr_rotation(fp,
+			    (int16_t*)&ru->common.txdata[aa][slot_offset],
+			    slot,
+			    idx_sym,
+			    1,
+			    fp->ofdm_symbol_size+fp->nb_prefix_samples);
           slot_offset += fp->nb_prefix_samples+fp->ofdm_symbol_size;
         }
         else {
@@ -130,6 +156,12 @@ void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) {
                        1,
                        fp->nb_prefix_samples0,
                        CYCLIC_PREFIX);
+	  apply_nr_rotation(fp,
+			    (int16_t*)&ru->common.txdata[aa][slot_offset],
+			    slot,
+			    0,
+			    1,
+			    fp->ofdm_symbol_size+fp->nb_prefix_samples0);
           slot_offset += fp->nb_prefix_samples0+fp->ofdm_symbol_size;
         }
       }
diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
index 94e356951aa916e105fe39f04a291a134d2425dc..6dfe967edc0b9666eaffc73d6b6a04466f8084cf 100644
--- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c
+++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
@@ -26,6 +26,7 @@
 #include "PHY/NR_TRANSPORT/nr_transport_proto.h"
 #include "PHY/NR_TRANSPORT/nr_dlsch.h"
 #include "PHY/NR_TRANSPORT/nr_ulsch.h"
+#include "PHY/NR_TRANSPORT/nr_dci.h"
 #include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
 #include "PHY/NR_UE_TRANSPORT/pucch_nr.h"
 #include "SCHED/sched_eNB.h"
@@ -160,41 +161,41 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
   }
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_COMMON_TX,0);
 
+  int pdcch_pdu_id=find_nr_pdcch(frame,slot,gNB,SEARCH_EXIST);
+  int ul_pdcch_pdu_id=find_nr_ul_dci(frame,slot,gNB,SEARCH_EXIST);
 
-  if (gNB->pdcch_pdu || gNB->ul_dci_pdu) {
+  LOG_D(PHY,"[gNB %d] Frame %d slot %d, pdcch_pdu_id %d, ul_pdcch_pdu_id %d\n",
+	gNB->Mod_id,frame,slot,pdcch_pdu_id,ul_pdcch_pdu_id);
+
+  if (pdcch_pdu_id >= 0 || ul_pdcch_pdu_id >= 0) {
     LOG_D(PHY, "[gNB %d] Frame %d slot %d Calling nr_generate_dci_top (number of UL/DL DCI %d/%d)\n",
 	  gNB->Mod_id, frame, slot,
-	  gNB->ul_dci_pdu==NULL?0:gNB->ul_dci_pdu->pdcch_pdu.pdcch_pdu_rel15.numDlDci,
-	  gNB->pdcch_pdu==NULL?0:gNB->pdcch_pdu->pdcch_pdu_rel15.numDlDci);
+	  gNB->ul_pdcch_pdu[ul_pdcch_pdu_id].pdcch_pdu.pdcch_pdu.pdcch_pdu_rel15.numDlDci,
+	  gNB->pdcch_pdu[pdcch_pdu_id].pdcch_pdu.pdcch_pdu_rel15.numDlDci);
   
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_PDCCH_TX,1);
 
-    nr_generate_dci_top(gNB->pdcch_pdu,
-			gNB->ul_dci_pdu,
+    nr_generate_dci_top(gNB,
+			pdcch_pdu_id>=0 ? &gNB->pdcch_pdu[pdcch_pdu_id].pdcch_pdu : NULL,
+			ul_pdcch_pdu_id>=0 ? &gNB->ul_pdcch_pdu[ul_pdcch_pdu_id].pdcch_pdu.pdcch_pdu : NULL,
 			gNB->nr_gold_pdcch_dmrs[slot],
 			&gNB->common_vars.txdataF[0][txdataF_offset],
 			AMP, *fp);
-  
+
+    // free up entry in pdcch tables
+    if (pdcch_pdu_id>=0) gNB->pdcch_pdu[pdcch_pdu_id].frame = -1;
+    if (ul_pdcch_pdu_id>=0) gNB->ul_pdcch_pdu[ul_pdcch_pdu_id].frame = -1;
+
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_gNB_PDCCH_TX,0);
+    if (pdcch_pdu_id >= 0) gNB->pdcch_pdu[pdcch_pdu_id].frame = -1;
+    if (ul_pdcch_pdu_id >= 0) gNB->ul_pdcch_pdu[ul_pdcch_pdu_id].frame = -1;
   }
  
-  for (int i=0; i<gNB->num_pdsch_rnti; i++) {
+  for (int i=0; i<gNB->num_pdsch_rnti[slot]; i++) {
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,1);
-    LOG_D(PHY, "PDSCH generation started (%d)\n", gNB->num_pdsch_rnti);
-    nr_generate_pdsch(gNB->dlsch[i][0],
-		      gNB->nr_gold_pdsch_dmrs[slot],
-		      gNB->common_vars.txdataF,
-		      AMP, frame, slot, fp, 0,
-		      &gNB->dlsch_encoding_stats,
-		      &gNB->dlsch_scrambling_stats,
-		      &gNB->dlsch_modulation_stats,
-		      &gNB->tinput,
-		      &gNB->tprep,
-		      &gNB->tparity,
-		      &gNB->toutput,
-		      &gNB->dlsch_rate_matching_stats,
-		      &gNB->dlsch_interleaving_stats,
-		      &gNB->dlsch_segmentation_stats);
+    LOG_D(PHY, "PDSCH generation started (%d) in frame %d.%d\n", gNB->num_pdsch_rnti[slot],frame,slot);
+    nr_generate_pdsch(gNB,frame, slot);
+    if ((frame&127) == 0) dump_pdsch_stats(gNB);
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GENERATE_DLSCH,0);
   }
 
@@ -239,16 +240,30 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH
                number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
                pusch_pdu->qam_mod_order,
                pusch_pdu->nrOfLayers);
-
+  
+  AssertFatal(G>0,"G is 0 : rb_size %u, number_symbols %d, nb_re_dmrs %d, number_dmrs_symbols %d, qam_mod_order %u, nrOfLayer %u\n",
+	      pusch_pdu->rb_size,
+	      number_symbols,
+	      nb_re_dmrs,
+	      number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
+	      pusch_pdu->qam_mod_order,
+	      pusch_pdu->nrOfLayers);
+  LOG_D(PHY,"rb_size %d, number_symbols %d, nb_re_dmrs %d, number_dmrs_symbols %d, qam_mod_order %d, nrOfLayer %d\n",
+	pusch_pdu->rb_size,
+	number_symbols,
+	nb_re_dmrs,
+	number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs
+	pusch_pdu->qam_mod_order,
+	pusch_pdu->nrOfLayers);
   //----------------------------------------------------------
   //------------------- ULSCH unscrambling -------------------
   //----------------------------------------------------------
   start_meas(&gNB->ulsch_unscrambling_stats);
-  nr_ulsch_unscrambling(gNB->pusch_vars[ULSCH_id]->llr,
-                        G,
-                        0,
-                        pusch_pdu->data_scrambling_id,
-                        pusch_pdu->rnti);
+  nr_ulsch_unscrambling_optim(gNB->pusch_vars[ULSCH_id]->llr,
+			      G,
+			      0,
+			      pusch_pdu->data_scrambling_id,
+			      pusch_pdu->rnti);
   stop_meas(&gNB->ulsch_unscrambling_stats);
   //----------------------------------------------------------
   //--------------------- ULSCH decoding ---------------------
@@ -266,13 +281,12 @@ void nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH
                           G);
   stop_meas(&gNB->ulsch_decoding_stats);
 
-
   if (ret > gNB->ulsch[ULSCH_id][0]->max_ldpc_iterations){
-    LOG_I(PHY, "ULSCH %d in error\n",ULSCH_id);
+    LOG_D(PHY, "ULSCH %d in error\n",ULSCH_id);
     nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 1);
   }
   else if(gNB->ulsch[ULSCH_id][0]->harq_processes[harq_pid]->b!=NULL){
-    LOG_I(PHY, "ULSCH received ok \n");
+    LOG_D(PHY, "ULSCH received ok \n");
     nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 0);
   }
 }
@@ -313,7 +327,9 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id,
   LOG_D(PHY, "Estimated timing advance PUSCH is  = %d, timing_advance_update is %d \n", sync_pos,timing_advance_update);
 
   // estimate UL_CQI for MAC (from antenna port 0 only)
-  int SNRtimes10 = dB_fixed_times10(gNB->pusch_vars[ULSCH_id]->ulsch_power[0]) - 300;//(10*gNB->measurements.n0_power_dB[0]);
+  int SNRtimes10 = dB_fixed_times10(gNB->pusch_vars[ULSCH_id]->ulsch_power[0]) - (10*gNB->measurements.n0_power_dB[0]);
+
+  LOG_D(PHY, "Estimated SNR for PUSCH is = %d dB\n", SNRtimes10/10);
 
   if      (SNRtimes10 < -640) cqi=0;
   else if (SNRtimes10 >  635) cqi=255;
@@ -332,7 +348,8 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id,
   gNB->crc_pdu_list[num_crc].num_cb = pusch_pdu->pusch_data.num_cb;
   gNB->crc_pdu_list[num_crc].ul_cqi = cqi;
   gNB->crc_pdu_list[num_crc].timing_advance = timing_advance_update;
-  gNB->crc_pdu_list[num_crc].rssi = 0xffff; // invalid value as this is not yet computed
+  // in terms of dBFS range -128 to 0 with 0.1 step
+  gNB->crc_pdu_list[num_crc].rssi = 1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(gNB->pusch_vars[ULSCH_id]->ulsch_power[0]));
 
   gNB->UL_INFO.crc_ind.number_crcs++;
 
@@ -346,7 +363,7 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id,
   gNB->rx_pdu_list[num_rx].harq_id = harq_pid;
   gNB->rx_pdu_list[num_rx].ul_cqi = cqi;
   gNB->rx_pdu_list[num_rx].timing_advance = timing_advance_update;
-  gNB->rx_pdu_list[num_rx].rssi = 0xffff; // invalid value as this is not yet computed
+  gNB->rx_pdu_list[num_rx].rssi = 1280 - (10*dB_fixed(32767*32767)-dB_fixed_times10(gNB->pusch_vars[ULSCH_id]->ulsch_power[0]));
   if (crc_flag)
     gNB->rx_pdu_list[num_rx].pdu_length = 0;
   else {
@@ -359,6 +376,71 @@ void nr_fill_indication(PHY_VARS_gNB *gNB, int frame, int slot_rx, int ULSCH_id,
   pthread_mutex_unlock(&gNB->UL_INFO_mutex);
 }
 
+// Function to fill UL RB mask to be used for N0 measurements
+void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) {
+
+  int rb2, rb, nb_rb;
+  for (int symbol=0;symbol<14;symbol++) {
+    if (gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list[symbol].slot_config.value==1){
+      nb_rb = 0;
+      for (int m=0;m<9;m++) gNB->rb_mask_ul[m] = 0;
+      gNB->ulmask_symb = -1;
+
+      for (int i=0;i<NUMBER_OF_NR_PUCCH_MAX;i++){
+        NR_gNB_PUCCH_t *pucch = gNB->pucch[i];
+        if (pucch) {
+          if ((pucch->active == 1) &&
+	      (pucch->frame == frame_rx) &&
+	      (pucch->slot == slot_rx) ) {
+            gNB->ulmask_symb = symbol;
+            nfapi_nr_pucch_pdu_t  *pucch_pdu = &pucch[i].pucch_pdu;
+            if ((symbol>=pucch_pdu->start_symbol_index) &&
+                (symbol<(pucch_pdu->start_symbol_index + pucch_pdu->nr_of_symbols))){
+              for (rb=0; rb<pucch_pdu->prb_size; rb++) {
+                rb2 = rb+pucch_pdu->prb_start;
+                gNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31));
+              }
+              nb_rb+=pucch_pdu->prb_size;
+            }
+          }
+        }
+      }
+      for (int ULSCH_id=0;ULSCH_id<NUMBER_OF_NR_ULSCH_MAX;ULSCH_id++) {
+        NR_gNB_ULSCH_t *ulsch = gNB->ulsch[ULSCH_id][0];
+        int harq_pid;
+        NR_UL_gNB_HARQ_t *ulsch_harq;
+
+        if ((ulsch) &&
+            (ulsch->rnti > 0)) {
+          for (harq_pid=0;harq_pid<NR_MAX_ULSCH_HARQ_PROCESSES;harq_pid++) {
+            ulsch_harq = ulsch->harq_processes[harq_pid];
+            AssertFatal(ulsch_harq!=NULL,"harq_pid %d is not allocated\n",harq_pid);
+            if ((ulsch_harq->status == NR_ACTIVE) &&
+                (ulsch_harq->frame == frame_rx) &&
+                (ulsch_harq->slot == slot_rx) &&
+                (ulsch_harq->handled == 0)){
+              uint8_t symbol_start = ulsch_harq->ulsch_pdu.start_symbol_index;
+              uint8_t symbol_end = symbol_start + ulsch_harq->ulsch_pdu.nr_of_symbols;
+              gNB->ulmask_symb = symbol;
+              if ((symbol>=symbol_start) &&
+                  (symbol<symbol_end)){
+                for (rb=0; rb<ulsch_harq->ulsch_pdu.rb_size; rb++) {
+                  rb2 = rb+ulsch_harq->ulsch_pdu.rb_start;
+                  gNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31));
+                }
+                nb_rb+=ulsch_harq->ulsch_pdu.rb_size;
+              }
+            }
+          }
+        }
+      //TODO Add check for PRACH as well?
+      }
+      if (nb_rb<gNB->frame_parms.N_RB_UL)
+        return;
+    }
+  }
+}
+
 void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) {
 
   uint8_t symbol;
@@ -385,6 +467,9 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,1);
   LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx);
 
+  fill_ul_rb_mask(gNB, frame_rx, slot_rx);
+  gNB_I0_measurements(gNB);
+
   for (int i=0;i<NUMBER_OF_NR_PUCCH_MAX;i++){
     NR_gNB_PUCCH_t *pucch = gNB->pucch[i];
     if (pucch) {
@@ -424,49 +509,73 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
   for (int ULSCH_id=0;ULSCH_id<NUMBER_OF_NR_ULSCH_MAX;ULSCH_id++) {
     NR_gNB_ULSCH_t *ulsch = gNB->ulsch[ULSCH_id][0];
     int harq_pid;
-    //int no_sig;
+    int no_sig;
     NR_UL_gNB_HARQ_t *ulsch_harq;
 
     if ((ulsch) &&
         (ulsch->rnti > 0)) {
       // for for an active HARQ process
       for (harq_pid=0;harq_pid<NR_MAX_ULSCH_HARQ_PROCESSES;harq_pid++) {
-	    ulsch_harq = ulsch->harq_processes[harq_pid];
+	ulsch_harq = ulsch->harq_processes[harq_pid];
     	AssertFatal(ulsch_harq!=NULL,"harq_pid %d is not allocated\n",harq_pid);
     	if ((ulsch_harq->status == NR_ACTIVE) &&
           (ulsch_harq->frame == frame_rx) &&
           (ulsch_harq->slot == slot_rx) &&
           (ulsch_harq->handled == 0)){
 
+          LOG_D(PHY, "PUSCH detection started in frame %d slot %d\n",
+                frame_rx,slot_rx);
+
 #ifdef DEBUG_RXDATA
           NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
           RU_t *ru = gNB->RU_list[0];
           int slot_offset = frame_parms->get_samples_slot_timestamp(slot_rx,frame_parms,0);
           slot_offset -= ru->N_TA_offset;
-          char name[128];
-          FILE *f;
-          sprintf(name, "rxdata.%d.%d.raw", frame_rx,slot_rx);
-          f = fopen(name, "w"); if (f == NULL) exit(1);
-          fwrite(&ru->common.rxdata[0][slot_offset],2,frame_parms->get_samples_per_slot(slot_rx,frame_parms)*2, f);
-          fclose(f);
+          ((int16_t*)&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset])[0]=(int16_t)ulsch->rnti;
+          ((int16_t*)&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset])[1]=(int16_t)ulsch_harq->ulsch_pdu.rb_size;
+          ((int16_t*)&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset])[2]=(int16_t)ulsch_harq->ulsch_pdu.rb_start;
+          ((int16_t*)&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset])[3]=(int16_t)ulsch_harq->ulsch_pdu.nr_of_symbols;
+          ((int16_t*)&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset])[4]=(int16_t)ulsch_harq->ulsch_pdu.start_symbol_index;
+          ((int16_t*)&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset])[5]=(int16_t)ulsch_harq->ulsch_pdu.mcs_index;
+          ((int16_t*)&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset])[6]=(int16_t)ulsch_harq->ulsch_pdu.pusch_data.rv_index;
+          ((int16_t*)&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset])[7]=(int16_t)harq_pid;
+          memcpy(&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset+4],&ru->common.rxdata[0][slot_offset],frame_parms->get_samples_per_slot(slot_rx,frame_parms)*sizeof(int32_t));
+          gNB->common_vars.debugBuff_sample_offset+=(frame_parms->get_samples_per_slot(slot_rx,frame_parms)+1000+4);
+          if(gNB->common_vars.debugBuff_sample_offset>((frame_parms->get_samples_per_slot(slot_rx,frame_parms)+1000+2)*20)) {
+            FILE *f;
+            f = fopen("rxdata_buff.raw", "w"); if (f == NULL) exit(1);
+            fwrite((int16_t*)gNB->common_vars.debugBuff,2,(frame_parms->get_samples_per_slot(slot_rx,frame_parms)+1000+4)*20*2, f);
+            fclose(f);
+            exit(-1);
+          }
 #endif
 
           uint8_t symbol_start = ulsch_harq->ulsch_pdu.start_symbol_index;
           uint8_t symbol_end = symbol_start + ulsch_harq->ulsch_pdu.nr_of_symbols;
           VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH,1);
-          for(uint8_t symbol = symbol_start; symbol < symbol_end; symbol++) {
-            nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, symbol, harq_pid);
-          }
+	  start_meas(&gNB->rx_pusch_stats);
+	  for(uint8_t symbol = symbol_start; symbol < symbol_end; symbol++) {
+	    no_sig = nr_rx_pusch(gNB, ULSCH_id, frame_rx, slot_rx, symbol, harq_pid);
+            if (no_sig) {
+              LOG_I(PHY, "PUSCH not detected in symbol %d\n",symbol);
+              nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 1);
+              return;
+            }
+	  }
+	  stop_meas(&gNB->rx_pusch_stats);
           VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH,0);
           //LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1);
           //LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1);
           VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX,1);
-            nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid);
+          nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, harq_pid);
           VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX,0);
           break;
         }
       }
     }
   }
+  // figure out a better way to choose slot_rx, 19 is ok for a particular TDD configuration with 30kHz SCS
+  if ((frame_rx&127) == 0 && slot_rx==19) dump_pusch_stats(gNB);
+
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_UESPEC_RX,0);
 }
diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h
index b393e9566e7a744dfbe609f952653f8c79ac07c1..59ac1496e779a9bb1ff9420f26dbc8cf092bc2c0 100644
--- a/openair1/SCHED_NR/sched_nr.h
+++ b/openair1/SCHED_NR/sched_nr.h
@@ -34,7 +34,7 @@
 #include "PHY/NR_TRANSPORT/nr_dci.h"
 #include "phy_frame_config_nr.h"
 
-
+void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx);
 void nr_set_ssb_first_subcarrier(nfapi_nr_config_request_scf_t *cfg, NR_DL_FRAME_PARMS *fp);
 void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, int frame_tx, int slot_tx, int do_meas);
 void phy_procedures_gNB_common_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx);
diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
index ea73f2feccdc486bc33311d9a0a67a400af0c37c..55c7cd0bafb8bb0fe095b33e7a17a124dba68731 100644
--- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
+++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
@@ -117,6 +117,7 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){
             dlsch0_harq->harq_ack.rx_status = downlink_harq_process(dlsch0_harq, dlsch0->current_harq_pid, dlsch_config_pdu->ndi, dlsch0->rnti_type);
             dlsch0_harq->harq_ack.vDAI_DL = dlsch_config_pdu->dai;
             LOG_D(MAC, ">>>> \tdlsch0->g_pucch = %d\tdlsch0_harq.mcs = %d\n", dlsch0->g_pucch, dlsch0_harq->mcs);
+		
           }
         }
       }
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index 68715e27a80babd3dc52455bfcd1b7fc1bf25801..691a231aba7b9a4d0901ca8e0b4f63977828d0d4 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -86,6 +86,8 @@ fifo_dump_emos_UE emos_dump_UE;
 
 char nr_mode_string[4][20] = {"NOT SYNCHED","PRACH","RAR","PUSCH"};
 
+const uint8_t nr_rv_round_map_ue[4] = {0, 2, 1, 3};
+
 extern double cpuf;
 
 /*
@@ -1099,169 +1101,6 @@ uint16_t nr_get_n1_pucch(PHY_VARS_NR_UE *ue,
   return(-1);
 }
 
-
-
-void ulsch_common_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t empty_subframe) {
-
-  int aa;
-  NR_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;
-
-  int nsymb;
-  int nr_tti_tx = proc->nr_tti_tx;
-  int frame_tx = proc->frame_tx;
-  int ulsch_start;
-  int overflow=0;
-#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706)
-  int k,l;
-  int dummy_tx_buffer[frame_parms->samples_per_subframe] __attribute__((aligned(16)));
-#endif
-
-  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_COMMON,VCD_FUNCTION_IN);
-#if UE_TIMING_TRACE
-  start_meas(&ue->ofdm_mod_stats);
-#endif
-  nsymb = (frame_parms->Ncp == 0) ? 14 : 12;
-
-#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706)//this is the EXPRESS MIMO case
-  ulsch_start = (ue->rx_offset+nr_tti_tx*frame_parms->samples_per_subframe-
-		 ue->hw_timing_advance-
-		 ue->timing_advance-
-		 ue->N_TA_offset+5);
-  //LOG_E(PHY,"ul-signal [nr_tti_rx: %d, ulsch_start %d]\n",nr_tti_tx, ulsch_start);
-
-  if(ulsch_start < 0)
-    ulsch_start = ulsch_start + (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_subframe);
-
-  if (ulsch_start > (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_subframe))
-    ulsch_start = ulsch_start % (LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_subframe);
-
-  //LOG_E(PHY,"ul-signal [nr_tti_rx: %d, ulsch_start %d]\n",nr_tti_tx, ulsch_start);
-#else //this is the normal case
-  ulsch_start = (frame_parms->samples_per_subframe*nr_tti_tx)-ue->N_TA_offset; //-ue->timing_advance;
-#endif //else EXMIMO
-
-  //#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706)
-  if (empty_subframe)
-    {
-      //#if 1
-      overflow = ulsch_start - 9*frame_parms->samples_per_subframe;
-      for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
-
-	if (overflow > 0)
-	  {
-	    memset(&ue->common_vars.txdata[aa][ulsch_start],0,4*(frame_parms->samples_per_subframe-overflow));
-	    memset(&ue->common_vars.txdata[aa][0],0,4*overflow);
-	  }
-	else
-	  {
-	    memset(&ue->common_vars.txdata[aa][ulsch_start],0,4*frame_parms->samples_per_subframe);
-	  }
-      }
-      /*#else
-	overflow = ulsch_start - 9*frame_parms->samples_per_subframe;
-	for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
-	for (k=ulsch_start; k<cmin(frame_parms->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME,ulsch_start+frame_parms->samples_per_subframe); k++) {
-	((short*)ue->common_vars.txdata[aa])[2*k] = 0;
-	((short*)ue->common_vars.txdata[aa])[2*k+1] = 0;
-	}
-
-	for (k=0; k<overflow; k++) {
-	((short*)ue->common_vars.txdata[aa])[2*k] = 0;
-	((short*)ue->common_vars.txdata[aa])[2*k+1] = 0;
-	}
-	}
-	endif*/
-      return;
-    }
-
-
-  if ((frame_tx%100) == 0)
-    LOG_D(PHY,"[UE %d] Frame %d, nr_tti_rx %d: ulsch_start = %d (rxoff %d, HW TA %d, timing advance %d, TA_offset %d\n",
-	  ue->Mod_id,frame_tx,nr_tti_tx,
-	  ulsch_start,
-	  ue->rx_offset,
-	  ue->hw_timing_advance,
-	  ue->timing_advance,
-	  ue->N_TA_offset);
-
-
-  for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
-    if (frame_parms->Ncp == 1)
-      PHY_ofdm_mod(&ue->common_vars.txdataF[aa][nr_tti_tx*nsymb*frame_parms->ofdm_symbol_size],
-#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706)
-		   dummy_tx_buffer,
-#else
-		   &ue->common_vars.txdata[aa][ulsch_start],
-#endif
-		   frame_parms->ofdm_symbol_size,
-		   nsymb,
-		   frame_parms->nb_prefix_samples,
-		   CYCLIC_PREFIX);
-    else
-      normal_prefix_mod(&ue->common_vars.txdataF[aa][nr_tti_tx*nsymb*frame_parms->ofdm_symbol_size],
-#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706)
-			dummy_tx_buffer,
-#else
-			&ue->common_vars.txdata[aa][ulsch_start],
-#endif
-			nsymb,
-			&ue->frame_parms);
-
-
-#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706)
-    apply_7_5_kHz(ue,dummy_tx_buffer,0);
-    apply_7_5_kHz(ue,dummy_tx_buffer,1);
-#else
-    apply_7_5_kHz(ue,&ue->common_vars.txdata[aa][ulsch_start],0);
-    apply_7_5_kHz(ue,&ue->common_vars.txdata[aa][ulsch_start],1);
-#endif
-
-
-#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706)
-    overflow = ulsch_start - 9*frame_parms->samples_per_subframe;
-
-
-    for (k=ulsch_start,l=0; k<cmin(frame_parms->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME,ulsch_start+frame_parms->samples_per_subframe); k++,l++) {
-      ((short*)ue->common_vars.txdata[aa])[2*k] = ((short*)dummy_tx_buffer)[2*l]<<4;
-      ((short*)ue->common_vars.txdata[aa])[2*k+1] = ((short*)dummy_tx_buffer)[2*l+1]<<4;
-    }
-
-    for (k=0; k<overflow; k++,l++) {
-      ((short*)ue->common_vars.txdata[aa])[2*k] = ((short*)dummy_tx_buffer)[2*l]<<4;
-      ((short*)ue->common_vars.txdata[aa])[2*k+1] = ((short*)dummy_tx_buffer)[2*l+1]<<4;
-    }
-#if defined(EXMIMO)
-    // handle switch before 1st TX nr_tti_rx, guarantee that the slot prior to transmission is switch on
-    for (k=ulsch_start - (frame_parms->samples_per_subframe>>1) ; k<ulsch_start ; k++) {
-      if (k<0)
-	ue->common_vars.txdata[aa][k+frame_parms->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME] &= 0xFFFEFFFE;
-      else if (k>(frame_parms->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME))
-	ue->common_vars.txdata[aa][k-frame_parms->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME] &= 0xFFFEFFFE;
-      else
-	ue->common_vars.txdata[aa][k] &= 0xFFFEFFFE;
-    }
-#endif
-#endif
-    /*
-      only for debug
-      LOG_I(PHY,"ul-signal [nr_tti_rx: %d, ulsch_start %d, TA: %d, rxOffset: %d, timing_advance: %d, hw_timing_advance: %d]\n",nr_tti_tx, ulsch_start, ue->N_TA_offset, ue->rx_offset, ue->timing_advance, ue->hw_timing_advance);
-      if( (crash == 1) && (nr_tti_tx == 0) )
-      {
-      LOG_E(PHY,"***** DUMP TX Signal [ulsch_start %d] *****\n",ulsch_start);
-      write_output("txBuff.m","txSignal",&ue->common_vars.txdata[aa][ulsch_start],frame_parms->samples_per_subframe,1,1);
-      }
-    */
-
-  } //nb_antennas_tx
-
-#if UE_TIMING_TRACE
-  stop_meas(&ue->ofdm_mod_stats);
-#endif
-
-  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_ULSCH_COMMON,VCD_FUNCTION_OUT);
-
-}
-
 #endif
 
 UE_MODE_t get_nrUE_mode(uint8_t Mod_id,uint8_t CC_id,uint8_t gNB_id){
@@ -1424,7 +1263,7 @@ void ue_ulsch_uespec_procedures(PHY_VARS_NR_UE *ue,
     }
 
     if (isBad) {
-      LOG_I(PHY,"Skip PUSCH generation!\n");
+      LOG_D(PHY,"Skip PUSCH generation!\n");
       ue->ulsch[eNB_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 0;
     }
   }
@@ -2229,7 +2068,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue,
 
   memset(ue->common_vars.txdataF[0], 0, sizeof(int)*14*ue->frame_parms.ofdm_symbol_size);
 
-  LOG_I(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
+  LOG_D(PHY,"****** start TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
 
 #if UE_TIMING_TRACE
   start_meas(&ue->phy_proc_tx);
@@ -2250,20 +2089,18 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue,
 */
 
    if (get_softmodem_params()->usim_test==0) {
-      LOG_D(PHY, "Sending PUCCH\n");
+      LOG_D(PHY, "Generating PUCCH\n");
       pucch_procedures_ue_nr(ue,
                              gNB_id,
                              proc,
-                             TRUE);
+                             FALSE);
    }
 
-    LOG_D(PHY, "Sending data \n");
+    LOG_D(PHY, "Sending Uplink data \n");
     nr_ue_pusch_common_procedures(ue,
-                                  harq_pid,
                                   slot_tx,
-                                  thread_id,
-                                  gNB_id,
-                                  &ue->frame_parms);
+                                  &ue->frame_parms,1);
+                                  //ue->ulsch[thread_id][gNB_id][0]->harq_processes[harq_pid]->pusch_pdu.nrOfLayers);
   }
   //LOG_M("txdata.m","txs",ue->common_vars.txdata[0],1228800,1,1);
 
@@ -2273,7 +2110,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue,
       nr_ue_prach_procedures(ue, proc, gNB_id, mode);
     }
   }
-  LOG_I(PHY,"****** end TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
+  LOG_D(PHY,"****** end TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_FUNCTION_OUT);
 #if UE_TIMING_TRACE
@@ -3026,7 +2863,7 @@ void copy_harq_proc_struct(NR_DL_UE_HARQ_t *harq_processes_dest, NR_DL_UE_HARQ_t
   memcpy(harq_ack_dest, current_harq_ack, sizeof(nr_harq_status_t));
   }*/
 
-void nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int eNB_id, PDSCH_t pdsch, NR_UE_DLSCH_t *dlsch0, NR_UE_DLSCH_t *dlsch1) {
+int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int eNB_id, PDSCH_t pdsch, NR_UE_DLSCH_t *dlsch0, NR_UE_DLSCH_t *dlsch1) {
 
   int nr_tti_rx = proc->nr_tti_rx;
   int m;
@@ -3034,9 +2871,9 @@ void nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int eNB
   int first_symbol_flag=0;
 
   if (!dlsch0)
-    return;
+    return 0;
   if (dlsch0->active == 0)
-    return;
+    return 0;
 
   if (!dlsch1)  {
     int harq_pid = dlsch0->current_harq_pid;
@@ -3047,7 +2884,7 @@ void nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int eNB
     uint16_t s0             = dlsch0->harq_processes[harq_pid]->start_symbol;
     uint16_t s1             = dlsch0->harq_processes[harq_pid]->nb_symbols;
 
-    LOG_D(PHY,"[UE %d] PDSCH type %d active in nr_tti_rx %d, harq_pid %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask %x\n",ue->Mod_id,pdsch,nr_tti_rx,harq_pid,pdsch_start_rb,pdsch_nb_rb,s0,s1,dlsch0->harq_processes[harq_pid]->dlDmrsSymbPos);
+    LOG_D(PHY,"[UE %d] PDSCH type %d active in nr_tti_rx %d, harq_pid %d (%d), rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask %x\n",ue->Mod_id,pdsch,nr_tti_rx,harq_pid,dlsch0->harq_processes[harq_pid]->status,pdsch_start_rb,pdsch_nb_rb,s0,s1,dlsch0->harq_processes[harq_pid]->dlDmrsSymbPos);
 
     // do channel estimation for first DMRS only
     for (m = s0; m < 3; m++) {
@@ -3081,8 +2918,8 @@ void nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int eNB
 #endif
       // process DLSCH received in first slot
       // skip DMRS symbols (will have to check later if PDSCH/DMRS are multiplexed
-      if (((1<<m)&dlsch0->harq_processes[harq_pid]->dlDmrsSymbPos) == 0) 
-	nr_rx_pdsch(ue,
+      if (((1<<m)&dlsch0->harq_processes[harq_pid]->dlDmrsSymbPos) == 0) { 
+	if (nr_rx_pdsch(ue,
 		    pdsch,
 		    eNB_id,
 		    eNB_id_i,
@@ -3092,20 +2929,25 @@ void nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int eNB
 		    first_symbol_flag,
 		    dual_stream_UE,
 		    i_mod,
-		    dlsch0->current_harq_pid);
+		    dlsch0->current_harq_pid) < 0)
+                      return -1;
+      }
       else { // This is to adjust the llr offset in the case of skipping over a dmrs symbol (i.e. in case of no PDSCH REs in DMRS)
-	if      (pdsch == RA_PDSCH) ue->pdsch_vars_ra[eNB_id]->llr_offset[m]=ue->pdsch_vars_ra[eNB_id]->llr_offset[m-1];
-	else if (pdsch == PDSCH)    nr_rx_pdsch(ue,
-                                  pdsch,
-                                  eNB_id,
-                                  eNB_id_i,
-                                  proc->frame_rx,
-                                  nr_tti_rx,  // nr_tti_rx,
-                                  m,
-                                  first_symbol_flag,
-                                  dual_stream_UE,
-                                  i_mod,
-                                  dlsch0->current_harq_pid);
+	if      (pdsch == RA_PDSCH) ue->pdsch_vars[ue->current_thread_id[nr_tti_rx]][eNB_id]->llr_offset[m]=ue->pdsch_vars[ue->current_thread_id[nr_tti_rx]][eNB_id]->llr_offset[m-1];
+	else if (pdsch == PDSCH) {
+          if (nr_rx_pdsch(ue,
+                    pdsch,
+                    eNB_id,
+                    eNB_id_i,
+                    proc->frame_rx,
+                    nr_tti_rx,  // nr_tti_rx,
+                    m,
+                    first_symbol_flag,
+                    dual_stream_UE,
+                    i_mod,
+                    dlsch0->current_harq_pid) < 0)
+                      return -1;
+        }
 	else AssertFatal(1==0,"not RA_PDSCH or PDSCH\n");
       }
       if (pdsch == PDSCH)  LOG_D(PHY,"Done processing symbol %d : llr_offset %d\n",m,ue->pdsch_vars[ue->current_thread_id[nr_tti_rx]][eNB_id]->llr_offset[m]);
@@ -3124,6 +2966,7 @@ void nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int eNB
 	}
     } // CRNTI active
   }
+  return 0;
 }
 
 // WIP fix:
@@ -3341,14 +3184,8 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
   if (1) {
     switch (pdsch) {
     case SI_PDSCH:
-      pdsch_vars = ue->pdsch_vars_SI[eNB_id];
-      break;
     case RA_PDSCH:
-      pdsch_vars = ue->pdsch_vars_ra[eNB_id];
-      break;
     case P_PDSCH:
-      pdsch_vars = ue->pdsch_vars_p[eNB_id];
-      break;
     case PDSCH:
       pdsch_vars = ue->pdsch_vars[ue->current_thread_id[nr_tti_rx]][eNB_id];
       break;
@@ -3377,6 +3214,9 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
       }
     }
 
+    // exit dlsch procedures as there are no active dlsch
+    if (is_cw0_active != ACTIVE && is_cw1_active != ACTIVE)
+      return;
 
     // start ldpc decode for CW 0
     dlsch0->harq_processes[harq_pid]->G = nr_get_G(dlsch0->harq_processes[harq_pid]->nb_rb,
@@ -3726,7 +3566,7 @@ void *UE_thread_slot1_dl_processing(void *arg) {
 
   int frame_rx;
   uint8_t nr_tti_rx;
-  uint8_t pilot0;
+  uint8_t pilot0; 
   uint8_t pilot1;
   uint8_t slot1;
 
@@ -4052,6 +3892,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
 
   int coreset_nb_rb=0;
   int coreset_start_rb=0;
+
   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);
   
@@ -4061,7 +3902,6 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
   if ((ue->decode_MIB == 1) && slot_pbch)
     {
       LOG_I(PHY," ------  PBCH ChannelComp/LLR: frame.slot %d.%d ------  \n", frame_rx%1024, nr_tti_rx);
-
       for (int i=1; i<4; i++) {
 
 	nr_slot_fep(ue,
@@ -4142,27 +3982,29 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
     } else if (ue->dlsch_ra[0]->active == 1){
       dlsch = ue->dlsch_ra[0];
     }
-    AssertFatal(dlsch != NULL, "Unsupported mode\n");
-    uint8_t harq_pid = dlsch->current_harq_pid;
-    NR_DL_UE_HARQ_t *dlsch0_harq = dlsch->harq_processes[harq_pid];
-    uint16_t nb_symb_sch = dlsch0_harq->nb_symbols;
-    uint16_t start_symb_sch = dlsch0_harq->start_symbol;
-    int symb_dmrs = -1;
-
-    LOG_D(PHY," ------ --> PDSCH ChannelComp/LLR Frame.slot %d.%d ------  \n", frame_rx%1024, nr_tti_rx);
-    //to update from pdsch config
-
-    for (int i=0;i<4;i++) if (((1<<i)&dlsch0_harq->dlDmrsSymbPos) > 0) {symb_dmrs=i;break;}
-    AssertFatal(symb_dmrs>=0,"no dmrs in 0..3\n");
-    LOG_D(PHY,"Initializing dmrs for symb %d DMRS mask %x\n",symb_dmrs,dlsch0_harq->dlDmrsSymbPos);
-    nr_gold_pdsch(ue,symb_dmrs,0, 1);
+
+    if (dlsch) {
+      uint8_t harq_pid = dlsch->current_harq_pid;
+      NR_DL_UE_HARQ_t *dlsch0_harq = dlsch->harq_processes[harq_pid];
+      uint16_t nb_symb_sch = dlsch0_harq->nb_symbols;
+      uint16_t start_symb_sch = dlsch0_harq->start_symbol;
+      int symb_dmrs = -1;
+
+      LOG_D(PHY," ------ --> PDSCH ChannelComp/LLR Frame.slot %d.%d ------  \n", frame_rx%1024, nr_tti_rx);
+      //to update from pdsch config
+
+      for (int i=0;i<4;i++) if (((1<<i)&dlsch0_harq->dlDmrsSymbPos) > 0) {symb_dmrs=i;break;}
+      AssertFatal(symb_dmrs>=0,"no dmrs in 0..3\n");
+      LOG_D(PHY,"Initializing dmrs for symb %d DMRS mask %x\n",symb_dmrs,dlsch0_harq->dlDmrsSymbPos);
+      nr_gold_pdsch(ue,symb_dmrs,0, 1);
     
-    for (uint16_t m=start_symb_sch;m<(nb_symb_sch+start_symb_sch) ; m++){
-      nr_slot_fep(ue,
+      for (uint16_t m=start_symb_sch;m<(nb_symb_sch+start_symb_sch) ; m++){
+        nr_slot_fep(ue,
                   m,  //to be updated from higher layer
                   nr_tti_rx,
                   0,
                   0);
+      }
     }
   } else {
     LOG_D(PHY,"[UE %d] Frame %d, nr_tti_rx %d: No DCIs found\n", ue->Mod_id, frame_rx, nr_tti_rx);
@@ -4174,9 +4016,10 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
   start_meas(&ue->generic_stat);
 #endif
   // do procedures for C-RNTI
+  int ret_pdsch = 0;
   if (ue->dlsch[ue->current_thread_id[nr_tti_rx]][eNB_id][0]->active == 1) {
     //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_IN);
-    nr_ue_pdsch_procedures(ue,
+    ret_pdsch = nr_ue_pdsch_procedures(ue,
 			   proc,
 			   eNB_id,
 			   PDSCH,
@@ -4271,7 +4114,8 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
     start_meas(&ue->dlsch_procedures_stat[ue->current_thread_id[nr_tti_rx]]);
 #endif
 
-    nr_ue_dlsch_procedures(ue,
+    if (ret_pdsch >= 0)
+      nr_ue_dlsch_procedures(ue,
 			   proc,
 			   eNB_id,
 			   PDSCH,
diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c
index f65e1f9633f14bdc898ca4937d6a6f8af2af1cd5..94214ab3b37a84010a0d7caa28efdf1eee746f5b 100644
--- a/openair1/SIMULATION/LTE_PHY/dlsim.c
+++ b/openair1/SIMULATION/LTE_PHY/dlsim.c
@@ -78,6 +78,8 @@ double t_rx_min = 1000000000; /*!< \brief initial min process time for rx */
 int n_tx_dropped = 0; /*!< \brief initial max process time for tx */
 int n_rx_dropped = 0; /*!< \brief initial max process time for rx */
 
+double DS_TDL = .03;
+
 int emulate_rf = 0;
 int split73=0;
 void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) {
@@ -161,7 +163,7 @@ void DL_channel(RU_t *ru,PHY_VARS_UE *UE,uint subframe,int awgn_flag,double SNR,
   // Multipath channel
   if (awgn_flag == 0) {
     multipath_channel(eNB2UE[round],s_re,s_im,r_re,r_im,
-                      2*UE->frame_parms.samples_per_tti,hold_channel);
+                      2*UE->frame_parms.samples_per_tti,hold_channel,0);
 
     //      printf("amc: ****************** eNB2UE[%d]->n_rx = %d,dd %d\n",round,eNB2UE[round]->nb_rx,eNB2UE[round]->channel_offset);
     if(abstx==1 && num_rounds>1)
@@ -1172,6 +1174,7 @@ int main(int argc, char **argv) {
                                    channel_model,
                                    N_RB2sampling_rate(eNB->frame_parms.N_RB_DL),
                                    N_RB2channel_bandwidth(eNB->frame_parms.N_RB_DL),
+                                   DS_TDL,
                                    forgetting_factor,
                                    rx_sample_offset,
                                    0);
@@ -1185,6 +1188,7 @@ int main(int argc, char **argv) {
                                        channel_model,
                                        N_RB2sampling_rate(eNB->frame_parms.N_RB_DL),
                                        N_RB2channel_bandwidth(eNB->frame_parms.N_RB_DL),
+                                       DS_TDL,
                                        forgetting_factor,
                                        rx_sample_offset,
                                        0);
diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c
index c950d6f4da2079fe3a23af075fe8e6f5ceb1e547..37ce3a65d60b5f60007bd07a8ed445a9c944be83 100644
--- a/openair1/SIMULATION/LTE_PHY/ulsim.c
+++ b/openair1/SIMULATION/LTE_PHY/ulsim.c
@@ -729,6 +729,7 @@ int main(int argc, char **argv) {
                                 channel_model,
                                 N_RB2sampling_rate(eNB->frame_parms.N_RB_UL),
                                 N_RB2channel_bandwidth(eNB->frame_parms.N_RB_UL),
+                                30e-9,
                                 forgetting_factor,
                                 delay,
                                 0);
@@ -1086,7 +1087,7 @@ int main(int argc, char **argv) {
           if (awgn_flag == 0) {
             if (UE2eNB->max_Doppler == 0) {
               multipath_channel(UE2eNB,s_re,s_im,r_re,r_im,
-                                eNB->frame_parms.samples_per_tti,hold_channel);
+                                eNB->frame_parms.samples_per_tti,hold_channel,0);
             } else {
               multipath_tv_channel(UE2eNB,s_re,s_im,r_re,r_im,
                                    2*eNB->frame_parms.samples_per_tti,hold_channel);
diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c
index 5e2d42a0f72ad569d56dbbeb841b1ac4e214995c..957495181af8688fe136f590578321a85729eb4b 100644
--- a/openair1/SIMULATION/NR_PHY/dlschsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlschsim.c
@@ -58,7 +58,8 @@ double cpuf;
 uint8_t nfapi_mode = 0;
 uint16_t NB_UE_INST = 1;
 
-
+uint8_t const nr_rv_round_map[4] = {0, 2, 1, 3};
+uint8_t const nr_rv_round_map_ue[4] = {0, 2, 1, 3};
 
 // needed for some functions
 PHY_VARS_NR_UE *PHY_vars_UE_g[1][1] = { { NULL } };
@@ -113,7 +114,7 @@ int main(int argc, char **argv)
 	uint16_t nb_rb = 50;
 	uint8_t Imcs = 9;
         uint8_t mcs_table = 0;
-
+        double DS_TDL = .03;
 	cpuf = get_cpu_freq_GHz();
 
 	if (load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY) == 0) {
@@ -336,6 +337,7 @@ int main(int argc, char **argv)
 	gNB2UE = new_channel_desc_scm(n_tx, n_rx, channel_model, 
 				      61.44e6, //N_RB2sampling_rate(N_RB_DL),
 				      40e6, //N_RB2channel_bandwidth(N_RB_DL),
+                                      DS_TDL,
 				      0, 0, 0);
 
 	if (gNB2UE == NULL) {
@@ -499,7 +501,7 @@ int main(int argc, char **argv)
 	//printf("crc32: [0]->0x%08x\n",crc24c(test_input, 32));
 	// generate signal
 	if (input_fd == NULL) {
-		nr_dlsch_encoding(test_input, frame, slot, dlsch, frame_parms,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+		nr_dlsch_encoding(gNB, test_input, frame, slot, dlsch, frame_parms,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
 	}
 
 	for (SNR = snr0; SNR < snr1; SNR += snr_step) {
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index 64ab482db894faef45b7637b5ae70e0277a970de..38400cab51aaaf8c74b5561eeb1aff093eb8323c 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -38,8 +38,10 @@
 #include "PHY/types.h"
 #include "PHY/INIT/phy_init.h"
 #include "PHY/MODULATION/modulation_eNB.h"
+#include "PHY/MODULATION/nr_modulation.h"
 #include "PHY/MODULATION/modulation_UE.h"
 #include "PHY/NR_REFSIG/refsig_defs_ue.h"
+#include "PHY/NR_TRANSPORT/nr_dlsch.h"
 #include "PHY/NR_TRANSPORT/nr_transport_proto.h"
 #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
 #include "SCHED_NR/fapi_nr_l1.h"
@@ -122,7 +124,7 @@ int generate_dlsch_header(unsigned char *mac_header,
                           unsigned char *ue_cont_res_id,
                           unsigned char short_padding,
                           unsigned short post_padding){return 0;}
-void nr_ip_over_LTE_DRB_preconfiguration(void){}
+void nr_DRB_preconfiguration(void){}
 
 // needed for some functions
 openair0_config_t openair0_cfg[MAX_CARDS];
@@ -180,7 +182,7 @@ int main(int argc, char **argv)
 
   //unsigned char frame_type = 0;
 
-  int frame=0,slot=1;
+  int frame=1,slot=1;
   int frame_length_complex_samples;
   int frame_length_complex_samples_no_prefix;
   NR_DL_FRAME_PARMS *frame_parms;
@@ -191,7 +193,8 @@ int main(int argc, char **argv)
   int cyclic_prefix_type = NFAPI_CP_NORMAL;
   int run_initial_sync=0;
   int do_pdcch_flag=1;
-
+  int pusch_tgt_snrx10 = 200;
+  int pucch_tgt_snrx10 = 200;
   int loglvl=OAILOG_INFO;
 
   float target_error_rate = 0.01;
@@ -528,9 +531,9 @@ int main(int argc, char **argv)
   AssertFatal((gNB->if_inst         = NR_IF_Module_init(0))!=NULL,"Cannot register interface");
   gNB->if_inst->NR_PHY_config_req      = nr_phy_config_request;
   // common configuration
-  rrc_mac_config_req_gNB(0,0,1,scc,0,0,NULL);
+  rrc_mac_config_req_gNB(0,0,1,pusch_tgt_snrx10,pucch_tgt_snrx10,scc,0,0,NULL);
   // UE dedicated configuration
-  rrc_mac_config_req_gNB(0,0,1,NULL,1,secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup);
+  rrc_mac_config_req_gNB(0,0,1,pusch_tgt_snrx10,pucch_tgt_snrx10,NULL,1,secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup);
   phy_init_nr_gNB(gNB,0,0);
   N_RB_DL = gNB->frame_parms.N_RB_DL;
   // stub to configure frame_parms
@@ -571,6 +574,7 @@ int main(int argc, char **argv)
                                 channel_model,
  				fs,
 				bw,
+				30e-9,
                                 0,
                                 0,
                                 0);
@@ -713,12 +717,16 @@ int main(int argc, char **argv)
     reset_meas(&gNB->tparity);
     reset_meas(&gNB->toutput);  
 
+    clear_pdsch_stats(gNB);
+
     n_errors = 0;
     effRate = 0;
     //n_errors2 = 0;
     //n_alamouti = 0;
     errors_scrambling=0;
     n_false_positive = 0;
+    if (n_trials== 1) num_rounds = 1;
+
     for (trial = 0; trial < n_trials; trial++) {
 
       errors_bit = 0;
@@ -753,6 +761,7 @@ int main(int argc, char **argv)
 
         UE_list->UE_sched_ctrl[0].harq_processes[harq_pid].ndi = !(trial&1);
 
+
         UE_list->UE_sched_ctrl[0].harq_processes[harq_pid].round = round;   
         UE_list->UE_sched_ctrl[0].current_harq_pid = harq_pid;
         gNB->dlsch[0][0]->harq_processes[harq_pid]->round = round;
@@ -777,12 +786,12 @@ int main(int argc, char **argv)
         int txdataF_offset = (slot%2) * frame_parms->samples_per_slot_wCP;
         
         if (n_trials==1) {
-          LOG_M("txsigF0.m","txsF0", gNB->common_vars.txdataF[0],frame_length_complex_samples_no_prefix,1,1);
+          LOG_M("txsigF0.m","txsF0", &gNB->common_vars.txdataF[0][txdataF_offset],frame_parms->samples_per_slot_wCP,1,1);
           if (gNB->frame_parms.nb_antennas_tx>1)
-          LOG_M("txsigF1.m","txsF1", gNB->common_vars.txdataF[1],frame_length_complex_samples_no_prefix,1,1);
+          LOG_M("txsigF1.m","txsF1", &gNB->common_vars.txdataF[1][txdataF_offset],frame_parms->samples_per_slot_wCP,1,1);
         }
         int tx_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0);
-        if (n_trials==1) printf("samples_per_slot_wCP = %d\n", frame_parms->samples_per_slot_wCP);
+        if (n_trials==1) printf("tx_offset %d, txdataF_offset %d \n", tx_offset,txdataF_offset);
         
         //TODO: loop over slots
         for (aa=0; aa<gNB->frame_parms.nb_antennas_tx; aa++) {
@@ -794,24 +803,51 @@ int main(int argc, char **argv)
                          12,
                          frame_parms->nb_prefix_samples,
                          CYCLIC_PREFIX);
-          } else {
+          } else {/*
             nr_normal_prefix_mod(&gNB->common_vars.txdataF[aa][txdataF_offset],
                                  &txdata[aa][tx_offset],
                                  14,
                                  frame_parms);
+		  */
+	    PHY_ofdm_mod(&gNB->common_vars.txdataF[aa][txdataF_offset],
+			 (int*)&txdata[aa][tx_offset],
+			 frame_parms->ofdm_symbol_size,
+			 1,
+			 frame_parms->nb_prefix_samples0,
+			 CYCLIC_PREFIX);
+	    	    
+	    apply_nr_rotation(frame_parms,
+			      (int16_t*)&txdata[aa][tx_offset],
+			      slot,
+			      0,
+			      1,
+			      frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples0);
+	    PHY_ofdm_mod(&gNB->common_vars.txdataF[aa][txdataF_offset+frame_parms->ofdm_symbol_size],
+			 (int*)&txdata[aa][tx_offset+frame_parms->nb_prefix_samples0+frame_parms->ofdm_symbol_size],
+			 frame_parms->ofdm_symbol_size,
+			 13,
+			 frame_parms->nb_prefix_samples,
+			 CYCLIC_PREFIX);
+	    apply_nr_rotation(frame_parms,
+			      (int16_t*)&txdata[aa][tx_offset+frame_parms->nb_prefix_samples0+frame_parms->ofdm_symbol_size],
+			      slot,
+			      1,
+			      13,
+			      frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples);
+	    
           }
         }
        
         if (n_trials==1) {
-          LOG_M("txsig0.m","txs0", txdata[0],frame_length_complex_samples,1,1);
+          LOG_M("txsig0.m","txs0", &txdata[0][tx_offset],frame_parms->get_samples_slot_timestamp(slot,frame_parms,0),1,1);
           if (gNB->frame_parms.nb_antennas_tx>1)
-            LOG_M("txsig1.m","txs1", txdata[1],frame_length_complex_samples,1,1);
+            LOG_M("txsig1.m","txs1", &txdata[1][tx_offset],frame_parms->get_samples_slot_timestamp(slot,frame_parms,0),1,1);
         }
         if (output_fd) {
           printf("writing txdata to binary file\n");
           fwrite(txdata[0],sizeof(int32_t),frame_length_complex_samples,output_fd);
         }
-        
+
         int txlev = signal_energy(&txdata[0][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)+5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0], frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples);
         
         //  if (n_trials==1) printf("txlev %d (%f)\n",txlev,10*log10((double)txlev));
@@ -923,6 +959,7 @@ int main(int argc, char **argv)
            (float) n_errors / (float) n_trials);
     printf("*****************************************\n");
     printf("\n");
+    dump_pdsch_stats(gNB);
     printf("SNR %f : n_errors (negative CRC) = %d/%d, Avg round %.2f, Channel BER %e, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %d bits/slot\n", SNR, n_errors, n_trials,roundStats[snrRun],(double)errors_scrambling/available_bits/n_trials,effRate,effRate/TBS*100,TBS);
     printf("\n");
 
@@ -984,6 +1021,7 @@ int main(int argc, char **argv)
 	LOG_M("rxsig1.m","rxs1", UE->common_vars.rxdata[1], frame_length_complex_samples, 1, 1);
       LOG_M("chestF0.m","chF0",UE->pdsch_vars[0][0]->dl_ch_estimates_ext,N_RB_DL*12*14,1,1);
       write_output("rxF_comp.m","rxFc",&UE->pdsch_vars[0][0]->rxdataF_comp0[0][0],N_RB_DL*12*14,1,1);
+      LOG_M("rxF_llr.m","rxFllr",UE->pdsch_vars[UE->current_thread_id[UE_proc.nr_tti_rx]][0]->llr[0],available_bits,1,0);
       break;
     }
 
diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c
index 8c37024858408eac29cc897d662f3af267d5b436..833b81f853b1d604d90825eee24dde1ae361e7fe 100644
--- a/openair1/SIMULATION/NR_PHY/pbchsim.c
+++ b/openair1/SIMULATION/NR_PHY/pbchsim.c
@@ -59,6 +59,10 @@ uint16_t NB_UE_INST = 1;
 
 // needed for some functions
 openair0_config_t openair0_cfg[MAX_CARDS];
+
+uint8_t const nr_rv_round_map[4] = {0, 2, 1, 3};
+uint8_t const nr_rv_round_map_ue[4] = {0, 2, 1, 3};
+
 uint64_t get_softmodem_optmask(void) {return 0;}
 
 void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) {}
@@ -104,6 +108,9 @@ void nr_phy_config_request_sim_pbchsim(PHY_VARS_gNB *gNB,
   gNB_config->carrier_config.dl_bandwidth.value = config_bandwidth(mu, N_RB_DL, fp->nr_band);
 
   nr_init_frame_parms(gNB_config, fp);
+
+  init_symbol_rotation(fp,fp->dl_CarrierFreq);
+
   gNB->configured    = 1;
   LOG_I(PHY,"gNB configured\n");
 }
@@ -467,6 +474,7 @@ int main(int argc, char **argv)
                                 channel_model,
  				fs, 
 				bw, 
+				300e-9,
                                 0,
                                 0,
                                 0);
@@ -547,10 +555,35 @@ int main(int argc, char **argv)
 				     frame_parms->nb_prefix_samples,
 				     CYCLIC_PREFIX);
     		} else {
-    			nr_normal_prefix_mod(gNB->common_vars.txdataF[aa],
+		  /*    			nr_normal_prefix_mod(gNB->common_vars.txdataF[aa],
     			                     &txdata[aa][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)],
 			                     14,
-			                     frame_parms);
+			                     frame_parms);*/
+		  PHY_ofdm_mod(gNB->common_vars.txdataF[aa],
+			       (int*)&txdata[aa][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)],
+			       frame_parms->ofdm_symbol_size,
+			       1,
+			       frame_parms->nb_prefix_samples0,
+			       CYCLIC_PREFIX);
+		  
+		  apply_nr_rotation(frame_parms,
+				    (int16_t*)&txdata[aa][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)],
+				    slot,
+				    0,
+				    1,
+				    frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples0);
+		  PHY_ofdm_mod(&gNB->common_vars.txdataF[aa][frame_parms->ofdm_symbol_size],
+			       (int*)&txdata[aa][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)+frame_parms->nb_prefix_samples0+frame_parms->ofdm_symbol_size],
+			       frame_parms->ofdm_symbol_size,
+			       13,
+			       frame_parms->nb_prefix_samples,
+			       CYCLIC_PREFIX);
+		  apply_nr_rotation(frame_parms,
+				    (int16_t*)&txdata[aa][frame_parms->get_samples_slot_timestamp(slot,frame_parms,0)+frame_parms->nb_prefix_samples0+frame_parms->ofdm_symbol_size],
+				    slot,
+				    1,
+				    13,
+				    frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples);
     		}
     	}
     }
diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c
index 950f9a67f665a0c548e56650af71889dea70dfd0..7d96e70809724ca4d92479a5f29e3305ac54812e 100644
--- a/openair1/SIMULATION/NR_PHY/prachsim.c
+++ b/openair1/SIMULATION/NR_PHY/prachsim.c
@@ -75,7 +75,7 @@ boolean_t pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP,
                         const sdu_size_t   sdu_buffer_sizeP,
                         mem_block_t *const sdu_buffer_pP) {return(false);}
 
-void nr_ip_over_LTE_DRB_preconfiguration(void){}
+void nr_DRB_preconfiguration(void){}
 void pdcp_layer_init(void) {}
 int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, const int CC_id, const uint8_t gNB_index, const int8_t channel, const uint8_t* pduP, const sdu_size_t pdu_len) {return 0;}
 
@@ -92,6 +92,7 @@ int main(int argc, char **argv){
   uint16_t Nid_cell = 0, preamble_tx = 0, preamble_delay, format, format0, format1;
   uint32_t tx_lev = 10000, prach_errors = 0, samp_count; //,tx_lev_dB;
   uint64_t SSB_positions = 0x01, absoluteFrequencyPointA = 640000;
+  double DS_TDL = .03;
 
   //  int8_t interf1=-19,interf2=-19;
   //  uint8_t abstraction_flag=0,calibration_flag=0;
@@ -557,6 +558,7 @@ int main(int argc, char **argv){
                                 channel_model,
                                 fs,
                                 bw,
+                                DS_TDL,
                                 0.0,
                                 delay,
                                 0);
@@ -602,7 +604,7 @@ int main(int argc, char **argv){
   /* tx_lev_dB not used later, no need to set */
   //tx_lev_dB = (unsigned int) dB_fixed(tx_lev);
 
-  prach_start = subframe*frame_parms->samples_per_subframe-UE->N_TA_offset;
+  prach_start = subframe*frame_parms->samples_per_subframe;
 
   #ifdef NR_PRACH_DEBUG
   LOG_M("txsig0.m", "txs0", &txdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1);
diff --git a/openair1/SIMULATION/NR_PHY/pucchsim.c b/openair1/SIMULATION/NR_PHY/pucchsim.c
index 86f7d651e40129023245d2ca82e2719caca32a7a..c14a3d719843ebb1fa73b2351dcc77defcc13606 100644
--- a/openair1/SIMULATION/NR_PHY/pucchsim.c
+++ b/openair1/SIMULATION/NR_PHY/pucchsim.c
@@ -35,6 +35,7 @@
 #include "PHY/NR_REFSIG/refsig_defs_ue.h"
 #include "PHY/MODULATION/modulation_eNB.h"
 #include "PHY/MODULATION/modulation_UE.h"
+#include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
 #include "PHY/INIT/phy_init.h"
 #include "PHY/NR_TRANSPORT/nr_transport_proto.h"
 #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
@@ -54,6 +55,8 @@ int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
 double cpuf;
 uint8_t nfapi_mode = 0;
 uint16_t NB_UE_INST = 1;
+uint8_t const nr_rv_round_map[4] = {0, 2, 1, 3};
+uint8_t const nr_rv_round_map_ue[4] = {0, 2, 1, 3};
 
 // needed for some functions
 PHY_VARS_NR_UE * PHY_vars_UE_g[1][1]={{NULL}};
@@ -77,11 +80,11 @@ int main(int argc, char **argv)
   //int freq_offset;
   //int subframe_offset;
   //char fname[40], vname[40];
-  int trial,n_trials=100,n_errors=0,ack_nack_errors=0;
+  int trial,n_trials=100,n_errors=0,ack_nack_errors=0,sr_errors=0;
   uint8_t transmission_mode = 1,n_tx=1,n_rx=1;
   uint16_t Nid_cell=0;
   uint64_t SSB_positions=0x01;
-  channel_desc_t *gNB2UE;
+  channel_desc_t *UE2gNB;
   int format=0;
   //uint8_t extended_prefix_flag=0;
   FILE *input_fd=NULL;
@@ -97,6 +100,8 @@ int main(int argc, char **argv)
   uint16_t nrofPRB=2;
   uint8_t timeDomainOCC=0;
   SCM_t channel_model=AWGN;//Rayleigh1_anticorr;
+
+  double DS_TDL = .03;
   
   int N_RB_DL=273,mu=1;
   float target_error_rate=0.001;
@@ -159,6 +164,20 @@ int main(int argc, char **argv)
       case 'G':
         channel_model=ETU;
         break;
+      case 'H':
+        channel_model = TDL_C;
+	DS_TDL = .030; // 30 ns
+	break;
+  
+      case 'I':
+	channel_model = TDL_C;
+	DS_TDL = .3;  // 300ns
+        break;
+     
+      case 'J':
+	channel_model=TDL_D;
+	DS_TDL = .03;
+	break;
 
       default:
         printf("Unsupported channel model!\n");
@@ -399,9 +418,9 @@ int main(int argc, char **argv)
 	printf("FFO = %lf; IFO = %d\n",eps-IFO,IFO);
   }
 
-  gNB2UE = new_channel_desc_scm(n_tx, n_rx, channel_model, fs, bw, 0, 0, 0);
+  UE2gNB = new_channel_desc_scm(n_tx, n_rx, channel_model, fs, bw, DS_TDL,0, 0, 0);
 
-  if (gNB2UE==NULL) {
+  if (UE2gNB==NULL) {
     printf("Problem generating channel model. Exiting.\n");
     exit(-1);
   }
@@ -460,20 +479,24 @@ int main(int argc, char **argv)
   uint32_t dmrs_scrambling_id = 0, data_scrambling_id=0;
   //t_nrPolar_params *currentPtr;
 
+  int shift = 0;
+
   if(format==0){
-  // for now we are not considering SR just HARQ-ACK
+    if (sr_flag)
+      shift = 1<<nr_bit;
     if (nr_bit ==0) 
       mcs=table1_mcs[0];
     else if(nr_bit==1)
-      mcs=table1_mcs[actual_payload];
+      mcs=table1_mcs[actual_payload+shift];
     else if(nr_bit==2)
-      mcs=table2_mcs[actual_payload];
+      mcs=table2_mcs[actual_payload+shift];
     else AssertFatal(1==0,"Either nr_bit %d or sr_flag %d must be non-zero\n", nr_bit, sr_flag);
   }
   else if (format == 2 && nr_bit > 11) gNB->uci_polarParams = nr_polar_params(2, nr_bit, nrofPRB, 1, NULL);
   
   for(SNR=snr0;SNR<=snr1;SNR=SNR+1){
     ack_nack_errors=0;
+    sr_errors=0;
     n_errors = 0;
     for (trial=0; trial<n_trials; trial++) {
       bzero(txdataF[aa],frame_parms->ofdm_symbol_size*sizeof(int));
@@ -502,6 +525,15 @@ int main(int argc, char **argv)
       }
       int rxlev = signal_energy(&rxdataF[aa][startingSymbolIndex*frame_parms->ofdm_symbol_size],
 				frame_parms->ofdm_symbol_size);
+
+      // noise measurement
+      gNB->ulmask_symb = startingSymbolIndex;
+      for (int rb=0; rb<nrofPRB; rb++) {
+        int rb2 = rb+startingPRB;
+        gNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31));
+      }
+      gNB_I0_measurements(gNB);
+
       if (n_trials==1) printf("rxlev %d (%d dB), sigma2 %f dB, SNR %f, TX %f\n",rxlev,dB_fixed(rxlev),sigma2_dB,SNR,10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12));
       if(format==0){
 	nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu;
@@ -519,15 +551,23 @@ int main(int argc, char **argv)
 	pucch_pdu.start_symbol_index    = startingSymbolIndex;
 	pucch_pdu.prb_start             = startingPRB;
         nr_decode_pucch0(gNB,nr_tti_tx,&uci_pdu,&pucch_pdu);
-        if(nr_bit==1)
-          ack_nack_errors+=(actual_payload^uci_pdu.harq->harq_list[0].harq_value);
-        else
-          ack_nack_errors+=(((actual_payload&1)^uci_pdu.harq->harq_list[0].harq_value)+((actual_payload>>1)^uci_pdu.harq->harq_list[1].harq_value));
-	free(uci_pdu.harq->harq_list);
+        if(sr_flag==1){
+          if (uci_pdu.sr->sr_indication == 0 || uci_pdu.sr->sr_confidence_level == 1)
+            sr_errors+=1;
+        }
+        if(nr_bit>0){
+          if(nr_bit==1)
+            ack_nack_errors+=(actual_payload^uci_pdu.harq->harq_list[0].harq_value);
+          else
+            ack_nack_errors+=(((actual_payload&1)^uci_pdu.harq->harq_list[0].harq_value)+((actual_payload>>1)^uci_pdu.harq->harq_list[1].harq_value));
+	  free(uci_pdu.harq->harq_list);
+        }
       }
       else if (format==1) {
-	
-        nr_decode_pucch1(rxdataF,PUCCH_GroupHopping,hopping_id,&(payload_received),frame_parms,amp,nr_tti_tx,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,timeDomainOCC,nr_bit);
+        nr_decode_pucch1(rxdataF,PUCCH_GroupHopping,hopping_id,
+                         &(payload_received),frame_parms,amp,nr_tti_tx,
+                         m0,nrofSymbols,startingSymbolIndex,startingPRB,
+                         startingPRB_intraSlotHopping,timeDomainOCC,nr_bit);
         if(nr_bit==1)
           ack_nack_errors+=((actual_payload^payload_received)&1);
         else
@@ -566,8 +606,11 @@ int main(int argc, char **argv)
       }
       n_errors=((actual_payload^payload_received)&1)+(((actual_payload^payload_received)&2)>>1)+(((actual_payload^payload_received)&4)>>2)+n_errors;
     }
-    printf("SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,ack_nack_errors);
-    if((float)ack_nack_errors/(float)(n_trials)<=target_error_rate){
+    if (sr_flag == 1)
+      printf("SR: SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,sr_errors);
+    if(nr_bit > 0)
+      printf("ACK/NACK: SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,ack_nack_errors);
+    if((float)(ack_nack_errors+sr_errors)/(float)(n_trials)<=target_error_rate){
       printf("PUCCH test OK\n");
       break;
     }
diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c
index af49aa757b94f88d2082def48678bae547ac62a8..f6d33c1d4b7fdb204f049118e96be60b5b648488 100644
--- a/openair1/SIMULATION/NR_PHY/ulschsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulschsim.c
@@ -55,6 +55,9 @@ int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
 
 void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) {}
 
+uint8_t const nr_rv_round_map[4] = {0, 2, 1, 3};
+uint8_t const nr_rv_round_map_ue[4] = {0, 2, 1, 3};
+
 double cpuf;
 uint8_t nfapi_mode = 0;
 uint16_t NB_UE_INST = 1;
@@ -96,6 +99,8 @@ int main(int argc, char **argv)
   uint16_t nb_rb = 50;
   uint8_t Imcs = 9;
 
+  double DS_TDL = .03;
+
   cpuf = get_cpu_freq_GHz();
 
   if (load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY) == 0) {
@@ -315,13 +320,12 @@ int main(int argc, char **argv)
     snr1 = snr0 + 10;
 
   gNB2UE = new_channel_desc_scm(n_tx,
-		                        n_rx,
-								channel_model,
+		                n_rx,
+				channel_model,
                                 61.44e6, //N_RB2sampling_rate(N_RB_DL),
                                 40e6, //N_RB2channel_bandwidth(N_RB_DL),
-                                0,
-								0,
-								0);
+                                DS_TDL,
+                                0,0,0);
 
   if (gNB2UE == NULL) {
     printf("Problem generating channel model. Exiting.\n");
diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c
index 934c6a2e6c84be9ae693d63ce216d0a7c36b2793..2eea321f165852f2841c757712798705eac59c84 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -55,7 +55,6 @@
 //#include "openair1/SIMULATION/NR_PHY/nr_dummy_functions.c"
 #include "openair2/LAYER2/NR_MAC_UE/mac_proto.h"
 #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
-
 #define inMicroS(a) (((double)(a))/(cpu_freq_GHz*1000.0))
 #include "SIMULATION/LTE_PHY/common_sim.h"
 
@@ -96,13 +95,20 @@ boolean_t pdcp_data_ind(
 ) { return(false);}
 
 void pdcp_run (const protocol_ctxt_t *const  ctxt_pP) { return;}
-void nr_ip_over_LTE_DRB_preconfiguration(void){}
+void nr_DRB_preconfiguration(void){}
 int rrc_init_nr_global_param(void){return(0);}
 
 
 // needed for some functions
 uint16_t n_rnti = 0x1234;
 openair0_config_t openair0_cfg[MAX_CARDS];
+//const uint8_t nr_rv_round_map[4] = {0, 2, 1, 3}; 
+
+channel_desc_t *UE2gNB[NUMBER_OF_UE_MAX][NUMBER_OF_gNB_MAX];
+double s_re0[122880],s_im0[122880],r_re0[122880],r_im0[122880];
+double s_re1[122880],s_im1[122880],r_re1[122880],r_im1[122880];
+double r_re2[122880],r_im2[122880];
+double r_re3[122880],r_im3[122880];
 
 int main(int argc, char **argv)
 {
@@ -112,27 +118,35 @@ int main(int argc, char **argv)
   double sigma, sigma_dB;
   double snr_step = .2;
   uint8_t snr1set = 0;
-  int slot = 8, frame = 0;
+  int slot = 8, frame = 1;
   FILE *output_fd = NULL;
+  double *s_re[2]= {s_re0,s_re1};
+  double *s_im[2]= {s_im0,s_im1};
+  double *r_re[4]= {r_re0,r_re1,r_re2,r_re3};
+  double *r_im[4]= {r_im0,r_im1,r_im2,r_im3};
   //uint8_t write_output_file = 0;
-  int trial, n_trials = 1, n_errors = 0, n_false_positive = 0, delay = 0;
+  int trial, n_trials = 1, n_false_positive = 0, delay = 0;
+  double maxDoppler = 0.0;
   uint8_t n_tx = 1, n_rx = 1;
   //uint8_t transmission_mode = 1;
   //uint16_t Nid_cell = 0;
-  channel_desc_t *gNB2UE;
+  channel_desc_t *UE2gNB;
   uint8_t extended_prefix_flag = 0;
   //int8_t interf1 = -21, interf2 = -21;
   FILE *input_fd = NULL;
   SCM_t channel_model = AWGN;  //Rayleigh1_anticorr;
   uint16_t N_RB_DL = 106, N_RB_UL = 106, mu = 1;
+  double tx_gain=1.0;
+  double N0=30;
+
   //unsigned char frame_type = 0;
   NR_DL_FRAME_PARMS *frame_parms;
-  int loglvl = OAILOG_WARNING;
+  int loglvl = OAILOG_INFO;
   //uint64_t SSB_positions=0x01;
   uint16_t nb_symb_sch = 12;
-  int start_symbol = 2;
+  int start_symbol = 0;
   uint16_t nb_rb = 50;
-  uint8_t Imcs = 9;
+  int Imcs = 9;
   uint8_t precod_nbr_layers = 1;
   int gNB_id = 0;
   int ap;
@@ -145,9 +159,12 @@ int main(int argc, char **argv)
   int print_perf = 0;
   cpuf = get_cpu_freq_GHz();
   int msg3_flag = 0;
+  int rv_index = 0;
+  float roundStats[50];
+  float effRate; 
+  //float eff_tp_check = 0.7;
+  uint8_t snrRun;
 
-  UE_nr_rxtx_proc_t UE_proc;
-  FILE *scg_fd=NULL;
   int enable_ptrs = 0;
   int modify_dmrs = 0;
   /* L_PTRS = ptrs_arg[0], K_PTRS = ptrs_arg[1] */
@@ -156,6 +173,14 @@ int main(int argc, char **argv)
   int dmrs_arg[2] = {-1,-1};// Invalid values
   uint8_t dmrs_type = typeB; // Default Values
   pusch_dmrs_AdditionalPosition_t add_pos = pusch_dmrs_pos0; // Default Values
+
+  UE_nr_rxtx_proc_t UE_proc;
+  FILE *scg_fd=NULL;
+  int file_offset = 0;
+
+  double DS_TDL = .03;
+  int pusch_tgt_snrx10 = 200;
+  int pucch_tgt_snrx10 = 200;
   int ibwps=24;
   int ibwp_rboffset=41;
   if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0 ) {
@@ -165,7 +190,7 @@ int main(int argc, char **argv)
   //logInit();
   randominit(0);
 
-  while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:j:kl:m:n:p:r:s:y:z:F:M:N:PR:S:T:U:L:")) != -1) {
+  while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:j:kl:m:n:p:r:s:y:z:F:G:H:M:N:PR:S:T:U:L:")) != -1) {
     printf("handling optarg %c\n",c);
     switch (c) {
 
@@ -234,7 +259,22 @@ int main(int argc, char **argv)
       case 'G':
 	channel_model = ETU;
 	break;
-	
+
+      case 'H':
+        channel_model = TDL_C;
+	DS_TDL = .030; // 30 ns
+	break;
+  
+      case 'I':
+	channel_model = TDL_C;
+	DS_TDL = .3;  // 300ns
+        break;
+     
+      case 'J':
+	channel_model=TDL_D;
+	DS_TDL = .03;
+	break;
+
       default:
 	printf("Unsupported channel model!\n");
 	exit(-1);
@@ -279,7 +319,12 @@ int main(int argc, char **argv)
       snr0 = atof(optarg);
       printf("Setting SNR0 to %f\n", snr0);
       break;
-      
+
+/*
+    case 't':
+      eff_tp_check = (float)atoi(optarg)/100;
+      break;
+*/
       /*
 	case 'r':
 	ricean_factor = pow(10,-.1*atof(optarg));
@@ -323,7 +368,15 @@ int main(int argc, char **argv)
       }
       
       break;
-      
+
+    case 'G':
+      file_offset = atoi(optarg);
+      break;
+
+    case 'H':
+      slot = atoi(optarg);
+      break;
+
     case 'M':
      // SSB_positions = atoi(optarg);
       break;
@@ -365,6 +418,7 @@ int main(int argc, char **argv)
         dmrs_arg[i] = atoi(argv[optind++]);
       }
       break;
+
     default:
     case 'h':
       printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -t Delayspread -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n", argv[0]);
@@ -391,6 +445,7 @@ int main(int argc, char **argv)
       printf("-N Nid_cell\n");
       printf("-O oversampling factor (1,2,4,8,16)\n");
       printf("-R N_RB_DL\n");
+      printf("-t Acceptable effective throughput (in percentage)\n");
       printf("-S Ending SNR, runs from SNR0 to SNR1\n");
       printf("-P Print ULSCH performances\n");
       printf("-T Enable PTRS, arguments list L_PTRS{0,1,2} K_PTRS{2,4}, e.g. -T 2 0 2 \n");
@@ -412,17 +467,32 @@ int main(int argc, char **argv)
 
   if (snr1set == 0)
     snr1 = snr0 + 10;
-
-  gNB2UE = new_channel_desc_scm(n_tx, n_rx, channel_model,
-                                61.44e6, //N_RB2sampling_rate(N_RB_DL),
-                                40e6, //N_RB2channel_bandwidth(N_RB_DL),
+  double sampling_frequency;
+  double bandwidth;
+
+  if (N_RB_UL >= 217) sampling_frequency = 122.88;
+  else if (N_RB_UL >= 106) sampling_frequency = 61.44;
+  else { printf("Need at least 106 PRBs\b"); exit(-1); }
+  if (N_RB_UL == 273) bandwidth = 100;
+  else if (N_RB_UL == 217) bandwidth = 80;
+  else if (N_RB_UL == 106) bandwidth = 40;
+  else { printf("Add N_RB_UL %d\n",N_RB_UL); exit(-1); }
+			   
+  if (openair0_cfg[0].threequarter_fs == 1) sampling_frequency*=.75;
+
+  UE2gNB = new_channel_desc_scm(n_tx, n_rx, channel_model,
+                                sampling_frequency,
+                                bandwidth,
+				DS_TDL,
                                 0, 0, 0);
 
-  if (gNB2UE == NULL) {
+  if (UE2gNB == NULL) {
     printf("Problem generating channel model. Exiting.\n");
     exit(-1);
   }
 
+  UE2gNB->max_Doppler = maxDoppler;
+
   RC.gNB = (PHY_VARS_gNB **) malloc(sizeof(PHY_VARS_gNB *));
   RC.gNB[0] = malloc(sizeof(PHY_VARS_gNB));
   gNB = RC.gNB[0];
@@ -474,14 +544,13 @@ int main(int argc, char **argv)
 
   gNB->if_inst->NR_PHY_config_req      = nr_phy_config_request;
   // common configuration
-  rrc_mac_config_req_gNB(0,0,1,scc,0,0,NULL);
+  rrc_mac_config_req_gNB(0,0,1,pusch_tgt_snrx10,pucch_tgt_snrx10,scc,0,0,NULL);
   // UE dedicated configuration
-  rrc_mac_config_req_gNB(0,0,1,NULL,1,secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup);
+  rrc_mac_config_req_gNB(0,0,1,pusch_tgt_snrx10,pucch_tgt_snrx10,NULL,1,secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity,secondaryCellGroup);
   phy_init_nr_gNB(gNB,0,0);
   N_RB_DL = gNB->frame_parms.N_RB_DL;
 
 
-
   NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[0];
 
   //crcTableInit();
@@ -556,7 +625,7 @@ int main(int argc, char **argv)
   unsigned char *estimated_output_bit;
   unsigned char *test_input_bit;
   uint32_t errors_decoding   = 0;
-  uint32_t errors_scrambling = 0;
+  
 
   test_input_bit       = (unsigned char *) malloc16(sizeof(unsigned char) * 16 * 68 * 384);
   estimated_output_bit = (unsigned char *) malloc16(sizeof(unsigned char) * 16 * 68 * 384);
@@ -577,6 +646,8 @@ int main(int argc, char **argv)
   uint16_t n_rb1 = 75;
   uint8_t mcs_table = 0;
   uint16_t pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; // | PUSCH_PDU_BITMAP_PUSCH_PTRS;
+  uint8_t max_rounds = 4;
+  uint8_t crc_status = 0;
 
   /* validate parameters othwerwise default values are used */
   /* -U flag can be used to set DMRS parameters*/
@@ -622,6 +693,8 @@ int main(int argc, char **argv)
     printf("NOTE: PTRS Enabled with L %d, K %d \n", ptrs_time_density, ptrs_freq_density );
   }
 
+  if (input_fd != NULL) max_rounds=1;
+
   if(1<<ptrs_time_density >= nb_symb_sch)
     pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
 
@@ -630,11 +703,72 @@ int main(int argc, char **argv)
 
   printf("\n");
 
-  for (int i=0;i<16;i++) printf("%f\n",gaussdouble(0.0,1.0));
-  for (SNR = snr0; SNR < snr1; SNR += snr_step) {
+  //for (int i=0;i<16;i++) printf("%f\n",gaussdouble(0.0,1.0));
+  snrRun = 0;
+  int n_errs = 0;
 
-      varArray_t *table_rx=initVarArray(1000,sizeof(double));
+  int slot_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0);
+  int slot_length = slot_offset - frame_parms->get_samples_slot_timestamp(slot-1,frame_parms,0);
+
+  if (input_fd != NULL)	{
+    AssertFatal(frame_parms->nb_antennas_rx == 1, "nb_ant != 1\n");
+    // 800 samples is N_TA_OFFSET for FR1 @ 30.72 Ms/s,
+    AssertFatal(frame_parms->subcarrier_spacing==30000,"only 30 kHz for file input for now (%d)\n",frame_parms->subcarrier_spacing);
+  
+    fseek(input_fd,file_offset*((slot_length<<2)+4000+16),SEEK_SET);
+    fread((void*)&n_rnti,sizeof(int16_t),1,input_fd);
+    printf("rnti %x\n",n_rnti);
+    fread((void*)&nb_rb,sizeof(int16_t),1,input_fd);
+    printf("nb_rb %d\n",nb_rb);
+    int16_t dummy;
+    fread((void*)&start_rb,sizeof(int16_t),1,input_fd);
+    //fread((void*)&dummy,sizeof(int16_t),1,input_fd);
+    printf("rb_start %d\n",start_rb);
+    fread((void*)&nb_symb_sch,sizeof(int16_t),1,input_fd);
+    //fread((void*)&dummy,sizeof(int16_t),1,input_fd);
+    printf("nb_symb_sch %d\n",nb_symb_sch);
+    fread((void*)&start_symbol,sizeof(int16_t),1,input_fd);
+    printf("start_symbol %d\n",start_symbol);
+    fread((void*)&Imcs,sizeof(int16_t),1,input_fd);
+    printf("mcs %d\n",Imcs);
+    fread((void*)&rv_index,sizeof(int16_t),1,input_fd);
+    printf("rv_index %d\n",rv_index);
+    //    fread((void*)&harq_pid,sizeof(int16_t),1,input_fd);
+    fread((void*)&dummy,sizeof(int16_t),1,input_fd);
+    printf("harq_pid %d\n",harq_pid);
+    fread((void*)&gNB->common_vars.rxdata[0][slot_offset-delay],
+	  sizeof(int16_t),
+	  slot_length<<1,
+	  input_fd);
+    for (int i=0;i<16;i+=2) printf("slot_offset %d : %d,%d\n",
+				   slot_offset,
+				   ((int16_t*)&gNB->common_vars.rxdata[0][slot_offset])[i],
+				   ((int16_t*)&gNB->common_vars.rxdata[0][slot_offset])[1+i]);
+  }
+  
+  for (SNR = snr0; SNR < snr1; SNR += snr_step) {
+    varArray_t *table_rx=initVarArray(1000,sizeof(double));
+    int error_flag = 0;
+    n_false_positive = 0;
+    effRate = 0;
+    int n_errors[4] = {0,0,0,0};;
+    int round_trials[4]={0,0,0,0};
+    uint32_t errors_scrambling[4] = {0,0,0,0};
+
+    clear_pusch_stats(gNB);
+    for (trial = 0; trial < n_trials; trial++) {
+    uint8_t round = 0;
+
+    crc_status = 1;
+    errors_decoding    = 0;
+    memset((void*)roundStats,0,50*sizeof(roundStats[0]));
+    while (round<max_rounds && crc_status) {
+      round_trials[round]++;
+      ulsch_ue[0]->harq_processes[harq_pid]->round = round;
+      gNB->ulsch[0][0]->harq_processes[harq_pid]->round = round;
+      rv_index = nr_rv_round_map[round];
       reset_meas(&gNB->phy_proc_rx);
+      reset_meas(&gNB->rx_pusch_stats);
       reset_meas(&gNB->ulsch_decoding_stats);
       reset_meas(&gNB->ulsch_deinterleaving_stats);
       reset_meas(&gNB->ulsch_rate_unmatching_stats);
@@ -643,6 +777,7 @@ int main(int argc, char **argv)
       reset_meas(&gNB->ulsch_channel_estimation_stats);
       reset_meas(&gNB->ulsch_ptrs_processing_stats);
       reset_meas(&gNB->ulsch_llr_stats);
+      reset_meas(&gNB->ulsch_mrc_stats);
       reset_meas(&gNB->ulsch_channel_compensation_stats);
       reset_meas(&gNB->ulsch_rbs_extraction_stats);
 
@@ -683,7 +818,7 @@ int main(int argc, char **argv)
 	else
 	  pusch_pdu->bwp_start = ibwp_start;
 	pusch_pdu->bwp_size = ibwp_size;
-	start_rb += (ibwp_start - abwp_start);
+	start_rb = (ibwp_start - abwp_start);
 	printf("msg3: ibwp_size %d, abwp_size %d, ibwp_start %d, abwp_start %d\n",
 	       ibwp_size,abwp_size,ibwp_start,abwp_start);
       }
@@ -706,7 +841,7 @@ int main(int argc, char **argv)
       pusch_pdu->ul_dmrs_scrambling_id =  *scc->physCellId;
       pusch_pdu->scid = 0;
       pusch_pdu->dmrs_ports = 1;
-      pusch_pdu->num_dmrs_cdm_grps_no_data = 1;
+      pusch_pdu->num_dmrs_cdm_grps_no_data = msg3_flag == 0 ? 1 : 2;
       pusch_pdu->resource_alloc = 1; 
       pusch_pdu->rb_start = start_rb;
       pusch_pdu->rb_size = nb_rb;
@@ -715,9 +850,9 @@ int main(int argc, char **argv)
       pusch_pdu->uplink_frequency_shift_7p5khz = 0;
       pusch_pdu->start_symbol_index = start_symbol;
       pusch_pdu->nr_of_symbols = nb_symb_sch;
-      pusch_pdu->pusch_data.rv_index = 0;
+      pusch_pdu->pusch_data.rv_index = rv_index;
       pusch_pdu->pusch_data.harq_process_id = 0;
-      pusch_pdu->pusch_data.new_data_indicator = 0;
+      pusch_pdu->pusch_data.new_data_indicator = trial & 0x1;
       pusch_pdu->pusch_data.num_cb = 0;
       pusch_pdu->pusch_ptrs.ptrs_time_density = ptrs_time_density;
       pusch_pdu->pusch_ptrs.ptrs_freq_density = ptrs_freq_density;
@@ -752,8 +887,8 @@ int main(int argc, char **argv)
       ul_config.ul_config_list[0].pusch_config_pdu.mcs_index = Imcs;
       ul_config.ul_config_list[0].pusch_config_pdu.mcs_table = mcs_table;
       ul_config.ul_config_list[0].pusch_config_pdu.num_dmrs_cdm_grps_no_data = 1;
-      ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.new_data_indicator = 0;
-      ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.rv_index = 0;
+      ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.new_data_indicator = trial & 0x1;
+      ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.rv_index = rv_index;
       ul_config.ul_config_list[0].pusch_config_pdu.nrOfLayers = precod_nbr_layers;
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.harq_process_id = harq_pid;
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_ptrs.ptrs_time_density = ptrs_time_density;
@@ -771,15 +906,12 @@ int main(int argc, char **argv)
       ul_config.ul_config_list[0].pusch_config_pdu.pusch_data.tb_size = TBS;
 
       nr_fill_ulsch(gNB,frame,slot,pusch_pdu);
-      int slot_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0);// - (int)(800*factor);
-      int slot_length = slot_offset - frame_parms->get_samples_slot_timestamp(slot-1,frame_parms,0);
 
       for (int i=0;i<(TBS>>3);i++) ulsch_ue[0]->harq_processes[harq_pid]->a[i]=i&0xff;
       double scale = 1;
 
       if (input_fd == NULL) {
 
-        if (SNR==snr0) { 
 	  // set FAPI parameters for UE, put them in the scheduled response and call
 	  nr_ue_scheduled_response(&scheduled_response);
 	  
@@ -804,62 +936,46 @@ int main(int argc, char **argv)
 	  txlev_float = (double)txlev/scale; // output of signal_energy is fixed point representation
 	  
 	  
-	  //AWGN
-	}
       }	
       else n_trials = 1;
 
+      if (input_fd == NULL ) {
 
-      sigma_dB = 10*log10(txlev_float)-SNR;
-      sigma    = pow(10,sigma_dB/10);
-      printf("txlev_float %f, sigma_dB %f\n",10*log10(txlev_float),sigma_dB);
+	sigma_dB = N0;
+	sigma    = pow(10,sigma_dB/10);
 
-      n_errors = 0;
-      n_false_positive = 0;
+	tx_gain = sqrt(pow(10.0,.1*(N0+SNR))/txlev_float);
+	if(n_trials==1) printf("txlev_float %f, sigma_dB %f, tx_gain %f tx_offset %d, slot_offset %d\n",10*log10(txlev_float),sigma_dB,tx_gain,tx_offset,slot_offset);
 
-      errors_scrambling  = 0;
-      errors_decoding    = 0;
-
-      int error_flag;
-      for (trial = 0; trial < n_trials; trial++) {
+	for (i=0; i<slot_length; i++) {
+	  for (int aa=0; aa<1; aa++) {
+	    s_re[aa][i] = ((double)(((short *)&UE->common_vars.txdata[aa][slot_offset]))[(i<<1)]);
+	    s_im[aa][i] = ((double)(((short *)&UE->common_vars.txdata[aa][slot_offset]))[(i<<1)+1]);
+	  }
+	}
+	
 
-        error_flag = 0;
-        //----------------------------------------------------------
-        //------------------------ add noise -----------------------
-        //----------------------------------------------------------
-        if (input_fd == NULL ) {
-          for (i=0; i<slot_length; i++) {
-            for (ap=0; ap<frame_parms->nb_antennas_rx; ap++) {
-              ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)]   = (int16_t)((double)(((int16_t *)&UE->common_vars.txdata[ap][slot_offset])[(i<<1)])/sqrt(scale)   + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point
-              ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)]   = (int16_t)((double)(((int16_t *)&UE->common_vars.txdata[ap][slot_offset])[(i<<1)+1])/sqrt(scale) + (sqrt(sigma/2)*gaussdouble(0.0,1.0)));
-              /* Add phase noise if enabled */
-              if (pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
-                phase_noise(ts, &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(i<<1)],
-                            &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(i<<1)+1]);
-              }
+	if (UE2gNB->max_Doppler == 0) {
+	  multipath_channel(UE2gNB,s_re,s_im,r_re,r_im,
+			    slot_length,0,(n_trials==1)?1:0);
+	} else {
+	  multipath_tv_channel(UE2gNB,s_re,s_im,r_re,r_im,
+			       2*slot_length,0);
+	}
+	for (i=0; i<slot_length; i++) {
+	  for (ap=0; ap<frame_parms->nb_antennas_rx; ap++) {
+	    ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i) + (delay*2)]   = (int16_t)((tx_gain*r_re[ap][i])   + (sqrt(sigma/2)*gaussdouble(0.0,1.0))); // convert to fixed point
+	    ((int16_t*) &gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1 + (delay*2)]   = (int16_t)((tx_gain*r_im[ap][i]) + (sqrt(sigma/2)*gaussdouble(0.0,1.0)));
+            /* Add phase noise if enabled */
+            if (pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) {
+              phase_noise(ts, &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(2*i)],
+                          &((int16_t*)&gNB->common_vars.rxdata[ap][slot_offset])[(2*i)+1]);
             }
-          }
-        }
-	else {
-	  AssertFatal(frame_parms->nb_antennas_rx == 1, "nb_ant != 1\n");
-	  // 800 samples is N_TA_OFFSET for FR1 @ 30.72 Ms/s,
-	  AssertFatal(frame_parms->subcarrier_spacing==30000,"only 30 kHz for file input for now (%d)\n",frame_parms->subcarrier_spacing);
-	  double factor = 1;
-	  if (openair0_cfg[0].threequarter_fs== 1) factor =.75;
-	  int ta_offset=1600;
-	  if (N_RB_DL <217) ta_offset=800;
-	  else if (N_RB_DL < 106) ta_offset = 400;
-
-	  fread((void*)&gNB->common_vars.rxdata[0][slot_offset],
-		sizeof(int16_t),
-		slot_length<<1,
-		input_fd);
-	  for (int i=0;i<16;i+=2) printf("slot_offset %d : %d,%d\n",
-					 slot_offset,
-					 ((int16_t*)&gNB->common_vars.rxdata[0][slot_offset])[i],
-					 ((int16_t*)&gNB->common_vars.rxdata[0][slot_offset])[1+i]);
-	  fclose(input_fd);
+	  }
 	}
+
+      }
+
 	////////////////////////////////////////////////////////////
 	
 	//----------------------------------------------------------
@@ -871,32 +987,48 @@ int main(int argc, char **argv)
         start_meas(&gNB->phy_proc_rx);
         phy_procedures_gNB_common_RX(gNB, frame, slot);
 
-	if (n_trials==1) {
-	  LOG_M("rxsig0.m","rx0",&gNB->common_vars.rxdata[0][0],frame_parms->samples_per_subframe*10,1,1);
+        phy_procedures_gNB_uespec_RX(gNB, frame, slot);
+
+	if (n_trials==1 && round==0) {
+	  LOG_M("rxsig0.m","rx0",&gNB->common_vars.rxdata[0][slot_offset],slot_length,1,1);
 
 	  LOG_M("rxsigF0.m","rxsF0",gNB->common_vars.rxdataF[0]+start_symbol*frame_parms->ofdm_symbol_size,nb_symb_sch*frame_parms->ofdm_symbol_size,1,1);
 
 	}
-        phy_procedures_gNB_uespec_RX(gNB, frame, slot);
-	if (n_trials == 1) { 
+
+
+	if (n_trials == 1  && round==0) { 
+#ifdef __AVX2__
+	  int off = ((nb_rb&1) == 1)? 4:0;
+#else
+	  int off = 0;
+#endif
+
 	  LOG_M("rxsigF0_ext.m","rxsF0_ext",
-		&gNB->pusch_vars[0]->rxdataF_ext[0][(start_symbol+1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size,1,1);
+		&gNB->pusch_vars[0]->rxdataF_ext[0][start_symbol*NR_NB_SC_PER_RB * pusch_pdu->rb_size],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1);
 	  LOG_M("chestF0.m","chF0",
 		&gNB->pusch_vars[0]->ul_ch_estimates[0][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1);
 	  LOG_M("chestF0_ext.m","chF0_ext",
-		&gNB->pusch_vars[0]->ul_ch_estimates_ext[0][(start_symbol+1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size,1,1);
+		&gNB->pusch_vars[0]->ul_ch_estimates_ext[0][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
+		(nb_symb_sch-1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1);
 	  LOG_M("rxsigF0_comp.m","rxsF0_comp",
-		&gNB->pusch_vars[0]->rxdataF_comp[0][(start_symbol+1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size,1,1);
+		&gNB->pusch_vars[0]->rxdataF_comp[0][start_symbol*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],nb_symb_sch*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size)),1,1);
+	  LOG_M("rxsigF0_llr.m","rxsF0_llr",
+		&gNB->pusch_vars[0]->llr[0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0);
 	}
         start_meas(&gNB->phy_proc_rx);
         ////////////////////////////////////////////////////////////
-
+	
 	if (gNB->ulsch[0][0]->last_iteration_cnt >= 
 	    gNB->ulsch[0][0]->max_ldpc_iterations+1) {
 	  error_flag = 1; 
-	  n_errors++;
+	  n_errors[round]++;
+	  crc_status = 1;
+	} else {
+	  crc_status = 0;
 	}
-	
+	if(n_trials==1) printf("end of round %d rv_index %d\n",round, rv_index);
+
         //----------------------------------------------------------
         //----------------- count and print errors -----------------
         //----------------------------------------------------------
@@ -911,82 +1043,106 @@ int main(int argc, char **argv)
             printf("After PTRS subtraction available_bits are : %u \n", available_bits);
         }
 
-        for (i = 0; i < available_bits; i++) {
-
-          if(((ulsch_ue[0]->g[i] == 0) && (gNB->pusch_vars[UE_id]->llr[i] <= 0)) ||
-             ((ulsch_ue[0]->g[i] == 1) && (gNB->pusch_vars[UE_id]->llr[i] >= 0)))
-          {
-            /*if(errors_scrambling == 0)
-              printf("\x1B[34m" "[frame %d][trial %d]\t1st bit in error in unscrambling = %d\n" "\x1B[0m", frame, trial, i);*/
-            errors_scrambling++;
-          }
-        }
-
-        if (errors_scrambling > 0) {
-	  if (n_trials==1)
-	    printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in unscrambling = %u\n" "\x1B[0m", frame, trial, errors_scrambling);
-        }
-
-        for (i = 0; i < TBS; i++) {
-
-          estimated_output_bit[i] = (ulsch_gNB->harq_processes[harq_pid]->b[i/8] & (1 << (i & 7))) >> (i & 7);
-          test_input_bit[i]       = (ulsch_ue[0]->harq_processes[harq_pid]->b[i/8] & (1 << (i & 7))) >> (i & 7);
-
-          if (estimated_output_bit[i] != test_input_bit[i]) {
-            /*if(errors_decoding == 0)
-              printf("\x1B[34m""[frame %d][trial %d]\t1st bit in error in decoding     = %d\n" "\x1B[0m", frame, trial, i);*/
-            errors_decoding++;
-          }
-        }
-	if (n_trials == 1 && errors_decoding > 0) {
-	  for (int r=0;r<ulsch_ue[0]->harq_processes[harq_pid]->C;r++) 
-	    for (int i=0;i<ulsch_ue[0]->harq_processes[harq_pid]->K>>3;i++) {
-	      if ((ulsch_ue[0]->harq_processes[harq_pid]->c[r][i]^ulsch_gNB->harq_processes[harq_pid]->c[r][i]) != 0) printf("************");
-	      printf("r %d: in[%d] %x, out[%d] %x (%x)\n",r,
-		     i,ulsch_ue[0]->harq_processes[harq_pid]->c[r][i],
-		     i,ulsch_gNB->harq_processes[harq_pid]->c[r][i],
-		     ulsch_ue[0]->harq_processes[harq_pid]->c[r][i]^ulsch_gNB->harq_processes[harq_pid]->c[r][i]);
+	for (i = 0; i < available_bits; i++) {
+	  
+	  if(((ulsch_ue[0]->g[i] == 0) && (gNB->pusch_vars[UE_id]->llr[i] <= 0)) ||
+	     ((ulsch_ue[0]->g[i] == 1) && (gNB->pusch_vars[UE_id]->llr[i] >= 0)))
+	    {
+	      /*if(errors_scrambling == 0)
+		printf("\x1B[34m" "[frame %d][trial %d]\t1st bit in error in unscrambling = %d\n" "\x1B[0m", frame, trial, i);*/
+	      errors_scrambling[round]++;
 	    }
 	}
-        if (errors_decoding > 0 && error_flag == 0) {
-          n_false_positive++;
-	  if (n_trials==1)
-	    printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in decoding     = %u\n" "\x1B[0m", frame, trial, errors_decoding);
-        } 
-      } // trial loop
-
-      printf("*****************************************\n");
-      printf("SNR %f: n_errors (negative CRC) = %d/%d, false_positive %d/%d, errors_scrambling %u/%u\n", SNR, n_errors, n_trials, n_false_positive, n_trials, errors_scrambling, available_bits*n_trials);
-      printf("\n");
-      printf("SNR %f: Channel BLER %e, Channel BER %e\n", SNR,(double)n_errors/n_trials,(double)errors_scrambling/available_bits/n_trials);
-      printf("*****************************************\n");
-      printf("\n");
- 
-      if (print_perf==1) {
-        printDistribution(&gNB->phy_proc_rx,table_rx,"Total PHY proc rx");
-        printStatIndent(&gNB->ulsch_channel_estimation_stats,"ULSCH channel estimation time");
-        printStatIndent(&gNB->ulsch_ptrs_processing_stats,"ULSCH PTRS Processing time");
-        printStatIndent(&gNB->ulsch_rbs_extraction_stats,"ULSCH rbs extraction time");
-        printStatIndent(&gNB->ulsch_channel_compensation_stats,"ULSCH channel compensation time");
-        printStatIndent(&gNB->ulsch_llr_stats,"ULSCH llr computation");
-        printStatIndent(&gNB->ulsch_unscrambling_stats,"ULSCH unscrambling");
-        printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
-        printStatIndent2(&gNB->ulsch_deinterleaving_stats,"ULSCH deinterleaving");
-        printStatIndent2(&gNB->ulsch_rate_unmatching_stats,"ULSCH rate matching rx");
-        printStatIndent2(&gNB->ulsch_ldpc_decoding_stats,"ULSCH ldpc decoding");
-        printf("\n");
+	round++;
+
+    } // round
+    
+    if (n_trials == 1 && errors_scrambling[0] > 0) {
+      printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in unscrambling = %u\n" "\x1B[0m", frame, trial, errors_scrambling[0]);
+    }
+    
+    for (i = 0; i < TBS; i++) {
+      
+      estimated_output_bit[i] = (ulsch_gNB->harq_processes[harq_pid]->b[i/8] & (1 << (i & 7))) >> (i & 7);
+      test_input_bit[i]       = (ulsch_ue[0]->harq_processes[harq_pid]->b[i/8] & (1 << (i & 7))) >> (i & 7);
+      
+      if (estimated_output_bit[i] != test_input_bit[i]) {
+	/*if(errors_decoding == 0)
+	  printf("\x1B[34m""[frame %d][trial %d]\t1st bit in error in decoding     = %d\n" "\x1B[0m", frame, trial, i);*/
+	errors_decoding++;
       }
+    }
+    if (n_trials == 1) {
+      for (int r=0;r<ulsch_ue[0]->harq_processes[harq_pid]->C;r++) 
+	for (int i=0;i<ulsch_ue[0]->harq_processes[harq_pid]->K>>3;i++) {
+	  /*if ((ulsch_ue[0]->harq_processes[harq_pid]->c[r][i]^ulsch_gNB->harq_processes[harq_pid]->c[r][i]) != 0) printf("************");
+	    printf("r %d: in[%d] %x, out[%d] %x (%x)\n",r,
+	    i,ulsch_ue[0]->harq_processes[harq_pid]->c[r][i],
+	    i,ulsch_gNB->harq_processes[harq_pid]->c[r][i],
+	    ulsch_ue[0]->harq_processes[harq_pid]->c[r][i]^ulsch_gNB->harq_processes[harq_pid]->c[r][i]);*/
+	}
+    }
+    if (errors_decoding > 0 && error_flag == 0) {
+      n_false_positive++;
+      if (n_trials==1)
+	printf("\x1B[31m""[frame %d][trial %d]\tnumber of errors in decoding     = %u\n" "\x1B[0m", frame, trial, errors_decoding);
+    } 
+    roundStats[snrRun] += ((float)round);
+    if (!crc_status) effRate += ((float)TBS)/round;
+    } // trial loop
+    
+    roundStats[snrRun]/=((float)n_trials);
+    effRate /= n_trials;
+    
+    printf("*****************************************\n");
+    printf("SNR %f: n_errors (%d/%d,%d/%d,%d/%d,%d/%d) (negative CRC), false_positive %d/%d, errors_scrambling (%u/%u,%u/%u,%u/%u,%u/%u\n", SNR, n_errors[0], round_trials[0],n_errors[1], round_trials[1],n_errors[2], round_trials[2],n_errors[3], round_trials[3], n_false_positive, n_trials, errors_scrambling[0],available_bits*n_trials,errors_scrambling[1],available_bits*n_trials,errors_scrambling[2],available_bits*n_trials,errors_scrambling[3],available_bits*n_trials);
+    printf("\n");
+    printf("SNR %f: Channel BLER (%e,%e,%e,%e), Channel BER (%e,%e,%e,%e) Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", 
+	   SNR,
+	   (double)n_errors[0]/round_trials[0],
+	   (double)n_errors[1]/round_trials[0],
+	   (double)n_errors[2]/round_trials[0],
+	   (double)n_errors[3]/round_trials[0],
+	   (double)errors_scrambling[0]/available_bits/round_trials[0],
+	   (double)errors_scrambling[1]/available_bits/round_trials[0],
+	   (double)errors_scrambling[2]/available_bits/round_trials[0],
+	   (double)errors_scrambling[3]/available_bits/round_trials[0],
+	   roundStats[snrRun],effRate,effRate/TBS*100,TBS);
+
+    dump_pusch_stats(gNB);
+
+    printf("*****************************************\n");
+    printf("\n");
+    
+    if (print_perf==1) {
+      printDistribution(&gNB->phy_proc_rx,table_rx,"Total PHY proc rx");
+      printStatIndent(&gNB->rx_pusch_stats,"RX PUSCH time");
+      printStatIndent2(&gNB->ulsch_channel_estimation_stats,"ULSCH channel estimation time");
+      printStatIndent2(&gNB->ulsch_ptrs_processing_stats,"ULSCH PTRS Processing time");
+      printStatIndent2(&gNB->ulsch_rbs_extraction_stats,"ULSCH rbs extraction time");
+      printStatIndent2(&gNB->ulsch_channel_compensation_stats,"ULSCH channel compensation time");
+      printStatIndent2(&gNB->ulsch_mrc_stats,"ULSCH mrc computation");
+      printStatIndent2(&gNB->ulsch_llr_stats,"ULSCH llr computation");
+      printStatIndent(&gNB->ulsch_unscrambling_stats,"ULSCH unscrambling");
+      printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time");
+      printStatIndent2(&gNB->ulsch_deinterleaving_stats,"ULSCH deinterleaving");
+      printStatIndent2(&gNB->ulsch_rate_unmatching_stats,"ULSCH rate matching rx");
+      printStatIndent2(&gNB->ulsch_ldpc_decoding_stats,"ULSCH ldpc decoding");
+      printf("\n");
+    }
 
-      if(n_trials==1)
-	break;
+    if(n_trials==1)
+      break;
 
-      if ((float)n_errors/(float)n_trials <= target_error_rate) {
-	printf("*************\n");
-	printf("PUSCH test OK\n");
-	printf("*************\n");
-	break;
-      }
-      
+    if ((float)n_errors[0]/(float)n_trials <= target_error_rate) {
+      printf("*************\n");
+      printf("PUSCH test OK\n");
+      printf("*************\n");
+      break;
+    }
+
+    snrRun++;
+    n_errs = n_errors[0];
   } // SNR loop
   printf("\n");
 
@@ -1002,5 +1158,5 @@ int main(int argc, char **argv)
   if (scg_fd)
     fclose(scg_fd);
 
-  return (n_errors);
+  return (n_errs);
 }
diff --git a/openair1/SIMULATION/TOOLS/channel_sim.c b/openair1/SIMULATION/TOOLS/channel_sim.c
index c5628fbcefebcdaecfc461b4925d06263aacfcdf..81949f40e6b334b2ca1b7231ee8ef48c174cb552 100644
--- a/openair1/SIMULATION/TOOLS/channel_sim.c
+++ b/openair1/SIMULATION/TOOLS/channel_sim.c
@@ -180,7 +180,7 @@ void do_DL_sig(sim_t *sim,
     
     //RU2UE[eNB_id][UE_id]->path_loss_dB = 0;
     multipath_channel(sim->RU2UE[ru_id][UE_id][CC_id],s_re,s_im,r_re0,r_im0,
-		      length,hold_channel);
+		      length,hold_channel,0);
 #ifdef DEBUG_SIM
     rx_pwr = signal_energy_fp2(sim->RU2UE[ru_id][UE_id][CC_id]->ch[0],
 			       sim->RU2UE[ru_id][UE_id][CC_id]->channel_length)*sim->RU2UE[ru_id][UE_id][CC_id]->channel_length;
@@ -394,7 +394,7 @@ void do_UL_sig(sim_t *sim,
       
       
       multipath_channel(sim->UE2RU[UE_id][ru_id][CC_id],s_re,s_im,r_re0,r_im0,
-			frame_parms->samples_per_tti,hold_channel);
+			frame_parms->samples_per_tti,hold_channel,0);
       
       
       rx_pwr = signal_energy_fp2(sim->UE2RU[UE_id][ru_id][CC_id]->ch[0],
diff --git a/openair1/SIMULATION/TOOLS/multipath_channel.c b/openair1/SIMULATION/TOOLS/multipath_channel.c
index 70227c8e8db271d51ef6c0345c9d01332f480e54..683526a8f010c308d9eb433953aefca43faa295b 100644
--- a/openair1/SIMULATION/TOOLS/multipath_channel.c
+++ b/openair1/SIMULATION/TOOLS/multipath_channel.c
@@ -44,7 +44,8 @@ void multipath_channel(channel_desc_t *desc,
                        double rx_sig_re[2][30720*2],
                        double rx_sig_im[2][30720*2],
                        uint32_t length,
-                       uint8_t keep_channel)
+                       uint8_t keep_channel,
+		       int log_channel)
 {
 
   int i,ii,j,l;
@@ -150,7 +151,8 @@ void multipath_channel(channel_desc_t *desc,
                        double *rx_sig_re[2],
                        double *rx_sig_im[2],
                        uint32_t length,
-                       uint8_t keep_channel)
+                       uint8_t keep_channel,
+		       int log_channel)
 {
 
   int i,ii,j,l;
@@ -196,16 +198,21 @@ void multipath_channel(channel_desc_t *desc,
 
           rx_tmp.x += (tx.x * desc->ch[ii+(j*desc->nb_rx)][l].x) - (tx.y * desc->ch[ii+(j*desc->nb_rx)][l].y);
           rx_tmp.y += (tx.y * desc->ch[ii+(j*desc->nb_rx)][l].x) + (tx.x * desc->ch[ii+(j*desc->nb_rx)][l].y);
+	  if (i==0 && log_channel == 1) {
+	    printf("channel[%d][%d][%d] = %f dB (%e,%e)\n",ii,j,l,10*log10(pow(desc->ch[ii+(j*desc->nb_rx)][l].x,2.0)+pow(desc->ch[ii+(j*desc->nb_rx)][l].y,2.0)),
+		   desc->ch[ii+(j*desc->nb_rx)][l].x,
+		   desc->ch[ii+(j*desc->nb_rx)][l].y);
+	  }
         } //l
       }  // j
 
       rx_sig_re[ii][i+dd] = rx_tmp.x*path_loss;
       rx_sig_im[ii][i+dd] = rx_tmp.y*path_loss;
-      /*
-      if ((ii==0)&&((i%32)==0)) {
-      printf("%p %p %f,%f => %e,%e\n",rx_sig_re[ii],rx_sig_im[ii],rx_tmp.x,rx_tmp.y,rx_sig_re[ii][i-dd],rx_sig_im[ii][i-dd]);
-      }
-      */
+      
+      /*      if ((ii==0)&&((i%32)==0)) {
+	printf("%p %p %f,%f => %e,%e\n",rx_sig_re[ii],rx_sig_im[ii],rx_tmp.x,rx_tmp.y,rx_sig_re[ii][i-dd],rx_sig_im[ii][i-dd]);
+	}*/
+      
       //rx_sig_re[ii][i] = sqrt(.5)*(tx_sig_re[0][i] + tx_sig_re[1][i]);
       //rx_sig_im[ii][i] = sqrt(.5)*(tx_sig_im[0][i] + tx_sig_im[1][i]);
 
diff --git a/openair1/SIMULATION/TOOLS/random_channel.c b/openair1/SIMULATION/TOOLS/random_channel.c
index f97b9dfb78a1d7bdebd35c8324d1ecac635b3936..8c063fadc093540a0bb3474adef65e241df3dbf3 100644
--- a/openair1/SIMULATION/TOOLS/random_channel.c
+++ b/openair1/SIMULATION/TOOLS/random_channel.c
@@ -178,6 +178,223 @@ double mbsfn_amps_dB[] = {0,-1.5,-1.4,-3.6,-0.6,-7.0,-10,-11.5,-11.4,-13.6,-10.6
 double scm_c_delays[] = {0, 0.0125, 0.0250, 0.3625, 0.3750, 0.3875, 0.2500, 0.2625, 0.2750, 1.0375, 1.0500, 1.0625, 2.7250, 2.7375, 2.7500, 4.6000, 4.6125, 4.6250};                
 double scm_c_amps_dB[] = {0.00, -2.22, -3.98, -1.86, -4.08, -5.84, -1.08, -3.30, -5.06, -9.08, -11.30, -13.06, -15.14, -17.36, -19.12, -20.64, -22.85, -24.62};
 
+double tdl_a_delays[] = {0.0000,
+			 0.3819,
+			 0.4025,
+			 0.5868,
+			 0.4610,
+			 0.5375,
+			 0.6708,
+			 0.5750,
+			 0.7618,
+			 1.5375,
+			 1.8978,
+			 2.2242,
+			 2.1718,
+			 2.4942,
+			 2.5119,
+			 3.0582,
+			 4.0810,
+			 4.4579,
+			 4.5695,
+			 4.7966,
+			 5.0066,
+			 5.3043,
+			 9.6586};
+double tdl_a_amps_dB[] = {-13.4,
+			  0,
+			  -2.2,
+			  -4,
+			  -6,
+			  -8.2,
+			  -9.9,
+			  -10.5,
+			  -7.5,
+			  -15.9,
+			  -6.6,
+			  -16.7,
+			  -12.4,
+			  -15.2,
+			  -10.8,
+			  -11.3,
+			  -12.7,
+			  -16.2,
+			  -18.3,
+			  -18.9,
+			  -16.6,
+			  -19.9,
+			  -29.7};
+#define TDL_A_PATHS 23
+
+double tdl_b_delays[] = {0.0000,
+			 0.1072,
+			 0.2155,
+			 0.2095,
+			 0.2870,
+			 0.2986,
+			 0.3752,
+			 0.5055,
+			 0.3681,
+			 0.3697,
+			 0.5700,
+			 0.5283,
+			 1.1021,
+			 1.2756,
+			 1.5474,
+			 1.7842,
+			 2.0169,
+			 2.8294,
+			 3.0219,
+			 3.6187,
+			 4.1067,
+			 4.2790,
+			 4.7834};
+
+double tdl_b_amps_dB[] = {0,
+			  -2.2,
+			  -4,
+			  -3.2,
+			  -9.8,
+			  -1.2,
+			  -3.4,
+			  -5.2,
+			  -7.6,
+			  -3,
+			  -8.9,
+			  -9,
+			  -4.8,
+			  -5.7,
+			  -7.5,
+			  -1.9,
+			  -7.6,
+			  -12.2,
+			  -9.8,
+			  -11.4,
+			  -14.9,
+			  -9.2,
+			  -11.3};
+#define TDL_B_PATHS 23
+
+double tdl_c_delays[] = {0,
+			 0.2099,
+			 0.2219,
+			 0.2329,
+			 0.2176,
+			 0.6366,
+			 0.6448,
+			 0.6560,
+			 0.6584,
+			 0.7935,
+			 0.8213,
+			 0.9336,
+			 1.2285,
+			 1.3083,
+			 2.1704,
+			 2.7105,
+			 4.2589,
+			 4.6003,
+			 5.4902,
+			 5.6077,
+			 6.3065,
+			 6.6374,
+			 7.0427,
+			 8.6523};
+
+double tdl_c_amps_dB[] = {-4.4,
+			  -1.2,
+			  -3.5,
+			  -5.2,
+			  -2.5,
+			  0,
+			  -2.2,
+			  -3.9,
+			  -7.4,
+			  -7.1,
+			  -10.7,
+			  -11.1,
+			  -5.1,
+			  -6.8,
+			  -8.7,
+			  -13.2,
+			  -13.9,
+			  -13.9,
+			  -15.8,
+			  -17.1,
+			  -16,
+			  -15.7,
+			  -21.6,
+			  -22.8};
+#define TDL_C_PATHS 24
+
+double tdl_d_delays[] = {//0,
+			 0,
+	  	         0.035,
+			 0.612,
+			 1.363,
+			 1.405,
+			 1.804,
+			 2.596,
+			 1.775,
+			 4.042,
+			 7.937,
+			 9.424,
+			 9.708,
+			 12.525};
+
+double tdl_d_amps_dB[] = {//-0.2,
+//-13.5,
+                          -.00147,
+			  -18.8,
+			  -21,
+			  -22.8,
+			  -17.9,
+			  -20.1,
+			  -21.9,
+			  -22.9,
+			  -27.8,
+			  -23.6,
+			  -24.8,
+			  -30.0,
+			  -27.7};
+
+#define TDL_D_PATHS 13
+#define TDL_D_RICEAN_FACTOR .046774
+
+double tdl_e_delays[] = {0,
+			 0.5133,
+			 0.5440,
+			 0.5630,
+			 0.5440,
+			 0.7112,
+			 1.9092,
+			 1.9293,
+			 1.9589,
+			 2.6426,
+			 3.7136,
+			 5.4524,
+			 12.0034,
+			 20.6519};
+
+double tdl_e_amps_dB[] = {//-0.03,
+			  //-22.03,
+                          -.00433,
+			  -15.8,
+			  -18.1,
+			  -19.8,
+			  -22.9,
+			  -22.4,
+			  -18.6,
+			  -20.8,
+			  -22.6,
+			  -22.3,
+			  -25.6,
+			  -20.2,
+			  -29.8,
+			  -29.2};
+
+#define TDL_E_PATHS 14
+#define TDL_E_RICEAN_FACTOR 0.0063096
+
 double epa_delays[] = { 0,.03,.07,.09,.11,.19,.41};
 double epa_amps_dB[] = {0.0,-1.0,-2.0,-3.0,-8.0,-17.2,-20.8};
 
@@ -282,7 +499,8 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
                                      SCM_t channel_model,
                                      double sampling_rate,
                                      double channel_bandwidth,
-                                     double forgetting_factor,              
+				     double DS_TDL,
+                                     double forgetting_factor,
                                      int32_t channel_offset,
                                      double path_loss_dB) {
   channel_desc_t *chan_desc = (channel_desc_t *)calloc(1,sizeof(channel_desc_t));
@@ -300,6 +518,7 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
   uint16_t i,j;
   double sum_amps;
   double aoa,ricean_factor,Td,maxDoppler;
+
   int channel_length,nb_taps;
   chan_desc->modelid                   = channel_model;
   chan_desc->nb_tx                      = nb_tx;
@@ -313,6 +532,11 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
   chan_desc->ip                                 = 0.0;
   LOG_I(OCM,"Channel Model (inside of new_channel_desc_scm)=%d\n\n", channel_model);
 
+  int tdl_paths=0;
+  double tdl_ricean_factor = 1;
+  double *tdl_amps_dB;
+  double *tdl_delays;
+
   switch (channel_model) {
     case SCM_A:
       LOG_W(OCM,"channel model not yet supported\n");
@@ -442,7 +666,101 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
       }
 
       break;
-                               
+      
+    case TDL_A:
+    case TDL_B:
+    case TDL_C:  
+    case TDL_D:  
+    case TDL_E:
+      if (channel_model == TDL_A) {  
+	tdl_paths=TDL_A_PATHS;
+	tdl_delays=tdl_a_delays;
+	tdl_amps_dB=tdl_a_amps_dB;
+      }else if (channel_model == TDL_B) {
+	  tdl_paths=TDL_B_PATHS;
+	tdl_delays=tdl_b_delays;
+	tdl_amps_dB=tdl_b_amps_dB;      
+      }
+      else if (channel_model == TDL_C) {
+	tdl_paths=TDL_C_PATHS;
+	tdl_delays=tdl_c_delays;
+	tdl_amps_dB=tdl_c_amps_dB;
+	printf("Initializing TDL_C channel with %d paths\n",TDL_C_PATHS);
+      } else if (channel_model == TDL_D) {
+	tdl_paths=TDL_D_PATHS;
+	tdl_delays=tdl_d_delays;
+	tdl_amps_dB=tdl_d_amps_dB;
+	tdl_ricean_factor = TDL_D_RICEAN_FACTOR;
+      } else if (channel_model == TDL_E) {
+	tdl_paths=TDL_E_PATHS-1;
+	tdl_delays=tdl_e_delays+1;
+	tdl_amps_dB=tdl_e_amps_dB;
+	tdl_ricean_factor = TDL_E_RICEAN_FACTOR;
+      }
+
+      int tdl_pathsby3 = tdl_paths/3;
+      if ((tdl_paths%3)>0) tdl_pathsby3++;
+
+      chan_desc->nb_taps        = tdl_paths;
+      chan_desc->Td             = tdl_delays[tdl_paths-1]*DS_TDL;
+      printf("last path (%d) at %f * %e = %e\n",tdl_paths-1,tdl_delays[tdl_paths-1],DS_TDL,chan_desc->Td);
+      chan_desc->channel_length = (int) (2*chan_desc->sampling_rate*chan_desc->Td + 1 + 2/(M_PI*M_PI)*log(4*M_PI*chan_desc->sampling_rate*chan_desc->Td));
+      printf("TDL : %f Ms/s, nb_taps %d, Td %e, channel_length %d\n",chan_desc->sampling_rate,tdl_paths,chan_desc->Td,chan_desc->channel_length);
+      sum_amps = 0;
+      chan_desc->amps           = (double *) malloc(chan_desc->nb_taps*sizeof(double));
+
+      for (i = 0; i<chan_desc->nb_taps; i++) {
+        chan_desc->amps[i]      = pow(10,.1*tdl_amps_dB[i]);
+        sum_amps += chan_desc->amps[i];
+      }
+
+      for (i = 0; i<chan_desc->nb_taps; i++) {
+        chan_desc->amps[i] /= sum_amps;
+	tdl_delays[i] *= DS_TDL;
+      }
+      chan_desc->delays         = tdl_delays;
+      chan_desc->ricean_factor  = tdl_ricean_factor;
+      chan_desc->aoa            = 0;
+      chan_desc->random_aoa     = 0;
+      chan_desc->ch             = (struct complex **) malloc(nb_tx*nb_rx*sizeof(struct complex *));
+      chan_desc->chF            = (struct complex **) malloc(nb_tx*nb_rx*sizeof(struct complex *));
+      chan_desc->a              = (struct complex **) malloc(chan_desc->nb_taps*sizeof(struct complex *));
+
+      for (i = 0; i<nb_tx*nb_rx; i++)
+        chan_desc->ch[i] = (struct complex *) malloc(chan_desc->channel_length * sizeof(struct complex));
+
+      for (i = 0; i<nb_tx*nb_rx; i++)
+        chan_desc->chF[i] = (struct complex *) malloc(1200 * sizeof(struct complex));
+
+      for (i = 0; i<chan_desc->nb_taps; i++)
+        chan_desc->a[i]         = (struct complex *) malloc(nb_tx*nb_rx * sizeof(struct complex));
+
+      chan_desc->R_sqrt  = (struct complex **) malloc(6*sizeof(struct complex **));
+
+      if (nb_tx==2 && nb_rx==2) {
+        for (i = 0; i<(tdl_pathsby3); i++)
+          chan_desc->R_sqrt[i] = (struct complex *) &R22_sqrt[i][0];
+      } else if (nb_tx==2 && nb_rx==1) {
+        for (i = 0; i<(tdl_pathsby3); i++)
+          chan_desc->R_sqrt[i] = (struct complex *) &R21_sqrt[i][0];
+      } else if (nb_tx==1 && nb_rx==2) {
+        for (i = 0; i<(tdl_pathsby3); i++)
+          chan_desc->R_sqrt[i] = (struct complex *) &R12_sqrt[i][0];
+      } else {
+        for (i = 0; i<(tdl_pathsby3); i++) {
+          chan_desc->R_sqrt[i]    = (struct complex *) malloc(nb_tx*nb_rx*nb_tx*nb_rx * sizeof(struct complex));
+
+          for (j = 0; j<nb_tx*nb_rx*nb_tx*nb_rx; j+=(nb_tx*nb_rx+1)) {
+            chan_desc->R_sqrt[i][j].x = 1.0;
+            chan_desc->R_sqrt[i][j].y = 0.0;
+          }
+
+          LOG_W(OCM,"correlation matrix not implemented for nb_tx==%d and nb_rx==%d, using identity\n", nb_tx, nb_rx);
+        }
+      }
+
+      break;
+
     case EPA:
       chan_desc->nb_taps        = 7;
       chan_desc->Td             = .410;
@@ -1462,15 +1780,14 @@ int random_channel(channel_desc_t *desc, uint8_t abstraction_flag) {
 
               desc->ch[aarx+(aatx*desc->nb_rx)][k].x += s*desc->a[l][aarx+(aatx*desc->nb_rx)].x;
               desc->ch[aarx+(aatx*desc->nb_rx)][k].y += s*desc->a[l][aarx+(aatx*desc->nb_rx)].y;
-              //    printf("l %d : desc->ch.x %f\n",l,desc->a[l][aarx+(aatx*desc->nb_rx)].x);
+	      //	      printf("l %d : desc->ch.x %f, s %e, delay %f\n",l,desc->a[l][aarx+(aatx*desc->nb_rx)].x,s,desc->delays[l]);
             } //nb_taps
 
 #ifdef DEBUG_CH
-            k=0;
-            printf("(%d,%d,%d)->(%f,%f)\n",k,aarx,aatx,desc->ch[aarx+(aatx*desc->nb_rx)][k].x,desc->ch[aarx+(aatx*desc->nb_rx)][k].y);
+            printf("(%d,%d,%d)->(%e,%e)\n",k,aarx,aatx,desc->ch[aarx+(aatx*desc->nb_rx)][k].x,desc->ch[aarx+(aatx*desc->nb_rx)][k].y);
 #endif
-          }
-        } //channel_length
+          } //channel_length
+        } 
       } //aatx
     } //aarx
 
diff --git a/openair1/SIMULATION/TOOLS/sim.h b/openair1/SIMULATION/TOOLS/sim.h
index e1ba52bfd52cc7dd509e6d81ebbf1440e4f5d739..d2684b15c1fd0602e553e9f9dc5d4d0355003a01 100644
--- a/openair1/SIMULATION/TOOLS/sim.h
+++ b/openair1/SIMULATION/TOOLS/sim.h
@@ -178,6 +178,11 @@ typedef enum {
   EVA,
   ETU,
   MBSFN,
+  TDL_A,
+  TDL_B,
+  TDL_C,
+  TDL_D,
+  TDL_E,
   Rayleigh8,
   Rayleigh1,
   Rayleigh1_800,
@@ -208,6 +213,11 @@ typedef enum {
   {"EVA",EVA},\
   {"ETU",ETU},\
   {"MBSFN",MBSFN},\
+  {"TDL_A",TDL_A},\
+  {"TDL_B",TDL_B},\
+  {"TDL_C",TDL_C},\
+  {"TDL_D",TDL_D},\
+  {"TDL_E",TDL_E},\
   {"Rayleigh8",Rayleigh8},\
   {"Rayleigh1",Rayleigh1},\
   {"Rayleigh1_800",Rayleigh1_800},\
@@ -262,33 +272,12 @@ typedef struct {
 } sim_t;
 
 
-/**
-\brief This routine initializes a new channel descriptor
-\param nb_tx Number of TX antennas
-\param nb_rx Number of RX antennas
-\param nb_taps Number of taps
-\param channel_length Length of the interpolated channel impulse response
-\param amps Linear amplitudes of the taps (length(amps)=channel_length). The values should sum up to 1.
-\param delays Delays of the taps. If delays==NULL the taps are assumed to be spaced equidistantly between 0 and t_max.
-\param R_sqrt Channel correlation matrix. If R_sqrt==NULL, no channel correlation is applied.
-\param Td Maximum path delay in mus.
-\param BW Channel bandwidth in MHz.
-\param ricean_factor Ricean factor applied to all taps.
-\param aoa Anlge of arrival
-\param forgetting_factor This parameter (0...1) allows for simple 1st order temporal variation
-\param max_Doppler This is the maximum Doppler frequency for Jakes' Model
-\param channel_offset This is a time delay to apply to channel
-\param path_loss_dB This is the path loss in dB
-\param random_aoa If set to 1, AoA of ricean component is randomized
-*/
-
-//channel_desc_t *new_channel_desc(uint8_t nb_tx,uint8_t nb_rx, uint8_t nb_taps, uint8_t channel_length, double *amps, double* delays, struct complex** R_sqrt, double Td, double BW, double ricean_factor, double aoa, double forgetting_factor, double max_Doppler, int32_t channel_offset, double path_loss_dB,uint8_t random_aoa);
-
 channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
                                      uint8_t nb_rx,
                                      SCM_t channel_model,
-				                     double sampling_rate,
+				     double sampling_rate,
                                      double channel_bandwidth,
+				     double TDL_DS,
                                      double forgetting_factor,
                                      int32_t channel_offset,
                                      double path_loss_dB);
@@ -316,7 +305,8 @@ int random_channel(channel_desc_t *desc, uint8_t abstraction_flag);
            double rx_sig_re[2],
            double rx_sig_im[2],
            uint32_t length,
-           uint8_t keep_channel)
+           uint8_t keep_channel,
+	   int log_channel)
 
 \brief This function generates and applys a random frequency selective random channel model.
 @param desc Pointer to channel descriptor
@@ -326,6 +316,7 @@ int random_channel(channel_desc_t *desc, uint8_t abstraction_flag);
 @param rx_sig_im output signal (imaginary component)
 @param length Length of input signal
 @param keep_channel Set to 1 to keep channel constant for null-B/F
+@param log_channel=1 make channel coefficients come out for first sample of input
 */
 
 void multipath_channel(channel_desc_t *desc,
@@ -334,7 +325,8 @@ void multipath_channel(channel_desc_t *desc,
                        double *rx_sig_re[2],
                        double *rx_sig_im[2],
                        uint32_t length,
-                       uint8_t keep_channel);
+                       uint8_t keep_channel,
+		       int log_channel);
 /*
 \fn double compute_pbch_sinr(channel_desc_t *desc,
                              channel_desc_t *desc_i1,
diff --git a/openair2/COMMON/platform_constants.h b/openair2/COMMON/platform_constants.h
index 77f7e26c67345dba27778cfed6270e574a880cfa..af364437b82e294e9a6a5c050f51c1d951f59aa1 100644
--- a/openair2/COMMON/platform_constants.h
+++ b/openair2/COMMON/platform_constants.h
@@ -101,9 +101,10 @@
 
 #define NUMBER_OF_NR_DLSCH_MAX 2//16
 #define NUMBER_OF_NR_ULSCH_MAX 2//16
-#define NUMBER_OF_NR_PUCCH_MAX 2
+#define NUMBER_OF_NR_SCH_STATS_MAX 16
+#define NUMBER_OF_NR_PUCCH_MAX 16
 #define NUMBER_OF_NR_SR_MAX 16
-
+#define NUMBER_OF_NR_PDCCH_MAX 16
 
 #define MAX_MANAGED_ENB_PER_MOBILE  2
 #define MAX_MANAGED_GNB_PER_MOBILE  2
diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h
index 7582de65ba4c9761f80c572254baaa21fede672c..0b143fe07edb40174f14bb6a0fe4fdfeae329ae4 100644
--- a/openair2/COMMON/rrc_messages_types.h
+++ b/openair2/COMMON/rrc_messages_types.h
@@ -403,8 +403,10 @@ typedef struct NRRrcConfigurationReq_s {
   uint16_t                mnc[PLMN_LIST_MAX_SIZE];
   uint8_t                 mnc_digit_length[PLMN_LIST_MAX_SIZE];
   NR_ServingCellConfigCommon_t *scc;
-  int                          ssb_SubcarrierOffset;
-  int                          pdsch_AntennaPorts;
+  int                     ssb_SubcarrierOffset;
+  int                     pdsch_AntennaPorts;
+  int                     pusch_TargetSNRx10;
+  int                     pucch_TargetSNRx10;
 } gNB_RrcConfigurationReq;
 
 
diff --git a/openair2/GNB_APP/RRC_nr_paramsvalues.h b/openair2/GNB_APP/RRC_nr_paramsvalues.h
index bc4c4cf9d945600a92e536aaefd19d3e3638a844..231aeb34f4f470a74f509179fa81875499e946b7 100644
--- a/openair2/GNB_APP/RRC_nr_paramsvalues.h
+++ b/openair2/GNB_APP/RRC_nr_paramsvalues.h
@@ -38,8 +38,7 @@
 
 /*    cell configuration section name */
 #define GNB_CONFIG_STRING_GNB_LIST                              "gNBs"
-#define GNB_CONFIG_STRING_SSBSUBCARRIEROFFSET                   "ssb_SubcarrierOffset"
-#define GNB_CONFIG_STRING_PDSCHANTENNAPORTS                     "pdsch_AntennaPorts"
+
 #define GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON               "servingCellConfigCommon"
 #define GNB_CONFIG_STRING_PHYSCELLID                            "physCellId"
 #define GNB_CONFIG_STRING_NTIMINGADVANCEOFFSET                  "n_TimingAdvanceOffset"
@@ -223,9 +222,6 @@
 #define GNB_CONFIG_DLCARRIERBANDWIDTH_IDX 10
 
 
-#define SSBPARAMS_DESC {{GNB_CONFIG_STRING_SSBSUBCARRIEROFFSET,NULL,0,iptr:&ssb_SubcarrierOffset,defintval:0,TYPE_INT,0}}
-#define PDSCHANTENNAPARAMS_DESC {{GNB_CONFIG_STRING_PDSCHANTENNAPORTS,NULL,0,iptr:&pdsch_AntennaPorts,defintval:1,TYPE_INT,0}}
-
 #define SCCPARAMS_DESC(scc) { \
 {GNB_CONFIG_STRING_PHYSCELLID,NULL,0,i64ptr:scc->physCellId,defint64val:0,TYPE_INT64,0/*0*/}, \
 {GNB_CONFIG_STRING_NTIMINGADVANCEOFFSET,NULL,0,i64ptr:scc->n_TimingAdvanceOffset,defint64val:NR_ServingCellConfigCommon__n_TimingAdvanceOffset_n0,TYPE_INT64,0/*1*/},\
diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c
index 61aa10e47b7310023712007af2677d5257cbf684..716134ad8abc52a5107eca443b05f56dbc1b6196 100644
--- a/openair2/GNB_APP/gnb_config.c
+++ b/openair2/GNB_APP/gnb_config.c
@@ -520,17 +520,11 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) {
   paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
 
   NR_ServingCellConfigCommon_t *scc = calloc(1,sizeof(NR_ServingCellConfigCommon_t));
-  int ssb_SubcarrierOffset = 31;
-  int pdsch_AntennaPorts = 1;
   uint64_t ssb_bitmap=0xff;
   memset((void*)scc,0,sizeof(NR_ServingCellConfigCommon_t));
   prepare_scc(scc);
   paramdef_t SCCsParams[] = SCCPARAMS_DESC(scc);
   paramlist_def_t SCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0};
-  paramdef_t SSBsParams[] = SSBPARAMS_DESC;
-  paramlist_def_t SSBsParamList = {GNB_CONFIG_STRING_SSBSUBCARRIEROFFSET, NULL, 0};
-  paramdef_t PDSCHANTENNAParams[] = PDSCHANTENNAPARAMS_DESC;
-  paramlist_def_t PDSCHANTENNAParamList = {GNB_CONFIG_STRING_PDSCHANTENNAPORTS, NULL, 0};
    ////////// Physical parameters
 
 
@@ -579,12 +573,6 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) {
     }
 
     sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
-    config_getlist(&SSBsParamList, NULL, 0, aprefix);
-    if (SSBsParamList.numelt > 0) config_get(SSBsParams,sizeof(SSBsParams)/sizeof(paramdef_t),aprefix);
-
-    config_getlist(&PDSCHANTENNAParamList, NULL, 0, aprefix);
-    if (PDSCHANTENNAParamList.numelt > 0) config_get(PDSCHANTENNAParams,sizeof(PDSCHANTENNAParams)/sizeof(paramdef_t),aprefix);
-
 
     config_getlist(&SCCsParamList, NULL, 0, aprefix);
     if (SCCsParamList.numelt > 0) {    
@@ -660,15 +648,16 @@ void RCconfig_NRRRC(MessageDef *msg_p, uint32_t i, gNB_RRC_INST *rrc) {
 		      (NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l] == 3),"BAD MNC DIGIT LENGTH %d",
 		      NRRRC_CONFIGURATION_REQ (msg_p).mnc_digit_length[l]);
 	}
-	
-        // Parse optional physical parameters
-        sprintf(gnbpath,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k),
-
-        printf("SSB SCO %d\n",ssb_SubcarrierOffset);
-	NRRRC_CONFIGURATION_REQ (msg_p).ssb_SubcarrierOffset = ssb_SubcarrierOffset;
-        printf("pdsch_AntennaPorts %d\n",pdsch_AntennaPorts);
-	NRRRC_CONFIGURATION_REQ (msg_p).pdsch_AntennaPorts = pdsch_AntennaPorts;
-	NRRRC_CONFIGURATION_REQ (msg_p).scc = scc;	   
+        printf("SSB SCO %d\n",*GNBParamList.paramarray[i][GNB_SSB_SUBCARRIEROFFSET_IDX].iptr);
+        NRRRC_CONFIGURATION_REQ (msg_p).ssb_SubcarrierOffset = *GNBParamList.paramarray[i][GNB_SSB_SUBCARRIEROFFSET_IDX].iptr;
+        printf("pdsch_AntennaPorts %d\n",*GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_IDX].iptr);
+        NRRRC_CONFIGURATION_REQ (msg_p).pdsch_AntennaPorts = *GNBParamList.paramarray[i][GNB_PDSCH_ANTENNAPORTS_IDX].iptr;
+        printf("pusch_TargetSNRx10 %d\n",*GNBParamList.paramarray[i][GNB_PUSCH_TARGETPOW_X10_IDX].iptr);
+        NRRRC_CONFIGURATION_REQ (msg_p).pusch_TargetSNRx10 = *GNBParamList.paramarray[i][GNB_PUSCH_TARGETPOW_X10_IDX].iptr;
+        printf("pucch_TargetSNRx10 %d\n",*GNBParamList.paramarray[i][GNB_PUCCH_TARGETPOW_X10_IDX].iptr);
+        NRRRC_CONFIGURATION_REQ (msg_p).pucch_TargetSNRx10 = *GNBParamList.paramarray[i][GNB_PUCCH_TARGETPOW_X10_IDX].iptr;
+        NRRRC_CONFIGURATION_REQ (msg_p).scc = scc;
+
 	  
       }//
     }//End for (k=0; k <num_gnbs ; k++)
@@ -777,11 +766,7 @@ int RCconfig_NR_S1(MessageDef *msg_p, uint32_t i) {
   if (GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt>0) {
     // Output a list of all gNBs.
        config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL); 
-    
-    
-      
-      
-    
+
     if (GNBParamList.numelt > 0) {
       for (k = 0; k < GNBParamList.numelt; k++) {
 	if (GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr == NULL) {
diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h
index 84045fc622f0a38fb7f8d16f520fc694fab415ec..84da1de530ac99bc188350c185e26704ea9c1184 100644
--- a/openair2/GNB_APP/gnb_paramdef.h
+++ b/openair2/GNB_APP/gnb_paramdef.h
@@ -113,6 +113,11 @@ typedef enum {
 #define GNB_CONFIG_STRING_REMOTE_S_PORTC                "remote_s_portc"
 #define GNB_CONFIG_STRING_LOCAL_S_PORTD                 "local_s_portd"
 #define GNB_CONFIG_STRING_REMOTE_S_PORTD                "remote_s_portd"
+#define GNB_CONFIG_STRING_SSBSUBCARRIEROFFSET           "ssb_SubcarrierOffset"
+#define GNB_CONFIG_STRING_PDSCHANTENNAPORTS             "pdsch_AntennaPorts"
+#define GNB_CONFIG_STRING_PUSCHTARGETPOWX10             "pusch_TargetSNRx10"
+#define GNB_CONFIG_STRING_PUCCHTARGETPOWX10             "pucch_TargetSNRx10"
+
 
 typedef struct ccparams_nr_x2 {
   char             *frame_type;
@@ -156,7 +161,12 @@ typedef struct ccparams_nr_x2 {
 {GNB_CONFIG_STRING_REMOTE_S_PORTC,               NULL,   0,            uptr:NULL,   defuintval:50000,            TYPE_UINT,      0},  \
 {GNB_CONFIG_STRING_LOCAL_S_PORTD,                NULL,   0,            uptr:NULL,   defuintval:50001,            TYPE_UINT,      0},  \
 {GNB_CONFIG_STRING_REMOTE_S_PORTD,               NULL,   0,            uptr:NULL,   defuintval:50001,            TYPE_UINT,      0},  \
+{GNB_CONFIG_STRING_SSBSUBCARRIEROFFSET,          NULL,   0,            iptr:NULL,   defintval:31,                TYPE_INT,       0},  \
+{GNB_CONFIG_STRING_PDSCHANTENNAPORTS,            NULL,   0,            iptr:NULL,   defintval:1,                 TYPE_INT,       0},  \
+{GNB_CONFIG_STRING_PUSCHTARGETPOWX10,            NULL,   0,            iptr:NULL,   defintval:200,               TYPE_INT,       0},  \
+{GNB_CONFIG_STRING_PUCCHTARGETPOWX10,            NULL,   0,            iptr:NULL,   defintval:200,               TYPE_INT,       0},  \
 }															     	
+
 #define GNB_GNB_ID_IDX                  0
 #define GNB_CELL_TYPE_IDX               1
 #define GNB_GNB_NAME_IDX                2
@@ -171,6 +181,10 @@ typedef struct ccparams_nr_x2 {
 #define GNB_REMOTE_S_PORTC_IDX          11
 #define GNB_LOCAL_S_PORTD_IDX           12
 #define GNB_REMOTE_S_PORTD_IDX          13
+#define GNB_SSB_SUBCARRIEROFFSET_IDX    14
+#define GNB_PDSCH_ANTENNAPORTS_IDX      15
+#define GNB_PUSCH_TARGETPOW_X10_IDX     16
+#define GNB_PUCCH_TARGETPOW_X10_IDX     17
 
 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD}
 #define GNBPARAMS_CHECK {                                         \
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
index 5d2d1e1f298585a2e1b0f617f0945c8bebb4d90a..bc105b9080502ec76c29541347561daff542b86b 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
@@ -1151,8 +1151,9 @@ uint8_t compute_nr_root_seq(NR_RACH_ConfigCommon_t *rach_config,
     if (NCS == 0) return nb_preambles;
     else {
       r = L_ra/NCS;
-      printf(" found_sequences %u\n", (nb_preambles/r));
-      return (nb_preambles/r);
+      found_sequences = (nb_preambles/r) + (nb_preambles%r!=0); //ceil(nb_preambles/r)
+      printf(" found_sequences %u\n", found_sequences);
+      return (found_sequences);
     }
   }
   else{
@@ -1615,92 +1616,156 @@ uint16_t Table_61412[28][2] = {{2,30},{2,40},{2,50},{2,64},{2,78},{2,99},{2,120}
 uint8_t nr_get_Qm_dl(uint8_t Imcs, uint8_t table_idx) {
   switch(table_idx) {
     case 0:
+      if (Imcs > 28) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 0 (expected range [0,28])\n", Imcs);
+        Imcs = 28;
+      }
       return (Table_51311[Imcs][0]);
     break;
 
     case 1:
+      if (Imcs > 27) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 1 (expected range [0,27])\n", Imcs);
+        Imcs = 27;
+      }
       return (Table_51312[Imcs][0]);
     break;
 
     case 2:
+      if (Imcs > 28) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 2 (expected range [0,28])\n", Imcs);
+        Imcs = 28;
+      }
       return (Table_51313[Imcs][0]);
     break;
 
     default:
-      AssertFatal(0, "Invalid MCS table index %d (expected in range [1,3])\n", table_idx);
+      AssertFatal(0, "Invalid MCS table index %d (expected in range [0,2])\n", table_idx);
   }
 }
 
 uint32_t nr_get_code_rate_dl(uint8_t Imcs, uint8_t table_idx) {
   switch(table_idx) {
     case 0:
+      if (Imcs > 28) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 0 (expected range [0,28])\n", Imcs);
+        Imcs = 28;
+      }
       return (Table_51311[Imcs][1]);
     break;
 
     case 1:
+      if (Imcs > 27) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 1 (expected range [0,27])\n", Imcs);
+        Imcs = 27;
+      }
       return (Table_51312[Imcs][1]);
     break;
 
     case 2:
+      if (Imcs > 28) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 2 (expected range [0,28])\n", Imcs);
+        Imcs = 28;
+      }
       return (Table_51313[Imcs][1]);
     break;
 
     default:
-      AssertFatal(0, "Invalid MCS table index %d (expected in range [1,3])\n", table_idx);
+      AssertFatal(0, "Invalid MCS table index %d (expected in range [0,2])\n", table_idx);
   }
 }
 
 uint8_t nr_get_Qm_ul(uint8_t Imcs, uint8_t table_idx) {
   switch(table_idx) {
     case 0:
+      if (Imcs > 28) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 0 (expected range [0,28])\n", Imcs);
+        Imcs = 28;
+      }
       return (Table_51311[Imcs][0]);
     break;
 
     case 1:
+      if (Imcs > 27) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 1 (expected range [0,27])\n", Imcs);
+        Imcs = 27;
+      }
       return (Table_51312[Imcs][0]);
     break;
 
     case 2:
+      if (Imcs > 28) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 2 (expected range [0,28])\n", Imcs);
+        Imcs = 28;
+      }
       return (Table_51313[Imcs][0]);
     break;
 
     case 3:
+      if (Imcs > 27) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 3 (expected range [0,27])\n", Imcs);
+        Imcs = 27;
+      }
       return (Table_61411[Imcs][0]);
     break;
 
     case 4:
+      if (Imcs > 27) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 4 (expected range [0,27])\n", Imcs);
+        Imcs = 27;
+      }
       return (Table_61412[Imcs][0]);
     break;
 
     default:
-      AssertFatal(0, "Invalid MCS table index %d (expected in range [1,2])\n", table_idx);
+      AssertFatal(0, "Invalid MCS table index %d (expected in range [0,4])\n", table_idx);
   }
 }
 
 uint32_t nr_get_code_rate_ul(uint8_t Imcs, uint8_t table_idx) {
   switch(table_idx) {
     case 0:
+      if (Imcs > 28) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 0 (expected range [0,28])\n", Imcs);
+        Imcs = 28;
+      }
       return (Table_51311[Imcs][1]);
     break;
 
     case 1:
+      if (Imcs > 27) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 1 (expected range [0,27])\n", Imcs);
+        Imcs = 27;
+      }
       return (Table_51312[Imcs][1]);
     break;
 
     case 2:
+      if (Imcs > 28) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 2 (expected range [0,28])\n", Imcs);
+        Imcs = 28;
+      }
       return (Table_51313[Imcs][1]);
     break;
 
     case 3:
+      if (Imcs > 27) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 3 (expected range [0,27])\n", Imcs);
+        Imcs = 27;
+      }
       return (Table_61411[Imcs][1]);
     break;
 
     case 4:
+      if (Imcs > 27) {
+        LOG_E(MAC, "Invalid MCS index %d for MCS table 4 (expected range [0,27])\n", Imcs);
+        Imcs = 27;
+      }
       return (Table_61412[Imcs][1]);
     break;
 
     default:
-      AssertFatal(0, "Invalid MCS table index %d (expected in range [1,2])\n", table_idx);
+      AssertFatal(0, "Invalid MCS table index %d (expected in range [0,4])\n", table_idx);
   }
 }
 
diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
index af9822a5dfa0e160c32ae572c71a9df1e01e08c4..bae8e0d3c0d61df06759242036e5dacf1cfa8246 100644
--- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
+++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
@@ -39,6 +39,7 @@
 #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"
 
 static NR_UE_MAC_INST_t *nr_ue_mac_inst; 
@@ -59,7 +60,7 @@ NR_UE_MAC_INST_t * nr_l2_init_ue(NR_UE_RRC_INST_t* rrc_inst)
 	  LOG_I(RLC, "Problem at RLC initiation \n");
     	}
     	pdcp_layer_init();
-    	nr_ip_over_LTE_DRB_preconfiguration();
+    	nr_DRB_preconfiguration();
       }
     }
     else LOG_I(MAC,"Running without RRC instance\n");
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index 60f331a08627534f34b3d70d7718c83919b11175..ab533af94122b36f4adf83a47b5f6fa68e338082 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -2342,7 +2342,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dc
     nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu_0_0,NULL,n_RB_ULBWP,0,dci->frequency_domain_assignment.val);
     /* TIME_DOM_RESOURCE_ASSIGNMENT */
     if (nr_ue_process_dci_time_dom_resource_assignment(mac,pusch_config_pdu_0_0,NULL,dci->time_domain_assignment.val) < 0)
-      break;
+      return -1;
     /* FREQ_HOPPING_FLAG */
     if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.resource_allocation != 0) &&
 	(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.frequency_hopping !=0))
@@ -2416,7 +2416,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dc
     nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu_0_1,NULL,n_RB_ULBWP,0,dci->frequency_domain_assignment.val);
     /* TIME_DOM_RESOURCE_ASSIGNMENT */
     if (nr_ue_process_dci_time_dom_resource_assignment(mac,pusch_config_pdu_0_1,NULL,dci->time_domain_assignment.val) < 0)
-      break;
+      return -1;
     /* FREQ_HOPPING_FLAG */
     if ((mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.resource_allocation != 0) &&
 	(mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated.frequency_hopping !=0))
@@ -2747,7 +2747,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dc
     nr_ue_process_dci_freq_dom_resource_assignment(NULL,dlsch_config_pdu_1_0,0,n_RB_DLBWP,dci->frequency_domain_assignment.val);
     /* TIME_DOM_RESOURCE_ASSIGNMENT */
     if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_0,dci->time_domain_assignment.val) < 0)
-      break;
+      return -1;
     /* dmrs symbol positions*/
     dlsch_config_pdu_1_0->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config,
 							 mac->scc->dmrs_TypeA_Position,
@@ -2872,7 +2872,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, dc
     nr_ue_process_dci_freq_dom_resource_assignment(NULL,dlsch_config_pdu_1_1,0,n_RB_DLBWP,dci->frequency_domain_assignment.val);
     /* TIME_DOM_RESOURCE_ASSIGNMENT */
     if (nr_ue_process_dci_time_dom_resource_assignment(mac,NULL,dlsch_config_pdu_1_1,dci->time_domain_assignment.val) < 0)
-      break;
+      return -1;
     /* dmrs symbol positions*/
     dlsch_config_pdu_1_1->dlDmrsSymbPos = fill_dmrs_mask(pdsch_config,
 							 mac->scc->dmrs_TypeA_Position,
@@ -3582,19 +3582,18 @@ void nr_ue_process_mac_pdu(module_id_t module_idP,
     //  L: The Length field indicates the length of the corresponding MAC SDU or variable-sized MAC CE in bytes. There is one L field per MAC subheader except for subheaders corresponding to fixed-sized MAC CEs and padding. The size of the L field is indicated by the F field;
     //  F: lenght of L is 0:8 or 1:16 bits wide
     //  R: Reserved bit, set to zero.
-    
     while (!done && pdu_len > 0){
         mac_ce_len = 0x0000;
         mac_subheader_len = 0x0001; //  default to fixed-length subheader = 1-oct
         mac_sdu_len = 0x0000;
         rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pdu_ptr)->LCID;
+	  //#ifdef DEBUG_HEADER_PARSING
+              LOG_D(MAC, "[UE] LCID %d, PDU length %d\n", ((NR_MAC_SUBHEADER_FIXED *)pdu_ptr)->LCID, pdu_len);
+	      //#endif
 
         switch(rx_lcid){
             //  MAC CE
 
-            /*#ifdef DEBUG_HEADER_PARSING
-              LOG_D(MAC, "[UE] LCID %d, PDU length %d\n", ((NR_MAC_SUBHEADER_FIXED *)pdu_ptr)->LCID, pdu_len);
-            #endif*/
             case DL_SCH_LCID_CCCH:
                 //  MSG4 RRC Connection Setup 38.331
                 //  varialbe length
@@ -3802,7 +3801,8 @@ void nr_ue_process_mac_pdu(module_id_t module_idP,
         }
         pdu_ptr += ( mac_subheader_len + mac_ce_len + mac_sdu_len );
         pdu_len -= ( mac_subheader_len + mac_ce_len + mac_sdu_len );
-        AssertFatal(pdu_len >= 0, "[MAC] nr_ue_process_mac_pdu, residual mac pdu length < 0!\n");
+        if (pdu_len < 0)
+          LOG_E(MAC, "[MAC] nr_ue_process_mac_pdu, residual mac pdu length %d < 0!\n", pdu_len);
     }
 }
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c
index 36b81927f80e95283b2b2ab339340e9970fcd1ae..4e46603dc92c9d9ed8a9e620886c78cfcc63e63b 100644
--- a/openair2/LAYER2/NR_MAC_gNB/config.c
+++ b/openair2/LAYER2/NR_MAC_gNB/config.c
@@ -298,41 +298,18 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
   else LOG_I(PHY,"TDD has been properly configurated\n");
   }
 
-/*
-  // PDCCH-ConfigCommon
-  cfg->pdcch_config.controlResourceSetZero.value = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero;
-  cfg->pdcch_config.searchSpaceZero.value = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceZero;
-
-  // PDSCH-ConfigCommon
-  cfg->pdsch_config.num_PDSCHTimeDomainResourceAllocations.value = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.count;
-  cfg->pdsch_config.dmrs_TypeA_Position.value = scc->dmrs_TypeA_Position;
-  AssertFatal(cfg->pdsch_config.num_PDSCHTimeDomainResourceAllocations.value<=NFAPI_NR_PDSCH_CONFIG_MAXALLOCATIONS,"illegal TimeDomainAllocation count %d\n",cfg->pdsch_config.num_PDSCHTimeDomainResourceAllocations.value);
-  for (int i=0;i<cfg->pdsch_config.num_PDSCHTimeDomainResourceAllocations.value;i++) {
-    cfg->pdsch_config.PDSCHTimeDomainResourceAllocation_k0[i].value=*scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->k0;
-    cfg->pdsch_config.PDSCHTimeDomainResourceAllocation_mappingType[i].value=scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->mappingType;
-    cfg->pdsch_config.PDSCHTimeDomainResourceAllocation_startSymbolAndLength[i].value=scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList->list.array[i]->startSymbolAndLength;
-  }
-
-  // PUSCH-ConfigCommon
-  cfg->pusch_config.num_PUSCHTimeDomainResourceAllocations.value = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count;
-  cfg->pusch_config.dmrs_TypeA_Position.value = scc->dmrs_TypeA_Position+2;
-  AssertFatal(cfg->pusch_config.num_PUSCHTimeDomainResourceAllocations.value<=NFAPI_NR_PUSCH_CONFIG_MAXALLOCATIONS,"illegal TimeDomainAllocation count %d\n",cfg->pusch_config.num_PUSCHTimeDomainResourceAllocations.value);
-  for (int i=0;i<cfg->pusch_config.num_PUSCHTimeDomainResourceAllocations.value;i++) {
-    cfg->pusch_config.PUSCHTimeDomainResourceAllocation_k2[i].value=*scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[0]->k2;
-  }*/
-
-
 }
 
 
 int rrc_mac_config_req_gNB(module_id_t Mod_idP, 
 			   int ssb_SubcarrierOffset,
                            int pdsch_AntennaPorts,
+                           int pusch_tgt_snrx10,
+                           int pucch_tgt_snrx10,
                            NR_ServingCellConfigCommon_t *scc,
 			   int add_ue,
 			   uint32_t rnti,
-			   NR_CellGroupConfig_t *secondaryCellGroup
-                           ){
+			   NR_CellGroupConfig_t *secondaryCellGroup){
 
   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);
@@ -353,7 +330,8 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
       }
     }
   
-  
+    RC.nrmac[Mod_idP]->pusch_target_snrx10 = pusch_tgt_snrx10;
+    RC.nrmac[Mod_idP]->pucch_target_snrx10 = pucch_tgt_snrx10;
     NR_PHY_Config_t phycfg;
     phycfg.Mod_id = Mod_idP;
     phycfg.CC_id  = 0;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
index e25680e8618462cf70e74e5dce11d50697c72dc6..548845eae5db766f19fa07cb1b1be6e3e92f524b 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
@@ -62,6 +62,32 @@
 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) {
+  memset((void*)gNB->UE_list.mac_stats,0,MAX_MOBILES_PER_GNB*sizeof(NR_mac_stats_t));
+}
+
+void dump_mac_stats(gNB_MAC_INST *gNB) {
+
+  NR_UE_list_t *UE_list = &gNB->UE_list;
+  NR_mac_stats_t *stats;
+  int lc_id;
+
+  for (int UE_id=0;UE_id<MAX_MOBILES_PER_GNB;UE_id++) {
+    if (UE_list->active[UE_id] == TRUE) {
+      LOG_I(MAC,"UE %x\n",UE_list->rnti[UE_id]);
+      stats = &UE_list->mac_stats[UE_id];
+      LOG_I(MAC,"dlsch_rounds %d/%d/%d/%d, dlsch_errors %d\n",stats->dlsch_rounds[0],stats->dlsch_rounds[1],stats->dlsch_rounds[2],stats->dlsch_rounds[3],stats->dlsch_errors);
+      LOG_I(MAC,"dlsch_total_bytes %d\n",stats->dlsch_total_bytes);
+      LOG_I(MAC,"ulsch_rounds %d/%d/%d/%d, ulsch_errors %d\n",stats->ulsch_rounds[0],stats->ulsch_rounds[1],stats->ulsch_rounds[2],stats->ulsch_rounds[3],stats->ulsch_errors);
+      LOG_I(MAC,"ulsch_total_bytes_scheduled %d, ulsch_total_bytes_received %d\n",stats->ulsch_total_bytes_scheduled,stats->ulsch_total_bytes_rx);
+      for (lc_id=0;lc_id<63;lc_id++) {
+	if (stats->lc_bytes_tx[lc_id]>0) LOG_I(MAC,"LCID %d : %d bytes TX\n",lc_id,stats->lc_bytes_tx[lc_id]);
+	if (stats->lc_bytes_rx[lc_id]>0) LOG_I(MAC,"LCID %d : %d bytes RX\n",lc_id,stats->lc_bytes_rx[lc_id]);
+      }
+    }
+  }
+}
+
 void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
                                 int CC_idP,
                                 frame_t frameP,
@@ -288,8 +314,33 @@ void copy_nr_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
 }
 */
 
+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_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
+  int k = slotP + ul_slots - num_slots_per_tdd;
+  NR_sched_pusch *pusch = &UE_list->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_list->UE_sched_ctrl[UE_id].sched_pusch[k],
+           0, sizeof(NR_sched_pusch));
+  }
+}
+
+
 void nr_schedule_pucch(int Mod_idP,
                        int UE_id,
+                       int nr_ulmix_slots,
                        frame_t frameP,
                        sub_frame_t slotP) {
 
@@ -306,15 +357,12 @@ void nr_schedule_pucch(int Mod_idP,
   nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
 
   NR_sched_pucch *curr_pucch;
-  int nr_ulmix_slots = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
-  if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0)
-    nr_ulmix_slots++;
 
   for (int k=0; k<nr_ulmix_slots; k++) {
     curr_pucch = &UE_list->UE_sched_ctrl[UE_id].sched_pucch[k];
     if ((curr_pucch->dai_c > 0) && (frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) {
-      UL_tti_req->SFN = frameP;
-      UL_tti_req->Slot = slotP;
+      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;
@@ -323,7 +371,7 @@ void nr_schedule_pucch(int Mod_idP,
       O_ack = curr_pucch->dai_c;
       O_uci = O_ack; // for now we are just sending acknacks in pucch
 
-      LOG_I(MAC, "Scheduling pucch reception for frame %d slot %d\n", frameP, slotP);
+      LOG_D(MAC, "Scheduling pucch reception for frame %d slot %d\n", frameP, slotP);
 
       nr_configure_pucch(pucch_pdu,
 			 scc,
@@ -333,11 +381,15 @@ void nr_schedule_pucch(int Mod_idP,
                          O_ack,
                          SR_flag);
 
-      curr_pucch->dai_c = 0;
+      memset((void *) &UE_list->UE_sched_ctrl[UE_id].sched_pucch[k],
+             0,
+             sizeof(NR_sched_pucch));
     }
   }
 }
 
+
+
 bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot){
 
   if((bitmap>>slot)&0x01)
@@ -347,15 +399,12 @@ bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot){
 }
 
 void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
-                               frame_t frame_rxP,
-                               sub_frame_t slot_rxP,
-                               frame_t frame_txP,
-                               sub_frame_t slot_txP){
+                               frame_t frame,
+                               sub_frame_t slot){
 
-  //printf("gNB_dlsch_ulsch_scheduler frameRX %d slotRX %d frameTX %d slotTX %d\n",frame_rxP,slot_rxP,frame_txP,slot_txP);
 			       
   protocol_ctxt_t   ctxt;
-  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frame_txP, slot_txP,module_idP);
+  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frame, slot,module_idP);
  
   int CC_id;
   int UE_id;
@@ -377,11 +426,14 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
   if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0)
     nr_ulmix_slots++;
 
-  if (slot_txP== 0 && (UE_list->fiveG_connected[UE_id] || get_softmodem_params()->phy_test)) {
+  if (slot== 0 && (UE_list->fiveG_connected[UE_id] || get_softmodem_params()->phy_test)) {
     for (int k=0; k<nr_ulmix_slots; k++) {
       memset((void *) &UE_list->UE_sched_ctrl[UE_id].sched_pucch[k],
              0,
              sizeof(NR_sched_pucch));
+      memset((void *) &UE_list->UE_sched_ctrl[UE_id].sched_pusch[k],
+             0,
+             sizeof(NR_sched_pusch));
     }
   }
 
@@ -391,93 +443,106 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
   pdcp_run(&ctxt);
   //rrc_rx_tx(&ctxt, CC_id);
 
-  RC.nrmac[module_idP]->frame    = frame_rxP;
-  RC.nrmac[module_idP]->slot     = slot_rxP;
-
   dlsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].dlsch_in_slot_bitmap;  // static bitmap signaling which slot in a tdd period contains dlsch
   ulsch_in_slot_bitmap = &RC.nrmac[module_idP]->UE_list.UE_sched_ctrl[UE_id].ulsch_in_slot_bitmap;  // static bitmap signaling which slot in a tdd period contains ulsch
 
   // hardcoding dlsch to be in slot 1
-  if (!(slot_txP%num_slots_per_tdd)) {
-    if(slot_txP==0)
+  if (!(slot%num_slots_per_tdd)) {
+    if(slot==0) {
       *dlsch_in_slot_bitmap = 0x02;
-    else
-      *dlsch_in_slot_bitmap = 0x00;
-  }
-
-  // hardcoding ulsch to be in slot 8
-  if (!(slot_rxP%num_slots_per_tdd)) {
-    if(slot_rxP==0)
       *ulsch_in_slot_bitmap = 0x100;
-    else
+    }
+    else {
+      *dlsch_in_slot_bitmap = 0x00;
       *ulsch_in_slot_bitmap = 0x00;
+    }
   }
 
-  // Check if there are downlink symbols in the slot, 
-  if (is_nr_DL_slot(cc->ServingCellConfigCommon,slot_txP)) {
-    memset(RC.nrmac[module_idP]->cce_list[bwp_id][0],0,MAX_NUM_CCE*sizeof(int)); // coreset0
-    memset(RC.nrmac[module_idP]->cce_list[bwp_id][1],0,MAX_NUM_CCE*sizeof(int)); // coresetid 1
-    for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
-      //mbsfn_status[CC_id] = 0;
+  memset(RC.nrmac[module_idP]->cce_list[bwp_id][0],0,MAX_NUM_CCE*sizeof(int)); // coreset0
+  memset(RC.nrmac[module_idP]->cce_list[bwp_id][1],0,MAX_NUM_CCE*sizeof(int)); // coresetid 1
+  for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
+    //mbsfn_status[CC_id] = 0;
 
-      // clear vrb_maps
-      memset(cc[CC_id].vrb_map, 0, 100);
-      memset(cc[CC_id].vrb_map_UL, 0, 100);
+    // clear vrb_maps
+    memset(cc[CC_id].vrb_map, 0, 100);
+    memset(cc[CC_id].vrb_map_UL, 0, 100);
 
-      clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame_txP, slot_txP);
-    }
+    clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame, slot);
+  }
 
-    // refresh UE list based on UEs dropped by PHY in previous subframe
-    /*
-    for (i = 0; i < MAX_MOBILES_PER_GNB; i++) {
-      if (UE_list->active[i]) {
+  // refresh UE list based on UEs dropped by PHY in previous subframe
+  /*
+  for (i = 0; i < MAX_MOBILES_PER_GNB; i++) {
+    if (UE_list->active[i]) {
 
-        nfapi_nr_config_request_t *cfg = &RC.nrmac[module_idP]->config[CC_id];      
+      nfapi_nr_config_request_t *cfg = &RC.nrmac[module_idP]->config[CC_id];      
       
-        rnti = 0;//UE_RNTI(module_idP, i);
-        CC_id = 0;//UE_PCCID(module_idP, i);
+      rnti = 0;//UE_RNTI(module_idP, i);
+      CC_id = 0;//UE_PCCID(module_idP, i);
 
-      } //END if (UE_list->active[i])
-    } //END for (i = 0; i < MAX_MOBILES_PER_GNB; i++)
-    */
+    } //END if (UE_list->active[i])
+  } //END for (i = 0; i < MAX_MOBILES_PER_GNB; i++)
+  */
 
-    // This schedules MIB
-    if((slot_txP == 0) && (frame_txP & 7) == 0){
-      schedule_nr_mib(module_idP, frame_txP, slot_txP);
-    }
-
-    if (get_softmodem_params()->phy_test == 0)
-      nr_schedule_RA(module_idP, frame_txP, slot_txP);
-    else
-      UE_list->fiveG_connected[UE_id] = true;
+  if ((slot == 0) && (frame & 127) == 0) dump_mac_stats(RC.nrmac[module_idP]);
 
-    // Phytest scheduling
+  // This schedules MIB
+  if((slot == 0) && (frame & 7) == 0){
+    schedule_nr_mib(module_idP, frame, slot);
+  }
 
-    if (get_softmodem_params()->phy_test) {
+  // 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);
+
+  // This schedule SR
+  // TODO
+
+  // This schedule CSI
+  // TODO
+
+  // This schedule RA procedure if not in phy_test mode
+  // Otherwise already consider 5G already connected
+  if (get_softmodem_params()->phy_test == 0) {
+    nr_schedule_RA(module_idP, frame, slot);
+    nr_schedule_reception_msg3(module_idP, 0, frame, slot);
+  } else
+    UE_list->fiveG_connected[UE_id] = true;
+
+  if (get_softmodem_params()->phy_test) {
+
+    // TbD once RACH is available, start ta_timer when UE is connected
+    if (ue_sched_ctl->ta_timer)
+      ue_sched_ctl->ta_timer--;
+    if (ue_sched_ctl->ta_timer == 0) {
+      gNB->ta_command = ue_sched_ctl->ta_update;
+      /* if time is up, then set the timer to not send it for 5 frames
+      // regardless of the TA value */
+      ue_sched_ctl->ta_timer = 100;
+      /* reset ta_update */
+      ue_sched_ctl->ta_update = 31;
+      /* MAC CE flag indicating TA length */
+      gNB->ta_len = 2;
+    }
+  }
 
-      // TbD once RACH is available, start ta_timer when UE is connected
-      if (ue_sched_ctl->ta_timer)
-        ue_sched_ctl->ta_timer--;
+  // This schedules the DCI for Uplink and subsequently PUSCH
+  if (UE_list->fiveG_connected[UE_id]) {
+    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);
+    nr_schedule_pusch(module_idP, UE_id, num_slots_per_tdd, nr_ulmix_slots, frame, slot);
+  }
 
-      if (ue_sched_ctl->ta_timer == 0) {
-        gNB->ta_command = ue_sched_ctl->ta_update;
-        /* if time is up, then set the timer to not send it for 5 frames
-        // regardless of the TA value */
-        ue_sched_ctl->ta_timer = 100;
-        /* reset ta_update */
-        ue_sched_ctl->ta_update = 31;
-        /* MAC CE flag indicating TA length */
-        gNB->ta_len = 2;
-      }
-    }
+  if (UE_list->fiveG_connected[UE_id] && (is_xlsch_in_slot(*dlsch_in_slot_bitmap,slot%num_slots_per_tdd))) {
+    ue_sched_ctl->current_harq_pid = slot % num_slots_per_tdd;
+    nr_update_pucch_scheduling(module_idP, UE_id, frame, slot, num_slots_per_tdd,&pucch_sched);
+    nr_schedule_uss_dlsch_phytest(module_idP, frame, slot, &UE_list->UE_sched_ctrl[UE_id].sched_pucch[pucch_sched], NULL);
+    // resetting ta flag
+    gNB->ta_len = 0;
+  }
 
-    if (UE_list->fiveG_connected[UE_id] && (is_xlsch_in_slot(*dlsch_in_slot_bitmap,slot_txP%num_slots_per_tdd))) {
-      ue_sched_ctl->current_harq_pid = slot_txP % num_slots_per_tdd;
-      nr_update_pucch_scheduling(module_idP, UE_id, frame_txP, slot_txP, num_slots_per_tdd,&pucch_sched);
-      nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP, &UE_list->UE_sched_ctrl[UE_id].sched_pucch[pucch_sched], NULL);
-      // resetting ta flag
-      gNB->ta_len = 0;
-    }
+  if (UE_list->fiveG_connected[UE_id])
+    nr_schedule_pucch(module_idP, UE_id, nr_ulmix_slots, frame, slot);
 
     /*
     // Allocate CCEs for good after scheduling is done
@@ -485,24 +550,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
       allocate_CCEs(module_idP, CC_id, subframeP, 0);
     */
 
-  } //is_nr_DL_slot
-
-  if (is_nr_UL_slot(cc->ServingCellConfigCommon,slot_rxP)) { 
-
-    if (get_softmodem_params()->phy_test == 0) {
-      if (UE_list->fiveG_connected[UE_id])
-        nr_schedule_pucch(module_idP, UE_id, frame_rxP, slot_rxP);
-      schedule_nr_prach(module_idP, (frame_rxP+1)&1023, slot_rxP);
-      nr_schedule_reception_msg3(module_idP, 0, frame_rxP, slot_rxP);
-    }
-    if (get_softmodem_params()->phy_test){
-      nr_schedule_pucch(module_idP, UE_id, frame_rxP, slot_rxP);
-      if (is_xlsch_in_slot(*ulsch_in_slot_bitmap,slot_rxP%num_slots_per_tdd)){
-        nr_schedule_uss_ulsch_phytest(module_idP, frame_rxP, slot_rxP);
-      }
-    }
-  }
-
   stop_meas(&RC.nrmac[module_idP]->eNB_scheduler);
   
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_OUT);
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
index e90a69638c47216554b29b01096c5c3adcac9b51..4c17ee3a0fb9c73e3b57e08792a5d93efc4aadc9 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
@@ -53,115 +53,117 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP
   NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
   nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req[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;
-  uint16_t format;
+  if (is_nr_UL_slot(scc,slotP)) {
 
-  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;
-
-  // 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) ) {
-
-    int fdm = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM;
-    uint16_t format0 = format&0xff;      // first column of format from table
-    uint16_t format1 = (format>>8)&0xff; // second column of format from table
-
-    UL_tti_req->SFN = frameP;
-    UL_tti_req->Slot = slotP;
-    for (int n=0; n<(1<<fdm); n++) { // one structure per frequency domain occasion
-      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 = n;
-      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);
-      // 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 = 9;
-            break;
-          case 0xa2:
-            prach_pdu->prach_format = 10;
-            break;
-          case 0xa3:
-            prach_pdu->prach_format = 11;
-            break;
-        default:
-          AssertFatal(1==0,"Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
+    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;
+    uint16_t format;
+
+    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;
+
+    // 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) ) {
+
+      int fdm = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM;
+      uint16_t format0 = format&0xff;      // first column of format from table
+      uint16_t format1 = (format>>8)&0xff; // second column of format from table
+
+      UL_tti_req->SFN = frameP;
+      UL_tti_req->Slot = slotP;
+      for (int n=0; n<(1<<fdm); n++) { // one structure per frequency domain occasion
+        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 = n;
+        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);
+        // 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 = 9;
+              break;
+            case 0xa2:
+              prach_pdu->prach_format = 10;
+              break;
+            case 0xa3:
+              prach_pdu->prach_format = 11;
+              break;
+          default:
+            AssertFatal(1==0,"Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
+          }
         }
-      }
-      else{
-        switch(format0) {
-          case 0xa1:
-            prach_pdu->prach_format = 0;
-            break;
-          case 0xa2:
-            prach_pdu->prach_format = 1;
-            break;
-          case 0xa3:
-            prach_pdu->prach_format = 2;
-            break;
-          case 0xb1:
-            prach_pdu->prach_format = 3;
-            break;
-          case 0xb2:
-            prach_pdu->prach_format = 4;
-            break;
-          case 0xb3:
-            prach_pdu->prach_format = 5;
-            break;
-          case 0xb4:
-            prach_pdu->prach_format = 6;
-            break;
-          case 0xc0:
-            prach_pdu->prach_format = 7;
-            break;
-          case 0xc2:
-            prach_pdu->prach_format = 8;
-            break;
-          case 0:
-            // long formats are handled @ PHY
-            break;
-          case 1:
-            // long formats are handled @ PHY
-            break;
-          case 2:
-            // long formats are handled @ PHY
-            break;
-          case 3:
-            // long formats are handled @ PHY
-            break;
-        default:
-          AssertFatal(1==0,"Invalid PRACH format");
+        else{
+          switch(format0) {
+            case 0xa1:
+              prach_pdu->prach_format = 0;
+              break;
+            case 0xa2:
+              prach_pdu->prach_format = 1;
+              break;
+            case 0xa3:
+              prach_pdu->prach_format = 2;
+              break;
+            case 0xb1:
+              prach_pdu->prach_format = 3;
+              break;
+            case 0xb2:
+              prach_pdu->prach_format = 4;
+              break;
+            case 0xb3:
+              prach_pdu->prach_format = 5;
+              break;
+            case 0xb4:
+              prach_pdu->prach_format = 6;
+              break;
+            case 0xc0:
+              prach_pdu->prach_format = 7;
+              break;
+            case 0xc2:
+              prach_pdu->prach_format = 8;
+              break;
+            case 0:
+              // long formats are handled @ PHY
+              break;
+            case 1:
+              // long formats are handled @ PHY
+              break;
+            case 2:
+              // long formats are handled @ PHY
+              break;
+            case 3:
+              // long formats are handled @ PHY
+              break;
+          default:
+            AssertFatal(1==0,"Invalid PRACH format");
+          }
         }
       }
     }
   }
 }
 
-
 void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot,
                       uint16_t *msg2_frame, uint16_t *msg2_slot,
                       NR_ServingCellConfigCommon_t *scc,
@@ -435,7 +437,10 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t
   NR_UE_list_t                               *UE_list = &mac->UE_list;
   int UE_id = 0;
 
-  AssertFatal(ra->state != RA_IDLE, "RA is not active for RA %X\n", ra->rnti);
+  if (ra->state == RA_IDLE) {
+    LOG_W(MAC,"RA is not active for RA %X. skipping msg3 scheduling\n", ra->rnti);
+    return;
+  }
 
   LOG_D(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);
 
@@ -538,7 +543,7 @@ void nr_generate_Msg2(module_id_t module_idP,
                       sub_frame_t slotP){
 
   int UE_id = 0, dci_formats[2], rnti_types[2], mcsIndex;
-  int startSymbolAndLength = 0, StartSymbolIndex = -1, NrOfSymbols = 14, StartSymbolIndex_tmp, NrOfSymbols_tmp, x_Overhead, time_domain_assignment;
+  int startSymbolAndLength = 0, StartSymbolIndex = -1, NrOfSymbols = 14, StartSymbolIndex_tmp, NrOfSymbols_tmp, x_Overhead, time_domain_assignment = 0;
   gNB_MAC_INST                      *nr_mac = RC.nrmac[module_idP];
   NR_COMMON_channels_t                  *cc = &nr_mac->common_channels[0];
   NR_RA_t                               *ra = &cc->ra[0];
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
index cf2323f5711574256739356ac3c48b4a8db8c9e5..495095ce9e30035c85b0275cfb42784c82ce3553 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
@@ -38,6 +38,7 @@
 #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*/
 #include "nfapi_nr_interface.h"
@@ -76,6 +77,8 @@ int nr_generate_dlsch_pdu(module_id_t module_idP,
   //NR_CellGroupConfig_t *config = UE_list->secondaryCellGroup[UE_id];
   ue_sched_ctl = &(UE_list->UE_sched_ctrl[UE_id]);
 
+  NR_mac_stats_t *mac_stats = &(UE_list->mac_stats[UE_id]);
+
   // 1) Compute MAC CE and related subheaders
 
   // DRX command subheader (MAC CE size 0)
@@ -112,6 +115,8 @@ int nr_generate_dlsch_pdu(module_id_t module_idP,
     memcpy((void *) mac_pdu_ptr, (void *) ce_ptr, mac_ce_size);
     ce_ptr += mac_ce_size;
     mac_pdu_ptr += (unsigned char) mac_ce_size;
+
+
   }
 
   // Contention resolution fixed subheader and MAC CE
@@ -324,6 +329,8 @@ int nr_generate_dlsch_pdu(module_id_t module_idP,
     memcpy((void *) mac_pdu_ptr, (void *) dlsch_buffer_ptr, sdu_lengths[i]);
     dlsch_buffer_ptr += sdu_lengths[i];
     mac_pdu_ptr += sdu_lengths[i];
+
+    mac_stats->lc_bytes_tx[sdu_lcids[i]] += sdu_lengths[i];
   }
 
   // 4) Compute final offset for padding
@@ -341,6 +348,70 @@ int nr_generate_dlsch_pdu(module_id_t module_idP,
   return offset;
 }
 
+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) {
+  // TODO
+  int max_harq_rounds = 4; // TODO define macro
+  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_PDCCH_PDU_TYPE: break;
+
+      case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: {
+        //if (get_softmodem_params()->phy_test == 0) {
+          nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu = &uci_list[i].pucch_pdu_format_0_1;
+          // handle harq
+          int harq_idx_s = 0;
+          // tpc (power control)
+          sched_ctrl->tpc1 = nr_get_tpc(target_snrx10,uci_pdu->ul_cqi,30);
+          // iterate over received harq bits
+          for (int harq_bit = 0; harq_bit < uci_pdu->harq->num_harq; harq_bit++) {
+            // 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 ((uci_pdu->harq->harq_list[harq_bit].harq_value == 1) &&
+                    (uci_pdu->harq->harq_confidence_level == 0)) {
+                  // toggle NDI and reset round
+                  sched_ctrl->harq_processes[harq_idx].ndi ^= 1;
+                  sched_ctrl->harq_processes[harq_idx].round = 0;
+                }
+                else
+                  sched_ctrl->harq_processes[harq_idx].round++;
+                sched_ctrl->harq_processes[harq_idx].is_waiting = 0;
+                harq_idx_s = harq_idx + 1;
+                // if the max harq rounds was reached
+                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++;
+                }
+                break;
+              }
+              // if feedback slot processing is aborted
+              else if (((UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot) &&
+                      (sched_ctrl->harq_processes[harq_idx].is_waiting)) {
+                sched_ctrl->harq_processes[harq_idx].round++;
+                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;
+                }
+                sched_ctrl->harq_processes[harq_idx].is_waiting = 0;
+              }
+            }
+          }
+        //}
+        break;
+      }
+
+      case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: break;
+    }
+  }
+
+  UL_info->uci_ind.num_ucis = 0;
+}
+
 /* functionalities of this function have been moved to nr_schedule_uss_dlsch_phytest */
 void nr_schedule_ue_spec(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) {
 }
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
index 9f5d4f5ec747cd4a7dd1535ede8fcb180ffb5a8a..f786db8ba907aeec4dcaba4e36b91fafcdbbf3fa 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
@@ -53,7 +53,10 @@
 #include "NR_SearchSpace.h"
 #include "NR_ControlResourceSet.h"
 
+//#define UL_HARQ_PRINT
 extern RAN_CONTEXT_t RC;
+
+const uint8_t nr_rv_round_map[4] = {0, 2, 1, 3}; 
 //#define ENABLE_MAC_PAYLOAD_DEBUG 1
 
 //uint8_t mac_pdu[MAX_NR_DLSCH_PAYLOAD_BYTES];
@@ -257,8 +260,6 @@ int configure_fapi_dl_pdu(int Mod_idP,
                           uint16_t *rbSize,
                           uint16_t *rbStart) {
 
-
-
   gNB_MAC_INST                        *nr_mac  = RC.nrmac[Mod_idP];
   NR_COMMON_channels_t                *cc      = nr_mac->common_channels;
   NR_ServingCellConfigCommon_t        *scc     = cc->ServingCellConfigCommon;
@@ -314,12 +315,12 @@ int configure_fapi_dl_pdu(int Mod_idP,
   pdsch_pdu_rel15->qamModOrder[0] = 2;
   pdsch_pdu_rel15->mcsIndex[0] = mcs;
   pdsch_pdu_rel15->mcsTable[0] = 0;
-  pdsch_pdu_rel15->rvIndex[0] = (get_softmodem_params()->phy_test==1) ? 0 : UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].round;
+  pdsch_pdu_rel15->rvIndex[0] = nr_rv_round_map[UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].round];
   pdsch_pdu_rel15->dataScramblingId = *scc->physCellId;
   pdsch_pdu_rel15->nrOfLayers = 1;    
   pdsch_pdu_rel15->transmissionScheme = 0;
   pdsch_pdu_rel15->refPoint = 0; // Point A
-    
+  UE_list->mac_stats[UE_id].dlsch_rounds[UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].round]++;
   pdsch_pdu_rel15->dmrsConfigType = bwp->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type == NULL ? 0 : 1;  
   pdsch_pdu_rel15->dlDmrsScramblingId = *scc->physCellId;
   pdsch_pdu_rel15->SCID = 0;
@@ -372,7 +373,7 @@ int configure_fapi_dl_pdu(int Mod_idP,
   dci_pdu_rel15[0].dai[0].val = (pucch_sched->dai_c-1)&3;
 
   // TPC for PUCCH
-  dci_pdu_rel15[0].tpc = 1; // table 7.2.1-1 in 38.213
+  dci_pdu_rel15[0].tpc = UE_list->UE_sched_ctrl[UE_id].tpc1; // table 7.2.1-1 in 38.213
   // PUCCH resource indicator
   dci_pdu_rel15[0].pucch_resource_indicator = pucch_sched->resource_indicator;
   // PDSCH to HARQ TI
@@ -454,6 +455,9 @@ int configure_fapi_dl_pdu(int Mod_idP,
 
   // Hardcode it for now
   TBS = dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15.TBSize[0];
+  if (UE_list->UE_sched_ctrl[UE_id].harq_processes[current_harq_pid].round==0)
+    UE_list->mac_stats[UE_id].dlsch_total_bytes += TBS;
+
   LOG_D(MAC, "DLSCH PDU: start PRB %d n_PRB %d startSymbolAndLength %d start symbol %d nb_symbols %d nb_layers %d nb_codewords %d mcs %d TBS: %d\n",
 	pdsch_pdu_rel15->rbStart,
 	pdsch_pdu_rel15->rbSize,
@@ -474,7 +478,7 @@ void config_uldci(NR_BWP_Uplink_t *ubwp,
                   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,
+                  int time_domain_assignment, uint8_t tpc,
                   int n_ubwp, int bwp_id) {
 
   switch(dci_formats[(pdcch_pdu_rel15->numDlDci)-1]) {
@@ -491,7 +495,7 @@ void config_uldci(NR_BWP_Uplink_t *ubwp,
       dci_pdu_rel15->ndi = 1;
       dci_pdu_rel15->rv = 0;
       dci_pdu_rel15->harq_pid = 0;
-      dci_pdu_rel15->tpc = 2;
+      dci_pdu_rel15->tpc = 1;
       break;
     case NR_UL_DCI_FORMAT_0_1:
       dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator;
@@ -516,7 +520,7 @@ void config_uldci(NR_BWP_Uplink_t *ubwp,
       // mcs
       dci_pdu_rel15->mcs = pusch_pdu->mcs_index;
       // tpc command for pusch
-      dci_pdu_rel15->tpc = 2; //TODO
+      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)
@@ -593,7 +597,7 @@ void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
   LOG_D(MAC, "In nr_schedule_uss_dlsch_phytest frame %d slot %d\n",frameP,slotP);
 
   int post_padding = 0, ta_len = 0, header_length_total = 0, sdu_length_total = 0, num_sdus = 0;
-  int lcid, offset, i, header_length_last, TBS_bytes;
+  int lcid, offset, i, header_length_last, TBS_bytes = 0;
   int UE_id = 0, CC_id = 0;
 
   gNB_MAC_INST *gNB_mac = RC.nrmac[module_idP];
@@ -627,69 +631,61 @@ void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
 
   if (TBS_bytes == 0)
    return;
- 
-  //The --NOS1 use case currently schedules DLSCH transmissions only when there is IP traffic arriving
-  //through the LTE stack
-  if (IS_SOFTMODEM_NOS1){
-
-    for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) {
-
-      // TODO: check if the lcid is active
-
-      LOG_D(MAC, "[gNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (TBS %d bytes, len %d)\n",
-        module_idP, frameP, lcid, TBS_bytes, TBS_bytes - ta_len - header_length_total - sdu_length_total - 3);
-
-      if (TBS_bytes - ta_len - header_length_total - sdu_length_total - 3 > 0) {
-        rlc_status = mac_rlc_status_ind(module_idP,
-                                        rnti,
-                                        module_idP,
-                                        frameP,
-                                        slotP,
-                                        ENB_FLAG_YES,
-                                        MBMS_FLAG_NO,
-                                        lcid,
-                                        0,
-                                        0);
-
-        if (rlc_status.bytes_in_buffer > 0) {
-
-          LOG_D(MAC, "[gNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d), TBS_bytes: %d \n \n",
-            module_idP, frameP, TBS_bytes - ta_len - header_length_total - sdu_length_total - 3,
-            lcid, header_length_total, TBS_bytes);
-
-          sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
-                                                   rnti,
-                                                   module_idP,
-                                                   frameP,
-                                                   ENB_FLAG_YES,
-                                                   MBMS_FLAG_NO,
-                                                   lcid,
-                                                   TBS_bytes - ta_len - header_length_total - sdu_length_total - 3,
-                                                   (char *)&mac_sdus[sdu_length_total],
-                                                   0,
-                                                   0);
 
-          LOG_D(MAC, "[gNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", module_idP, sdu_lengths[num_sdus], lcid);
+  lcid = DL_SCH_LCID_DTCH;
 
-          sdu_lcids[num_sdus] = lcid;
-          sdu_length_total += sdu_lengths[num_sdus];
-          header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128);
-          header_length_total += header_length_last;
+  //for (lcid = NB_RB_MAX - 1; lcid >= DTCH; lcid--) {
 
-          num_sdus++;
+  // TODO: check if the lcid is active
 
-          //ue_sched_ctl->uplane_inactivity_timer = 0;
-        }
-      } else { // no TBS_bytes left
-      break;
-      }
-    }
+  LOG_D(MAC, "[gNB %d], Frame %d, DTCH%d->DLSCH, Checking RLC status (TBS %d bytes, len %d)\n",
+      module_idP, frameP, lcid, TBS_bytes, TBS_bytes - ta_len - header_length_total - sdu_length_total - 3);
 
-  } //if (IS_SOFTMODEM_NOS1)
-  else {
+  //if (TBS_bytes - ta_len - header_length_total - sdu_length_total - 3 > 0) {
+  rlc_status = mac_rlc_status_ind(module_idP,
+      rnti,
+      module_idP,
+      frameP,
+      slotP,
+      ENB_FLAG_YES,
+      MBMS_FLAG_NO,
+      lcid,
+      0,
+      0);
+
+  if (rlc_status.bytes_in_buffer > 0) {
+
+    LOG_I(MAC, "configure fapi due to data availability \n");
+
+    LOG_I(MAC, "[gNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting %d bytes from RLC (lcid %d total hdr len %d), TBS_bytes: %d \n \n",
+        module_idP, frameP, TBS_bytes - ta_len - header_length_total - sdu_length_total - 3,
+        lcid, header_length_total, TBS_bytes);
+
+    sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
+        rnti,
+        module_idP,
+        frameP,
+        ENB_FLAG_YES,
+        MBMS_FLAG_NO,
+        lcid,
+        TBS_bytes - ta_len - header_length_total - sdu_length_total - 3,
+        (char *)&mac_sdus[sdu_length_total],
+        0,
+        0);
+
+    LOG_W(MAC, "[gNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n", module_idP, sdu_lengths[num_sdus], lcid);
 
-    //When the --NOS1 option is not enabled, DLSCH transmissions with random data
-    //occur every time that the current function is called (dlsch phytest mode)
+    sdu_lcids[num_sdus] = lcid;
+    sdu_length_total += sdu_lengths[num_sdus];
+    header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128);
+    header_length_total += header_length_last;
+
+    num_sdus++;
+
+    //ue_sched_ctl->uplane_inactivity_timer = 0;
+  }
+
+  else {
 
     LOG_D(MAC,"Configuring DL_TX in %d.%d\n", frameP, slotP);
 
@@ -715,7 +711,7 @@ void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
     }
     #endif
 
-  } // else IS_SOFTMODEM_NOS1
+  }
 
   // there is at least one SDU or TA command
   // if (num_sdus > 0 ){
@@ -758,14 +754,14 @@ void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
         }
       #endif
     } else {
-      #if defined(ENABLE_MAC_PAYLOAD_DEBUG)
+#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
       if (frameP%100 == 0){
         LOG_I(MAC, "Printing first 10 payload bytes at the gNB side, Frame: %d, slot: %d, TBS size: %d \n", frameP, slotP, TBS_bytes);
         for(int i = 0; i < 10; i++) {
-          LOG_I(MAC, "%x. ", ((uint8_t *)gNB_mac->UE_list.DLSCH_pdu[CC_id][0][0].payload[0])[i]); //LOG_I(MAC, "%x. ", mac_payload[i]);
+          LOG_I(MAC, "byte %d : %x\n", i,((uint8_t *)gNB_mac->UE_list.DLSCH_pdu[0][0].payload[0])[i]); //LOG_I(MAC, "%x. ", mac_payload[i]);
         }
       }
-      #endif
+#endif
     }
   }
   else {  // There is no data from RLC or MAC header, so don't schedule
@@ -773,10 +769,42 @@ void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
 
 }
 
+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_schedule_uss_ulsch_phytest(int Mod_idP,
-                                   frame_t       frameP,
-                                   sub_frame_t   slotP) {
+  // 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;
+}
+
+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) {
 
   gNB_MAC_INST                      *nr_mac    = RC.nrmac[Mod_idP];
   NR_COMMON_channels_t                  *cc    = nr_mac->common_channels;
@@ -796,40 +824,11 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
   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;
-  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
-  nfapi_nr_ul_dci_request_t *UL_dci_req = &RC.nrmac[Mod_idP]->UL_dci_req[0];
-
-  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_list->rnti[UE_id];
-  nfapi_nr_ul_dci_request_pdus_t  *ul_dci_request_pdu;
-
-  UL_tti_req->SFN = frameP;
-  UL_tti_req->Slot = slotP;
-  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);
-  nfapi_nr_pusch_pdu_t  *pusch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pusch_pdu;
-  memset(pusch_pdu,0,sizeof(nfapi_nr_pusch_pdu_t));
-  UL_tti_req->n_pdus+=1;  
-
-  LOG_D(MAC, "Scheduling UE specific PUSCH\n");
-  //UL_tti_req = &nr_mac->UL_tti_req[CC_id];
-
-  //Resource Allocation in time domain
-  int startSymbolAndLength=0;
-  int time_domain_assignment=1;
-  int StartSymbolIndex,NrOfSymbols,K2,mapping_type;
 
   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);
-  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;
+  int K2;
   if (ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->k2 != NULL)
    K2 = *ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->k2;
   else {
@@ -838,224 +837,272 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
          else K2=3;
   }
 
-  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;
-  //pusch information always include
-  //this informantion seems to be redundant. with hthe mcs_index and the modulation table, the mod_order and target_code_rate can be determined.
-  pusch_pdu->mcs_index = 9;
-  pusch_pdu->mcs_table = 0; //0: notqam256 [TS38.214, table 5.1.3.1-1] - corresponds to nr_target_code_rate_table1 in PHY
-  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->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;
+  if (is_xlsch_in_slot(UE_list->UE_sched_ctrl[UE_id].ulsch_in_slot_bitmap,(slotP+K2)%num_slots_per_tdd)) {
 
-  pusch_pdu->nrOfLayers = 1;
+    //nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
+    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;
 
-  //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;
-    pusch_pdu->rb_size = 50;
-  }
-  else
-    AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n");
+    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");
 
-  pusch_pdu->vrb_to_prb_mapping = 0;
+    uint16_t rnti = UE_list->rnti[UE_id];
 
-  if (pusch_Config->frequencyHopping==NULL)
-    pusch_pdu->frequency_hopping = 0;
-  else
-    pusch_pdu->frequency_hopping = 1;
+    int first_ul_slot = num_slots_per_tdd - ul_slots;
+    NR_sched_pusch *pusch_sched = &UE_list->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));
 
-  //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;
+    LOG_D(MAC, "Scheduling UE specific PUSCH\n");
+    //UL_tti_req = &nr_mac->UL_tti_req[CC_id];
 
+    //Resource Allocation in time domain
+    int startSymbolAndLength=0;
+    int StartSymbolIndex,NrOfSymbols,mapping_type;
 
-  // --------------------
-  // ------- 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
-  }
+    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 Allocation in frequency domain [TS38.214, sec 6.1.2.2]
-  //Optional Data only included if indicated in pduBitmap
-  // TODO from harq function as in pdsch
-  pusch_pdu->pusch_data.rv_index = 0;
-  pusch_pdu->pusch_data.harq_process_id = 0;
-  pusch_pdu->pusch_data.new_data_indicator = 1;
+    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;
+    //pusch information always include
+    //this informantion seems to be redundant. with hthe mcs_index and the modulation table, the mod_order and target_code_rate can be determined.
+    pusch_pdu->mcs_index = 9;
+    pusch_pdu->mcs_table = 0; //0: notqam256 [TS38.214, table 5.1.3.1-1] - corresponds to nr_target_code_rate_table1 in PHY
+    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->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;
 
-  uint8_t num_dmrs_symb = 0;
+    pusch_pdu->nrOfLayers = 1;
 
-  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);
+    //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 = 50;
+      else
+        pusch_pdu->rb_size = 5;
+    }
+    else
+      AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n");
 
-  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;
-  }
+    pusch_pdu->vrb_to_prb_mapping = 0;
 
-  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;
+    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;
 
-  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
 
+    // --------------------
+    // ------- 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
+    }
 
-  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;
+    // --------------------------------------------------------------------------------------------------------------------------------------------
 
-  int dci_formats[2];
-  int rnti_types[2];
+    //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_list->UE_sched_ctrl[UE_id]);
+    if (harq_id < 0) return;
+    NR_UE_ul_harq_t *cur_harq = &UE_list->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];
 
-  NR_SearchSpace_t *ss;
-  int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+    cur_harq->state = ACTIVE_SCHED;
+    cur_harq->last_tx_slot = pusch_sched->slot;
 
-  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");
+    uint8_t num_dmrs_symb = 0;
 
-  int found=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);
 
-  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;
+    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;
     }
-  }
-  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;
-  LOG_D(MAC,"Configuring ULDCI/PDCCH in %d.%d\n", frameP,slotP);
 
-  int ret = nr_configure_pdcch(nr_mac,
-                               pdcch_pdu_rel15,
-                               UE_list->rnti[UE_id],
-                               1, // ue-specific,
-		               ss,
-		               scc,
-		               bwp);
+    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_list->mac_stats[UE_id].ulsch_rounds[cur_harq->round]++;      
+    if (cur_harq->round == 0) UE_list->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;
+
+    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 (ret < 0) {
-   LOG_I(MAC,"CCE list not empty, couldn't schedule PUSCH\n");
-   UL_tti_req->n_pdus-=1;
-   return;
-  }
-  else {
+    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;
+    LOG_D(MAC,"Configuring ULDCI/PDCCH in %d.%d\n", frameP,slotP);
+
+    int ret = nr_configure_pdcch(nr_mac,
+                                 pdcch_pdu_rel15,
+                                 UE_list->rnti[UE_id],
+                                 1, // ue-specific,
+                                 ss,
+		                 scc,
+		                 bwp);
+
+    if (ret < 0) {
+      LOG_I(MAC,"CCE list not empty, couldn't schedule PUSCH\n");
+      pusch_sched->active = false;
+      return;
+    }
+    else {
       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,n_ubwp,bwp_id);
+      config_uldci(ubwp,pusch_pdu,pdcch_pdu_rel15,&dci_pdu_rel15[0],dci_formats,rnti_types,time_domain_assignment,UE_list->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);
+    }
   }
 }
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index acb239ee39e59ba4ebb98160e55cacf62bd847c3..f4ec142da191a1608c2681b6ca6076a14fd9bb51 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -1465,7 +1465,17 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){
     memset((void *) &UE_list->UE_sched_ctrl[UE_id],
            0,
            sizeof(NR_UE_sched_ctrl_t));
+    UE_list->UE_sched_ctrl[UE_id].ul_rssi = 0;
     UE_list->UE_sched_ctrl[UE_id].sched_pucch = (NR_sched_pucch *)malloc(num_slots_ul*sizeof(NR_sched_pucch));
+    UE_list->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++) {
+      memset((void *) &UE_list->UE_sched_ctrl[UE_id].sched_pucch[k],
+             0,
+             sizeof(NR_sched_pucch));
+      memset((void *) &UE_list->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,
           UE_id,
@@ -1482,6 +1492,18 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){
   return -1;
 }
 
+
+uint8_t nr_get_tpc(int target, uint8_t cqi, int incr) {
+  // al values passed to this function are x10
+
+  int snrx10 = (cqi*5) - 640;
+  if (snrx10 > target + incr) return 0; // decrease 1dB
+  if (snrx10 < target - incr) return 2; // increase 1dB
+  if (snrx10 < target - (3*incr)) return 3; // increase 3dB
+  return 1; // no change
+}
+
+
 void get_pdsch_to_harq_feedback(int Mod_idP,
                                 int UE_id,
                                 NR_SearchSpace__searchSpaceType_PR ss_type,
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
index 89c3fe69fe00c0b7f1cd628374ba28054074d36a..bb0dad7064d5a13b229c99785648b3f751d84910 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
@@ -36,6 +36,7 @@
 
 void nr_process_mac_pdu(
     module_id_t module_idP,
+    rnti_t rnti,
     uint8_t CC_id,
     frame_t frameP,
     uint8_t *pduP,
@@ -210,7 +211,8 @@ void nr_process_mac_pdu(
                 }
 
                 LOG_D(MAC, "[UE %d] Frame %d : ULSCH -> UL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, rx_lcid, module_idP, mac_sdu_len);
-
+		int UE_id = find_nr_UE_id(module_idP, rnti);
+		RC.nrmac[module_idP]->UE_list.mac_stats[UE_id].lc_bytes_rx[rx_lcid] += mac_sdu_len;
                 #if defined(ENABLE_MAC_PAYLOAD_DEBUG)
                     LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP);
 
@@ -219,26 +221,34 @@ void nr_process_mac_pdu(
 
                     LOG_T(MAC, "\n");
                 #endif
-
-                if (IS_SOFTMODEM_NOS1){
-                  if (rx_lcid < NB_RB_MAX && rx_lcid >= UL_SCH_LCID_DTCH) {
-
-                    mac_rlc_data_ind(module_idP,
-                                     0x1234,
-                                     module_idP,
-                                     frameP,
-                                     ENB_FLAG_YES,
-                                     MBMS_FLAG_NO,
-                                     rx_lcid,
-                                     (char *) (pdu_ptr + mac_subheader_len),
-                                     mac_sdu_len,
-                                     1,
-                                     NULL);
-                  } else {
-                    LOG_E(MAC, "[UE %d] Frame %d : unknown LCID %d (gNB %d)\n", module_idP, frameP, rx_lcid, module_idP);
-                  }
+                if(IS_SOFTMODEM_NOS1){
+                  mac_rlc_data_ind(module_idP,
+                      0x1234,
+                      module_idP,
+                      frameP,
+                      ENB_FLAG_YES,
+                      MBMS_FLAG_NO,
+                      rx_lcid,
+                      (char *) (pdu_ptr + mac_subheader_len),
+                      mac_sdu_len,
+                      1,
+                      NULL);
+                }
+                else{
+                  mac_rlc_data_ind(module_idP,
+                      rnti,
+                      module_idP,
+                      frameP,
+                      ENB_FLAG_YES,
+                      MBMS_FLAG_NO,
+                      rx_lcid,
+                      (char *) (pdu_ptr + mac_subheader_len),
+                      mac_sdu_len,
+                      1,
+                      NULL);
                 }
 
+
             break;
 
         default:
@@ -255,6 +265,39 @@ 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) {
+
+  int max_harq_rounds = 4; // TODO define macro
+  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) {
+      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
+    } 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
+    }
+
+    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++;
+    }
+    return;
+  } else
+    LOG_E(MAC,"Incorrect ULSCH HARQ process %d or invalid state %d\n",hrq_id,cur_harq->state);
+}
+
 /*
 * When data are received on PHY and transmitted to MAC
 */
@@ -266,7 +309,8 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
                uint8_t *sduP,
                const uint16_t sdu_lenP,
                const uint16_t timing_advance,
-               const uint8_t ul_cqi){
+               const uint8_t ul_cqi,
+               const uint16_t rssi){
   int current_rnti = 0, UE_id = -1, harq_pid = 0;
   gNB_MAC_INST *gNB_mac = NULL;
   NR_UE_list_t *UE_list = NULL;
@@ -276,10 +320,12 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
   UE_id = find_nr_UE_id(gnb_mod_idP, current_rnti);
   gNB_mac = RC.nrmac[gnb_mod_idP];
   UE_list = &gNB_mac->UE_list;
+  int target_snrx10 = gNB_mac->pusch_target_snrx10;
 
   if (UE_id != -1) {
     UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]);
 
+    UE_list->mac_stats[UE_id].ulsch_total_bytes_rx += sdu_lenP;
     LOG_D(MAC, "[gNB %d][PUSCH %d] CC_id %d %d.%d Received ULSCH sdu from PHY (rnti %x, UE_id %d) ul_cqi %d\n",
           gnb_mod_idP,
           harq_pid,
@@ -290,20 +336,33 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
           UE_id,
           ul_cqi);
 
+    // if not missed detection (10dB threshold for now)
+    if (UE_scheduling_control->ul_rssi < (100+rssi)) {
+      UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10,ul_cqi,30);
+      UE_scheduling_control->ta_update = timing_advance;
+      UE_scheduling_control->ul_rssi = rssi;
+      LOG_D(MAC, "[UE %d] PUSCH TPC %d and TA %d\n",UE_id,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update);
+    }
+    else{
+      UE_scheduling_control->tpc0 = 1;
+    }
+
 #if defined(ENABLE_MAC_PAYLOAD_DEBUG)
-  LOG_I(MAC, "Printing received UL MAC payload at gNB side: %d \n");
-  for (int i = 0; i < sdu_lenP ; i++) {
+    LOG_I(MAC, "Printing received UL MAC payload at gNB side: %d \n");
+    for (int i = 0; i < sdu_lenP ; i++) {
 	  //harq_process_ul_ue->a[i] = (unsigned char) rand();
 	  //printf("a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]);
 	  printf("%02x ",(unsigned char)sduP[i]);
-  }
-  printf("\n");
+    }
+    printf("\n");
 #endif
 
     if (sduP != NULL){
-      UE_scheduling_control->ta_update = timing_advance;
       LOG_D(MAC, "Received PDU at MAC gNB \n");
-      nr_process_mac_pdu(gnb_mod_idP, CC_idP, frameP, sduP, sdu_lenP);
+      nr_process_mac_pdu(gnb_mod_idP, current_rnti, CC_idP, frameP, sduP, sdu_lenP);
+    }
+    else {
+
     }
   }
   else {
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index 74c6841a3a370205726d947e569ffb6ad394be77..7caf1baed57bcf22d32ce286afe90d7ee174c79a 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -50,6 +50,8 @@ void config_common(int Mod_idP,
 int rrc_mac_config_req_gNB(module_id_t Mod_idP, 
 			   int ssb_SubcarrierOffset,
                            int pdsch_AntennaPorts,
+                           int pusch_tgt_snrx10,
+                           int pucch_tgt_snrx10,
                            NR_ServingCellConfigCommon_t *scc,
 			   int nsa_flag,
 			   uint32_t rnti,
@@ -62,7 +64,6 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
                                 sub_frame_t subframeP);
 
 void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
-			       frame_t frame_txP, sub_frame_t slot_txP,
 			       frame_t frame_rxP, sub_frame_t slot_rxP);
 
 int nr_generate_dlsch_pdu(module_id_t Mod_idP,
@@ -137,7 +138,7 @@ void config_uldci(NR_BWP_Uplink_t *ubwp,
                   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,
+                  int time_domain_assignment, uint8_t tpc,
                   int n_ubwp, int bwp_id);
 
 void configure_fapi_dl_Tx(module_id_t Mod_idP,
@@ -154,9 +155,18 @@ void nr_schedule_uss_dlsch_phytest(module_id_t   module_idP,
                                    NR_sched_pucch *pucch_sched,
                                    nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_config);
 
-void nr_schedule_uss_ulsch_phytest(int Mod_idP,
-                                   frame_t       frameP,
-                                   sub_frame_t   slotP);
+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,
+                       frame_t frameP,
+                       sub_frame_t slotP);
 
 void nr_update_pucch_scheduling(int Mod_idP,
                                 int UE_id,
@@ -227,6 +237,8 @@ void find_aggregation_candidates(uint8_t *aggregation_level,
                                  uint8_t *nr_of_candidates,
                                  NR_SearchSpace_t *ss);
 
+uint8_t nr_get_tpc(int target, uint8_t cqi, int incr);
+
 int get_spf(nfapi_nr_config_request_scf_t *cfg);
 
 int to_absslot(nfapi_nr_config_request_scf_t *cfg,int frame,int slot);
@@ -288,9 +300,16 @@ void nr_generate_Msg2(module_id_t module_idP,
 
 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);
 
 void nr_process_mac_pdu(
     module_id_t module_idP,
+    rnti_t rnti,
     uint8_t CC_id,
     frame_t frameP,
     uint8_t *pduP,
@@ -298,6 +317,8 @@ void nr_process_mac_pdu(
 
 int binomial(int n, int k);
 
+bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot);
+
 
 /* \brief Function to indicate a received SDU on ULSCH.
 @param Mod_id Instance ID of gNB
@@ -315,6 +336,11 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
                const rnti_t rntiP,
                uint8_t * sduP,
                const uint16_t sdu_lenP,
-               const uint16_t timing_advance, const uint8_t ul_cqi);
+               const uint16_t timing_advance,
+               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_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 56e020838d267847670fce5b0b9b5b864b439219..bd0be8c4092f070bf6a2c47b8f11c7c89ec4e30f 100644
--- a/openair2/LAYER2/NR_MAC_gNB/main.c
+++ b/openair2/LAYER2/NR_MAC_gNB/main.c
@@ -35,6 +35,7 @@
 #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"
 //#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
@@ -89,7 +90,7 @@ void mac_top_init_gNB(void)
     pdcp_layer_init();
 
     if(IS_SOFTMODEM_NOS1)
-      nr_ip_over_LTE_DRB_preconfiguration();
+      nr_DRB_preconfiguration();
 
     rrc_init_nr_global_param();
 
@@ -117,6 +118,9 @@ void mac_top_init_gNB(void)
         UE_list->UE_sched_ctrl[list_el].harq_processes[list_harq].round = 0;
         UE_list->UE_sched_ctrl[list_el].harq_processes[list_harq].ndi = 0;
         UE_list->UE_sched_ctrl[list_el].harq_processes[list_harq].is_waiting = 0;
+        UE_list->UE_sched_ctrl[list_el].ul_harq_processes[list_harq].round = 0;
+        UE_list->UE_sched_ctrl[list_el].ul_harq_processes[list_harq].ndi = 0;
+        UE_list->UE_sched_ctrl[list_el].ul_harq_processes[list_harq].state = 0;
       }
     }
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index f84e7a900c95eeb53e485dcf39dcc33d465f696b..bd8f0208c6561f1c3c93f04d6715909aa3613df8 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -251,8 +251,16 @@ typedef struct NR_sched_pucch {
   uint8_t dai_c;
   uint8_t timing_indicator;
   uint8_t resource_indicator;
+  bool active;
 } NR_sched_pucch;
 
+typedef struct NR_sched_pusch {
+  int frame;
+  int slot;
+  bool active;
+  nfapi_nr_pusch_pdu_t pusch_pdu;
+} NR_sched_pusch;
+
 typedef struct NR_UE_harq {
   uint8_t is_waiting;
   uint8_t ndi;
@@ -260,15 +268,33 @@ typedef struct NR_UE_harq {
   uint16_t feedback_slot;
 } NR_UE_harq_t;
 
+typedef enum {
+  INACTIVE = 0,
+  ACTIVE_NOT_SCHED,
+  ACTIVE_SCHED
+} NR_UL_harq_states_t;
+
+typedef struct NR_UE_ul_harq {
+  uint8_t ndi;
+  uint8_t round;
+  uint16_t last_tx_slot;
+  NR_UL_harq_states_t state;
+} NR_UE_ul_harq_t;
+
 /*! \brief scheduling control information set through an API */
 typedef struct {
   uint64_t dlsch_in_slot_bitmap;  // static bitmap signaling which slot in a tdd period contains dlsch
   uint64_t ulsch_in_slot_bitmap;  // static bitmap signaling which slot in a tdd period contains ulsch
   NR_sched_pucch *sched_pucch;
+  NR_sched_pusch *sched_pusch;
   uint16_t ta_timer;
   int16_t ta_update;
+  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;
   NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl;// MAC CE related information
 } NR_UE_sched_ctrl_t;
@@ -278,11 +304,25 @@ typedef struct NR_preamble_ue {
   uint8_t *preamble_list;
 } NR_preamble_ue;
 
+typedef struct {
+
+  int lc_bytes_tx[64];
+  int lc_bytes_rx[64];
+  int dlsch_rounds[8];
+  int dlsch_errors;
+  int dlsch_total_bytes;
+  int ulsch_rounds[8];
+  int ulsch_errors;
+  int ulsch_total_bytes_scheduled;
+  int ulsch_total_bytes_rx;
+} NR_mac_stats_t;
+
 /*! \brief UE list used by gNB to order UEs/CC for scheduling*/
 typedef struct {
   DLSCH_PDU DLSCH_pdu[4][MAX_MOBILES_PER_GNB];
   /// scheduling control info
   NR_UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB];
+  NR_mac_stats_t mac_stats[MAX_MOBILES_PER_GNB];
   int next[MAX_MOBILES_PER_GNB];
   int head;
   int next_ul[MAX_MOBILES_PER_GNB];
@@ -305,14 +345,14 @@ typedef struct gNB_MAC_INST_s {
   eth_params_t                    eth_params_s;
   /// Module
   module_id_t                     Mod_id;
-  /// frame counter
-  frame_t                         frame;
-  /// slot counter
-  int                             slot;
   /// timing advance group
   NR_TAG_t                        *tag;
   /// Pointer to IF module instance for PHY
   NR_IF_Module_t                  *if_inst;
+  /// Pusch target SNR
+  int                             pusch_target_snrx10;
+  /// Pucch target SNR
+  int                             pucch_target_snrx10;
   /// TA command
   int                             ta_command;
   /// MAC CE flag indicating TA length
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
index 3667af26984326071cc20b7d33fd55c3cc4b5ae7..33f268f07fbb25fadc232e1843de855d95644707 100644
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
@@ -2353,101 +2353,6 @@ void pdcp_module_cleanup (void)
 {
 }
 
-void nr_ip_over_LTE_DRB_preconfiguration(void){
-
-	  // Addition for the use-case of 4G stack on top of 5G-NR.
-	  // We need to configure pdcp and rlc instances without having an actual
-	  // UE RRC Connection. In order to be able to test the NR PHY with some injected traffic
-	  // on top of the LTE stack.
-	  protocol_ctxt_t ctxt;
-	  LTE_DRB_ToAddModList_t*                DRB_configList=NULL;
-	  DRB_configList = CALLOC(1, sizeof(LTE_DRB_ToAddModList_t));
-	  struct LTE_LogicalChannelConfig        *DRB_lchan_config                                 = NULL;
-	  struct LTE_RLC_Config                  *DRB_rlc_config                   = NULL;
-	  struct LTE_PDCP_Config                 *DRB_pdcp_config                  = NULL;
-	  struct LTE_PDCP_Config__rlc_UM         *PDCP_rlc_UM                      = NULL;
-
-	  struct LTE_DRB_ToAddMod                *DRB_config                       = NULL;
-	  struct LTE_LogicalChannelConfig__ul_SpecificParameters *DRB_ul_SpecificParameters        = NULL;
-	  long  *logicalchannelgroup_drb;
-
-
-	  //Static preconfiguration of DRB
-	  DRB_config = CALLOC(1, sizeof(*DRB_config));
-
-	  DRB_config->eps_BearerIdentity = CALLOC(1, sizeof(long));
-	  // allowed value 5..15, value : x+4
-	  *(DRB_config->eps_BearerIdentity) = 1; //ue_context_pP->ue_context.e_rab[i].param.e_rab_id;//+ 4; // especial case generation
-	  //   DRB_config->drb_Identity =  1 + drb_identity_index + e_rab_done;// + i ;// (DRB_Identity_t) ue_context_pP->ue_context.e_rab[i].param.e_rab_id;
-	  // 1 + drb_identiy_index;
-	  DRB_config->drb_Identity = 1;
-	  DRB_config->logicalChannelIdentity = CALLOC(1, sizeof(long));
-	  *(DRB_config->logicalChannelIdentity) = DRB_config->drb_Identity + 3; //(long) (ue_context_pP->ue_context.e_rab[i].param.e_rab_id + 2); // value : x+2
-
-	  DRB_rlc_config = CALLOC(1, sizeof(*DRB_rlc_config));
-	  DRB_config->rlc_Config = DRB_rlc_config;
-
-	  DRB_pdcp_config = CALLOC(1, sizeof(*DRB_pdcp_config));
-	  DRB_config->pdcp_Config = DRB_pdcp_config;
-	  DRB_pdcp_config->discardTimer = CALLOC(1, sizeof(long));
-	  *DRB_pdcp_config->discardTimer = LTE_PDCP_Config__discardTimer_infinity;
-	  DRB_pdcp_config->rlc_AM = NULL;
-	  DRB_pdcp_config->rlc_UM = NULL;
-
-	  DRB_rlc_config->present = LTE_RLC_Config_PR_um_Bi_Directional;
-	  DRB_rlc_config->choice.um_Bi_Directional.ul_UM_RLC.sn_FieldLength = LTE_SN_FieldLength_size10;
-	  DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.sn_FieldLength = LTE_SN_FieldLength_size10;
-	  DRB_rlc_config->choice.um_Bi_Directional.dl_UM_RLC.t_Reordering = LTE_T_Reordering_ms35;
-	  // PDCP
-	  PDCP_rlc_UM = CALLOC(1, sizeof(*PDCP_rlc_UM));
-	  DRB_pdcp_config->rlc_UM = PDCP_rlc_UM;
-	  PDCP_rlc_UM->pdcp_SN_Size = LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits;
-
-	  DRB_pdcp_config->headerCompression.present = LTE_PDCP_Config__headerCompression_PR_notUsed;
-
-	  DRB_lchan_config = CALLOC(1, sizeof(*DRB_lchan_config));
-	  DRB_config->logicalChannelConfig = DRB_lchan_config;
-	  DRB_ul_SpecificParameters = CALLOC(1, sizeof(*DRB_ul_SpecificParameters));
-	  DRB_lchan_config->ul_SpecificParameters = DRB_ul_SpecificParameters;
-
-	  DRB_ul_SpecificParameters->priority= 4;
-
-	  DRB_ul_SpecificParameters->prioritisedBitRate = LTE_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_kBps8;
-	  //LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
-	  DRB_ul_SpecificParameters->bucketSizeDuration =
-	  LTE_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
-
-	  logicalchannelgroup_drb = CALLOC(1, sizeof(long));
-	  *logicalchannelgroup_drb = 1;//(i+1) % 3;
-	  DRB_ul_SpecificParameters->logicalChannelGroup = logicalchannelgroup_drb;
-
-	  ASN_SEQUENCE_ADD(&DRB_configList->list,DRB_config);
-
-	  if (ENB_NAS_USE_TUN){
-		  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_YES, 0x1234, 0, 0,0);
-	  }
-	  else{
-		  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_NO, 0x1234, 0, 0,0);
-	  }
-
-	  rrc_pdcp_config_asn1_req(&ctxt,
-	               (LTE_SRB_ToAddModList_t *) NULL,
-	               DRB_configList,
-	               (LTE_DRB_ToReleaseList_t *) NULL,
-	               0xff, NULL, NULL, NULL
-	               , (LTE_PMCH_InfoList_r9_t *) NULL,
-	               &DRB_config->drb_Identity);
-
-	rrc_rlc_config_asn1_req(&ctxt,
-	               (LTE_SRB_ToAddModList_t*)NULL,
-	               DRB_configList,
-	               (LTE_DRB_ToReleaseList_t*)NULL
-	//#if (RRC_VERSION >= MAKE_VERSION(10, 0, 0))
-	               ,(LTE_PMCH_InfoList_r9_t *)NULL
-	               , 0, 0
-	//#endif
-	         );
-}
 //-----------------------------------------------------------------------------
 void pdcp_layer_init(void)
 //-----------------------------------------------------------------------------
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
new file mode 100644
index 0000000000000000000000000000000000000000..e25201c22c4b4d0ba71df92c9994fcee8bd9370c
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
@@ -0,0 +1,74 @@
+/*
+ * 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 "nr_pdcp_entity.h"
+
+#include "nr_pdcp_entity_drb_am.h"
+
+#include "LOG/log.h"
+
+nr_pdcp_entity_t *new_nr_pdcp_entity_srb(
+    int rb_id,
+    void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
+                        char *buf, int size),
+    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)
+{
+  abort();
+}
+
+nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
+    int rb_id,
+    void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
+                        char *buf, int size),
+    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)
+{
+  nr_pdcp_entity_drb_am_t *ret;
+
+  ret = calloc(1, sizeof(nr_pdcp_entity_drb_am_t));
+  if (ret == NULL) {
+    LOG_E(PDCP, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  ret->common.recv_pdu          = nr_pdcp_entity_drb_am_recv_pdu;
+  ret->common.recv_sdu          = nr_pdcp_entity_drb_am_recv_sdu;
+  ret->common.set_integrity_key = nr_pdcp_entity_drb_am_set_integrity_key;
+
+  ret->common.delete = nr_pdcp_entity_drb_am_delete;
+
+  ret->common.deliver_sdu = deliver_sdu;
+  ret->common.deliver_sdu_data = deliver_sdu_data;
+
+  ret->common.deliver_pdu = deliver_pdu;
+  ret->common.deliver_pdu_data = deliver_pdu_data;
+
+  ret->rb_id = rb_id;
+
+  ret->common.maximum_nr_pdcp_sn = 4095;
+
+  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
new file mode 100644
index 0000000000000000000000000000000000000000..45555ad6af9374dc2a8c5138bc09f10e12311a1a
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
@@ -0,0 +1,65 @@
+/*
+ * 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 _NR_PDCP_ENTITY_H_
+#define _NR_PDCP_ENTITY_H_
+
+typedef struct nr_pdcp_entity_t {
+  /* functions provided by the PDCP module */
+  void (*recv_pdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size);
+  void (*recv_sdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size,
+                   int sdu_id);
+  void (*delete)(struct nr_pdcp_entity_t *entity);
+  void (*set_integrity_key)(struct nr_pdcp_entity_t *entity, char *key);
+
+  /* callbacks provided to the PDCP module */
+  void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
+                      char *buf, int size);
+  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;
+  int tx_hfn;
+  int next_nr_pdcp_tx_sn;
+  int maximum_nr_pdcp_sn;
+} nr_pdcp_entity_t;
+
+nr_pdcp_entity_t *new_nr_pdcp_entity_srb(
+    int rb_id,
+    void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
+                        char *buf, int size),
+    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);
+
+nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
+    int rb_id,
+    void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
+                        char *buf, int size),
+    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 nr_DRB_preconfiguration(void);
+
+#endif /* _NR_PDCP_ENTITY_H_ */
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c
new file mode 100644
index 0000000000000000000000000000000000000000..85f638d66d9b5b87a2795ea5861013cf577e408c
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c
@@ -0,0 +1,71 @@
+/*
+ * 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 "nr_pdcp_entity_drb_am.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void nr_pdcp_entity_drb_am_recv_pdu(nr_pdcp_entity_t *_entity, char *buffer, int size)
+{
+  nr_pdcp_entity_drb_am_t *entity = (nr_pdcp_entity_drb_am_t *)_entity;
+
+  if (size < 3) abort();
+  if (!(buffer[0] & 0x80)) { printf("%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); exit(1); }
+  entity->common.deliver_sdu(entity->common.deliver_sdu_data,
+                             (nr_pdcp_entity_t *)entity, buffer+3, size-3);
+}
+
+void nr_pdcp_entity_drb_am_recv_sdu(nr_pdcp_entity_t *_entity, char *buffer, int size,
+                              int sdu_id)
+{
+  nr_pdcp_entity_drb_am_t *entity = (nr_pdcp_entity_drb_am_t *)_entity;
+  int sn;
+  char buf[size+2];
+
+  sn = entity->common.next_nr_pdcp_tx_sn;
+
+  entity->common.next_nr_pdcp_tx_sn++;
+  if (entity->common.next_nr_pdcp_tx_sn > entity->common.maximum_nr_pdcp_sn) {
+    entity->common.next_nr_pdcp_tx_sn = 0;
+    entity->common.tx_hfn++;
+  }
+
+  buf[0] = 0x80 | ((sn >> 16) & 0x3);
+  buf[1] = (sn >> 8) & 0xff;
+  buf[2] = sn & 0xff;
+  memcpy(buf+3, buffer, size);
+
+  entity->common.deliver_pdu(entity->common.deliver_pdu_data,
+                             (nr_pdcp_entity_t *)entity, buf, size+3, sdu_id);
+}
+
+void nr_pdcp_entity_drb_am_set_integrity_key(nr_pdcp_entity_t *_entity, char *key)
+{
+  /* nothing to do */
+}
+
+void nr_pdcp_entity_drb_am_delete(nr_pdcp_entity_t *_entity)
+{
+  nr_pdcp_entity_drb_am_t *entity = (nr_pdcp_entity_drb_am_t *)_entity;
+  free(entity);
+}
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h
new file mode 100644
index 0000000000000000000000000000000000000000..faa8226e93b64ad3b0333254f60de646494e16ed
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h
@@ -0,0 +1,38 @@
+/*
+ * 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 _NR_PDCP_ENTITY_DRB_AM_H_
+#define _NR_PDCP_ENTITY_DRB_AM_H_
+
+#include "nr_pdcp_entity.h"
+
+typedef struct {
+  nr_pdcp_entity_t common;
+  int rb_id;
+} nr_pdcp_entity_drb_am_t;
+
+void nr_pdcp_entity_drb_am_recv_pdu(nr_pdcp_entity_t *entity, char *buffer, int size);
+void nr_pdcp_entity_drb_am_recv_sdu(nr_pdcp_entity_t *entity, char *buffer, int size,
+                                    int sdu_id);
+void nr_pdcp_entity_drb_am_set_integrity_key(nr_pdcp_entity_t *entity, char *key);
+void nr_pdcp_entity_drb_am_delete(nr_pdcp_entity_t *entity);
+
+#endif /* _NR_PDCP_ENTITY_DRB_AM_H_ */
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
new file mode 100644
index 0000000000000000000000000000000000000000..c8b385bbfcdcf5ea755287d69ea68e1b33b3013e
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
@@ -0,0 +1,946 @@
+/*
+ * 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 "nr_pdcp_ue_manager.h"
+#include "NR_RadioBearerConfig.h"
+#include "NR_RLC-BearerConfig.h"
+#include "NR_CellGroupConfig.h"
+#include "openair2/RRC/NR/nr_rrc_proto.h"
+
+/* from OAI */
+#include "pdcp.h"
+
+#define TODO do { \
+    printf("%s:%d:%s: todo\n", __FILE__, __LINE__, __FUNCTION__); \
+    exit(1); \
+  } while (0)
+
+static nr_pdcp_ue_manager_t *nr_pdcp_ue_manager;
+
+/* necessary globals for OAI, not used internally */
+hash_table_t  *pdcp_coll_p;
+static uint64_t pdcp_optmask;
+
+/****************************************************************************/
+/* rlc_data_req queue - begin                                               */
+/****************************************************************************/
+
+#include <pthread.h>
+
+/* NR PDCP and RLC both use "big locks". In some cases a thread may do
+ * lock(rlc) followed by lock(pdcp) (typically when running 'rx_sdu').
+ * Another thread may first do lock(pdcp) and then lock(rlc) (typically
+ * the GTP module calls 'pdcp_data_req' that, in a previous implementation
+ * was indirectly calling 'rlc_data_req' which does lock(rlc)).
+ * To avoid the resulting deadlock it is enough to ensure that a call
+ * to lock(pdcp) will never be followed by a call to lock(rlc). So,
+ * here we chose to have a separate thread that deals with rlc_data_req,
+ * out of the PDCP lock. Other solutions may be possible.
+ * So instead of calling 'rlc_data_req' directly we have a queue and a
+ * separate thread emptying it.
+ */
+
+typedef struct {
+  protocol_ctxt_t ctxt_pP;
+  srb_flag_t      srb_flagP;
+  MBMS_flag_t     MBMS_flagP;
+  rb_id_t         rb_idP;
+  mui_t           muiP;
+  confirm_t       confirmP;
+  sdu_size_t      sdu_sizeP;
+  mem_block_t     *sdu_pP;
+} rlc_data_req_queue_item;
+
+#define RLC_DATA_REQ_QUEUE_SIZE 10000
+
+typedef struct {
+  rlc_data_req_queue_item q[RLC_DATA_REQ_QUEUE_SIZE];
+  volatile int start;
+  volatile int length;
+  pthread_mutex_t m;
+  pthread_cond_t c;
+} rlc_data_req_queue;
+
+static rlc_data_req_queue q;
+
+extern rlc_op_status_t nr_rrc_rlc_config_asn1_req (const protocol_ctxt_t   * const ctxt_pP,
+    const NR_SRB_ToAddModList_t   * const srb2add_listP,
+    const NR_DRB_ToAddModList_t   * const drb2add_listP,
+    const NR_DRB_ToReleaseList_t  * const drb2release_listP,
+    const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP,
+    struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list);
+
+static void *rlc_data_req_thread(void *_)
+{
+  int i;
+
+  while (1) {
+    if (pthread_mutex_lock(&q.m) != 0) abort();
+    while (q.length == 0)
+      if (pthread_cond_wait(&q.c, &q.m) != 0) abort();
+    i = q.start;
+    if (pthread_mutex_unlock(&q.m) != 0) abort();
+
+    rlc_data_req(&q.q[i].ctxt_pP,
+                 q.q[i].srb_flagP,
+                 q.q[i].MBMS_flagP,
+                 q.q[i].rb_idP,
+                 q.q[i].muiP,
+                 q.q[i].confirmP,
+                 q.q[i].sdu_sizeP,
+                 q.q[i].sdu_pP,
+                 NULL,
+                 NULL);
+
+    if (pthread_mutex_lock(&q.m) != 0) abort();
+
+    q.length--;
+    q.start = (q.start + 1) % RLC_DATA_REQ_QUEUE_SIZE;
+
+    if (pthread_cond_signal(&q.c) != 0) abort();
+    if (pthread_mutex_unlock(&q.m) != 0) abort();
+  }
+}
+
+static void init_nr_rlc_data_req_queue(void)
+{
+  pthread_t t;
+
+  pthread_mutex_init(&q.m, NULL);
+  pthread_cond_init(&q.c, NULL);
+
+  if (pthread_create(&t, NULL, rlc_data_req_thread, NULL) != 0) {
+    LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+}
+
+static void enqueue_rlc_data_req(const protocol_ctxt_t *const ctxt_pP,
+                                 const srb_flag_t   srb_flagP,
+                                 const MBMS_flag_t  MBMS_flagP,
+                                 const rb_id_t      rb_idP,
+                                 const mui_t        muiP,
+                                 confirm_t    confirmP,
+                                 sdu_size_t   sdu_sizeP,
+                                 mem_block_t *sdu_pP,
+                                 void *_unused1, void *_unused2)
+{
+  int i;
+  int logged = 0;
+
+  if (pthread_mutex_lock(&q.m) != 0) abort();
+  while (q.length == RLC_DATA_REQ_QUEUE_SIZE) {
+    if (!logged) {
+      logged = 1;
+      LOG_W(PDCP, "%s: rlc_data_req queue is full\n", __FUNCTION__);
+    }
+    if (pthread_cond_wait(&q.c, &q.m) != 0) abort();
+  }
+
+  i = (q.start + q.length) % RLC_DATA_REQ_QUEUE_SIZE;
+  q.length++;
+
+  q.q[i].ctxt_pP    = *ctxt_pP;
+  q.q[i].srb_flagP  = srb_flagP;
+  q.q[i].MBMS_flagP = MBMS_flagP;
+  q.q[i].rb_idP     = rb_idP;
+  q.q[i].muiP       = muiP;
+  q.q[i].confirmP   = confirmP;
+  q.q[i].sdu_sizeP  = sdu_sizeP;
+  q.q[i].sdu_pP     = sdu_pP;
+
+  if (pthread_cond_signal(&q.c) != 0) abort();
+  if (pthread_mutex_unlock(&q.m) != 0) abort();
+}
+
+/****************************************************************************/
+/* rlc_data_req queue - end                                                 */
+/****************************************************************************/
+
+/****************************************************************************/
+/* hacks to be cleaned up at some point - begin                             */
+/****************************************************************************/
+
+#include "LAYER2/MAC/mac_extern.h"
+
+static void reblock_tun_socket(void)
+{
+  extern int nas_sock_fd[];
+  int f;
+
+  f = fcntl(nas_sock_fd[0], F_GETFL, 0);
+  f &= ~(O_NONBLOCK);
+  if (fcntl(nas_sock_fd[0], F_SETFL, f) == -1) {
+    LOG_E(PDCP, "reblock_tun_socket failed\n");
+    exit(1);
+  }
+}
+
+static void *enb_tun_read_thread(void *_)
+{
+  extern int nas_sock_fd[];
+  char rx_buf[NL_MAX_PAYLOAD];
+  int len;
+  int rnti;
+  protocol_ctxt_t ctxt;
+
+  int rb_id = 1;
+
+  while (1) {
+    len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD);
+    if (len == -1) {
+      LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+      exit(1);
+    }
+
+printf("\n\n\n########## nas_sock_fd read returns len %d\n", len);
+
+    nr_pdcp_manager_lock(nr_pdcp_ue_manager);
+    rnti = nr_pdcp_get_first_rnti(nr_pdcp_ue_manager);
+    nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
+
+    if (rnti == -1) continue;
+
+    ctxt.module_id = 0;
+    ctxt.enb_flag = 1;
+    ctxt.instance = 0;
+    ctxt.frame = 0;
+    ctxt.subframe = 0;
+    ctxt.eNB_index = 0;
+    ctxt.configured = 1;
+    ctxt.brOption = 0;
+
+    ctxt.rnti = rnti;
+
+    pdcp_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED,
+                  RLC_SDU_CONFIRM_NO, len, (unsigned char *)rx_buf,
+                  PDCP_TRANSMISSION_MODE_DATA, NULL, NULL);
+  }
+
+  return NULL;
+}
+
+static void *ue_tun_read_thread(void *_)
+{
+  extern int nas_sock_fd[];
+  char rx_buf[NL_MAX_PAYLOAD];
+  int len;
+  int rnti;
+  protocol_ctxt_t ctxt;
+
+  int rb_id = 1;
+
+  while (1) {
+    len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD);
+    if (len == -1) {
+      LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+      exit(1);
+    }
+
+printf("\n\n\n########## nas_sock_fd read returns len %d\n", len);
+
+    nr_pdcp_manager_lock(nr_pdcp_ue_manager);
+    rnti = nr_pdcp_get_first_rnti(nr_pdcp_ue_manager);
+    nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
+
+    if (rnti == -1) continue;
+
+    ctxt.module_id = 0;
+    ctxt.enb_flag = 0;
+    ctxt.instance = 0;
+    ctxt.frame = 0;
+    ctxt.subframe = 0;
+    ctxt.eNB_index = 0;
+    ctxt.configured = 1;
+    ctxt.brOption = 0;
+
+    ctxt.rnti = rnti;
+
+    pdcp_data_req(&ctxt, SRB_FLAG_NO, rb_id, RLC_MUI_UNDEFINED,
+                  RLC_SDU_CONFIRM_NO, len, (unsigned char *)rx_buf,
+                  PDCP_TRANSMISSION_MODE_DATA, NULL, NULL);
+  }
+
+  return NULL;
+}
+
+static void start_pdcp_tun_enb(void)
+{
+  pthread_t t;
+
+  reblock_tun_socket();
+
+  if (pthread_create(&t, NULL, enb_tun_read_thread, NULL) != 0) {
+    LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+}
+
+static void start_pdcp_tun_ue(void)
+{
+  pthread_t t;
+
+  reblock_tun_socket();
+
+  if (pthread_create(&t, NULL, ue_tun_read_thread, NULL) != 0) {
+    LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+}
+
+/****************************************************************************/
+/* hacks to be cleaned up at some point - end                               */
+/****************************************************************************/
+
+int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP)
+{
+  return 0;
+}
+
+void pdcp_layer_init(void)
+{
+  /* hack: be sure to initialize only once */
+  static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+  static int initialized = 0;
+  if (pthread_mutex_lock(&m) != 0) abort();
+  if (initialized) {
+    if (pthread_mutex_unlock(&m) != 0) abort();
+    return;
+  }
+  initialized = 1;
+  if (pthread_mutex_unlock(&m) != 0) abort();
+
+  nr_pdcp_ue_manager = new_nr_pdcp_ue_manager(1);
+  init_nr_rlc_data_req_queue();
+}
+
+#include "nfapi/oai_integration/vendor_ext.h"
+#include "targets/RT/USER/lte-softmodem.h"
+#include "openair2/RRC/NAS/nas_config.h"
+
+uint64_t pdcp_module_init(uint64_t _pdcp_optmask)
+{
+  /* hack: be sure to initialize only once */
+  static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+  static int initialized = 0;
+  if (pthread_mutex_lock(&m) != 0) abort();
+  if (initialized) {
+    abort();
+  }
+  initialized = 1;
+  if (pthread_mutex_unlock(&m) != 0) abort();
+
+#if 0
+  pdcp_optmask = _pdcp_optmask;
+  return pdcp_optmask;
+#endif
+  /* temporary enforce netlink when UE_NAS_USE_TUN is set,
+     this is while switching from noS1 as build option
+     to noS1 as config option                               */
+  if ( _pdcp_optmask & UE_NAS_USE_TUN_BIT) {
+    pdcp_optmask = pdcp_optmask | PDCP_USE_NETLINK_BIT ;
+  }
+
+  pdcp_optmask = pdcp_optmask | _pdcp_optmask ;
+  LOG_I(PDCP, "pdcp init,%s %s\n",
+        ((LINK_ENB_PDCP_TO_GTPV1U)?"usegtp":""),
+        ((PDCP_USE_NETLINK)?"usenetlink":""));
+
+  if (PDCP_USE_NETLINK) {
+    nas_getparams();
+
+    if(UE_NAS_USE_TUN) {
+      int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 )?MAX_NUMBER_NETIF:1;
+      netlink_init_tun("ue",num_if);
+      //Add --nr-ip-over-lte option check for next line
+      if (IS_SOFTMODEM_NOS1)
+          nas_config(1, 1, 2, "ue");
+      LOG_I(PDCP, "UE pdcp will use tun interface\n");
+      start_pdcp_tun_ue();
+    } else if(ENB_NAS_USE_TUN) {
+      netlink_init_tun("enb",1);
+      nas_config(1, 1, 1, "enb");
+      LOG_I(PDCP, "ENB pdcp will use tun interface\n");
+      start_pdcp_tun_enb();
+    } else {
+      LOG_I(PDCP, "pdcp will use kernel modules\n");
+      abort();
+      netlink_init();
+    }
+  }
+  return pdcp_optmask ;
+}
+
+static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
+                            char *buf, int size)
+{
+  extern int nas_sock_fd[];
+  int len;
+  nr_pdcp_ue_t *ue = _ue;
+  MessageDef  *message_p;
+  uint8_t     *gtpu_buffer_p;
+  int rb_id;
+  int i;
+
+  if(IS_SOFTMODEM_NOS1){
+    len = write(nas_sock_fd[0], buf, size);
+    if (len != size) {
+      LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+      exit(1);
+    }
+  }
+  else{
+    for (i = 0; i < 5; i++) {
+        if (entity == ue->drb[i]) {
+          rb_id = i+1;
+          goto rb_found;
+        }
+      }
+
+      LOG_E(PDCP, "%s:%d:%s: fatal, no RB found for ue %d\n",
+            __FILE__, __LINE__, __FUNCTION__, ue->rnti);
+      exit(1);
+
+    rb_found:
+      gtpu_buffer_p = itti_malloc(TASK_PDCP_ENB, TASK_GTPV1_U,
+                                  size + GTPU_HEADER_OVERHEAD_MAX);
+      AssertFatal(gtpu_buffer_p != NULL, "OUT OF MEMORY");
+      memcpy(&gtpu_buffer_p[GTPU_HEADER_OVERHEAD_MAX], buf, size);
+      message_p = itti_alloc_new_message(TASK_PDCP_ENB, GTPV1U_ENB_TUNNEL_DATA_REQ);
+      AssertFatal(message_p != NULL, "OUT OF MEMORY");
+      GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).buffer       = gtpu_buffer_p;
+      GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).length       = size;
+      GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).offset       = GTPU_HEADER_OVERHEAD_MAX;
+      GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rnti         = ue->rnti;
+      GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rab_id       = rb_id + 4;
+    printf("!!!!!!! deliver_sdu_drb (drb %d) sending message to gtp size %d: ", rb_id, size);
+    //for (i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]);
+    printf("\n");
+      itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p);
+
+  }
+}
+
+static void deliver_pdu_drb(void *_ue, nr_pdcp_entity_t *entity,
+                            char *buf, int size, int sdu_id)
+{
+  nr_pdcp_ue_t *ue = _ue;
+  int rb_id;
+  protocol_ctxt_t ctxt;
+  int i;
+  mem_block_t *memblock;
+
+  for (i = 0; i < 5; i++) {
+    if (entity == ue->drb[i]) {
+      rb_id = i+1;
+      goto rb_found;
+    }
+  }
+
+  LOG_E(PDCP, "%s:%d:%s: fatal, no RB found for ue %d\n",
+        __FILE__, __LINE__, __FUNCTION__, ue->rnti);
+  exit(1);
+
+rb_found:
+  ctxt.module_id = 0;
+  ctxt.enb_flag = 1;
+  ctxt.instance = 0;
+  ctxt.frame = 0;
+  ctxt.subframe = 0;
+  ctxt.eNB_index = 0;
+  ctxt.configured = 1;
+  ctxt.brOption = 0;
+
+  ctxt.rnti = ue->rnti;
+
+  memblock = get_free_mem_block(size, __FUNCTION__);
+  memcpy(memblock->data, buf, size);
+
+printf("!!!!!!! deliver_pdu_drb (srb %d) calling rlc_data_req size %d: ", rb_id, size);
+//for (i = 0; i < size; i++) printf(" %2.2x", (unsigned char)memblock->data[i]);
+printf("\n");
+  enqueue_rlc_data_req(&ctxt, 0, MBMS_FLAG_NO, rb_id, sdu_id, 0, size, memblock, NULL, NULL);
+}
+
+boolean_t pdcp_data_ind(
+  const protocol_ctxt_t *const  ctxt_pP,
+  const srb_flag_t srb_flagP,
+  const MBMS_flag_t MBMS_flagP,
+  const rb_id_t rb_id,
+  const sdu_size_t sdu_buffer_size,
+  mem_block_t *const sdu_buffer)
+{
+  nr_pdcp_ue_t *ue;
+  nr_pdcp_entity_t *rb;
+  int rnti = ctxt_pP->rnti;
+
+  if (ctxt_pP->module_id != 0 ||
+      //ctxt_pP->enb_flag != 1 ||
+      ctxt_pP->instance != 0 ||
+      ctxt_pP->eNB_index != 0 ||
+      ctxt_pP->configured != 1 ||
+      ctxt_pP->brOption != 0) {
+    LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  if (ctxt_pP->enb_flag)
+    T(T_ENB_PDCP_UL, T_INT(ctxt_pP->module_id), T_INT(rnti),
+      T_INT(rb_id), T_INT(sdu_buffer_size));
+
+  nr_pdcp_manager_lock(nr_pdcp_ue_manager);
+  ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, rnti);
+
+  if (srb_flagP == 1) {
+    if (rb_id < 1 || rb_id > 2)
+      rb = NULL;
+    else
+      rb = ue->srb[rb_id - 1];
+  } else {
+    if (rb_id < 1 || rb_id > 5)
+      rb = NULL;
+    else
+      rb = ue->drb[rb_id - 1];
+  }
+
+  if (rb != NULL) {
+    rb->recv_pdu(rb, (char *)sdu_buffer->data, sdu_buffer_size);
+  } else {
+    LOG_E(PDCP, "%s:%d:%s: fatal: no RB found (rb_id %ld, srb_flag %d)\n",
+          __FILE__, __LINE__, __FUNCTION__, rb_id, srb_flagP);
+    exit(1);
+  }
+
+  nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
+
+  free_mem_block(sdu_buffer, __FUNCTION__);
+
+  return 1;
+}
+
+void pdcp_run(const protocol_ctxt_t *const  ctxt_pP)
+{
+  MessageDef      *msg_p;
+  int             result;
+  protocol_ctxt_t ctxt;
+
+  while (1) {
+    itti_poll_msg(ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, &msg_p);
+    if (msg_p == NULL)
+      break;
+    switch (ITTI_MSG_ID(msg_p)) {
+    case RRC_DCCH_DATA_REQ:
+      PROTOCOL_CTXT_SET_BY_MODULE_ID(
+          &ctxt,
+          RRC_DCCH_DATA_REQ(msg_p).module_id,
+          RRC_DCCH_DATA_REQ(msg_p).enb_flag,
+          RRC_DCCH_DATA_REQ(msg_p).rnti,
+          RRC_DCCH_DATA_REQ(msg_p).frame,
+          0,
+          RRC_DCCH_DATA_REQ(msg_p).eNB_index);
+      result = pdcp_data_req(&ctxt,
+                             SRB_FLAG_YES,
+                             RRC_DCCH_DATA_REQ(msg_p).rb_id,
+                             RRC_DCCH_DATA_REQ(msg_p).muip,
+                             RRC_DCCH_DATA_REQ(msg_p).confirmp,
+                             RRC_DCCH_DATA_REQ(msg_p).sdu_size,
+                             RRC_DCCH_DATA_REQ(msg_p).sdu_p,
+                             RRC_DCCH_DATA_REQ(msg_p).mode,
+                             NULL, NULL);
+
+      if (result != TRUE)
+        LOG_E(PDCP, "PDCP data request failed!\n");
+      result = itti_free(ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_REQ(msg_p).sdu_p);
+      AssertFatal(result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+      break;
+    default:
+      LOG_E(PDCP, "Received unexpected message %s\n", ITTI_MSG_NAME(msg_p));
+      break;
+    }
+  }
+}
+
+static void add_srb(int rnti, struct NR_SRB_ToAddMod *s)
+{
+  TODO;
+}
+
+static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s)
+{
+  nr_pdcp_entity_t *pdcp_drb;
+  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);
+
+  if (drb_id != 1) {
+    LOG_E(PDCP, "%s:%d:%s: fatal, bad drb id %d\n",
+          __FILE__, __LINE__, __FUNCTION__, drb_id);
+    exit(1);
+  }
+
+  nr_pdcp_manager_lock(nr_pdcp_ue_manager);
+  ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, rnti);
+  if (ue->drb[drb_id-1] != NULL) {
+    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);
+    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",
+          __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
+  }
+  nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
+}
+
+static void add_drb(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_Config_t *rlc_Config)
+{
+  switch (rlc_Config->present) {
+  case NR_RLC_Config_PR_am:
+    add_drb_am(rnti, s);
+    break;
+  case NR_RLC_Config_PR_um_Bi_Directional:
+    //add_drb_um(rnti, s);
+    /* hack */
+    add_drb_am(rnti, s);
+    break;
+  default:
+    LOG_E(PDCP, "%s:%d:%s: fatal: unhandled DRB type\n",
+          __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+}
+
+boolean_t nr_rrc_pdcp_config_asn1_req(
+  const protocol_ctxt_t *const  ctxt_pP,
+  NR_SRB_ToAddModList_t  *const srb2add_list,
+  NR_DRB_ToAddModList_t  *const drb2add_list,
+  NR_DRB_ToReleaseList_t *const drb2release_list,
+  const uint8_t                   security_modeP,
+  uint8_t                  *const kRRCenc,
+  uint8_t                  *const kRRCint,
+  uint8_t                  *const kUPenc
+#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0))
+  ,LTE_PMCH_InfoList_r9_t  *pmch_InfoList_r9
+#endif
+  ,rb_id_t                 *const defaultDRB,
+  struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list)
+  //struct NR_RLC_Config     *rlc_Config)
+{
+  int rnti = ctxt_pP->rnti;
+  int i;
+
+  if (//ctxt_pP->enb_flag != 1 ||
+      ctxt_pP->module_id != 0 ||
+      ctxt_pP->instance != 0 ||
+      ctxt_pP->eNB_index != 0 ||
+      //ctxt_pP->configured != 2 ||
+      //srb2add_list == NULL ||
+      //drb2add_list != NULL ||
+      drb2release_list != NULL ||
+      security_modeP != 255 ||
+      //kRRCenc != NULL ||
+      //kRRCint != NULL ||
+      //kUPenc != NULL ||
+      pmch_InfoList_r9 != NULL /*||
+      defaultDRB != NULL */) {
+    TODO;
+  }
+
+  if (srb2add_list != NULL) {
+    for (i = 0; i < srb2add_list->list.count; i++) {
+      add_srb(rnti, srb2add_list->list.array[i]);
+    }
+  }
+
+  if (drb2add_list != NULL) {
+    for (i = 0; i < drb2add_list->list.count; i++) {
+      LOG_I(PDCP, "Before calling add_drb \n");
+      add_drb(rnti, drb2add_list->list.array[i], rlc_bearer2add_list->list.array[i]->rlc_Config);
+    }
+  }
+
+  /* update security */
+  if (kRRCint != NULL) {
+    /* todo */
+  }
+
+  free(kRRCenc);
+  free(kRRCint);
+  free(kUPenc);
+
+  return 0;
+}
+
+/* Dummy function due to dependency from LTE libraries */
+boolean_t rrc_pdcp_config_asn1_req(
+  const protocol_ctxt_t *const  ctxt_pP,
+  LTE_SRB_ToAddModList_t  *const srb2add_list,
+  LTE_DRB_ToAddModList_t  *const drb2add_list,
+  LTE_DRB_ToReleaseList_t *const drb2release_list,
+  const uint8_t                   security_modeP,
+  uint8_t                  *const kRRCenc,
+  uint8_t                  *const kRRCint,
+  uint8_t                  *const kUPenc
+#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0))
+  ,LTE_PMCH_InfoList_r9_t  *pmch_InfoList_r9
+#endif
+  ,rb_id_t                 *const defaultDRB)
+{
+  return 0;
+}
+
+void nr_DRB_preconfiguration(void)
+{
+
+  NR_RadioBearerConfig_t             *rbconfig = NULL;
+  struct NR_CellGroupConfig__rlc_BearerToAddModList *Rlc_Bearer_ToAdd_list = NULL;
+  protocol_ctxt_t ctxt;
+  //fill_default_rbconfig(rb_config, 5, 1);
+  rbconfig = calloc(1, sizeof(*rbconfig));
+
+  rbconfig->srb_ToAddModList = NULL;
+  rbconfig->srb3_ToRelease = NULL;
+  rbconfig->drb_ToAddModList = calloc(1,sizeof(*rbconfig->drb_ToAddModList));
+  NR_DRB_ToAddMod_t *drb_ToAddMod = calloc(1,sizeof(*drb_ToAddMod));
+  drb_ToAddMod->cnAssociation = calloc(1,sizeof(*drb_ToAddMod->cnAssociation));
+  drb_ToAddMod->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity;
+  drb_ToAddMod->cnAssociation->choice.eps_BearerIdentity= 5;
+  drb_ToAddMod->drb_Identity = 1;
+  drb_ToAddMod->reestablishPDCP = NULL;
+  drb_ToAddMod->recoverPDCP = NULL;
+  drb_ToAddMod->pdcp_Config = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config));
+  drb_ToAddMod->pdcp_Config->drb = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config->drb));
+  drb_ToAddMod->pdcp_Config->drb->discardTimer = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config->drb->discardTimer));
+  *drb_ToAddMod->pdcp_Config->drb->discardTimer=NR_PDCP_Config__drb__discardTimer_ms30;
+  drb_ToAddMod->pdcp_Config->drb->pdcp_SN_SizeUL = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config->drb->pdcp_SN_SizeUL));
+  *drb_ToAddMod->pdcp_Config->drb->pdcp_SN_SizeUL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len12bits;
+  drb_ToAddMod->pdcp_Config->drb->pdcp_SN_SizeDL = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config->drb->pdcp_SN_SizeDL));
+  *drb_ToAddMod->pdcp_Config->drb->pdcp_SN_SizeDL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len12bits;
+  drb_ToAddMod->pdcp_Config->drb->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed;
+  drb_ToAddMod->pdcp_Config->drb->headerCompression.choice.notUsed = 0;
+
+  drb_ToAddMod->pdcp_Config->drb->integrityProtection=NULL;
+  drb_ToAddMod->pdcp_Config->drb->statusReportRequired=NULL;
+  drb_ToAddMod->pdcp_Config->drb->outOfOrderDelivery=NULL;
+  drb_ToAddMod->pdcp_Config->moreThanOneRLC = NULL;
+
+  drb_ToAddMod->pdcp_Config->t_Reordering = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config->t_Reordering));
+  *drb_ToAddMod->pdcp_Config->t_Reordering = NR_PDCP_Config__t_Reordering_ms0;
+  drb_ToAddMod->pdcp_Config->ext1 = NULL;
+
+  ASN_SEQUENCE_ADD(&rbconfig->drb_ToAddModList->list,drb_ToAddMod);
+
+  rbconfig->drb_ToReleaseList = NULL;
+
+  rbconfig->securityConfig = calloc(1,sizeof(*rbconfig->securityConfig));
+  rbconfig->securityConfig->securityAlgorithmConfig = calloc(1,sizeof(*rbconfig->securityConfig->securityAlgorithmConfig));
+  rbconfig->securityConfig->securityAlgorithmConfig->cipheringAlgorithm = NR_CipheringAlgorithm_nea0;
+  rbconfig->securityConfig->securityAlgorithmConfig->integrityProtAlgorithm=NULL;
+  rbconfig->securityConfig->keyToUse = calloc(1,sizeof(*rbconfig->securityConfig->keyToUse));
+  *rbconfig->securityConfig->keyToUse = NR_SecurityConfig__keyToUse_master;
+
+  xer_fprint(stdout, &asn_DEF_NR_RadioBearerConfig, (const void*)rbconfig);
+
+
+  NR_RLC_BearerConfig_t *RLC_BearerConfig = calloc(1,sizeof(*RLC_BearerConfig));
+
+  RLC_BearerConfig->logicalChannelIdentity = 4;
+  RLC_BearerConfig->servedRadioBearer = calloc(1,sizeof(*RLC_BearerConfig->servedRadioBearer));
+  RLC_BearerConfig->servedRadioBearer->present =    NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity;
+
+  RLC_BearerConfig->servedRadioBearer->choice.drb_Identity=1;
+  RLC_BearerConfig->reestablishRLC=calloc(1,sizeof(*RLC_BearerConfig->reestablishRLC));
+  *RLC_BearerConfig->reestablishRLC=NR_RLC_BearerConfig__reestablishRLC_true;
+  RLC_BearerConfig->rlc_Config=calloc(1,sizeof(*RLC_BearerConfig->rlc_Config));
+
+  // RLC UM Bi-directional Bearer configuration
+  RLC_BearerConfig->rlc_Config->present = NR_RLC_Config_PR_um_Bi_Directional;
+  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional));
+  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength));
+  *RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength   =    NR_SN_FieldLengthUM_size12;
+
+  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength));
+  *RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength   =    NR_SN_FieldLengthUM_size12;
+  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = NR_T_Reassembly_ms15;
+
+  // RLC AM Bearer configuration
+  /*RLC_BearerConfig->rlc_Config->present = NR_RLC_Config_PR_am;
+  RLC_BearerConfig->rlc_Config->choice.am = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am));
+  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength));
+  *RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength   =    NR_SN_FieldLengthAM_size18;
+  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45;
+  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.pollPDU          = NR_PollPDU_p64;
+  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.pollByte         = NR_PollByte_kB500;
+  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t32;
+
+  RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength));
+  *RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18;
+  RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.t_Reassembly   = NR_T_Reassembly_ms15;
+  RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15;*/
+
+  RLC_BearerConfig->mac_LogicalChannelConfig = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig));
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters));
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->priority            = 1;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->prioritisedBitRate  = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->bucketSizeDuration  = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->allowedServingCells = NULL;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->allowedSCS_List     = NULL;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->maxPUSCH_Duration   = NULL;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->configuredGrantType1Allowed = NULL;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup   = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup));
+  *RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup  = 1;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID   = NULL;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = false;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = false;
+  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->bitRateQueryProhibitTimer   = NULL;
+
+  Rlc_Bearer_ToAdd_list = calloc(1,sizeof(*Rlc_Bearer_ToAdd_list));
+  ASN_SEQUENCE_ADD(&Rlc_Bearer_ToAdd_list->list, RLC_BearerConfig);
+
+  if (ENB_NAS_USE_TUN){
+    PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_YES, 0x1234, 0, 0,0);
+  }
+  else{
+    PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_NO, 0x1234, 0, 0,0);
+  }
+
+  nr_rrc_pdcp_config_asn1_req(
+    &ctxt,
+    (NR_SRB_ToAddModList_t *) NULL,
+    rbconfig->drb_ToAddModList ,
+    rbconfig->drb_ToReleaseList,
+    0xff,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    Rlc_Bearer_ToAdd_list);
+
+  nr_rrc_rlc_config_asn1_req (&ctxt,
+      (NR_SRB_ToAddModList_t *) NULL,
+      rbconfig->drb_ToAddModList,
+      rbconfig->drb_ToReleaseList,
+      (LTE_PMCH_InfoList_r9_t *) NULL,
+      Rlc_Bearer_ToAdd_list);
+}
+
+uint64_t get_pdcp_optmask(void)
+{
+  return pdcp_optmask;
+}
+
+boolean_t pdcp_remove_UE(
+  const protocol_ctxt_t *const  ctxt_pP)
+{
+  TODO;
+  return 1;
+}
+
+void pdcp_config_set_security(const protocol_ctxt_t* const  ctxt_pP, pdcp_t *pdcp_pP, rb_id_t rb_id,
+                              uint16_t lc_idP, uint8_t security_modeP, uint8_t *kRRCenc_pP, uint8_t *kRRCint_pP, uint8_t *kUPenc_pP)
+{
+  TODO;
+}
+
+static boolean_t pdcp_data_req_drb(
+  protocol_ctxt_t  *ctxt_pP,
+  const rb_id_t rb_id,
+  const mui_t muiP,
+  const confirm_t confirmP,
+  const sdu_size_t sdu_buffer_size,
+  unsigned char *const sdu_buffer)
+{
+printf("pdcp_data_req called size %d\n", sdu_buffer_size);
+  nr_pdcp_ue_t *ue;
+  nr_pdcp_entity_t *rb;
+  int rnti = ctxt_pP->rnti;
+
+  if (ctxt_pP->module_id != 0 ||
+      //ctxt_pP->enb_flag != 1 ||
+      ctxt_pP->instance != 0 ||
+      ctxt_pP->eNB_index != 0 /*||
+      ctxt_pP->configured != 1 ||
+      ctxt_pP->brOption != 0*/) {
+    LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  nr_pdcp_manager_lock(nr_pdcp_ue_manager);
+
+  ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, rnti);
+
+  if (rb_id < 1 || rb_id > 5)
+    rb = NULL;
+  else
+    rb = ue->drb[rb_id - 1];
+
+  if (rb == NULL) {
+    LOG_E(PDCP, "%s:%d:%s: fatal: no DRB found (rnti %d, rb_id %ld)\n",
+          __FILE__, __LINE__, __FUNCTION__, rnti, rb_id);
+    exit(1);
+  }
+
+  rb->recv_sdu(rb, (char *)sdu_buffer, sdu_buffer_size, muiP);
+
+  nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
+
+  return 1;
+}
+
+boolean_t pdcp_data_req(
+  protocol_ctxt_t  *ctxt_pP,
+  const srb_flag_t srb_flagP,
+  const rb_id_t rb_id,
+  const mui_t muiP,
+  const confirm_t confirmP,
+  const sdu_size_t sdu_buffer_size,
+  unsigned char *const sdu_buffer,
+  const pdcp_transmission_mode_t mode
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+  ,const uint32_t *const sourceL2Id
+  ,const uint32_t *const destinationL2Id
+#endif
+  )
+{
+  if (srb_flagP) { TODO; }
+  return pdcp_data_req_drb(ctxt_pP, rb_id, muiP, confirmP, sdu_buffer_size,
+                           sdu_buffer);
+}
+
+void pdcp_set_pdcp_data_ind_func(pdcp_data_ind_func_t pdcp_data_ind)
+{
+  /* nothing to do */
+}
+
+void pdcp_set_rlc_data_req_func(send_rlc_data_req_func_t send_rlc_data_req)
+{
+  /* nothing to do */
+}
+
+//Dummy function needed due to LTE dependencies
+void
+pdcp_mbms_run ( const protocol_ctxt_t *const  ctxt_pP){
+  /* nothing to do */
+}
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
new file mode 100644
index 0000000000000000000000000000000000000000..ca51da3d5f13426993c9395cf3c06550fff9c4f5
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
@@ -0,0 +1,198 @@
+/*
+ * 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 "nr_pdcp_ue_manager.h"
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "LOG/log.h"
+
+typedef struct {
+  pthread_mutex_t lock;
+  nr_pdcp_ue_t    **ue_list;
+  int             ue_count;
+  int             enb_flag;
+} nr_pdcp_ue_manager_internal_t;
+
+nr_pdcp_ue_manager_t *new_nr_pdcp_ue_manager(int enb_flag)
+{
+  nr_pdcp_ue_manager_internal_t *ret;
+
+  ret = calloc(1, sizeof(nr_pdcp_ue_manager_internal_t));
+  if (ret == NULL) {
+    LOG_E(PDCP, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  if (pthread_mutex_init(&ret->lock, NULL)) abort();
+  ret->enb_flag = enb_flag;
+
+  return ret;
+}
+
+int nr_pdcp_manager_get_enb_flag(nr_pdcp_ue_manager_t *_m)
+{
+  nr_pdcp_ue_manager_internal_t *m = _m;
+  return m->enb_flag;
+}
+
+void nr_pdcp_manager_lock(nr_pdcp_ue_manager_t *_m)
+{
+  nr_pdcp_ue_manager_internal_t *m = _m;
+  if (pthread_mutex_lock(&m->lock)) {
+    LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+}
+
+void nr_pdcp_manager_unlock(nr_pdcp_ue_manager_t *_m)
+{
+  nr_pdcp_ue_manager_internal_t *m = _m;
+  if (pthread_mutex_unlock(&m->lock)) {
+    LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+}
+
+/* must be called with lock acquired */
+nr_pdcp_ue_t *nr_pdcp_manager_get_ue(nr_pdcp_ue_manager_t *_m, int rnti)
+{
+  /* TODO: optimze */
+  nr_pdcp_ue_manager_internal_t *m = _m;
+  int i;
+
+  for (i = 0; i < m->ue_count; i++)
+    if (m->ue_list[i]->rnti == rnti)
+      return m->ue_list[i];
+
+  LOG_D(PDCP, "%s:%d:%s: new UE %d\n", __FILE__, __LINE__, __FUNCTION__, rnti);
+
+  m->ue_count++;
+  m->ue_list = realloc(m->ue_list, sizeof(nr_pdcp_ue_t *) * m->ue_count);
+  if (m->ue_list == NULL) {
+    LOG_E(PDCP, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+  m->ue_list[m->ue_count-1] = calloc(1, sizeof(nr_pdcp_ue_t));
+  if (m->ue_list[m->ue_count-1] == NULL) {
+    LOG_E(PDCP, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  m->ue_list[m->ue_count-1]->rnti = rnti;
+
+  return m->ue_list[m->ue_count-1];
+}
+
+/* must be called with lock acquired */
+void nr_pdcp_manager_remove_ue(nr_pdcp_ue_manager_t *_m, int rnti)
+{
+  nr_pdcp_ue_manager_internal_t *m = _m;
+  nr_pdcp_ue_t *ue;
+  int i;
+  int j;
+
+  for (i = 0; i < m->ue_count; i++)
+    if (m->ue_list[i]->rnti == rnti)
+      break;
+
+  if (i == m->ue_count) {
+    LOG_D(PDCP, "%s:%d:%s: warning: ue %d not found\n",
+          __FILE__, __LINE__, __FUNCTION__,
+          rnti);
+    return;
+  }
+
+  ue = m->ue_list[i];
+
+  for (j = 0; j < 2; j++)
+    if (ue->srb[j] != NULL)
+      ue->srb[j]->delete(ue->srb[j]);
+
+  for (j = 0; j < 5; j++)
+    if (ue->drb[j] != NULL)
+      ue->drb[j]->delete(ue->drb[j]);
+
+  free(ue);
+
+  m->ue_count--;
+  if (m->ue_count == 0) {
+    free(m->ue_list);
+    m->ue_list = NULL;
+    return;
+  }
+
+  memmove(&m->ue_list[i], &m->ue_list[i+1],
+          (m->ue_count - i) * sizeof(nr_pdcp_ue_t *));
+  m->ue_list = realloc(m->ue_list, m->ue_count * sizeof(nr_pdcp_ue_t *));
+  if (m->ue_list == NULL) {
+    LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+}
+
+/* must be called with lock acquired */
+void nr_pdcp_ue_add_srb_pdcp_entity(nr_pdcp_ue_t *ue, int srb_id, nr_pdcp_entity_t *entity)
+{
+  if (srb_id < 1 || srb_id > 2) {
+    LOG_E(PDCP, "%s:%d:%s: fatal, bad srb id\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  srb_id--;
+
+  if (ue->srb[srb_id] != NULL) {
+    LOG_E(PDCP, "%s:%d:%s: fatal, srb already present\n",
+          __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  ue->srb[srb_id] = entity;
+}
+
+/* must be called with lock acquired */
+void nr_pdcp_ue_add_drb_pdcp_entity(nr_pdcp_ue_t *ue, int drb_id, nr_pdcp_entity_t *entity)
+{
+  if (drb_id < 1 || drb_id > 5) {
+    LOG_E(PDCP, "%s:%d:%s: fatal, bad drb id\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  drb_id--;
+
+  if (ue->drb[drb_id] != NULL) {
+    LOG_E(PDCP, "%s:%d:%s: fatal, drb already present\n",
+          __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  ue->drb[drb_id] = entity;
+}
+
+int nr_pdcp_get_first_rnti(nr_pdcp_ue_manager_t *_m)
+{
+  nr_pdcp_ue_manager_internal_t *m = _m;
+  if (m->ue_count == 0)
+    return -1;
+  return m->ue_list[0]->rnti;
+}
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..0de2f024b3f53746ff12537dfb08da9ec8fef1b1
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h
@@ -0,0 +1,65 @@
+/*
+ * 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 _NR_PDCP_UE_MANAGER_H_
+#define _NR_PDCP_UE_MANAGER_H_
+
+#include "nr_pdcp_entity.h"
+
+typedef void nr_pdcp_ue_manager_t;
+
+typedef struct nr_pdcp_ue_t {
+  int rnti;
+  nr_pdcp_entity_t *srb[2];
+  nr_pdcp_entity_t *drb[5];
+} nr_pdcp_ue_t;
+
+/***********************************************************************/
+/* manager functions                                                   */
+/***********************************************************************/
+
+nr_pdcp_ue_manager_t *new_nr_pdcp_ue_manager(int enb_flag);
+
+int nr_pdcp_manager_get_enb_flag(nr_pdcp_ue_manager_t *m);
+
+void nr_pdcp_manager_lock(nr_pdcp_ue_manager_t *m);
+void nr_pdcp_manager_unlock(nr_pdcp_ue_manager_t *m);
+
+nr_pdcp_ue_t *nr_pdcp_manager_get_ue(nr_pdcp_ue_manager_t *m, int rnti);
+void nr_pdcp_manager_remove_ue(nr_pdcp_ue_manager_t *m, int rnti);
+
+/***********************************************************************/
+/* ue functions                                                        */
+/***********************************************************************/
+
+void nr_pdcp_ue_add_srb_pdcp_entity(nr_pdcp_ue_t *ue, int srb_id,
+                                    nr_pdcp_entity_t *entity);
+void nr_pdcp_ue_add_drb_pdcp_entity(nr_pdcp_ue_t *ue, int drb_id,
+                                    nr_pdcp_entity_t *entity);
+
+/***********************************************************************/
+/* hacks                                                               */
+/***********************************************************************/
+
+/* returns -1 if no UE */
+int nr_pdcp_get_first_rnti(nr_pdcp_ue_manager_t *m);
+
+#endif /* _NR_PDCP_UE_MANAGER_H_ */
diff --git a/openair2/LAYER2/nr_rlc/asn1_utils.c b/openair2/LAYER2/nr_rlc/asn1_utils.c
index 46f7d90da57d2cb7d15cee8c60614a49a832e955..43d55af1ac521cc21885a66b708a1393e51ef87d 100644
--- a/openair2/LAYER2/nr_rlc/asn1_utils.c
+++ b/openair2/LAYER2/nr_rlc/asn1_utils.c
@@ -21,14 +21,14 @@
 
 #include "rlc.h"
 
-int decode_t_reordering(int v)
+int decode_t_reassembly(int v)
 {
-  static int tab[32] = {
-    0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85,
-    90, 95, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 1600
+  static int tab[31] = {
+    0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90,
+    95, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200
   };
 
-  if (v < 0 || v > 31) {
+  if (v < 0 || v > 30) {
     LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
     exit(1);
   }
@@ -72,11 +72,13 @@ int decode_t_poll_retransmit(int v)
 
 int decode_poll_pdu(int v)
 {
-  static int tab[8] = {
-    4, 8, 16, 32, 64, 128, 256, -1 /* -1 means infinity */
+  static int tab[24] = {
+    4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 6144, 8192, 12288,
+    16384, 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536
+    -1 /* -1 means infinity */
   };
 
-  if (v < 0 || v > 7) {
+  if (v < 0 || v > 23) {
     LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
     exit(1);
   }
@@ -86,12 +88,23 @@ int decode_poll_pdu(int v)
 
 int decode_poll_byte(int v)
 {
-  static int tab[15] = {
-    25, 50, 75, 100, 125, 250, 375, 500, 750, 1000, 1250, 1500, 2000, 3000,
+  static int tab[44] = {
+    /* KB */
+    1024 * 1,    1024 * 2,    1024 * 5,    1024 * 8,    1024 * 10,
+    1024 * 15,   1024 * 25,   1024 * 50,   1024 * 75,   1024 * 100,
+    1024 * 125,  1024 * 250,  1024 * 375,  1024 * 500,  1024 * 750,
+    1024 * 1000, 1024 * 1250, 1024 * 1500, 1024 * 2000, 1024 * 3000,
+    1024 * 4000, 1024 * 4500, 1024 * 5000, 1024 * 5500, 1024 * 6000,
+    1024 * 6500, 1024 * 7000, 1024 * 7500,
+    /* MB */
+    1024 * 1024 * 8,  1024 * 1024 * 9,  1024 * 1024 * 10, 1024 * 1024 * 11,
+    1024 * 1024 * 12, 1024 * 1024 * 13, 1024 * 1024 * 14, 1024 * 1024 * 15,
+    1024 * 1024 * 16, 1024 * 1024 * 17, 1024 * 1024 * 18, 1024 * 1024 * 20,
+    1024 * 1024 * 25, 1024 * 1024 * 30, 1024 * 1024 * 40,
     -1 /* -1 means infinity */
   };
 
-  if (v < 0 || v > 14) {
+  if (v < 0 || v > 43) {
     LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
     exit(1);
   }
@@ -114,10 +127,24 @@ int decode_max_retx_threshold(int v)
   return tab[v];
 }
 
-int decode_sn_field_length(int v)
+int decode_sn_field_length_um(int v)
+{
+  static int tab[2] = {
+    6, 12
+  };
+
+  if (v < 0 || v > 1) {
+    LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  return tab[v];
+}
+
+int decode_sn_field_length_am(int v)
 {
   static int tab[2] = {
-    5, 10
+    12, 18
   };
 
   if (v < 0 || v > 1) {
diff --git a/openair2/LAYER2/nr_rlc/asn1_utils.h b/openair2/LAYER2/nr_rlc/asn1_utils.h
index 61394c9c6991ccdc32722bfb039bfdac82a741ae..6f010b02da9bf09b360014805ecbdb1373b2a5ef 100644
--- a/openair2/LAYER2/nr_rlc/asn1_utils.h
+++ b/openair2/LAYER2/nr_rlc/asn1_utils.h
@@ -19,15 +19,16 @@
  *      contact@openairinterface.org
  */
 
-#ifndef _ASN1_UTILS_H_
-#define _ASN1_UTILS_H_
+#ifndef _OPENAIR2_LAYER2_NR_RLC_ASN1_UTILS_H_
+#define _OPENAIR2_LAYER2_NR_RLC_ASN1_UTILS_H_
 
-int decode_t_reordering(int v);
+int decode_t_reassembly(int v);
 int decode_t_status_prohibit(int v);
 int decode_t_poll_retransmit(int v);
 int decode_poll_pdu(int v);
 int decode_poll_byte(int v);
 int decode_max_retx_threshold(int v);
-int decode_sn_field_length(int v);
+int decode_sn_field_length_um(int v);
+int decode_sn_field_length_am(int v);
 
-#endif /* _ASN1_UTILS_H_ */
+#endif /* _OPENAIR2_LAYER2_NR_RLC_ASN1_UTILS_H_ */
diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
index 8f3d49d8c2391b98daf24f8d74ad7bb54a951905..78a49e4604a1f300d433fb185e126c30a9d49e48 100644
--- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
@@ -109,7 +109,8 @@ static void consider_retransmission(nr_rlc_entity_am_t *entity,
    * upper layers should deal with this condition, internally it's better
    * for the RLC code to keep going with this segment (we only remove
    * a segment that was ACKed)
-   */
+   */ 
+  LOG_D(RLC, "RLC segment to be added at the ReTx list \n"); 
   nr_rlc_sdu_segment_list_append(&entity->retransmit_list,
                                  &entity->retransmit_end,
                                  cur);
@@ -1588,6 +1589,8 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity,
 
   sdu = nr_rlc_new_sdu(buffer, size, sdu_id);
 
+  LOG_D(RLC, "Created new RLC SDU and append it to the RLC list \n");
+
   nr_rlc_sdu_segment_list_append(&entity->tx_list, &entity->tx_end, sdu);
 }
 
diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c
index bbc4acbd56d3624adfe92241e0b17531701f9c0a..919cf1a46a01a758cb2f8bc147402904e1437cf1 100644
--- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c
@@ -27,19 +27,23 @@
 #include "asn1_utils.h"
 #include "nr_rlc_ue_manager.h"
 #include "nr_rlc_entity.h"
+#include "NR_RLC-BearerConfig.h"
+#include "NR_DRB-ToAddMod.h"
+#include "NR_DRB-ToAddModList.h"
+#include "NR_SRB-ToAddModList.h"
+#include "NR_DRB-ToReleaseList.h"
+#include "NR_CellGroupConfig.h"
+#include "NR_RLC-Config.h"
 
 #include <stdint.h>
 
 static nr_rlc_ue_manager_t *nr_rlc_ue_manager;
 
 /* TODO: handle time a bit more properly */
-//#if 0
 static uint64_t nr_rlc_current_time;
 static int      nr_rlc_current_time_last_frame;
 static int      nr_rlc_current_time_last_subframe;
-//#endif
 
-//#if 0
 void mac_rlc_data_ind     (
   const module_id_t         module_idP,
   const rnti_t              rntiP,
@@ -195,7 +199,6 @@ mac_rlc_status_resp_t mac_rlc_status_ind(
   ret.head_sdu_is_segmented = 0;
   return ret;
 }
-//#endif
 
 rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind(
   const module_id_t       module_idP,
@@ -254,7 +257,6 @@ rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind(
 
 int oai_emulation;
 
-//#if 0
 rlc_op_status_t rlc_data_req     (const protocol_ctxt_t *const ctxt_pP,
                                   const srb_flag_t   srb_flagP,
                                   const MBMS_flag_t  MBMS_flagP,
@@ -306,9 +308,7 @@ rlc_op_status_t rlc_data_req     (const protocol_ctxt_t *const ctxt_pP,
 
   return RLC_OP_STATUS_OK;
 }
-//#endif
 
-//#if 0
 int rlc_module_init(int enb_flag)
 {
   static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
@@ -329,13 +329,10 @@ int rlc_module_init(int enb_flag)
 
   return 0;
 }
-//#endif
 
-//#if 0
 void rlc_util_print_hex_octets(comp_name_t componentP, unsigned char *dataP, const signed long sizeP)
 {
 }
-//#endif
 
 static void deliver_sdu(void *_ue, nr_rlc_entity_t *entity, char *buf, int size)
 {
@@ -522,7 +519,7 @@ rb_found:
 #endif
 }
 
-__attribute__ ((unused)) static void add_srb(int rnti, struct LTE_SRB_ToAddMod *s)
+static void add_srb(int rnti, struct LTE_SRB_ToAddMod *s)
 {
   nr_rlc_entity_t            *nr_rlc_am;
   nr_rlc_ue_t                *ue;
@@ -532,7 +529,6 @@ __attribute__ ((unused)) static void add_srb(int rnti, struct LTE_SRB_ToAddMod *
   int srb_id = s->srb_Identity;
   int logical_channel_group;
 
-  //int t_reordering;
   int t_status_prohibit;
   int t_poll_retransmit;
   int poll_pdu;
@@ -575,7 +571,6 @@ __attribute__ ((unused)) static void add_srb(int rnti, struct LTE_SRB_ToAddMod *
       exit(1);
     }
     am = &r->choice.explicitValue.choice.am;
-    //t_reordering       = decode_t_reordering(am->dl_AM_RLC.t_Reordering);
     t_status_prohibit  = decode_t_status_prohibit(am->dl_AM_RLC.t_StatusProhibit);
     t_poll_retransmit  = decode_t_poll_retransmit(am->ul_AM_RLC.t_PollRetransmit);
     poll_pdu           = decode_poll_pdu(am->ul_AM_RLC.pollPDU);
@@ -585,7 +580,6 @@ __attribute__ ((unused)) static void add_srb(int rnti, struct LTE_SRB_ToAddMod *
   }
   case LTE_SRB_ToAddMod__rlc_Config_PR_defaultValue:
     /* default values from 36.331 9.2.1 */
-    //t_reordering       = 35;
     t_status_prohibit  = 0;
     t_poll_retransmit  = 45;
     poll_pdu           = -1;
@@ -628,18 +622,17 @@ __attribute__ ((unused)) static void add_srb(int rnti, struct LTE_SRB_ToAddMod *
   nr_rlc_manager_unlock(nr_rlc_ue_manager);
 }
 
-static void add_drb_am(int rnti, struct LTE_DRB_ToAddMod *s)
+static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_t *rlc_BearerConfig)
 {
   nr_rlc_entity_t            *nr_rlc_am;
   nr_rlc_ue_t                *ue;
 
-  struct LTE_RLC_Config *r = s->rlc_Config;
-  struct LTE_LogicalChannelConfig *l = s->logicalChannelConfig;
+  struct NR_RLC_Config *r = rlc_BearerConfig->rlc_Config;
+  struct NR_LogicalChannelConfig *l = rlc_BearerConfig->mac_LogicalChannelConfig;
   int drb_id = s->drb_Identity;
-  int channel_id = *s->logicalChannelIdentity;
+  int channel_id = rlc_BearerConfig->logicalChannelIdentity;
   int logical_channel_group;
 
-  //int t_reordering;
   int t_status_prohibit;
   int t_poll_retransmit;
   int poll_pdu;
@@ -669,15 +662,20 @@ static void add_drb_am(int rnti, struct LTE_DRB_ToAddMod *s)
   }
 
   switch (r->present) {
-  case LTE_RLC_Config_PR_am: {
-    struct LTE_RLC_Config__am *am;
-    am = &r->choice.am;
-    //t_reordering       = decode_t_reordering(am->dl_AM_RLC.t_Reordering);
+  case NR_RLC_Config_PR_am: {
+    struct NR_RLC_Config__am *am;
+    am = r->choice.am;
+    t_reassembly       = decode_t_reassembly(am->dl_AM_RLC.t_Reassembly);
     t_status_prohibit  = decode_t_status_prohibit(am->dl_AM_RLC.t_StatusProhibit);
     t_poll_retransmit  = decode_t_poll_retransmit(am->ul_AM_RLC.t_PollRetransmit);
     poll_pdu           = decode_poll_pdu(am->ul_AM_RLC.pollPDU);
     poll_byte          = decode_poll_byte(am->ul_AM_RLC.pollByte);
     max_retx_threshold = decode_max_retx_threshold(am->ul_AM_RLC.maxRetxThreshold);
+    if (*am->dl_AM_RLC.sn_FieldLength != *am->ul_AM_RLC.sn_FieldLength) {
+      LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+      exit(1);
+    }
+    sn_field_length    = decode_sn_field_length_am(*am->dl_AM_RLC.sn_FieldLength);
     break;
   }
   default:
@@ -691,14 +689,6 @@ static void add_drb_am(int rnti, struct LTE_DRB_ToAddMod *s)
     LOG_D(RLC, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n",
           __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   } else {
-    /* hack: hardcode values for NR */
-    t_poll_retransmit = 45;
-    t_reassembly = 35;
-    t_status_prohibit = 0;
-    poll_pdu = -1;
-    poll_byte = -1;
-    max_retx_threshold = 8;
-    sn_field_length = 12;
     nr_rlc_am = new_nr_rlc_entity_am(100000,
                                      100000,
                                      deliver_sdu, ue,
@@ -716,18 +706,17 @@ static void add_drb_am(int rnti, struct LTE_DRB_ToAddMod *s)
   nr_rlc_manager_unlock(nr_rlc_ue_manager);
 }
 
-static void add_drb_um(int rnti, struct LTE_DRB_ToAddMod *s)
+static void add_drb_um(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_t *rlc_BearerConfig)
 {
   nr_rlc_entity_t            *nr_rlc_um;
   nr_rlc_ue_t                *ue;
 
-  struct LTE_RLC_Config *r = s->rlc_Config;
-  struct LTE_LogicalChannelConfig *l = s->logicalChannelConfig;
+  struct NR_RLC_Config *r = rlc_BearerConfig->rlc_Config;
+  struct NR_LogicalChannelConfig *l = rlc_BearerConfig->mac_LogicalChannelConfig;
   int drb_id = s->drb_Identity;
-  int channel_id = *s->logicalChannelIdentity;
+  int channel_id = rlc_BearerConfig->logicalChannelIdentity;
   int logical_channel_group;
 
-  //int t_reordering;
   int sn_field_length;
   int t_reassembly;
 
@@ -752,15 +741,15 @@ static void add_drb_um(int rnti, struct LTE_DRB_ToAddMod *s)
   }
 
   switch (r->present) {
-  case LTE_RLC_Config_PR_um_Bi_Directional: {
-    struct LTE_RLC_Config__um_Bi_Directional *um;
-    um = &r->choice.um_Bi_Directional;
-    //t_reordering    = decode_t_reordering(um->dl_UM_RLC.t_Reordering);
-    if (um->dl_UM_RLC.sn_FieldLength != um->ul_UM_RLC.sn_FieldLength) {
+  case NR_RLC_Config_PR_um_Bi_Directional: {
+    struct NR_RLC_Config__um_Bi_Directional *um;
+    um = r->choice.um_Bi_Directional;
+    t_reassembly = decode_t_reassembly(um->dl_UM_RLC.t_Reassembly);
+    if (*um->dl_UM_RLC.sn_FieldLength != *um->ul_UM_RLC.sn_FieldLength) {
       LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
       exit(1);
     }
-    sn_field_length = decode_sn_field_length(um->dl_UM_RLC.sn_FieldLength);
+    sn_field_length = decode_sn_field_length_um(*um->dl_UM_RLC.sn_FieldLength);
     break;
   }
   default:
@@ -774,9 +763,6 @@ static void add_drb_um(int rnti, struct LTE_DRB_ToAddMod *s)
     LOG_D(RLC, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n",
           __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   } else {
-    /* hack: hardcode values for NR */
-    t_reassembly = 35;
-    sn_field_length = 6;
     nr_rlc_um = new_nr_rlc_entity_um(1000000,
                                      1000000,
                                      deliver_sdu, ue,
@@ -790,14 +776,14 @@ static void add_drb_um(int rnti, struct LTE_DRB_ToAddMod *s)
   nr_rlc_manager_unlock(nr_rlc_ue_manager);
 }
 
-__attribute__ ((unused)) static void add_drb(int rnti, struct LTE_DRB_ToAddMod *s)
+static void add_drb(int rnti, struct NR_DRB_ToAddMod *s, struct NR_RLC_BearerConfig *rlc_BearerConfig)
 {
-  switch (s->rlc_Config->present) {
-  case LTE_RLC_Config_PR_am:
-    add_drb_am(rnti, s);
+  switch (rlc_BearerConfig->rlc_Config->present) {
+  case NR_RLC_Config_PR_am:
+    add_drb_am(rnti, s, rlc_BearerConfig);
     break;
-  case LTE_RLC_Config_PR_um_Bi_Directional:
-    add_drb_um(rnti, s);
+  case NR_RLC_Config_PR_um_Bi_Directional:
+    add_drb_um(rnti, s, rlc_BearerConfig);
     break;
   default:
     LOG_E(RLC, "%s:%d:%s: fatal: unhandled DRB type\n",
@@ -806,7 +792,7 @@ __attribute__ ((unused)) static void add_drb(int rnti, struct LTE_DRB_ToAddMod *
   }
 }
 
-//#if 0
+/* Dummy function due to dependency from LTE libraries */
 rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t   * const ctxt_pP,
     const LTE_SRB_ToAddModList_t   * const srb2add_listP,
     const LTE_DRB_ToAddModList_t   * const drb2add_listP,
@@ -814,6 +800,16 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t   * const ctxt_pP
     const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP,
     const uint32_t sourceL2Id,
     const uint32_t destinationL2Id)
+{
+  return 0;
+}
+
+rlc_op_status_t nr_rrc_rlc_config_asn1_req (const protocol_ctxt_t   * const ctxt_pP,
+    const LTE_SRB_ToAddModList_t   * const srb2add_listP,
+    const NR_DRB_ToAddModList_t   * const drb2add_listP,
+    const NR_DRB_ToReleaseList_t  * const drb2release_listP,
+    const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP,
+    struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list)
 {
   int rnti = ctxt_pP->rnti;
   int i;
@@ -845,15 +841,13 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t   * const ctxt_pP
 
   if (drb2add_listP != NULL) {
     for (i = 0; i < drb2add_listP->list.count; i++) {
-      add_drb(rnti, drb2add_listP->list.array[i]);
+      add_drb(rnti, drb2add_listP->list.array[i], rlc_bearer2add_list->list.array[i]);
     }
   }
 
   return RLC_OP_STATUS_OK;
 }
-//#endif
 
-//#if 0
 rlc_op_status_t rrc_rlc_config_req   (
   const protocol_ctxt_t* const ctxt_pP,
   const srb_flag_t      srb_flagP,
@@ -912,16 +906,12 @@ rlc_op_status_t rrc_rlc_config_req   (
   nr_rlc_manager_unlock(nr_rlc_ue_manager);
   return RLC_OP_STATUS_OK;
 }
-//#endif
 
-//#if 0
 void rrc_rlc_register_rrc (rrc_data_ind_cb_t rrc_data_indP, rrc_data_conf_cb_t rrc_data_confP)
 {
   /* nothing to do */
 }
-//#endif
 
-//#if 0
 rlc_op_status_t rrc_rlc_remove_ue (const protocol_ctxt_t* const x)
 {
   LOG_D(RLC, "%s:%d:%s: remove UE %d\n", __FILE__, __LINE__, __FUNCTION__, x->rnti);
@@ -931,4 +921,3 @@ rlc_op_status_t rrc_rlc_remove_ue (const protocol_ctxt_t* const x)
 
   return RLC_OP_STATUS_OK;
 }
-//#endif
diff --git a/openair2/LAYER2/rlc_v2/asn1_utils.h b/openair2/LAYER2/rlc_v2/asn1_utils.h
index 61394c9c6991ccdc32722bfb039bfdac82a741ae..fadaf16f0a53478dbf9c37138cdf541e2210516e 100644
--- a/openair2/LAYER2/rlc_v2/asn1_utils.h
+++ b/openair2/LAYER2/rlc_v2/asn1_utils.h
@@ -19,8 +19,8 @@
  *      contact@openairinterface.org
  */
 
-#ifndef _ASN1_UTILS_H_
-#define _ASN1_UTILS_H_
+#ifndef _OPENAIR2_LAYER2_RLC_V2_ASN1_UTILS_H_
+#define _OPENAIR2_LAYER2_RLC_V2_ASN1_UTILS_H_
 
 int decode_t_reordering(int v);
 int decode_t_status_prohibit(int v);
@@ -30,4 +30,4 @@ int decode_poll_byte(int v);
 int decode_max_retx_threshold(int v);
 int decode_sn_field_length(int v);
 
-#endif /* _ASN1_UTILS_H_ */
+#endif /* _OPENAIR2_LAYER2_RLC_V2_ASN1_UTILS_H_ */
diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
index ec969c674128694cf39bfcd412c805862258a70e..c5b90cf028047d4d48cf6280ca9e4fcab0ca130c 100644
--- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
@@ -41,6 +41,7 @@
 #include "executables/softmodem-common.h"
 
 #define MAX_IF_MODULES 100
+//#define UL_HARQ_PRINT
 
 NR_IF_Module_t *if_inst[MAX_IF_MODULES];
 NR_Sched_Rsp_t Sched_INFO[MAX_IF_MODULES][MAX_NUM_CCs];
@@ -77,62 +78,8 @@ 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) {
-  // TODO
-  int max_harq_rounds = 4; // TODO define macro
-  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_PDCCH_PDU_TYPE: break;
-
-      case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: {
-        if (get_softmodem_params()->phy_test == 0) {
-          nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu = &uci_list[i].pucch_pdu_format_0_1;
-          // handle harq
-          int harq_idx_s = 0;
-          // iterate over received harq bits
-          for (int harq_bit = 0; harq_bit < uci_pdu->harq->num_harq; harq_bit++) {
-            // search for the right harq process
-            for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES-1; harq_idx++) {
-              if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
-                if (uci_pdu->harq->harq_list[harq_bit].harq_value == 0)
-                  sched_ctrl->harq_processes[harq_idx].round++;
-                if ((uci_pdu->harq->harq_list[harq_bit].harq_value == 1) ||
-                   (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;
-                }
-                sched_ctrl->harq_processes[harq_idx].is_waiting = 0;
-                harq_idx_s = harq_idx + 1;
-                break;
-              }
-              // if gNB fails to receive a ACK/NACK
-              else if (((UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot) &&
-                      (sched_ctrl->harq_processes[harq_idx].is_waiting)) {
-                sched_ctrl->harq_processes[harq_idx].round++;
-                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;
-                }
-                sched_ctrl->harq_processes[harq_idx].is_waiting = 0;
-              }
-            }
-          }
-        }
-        break;
-      }
-
-      case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: break;
-    }
-  }
+void handle_nr_ulsch(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats) {
 
-  UL_info->uci_ind.num_ucis = 0;
-}
-
-
-void handle_nr_ulsch(NR_UL_IND_t *UL_info) {
   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));
@@ -159,6 +106,8 @@ void handle_nr_ulsch(NR_UL_IND_t *UL_info) {
               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);
 
@@ -170,7 +119,8 @@ void handle_nr_ulsch(NR_UL_IND_t *UL_info) {
                         (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].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,
@@ -181,7 +131,8 @@ void handle_nr_ulsch(NR_UL_IND_t *UL_info) {
                         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].ul_cqi,
+                        UL_info->rx_ind.pdu_list[i].rssi);
             }
             break;
           }
@@ -209,7 +160,6 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
   NR_Sched_Rsp_t   *sched_info = &Sched_INFO[module_id][CC_id];
   NR_IF_Module_t   *ifi        = if_inst[module_id];
   gNB_MAC_INST     *mac        = RC.nrmac[module_id];
-
   LOG_D(PHY,"SFN/SF:%d%d module_id:%d CC_id:%d UL_info[rach_pdus:%d rx_ind:%d crcs:%d]\n",
         UL_info->frame,UL_info->slot,
         module_id,CC_id, UL_info->rach_ind.number_of_pdus,
@@ -230,10 +180,11 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
   // 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_list.UE_sched_ctrl[0]);
+  
+  handle_nr_uci(UL_info,&mac->UE_list.UE_sched_ctrl[0],&mac->UE_list.mac_stats[0],mac->pucch_target_snrx10);
   // clear HI prior to handling ULSCH
   mac->UL_dci_req[CC_id].numPdus = 0;
-  handle_nr_ulsch(UL_info);
+  handle_nr_ulsch(UL_info, &mac->UE_list.UE_sched_ctrl[0],&mac->UE_list.mac_stats[0]);
 
   if (nfapi_mode != 1) {
     if (ifi->CC_mask == ((1<<MAX_NUM_CCs)-1)) {
@@ -245,8 +196,6 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
       nfapi_nr_config_request_scf_t *cfg = &mac->config[CC_id];
       int spf = get_spf(cfg);
       gNB_dlsch_ulsch_scheduler(module_id,
-				UL_info->frame,
-				UL_info->slot,
 				(UL_info->frame+((UL_info->slot>(spf-1-sl_ahead))?1:0)) % 1024,
 				(UL_info->slot+sl_ahead)%spf);
       
@@ -258,13 +207,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];
 
-      if ((mac->common_channels[CC_id].ServingCellConfigCommon->tdd_UL_DL_ConfigurationCommon==NULL) ||
-          (is_nr_UL_slot(mac->common_channels[CC_id].ServingCellConfigCommon,UL_info->slot)>0)) {
-	//printf("NR_UL_indication: this is an UL slot. UL_info: frame %d, slot %d. UL_tti_req: frame %d, slot %d\n",UL_info->frame,UL_info->slot,mac->UL_tti_req[CC_id].SFN,mac->UL_tti_req[CC_id].Slot);
-        sched_info->UL_tti_req      = &mac->UL_tti_req[CC_id];
-      }
-      else
-        sched_info->UL_tti_req      = NULL;
+      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/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
index e63f93b02819877c6bb70919850a3680d1547729..91cc9654739e8ecf680a0337de00f035f7d0bf95 100644
--- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
@@ -167,13 +167,16 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info, NR_UL_TIME_ALIGNMENT_
       for(i=0; i<dl_info->dci_ind->number_of_dcis; ++i){
         LOG_D(MAC,">>>NR_IF_Module i=%d, dl_info->dci_ind->number_of_dcis=%d\n",i,dl_info->dci_ind->number_of_dcis);
 
-        ret_mask |= (handle_dci(dl_info->module_id,
+        int8_t ret = handle_dci(dl_info->module_id,
                                 dl_info->cc_id,
                                 dl_info->gNB_index,
-                                dl_info->dci_ind->dci_list+i)<< FAPI_NR_DCI_IND);
+                                dl_info->dci_ind->dci_list+i);
 
-        AssertFatal( nr_ue_if_module_inst[module_id] != NULL, "IF module is void!\n" );
-        nr_ue_if_module_inst[module_id]->scheduled_response(&mac->scheduled_response);
+        ret_mask |= (ret << FAPI_NR_DCI_IND);
+        if (ret >= 0) {
+          AssertFatal( nr_ue_if_module_inst[module_id] != NULL, "IF module is void!\n" );
+          nr_ue_if_module_inst[module_id]->scheduled_response(&mac->scheduled_response);
+        }
       }
     }
 
diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c
index b6062df2c4a0b60d436784649fcd34ce5808ffe4..31a26d322d4d280ed8ad762f2128405c2e7a586b 100644
--- a/openair2/RRC/LTE/rrc_eNB.c
+++ b/openair2/RRC/LTE/rrc_eNB.c
@@ -9089,47 +9089,53 @@ void rrc_eNB_process_AdditionResponseInformation(const module_id_t enb_mod_idP,
     return;
   }
 
-  protocol_ctxt_t ctxt;
-  rrc_eNB_ue_context_t *ue_context;
-  unsigned char buffer[8192];
-  int size;
-  ue_context = rrc_eNB_get_ue_context(RC.rrc[enb_mod_idP], m->rnti);
-  ue_context->ue_context.nb_of_modify_endc_e_rabs = m->nb_e_rabs_admitted_tobeadded;
-  int j=0;
-
-  while(j < m->nb_e_rabs_admitted_tobeadded) {
-    for (int e_rab_idx=0; e_rab_idx<ue_context->ue_context.setup_e_rabs; e_rab_idx++) {
-      //Update ue_context information with gNB's address and new GTP tunnel ID
-      if( ue_context->ue_context.e_rab[e_rab_idx].param.e_rab_id == m->e_rabs_admitted_tobeadded[j].e_rab_id) {
-        memcpy(ue_context->ue_context.gnb_gtp_endc_addrs[e_rab_idx].buffer,
-               m->e_rabs_admitted_tobeadded[j].gnb_addr.buffer,
-               m->e_rabs_admitted_tobeadded[j].gnb_addr.length);
-        ue_context->ue_context.gnb_gtp_endc_addrs[e_rab_idx].length = m->e_rabs_admitted_tobeadded[j].gnb_addr.length;
-        ue_context->ue_context.gnb_gtp_endc_teid[e_rab_idx] = m->e_rabs_admitted_tobeadded[j].gtp_teid;
-        ue_context->ue_context.e_rab[e_rab_idx].status = E_RAB_STATUS_TOMODIFY;
-        break;
+    protocol_ctxt_t ctxt;
+    rrc_eNB_ue_context_t *ue_context;
+    unsigned char buffer[8192];
+    int size;
+
+    ue_context = rrc_eNB_get_ue_context(RC.rrc[enb_mod_idP], m->rnti);
+    if (ue_context) {
+      ue_context->ue_context.nb_of_modify_endc_e_rabs = m->nb_e_rabs_admitted_tobeadded;
+
+      int j=0;
+      while(j < m->nb_e_rabs_admitted_tobeadded){
+	for (int e_rab_idx=0; e_rab_idx<ue_context->ue_context.setup_e_rabs; e_rab_idx++){
+	  //Update ue_context information with gNB's address and new GTP tunnel ID
+	  if( ue_context->ue_context.e_rab[e_rab_idx].param.e_rab_id == m->e_rabs_admitted_tobeadded[j].e_rab_id){
+	    memcpy(ue_context->ue_context.gnb_gtp_endc_addrs[e_rab_idx].buffer,
+		   m->e_rabs_admitted_tobeadded[j].gnb_addr.buffer,
+		   m->e_rabs_admitted_tobeadded[j].gnb_addr.length);
+	    ue_context->ue_context.gnb_gtp_endc_addrs[e_rab_idx].length = m->e_rabs_admitted_tobeadded[j].gnb_addr.length;
+	    ue_context->ue_context.gnb_gtp_endc_teid[e_rab_idx] = m->e_rabs_admitted_tobeadded[j].gtp_teid;
+	    ue_context->ue_context.e_rab[e_rab_idx].status = E_RAB_STATUS_TOMODIFY;
+	    break;
+	  }
+	}
+	j++;
       }
-    }
 
-    j++;
-  }
+      PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt,
+                                    0,
+                                    ENB_FLAG_YES,
+                                    m->rnti,
+                                    0, 0);
+
+      size = rrc_eNB_generate_RRCConnectionReconfiguration_endc(&ctxt, ue_context, buffer, 8192, scg_CellGroupConfig, nr1_conf);
+
+      rrc_data_req(&ctxt,
+                   DCCH,
+                   rrc_eNB_mui++,
+                   SDU_CONFIRM_NO,
+                   size,
+                   buffer,
+                   PDCP_TRANSMISSION_MODE_CONTROL);
+    } else {
+      LOG_E(F1AP, "no ue_context for RNTI %x, acknowledging release\n", m->rnti);
+    }
 
-  PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt,
-                                0,
-                                ENB_FLAG_YES,
-                                m->rnti,
-                                0, 0);
-  size = rrc_eNB_generate_RRCConnectionReconfiguration_endc(&ctxt, ue_context, buffer, 8192, scg_CellGroupConfig, nr1_conf);
-  rrc_data_req(&ctxt,
-               DCCH,
-               rrc_eNB_mui++,
-               SDU_CONFIRM_NO,
-               size,
-               buffer,
-               PDCP_TRANSMISSION_MODE_CONTROL);
 }
 
-
 //-----------------------------------------------------------------------------
 void *rrc_enb_process_itti_msg(void *notUsed) {
   MessageDef                         *msg_p;
diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h
index eeb16c308742cea66728b32bfad2bf30ad4ae3d6..9a53a5bbe01b3f791fe580f794e0cc3323615be7 100644
--- a/openair2/RRC/NR/nr_rrc_defs.h
+++ b/openair2/RRC/NR/nr_rrc_defs.h
@@ -379,6 +379,8 @@ typedef struct {
   NR_BCCH_BCH_Message_t                     mib;
   int ssb_SubcarrierOffset;                  
   int pdsch_AntennaPorts;
+  int pusch_TargetSNRx10;
+  int pucch_TargetSNRx10;
   NR_BCCH_DL_SCH_Message_t                  *siblock1;
   NR_ServingCellConfigCommon_t              *servingcellconfigcommon;
   NR_CellGroupConfig_t                      *secondaryCellGroup[MAX_NR_RRC_UE_CONTEXTS];
diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c
index 1f341cfdf9c76c118d92c7594aa99f9e64bebb60..5721d05aee50455f4fa5cdef949f8757dec96d6f 100644
--- a/openair2/RRC/NR/rrc_gNB.c
+++ b/openair2/RRC/NR/rrc_gNB.c
@@ -186,6 +186,8 @@ static void init_NR_SI(gNB_RRC_INST *rrc) {
   rrc_mac_config_req_gNB(rrc->module_id,
                          rrc->carrier.ssb_SubcarrierOffset,
                          rrc->carrier.pdsch_AntennaPorts,
+                         rrc->carrier.pusch_TargetSNRx10,
+                         rrc->carrier.pucch_TargetSNRx10,
                          (NR_ServingCellConfigCommon_t *)rrc->carrier.servingcellconfigcommon,
                          0,
                          0, // WIP hardcoded rnti
@@ -265,6 +267,8 @@ char openair_rrc_gNB_configuration(const module_id_t gnb_mod_idP, gNB_RrcConfigu
   rrc->carrier.servingcellconfigcommon = configuration->scc;
   rrc->carrier.ssb_SubcarrierOffset = configuration->ssb_SubcarrierOffset;
   rrc->carrier.pdsch_AntennaPorts = configuration->pdsch_AntennaPorts;
+  rrc->carrier.pusch_TargetSNRx10 = configuration->pusch_TargetSNRx10;
+  rrc->carrier.pucch_TargetSNRx10 = configuration->pucch_TargetSNRx10;
   /// System Information INIT
   LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_FMT" Checking release \n",PROTOCOL_NR_RRC_CTXT_ARGS(&ctxt));
   init_NR_SI(rrc);
diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c
index 22e31aa48abf5f6e66a8919165ec6390f63e8be9..78f39c16d7297f3cded998a19fe788b126fb0bc0 100644
--- a/openair2/RRC/NR/rrc_gNB_nsa.c
+++ b/openair2/RRC/NR/rrc_gNB_nsa.c
@@ -36,11 +36,34 @@
 //#include "NR_UE-CapabilityRAT-ContainerList.h"
 #include "LTE_UE-CapabilityRAT-ContainerList.h"
 #include "NR_CG-Config.h"
+//#include "NR_SRB-ToAddModList.h"
 #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
 #include "openair2/RRC/LTE/rrc_eNB_GTPV1U.h"
 #include "executables/softmodem-common.h"
 #include <openair2/RRC/NR/rrc_gNB_UE_context.h>
 
+extern boolean_t nr_rrc_pdcp_config_asn1_req(
+    const protocol_ctxt_t *const  ctxt_pP,
+    NR_SRB_ToAddModList_t  *const srb2add_list,
+    NR_DRB_ToAddModList_t  *const drb2add_list,
+    NR_DRB_ToReleaseList_t *const drb2release_list,
+    const uint8_t                   security_modeP,
+    uint8_t                  *const kRRCenc,
+    uint8_t                  *const kRRCint,
+    uint8_t                  *const kUPenc
+  #if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0))
+    ,LTE_PMCH_InfoList_r9_t  *pmch_InfoList_r9
+  #endif
+    ,rb_id_t                 *const defaultDRB,
+    struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list);
+
+extern rlc_op_status_t nr_rrc_rlc_config_asn1_req (const protocol_ctxt_t   * const ctxt_pP,
+    const NR_SRB_ToAddModList_t   * const srb2add_listP,
+    const NR_DRB_ToAddModList_t   * const drb2add_listP,
+    const NR_DRB_ToReleaseList_t  * const drb2release_listP,
+    const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP,
+    struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list);
+
 void rrc_parse_ue_capabilities(gNB_RRC_INST *rrc, LTE_UE_CapabilityRAT_ContainerList_t *UE_CapabilityRAT_ContainerList, x2ap_ENDC_sgnb_addition_req_t *m, NR_CG_ConfigInfo_IEs_t  *cg_config_info) {
   struct rrc_gNB_ue_context_s        *ue_context_p = NULL;
 
@@ -238,10 +261,33 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
   rrc_mac_config_req_gNB(rrc->module_id,
                          rrc->carrier.ssb_SubcarrierOffset,
                          rrc->carrier.pdsch_AntennaPorts,
+                         rrc->carrier.pusch_TargetSNRx10,
+                         rrc->carrier.pucch_TargetSNRx10,
                          NULL,
                          1, // add_ue flag
                          ue_context_p->ue_id_rnti,
                          ue_context_p->ue_context.secondaryCellGroup);
+
+  nr_rrc_pdcp_config_asn1_req(
+    &ctxt,
+    (NR_SRB_ToAddModList_t *) NULL,
+    ue_context_p->ue_context.rb_config->drb_ToAddModList ,
+    ue_context_p->ue_context.rb_config->drb_ToReleaseList,
+    0xff,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList);
+
+  nr_rrc_rlc_config_asn1_req (&ctxt,
+      (NR_SRB_ToAddModList_t *) NULL,
+      ue_context_p->ue_context.rb_config->drb_ToAddModList,
+      ue_context_p->ue_context.rb_config->drb_ToReleaseList,
+      (LTE_PMCH_InfoList_r9_t *) NULL,
+      ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList);
+
 }
 
 
diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c
index 6ea6f3b3b33181ba9944a27df61963b92797f22c..b8962051d8442a2b9a4de073186cc2d1834460b6 100644
--- a/openair2/RRC/NR/rrc_gNB_reconfig.c
+++ b/openair2/RRC/NR/rrc_gNB_reconfig.c
@@ -66,6 +66,22 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
   RLC_BearerConfig->reestablishRLC=calloc(1,sizeof(*RLC_BearerConfig->reestablishRLC));
   *RLC_BearerConfig->reestablishRLC=NR_RLC_BearerConfig__reestablishRLC_true;
   RLC_BearerConfig->rlc_Config=calloc(1,sizeof(*RLC_BearerConfig->rlc_Config));
+
+#if 0
+
+  // RLC UM Bi-directional Bearer configuration 
+  RLC_BearerConfig->rlc_Config->present = NR_RLC_Config_PR_um_Bi_Directional;
+  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional));
+  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength));
+  *RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength   =    NR_SN_FieldLengthUM_size12;
+
+  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength));
+  *RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength   =    NR_SN_FieldLengthUM_size12;
+  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = NR_T_Reassembly_ms15;
+
+#else
+
+  // RLC AM Bearer configuration
   RLC_BearerConfig->rlc_Config->present = NR_RLC_Config_PR_am;
   RLC_BearerConfig->rlc_Config->choice.am = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am));
   RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength));
@@ -78,6 +94,9 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
   *RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18;
   RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.t_Reassembly   = NR_T_Reassembly_ms15;
   RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15;
+
+#endif
+
   RLC_BearerConfig->mac_LogicalChannelConfig = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig));
   RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters));
   RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->priority            = 1;
@@ -150,9 +169,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
   secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions= calloc(1,sizeof(struct NR_CFRA__occasions));
   memcpy(&secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->rach_ConfigGeneric,
          &servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric, sizeof(NR_RACH_ConfigGeneric_t));
-  //secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->ssb_perRACH_Occasion= calloc(1,sizeof(long));
-  //*secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->ssb_perRACH_Occasion = NR_CFRA__occasions__ssb_perRACH_Occasion_one;
-  secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->ssb_perRACH_Occasion= NULL;
+  secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->ssb_perRACH_Occasion= calloc(1,sizeof(long));
+  *secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->ssb_perRACH_Occasion = NR_CFRA__occasions__ssb_perRACH_Occasion_one;
   secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.present = NR_CFRA__resources_PR_ssb;
   secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb = calloc(1,sizeof(struct NR_CFRA__resources__ssb));
   secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ra_ssb_OccasionMaskIndex = 0;
@@ -2047,7 +2065,7 @@ void fill_default_rbconfig(NR_RadioBearerConfig_t *rbconfig) {
   NR_DRB_ToAddMod_t *drb_ToAddMod = calloc(1,sizeof(*drb_ToAddMod));
   drb_ToAddMod->cnAssociation = calloc(1,sizeof(*drb_ToAddMod->cnAssociation));
   drb_ToAddMod->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity;
-  drb_ToAddMod->cnAssociation->choice.eps_BearerIdentity=5;
+  drb_ToAddMod->cnAssociation->choice.eps_BearerIdentity= 5;
   drb_ToAddMod->drb_Identity = 1;
   drb_ToAddMod->reestablishPDCP = NULL;
   drb_ToAddMod->recoverPDCP = NULL;
diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h
index d086c0e13a08b95955da404c840b6729b59f4141..778c8165eb8b5b9198745834231c29fecc7c77af 100644
--- a/targets/ARCH/COMMON/common_lib.h
+++ b/targets/ARCH/COMMON/common_lib.h
@@ -90,6 +90,8 @@ typedef enum {
   USRP_B200_DEV,
   /*!\brief device is USRP X300/X310*/
   USRP_X300_DEV,
+  /*!\brief device is USRP N300/N310*/
+  USRP_N300_DEV,
   /*!\brief device is BLADE RF*/
   BLADERF_DEV,
   /*!\brief device is LMSSDR (SoDeRa)*/
@@ -104,7 +106,7 @@ typedef enum {
   UEDv2_DEV,
   MAX_RF_DEV_TYPE
 } dev_type_t;
-#define DEVTYPE_NAMES {"","EXMIMO","USRP B200","USRP X300","BLADERF","LMSSDR","IRIS","No HW","ADRV9371_ZC706","UEDv2"} 
+#define DEVTYPE_NAMES {"","EXMIMO","USRP B200","USRP X300","USRP N300","BLADERF","LMSSDR","IRIS","No HW","ADRV9371_ZC706","UEDv2"} 
 /*!\brief transport protocol types
  */
 typedef enum {
@@ -434,6 +436,11 @@ struct openair0_device_t {
    * \param arg pointer to capabilities or configuration
    */
   int (*trx_write_init)(openair0_device *device);
+  /* \brief Get internal parameter
+   * \param id parameter to get
+   * \return a pointer to the parameter
+   */
+  void *(*get_internal_parameter)(char *id);
 };
 
 /* type of device init function, implemented in shared lib */
diff --git a/targets/ARCH/ETHERNET/benetel/4g/benetel.c b/targets/ARCH/ETHERNET/benetel/4g/benetel.c
new file mode 100644
index 0000000000000000000000000000000000000000..37f55c689fe1c31ae377f8c4a468d2660130186c
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/4g/benetel.c
@@ -0,0 +1,386 @@
+/*
+ * 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 <stdio.h>
+
+#include "common_lib.h"
+#include "ethernet_lib.h"
+#include "shared_buffers.h"
+#include "low.h"
+#include "common/utils/LOG/log.h"
+#include "common/utils/LOG/vcd_signal_dumper.h"
+
+typedef struct {
+  eth_state_t           e;
+  shared_buffers        buffers;
+  rru_config_msg_type_t last_msg;
+  int                   capabilities_sent;
+  void                  *benetel_priv;
+  char                  *dpdk_main_command_line;
+} benetel_eth_state_t;
+
+int trx_benetel_start(openair0_device *device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return 0;
+}
+
+
+void trx_benetel_end(openair0_device *device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+}
+
+
+int trx_benetel_stop(openair0_device *device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int trx_benetel_set_freq(openair0_device* device,
+                         openair0_config_t *openair0_cfg,
+                         int exmimo_dump_config)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int trx_benetel_set_gains(openair0_device* device,
+                          openair0_config_t *openair0_cfg)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int trx_benetel_get_stats(openair0_device* device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int trx_benetel_reset_stats(openair0_device* device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int ethernet_tune(openair0_device *device,
+                  unsigned int option,
+                  int value)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return 0;
+}
+
+int trx_benetel_write_raw(openair0_device *device,
+                          openair0_timestamp timestamp,
+                          void **buff, int nsamps, int cc, int flags)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return nsamps*4;
+}
+
+int trx_benetel_read_raw(openair0_device *device,
+                         openair0_timestamp *timestamp,
+                         void **buff, int nsamps, int cc)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return nsamps*4;
+}
+
+char *msg_type(int t)
+{
+  static char *s[12] = {
+    "RAU_tick",
+    "RRU_capabilities",
+    "RRU_config",
+    "RRU_config_ok",
+    "RRU_start",
+    "RRU_stop",
+    "RRU_sync_ok",
+    "RRU_frame_resynch",
+    "RRU_MSG_max_num",
+    "RRU_check_sync",
+    "RRU_config_update",
+    "RRU_config_update_ok",
+  };
+
+  if (t < 0 || t > 11) return "UNKNOWN";
+  return s[t];
+}
+
+int trx_benetel_ctlsend(openair0_device *device, void *msg, ssize_t msg_len)
+{
+  RRU_CONFIG_msg_t *rru_config_msg = msg;
+  benetel_eth_state_t *s = device->priv;
+
+  printf("BENETEL: %s\n", __FUNCTION__);
+
+  printf("    rru_config_msg->type %d [%s]\n", rru_config_msg->type,
+         msg_type(rru_config_msg->type));
+
+  s->last_msg = rru_config_msg->type;
+
+  return msg_len;
+}
+
+int trx_benetel_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
+{
+  RRU_CONFIG_msg_t *rru_config_msg = msg;
+  benetel_eth_state_t *s = device->priv;
+
+  printf("BENETEL: %s\n", __FUNCTION__);
+
+  if (s->last_msg == RAU_tick && s->capabilities_sent == 0) {
+    RRU_capabilities_t *cap;
+    rru_config_msg->type = RRU_capabilities;
+    rru_config_msg->len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
+    cap = (RRU_capabilities_t*)&rru_config_msg->msg[0];
+    cap->FH_fmt                           = OAI_IF4p5_only;
+    cap->num_bands                        = 1;
+    cap->band_list[0]                     = 7;
+    cap->nb_rx[0]                         = 1;
+    cap->nb_tx[0]                         = 1;
+    cap->max_pdschReferenceSignalPower[0] = -27;
+    cap->max_rxgain[0]                    = 90;
+
+    s->capabilities_sent = 1;
+
+    return rru_config_msg->len;
+  }
+  if (s->last_msg == RRU_config) {
+    rru_config_msg->type = RRU_config_ok;
+    return 0;
+  }
+  if (s->last_msg == RRU_start) {
+    s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line);
+  }
+  /* correct? */
+  while (1) pause();
+
+  return 0;
+}
+
+void benetel_fh_if4p5_south_in(RU_t *ru,
+                               int *frame,
+                               int *subframe)
+{
+  benetel_eth_state_t *s = ru->ifdevice.priv;
+  PHY_VARS_eNB **eNB_list = ru->eNB_list, *eNB;
+  LTE_DL_FRAME_PARMS *fp;
+  int symbol;
+  int32_t *rxdata;
+  int antenna = 0;
+
+  lock_ul_buffer(&s->buffers, *subframe);
+next:
+  while (!(s->buffers.ul_busy[*subframe] == 0x3fff ||
+           s->buffers.prach_busy[*subframe] == 1))
+    wait_ul_buffer(&s->buffers, *subframe);
+  if (s->buffers.prach_busy[*subframe] == 1) {
+    int i;
+    int antenna = 0;
+    uint16_t *in;
+    uint16_t *out;
+    in = (uint16_t *)s->buffers.prach[*subframe];
+    out = (uint16_t *)ru->prach_rxsigF[antenna];
+    for (i = 0; i < 840*2; i++)
+      out[i] = ntohs(in[i]);
+    s->buffers.prach_busy[*subframe] = 0;
+    ru->wakeup_prach_eNB(ru->eNB_list[0], ru, *frame, *subframe);
+    goto next;
+  }
+
+  eNB = eNB_list[0];
+  fp  = &eNB->frame_parms;
+  for (symbol = 0; symbol < 14; symbol++) {
+    int i;
+    uint16_t *p = (uint16_t *)(&s->buffers.ul[*subframe][symbol*1200*4]);
+    for (i = 0; i < 1200*2; i++) {
+      p[i] = htons(p[i]);
+    }
+    rxdata = &ru->common.rxdataF[antenna][symbol * fp->ofdm_symbol_size];
+#if 1
+    memcpy(rxdata + 2048 - 600,
+           &s->buffers.ul[*subframe][symbol*1200*4],
+           600 * 4);
+    memcpy(rxdata,
+           &s->buffers.ul[*subframe][symbol*1200*4] + 600*4,
+           600 * 4);
+#endif
+  }
+
+  s->buffers.ul_busy[*subframe] = 0;
+  signal_ul_buffer(&s->buffers, *subframe);
+  unlock_ul_buffer(&s->buffers, *subframe);
+
+  //printf("BENETEL: %s (f.sf %d.%d)\n", __FUNCTION__, *frame, *subframe);
+
+  RU_proc_t *proc = &ru->proc;
+  extern uint16_t sf_ahead;
+  int f = *frame;
+  int sf = *subframe;
+
+  //calculate timestamp_rx, timestamp_tx based on frame and subframe
+  proc->tti_rx       = sf;
+  proc->frame_rx     = f;
+  proc->timestamp_rx = ((proc->frame_rx * 10)  + proc->tti_rx ) * fp->samples_per_tti ;
+
+  if (get_nprocs()<=4) {
+    proc->tti_tx   = (sf+sf_ahead)%10;
+    proc->frame_tx = (sf>(9-sf_ahead)) ? (f+1)&1023 : f;
+  }
+
+  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_IF4P5_SOUTH_IN_RU+ru->idx,f);
+  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_IF4P5_SOUTH_IN_RU+ru->idx,sf);
+  proc->symbol_mask[sf] = 0;
+  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff);
+
+}
+
+void benetel_fh_if4p5_south_out(RU_t *ru,
+                                int frame,
+                                int subframe,
+                                uint64_t timestamp)
+{
+  benetel_eth_state_t *s = ru->ifdevice.priv;
+  PHY_VARS_eNB **eNB_list = ru->eNB_list, *eNB;
+  LTE_DL_FRAME_PARMS *fp;
+  int symbol;
+  int32_t *txdata;
+  int aa = 0;
+
+  //printf("BENETEL: %s (f.sf %d.%d ts %ld)\n", __FUNCTION__, frame, subframe, timestamp);
+
+  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
+
+  lock_dl_buffer(&s->buffers, subframe);
+  if (s->buffers.dl_busy[subframe]) {
+    printf("%s: fatal: DL buffer busy for subframe %d\n", __FUNCTION__, subframe);
+     unlock_dl_buffer(&s->buffers, subframe);
+    return;
+  }
+  eNB = eNB_list[0];
+  fp  = &eNB->frame_parms;
+  if (ru->num_eNB != 1 || ru->nb_tx != 1 || fp->ofdm_symbol_size != 2048 ||
+      fp->Ncp != NORMAL || fp->symbols_per_tti != 14) {
+    printf("%s:%d:%s: unsupported configuration\n",
+           __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  for (symbol = 0; symbol < 14; symbol++) {
+    txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size];
+#if 1
+    memcpy(&s->buffers.dl[subframe][symbol*1200*4],
+           txdata + 2048 - 600,
+           600 * 4);
+    memcpy(&s->buffers.dl[subframe][symbol*1200*4] + 600*4,
+           txdata + 1,
+           600 * 4);
+#endif
+    int i;
+    uint16_t *p = (uint16_t *)(&s->buffers.dl[subframe][symbol*1200*4]);
+    for (i = 0; i < 1200*2; i++) {
+      p[i] = htons(p[i]);
+    }
+  }
+
+  s->buffers.dl_busy[subframe] = 0x3fff;
+  unlock_dl_buffer(&s->buffers, subframe);
+
+  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_IF4P5_SOUTH_OUT_RU+ru->idx, ru->proc.frame_tx);
+  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_IF4P5_SOUTH_OUT_RU+ru->idx, ru->proc.tti_tx);
+
+}
+
+void *get_internal_parameter(char *name)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+
+  if (!strcmp(name, "fh_if4p5_south_in"))
+    return benetel_fh_if4p5_south_in;
+  if (!strcmp(name, "fh_if4p5_south_out"))
+    return benetel_fh_if4p5_south_out;
+
+  return NULL;
+}
+
+__attribute__((__visibility__("default")))
+int transport_init(openair0_device *device,
+                   openair0_config_t *openair0_cfg,
+                   eth_params_t * eth_params )
+{
+  benetel_eth_state_t *eth;
+
+  printf("BENETEL: %s\n", __FUNCTION__);
+
+  device->Mod_id               = 0;
+  device->transp_type          = ETHERNET_TP;
+  device->trx_start_func       = trx_benetel_start;
+  device->trx_get_stats_func   = trx_benetel_get_stats;
+  device->trx_reset_stats_func = trx_benetel_reset_stats;
+  device->trx_end_func         = trx_benetel_end;
+  device->trx_stop_func        = trx_benetel_stop;
+  device->trx_set_freq_func    = trx_benetel_set_freq;
+  device->trx_set_gains_func   = trx_benetel_set_gains;
+
+  device->trx_write_func       = trx_benetel_write_raw;
+  device->trx_read_func        = trx_benetel_read_raw;
+
+  device->trx_ctlsend_func     = trx_benetel_ctlsend;
+  device->trx_ctlrecv_func     = trx_benetel_ctlrecv;
+
+  device->get_internal_parameter = get_internal_parameter;
+
+  eth = calloc(1, sizeof(benetel_eth_state_t));
+  if (eth == NULL) {
+    AssertFatal(0==1, "out of memory\n");
+  }
+
+  eth->e.flags = ETH_RAW_IF4p5_MODE;
+  eth->e.compression = NO_COMPRESS;
+  eth->e.if_name = eth_params->local_if_name;
+  device->priv = eth;
+  device->openair0_cfg=&openair0_cfg[0];
+
+  if (openair0_cfg->sdr_addrs == NULL) {
+    printf("benetel: fatal: sdr_addrs not set in configuration file\n");
+    exit(1);
+  }
+
+  eth->dpdk_main_command_line = strdup(openair0_cfg->sdr_addrs);
+  if (eth->dpdk_main_command_line == NULL) {
+    AssertFatal(0==1, "out of memory\n");
+  }
+
+  eth->last_msg = -1;
+
+  init_buffers(&eth->buffers);
+
+  return 0;
+}
diff --git a/targets/ARCH/ETHERNET/benetel/4g/dpdk_driver.c b/targets/ARCH/ETHERNET/benetel/4g/dpdk_driver.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b64f01d447ebf8cbaa293d1c09ba33e143a6dc6
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/4g/dpdk_driver.c
@@ -0,0 +1,787 @@
+/* license: to be defined */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_eal.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+
+#include "low.h"
+
+// HEADER DEFINITION
+#define ANT_NUM buf[23]
+#define PAYLOAD_1 buf[20]
+#define PAYLOAD_2 buf[21]
+#define ETH_TYPE buf[17]
+#define SYMBOL buf[29]
+#define SUBFRAME buf[28]
+#define FRAME buf[27]
+
+static volatile bool force_quit;
+
+unsigned short iq[33600];
+unsigned char iq_swap[67200];
+
+unsigned short *iq_ptr[14];
+unsigned int dl_start = 0;
+
+/* MAC updating enabled by default */
+static int mac_updating = 1;
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 5 /* TX drain every ~100us */
+#define MEMPOOL_CACHE_SIZE 256
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 1024
+#define RTE_TEST_TX_DESC_DEFAULT 1024
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+        unsigned n_rx_port;
+        unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
+static struct rte_eth_conf port_conf = {
+        .rxmode = {
+                .split_hdr_size = 0,
+                .offloads = DEV_RX_OFFLOAD_CRC_STRIP,        
+				.offloads       = DEV_RX_OFFLOAD_JUMBO_FRAME,
+				.split_hdr_size = 0,
+				.max_rx_pkt_len = 9500,	
+        },
+        .txmode = {
+                .mq_mode = ETH_MQ_TX_NONE,
+        },
+};
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+        uint64_t tx;
+        uint64_t rx;
+        uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* A tsc-based timer responsible for triggering statistics printout */
+static uint64_t timer_period = 10; /* default period is 10 seconds */
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+        uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+        unsigned portid;
+        total_packets_dropped = 0;
+        total_packets_tx = 0;
+        total_packets_rx = 0;
+        const char clr[] = { 27, '[', '2', 'J', '\0' };
+        const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+                /* Clear screen and move to top left */
+        printf("%s%s", clr, topLeft);
+        printf("\nPort statistics ====================================");
+        for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+                /* skip disabled ports */
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+                        continue;
+                printf("\nStatistics for port %u ------------------------------"
+                           "\nPackets sent: %24"PRIu64
+                           "\nPackets received: %20"PRIu64
+                           "\nPackets dropped: %21"PRIu64,
+                           portid,
+                           port_statistics[portid].tx,
+                           port_statistics[portid].rx,
+                           port_statistics[portid].dropped);
+                total_packets_dropped += port_statistics[portid].dropped;
+                total_packets_tx += port_statistics[portid].tx;
+                total_packets_rx += port_statistics[portid].rx;
+        }
+        printf("\nAggregate statistics ==============================="
+                   "\nTotal packets sent: %18"PRIu64
+                   "\nTotal packets received: %14"PRIu64
+                   "\nTotal packets dropped: %15"PRIu64,
+                   total_packets_tx,
+                   total_packets_rx,
+                   total_packets_dropped);
+        printf("\n====================================================\n");
+}
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid, benetel_t *bs)
+{
+	unsigned char *buf, *buf_tx;
+	unsigned int len;
+	struct ether_hdr *eth;
+
+	unsigned dst_port;
+	int sent, prach_ctrl = 0;
+	struct rte_eth_dev_tx_buffer *buffer;
+
+	unsigned char * IQ_ptr;
+
+        ul_packet_t p;
+
+	buf = rte_pktmbuf_mtod(m, unsigned char *);
+	//rte_memdump(stdout, "Rx Packet",buf ,34);
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+	len = rte_pktmbuf_data_len(m);
+
+	IQ_ptr = &buf[34];
+
+	//destination mac address (RRU MAC)
+	eth->d_addr.addr_bytes[0] = 0x02;
+	eth->d_addr.addr_bytes[1] = 0x00;
+	eth->d_addr.addr_bytes[2] = 0x5e;
+	eth->d_addr.addr_bytes[3] = 0x01;
+	eth->d_addr.addr_bytes[4] = 0x01;
+	eth->d_addr.addr_bytes[5] = 0x01;
+
+	//source mac address (DU MAC)
+	eth->s_addr.addr_bytes[0] = 0xdd;
+	eth->s_addr.addr_bytes[1] = 0xdd;
+	eth->s_addr.addr_bytes[2] = 0xdd;
+	eth->s_addr.addr_bytes[3] = 0xdd;
+	eth->s_addr.addr_bytes[4] = 0xdd;
+	eth->s_addr.addr_bytes[5] = 0xdd;
+
+	dst_port = l2fwd_dst_ports[portid];
+         #if 1 
+	 
+		if (buf[18] == 0xAA) //msg1 check
+		{
+			printf("\nHandshake MSG 1 Received\n");
+			printf("\n====================================================\n");
+
+			buf[18] = 0xBB;//change to msg2 after receive msg1
+
+			printf("Handshake MSG 2 Sent\n");
+			printf("\n====================================================\n");
+		}
+
+         #else
+	// Handshake Condition
+	if (buf[18] == 0x01 || buf[18] == 0x03) // ORAN handshake msgs.
+	{
+		if (buf[18] == 0x01) //msg1 check
+		{
+			printf("\nHandshake MSG 1 Received\n");
+			printf("\n====================================================\n");
+
+			buf[18] = 0x02;//change to msg2 after receive msg1
+
+			printf("Handshake MSG 2 Sent\n");
+			printf("\n====================================================\n");
+		}
+
+		else if(buf[18] == 0x03) //msg3 check
+		{
+			printf("Handshake MSG 3 Sent\n");
+			printf("\n====================================================\n");
+
+			buf[18] = 0x04;
+
+			printf("Handshake MSG 4 Sent\n");
+			printf("\n====================================================\n");
+		}
+	}
+        #endif
+	// Trigger start send DL packets
+	if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && SYMBOL == 0x09 && ANT_NUM == 0x00 && dl_start == 0){
+
+		printf("\nU-Plane Started\n");
+		printf("\n====================================================\n");
+
+		dl_start = 1;
+	}
+
+
+	if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x00) {
+          p.frame = FRAME;
+          p.subframe = SUBFRAME >> 4;
+          p.slot = 0; /* unused */
+          p.symbol = SYMBOL;
+          p.antenna = 0;
+          memcpy(p.iq, IQ_ptr, 4800);
+          store_ul(bs, &p);
+        }
+
+	// U-PLANE UL ANT_0 PROCESSING
+	if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x00 && dl_start == 1)
+	{
+                int tx_frame = FRAME;
+                int tx_subframe = SUBFRAME >> 4;
+                int tx_symbol = SYMBOL + 5;
+                if (tx_symbol > 13) {
+                  tx_symbol -= 14;
+                  tx_subframe++;
+                  if (tx_subframe == 10) {
+                    tx_subframe = 0;
+                    tx_frame = (tx_frame + 1) & 255;
+                  }
+                }
+
+//		ANT_NUM = 0x00;
+//		SYMBOL = (SYMBOL + 5) % 14;
+		PAYLOAD_2 = 0xc8;
+
+                FRAME = tx_frame;
+                SUBFRAME = tx_subframe << 4;
+                SYMBOL = tx_symbol;
+
+                /* antenna 0 - send actual DL data (if available) */
+                lock_dl_buffer(bs->buffers, tx_subframe);
+                if (!(bs->buffers->dl_busy[tx_subframe] & (1 << tx_symbol))) {
+                  printf("%s: warning, DL underflow (sf.symbol %d.%d)\n", __FUNCTION__,
+                         tx_subframe, tx_symbol);
+                  memset(IQ_ptr, 0, 1200 * 4);
+                } else {
+                  memcpy(IQ_ptr, bs->buffers->dl[tx_subframe] + tx_symbol * 1200*4,
+                         1200*4);
+                }
+                bs->buffers->dl_busy[tx_subframe] &= ~(1 << tx_symbol);
+                unlock_dl_buffer(bs->buffers, tx_subframe);
+
+		// fill DL Data for ant 0 with 0 value
+//		memset(IQ_ptr, 0, 4800);
+	}
+
+	// U-PLANE UL ANT_1 PROCESSING
+	else if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x01 && dl_start == 1)
+	{
+
+//		ANT_NUM = 0x01;
+		SYMBOL = (SYMBOL + 5) % 14;
+		PAYLOAD_2 = 0xc8;
+
+		// fill DL Data for ant 1 with 0 value
+		memset(IQ_ptr, 0, 4800);
+	}
+
+	// U-PLANE PRACH PROCESSING
+	else if(PAYLOAD_1 == 0x0d && PAYLOAD_2 == 0x28){
+                if (ANT_NUM == 0) {
+                  store_prach(bs, FRAME, SUBFRAME>>4, IQ_ptr);
+                }
+
+		rte_pktmbuf_free(m);
+		return;
+	}
+
+	// Send Packets
+	buffer = tx_buffer[dst_port];
+
+	sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
+
+	if (sent)
+		port_statistics[dst_port].tx += sent;
+
+}
+/* main processing loop */
+static void
+l2fwd_main_loop(benetel_t *bs)
+{
+        struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+        struct rte_mbuf *m;
+        int sent;
+        unsigned lcore_id;
+        uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+        unsigned i, j, portid, nb_rx;
+        struct lcore_queue_conf *qconf;
+        const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
+                        BURST_TX_DRAIN_US;
+        struct rte_eth_dev_tx_buffer *buffer;
+        prev_tsc = 0;
+        timer_tsc = 0;
+        lcore_id = rte_lcore_id();
+        qconf = &lcore_queue_conf[lcore_id];
+        if (qconf->n_rx_port == 0) {
+                RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+                return;
+        }
+        RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+        for (i = 0; i < qconf->n_rx_port; i++) {
+                portid = qconf->rx_port_list[i];
+                RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+                        portid);
+        }
+        while (!force_quit) {
+                cur_tsc = rte_rdtsc();
+                /*
+                 * TX burst queue drain
+                 */
+                diff_tsc = cur_tsc - prev_tsc;
+                if (unlikely(diff_tsc > drain_tsc)) {
+                        for (i = 0; i < qconf->n_rx_port; i++) {
+                                portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
+                                buffer = tx_buffer[portid];
+                                sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
+                                if (sent)
+                                        port_statistics[portid].tx += sent;
+                        }
+                        /* if timer is enabled */
+                        if (timer_period > 0) {
+                                /* advance the timer */
+                                timer_tsc += diff_tsc;
+                                /* if timer has reached its timeout */
+                                if (unlikely(timer_tsc >= timer_period)) {
+                                        /* do this only on master core */
+                                        if (lcore_id == rte_get_master_lcore()) {
+                                                //print_stats();
+                                                /* reset the timer */
+                                                timer_tsc = 0;
+                                        }
+                                }
+                        }
+                        prev_tsc = cur_tsc;
+                }
+                /*
+                 * Read packet from RX queues
+                 */
+                for (i = 0; i < qconf->n_rx_port; i++) {
+                        portid = qconf->rx_port_list[i];
+                        nb_rx = rte_eth_rx_burst(portid, 0,
+                                                 pkts_burst, MAX_PKT_BURST);
+                        port_statistics[portid].rx += nb_rx;
+                        for (j = 0; j < nb_rx; j++) {
+                                m = pkts_burst[j];
+                                rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+                                l2fwd_simple_forward(m, portid, bs);
+                        }
+                }
+        }
+}
+static int
+l2fwd_launch_one_lcore(void *bs)
+{
+        l2fwd_main_loop(bs);
+        return 0;
+}
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+        printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+               "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+               "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+                   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
+                   "  --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
+                   "      When enabled:\n"
+                   "       - The source MAC address is replaced by the TX port MAC address\n"
+                   "       - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n",
+               prgname);
+}
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+        char *end = NULL;
+        unsigned long pm;
+        /* parse hexadecimal string */
+        pm = strtoul(portmask, &end, 16);
+        if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+                return -1;
+        if (pm == 0)
+                return -1;
+        return pm;
+}
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+        char *end = NULL;
+        unsigned long n;
+        /* parse hexadecimal string */
+        n = strtoul(q_arg, &end, 10);
+        if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+                return 0;
+        if (n == 0)
+                return 0;
+        if (n >= MAX_RX_QUEUE_PER_LCORE)
+                return 0;
+        return n;
+}
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+        char *end = NULL;
+        int n;
+        /* parse number string */
+        n = strtol(q_arg, &end, 10);
+        if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+                return -1;
+        if (n >= MAX_TIMER_PERIOD)
+                return -1;
+        return n;
+}
+static const char short_options[] =
+        "p:"  /* portmask */
+        "q:"  /* number of queues */
+        "T:"  /* timer period */
+        ;
+#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
+#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
+enum {
+        /* long options mapped to a short option */
+        /* first long only option value must be >= 256, so that we won't
+         * conflict with short options */
+        CMD_LINE_OPT_MIN_NUM = 256,
+};
+static const struct option lgopts[] = {
+        { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
+        { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
+        {NULL, 0, 0, 0}
+};
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+        int opt, ret, timer_secs;
+        char **argvopt;
+        int option_index;
+        char *prgname = argv[0];
+        argvopt = argv;
+        while ((opt = getopt_long(argc, argvopt, short_options,
+                                  lgopts, &option_index)) != EOF) {
+                switch (opt) {
+                /* portmask */
+                case 'p':
+                        l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+                        if (l2fwd_enabled_port_mask == 0) {
+                                printf("invalid portmask\n");
+                                l2fwd_usage(prgname);
+                                return -1;
+                        }
+                        break;
+                /* nqueue */
+                case 'q':
+                        l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+                        if (l2fwd_rx_queue_per_lcore == 0) {
+                                printf("invalid queue number\n");
+                                l2fwd_usage(prgname);
+                                return -1;
+                        }
+                        break;
+                /* timer period */
+                case 'T':
+                        timer_secs = l2fwd_parse_timer_period(optarg);
+                        if (timer_secs < 0) {
+                                printf("invalid timer period\n");
+                                l2fwd_usage(prgname);
+                                return -1;
+                        }
+                        timer_period = timer_secs;
+                        break;
+                /* long options */
+                case 0:
+                        break;
+                default:
+                        l2fwd_usage(prgname);
+                        return -1;
+                }
+        }
+        if (optind >= 0)
+                argv[optind-1] = prgname;
+        ret = optind-1;
+        optind = 1; /* reset getopt lib */
+        return ret;
+}
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+        uint16_t portid;
+        uint8_t count, all_ports_up, print_flag = 0;
+        struct rte_eth_link link;
+        printf("\nChecking link status");
+        fflush(stdout);
+        for (count = 0; count <= MAX_CHECK_TIME; count++) {
+                if (force_quit)
+                        return;
+                all_ports_up = 1;
+                RTE_ETH_FOREACH_DEV(portid) {
+                        if (force_quit)
+                                return;
+                        if ((port_mask & (1 << portid)) == 0)
+                                continue;
+                        memset(&link, 0, sizeof(link));
+                        rte_eth_link_get_nowait(portid, &link);
+                        /* print link status if flag set */
+                        if (print_flag == 1) {
+                                if (link.link_status)
+                                        printf(
+                                        "Port%d Link Up. Speed %u Mbps - %s\n",
+                                                portid, link.link_speed,
+                                (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+                                        ("full-duplex") : ("half-duplex\n"));
+                                else
+                                        printf("Port %d Link Down\n", portid);
+                                continue;
+                        }
+                        /* clear all_ports_up flag if any link down */
+                        if (link.link_status == ETH_LINK_DOWN) {
+                                all_ports_up = 0;
+                                break;
+                        }
+                }
+                /* after finally printing all link status, get out */
+                if (print_flag == 1)
+                        break;
+                if (all_ports_up == 0) {
+                        printf(".");
+                        fflush(stdout);
+                        rte_delay_ms(CHECK_INTERVAL);
+                }
+                /* set the print_flag if all ports up or timeout */
+                if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+                        print_flag = 1;
+                        printf("done\n");
+                }
+        }
+}
+static void
+signal_handler(int signum)
+{
+        if (signum == SIGINT || signum == SIGTERM) {
+                printf("\n\nSignal %d received, preparing to exit...\n",
+                                signum);
+                force_quit = true;
+        }
+}
+int
+dpdk_main(int argc, char **argv, benetel_t *bs)
+{
+        struct lcore_queue_conf *qconf;
+        int ret;
+        uint16_t nb_ports;
+        uint16_t nb_ports_available = 0;
+        uint16_t portid, last_port;
+        unsigned lcore_id, rx_lcore_id;
+        unsigned nb_ports_in_mask = 0;
+        unsigned int nb_lcores = 0;
+        unsigned int nb_mbufs;
+        /* init EAL */
+        ret = rte_eal_init(argc, argv);
+        if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+        argc -= ret;
+        argv += ret;
+        force_quit = false;
+        signal(SIGINT, signal_handler);
+        signal(SIGTERM, signal_handler);
+        /* parse application arguments (after the EAL ones) */
+        ret = l2fwd_parse_args(argc, argv);
+        if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+        printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
+        /* convert to number of cycles */
+        timer_period *= rte_get_timer_hz();
+        nb_ports = rte_eth_dev_count_avail();
+        if (nb_ports == 0)
+                rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+        /* check port mask to possible port mask */
+        if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
+                rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
+                        (1 << nb_ports) - 1);
+        /* reset l2fwd_dst_ports */
+        for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+                l2fwd_dst_ports[portid] = 0;
+        last_port = 0;
+        /*
+         * Each logical core is assigned a dedicated TX queue on each port.
+         */
+        RTE_ETH_FOREACH_DEV(portid) {
+                /* skip ports that are not enabled */
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+                        continue;
+                if (nb_ports_in_mask % 2) {
+                        l2fwd_dst_ports[portid] = last_port;
+                        l2fwd_dst_ports[last_port] = portid;
+                }
+                else
+                        last_port = portid;
+                nb_ports_in_mask++;
+        }
+        if (nb_ports_in_mask % 2) {
+                printf("Notice: odd number of ports in portmask.\n");
+                l2fwd_dst_ports[last_port] = last_port;
+        }
+        rx_lcore_id = 0;
+        qconf = NULL;
+        /* Initialize the port/queue configuration of each logical core */
+        RTE_ETH_FOREACH_DEV(portid) {
+                /* skip ports that are not enabled */
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+                        continue;
+                /* get the lcore_id for this port */
+                while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+                       lcore_queue_conf[rx_lcore_id].n_rx_port ==
+                       l2fwd_rx_queue_per_lcore) {
+                        rx_lcore_id++;
+                        if (rx_lcore_id >= RTE_MAX_LCORE)
+                                rte_exit(EXIT_FAILURE, "Not enough cores\n");
+                }
+                if (qconf != &lcore_queue_conf[rx_lcore_id]) {
+                        /* Assigned a new logical core in the loop above. */
+                        qconf = &lcore_queue_conf[rx_lcore_id];
+                        nb_lcores++;
+                }
+                qconf->rx_port_list[qconf->n_rx_port] = portid;
+                qconf->n_rx_port++;
+                printf("Lcore %u: RX port %u\n", rx_lcore_id, portid);
+        }
+        nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
+                nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
+        /* create the mbuf pool */
+        l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
+                MEMPOOL_CACHE_SIZE, 0, 9680,
+                rte_socket_id());
+        if (l2fwd_pktmbuf_pool == NULL)
+                rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+        /* Initialise each port */
+        RTE_ETH_FOREACH_DEV(portid) {
+                struct rte_eth_rxconf rxq_conf;
+                struct rte_eth_txconf txq_conf;
+                struct rte_eth_conf local_port_conf = port_conf;
+                struct rte_eth_dev_info dev_info;
+                /* skip ports that are not enabled */
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+                        printf("Skipping disabled port %u\n", portid);
+                        continue;
+                }
+                nb_ports_available++;
+                /* init port */
+                printf("Initializing port %u... ", portid);
+                fflush(stdout);
+                rte_eth_dev_info_get(portid, &dev_info);
+                if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
+                        local_port_conf.txmode.offloads |=
+                                DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+                ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+                                  ret, portid);
+                ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
+                                                       &nb_txd);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE,
+                                 "Cannot adjust number of descriptors: err=%d, port=%u\n",
+                                 ret, portid);
+                rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+                /* init one RX queue */
+                fflush(stdout);
+                rxq_conf = dev_info.default_rxconf;
+                rxq_conf.offloads = local_port_conf.rxmode.offloads;
+                ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+                                             rte_eth_dev_socket_id(portid),
+                                             &rxq_conf,
+                                             l2fwd_pktmbuf_pool);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+                                  ret, portid);
+                /* init one TX queue on each port */
+                fflush(stdout);
+                txq_conf = dev_info.default_txconf;
+                txq_conf.offloads = local_port_conf.txmode.offloads;
+                ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+                                rte_eth_dev_socket_id(portid),
+                                &txq_conf);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+                                ret, portid);
+                /* Initialize TX buffers */
+                tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
+                                RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
+                                rte_eth_dev_socket_id(portid));
+                if (tx_buffer[portid] == NULL)
+                        rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
+                                        portid);
+                rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
+                ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
+                                rte_eth_tx_buffer_count_callback,
+                                &port_statistics[portid].dropped);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE,
+                        "Cannot set error callback for tx buffer on port %u\n",
+                                 portid);
+                /* Start device */
+                ret = rte_eth_dev_start(portid);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
+                                  ret, portid);
+                printf("done: \n");
+                rte_eth_promiscuous_enable(portid);
+                printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
+                                portid,
+                                l2fwd_ports_eth_addr[portid].addr_bytes[0],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[1],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[2],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[3],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[4],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[5]);
+                /* initialize port stats */
+                memset(&port_statistics, 0, sizeof(port_statistics));
+        }
+        if (!nb_ports_available) {
+                rte_exit(EXIT_FAILURE,
+                        "All available ports are disabled. Please set portmask.\n");
+        }
+        check_all_ports_link_status(l2fwd_enabled_port_mask);
+        ret = 0;
+        /* launch per-lcore init on every lcore */
+        rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, bs, CALL_MASTER);
+        RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+                if (rte_eal_wait_lcore(lcore_id) < 0) {
+                        ret = -1;
+                        break;
+                }
+        }
+        RTE_ETH_FOREACH_DEV(portid) {
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+                        continue;
+                printf("Closing port %d...", portid);
+                rte_eth_dev_stop(portid);
+                rte_eth_dev_close(portid);
+                printf(" Done\n");
+        }
+        printf("Bye...\n");
+        return ret;
+}
diff --git a/targets/ARCH/ETHERNET/benetel/4g/low.c b/targets/ARCH/ETHERNET/benetel/4g/low.c
new file mode 100644
index 0000000000000000000000000000000000000000..038592d596c4cac0d21a4f1a79afe1014174f59c
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/4g/low.c
@@ -0,0 +1,95 @@
+/*
+ * 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 "low.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void store_ul(benetel_t *bs, ul_packet_t *ul)
+{
+  /* only antenna 0 for the moment */
+  if (ul->antenna != 0)
+    return;
+
+  if (ul->subframe != bs->next_subframe ||
+      ul->symbol != bs->next_symbol) {
+    printf("%s: fatal, expected frame.sf.symbol %d.%d.%d, got %d.%d.%d\n",
+           __FUNCTION__,
+           bs->expected_benetel_frame, bs->next_subframe, bs->next_symbol,
+           ul->frame, ul->subframe, ul->symbol);
+    exit(1);
+  }
+
+  lock_ul_buffer(bs->buffers, bs->next_subframe);
+  if (bs->buffers->ul_busy[bs->next_subframe] & (1 << bs->next_symbol)) {
+    printf("%s: warning, UL overflow (sf.symbol %d.%d)\n", __FUNCTION__,
+           bs->next_subframe, bs->next_symbol);
+  }
+  memcpy(bs->buffers->ul[bs->next_subframe] + bs->next_symbol * 1200*4,
+         ul->iq, 1200*4);
+  bs->buffers->ul_busy[bs->next_subframe] |= (1 << bs->next_symbol);
+  signal_ul_buffer(bs->buffers, bs->next_subframe);
+  unlock_ul_buffer(bs->buffers, bs->next_subframe);
+
+  bs->next_symbol++;
+  if (bs->next_symbol == 14) {
+    bs->next_symbol = 0;
+    bs->next_subframe = (bs->next_subframe + 1) % 10;
+    if (bs->next_subframe == 0) {
+      bs->expected_benetel_frame++;
+      bs->expected_benetel_frame &= 255;
+    }
+  }
+}
+
+void store_prach(benetel_t *bs, int frame, int subframe, void *data)
+{
+  static int last_frame = -1;
+  static int last_subframe = -1;
+  /* hack: antenna number is always 0, discard second packet with same f/sf */
+  if (frame == last_frame && subframe == last_subframe) return;
+  last_frame = frame;
+  last_subframe = subframe;
+
+  lock_ul_buffer(bs->buffers, subframe);
+  if (bs->buffers->prach_busy[subframe]) {
+    printf("store_prach: fatal: previous prach buffer not processed\n");
+    unlock_ul_buffer(bs->buffers, subframe);
+    return;
+  }
+  bs->buffers->prach_busy[subframe] = 1;
+  memcpy(bs->buffers->prach[subframe], data, 849*4);
+  signal_ul_buffer(bs->buffers, subframe);
+  unlock_ul_buffer(bs->buffers, subframe);
+
+}
+
+void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
+
+void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
+{
+  if (!strcmp(ifname, "dpdk"))
+    return benetel_start_dpdk(ifname, buffers, dpdk_main_command_line);
+  printf("benetel: fatal: interface %s not supported, only dpdpk is supported\n", ifname);
+  exit(1);
+}
diff --git a/targets/ARCH/ETHERNET/benetel/4g/low.h b/targets/ARCH/ETHERNET/benetel/4g/low.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e75d9181e84f06447a6631373c043fe3d9779eb
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/4g/low.h
@@ -0,0 +1,49 @@
+/*
+ * 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 _BENETEL_4G_LOW_H_
+#define _BENETEL_4G_LOW_H_
+
+#include "shared_buffers.h"
+
+typedef struct {
+  shared_buffers *buffers;
+  int            next_subframe;
+  int            next_symbol;
+  int            expected_benetel_frame;
+  char           *dpdk_main_command_line;
+} benetel_t;
+
+typedef struct {
+  int frame;
+  int subframe;
+  int slot;
+  int symbol;
+  int antenna;
+  unsigned char iq[4800];
+} ul_packet_t;
+
+void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
+
+void store_ul(benetel_t *bs, ul_packet_t *ul);
+void store_prach(benetel_t *bs, int frame, int subframe, void *data);
+
+#endif /* _BENETEL_4G_LOW_H_ */
diff --git a/targets/ARCH/ETHERNET/benetel/4g/low_dpdk.c b/targets/ARCH/ETHERNET/benetel/4g/low_dpdk.c
new file mode 100644
index 0000000000000000000000000000000000000000..ecff473010c34f1bfae5ab166ca3c83f663cb5b8
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/4g/low_dpdk.c
@@ -0,0 +1,118 @@
+/*
+ * 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
+ */
+
+/* those 2 lines for CPU_SET */
+#define _GNU_SOURCE
+#include <sched.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "low.h"
+
+int dpdk_main(int argc, char **argv, benetel_t *);
+
+void *dpdk_thread(void *_bs)
+{
+  benetel_t *bs = _bs;
+  int n = 0;
+  char **v = NULL; // { "softmodem", "-n", "2", "-l", "8", "--", "-p", "0x2" };
+  char *s = bs->dpdk_main_command_line;
+  char *tok;
+
+  while ((tok = strtok(s, " ")) != NULL) {
+    n++;
+    v = realloc(v, n * sizeof(char *));
+    if (v == NULL) {
+      printf("%s: out of memory\n", __FUNCTION__);
+      exit(1);
+    }
+    v[n-1] = tok;
+    s = NULL;
+  }
+
+  dpdk_main(n, v, bs);
+  exit(1);
+  return 0;
+}
+
+void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
+{
+  benetel_t *bs;
+
+  bs = calloc(1, sizeof(benetel_t));
+  if (bs == NULL) {
+    printf("%s: out of memory\n", __FUNCTION__);
+    exit(1);
+  }
+
+  bs->buffers = buffers;
+
+  bs->expected_benetel_frame = 255;
+
+  bs->dpdk_main_command_line = dpdk_main_command_line;
+
+  pthread_attr_t attr;
+
+  if (pthread_attr_init(&attr) != 0) {
+    printf("pthread_attr_init failed\n");
+    exit(1);
+  }
+
+  cpu_set_t cpuset;
+  CPU_ZERO(&cpuset);
+  CPU_SET(12,&cpuset);
+  if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset) != 0) {
+    printf("pthread_attr_setaffinity_np failed\n");
+    exit(1);
+  }
+
+  if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) {
+    printf("pthread_attr_setschedpolicy failed\n");
+    exit(1);
+  }
+
+  struct sched_param params;
+  params.sched_priority = sched_get_priority_max(SCHED_FIFO);
+  if (sched_get_priority_max(SCHED_FIFO) == -1) {
+    printf("sched_get_priority_max failed\n");
+    exit(1);
+  }
+  if (pthread_attr_setschedparam(&attr, &params) != 0) {
+    printf("pthread_setschedparam failed\n");
+    exit(1);
+  }
+
+  pthread_t t;
+  if (pthread_create(&t, &attr, dpdk_thread, bs) != 0) {
+    printf("%s: thread creation failed\n", __FUNCTION__);
+    exit(1);
+  }
+
+  if (pthread_attr_destroy(&attr) != 0) {
+    printf("pthread_attr_init failed\n");
+    exit(1);
+  }
+
+  return bs;
+}
diff --git a/targets/ARCH/ETHERNET/benetel/4g/shared_buffers.c b/targets/ARCH/ETHERNET/benetel/4g/shared_buffers.c
new file mode 100644
index 0000000000000000000000000000000000000000..492a15dfc3833e85b38d196b32903615f8618114
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/4g/shared_buffers.c
@@ -0,0 +1,114 @@
+/*
+ * 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 "shared_buffers.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void init_buffers(shared_buffers *s)
+{
+  int subframe;
+
+  memset(s, 0, sizeof(*s));
+
+  for (subframe = 0; subframe < 10; subframe++) {
+    if (pthread_mutex_init(&s->m_dl[subframe], NULL) != 0 ||
+        pthread_cond_init(&s->c_dl[subframe], NULL) != 0  ||
+        pthread_mutex_init(&s->m_ul[subframe], NULL) != 0 ||
+        pthread_cond_init(&s->c_ul[subframe], NULL) != 0) {
+      printf("%s: error initializing mutex/cond\n", __FUNCTION__);
+      exit(1);
+    }
+  }
+
+  /* in FDD the eNB's first transmitted DL subframe is 4 but the device
+   * needs to have subframes 1, 2 and 3 ready. Let's pretend there are ready.
+   */
+  s->dl_busy[1] = 0x3fff;
+  s->dl_busy[2] = 0x3fff;
+  s->dl_busy[3] = 0x3fff;
+}
+
+void lock_dl_buffer(shared_buffers *s, int subframe)
+{
+  if (pthread_mutex_lock(&s->m_dl[subframe]) != 0) {
+    printf("%s: fatal: lock fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void unlock_dl_buffer(shared_buffers *s, int subframe)
+{
+  if (pthread_mutex_unlock(&s->m_dl[subframe]) != 0) {
+    printf("%s: fatal: unlock fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void wait_dl_buffer(shared_buffers *s, int subframe)
+{
+  if (pthread_cond_wait(&s->c_dl[subframe], &s->m_dl[subframe]) != 0) {
+    printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void signal_dl_buffer(shared_buffers *s, int subframe)
+{
+  if (pthread_cond_broadcast(&s->c_dl[subframe]) != 0) {
+    printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void lock_ul_buffer(shared_buffers *s, int subframe)
+{
+  if (pthread_mutex_lock(&s->m_ul[subframe]) != 0) {
+    printf("%s: fatal: lock fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void unlock_ul_buffer(shared_buffers *s, int subframe)
+{
+  if (pthread_mutex_unlock(&s->m_ul[subframe]) != 0) {
+    printf("%s: fatal: unlock fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void wait_ul_buffer(shared_buffers *s, int subframe)
+{
+  if (pthread_cond_wait(&s->c_ul[subframe], &s->m_ul[subframe]) != 0) {
+    printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void signal_ul_buffer(shared_buffers *s, int subframe)
+{
+  if (pthread_cond_broadcast(&s->c_ul[subframe]) != 0) {
+    printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
diff --git a/targets/ARCH/ETHERNET/benetel/4g/shared_buffers.h b/targets/ARCH/ETHERNET/benetel/4g/shared_buffers.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d5040b95b55d3ef76fd6d40ede97f7ea686acca
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/4g/shared_buffers.h
@@ -0,0 +1,60 @@
+/*
+ * 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 _BENETEL_4G_SHARED_BUFFERS_H_
+#define _BENETEL_4G_SHARED_BUFFERS_H_
+
+#include <pthread.h>
+#include <stdint.h>
+
+typedef struct {
+  unsigned char dl[10][14*1200*4];
+  unsigned char ul[10][14*1200*4];
+  uint16_t dl_busy[10];
+  uint16_t ul_busy[10];
+
+  pthread_mutex_t m_ul[10];
+  pthread_cond_t  c_ul[10];
+
+  pthread_mutex_t m_dl[10];
+  pthread_cond_t  c_dl[10];
+
+  unsigned char prach[10][849*4];
+  unsigned char prach_busy[10];
+
+  /* statistics/error counting */
+  int ul_overflow;
+  int dl_underflow;
+} shared_buffers;
+
+void init_buffers(shared_buffers *s);
+
+void lock_dl_buffer(shared_buffers *s, int subframe);
+void unlock_dl_buffer(shared_buffers *s, int subframe);
+void wait_dl_buffer(shared_buffers *s, int subframe);
+void signal_dl_buffer(shared_buffers *s, int subframe);
+
+void lock_ul_buffer(shared_buffers *s, int subframe);
+void unlock_ul_buffer(shared_buffers *s, int subframe);
+void wait_ul_buffer(shared_buffers *s, int subframe);
+void signal_ul_buffer(shared_buffers *s, int subframe);
+
+#endif /* _BENETEL_4G_SHARED_BUFFERS_H_ */
diff --git a/targets/ARCH/ETHERNET/benetel/5g/benetel.c b/targets/ARCH/ETHERNET/benetel/5g/benetel.c
new file mode 100644
index 0000000000000000000000000000000000000000..c1ae1afcc79295c09478ab461f8d51becb308c57
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/5g/benetel.c
@@ -0,0 +1,388 @@
+/*
+ * 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 <stdio.h>
+
+#include "common_lib.h"
+#include "ethernet_lib.h"
+#include "shared_buffers.h"
+#include "low.h"
+#include "openair1/PHY/defs_gNB.h"
+
+typedef struct {
+  eth_state_t           e;
+  shared_buffers        buffers;
+  rru_config_msg_type_t last_msg;
+  int                   capabilities_sent;
+  void                  *benetel_priv;
+  char                  *dpdk_main_command_line;
+} benetel_eth_state_t;
+
+int trx_benetel_start(openair0_device *device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return 0;
+}
+
+
+void trx_benetel_end(openair0_device *device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+}
+
+
+int trx_benetel_stop(openair0_device *device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int trx_benetel_set_freq(openair0_device* device,
+                         openair0_config_t *openair0_cfg,
+                         int exmimo_dump_config)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int trx_benetel_set_gains(openair0_device* device,
+                          openair0_config_t *openair0_cfg)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int trx_benetel_get_stats(openair0_device* device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int trx_benetel_reset_stats(openair0_device* device)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return(0);
+}
+
+
+int ethernet_tune(openair0_device *device,
+                  unsigned int option,
+                  int value)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return 0;
+}
+
+int trx_benetel_write_raw(openair0_device *device,
+                          openair0_timestamp timestamp,
+                          void **buff, int nsamps, int cc, int flags)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return nsamps*4;
+}
+
+int trx_benetel_read_raw(openair0_device *device,
+                         openair0_timestamp *timestamp,
+                         void **buff, int nsamps, int cc)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+  return nsamps*4;
+}
+
+char *msg_type(int t)
+{
+  static char *s[12] = {
+    "RAU_tick",
+    "RRU_capabilities",
+    "RRU_config",
+    "RRU_config_ok",
+    "RRU_start",
+    "RRU_stop",
+    "RRU_sync_ok",
+    "RRU_frame_resynch",
+    "RRU_MSG_max_num",
+    "RRU_check_sync",
+    "RRU_config_update",
+    "RRU_config_update_ok",
+  };
+
+  if (t < 0 || t > 11) return "UNKNOWN";
+  return s[t];
+}
+
+int trx_benetel_ctlsend(openair0_device *device, void *msg, ssize_t msg_len)
+{
+  RRU_CONFIG_msg_t *rru_config_msg = msg;
+  benetel_eth_state_t *s = device->priv;
+
+  printf("BENETEL: %s\n", __FUNCTION__);
+
+  printf("    rru_config_msg->type %d [%s]\n", rru_config_msg->type,
+         msg_type(rru_config_msg->type));
+
+  s->last_msg = rru_config_msg->type;
+
+  return msg_len;
+}
+
+int trx_benetel_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
+{
+  RRU_CONFIG_msg_t *rru_config_msg = msg;
+  benetel_eth_state_t *s = device->priv;
+
+  printf("BENETEL: %s\n", __FUNCTION__);
+
+  if (s->last_msg == RAU_tick && s->capabilities_sent == 0) {
+    RRU_capabilities_t *cap;
+    rru_config_msg->type = RRU_capabilities;
+    rru_config_msg->len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
+    cap = (RRU_capabilities_t*)&rru_config_msg->msg[0];
+    cap->FH_fmt                           = OAI_IF4p5_only;
+    cap->num_bands                        = 1;
+    cap->band_list[0]                     = 78;
+    cap->nb_rx[0]                         = 1;
+    cap->nb_tx[0]                         = 1;
+    cap->max_pdschReferenceSignalPower[0] = -27;
+    cap->max_rxgain[0]                    = 90;
+
+    s->capabilities_sent = 1;
+
+    return rru_config_msg->len;
+  }
+#if 0
+  if (s->last_msg == RRU_config) {
+    rru_config_msg->type = RRU_config_ok;
+    return 0;
+  }
+  if (s->last_msg == RRU_start) {
+printf("***************** benetel start\n");
+    s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line);
+  }
+#endif
+  if (s->last_msg == RRU_config) {
+    rru_config_msg->type = RRU_config_ok;
+    s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line);
+  }
+  /* correct? */
+//printf("***************** benetel pause\n");
+//  while (1) pause();
+
+  return 0;
+}
+
+void benetel_fh_if4p5_south_in(RU_t *ru,
+                               int *frame,
+                               int *slot)
+{
+//printf("XXX benetel_fh_if4p5_south_in %d %d\n", *frame, *slot);
+  benetel_eth_state_t *s = ru->ifdevice.priv;
+  NR_DL_FRAME_PARMS *fp;
+  int symbol;
+  int32_t *rxdata;
+  int antenna = 0;
+
+  lock_ul_buffer(&s->buffers, *slot);
+#if 1
+next:
+  while (!(s->buffers.ul_busy[*slot] == 0x3fff ||
+           s->buffers.prach_busy[*slot] == 1))
+    wait_ul_buffer(&s->buffers, *slot);
+  if (s->buffers.prach_busy[*slot] == 1) {
+    int i;
+    int antenna = 0;
+    uint16_t *in;
+    uint16_t *out;
+    in = (uint16_t *)s->buffers.prach[*slot];
+    out = (uint16_t *)ru->prach_rxsigF[antenna];
+    for (i = 0; i < 839*2; i++)
+      out[i] = ntohs(in[i]);
+    s->buffers.prach_busy[*slot] = 0;
+    //printf("prach for f.sl %d.%d\n", *frame, *slot);
+    //ru->wakeup_prach_gNB(ru->gNB_list[0], ru, *frame, *slot);
+    goto next;
+  }
+#endif
+
+  fp = ru->nr_frame_parms;
+  for (symbol = 0; symbol < 14; symbol++) {
+    int i;
+    uint16_t *p = (uint16_t *)(&s->buffers.ul[*slot][symbol*1272*4]);
+    for (i = 0; i < 1272*2; i++) {
+      p[i] = htons(p[i]);
+    }
+    rxdata = &ru->common.rxdataF[antenna][symbol * fp->ofdm_symbol_size];
+#if 1
+    memcpy(rxdata + 2048 - 1272/2,
+           &s->buffers.ul[*slot][symbol*1272*4],
+           (1272/2) * 4);
+    memcpy(rxdata,
+           &s->buffers.ul[*slot][symbol*1272*4] + (1272/2)*4,
+           (1272/2) * 4);
+#endif
+  }
+
+  s->buffers.ul_busy[*slot] = 0;
+  signal_ul_buffer(&s->buffers, *slot);
+  unlock_ul_buffer(&s->buffers, *slot);
+
+  //printf("BENETEL: %s (f.sf %d.%d)\n", __FUNCTION__, *frame, *slot);
+
+  RU_proc_t *proc = &ru->proc;
+  extern uint16_t sl_ahead;
+  int f = *frame;
+  int sl = *slot;
+
+  //calculate timestamp_rx, timestamp_tx based on frame and slot
+  proc->tti_rx       = sl;
+  proc->frame_rx     = f;
+  /* TODO: be sure of samples_per_slot0
+  FK: should use get_samples_per_slot(slot)
+  but for mu=1 its ok
+  */
+  proc->timestamp_rx = ((proc->frame_rx * 20)  + proc->tti_rx ) * fp->samples_per_slot0;
+
+  if (get_nprocs()<=4) {
+    // why? what if there are more?
+    proc->tti_tx   = (sl+sl_ahead)%20;
+    proc->frame_tx = (sl>(19-sl_ahead)) ? (f+1)&1023 : f;
+  }
+}
+
+void benetel_fh_if4p5_south_out(RU_t *ru,
+                                int frame,
+                                int slot,
+                                uint64_t timestamp)
+{
+//printf("XXX benetel_fh_if4p5_south_out %d %d %ld\n", frame, slot, timestamp);
+  benetel_eth_state_t *s = ru->ifdevice.priv;
+  NR_DL_FRAME_PARMS *fp;
+  int symbol;
+  int32_t *txdata;
+  int aa = 0;
+
+  //printf("BENETEL: %s (f.sf %d.%d ts %ld)\n", __FUNCTION__, frame, slot, timestamp);
+
+  lock_dl_buffer(&s->buffers, slot);
+  if (s->buffers.dl_busy[slot]) {
+    printf("%s: fatal: DL buffer busy for subframe %d\n", __FUNCTION__, slot);
+    unlock_dl_buffer(&s->buffers, slot);
+    return;
+  }
+
+  fp = ru->nr_frame_parms;
+  if (ru->num_gNB != 1 || ru->nb_tx != 1 || fp->ofdm_symbol_size != 2048 ||
+      fp->Ncp != NORMAL || fp->symbols_per_slot != 14) {
+    printf("%s:%d:%s: unsupported configuration\n",
+           __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  for (symbol = 0; symbol < 14; symbol++) {
+    txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size];
+#if 1
+    memcpy(&s->buffers.dl[slot][symbol*1272*4],
+           txdata + 2048 - (1272/2),
+           (1272/2) * 4);
+    memcpy(&s->buffers.dl[slot][symbol*1272*4] + (1272/2)*4,
+           txdata,
+           (1272/2) * 4);
+#endif
+    int i;
+    uint16_t *p = (uint16_t *)(&s->buffers.dl[slot][symbol*1272*4]);
+    for (i = 0; i < 1272*2; i++) {
+      p[i] = htons(p[i]);
+    }
+  }
+
+  s->buffers.dl_busy[slot] = 0x3fff;
+  unlock_dl_buffer(&s->buffers, slot);
+}
+
+void *get_internal_parameter(char *name)
+{
+  printf("BENETEL: %s\n", __FUNCTION__);
+
+  if (!strcmp(name, "fh_if4p5_south_in"))
+    return benetel_fh_if4p5_south_in;
+  if (!strcmp(name, "fh_if4p5_south_out"))
+    return benetel_fh_if4p5_south_out;
+
+  return NULL;
+}
+
+__attribute__((__visibility__("default")))
+int transport_init(openair0_device *device,
+                   openair0_config_t *openair0_cfg,
+                   eth_params_t * eth_params )
+{
+  benetel_eth_state_t *eth;
+
+  printf("BENETEL: %s\n", __FUNCTION__);
+
+  device->Mod_id               = 0;
+  device->transp_type          = ETHERNET_TP;
+  device->trx_start_func       = trx_benetel_start;
+  device->trx_get_stats_func   = trx_benetel_get_stats;
+  device->trx_reset_stats_func = trx_benetel_reset_stats;
+  device->trx_end_func         = trx_benetel_end;
+  device->trx_stop_func        = trx_benetel_stop;
+  device->trx_set_freq_func    = trx_benetel_set_freq;
+  device->trx_set_gains_func   = trx_benetel_set_gains;
+
+  device->trx_write_func       = trx_benetel_write_raw;
+  device->trx_read_func        = trx_benetel_read_raw;
+
+  device->trx_ctlsend_func     = trx_benetel_ctlsend;
+  device->trx_ctlrecv_func     = trx_benetel_ctlrecv;
+
+  device->get_internal_parameter = get_internal_parameter;
+
+  eth = calloc(1, sizeof(benetel_eth_state_t));
+  if (eth == NULL) {
+    AssertFatal(0==1, "out of memory\n");
+  }
+
+  eth->e.flags = ETH_RAW_IF4p5_MODE;
+  eth->e.compression = NO_COMPRESS;
+  eth->e.if_name = eth_params->local_if_name;
+  device->priv = eth;
+  device->openair0_cfg=&openair0_cfg[0];
+
+  if (openair0_cfg->sdr_addrs == NULL) {
+    printf("benetel: fatal: sdr_addrs not set in configuration file\n");
+    exit(1);
+  }
+
+  eth->dpdk_main_command_line = strdup(openair0_cfg->sdr_addrs);
+  if (eth->dpdk_main_command_line == NULL) {
+    AssertFatal(0==1, "out of memory\n");
+  }
+
+  eth->last_msg = -1;
+
+  init_buffers(&eth->buffers);
+
+  return 0;
+}
diff --git a/targets/ARCH/ETHERNET/benetel/5g/dpdk_driver.c b/targets/ARCH/ETHERNET/benetel/5g/dpdk_driver.c
new file mode 100644
index 0000000000000000000000000000000000000000..b90702d33102512555b8db5e915593c77dee2d2c
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/5g/dpdk_driver.c
@@ -0,0 +1,856 @@
+/* license: to be defined */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_eal.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+
+#include "low.h"
+
+// HEADER DEFINITION
+#define ANT_NUM buf[23]
+#define PAYLOAD_1 buf[20]
+#define PAYLOAD_2 buf[21]
+#define ETH_TYPE buf[17]
+#define SYMBOL buf[29]
+#define SUBFRAME buf[28]
+#define FRAME buf[27]
+
+static volatile bool force_quit;
+
+unsigned short iq[712320];
+unsigned char iq_swap[1424640];
+
+unsigned short *iq_ptr[14];
+unsigned int dl_start = 0, slot_id_ctrl = 0, count_symbol = 0, sf = 0x10;
+
+/* MAC updating enabled by default */
+static int mac_updating = 1;
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 5 /* TX drain every ~100us */
+#define MEMPOOL_CACHE_SIZE 256
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 1024
+#define RTE_TEST_TX_DESC_DEFAULT 1024
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+        unsigned n_rx_port;
+        unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS];
+static struct rte_eth_conf port_conf = {
+        .rxmode = {
+                .split_hdr_size = 0,
+                .offloads = DEV_RX_OFFLOAD_CRC_STRIP,        
+				.offloads       = DEV_RX_OFFLOAD_JUMBO_FRAME,
+				.split_hdr_size = 0,
+				.max_rx_pkt_len = 9500,
+        },
+        .txmode = {
+                .mq_mode = ETH_MQ_TX_NONE,
+        },
+};
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+        uint64_t tx;
+        uint64_t rx;
+        uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+/* A tsc-based timer responsible for triggering statistics printout */
+static uint64_t timer_period = 10; /* default period is 10 seconds */
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+        uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+        unsigned portid;
+        total_packets_dropped = 0;
+        total_packets_tx = 0;
+        total_packets_rx = 0;
+        const char clr[] = { 27, '[', '2', 'J', '\0' };
+        const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+                /* Clear screen and move to top left */
+        printf("%s%s", clr, topLeft);
+        printf("\nPort statistics ====================================");
+        for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+                /* skip disabled ports */
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+                        continue;
+                printf("\nStatistics for port %u ------------------------------"
+                           "\nPackets sent: %24"PRIu64
+                           "\nPackets received: %20"PRIu64
+                           "\nPackets dropped: %21"PRIu64,
+                           portid,
+                           port_statistics[portid].tx,
+                           port_statistics[portid].rx,
+                           port_statistics[portid].dropped);
+                total_packets_dropped += port_statistics[portid].dropped;
+                total_packets_tx += port_statistics[portid].tx;
+                total_packets_rx += port_statistics[portid].rx;
+        }
+        printf("\nAggregate statistics ==============================="
+                   "\nTotal packets sent: %18"PRIu64
+                   "\nTotal packets received: %14"PRIu64
+                   "\nTotal packets dropped: %15"PRIu64,
+                   total_packets_tx,
+                   total_packets_rx,
+                   total_packets_dropped);
+        printf("\n====================================================\n");
+}
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid, benetel_t *bs)
+{
+	unsigned char *buf, *buf_tx;
+	unsigned int len;
+	struct ether_hdr *eth;
+
+	unsigned dst_port;
+	int sent, prach_ctrl = 0;
+	struct rte_eth_dev_tx_buffer *buffer;
+
+	unsigned char * IQ_ptr;
+
+        ul_packet_t p;
+
+	buf = rte_pktmbuf_mtod(m, unsigned char *);
+	//DD Debug
+	//rte_memdump(stdout, "Rx Packet",buf ,34);
+	eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+	len = rte_pktmbuf_data_len(m);
+
+	IQ_ptr = &buf[34];
+	if (portid == 0)
+	{
+		//destination mac address (RRU MAC)
+		/*eth->d_addr.addr_bytes[0] = 0x02;
+		eth->d_addr.addr_bytes[1] = 0x00;
+		eth->d_addr.addr_bytes[2] = 0x5e;
+		eth->d_addr.addr_bytes[3] = 0x01;
+		eth->d_addr.addr_bytes[4] = 0x01;
+		eth->d_addr.addr_bytes[5] = 0x01;*/
+		
+		eth->d_addr.addr_bytes[0] = buf[6];
+		eth->d_addr.addr_bytes[1] = buf[7];
+		eth->d_addr.addr_bytes[2] = buf[8];
+		eth->d_addr.addr_bytes[3] = buf[9];
+		eth->d_addr.addr_bytes[4] = buf[10];
+		eth->d_addr.addr_bytes[5] = buf[11];
+
+		//source mac address (DU MAC)
+		eth->s_addr.addr_bytes[0] = 0xdd;
+		eth->s_addr.addr_bytes[1] = 0xdd;
+		eth->s_addr.addr_bytes[2] = 0xdd;
+		eth->s_addr.addr_bytes[3] = 0xdd;
+		eth->s_addr.addr_bytes[4] = 0xdd;
+		eth->s_addr.addr_bytes[5] = 0xdd;
+	}
+	else
+	{
+		//destination mac address (RRU MAC)
+		/*eth->d_addr.addr_bytes[0] = 0x02;
+		eth->d_addr.addr_bytes[1] = 0x00;
+		eth->d_addr.addr_bytes[2] = 0x5e;
+		eth->d_addr.addr_bytes[3] = 0x01;
+		eth->d_addr.addr_bytes[4] = 0x01;
+		eth->d_addr.addr_bytes[5] = 0x01;*/
+
+		eth->d_addr.addr_bytes[0] = buf[6];
+		eth->d_addr.addr_bytes[1] = buf[7];
+		eth->d_addr.addr_bytes[2] = buf[8];
+		eth->d_addr.addr_bytes[3] = buf[9];
+		eth->d_addr.addr_bytes[4] = buf[10];
+		eth->d_addr.addr_bytes[5] = buf[11];
+		//source mac address (DU MAC)
+		eth->s_addr.addr_bytes[0] = 0xdd;
+		eth->s_addr.addr_bytes[1] = 0xdd;
+		eth->s_addr.addr_bytes[2] = 0xdd;
+		eth->s_addr.addr_bytes[3] = 0xdd;
+		eth->s_addr.addr_bytes[4] = 0xdd;
+		eth->s_addr.addr_bytes[5] = 0xde;
+		
+	}
+	dst_port = l2fwd_dst_ports[portid];
+	//DD Debug
+	//printf("dstPort =%d\n", dst_port);
+	// Handshake Condition
+	if (buf[18] == 0xAA ) // ORAN handshake msgs.
+	{
+		printf("\n Start UP Request Received\n");
+		printf("\n====================================================\n");
+
+		buf[18] = 0xBB;//change to msg2 after receive msg1
+
+		printf(" Start Up Response Sent\n");
+		printf("\n====================================================\n");
+	
+	}
+
+	// Trigger start send DL packets
+	if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && SYMBOL == 0x46 && ANT_NUM == 0x00 && SUBFRAME == 0x00 && dl_start == 0){
+
+		printf("\nU-Plane Started\n");
+		printf("\n====================================================\n");
+
+		dl_start = 1;
+		count_symbol = 28;
+	}
+
+
+	if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && ANT_NUM == 0x00) {
+          int subframe = SUBFRAME >> 4;
+          int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03);
+          p.frame = FRAME;
+          p.slot = subframe * 2 + slot;
+          p.symbol = SYMBOL & 0x3f;
+          p.antenna = 0;
+          memcpy(p.iq, IQ_ptr, 5088);
+          store_ul(bs, &p);
+          //if (p.symbol==0) printf("store ul f.sl.sy %d.%d.%d\n", p.frame, p.slot, p.symbol);
+        }
+
+	// U-PLANE UL ANT_0 PROCESSING
+	if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && ANT_NUM == 0x00 && dl_start == 1)
+	{
+                int frame    = FRAME;
+                int subframe = SUBFRAME >> 4;
+                int slot     = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03);
+                int symbol   = SYMBOL & 0x3f;
+                int oai_slot;
+
+                int tx_frame    = frame;
+                int tx_subframe = subframe;
+                int tx_slot     = slot;
+                int tx_symbol   = symbol + 8;
+
+                if (tx_symbol > 13) {
+                  tx_symbol -= 14;
+                  tx_slot++;
+                  if (tx_slot == 2) {
+                    tx_slot = 0;
+                    tx_subframe++;
+                    if (tx_subframe == 10) {
+                      tx_subframe = 0;
+                      tx_frame = (tx_frame + 1) & 255;
+                    }
+                  }
+                }
+
+		ANT_NUM = 0x00;
+
+		// Mask the symbol bits from UL packet received and apply the shift.
+		SYMBOL = ((SYMBOL & 0b00111111) + 8) % 14;
+
+		ANT_NUM = 0x00;
+		SUBFRAME = sf;
+
+		// Slot id control for DL
+		if(slot_id_ctrl > 13){
+			SYMBOL = SYMBOL | 0b01000000;
+		}
+
+                /* antenna 0 - send actual DL data (if available) */
+                oai_slot = tx_subframe * 2 + tx_slot;
+                lock_dl_buffer(bs->buffers, oai_slot);
+                if (!(bs->buffers->dl_busy[oai_slot] & (1 << tx_symbol))) {
+                  printf("%s: warning, DL underflow (sl.symbol %d.%d)\n", __FUNCTION__,
+                         oai_slot, tx_symbol);
+                  memset(IQ_ptr, 0, 1272 * 4);
+                } else {
+                  memcpy(IQ_ptr, bs->buffers->dl[oai_slot] + tx_symbol * 1272*4,
+                         1272*4);
+                }
+                bs->buffers->dl_busy[oai_slot] &= ~(1 << tx_symbol);
+                unlock_dl_buffer(bs->buffers, oai_slot);
+
+		// fill DL Data for ant 0 with 0 value
+//		memset(IQ_ptr, 0, 5088);
+	}
+
+	// U-PLANE UL ANT_1 PROCESSING
+	if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && ANT_NUM == 0x01 && dl_start == 1)
+	{
+
+		// Mask the symbol bits from UL packet received and apply the shift.
+		SYMBOL = ((SYMBOL & 0b00111111) + 8) % 14;
+
+		ANT_NUM = 0x01;
+		SUBFRAME = sf;
+
+		slot_id_ctrl++;
+
+		// Slot id control for DL
+		if(slot_id_ctrl > 13){
+			SYMBOL = SYMBOL | 0b01000000;
+
+			if(slot_id_ctrl > 27){
+				slot_id_ctrl = 0;
+				sf = sf + 0x10;
+
+				if (sf >0x90){
+					sf = 0;
+				}
+			}
+		}
+
+		// fill DL Data for ant 1 with 0 value
+		memset(IQ_ptr, 0, 5088);
+	}
+
+	// U-PLANE PRACH PROCESSING
+	else if(PAYLOAD_1 == 0x0d && PAYLOAD_2 == 0x28){
+                if (ANT_NUM == 0) {
+                  int subframe = SUBFRAME >> 4;
+                  int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03);
+                  if (subframe==9) {
+                     //printf("store prach f.sf.sl %d.%d.%d %d\n", FRAME, subframe, slot, subframe * 2 + slot);
+                     store_prach(bs, FRAME, slot /*subframe * 2 + slot*/, IQ_ptr);
+                  } 
+                }
+		rte_pktmbuf_free(m);
+		return;
+	}
+
+	// Send Packets
+	buffer = tx_buffer[dst_port];
+
+	sent = rte_eth_tx_buffer(dst_port, 0, buffer, m);
+
+	if (sent)
+		port_statistics[dst_port].tx += sent;
+
+}
+/* main processing loop */
+static void
+l2fwd_main_loop(benetel_t *bs)
+{
+        struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+        struct rte_mbuf *m;
+        int sent;
+        unsigned lcore_id;
+        uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+        unsigned i, j, portid, nb_rx;
+        struct lcore_queue_conf *qconf;
+        const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S *
+                        BURST_TX_DRAIN_US;
+        struct rte_eth_dev_tx_buffer *buffer;
+        prev_tsc = 0;
+        timer_tsc = 0;
+        lcore_id = rte_lcore_id();
+        qconf = &lcore_queue_conf[lcore_id];
+        if (qconf->n_rx_port == 0) {
+                RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+                return;
+        }
+        RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+        for (i = 0; i < qconf->n_rx_port; i++) {
+                portid = qconf->rx_port_list[i];
+                RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+                        portid);
+        }
+        while (!force_quit) {
+                cur_tsc = rte_rdtsc();
+                /*
+                 * TX burst queue drain
+                 */
+                diff_tsc = cur_tsc - prev_tsc;
+                if (unlikely(diff_tsc > drain_tsc)) {
+                        for (i = 0; i < qconf->n_rx_port; i++) {
+                                portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
+                                buffer = tx_buffer[portid];
+                                sent = rte_eth_tx_buffer_flush(portid, 0, buffer);
+                                if (sent)
+                                        port_statistics[portid].tx += sent;
+                        }
+                        /* if timer is enabled */
+                        if (timer_period > 0) {
+                                /* advance the timer */
+                                timer_tsc += diff_tsc;
+                                /* if timer has reached its timeout */
+                                if (unlikely(timer_tsc >= timer_period)) {
+                                        /* do this only on master core */
+                                        if (lcore_id == rte_get_master_lcore()) {
+                                                print_stats();
+                                                /* reset the timer */
+                                                timer_tsc = 0;
+                                        }
+                                }
+                        }
+                        prev_tsc = cur_tsc;
+                }
+                /*
+                 * Read packet from RX queues
+                 */
+                for (i = 0; i < qconf->n_rx_port; i++) {
+                        portid = qconf->rx_port_list[i];
+                        nb_rx = rte_eth_rx_burst(portid, 0,
+                                                 pkts_burst, MAX_PKT_BURST);
+                        port_statistics[portid].rx += nb_rx;
+                        for (j = 0; j < nb_rx; j++) {
+                                m = pkts_burst[j];
+                                rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+                                l2fwd_simple_forward(m, portid, bs);
+                        }
+                }
+        }
+}
+static int
+l2fwd_launch_one_lcore(void *bs)
+{
+        l2fwd_main_loop(bs);
+        return 0;
+}
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+        printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+               "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+               "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+                   "  -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
+                   "  --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n"
+                   "      When enabled:\n"
+                   "       - The source MAC address is replaced by the TX port MAC address\n"
+                   "       - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n",
+               prgname);
+}
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+        char *end = NULL;
+        unsigned long pm;
+        /* parse hexadecimal string */
+        pm = strtoul(portmask, &end, 16);
+        if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+                return -1;
+        if (pm == 0)
+                return -1;
+        return pm;
+}
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+        char *end = NULL;
+        unsigned long n;
+        /* parse hexadecimal string */
+        n = strtoul(q_arg, &end, 10);
+        if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+                return 0;
+        if (n == 0)
+                return 0;
+        if (n >= MAX_RX_QUEUE_PER_LCORE)
+                return 0;
+        return n;
+}
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+        char *end = NULL;
+        int n;
+        /* parse number string */
+        n = strtol(q_arg, &end, 10);
+        if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+                return -1;
+        if (n >= MAX_TIMER_PERIOD)
+                return -1;
+        return n;
+}
+static const char short_options[] =
+        "p:"  /* portmask */
+        "q:"  /* number of queues */
+        "T:"  /* timer period */
+        ;
+#define CMD_LINE_OPT_MAC_UPDATING "mac-updating"
+#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating"
+enum {
+        /* long options mapped to a short option */
+        /* first long only option value must be >= 256, so that we won't
+         * conflict with short options */
+        CMD_LINE_OPT_MIN_NUM = 256,
+};
+static const struct option lgopts[] = {
+        { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1},
+        { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0},
+        {NULL, 0, 0, 0}
+};
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+        int opt, ret, timer_secs;
+        char **argvopt;
+        int option_index;
+        char *prgname = argv[0];
+        argvopt = argv;
+        while ((opt = getopt_long(argc, argvopt, short_options,
+                                  lgopts, &option_index)) != EOF) {
+                switch (opt) {
+                /* portmask */
+                case 'p':
+                        l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+                        if (l2fwd_enabled_port_mask == 0) {
+                                printf("invalid portmask\n");
+                                l2fwd_usage(prgname);
+                                return -1;
+                        }
+                        break;
+                /* nqueue */
+                case 'q':
+                        l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+                        if (l2fwd_rx_queue_per_lcore == 0) {
+                                printf("invalid queue number\n");
+                                l2fwd_usage(prgname);
+                                return -1;
+                        }
+                        break;
+                /* timer period */
+                case 'T':
+                        timer_secs = l2fwd_parse_timer_period(optarg);
+                        if (timer_secs < 0) {
+                                printf("invalid timer period\n");
+                                l2fwd_usage(prgname);
+                                return -1;
+                        }
+                        timer_period = timer_secs;
+                        break;
+                /* long options */
+                case 0:
+                        break;
+                case 'proc-type':
+                        break;
+                case 'socket-mem':
+                        break;
+                case 'file-prefix':
+                        l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+                        if (l2fwd_rx_queue_per_lcore == 0) {
+                                printf("invalid queue number\n");
+                                l2fwd_usage(prgname);
+                                return -1;
+                        }
+                        break;
+                /* timer period */
+                /* timer period */
+                /* timer period */
+                default:
+                        l2fwd_usage(prgname);
+                        return -1;
+                }
+        }
+        if (optind >= 0)
+                argv[optind-1] = prgname;
+        ret = optind-1;
+        optind = 1; /* reset getopt lib */
+        return ret;
+}
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+        uint16_t portid;
+        uint8_t count, all_ports_up, print_flag = 0;
+        struct rte_eth_link link;
+        printf("\nChecking link status");
+        fflush(stdout);
+        for (count = 0; count <= MAX_CHECK_TIME; count++) {
+                if (force_quit)
+                        return;
+                all_ports_up = 1;
+                RTE_ETH_FOREACH_DEV(portid) {
+                        if (force_quit)
+                                return;
+                        if ((port_mask & (1 << portid)) == 0)
+                                continue;
+                        memset(&link, 0, sizeof(link));
+                        rte_eth_link_get_nowait(portid, &link);
+                        /* print link status if flag set */
+                        if (print_flag == 1) {
+                                if (link.link_status)
+                                        printf(
+                                        "Port%d Link Up. Speed %u Mbps - %s\n",
+                                                portid, link.link_speed,
+                                (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+                                        ("full-duplex") : ("half-duplex\n"));
+                                else
+                                        printf("Port %d Link Down\n", portid);
+                                continue;
+                        }
+                        /* clear all_ports_up flag if any link down */
+                        if (link.link_status == ETH_LINK_DOWN) {
+                                all_ports_up = 0;
+                                break;
+                        }
+                }
+                /* after finally printing all link status, get out */
+                if (print_flag == 1)
+                        break;
+                if (all_ports_up == 0) {
+                        printf(".");
+                        fflush(stdout);
+                        rte_delay_ms(CHECK_INTERVAL);
+                }
+                /* set the print_flag if all ports up or timeout */
+                if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+                        print_flag = 1;
+                        printf("done\n");
+                }
+        }
+}
+static void
+signal_handler(int signum)
+{
+        if (signum == SIGINT || signum == SIGTERM) {
+                printf("\n\nSignal %d received, preparing to exit...\n",
+                                signum);
+                force_quit = true;
+        }
+}
+int
+dpdk_main(int argc, char **argv, benetel_t *bs)
+{
+        struct lcore_queue_conf *qconf;
+        int ret;
+        uint16_t nb_ports;
+        uint16_t nb_ports_available = 0;
+        uint16_t portid, last_port;
+        unsigned lcore_id, rx_lcore_id;
+        unsigned nb_ports_in_mask = 0;
+        unsigned int nb_lcores = 0;
+        unsigned int nb_mbufs;
+        /* init EAL */
+        ret = rte_eal_init(argc, argv);
+        if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+        argc -= ret;
+        argv += ret;
+        force_quit = false;
+        signal(SIGINT, signal_handler);
+        signal(SIGTERM, signal_handler);
+        /* parse application arguments (after the EAL ones) */
+        ret = l2fwd_parse_args(argc, argv);
+        if (ret < 0)
+                rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+        printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled");
+        /* convert to number of cycles */
+        timer_period *= rte_get_timer_hz();
+        nb_ports = rte_eth_dev_count_avail();
+        if (nb_ports == 0)
+                rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+        /* check port mask to possible port mask */
+        if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1))
+                rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n",
+                        (1 << nb_ports) - 1);
+        /* reset l2fwd_dst_ports */
+        for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+                l2fwd_dst_ports[portid] = 0;
+        last_port = 0;
+        /*
+         * Each logical core is assigned a dedicated TX queue on each port.
+         */
+        RTE_ETH_FOREACH_DEV(portid) {
+                /* skip ports that are not enabled */
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+                        continue;
+                if (nb_ports_in_mask % 2) {
+                        l2fwd_dst_ports[portid] = last_port;
+                        l2fwd_dst_ports[last_port] = portid;
+                }
+                else
+                        last_port = portid;
+                nb_ports_in_mask++;
+        }
+        if (nb_ports_in_mask % 2) {
+                printf("Notice: odd number of ports in portmask.\n");
+                l2fwd_dst_ports[last_port] = last_port;
+        }
+        rx_lcore_id = 0;
+        qconf = NULL;
+        /* Initialize the port/queue configuration of each logical core */
+        RTE_ETH_FOREACH_DEV(portid) {
+                /* skip ports that are not enabled */
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+                        continue;
+                /* get the lcore_id for this port */
+                while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+                       lcore_queue_conf[rx_lcore_id].n_rx_port ==
+                       l2fwd_rx_queue_per_lcore) {
+                        rx_lcore_id++;
+                        if (rx_lcore_id >= RTE_MAX_LCORE)
+                                rte_exit(EXIT_FAILURE, "Not enough cores\n");
+                }
+                if (qconf != &lcore_queue_conf[rx_lcore_id]) {
+                        /* Assigned a new logical core in the loop above. */
+                        qconf = &lcore_queue_conf[rx_lcore_id];
+                        nb_lcores++;
+                }
+                qconf->rx_port_list[qconf->n_rx_port] = portid;
+                qconf->n_rx_port++;
+                printf("Lcore %u: RX port %u\n", rx_lcore_id, portid);
+        }
+        nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST +
+                nb_lcores * MEMPOOL_CACHE_SIZE), 8192U);
+        /* create the mbuf pool */
+	//DD Debug
+	//printf ("Proc Type %d \n", rte_eal_process_type());
+        l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs,
+                MEMPOOL_CACHE_SIZE, 0, 9680,
+                rte_socket_id());
+        if (l2fwd_pktmbuf_pool == NULL)
+                rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+        /* Initialise each port */
+        RTE_ETH_FOREACH_DEV(portid) {
+                struct rte_eth_rxconf rxq_conf;
+                struct rte_eth_txconf txq_conf;
+                struct rte_eth_conf local_port_conf = port_conf;
+                struct rte_eth_dev_info dev_info;
+                /* skip ports that are not enabled */
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+                        printf("Skipping disabled port %u\n", portid);
+                        continue;
+                }
+                nb_ports_available++;
+                /* init port */
+                printf("Initializing port %u... ", portid);
+                fflush(stdout);
+                rte_eth_dev_info_get(portid, &dev_info);
+                if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
+                        local_port_conf.txmode.offloads |=
+                                DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+                ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+                                  ret, portid);
+                ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd,
+                                                       &nb_txd);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE,
+                                 "Cannot adjust number of descriptors: err=%d, port=%u\n",
+                                 ret, portid);
+                rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+                /* init one RX queue */
+                fflush(stdout);
+                rxq_conf = dev_info.default_rxconf;
+                rxq_conf.offloads = local_port_conf.rxmode.offloads;
+                ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+                                             rte_eth_dev_socket_id(portid),
+                                             &rxq_conf,
+                                             l2fwd_pktmbuf_pool);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+                                  ret, portid);
+                /* init one TX queue on each port */
+                fflush(stdout);
+                txq_conf = dev_info.default_txconf;
+                txq_conf.offloads = local_port_conf.txmode.offloads;
+                ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+                                rte_eth_dev_socket_id(portid),
+                                &txq_conf);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+                                ret, portid);
+                /* Initialize TX buffers */
+                tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
+                                RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
+                                rte_eth_dev_socket_id(portid));
+                if (tx_buffer[portid] == NULL)
+                        rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n",
+                                        portid);
+                rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
+                ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
+                                rte_eth_tx_buffer_count_callback,
+                                &port_statistics[portid].dropped);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE,
+                        "Cannot set error callback for tx buffer on port %u\n",
+                                 portid);
+                /* Start device */
+                ret = rte_eth_dev_start(portid);
+                if (ret < 0)
+                        rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
+                                  ret, portid);
+                printf("done: \n");
+                rte_eth_promiscuous_enable(portid);
+                printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
+                                portid,
+                                l2fwd_ports_eth_addr[portid].addr_bytes[0],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[1],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[2],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[3],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[4],
+                                l2fwd_ports_eth_addr[portid].addr_bytes[5]);
+                /* initialize port stats */
+                memset(&port_statistics, 0, sizeof(port_statistics));
+        }
+        if (!nb_ports_available) {
+                rte_exit(EXIT_FAILURE,
+                        "All available ports are disabled. Please set portmask.\n");
+        }
+        check_all_ports_link_status(l2fwd_enabled_port_mask);
+        ret = 0;
+        /* launch per-lcore init on every lcore */
+        rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, bs, CALL_MASTER);
+        RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+                if (rte_eal_wait_lcore(lcore_id) < 0) {
+                        ret = -1;
+                        break;
+                }
+        }
+        RTE_ETH_FOREACH_DEV(portid) {
+                if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+                        continue;
+                printf("Closing port %d...", portid);
+                rte_eth_dev_stop(portid);
+                rte_eth_dev_close(portid);
+                printf(" Done\n");
+        }
+        printf("Bye...\n");
+        return ret;
+}
diff --git a/targets/ARCH/ETHERNET/benetel/5g/low.c b/targets/ARCH/ETHERNET/benetel/5g/low.c
new file mode 100644
index 0000000000000000000000000000000000000000..984e401421da61331bbf2abe5811edea4eb392ee
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/5g/low.c
@@ -0,0 +1,97 @@
+/*
+ * 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 "low.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void store_ul(benetel_t *bs, ul_packet_t *ul)
+{
+  /* only antenna 0 for the moment */
+  if (ul->antenna != 0)
+    return;
+
+  if (ul->slot != bs->next_slot ||
+      ul->symbol != bs->next_symbol) {
+    printf("%s: fatal, expected frame.sl.symbol %d.%d.%d, got %d.%d.%d\n",
+           __FUNCTION__,
+           bs->expected_benetel_frame, bs->next_slot, bs->next_symbol,
+           ul->frame, ul->slot, ul->symbol);
+    exit(1);
+  }
+
+  lock_ul_buffer(bs->buffers, bs->next_slot);
+  if (bs->buffers->ul_busy[bs->next_slot] & (1 << bs->next_symbol)) {
+    printf("%s: warning, UL overflow (sl.symbol %d.%d)\n", __FUNCTION__,
+           bs->next_slot, bs->next_symbol);
+  }
+
+  memcpy(bs->buffers->ul[bs->next_slot] + bs->next_symbol * 1272*4,
+         ul->iq, 1272*4);
+  bs->buffers->ul_busy[bs->next_slot] |= (1 << bs->next_symbol);
+  signal_ul_buffer(bs->buffers, bs->next_slot);
+  unlock_ul_buffer(bs->buffers, bs->next_slot);
+
+  bs->next_symbol++;
+  if (bs->next_symbol == 14) {
+    bs->next_symbol = 0;
+    bs->next_slot = (bs->next_slot + 1) % 20;
+    if (bs->next_slot == 0) {
+      bs->expected_benetel_frame++;
+      bs->expected_benetel_frame &= 255;
+    }
+  }
+}
+
+void store_prach(benetel_t *bs, int frame, int slot, void *data)
+{
+  static int last_frame = -1;
+  static int last_slot = -1;
+  /* hack: antenna number is always 0, discard second packet with same f/sf */
+  //if (frame == last_frame && slot == last_slot) return;
+  if (frame == last_frame && slot == last_slot) { printf("got f.sl %d.%d twice\n", frame, slot); return; }
+  last_frame = frame;
+  last_slot = slot;
+
+  lock_ul_buffer(bs->buffers, slot);
+  if (bs->buffers->prach_busy[slot]) {
+    printf("store_prach: fatal: previous prach buffer not processed\n");
+    unlock_ul_buffer(bs->buffers, slot);
+    return;
+  }
+  bs->buffers->prach_busy[slot] = 1;
+  memcpy(bs->buffers->prach[slot], data, 839*4);
+  signal_ul_buffer(bs->buffers, slot);
+  unlock_ul_buffer(bs->buffers, slot);
+
+}
+
+void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
+
+void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
+{
+  if (!strcmp(ifname, "dpdk"))
+    return benetel_start_dpdk(ifname, buffers, dpdk_main_command_line);
+  printf("benetel: fatal: interface %s not supported, only dpdpk is supported\n", ifname);
+  exit(1);
+}
diff --git a/targets/ARCH/ETHERNET/benetel/5g/low.h b/targets/ARCH/ETHERNET/benetel/5g/low.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e1daee9d1ceaf005e957426526a752291ecaeda
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/5g/low.h
@@ -0,0 +1,48 @@
+/*
+ * 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 _BENETEL_5G_LOW_H_
+#define _BENETEL_5G_LOW_H_
+
+#include "shared_buffers.h"
+
+typedef struct {
+  shared_buffers *buffers;
+  int            next_slot;
+  int            next_symbol;
+  int            expected_benetel_frame;
+  char           *dpdk_main_command_line;
+} benetel_t;
+
+typedef struct {
+  int frame;
+  int slot;
+  int symbol;
+  int antenna;
+  unsigned char iq[5088];
+} ul_packet_t;
+
+void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line);
+
+void store_ul(benetel_t *bs, ul_packet_t *ul);
+void store_prach(benetel_t *bs, int frame, int slot, void *data);
+
+#endif /* _BENETEL_5G_LOW_H_ */
diff --git a/targets/ARCH/ETHERNET/benetel/5g/low_dpdk.c b/targets/ARCH/ETHERNET/benetel/5g/low_dpdk.c
new file mode 100644
index 0000000000000000000000000000000000000000..5e26f6782ea737e0b6b18c23b39bc86a01d74839
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/5g/low_dpdk.c
@@ -0,0 +1,118 @@
+/*
+ * 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
+ */
+
+/* those 2 lines for CPU_SET */
+#define _GNU_SOURCE
+#include <sched.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "low.h"
+
+int dpdk_main(int argc, char **argv, benetel_t *);
+
+void *dpdk_thread(void *_bs)
+{
+  benetel_t *bs = _bs;
+  int n = 0;
+  char **v = NULL; // = { "softmodem", "-n", "2", "--file-prefix", "pg2", "-l", "6", "--", "-p", "0x1" };
+  char *s = bs->dpdk_main_command_line;
+  char *tok;
+
+  while ((tok = strtok(s, " ")) != NULL) {
+    n++;
+    v = realloc(v, n * sizeof(char *));
+    if (v == NULL) {
+      printf("%s: out of memory\n", __FUNCTION__);
+      exit(1);
+    }
+    v[n-1] = tok;
+    s = NULL;
+  }
+
+  dpdk_main(n, v, bs);
+  exit(1);
+  return 0;
+}
+
+void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line)
+{
+  benetel_t *bs;
+
+  bs = calloc(1, sizeof(benetel_t));
+  if (bs == NULL) {
+    printf("%s: out of memory\n", __FUNCTION__);
+    exit(1);
+  }
+
+  bs->buffers = buffers;
+
+  bs->expected_benetel_frame = 255;
+
+  bs->dpdk_main_command_line = dpdk_main_command_line;
+
+  pthread_attr_t attr;
+
+  if (pthread_attr_init(&attr) != 0) {
+    printf("pthread_attr_init failed\n");
+    exit(1);
+  }
+
+  cpu_set_t cpuset;
+  CPU_ZERO(&cpuset);
+  CPU_SET(10,&cpuset);
+  if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset) != 0) {
+    printf("pthread_attr_setaffinity_np failed\n");
+    exit(1);
+  }
+
+  if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) {
+    printf("pthread_attr_setschedpolicy failed\n");
+    exit(1);
+  }
+
+  struct sched_param params;
+  params.sched_priority = sched_get_priority_max(SCHED_FIFO);
+  if (sched_get_priority_max(SCHED_FIFO) == -1) {
+    printf("sched_get_priority_max failed\n");
+    exit(1);
+  }
+  if (pthread_attr_setschedparam(&attr, &params) != 0) {
+    printf("pthread_setschedparam failed\n");
+    exit(1);
+  }
+
+  pthread_t t;
+  if (pthread_create(&t, &attr, dpdk_thread, bs) != 0) {
+    printf("%s: thread creation failed\n", __FUNCTION__);
+    exit(1);
+  }
+
+  if (pthread_attr_destroy(&attr) != 0) {
+    printf("pthread_attr_init failed\n");
+    exit(1);
+  }
+
+  return bs;
+}
diff --git a/targets/ARCH/ETHERNET/benetel/5g/shared_buffers.c b/targets/ARCH/ETHERNET/benetel/5g/shared_buffers.c
new file mode 100644
index 0000000000000000000000000000000000000000..b9da10b380687819a643f0593c152e6879ab9e69
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/5g/shared_buffers.c
@@ -0,0 +1,118 @@
+/*
+ * 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 "shared_buffers.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void init_buffers(shared_buffers *s)
+{
+  int slot;
+
+  memset(s, 0, sizeof(*s));
+
+  for (slot = 0; slot < 20; slot++) {
+    if (pthread_mutex_init(&s->m_dl[slot], NULL) != 0 ||
+        pthread_cond_init(&s->c_dl[slot], NULL) != 0  ||
+        pthread_mutex_init(&s->m_ul[slot], NULL) != 0 ||
+        pthread_cond_init(&s->c_ul[slot], NULL) != 0) {
+      printf("%s: error initializing mutex/cond\n", __FUNCTION__);
+      exit(1);
+    }
+  }
+
+  /* the gNB's first transmitted DL slot is 6 but the device
+   * needs to have slots 1, 2 and 3, 4 and 5 ready. Let's pretend
+   * they are ready.
+   */
+  s->dl_busy[1] = 0x3fff;
+  s->dl_busy[2] = 0x3fff;
+  s->dl_busy[3] = 0x3fff;
+  s->dl_busy[4] = 0x3fff;
+  s->dl_busy[5] = 0x3fff;
+}
+
+void lock_dl_buffer(shared_buffers *s, int slot)
+{
+  if (pthread_mutex_lock(&s->m_dl[slot]) != 0) {
+    printf("%s: fatal: lock fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void unlock_dl_buffer(shared_buffers *s, int slot)
+{
+  if (pthread_mutex_unlock(&s->m_dl[slot]) != 0) {
+    printf("%s: fatal: unlock fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void wait_dl_buffer(shared_buffers *s, int slot)
+{
+  if (pthread_cond_wait(&s->c_dl[slot], &s->m_dl[slot]) != 0) {
+    printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void signal_dl_buffer(shared_buffers *s, int slot)
+{
+  if (pthread_cond_broadcast(&s->c_dl[slot]) != 0) {
+    printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void lock_ul_buffer(shared_buffers *s, int slot)
+{
+  if (pthread_mutex_lock(&s->m_ul[slot]) != 0) {
+    printf("%s: fatal: lock fails\n", __FUNCTION__);
+    printf("%s: fatal: lock fails slot %d\n", __FUNCTION__, slot);
+    exit(1);
+  }
+}
+
+void unlock_ul_buffer(shared_buffers *s, int slot)
+{
+  if (pthread_mutex_unlock(&s->m_ul[slot]) != 0) {
+    printf("%s: fatal: unlock fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void wait_ul_buffer(shared_buffers *s, int slot)
+{
+  if (pthread_cond_wait(&s->c_ul[slot], &s->m_ul[slot]) != 0) {
+    printf("%s: fatal: cond_wait fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
+
+void signal_ul_buffer(shared_buffers *s, int slot)
+{
+  if (pthread_cond_broadcast(&s->c_ul[slot]) != 0) {
+    printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__);
+    exit(1);
+  }
+}
diff --git a/targets/ARCH/ETHERNET/benetel/5g/shared_buffers.h b/targets/ARCH/ETHERNET/benetel/5g/shared_buffers.h
new file mode 100644
index 0000000000000000000000000000000000000000..ca7dbd9c8f92aef059813f721462812f8e87efc1
--- /dev/null
+++ b/targets/ARCH/ETHERNET/benetel/5g/shared_buffers.h
@@ -0,0 +1,60 @@
+/*
+ * 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 _BENETEL_5G_SHARED_BUFFERS_H_
+#define _BENETEL_5G_SHARED_BUFFERS_H_
+
+#include <pthread.h>
+#include <stdint.h>
+
+typedef struct {
+  unsigned char dl[20][14*1272*4];
+  unsigned char ul[20][14*1272*4];
+  uint16_t dl_busy[20];
+  uint16_t ul_busy[20];
+
+  pthread_mutex_t m_ul[20];
+  pthread_cond_t  c_ul[20];
+
+  pthread_mutex_t m_dl[20];
+  pthread_cond_t  c_dl[20];
+
+  unsigned char prach[20][849*4];
+  unsigned char prach_busy[20];
+
+  /* statistics/error counting */
+  int ul_overflow;
+  int dl_underflow;
+} shared_buffers;
+
+void init_buffers(shared_buffers *s);
+
+void lock_dl_buffer(shared_buffers *s, int slot);
+void unlock_dl_buffer(shared_buffers *s, int slot);
+void wait_dl_buffer(shared_buffers *s, int slot);
+void signal_dl_buffer(shared_buffers *s, int slot);
+
+void lock_ul_buffer(shared_buffers *s, int slot);
+void unlock_ul_buffer(shared_buffers *s, int slot);
+void wait_ul_buffer(shared_buffers *s, int slot);
+void signal_ul_buffer(shared_buffers *s, int slot);
+
+#endif /* _BENETEL_5G_SHARED_BUFFERS_H_ */
diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
index 6e94717a6fbcf02525782f11eebf58e31a01cf44..0c89a68dd583fe00fe5d349e4289f6a789d0bd2d 100644
--- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
+++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
@@ -108,7 +108,8 @@ typedef struct {
   int64_t rx_count;
   int wait_for_first_pps;
   int use_gps;
-  int first_tx;
+  //int first_tx;
+  //int first_rx;
   //! timestamp of RX packet
   openair0_timestamp rx_timestamp;
 } usrp_state_t;
@@ -282,31 +283,28 @@ static int trx_usrp_start(openair0_device *device) {
   // set pin 5 (Shutdown LNA) to 1 when the radio is transmitting and receiveing (ATR_XX)
   // (we use full duplex here, because our RX is on all the time - this might need to change later)
   s->usrp->set_gpio_attr("FP0", "ATR_XX", (1<<5), 0x7f);
-  // set the output pins to 0
+  // set the output pins to 1
   s->usrp->set_gpio_attr("FP0", "OUT", 7<<7, 0xf80);
 
-  // init recv and send streaming
-  uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
-  LOG_I(HW,"Time in secs now: %llu \n", s->usrp->get_time_now().to_ticks(s->sample_rate));
-  LOG_I(HW,"Time in secs last pps: %llu \n", s->usrp->get_time_last_pps().to_ticks(s->sample_rate));
-  
-  if (s->use_gps == 1 || device->openair0_cfg[0].time_source == external) {
-    s->wait_for_first_pps = 1;
-    cmd.time_spec = s->usrp->get_time_last_pps() + uhd::time_spec_t(1.0);
-  } else {
-    s->wait_for_first_pps = 0;
-    cmd.time_spec = s->usrp->get_time_now() + uhd::time_spec_t(0.005);
+  s->wait_for_first_pps = 1;
+  s->rx_count = 0;
+  s->tx_count = 0;
+  //s->first_tx = 1;
+  //s->first_rx = 1;
+  s->rx_timestamp = 0;
+
+  s->usrp->set_time_next_pps(uhd::time_spec_t(0.0));
+  // wait for the pps to change
+  uhd::time_spec_t time_last_pps = s->usrp->get_time_last_pps();
+  while (time_last_pps == s->usrp->get_time_last_pps()) {
+    boost::this_thread::sleep(boost::posix_time::milliseconds(1));
   }
 
+  uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
+  cmd.time_spec = uhd::time_spec_t(1.0);    
   cmd.stream_now = false; // start at constant delay
   s->rx_stream->issue_stream_cmd(cmd);
-  /*s->tx_md.time_spec = cmd.time_spec + uhd::time_spec_t(1-(double)s->tx_forward_nsamps/s->sample_rate);
-  s->tx_md.has_time_spec = true;
-  s->tx_md.start_of_burst = true;
-  s->tx_md.end_of_burst = false;*/
-  s->rx_count = 0;
-  s->tx_count = 0;
-  s->rx_timestamp = 0;
+
   return 0;
 }
 /*! \brief Terminate operation of the USRP transceiver -- free all associated resources
@@ -635,7 +633,6 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
   int16x8_t buff_tmp[2][nsamps2];
 #endif
 
-  if (device->type == USRP_B200_DEV) {
     if (cc>1) {
       // receive multiple channels (e.g. RF A and RF B)
       std::vector<void *> buff_ptrs;
@@ -648,7 +645,7 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
       samples_received=0;
 
       while (samples_received != nsamps) {
-        samples_received += s->rx_stream->recv(buff_tmp[0]+samples_received,
+        samples_received += s->rx_stream->recv((void*)((int32_t*)buff_tmp[0]+samples_received),
                                                nsamps-samples_received, s->rx_md);
 
         if  ((s->wait_for_first_pps == 0) && (s->rx_md.error_code!=uhd::rx_metadata_t::ERROR_CODE_NONE))
@@ -658,7 +655,6 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
           printf("sleep...\n"); //usleep(100);
         }
       }
-
       if (samples_received == nsamps) s->wait_for_first_pps=0;
     }
 
@@ -684,22 +680,10 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
 #endif
       }
     }
-  } else if (device->type == USRP_X300_DEV) {
-    if (cc>1) {
-      // receive multiple channels (e.g. RF A and RF B)
-      std::vector<void *> buff_ptrs;
 
-      for (int i=0; i<cc; i++) buff_ptrs.push_back(buff[i]);
-
-      samples_received = s->rx_stream->recv(buff_ptrs, nsamps, s->rx_md,1.0);
-    } else {
-      // receive a single channel (e.g. from connector RF A)
-      samples_received = s->rx_stream->recv(buff[0], nsamps, s->rx_md,1.0);
+    if (samples_received < nsamps) {
+      LOG_E(HW,"[recv] received %d samples out of %d\n",samples_received,nsamps);
     }
-  }
-
-  if (samples_received < nsamps)
-    LOG_E(HW,"[recv] received %d samples out of %d\n",samples_received,nsamps);
 
   if ( s->rx_md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE)
     LOG_E(HW, "%s\n", s->rx_md.to_pp_string(true).c_str());
@@ -835,6 +819,17 @@ rx_gain_calib_table_t calib_table_x310[] = {
   {-1,0}
 };
 
+/*! \brief USRPB210 RX calibration table */
+rx_gain_calib_table_t calib_table_n310[] = {
+  {3500000000.0,0.0},
+  {2660000000.0,0.0},
+  {2300000000.0,0.0},
+  {1880000000.0,0.0},
+  {816000000.0, 0.0},
+  {-1,0}
+};
+
+
 /*! \brief Set RX gain offset
  * \param openair0_cfg RF frontend parameters set by application
  * \param chain_index RF chain to apply settings to
@@ -984,7 +979,7 @@ extern "C" {
   
     if (device_adds[0].get("type") == "n3xx") {
       printf("Found USRP n300\n");
-      device->type=USRP_X300_DEV; //treat it as X300 for now
+      device->type=USRP_N300_DEV; 
       usrp_master_clock = 122.88e6;
       args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock);
       //args += ", send_buff_size=33554432";
@@ -1070,9 +1065,18 @@ extern "C" {
   
   if (device->type==USRP_X300_DEV) {
     openair0_cfg[0].rx_gain_calib_table = calib_table_x310;
-    std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; // Bell Labs info
+    std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; 
+  }
+
+  if (device->type==USRP_N300_DEV) {
+    openair0_cfg[0].rx_gain_calib_table = calib_table_n310;
+    std::cerr << "-- Using calibration table: calib_table_n310" << std::endl; 
+  }
+
+
+  if (device->type==USRP_N300_DEV || device->type==USRP_X300_DEV) {
     LOG_I(HW,"%s() sample_rate:%u\n", __FUNCTION__, (int)openair0_cfg[0].sample_rate);
-  
+
     switch ((int)openair0_cfg[0].sample_rate) {
       case 122880000:
         // from usrp_time_offset
diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c
index 81ea1cf8ba147a2f4828eab677a1a259a3c991ea..93c07a575f70cdd7b1097c1112195755f9bbb717 100644
--- a/targets/ARCH/rfsimulator/simulator.c
+++ b/targets/ARCH/rfsimulator/simulator.c
@@ -184,10 +184,12 @@ void allocCirBuf(rfsimulator_state_t *bridge, int sock) {
                                             bridge->channelmod,
                                             bridge->sample_rate,
                                             bridge->tx_bw,
+                                            30e-9,  // TDL delay-spread parameter
                                             bridge->chan_forgetfact, // forgetting_factor
                                             bridge->chan_offset, // maybe used for TA
                                             bridge->chan_pathloss); // path_loss in dB
     set_channeldesc_owner(ptr->channel_model, RFSIMU_MODULEID);
+
     random_channel(ptr->channel_model,false);
   }
 }
@@ -330,6 +332,7 @@ static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt,
                                                 channelmod,
                                                 t->sample_rate,
                                                 t->tx_bw,
+                                                30e-9,  // TDL delay-spread parameter
                                                 t->chan_forgetfact, // forgetting_factor
                                                 t->chan_offset, // maybe used for TA
                                                 t->chan_pathloss); // path_loss in dB
@@ -456,7 +459,7 @@ int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, voi
 static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initial) {
   // Process all incoming events on sockets
   // store the data in lists
-  struct epoll_event events[FD_SETSIZE]= {0};
+  struct epoll_event events[FD_SETSIZE]= {{0}};
   int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, timeout);
 
   if ( nfds==-1 ) {
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-4g.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-4g.conf
new file mode 100644
index 0000000000000000000000000000000000000000..716bfd3b6bc4226175e5d5483b390992bd673cce
--- /dev/null
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-4g.conf
@@ -0,0 +1,281 @@
+Active_eNBs = ( "eNB-Eurecom-LTEBox");
+# 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-LTEBox";
+
+    // Tracking area code, 0x0000 and 0xfffe are reserved values
+    tracking_area_code = 1;
+    plmn_list = ( { mcc = 222; mnc = 01; mnc_length = 2; } );
+
+    tr_s_preference     = "local_mac"
+
+    ////////// Physical parameters:
+
+    component_carriers = (
+      {
+      node_function             = "NGFI_RCC_IF4p5";
+      node_timing               = "synch_to_ext_device";
+      node_synch_ref            = 0;
+      frame_type					      = "FDD";
+      tdd_config 					      = 3;
+      tdd_config_s            			      = 0;
+      prefix_type             			      = "NORMAL";
+      eutra_band              			      = 7;
+      downlink_frequency      			      = 2655000000L;
+      uplink_frequency_offset 			      = -120000000;
+      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;
+      pbch_repetition                                 = "FALSE";
+      prach_root              			      = 0;
+      prach_config_index      			      = 0;
+      prach_high_speed        			      = "DISABLE";
+      prach_zero_correlation  			      = 1;
+      prach_freq_offset       			      = 90;
+      pucch_delta_shift       			      = 1;
+      pucch_nRB_CQI           			      = 0;
+      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                                   = -104;
+      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;
+
+      //Parameters for SIB18
+      rxPool_sc_CP_Len                                       = "normal";
+      rxPool_sc_Period                                       = "sf40";
+      rxPool_data_CP_Len                                     = "normal";
+      rxPool_ResourceConfig_prb_Num                          = 20;
+      rxPool_ResourceConfig_prb_Start                        = 5;
+      rxPool_ResourceConfig_prb_End                          = 44;
+      rxPool_ResourceConfig_offsetIndicator_present          = "prSmall";
+      rxPool_ResourceConfig_offsetIndicator_choice           = 0;
+      rxPool_ResourceConfig_subframeBitmap_present           = "prBs40";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_buf              = "00000000000000000000";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_size             = 5;
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused      = 0;
+/*    rxPool_dataHoppingConfig_hoppingParameter                       = 0;
+      rxPool_dataHoppingConfig_numSubbands                            = "ns1";
+      rxPool_dataHoppingConfig_rbOffset                               = 0;
+      rxPool_commTxResourceUC-ReqAllowed                              = "TRUE";
+*/
+      // Parameters for SIB19
+      discRxPool_cp_Len                                               = "normal"
+      discRxPool_discPeriod                                           = "rf32"
+      discRxPool_numRetx                                              = 1;
+      discRxPool_numRepetition                                        = 2;
+      discRxPool_ResourceConfig_prb_Num                               = 5;
+      discRxPool_ResourceConfig_prb_Start                             = 3;
+      discRxPool_ResourceConfig_prb_End                               = 21;
+      discRxPool_ResourceConfig_offsetIndicator_present               = "prSmall";
+      discRxPool_ResourceConfig_offsetIndicator_choice                = 0;
+      discRxPool_ResourceConfig_subframeBitmap_present                = "prBs40";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf          = "f0ffffffff";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_size         = 5;
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused  = 0;
+
+      }
+    );
+
+
+    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.61.195";
+                              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 */
+
+    NETWORK_INTERFACES :
+    {
+        ENB_INTERFACE_NAME_FOR_S1_MME            = "eth0";
+        ENB_IPV4_ADDRESS_FOR_S1_MME              = "192.168.160.46";
+        ENB_INTERFACE_NAME_FOR_S1U               = "eth0";
+        ENB_IPV4_ADDRESS_FOR_S1U                 = "192.168.160.46";
+        ENB_PORT_FOR_S1U                         = 2152; # Spec 2152
+        ENB_IPV4_ADDRESS_FOR_X2C                 = "127.0.0.1";
+        ENB_PORT_FOR_X2C                         = 36422; # Spec 36422
+    };
+  }
+);
+
+MACRLCs = (
+	{
+	num_cc = 1;
+	tr_s_preference = "local_L1";
+	tr_n_preference = "local_RRC";
+	phy_test_mode = 0;
+        puSch10xSnr     =  160;
+        puCch10xSnr     =  160;
+        }
+);
+
+L1s = (
+      {
+	num_cc = 1;
+	tr_n_preference = "local_mac";
+        prach_dtx_threshold = 150;
+      }
+);
+
+RUs = (
+    {
+        //local_if_name  = "enp129s0f0";
+        local_if_name  = "dpdk";
+        sdr_addrs      = "softmodem -m 2048 -l 8 -n 2 -b 0000:3b:00.0 --proc-type auto --file-prefix ggg -- -p 0x1";
+        #sdr_addrs      = "softmodem -l 8 -n 2 -- -p 0x2";
+        remote_address = "127.0.0.2";
+        local_address  = "127.0.0.1";
+        local_portc    = 50000;
+        remote_portc   = 50000;
+        local_portd    = 50001;
+        remote_portd   = 50001;
+        local_rf       = "no"
+        tr_preference  = "raw_if4p5"
+        nb_tx          = 1
+        nb_rx          = 1
+        att_tx         = 0
+        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";
+    parallel_config    = "PARALLEL_SINGLE_THREAD";
+    #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";
+};
+
+     log_config :
+     {
+       global_log_level                      ="info";
+       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";
+    };
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf
new file mode 100644
index 0000000000000000000000000000000000000000..27fc90e5e30d2844f63615653e416ffbbb0cbc09
--- /dev/null
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf
@@ -0,0 +1,307 @@
+Active_gNBs = ( "gNB-Eurecom-5GNRBox");
+# Asn1_verbosity, choice in: none, info, annoying
+Asn1_verbosity = "none";
+
+gNBs =
+(
+ {
+    ////////// Identification parameters:
+    gNB_ID    =  0xe00;
+
+    cell_type =  "CELL_MACRO_GNB";
+
+    gNB_name  =  "gNB-Eurecom-5GNRBox";
+
+    // Tracking area code, 0x0000 and 0xfffe are reserved values
+    tracking_area_code  =  1;
+
+    plmn_list = ({mcc = 222; mnc = 01; mnc_length = 2;});	 
+
+    tr_s_preference     = "local_mac"
+
+    ////////// Physical parameters:
+
+    ssb_SubcarrierOffset                                      = 31; //0;
+    pdsch_AntennaPorts                                        = 1;
+	
+    servingCellConfigCommon = (
+    {
+ #spCellConfigCommon
+
+      physCellId                                                    = 0;
+
+#  downlinkConfigCommon
+    #frequencyInfoDL
+      # this is is the central frequency of SSB 
+      absoluteFrequencySSB                                          = 640000; //641272
+      dl_frequencyBand                                                 = 78;
+      # the carrier frequency is assumed to be in the middle of the carrier, i.e. dl_absoluteFrequencyPointA_kHz + dl_carrierBandwidth*12*SCS_kHz/2
+      dl_absoluteFrequencyPointA                                       = 638728; //640000;
+      #scs-SpecificCarrierList
+        dl_offstToCarrier                                              = 0;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+        dl_subcarrierSpacing                                           = 1;
+        dl_carrierBandwidth                                            = 106;
+     #initialDownlinkBWP
+      #genericParameters
+        # this is RBstart=84,L=13 (275*(L-1))+RBstart
+        initialDLBWPlocationAndBandwidth                                        = 6366; //28875; //6366; #6407; #3384;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+        initialDLBWPsubcarrierSpacing                                           = 1;
+      #pdcch-ConfigCommon
+        initialDLBWPcontrolResourceSetZero                                      = 0;
+        initialDLBWPsearchSpaceZero                                             = 0;
+      #pdsch-ConfigCommon
+        #pdschTimeDomainAllocationList (up to 16 entries)
+             initialDLBWPk0_0                    = 0;
+             #initialULBWPmappingType
+	     #0=typeA,1=typeB
+             initialDLBWPmappingType_0           = 0;
+             #this is SS=1,L=13
+             initialDLBWPstartSymbolAndLength_0  = 40;
+
+             initialDLBWPk0_1                    = 0;
+             initialDLBWPmappingType_1           = 0;
+             #this is SS=2,L=12 
+             initialDLBWPstartSymbolAndLength_1  = 53;
+
+             initialDLBWPk0_2                    = 0;
+             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                                                 = 78;
+      #scs-SpecificCarrierList
+      ul_offstToCarrier                                              = 0;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+      ul_subcarrierSpacing                                           = 1;
+      ul_carrierBandwidth                                            = 106;
+      pMax                                                          = 20;
+     #initialUplinkBWP
+      #genericParameters
+        initialULBWPlocationAndBandwidth                                        = 6366; //28875; //6366; #6407; #3384;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+        initialULBWPsubcarrierSpacing                                           = 1;
+      #rach-ConfigCommon
+        #rach-ConfigGeneric
+          prach_ConfigurationIndex                                  = 4;
+#prach_msg1_FDM
+#0 = one, 1=two, 2=four, 3=eight
+          prach_msg1_FDM                                            = 0;
+          prach_msg1_FrequencyStart                                 = 74;
+          zeroCorrelationZoneConfig                                 = 13;
+          #preambleReceivedTargetPower                               = -118;
+          preambleReceivedTargetPower                               = -104;
+#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
+          preambleTransMax                                          = 6;
+#powerRampingStep
+# 0=dB0,1=dB2,2=dB4,3=dB6
+        powerRampingStep                                            = 2;
+#ra_ReponseWindow
+#1,2,4,8,10,20,40,80
+        ra_ResponseWindow                                           = 5;
+#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
+#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR                = 4;
+#oneHalf (0..15) 4,8,12,16,...60,64
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB                   = 14; //15;
+#ra_ContentionResolutionTimer
+#(0..7) 8,16,24,32,40,48,56,64
+        ra_ContentionResolutionTimer                                = 7;
+        rsrp_ThresholdSSB                                           = 19;
+#prach-RootSequenceIndex_PR
+#1 = 839, 2 = 139
+        prach_RootSequenceIndex_PR                                  = 1;
+        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,
+
+# restrictedSetConfig
+# 0=unrestricted, 1=restricted type A, 2=restricted type B
+        restrictedSetConfig                                         = 0,
+      # pusch-ConfigCommon (up to 16 elements)
+        initialULBWPk2_0                      = 2;
+        initialULBWPmappingType_0             = 1
+        # this is SS=0 L=11
+        initialULBWPstartSymbolAndLength_0    = 55;
+ 	
+	initialULBWPk2_1                      = 2;
+        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;
+
+# pucch-ConfigCommon setup :
+# pucchGroupHopping
+# 0 = neither, 1= group hopping, 2=sequence hopping
+        pucchGroupHopping                                           = 0;
+        hoppingId                                                   = 40;
+        p0_nominal                                                  = -90;
+# ssb_PositionsInBurs_BitmapPR
+# 1=short, 2=medium, 3=long
+      ssb_PositionsInBurst_PR                                       = 2;
+      ssb_PositionsInBurst_Bitmap                                   = 1; #0x80;
+
+# ssb_periodicityServingCell
+# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 
+      ssb_periodicityServingCell                                    = 2;
+
+# dmrs_TypeA_position
+# 0 = pos2, 1 = pos3
+      dmrs_TypeA_Position                                           = 0;
+
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+      subcarrierSpacing                                             = 1;
+
+
+  #tdd-UL-DL-ConfigurationCommon
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+      referenceSubcarrierSpacing                                    = 1;
+      # pattern1 
+      # dl_UL_TransmissionPeriodicity
+      # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
+      dl_UL_TransmissionPeriodicity                                 = 6;
+      nrofDownlinkSlots                                             = 7; //8; //7;
+      nrofDownlinkSymbols                                           = 6; //0; //6;
+      nrofUplinkSlots                                               = 2;
+      nrofUplinkSymbols                                             = 4; //0; //4;
+
+  #ssPBCH_BlockPower                                             = 10;
+  ssPBCH_BlockPower                                             = 10;
+  }
+
+  );
+
+
+    # ------- 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.61.195";
+                              ipv6       = "192:168:30::17";
+                              active     = "yes";
+                              preference = "ipv4";
+                            }
+                          );
+
+    ///X2
+    enable_x2 = "yes";
+    t_reloc_prep      = 1000;      /* unit: millisecond */
+    tx2_reloc_overall = 2000;      /* unit: millisecond */
+    target_enb_x2_ip_address      = (
+                                     { ipv4       = "127.0.0.1";
+                                       ipv6       = "192:168:30::17";
+                                       preference = "ipv4";
+                                     }
+                                    );
+
+    NETWORK_INTERFACES :
+    {
+
+        GNB_INTERFACE_NAME_FOR_S1_MME            = "eth0";
+        GNB_IPV4_ADDRESS_FOR_S1_MME              = "192.168.160.146/24";
+        GNB_INTERFACE_NAME_FOR_S1U               = "eth0";
+        GNB_IPV4_ADDRESS_FOR_S1U                 = "192.168.160.146/24";
+        GNB_PORT_FOR_S1U                         = 2152; # Spec 2152
+        GNB_IPV4_ADDRESS_FOR_X2C                 = "127.0.0.2/24";
+        GNB_PORT_FOR_X2C                         = 36422; # Spec 36422
+    };
+  }
+);
+
+MACRLCs = (
+	{
+	num_cc = 1;
+	tr_s_preference = "local_L1";
+	tr_n_preference = "local_RRC";
+        }  
+);
+
+L1s = (
+    	{
+	num_cc = 1;
+	tr_n_preference = "local_mac";
+        }  
+);
+
+RUs = (
+    {		  
+       local_rf       = "no"
+         nb_tx          = 1
+         nb_rx          = 1
+         att_tx         = 0
+         att_rx         = 0;
+         bands          = [7];
+         max_pdschReferenceSignalPower = -27;
+         max_rxgain                    = 114;
+         eNB_instances  = [0];
+         //clock_src = "internal";
+         clock_src = "external";
+
+        local_if_name  = "dpdk";
+        sdr_addrs      = "softmodem -m 2048 -l 6  -n 3 -b 0000:3b:00.1 --proc-type auto --file-prefix hhh -- -p 0x1";
+        remote_address = "127.0.0.2";
+        local_address  = "127.0.0.1";
+        local_portc    = 50000;
+        remote_portc   = 50000;
+        local_portd    = 50001;
+        remote_portd   = 50001;
+        tr_preference  = "raw_if4p5"
+
+    }
+);  
+
+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";
+    parallel_config    = "PARALLEL_SINGLE_THREAD";
+    #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
+    worker_config      = "WORKER_DISABLE";
+  }
+);
+
+     log_config :
+     {
+       global_log_level                      ="info";
+       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";
+    };
+
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 d5bc492644ce6466e5f8a5f25aab4c9f52842b91..983404e4598334986cdf26b5fadf45ff05a73610 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
@@ -235,7 +235,7 @@ RUs = (
          att_rx         = 0;
          bands          = [7];
          max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 114;
+         max_rxgain                    = 75;
          eNB_instances  = [0];
 	 sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
          if_freq = 5300000000;
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf
index 93a6c7fbc92ee18b71e592a0a0dd31e0ddaba260..273735785109c26521ce447a1b77d6860c124719 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf
@@ -235,7 +235,7 @@ RUs = (
          att_rx         = 0;
          bands          = [7];
          max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 114;
+         max_rxgain                    = 75;
          eNB_instances  = [0];
 	 sdr_addrs = "type=n300";
     }
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 72a27cc1e73d2ddad59ef5fc9a67c26f63cef48b..e171b2faa98684a8142adeb7cf8576c8f52eaa16 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
@@ -235,7 +235,7 @@ RUs = (
          att_rx         = 0;
          bands          = [7];
          max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 114;
+         max_rxgain                    = 75;
          eNB_instances  = [0];
 	 sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
          if_freq = 5124520000L;
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf
index fdc4894da64a9606bf69b59fb1440d64e55278f4..862f0e6303f29bca115302c991c844f18af76649 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf
@@ -21,183 +21,166 @@ gNBs =
 
     ////////// Physical parameters:
 
-    component_carriers = (
-      {
-      node_function                                                 = "3GPP_gNODEB";
-      node_timing                                                   = "synch_to_ext_device";
-      node_synch_ref                                                = 0;
-      frame_type                                                    = "TDD";
-      DL_prefix_type                                                = "NORMAL";
-      UL_prefix_type                                                = "NORMAL";
-      eutra_band                                                    = 78;
-      downlink_frequency                                            = 3510000000L;
-      uplink_frequency_offset                                       = -120000000;
-      Nid_cell                                                      = 0;
-      N_RB_DL                                                       = 106;
-      nb_antenna_ports                                              = 1;
-      nb_antennas_tx                                                = 1;
-      nb_antennas_rx                                                = 1;
-      tx_gain                                                       = 90;
-      rx_gain                                                       = 125;
-      MIB_subCarrierSpacingCommon                                   = 30;
-      MIB_ssb_SubcarrierOffset                                      = 0;
-      MIB_dmrs_TypeA_Position                                       = 2;
-      pdcch_ConfigSIB1                                              = 0;
-      SIB1_frequencyOffsetSSB                                       = "khz5";
-      SIB1_ssb_PeriodicityServingCell                               = 5;
-      SIB1_ss_PBCH_BlockPower                                       = -60;
-      absoluteFrequencySSB                                          = 0;
-      DL_FreqBandIndicatorNR                                        = 15;
-      DL_absoluteFrequencyPointA                                    = 15;
-      DL_offsetToCarrier                                            = 15;
-      DL_SCS_SubcarrierSpacing                                      = "kHz30";
-      DL_SCS_SpecificCarrier_k0                                     = 0;
-      DL_carrierBandwidth                                           = 15;
-      DL_locationAndBandwidth                                       = 15;
-      DL_BWP_SubcarrierSpacing                                      = "kHz30";
-      DL_BWP_prefix_type                                            = "NORMAL";
-      UL_FreqBandIndicatorNR                                        = 15;
-      UL_absoluteFrequencyPointA                                    = 13;
-      UL_additionalSpectrumEmission                                 = 3;
-      UL_p_Max                                                      = -1;
-      UL_frequencyShift7p5khz                                       = "TRUE";
-      UL_offsetToCarrier                                            = 10;
-      UL_SCS_SubcarrierSpacing                                      = "kHz30";
-      UL_SCS_SpecificCarrier_k0                                     = 0;
-      UL_carrierBandwidth                                           = 15;
-      UL_locationAndBandwidth                                       = 15;
-      UL_BWP_SubcarrierSpacing                                      = "kHz30";
-      UL_BWP_prefix_type                                            = "NORMAL";
-      UL_timeAlignmentTimerCommon                                   = "infinity";
-      ServingCellConfigCommon_n_TimingAdvanceOffset                 = "n0"
-      ServingCellConfigCommon_ssb_PositionsInBurst_PR               = 0x01;
-      ServingCellConfigCommon_ssb_periodicityServingCell            = 10;
-      ServingCellConfigCommon_dmrs_TypeA_Position                   = 2;
-      NIA_SubcarrierSpacing                                         = "kHz15"; 
-      ServingCellConfigCommon_ss_PBCH_BlockPower                    = -60;
-      referenceSubcarrierSpacing                                    = "kHz15";
-      dl_UL_TransmissionPeriodicity                                 = "ms0p5";
-      nrofDownlinkSlots                                             = 10;
-      nrofDownlinkSymbols                                           = 10;
-      nrofUplinkSlots                                               = 10;
-      nrofUplinkSymbols                                             = 10;
-      rach_totalNumberOfRA_Preambles                                = 63;
-      rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_choice         = "oneEighth";
-      rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneEighth      = 4;
-      rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneFourth      = 8;
-      rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneHalf        = 16;
-      rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_one            = 24;
-      rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_two            = 32;
-      rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_four           = 8;
-      rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_eight          = 4;
-      rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_sixteen        = 2;
-      rach_groupBconfigured                                         = "ENABLE";
-      rach_ra_Msg3SizeGroupA                                        = 56;
-      rach_messagePowerOffsetGroupB                                 = "dB0";
-      rach_numberOfRA_PreamblesGroupA                               = 32;
-      rach_ra_ContentionResolutionTimer                             = 8;
-      rsrp_ThresholdSSB                                             = 64;
-      rsrp_ThresholdSSB_SUL                                         = 64;
-      prach_RootSequenceIndex_choice                                = "l839";
-      prach_RootSequenceIndex_l839                                  = 0;
-      prach_RootSequenceIndex_l139                                  = 0;
-      prach_msg1_SubcarrierSpacing                                  = "kHz30";
-      restrictedSetConfig                                           = "unrestrictedSet";
-      msg3_transformPrecoding                                       = "ENABLE";
-      prach_ConfigurationIndex                                      = 10;
-      prach_msg1_FDM                                                = "one";
-      prach_msg1_FrequencyStart                                     = 10;
-      zeroCorrelationZoneConfig                                     = 10;
-      preambleReceivedTargetPower                                   = -150;
-      preambleTransMax                                              = 6;
-      powerRampingStep                                              = "dB0";
-      ra_ResponseWindow                                             = 8;
-      groupHoppingEnabledTransformPrecoding                         = "ENABLE";
-      msg3_DeltaPreamble                                            = 0;
-      p0_NominalWithGrant                                           = 0;
-      PUSCH_TimeDomainResourceAllocation_k2                         = 0;
-      PUSCH_TimeDomainResourceAllocation_mappingType                = "typeA";
-      PUSCH_TimeDomainResourceAllocation_startSymbolAndLength       = 0;
-      pucch_ResourceCommon                                          = 0;
-      pucch_GroupHopping                                            = "neither";
-      hoppingId                                                     = 0;
-      p0_nominal                                                    = -30;
-      PDSCH_TimeDomainResourceAllocation_k0                         = 2;
-      PDSCH_TimeDomainResourceAllocation_mappingType                = "typeA";
-      PDSCH_TimeDomainResourceAllocation_startSymbolAndLength       = 0;
-      rateMatchPatternId                                            = 0;
-      RateMatchPattern_patternType                                  = "bitmaps";
-      symbolsInResourceBlock                                        = "oneSlot";
-      periodicityAndPattern                                         = 2;
-      RateMatchPattern_controlResourceSet                           = 5;
-      RateMatchPattern_subcarrierSpacing                            = "kHz30";
-      RateMatchPattern_mode                                         = "dynamic";
-      controlResourceSetZero                                        = 0;
-      searchSpaceZero                                               = 0;
-      searchSpaceSIB1                                               = 10;
-      searchSpaceOtherSystemInformation                             = 10;
-      pagingSearchSpace                                             = 10;
-      ra_SearchSpace                                                = 10;
-      PDCCH_common_controlResourceSetId                             = 5;
-      PDCCH_common_ControlResourceSet_duration                      = 2;
-      PDCCH_cce_REG_MappingType                                     = "nonInterleaved";
-      PDCCH_reg_BundleSize                                          = 3;
-      PDCCH_interleaverSize                                         = 3;
-      PDCCH_shiftIndex                                              = 10;  
-      PDCCH_precoderGranularity                                     = "sameAsREG-bundle";
-      PDCCH_TCI_StateId                                             = 32;
-      tci_PresentInDCI                                              = "ENABLE";
-      PDCCH_DMRS_ScramblingID                                       = 0;
-      SearchSpaceId                                                 = 10;
-      commonSearchSpaces_controlResourceSetId                       = 5;
-      SearchSpace_monitoringSlotPeriodicityAndOffset_choice         = "sl1";
-      SearchSpace_monitoringSlotPeriodicityAndOffset_value          = 0;
-      SearchSpace_duration                                          = 2;
-      SearchSpace_nrofCandidates_aggregationLevel1                  = 0;
-      SearchSpace_nrofCandidates_aggregationLevel2                  = 0;
-      SearchSpace_nrofCandidates_aggregationLevel4                  = 0;
-      SearchSpace_nrofCandidates_aggregationLevel8                  = 0;
-      SearchSpace_nrofCandidates_aggregationLevel16                 = 0;
-      SearchSpace_searchSpaceType                                   = "common";
-      Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel1     = 1;
-      Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel2     = 1;
-      Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel4     = 1;
-      Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel8     = 1;
-      Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel16    = 1; 
-      Common_dci_Format2_3_monitoringPeriodicity                    = 1;
-      Common_dci_Format2_3_nrofPDCCH_Candidates                     = 1;
-      ue_Specific__dci_Formats                                      = "formats0-0-And-1-0";
-      RateMatchPatternLTE_CRS_carrierFreqDL                         = 6;
-      RateMatchPatternLTE_CRS_carrierBandwidthDL                    = 6;
-      RateMatchPatternLTE_CRS_nrofCRS_Ports                         = 1;
-      RateMatchPatternLTE_CRS_v_Shift                               = 0;
-      RateMatchPatternLTE_CRS_radioframeAllocationPeriod            = 1;
-      RateMatchPatternLTE_CRS_radioframeAllocationOffset            = 0;
-      RateMatchPatternLTE_CRS_subframeAllocation_choice             = "oneFrame";
-      }
-    );
-
-
-    srb1_parameters :
+    ssb_SubcarrierOffset                                      = 0;
+    pdsch_AntennaPorts                                        = 1;
+	
+    servingCellConfigCommon = (
     {
-        # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
-        timer_poll_retransmit    = 80;
+ #spCellConfigCommon
 
-        # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
-        timer_reordering         = 35;
+      physCellId                                                    = 0;
 
-        # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
-        timer_status_prohibit    = 0;
+#  downlinkConfigCommon
+    #frequencyInfoDL
+      # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
+      absoluteFrequencySSB                                          = 641032;
+      dl_frequencyBand                                                 = 78;
+      # this is 3600 MHz
+      dl_absoluteFrequencyPointA                                       = 640000;
+      #scs-SpecificCarrierList
+        dl_offstToCarrier                                              = 0;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+        dl_subcarrierSpacing                                           = 1;
+        dl_carrierBandwidth                                            = 106;
+     #initialDownlinkBWP
+      #genericParameters
+        # this is RBstart=0,L=50 (275*(L-1))+RBstart
+        initialDLBWPlocationAndBandwidth                                        = 13475;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+        initialDLBWPsubcarrierSpacing                                           = 1;
+      #pdcch-ConfigCommon
+        initialDLBWPcontrolResourceSetZero                                      = 12;
+        initialDLBWPsearchSpaceZero                                             = 0;
+      #pdsch-ConfigCommon
+        #pdschTimeDomainAllocationList (up to 16 entries)
+             initialDLBWPk0_0                    = 0;
+             #initialULBWPmappingType
+	     #0=typeA,1=typeB
+             initialDLBWPmappingType_0           = 0;
+             #this is SS=2,L=3
+             initialDLBWPstartSymbolAndLength_0  = 40;
 
-        # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
-        poll_pdu                 =  4;
+             initialDLBWPk0_1                    = 0;
+             initialDLBWPmappingType_1           = 0;
+             #this is SS=2,L=12 
+             initialDLBWPstartSymbolAndLength_1  = 53;
 
-        # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
-        poll_byte                =  99999;
+             initialDLBWPk0_2                    = 0;
+             initialDLBWPmappingType_2           = 0;
+             #this is SS=1,L=12 
+             initialDLBWPstartSymbolAndLength_2  = 54;
+  #uplinkConfigCommon 
+     #frequencyInfoUL
+      ul_frequencyBand                                                 = 78;
+      #scs-SpecificCarrierList
+      ul_offstToCarrier                                              = 0;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+      ul_subcarrierSpacing                                           = 1;
+      ul_carrierBandwidth                                            = 106;
+      pMax                                                          = 20;
+     #initialUplinkBWP
+      #genericParameters
+        initialULBWPlocationAndBandwidth                                        = 13475;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+        initialULBWPsubcarrierSpacing                                           = 1;
+      #rach-ConfigCommon
+        #rach-ConfigGeneric
+          prach_ConfigurationIndex                                  = 98;
+#prach_msg1_FDM
+#0 = one, 1=two, 2=four, 3=eight
+          prach_msg1_FDM                                            = 0;
+          prach_msg1_FrequencyStart                                 = 0;
+          zeroCorrelationZoneConfig                                 = 13;
+          preambleReceivedTargetPower                               = -118;
+#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
+          preambleTransMax                                          = 6;
+#powerRampingStep
+# 0=dB0,1=dB2,2=dB4,3=dB6
+        powerRampingStep                                            = 1;
+#ra_ReponseWindow
+#1,2,4,8,10,20,40,80
+        ra_ResponseWindow                                           = 4;
+#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
+#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR                = 3;
+#oneHalf (0..15) 4,8,12,16,...60,64
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB                   = 15;
+#ra_ContentionResolutionTimer
+#(0..7) 8,16,24,32,40,48,56,64
+        ra_ContentionResolutionTimer                                = 7;
+        rsrp_ThresholdSSB                                           = 19;
+#prach-RootSequenceIndex_PR
+#0 = 839, 1 = 139
+        prach_RootSequenceIndex_PR                                  = 1;
+        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,
+
+# restrictedSetConfig
+# 0=unrestricted, 1=restricted type A, 2=restricted type B
+        restrictedSetConfig                                         = 0,
+      # pusch-ConfigCommon (up to 16 elements)
+        initialULBWPk2_0                      = 2;
+        initialULBWPmappingType_0             = 1
+        # this is SS=0 L=11
+        initialULBWPstartSymbolAndLength_0    = 55;
+ 	
+	initialULBWPk2_1                      = 2;
+        initialULBWPmappingType_1             = 1;
+        # this is SS=0 L=12
+        initialULBWPstartSymbolAndLength_1    = 69;
+
+
+        msg3_DeltaPreamble                                          = 1;
+        p0_NominalWithGrant                                         =-90;
+
+# pucch-ConfigCommon setup :
+# pucchGroupHopping
+# 0 = neither, 1= group hopping, 2=sequence hopping
+        pucchGroupHopping                                           = 0;
+        hoppingId                                                   = 40;
+        p0_nominal                                                  = -90;
+# ssb_PositionsInBurs_BitmapPR
+# 1=short, 2=medium, 3=long
+      ssb_PositionsInBurst_PR                                       = 2;
+      ssb_PositionsInBurst_Bitmap                                   = 1;
+
+# ssb_periodicityServingCell
+# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 
+      ssb_periodicityServingCell                                    = 2;
+
+# dmrs_TypeA_position
+# 0 = pos2, 1 = pos3
+      dmrs_TypeA_Position                                           = 0;
+
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+      subcarrierSpacing                                             = 1;
+
+
+  #tdd-UL-DL-ConfigurationCommon
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+      referenceSubcarrierSpacing                                    = 1;
+      # pattern1 
+      # dl_UL_TransmissionPeriodicity
+      # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
+      dl_UL_TransmissionPeriodicity                                 = 6;
+      nrofDownlinkSlots                                             = 7;
+      nrofDownlinkSymbols                                           = 6;
+      nrofUplinkSlots                                               = 2;
+      nrofUplinkSymbols                                             = 4;
+
+  ssPBCH_BlockPower                                             = 10;
+  }
+
+  );
 
-        # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
-        max_retx_threshold       =  4;
-    }
 
     # ------- SCTP definitions
     SCTP :
@@ -255,7 +238,7 @@ RUs = (
          max_rxgain                    = 114;
          eNB_instances  = [0];
 	 sdr_addrs = "type=b200";
-
+         #clock_src = "external";
     }
 );  
 
@@ -264,20 +247,10 @@ THREAD_STRUCT = (
     #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
     parallel_config    = "PARALLEL_SINGLE_THREAD";
     #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
-    worker_config      = "WORKER_DISABLE";
+    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";
-};
-
      log_config :
      {
        global_log_level                      ="info";
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 dbcbb2ed4f5456add888adeb842345d3e94fc5f2..aeb9e2be8890336e02750f0317c01f3f3b998dff 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
@@ -246,7 +246,7 @@ RUs = (
          att_rx         = 0;
          bands          = [7];
          max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 114;
+         max_rxgain                    = 75;
          eNB_instances  = [0];
          #beamforming 1x4 matrix:
          bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000];
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf
index ae17efc9bd0c674df1a29f2e59b4b3efea138b03..9420c488ec0b080456e27e8a5f3fa993a132f642 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf
@@ -254,7 +254,7 @@ RUs = (
          att_rx         = 0;
          bands          = [7];
          max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 114;
+         max_rxgain                    = 75;
          eNB_instances  = [0];
 	 sdr_addrs = "addr=192.168.10.2,mgmt_addr=192.168.10.2";
          clock_src = "external";
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf
index 464ce6b9aae149f2278f001b7430d832371a9b61..0a6268f8a85b856ac572f95db8c7874363130389 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf
@@ -240,7 +240,7 @@ RUs = (
          att_rx         = 0;
          bands          = [7];
          max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 114;
+         max_rxgain                    = 75;
          eNB_instances  = [0];
 	 sdr_addrs = "addr=192.168.10.2,mgmt_addr=192.168.10.2,second_addr=192.168.20.2";
          clock_src = "external";
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_enb.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_enb.conf
index ea105d86b62abdd255804e375323f0eda99d1a14..4c0d346360ed17a9e95a262e984fa3602e318ce9 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_enb.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_enb.conf
@@ -235,7 +235,7 @@ MACRLCs = (
 
 THREAD_STRUCT = (
   {
-    parallel_config = "PARALLEL_RU_L1_TRX_SPLITaaaaaa";
+    parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
     worker_config = "ENABLE";
   }
 );
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
index b63939add2be238eeee83d1d0f710a793e30ba2b..2eed408b53cc9e708d15581ef7c3ada50ce3c573 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
@@ -23,7 +23,9 @@ gNBs =
 
     ssb_SubcarrierOffset                                      = 31; //0;
     pdsch_AntennaPorts                                        = 1;
-	
+    pusch_TargetSNRx10                                        = 200;
+    pucch_TargetSNRx10                                        = 200;
+
     servingCellConfigCommon = (
     {
  #spCellConfigCommon
@@ -132,12 +134,12 @@ gNBs =
       # pusch-ConfigCommon (up to 16 elements)
         initialULBWPk2_0                      = 2;
         initialULBWPmappingType_0             = 1
-        # this is SS=0 L=11
+        # this is SS=0 L=12
         initialULBWPstartSymbolAndLength_0    = 55;
  	
 	initialULBWPk2_1                      = 2;
         initialULBWPmappingType_1             = 1;
-        # this is SS=0 L=12
+        # this is SS=0 L=11
         initialULBWPstartSymbolAndLength_1    = 69;
 
         initialULBWPk2_2                      = 7;
@@ -266,8 +268,8 @@ RUs = (
 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";
-    parallel_config    = "PARALLEL_SINGLE_THREAD";
+    parallel_config    = "PARALLEL_RU_L1_TRX_SPLIT";
+    //parallel_config    = "PARALLEL_SINGLE_THREAD";
     #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
     worker_config      = "WORKER_ENABLE";
   }
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf
new file mode 100644
index 0000000000000000000000000000000000000000..f30c9284484f4dd34204d491561e5ae44b64169a
--- /dev/null
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb_n310.conf
@@ -0,0 +1,295 @@
+Active_gNBs = ( "gNB-Eurecom-5GNRBox");
+# Asn1_verbosity, choice in: none, info, annoying
+Asn1_verbosity = "none";
+
+gNBs =
+(
+ {
+    ////////// Identification parameters:
+    gNB_ID    =  0xe00;
+
+    cell_type =  "CELL_MACRO_GNB";
+
+    gNB_name  =  "gNB-Eurecom-5GNRBox";
+
+    // Tracking area code, 0x0000 and 0xfffe are reserved values
+    tracking_area_code  =  1;
+
+    plmn_list = ({mcc = 222; mnc = 01; mnc_length = 2;});	 
+
+    tr_s_preference     = "local_mac"
+
+    ////////// Physical parameters:
+
+    ssb_SubcarrierOffset                                      = 31; //0;
+    pdsch_AntennaPorts                                        = 1;
+	
+    servingCellConfigCommon = (
+    {
+ #spCellConfigCommon
+
+      physCellId                                                    = 0;
+
+#  downlinkConfigCommon
+    #frequencyInfoDL
+      # this is 3600 MHz + 84 PRBs@30kHz SCS (same as initial BWP)
+      absoluteFrequencySSB                                          = 641272; //641032;      #641968; 641968=start of ssb at 3600MHz + 82 RBs    641032=center of SSB at center of cell
+      dl_frequencyBand                                                 = 78;
+      # this is 3600 MHz
+      dl_absoluteFrequencyPointA                                       = 640000;
+      #scs-SpecificCarrierList
+        dl_offstToCarrier                                              = 0;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+        dl_subcarrierSpacing                                           = 1;
+        dl_carrierBandwidth                                            = 106;
+     #initialDownlinkBWP
+      #genericParameters
+        # this is RBstart=84,L=13 (275*(L-1))+RBstart
+        initialDLBWPlocationAndBandwidth                                        = 6366; //28875; //6366; #6407; #3384;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+        initialDLBWPsubcarrierSpacing                                           = 1;
+      #pdcch-ConfigCommon
+        initialDLBWPcontrolResourceSetZero                                      = 0;
+        initialDLBWPsearchSpaceZero                                             = 0;
+      #pdsch-ConfigCommon
+        #pdschTimeDomainAllocationList (up to 16 entries)
+             initialDLBWPk0_0                    = 0;
+             #initialULBWPmappingType
+	     #0=typeA,1=typeB
+             initialDLBWPmappingType_0           = 0;
+             #this is SS=1,L=13
+             initialDLBWPstartSymbolAndLength_0  = 40;
+
+             initialDLBWPk0_1                    = 0;
+             initialDLBWPmappingType_1           = 0;
+             #this is SS=2,L=12 
+             initialDLBWPstartSymbolAndLength_1  = 53;
+
+             initialDLBWPk0_2                    = 0;
+             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                                                 = 78;
+      #scs-SpecificCarrierList
+      ul_offstToCarrier                                              = 0;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+      ul_subcarrierSpacing                                           = 1;
+      ul_carrierBandwidth                                            = 106;
+      pMax                                                          = 20;
+     #initialUplinkBWP
+      #genericParameters
+        initialULBWPlocationAndBandwidth                                        = 6366; //28875; //6366; #6407; #3384;
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+        initialULBWPsubcarrierSpacing                                           = 1;
+      #rach-ConfigCommon
+        #rach-ConfigGeneric
+          prach_ConfigurationIndex                                  = 98;
+#prach_msg1_FDM
+#0 = one, 1=two, 2=four, 3=eight
+          prach_msg1_FDM                                            = 0;
+          prach_msg1_FrequencyStart                                 = 0;
+          zeroCorrelationZoneConfig                                 = 13;
+          preambleReceivedTargetPower                               = -90;
+#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
+          preambleTransMax                                          = 6;
+#powerRampingStep
+# 0=dB0,1=dB2,2=dB4,3=dB6
+        powerRampingStep                                            = 1;
+#ra_ReponseWindow
+#1,2,4,8,10,20,40,80
+        ra_ResponseWindow                                           = 5;
+#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
+#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR                = 4;
+#oneHalf (0..15) 4,8,12,16,...60,64
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB                   = 14; //15;
+#ra_ContentionResolutionTimer
+#(0..7) 8,16,24,32,40,48,56,64
+        ra_ContentionResolutionTimer                                = 7;
+        rsrp_ThresholdSSB                                           = 19;
+#prach-RootSequenceIndex_PR
+#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
+        #  
+        msg1_SubcarrierSpacing                                      = 1,
+
+# restrictedSetConfig
+# 0=unrestricted, 1=restricted type A, 2=restricted type B
+        restrictedSetConfig                                         = 0,
+      # pusch-ConfigCommon (up to 16 elements)
+        initialULBWPk2_0                      = 2;
+        initialULBWPmappingType_0             = 1
+        # this is SS=0 L=11
+        initialULBWPstartSymbolAndLength_0    = 55;
+ 	
+	initialULBWPk2_1                      = 2;
+        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;
+
+# pucch-ConfigCommon setup :
+# pucchGroupHopping
+# 0 = neither, 1= group hopping, 2=sequence hopping
+        pucchGroupHopping                                           = 0;
+        hoppingId                                                   = 40;
+        p0_nominal                                                  = -90;
+# ssb_PositionsInBurs_BitmapPR
+# 1=short, 2=medium, 3=long
+      ssb_PositionsInBurst_PR                                       = 2;
+      ssb_PositionsInBurst_Bitmap                                   = 1; #0x80;
+
+# ssb_periodicityServingCell
+# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 
+      ssb_periodicityServingCell                                    = 2;
+
+# dmrs_TypeA_position
+# 0 = pos2, 1 = pos3
+      dmrs_TypeA_Position                                           = 0;
+
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+      subcarrierSpacing                                             = 1;
+
+
+  #tdd-UL-DL-ConfigurationCommon
+# subcarrierSpacing
+# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
+      referenceSubcarrierSpacing                                    = 1;
+      # pattern1 
+      # dl_UL_TransmissionPeriodicity
+      # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
+      dl_UL_TransmissionPeriodicity                                 = 6;
+      nrofDownlinkSlots                                             = 7; //8; //7;
+      nrofDownlinkSymbols                                           = 6; //0; //6;
+      nrofUplinkSlots                                               = 2;
+      nrofUplinkSymbols                                             = 4; //0; //4;
+
+  ssPBCH_BlockPower                                             = 0;
+  }
+
+  );
+
+
+    # ------- 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.99";
+                              ipv6       = "192:168:30::17";
+                              active     = "yes";
+                              preference = "ipv4";
+                            }
+                          );
+
+    ///X2
+    enable_x2 = "yes";
+    t_reloc_prep      = 1000;      /* unit: millisecond */
+    tx2_reloc_overall = 2000;      /* unit: millisecond */
+    target_enb_x2_ip_address      = (
+                                     { ipv4       = "192.168.18.199";
+                                       ipv6       = "192:168:30::17";
+                                       preference = "ipv4";
+                                     }
+                                    );
+
+    NETWORK_INTERFACES :
+    {
+
+        GNB_INTERFACE_NAME_FOR_S1_MME            = "eth0";
+        GNB_IPV4_ADDRESS_FOR_S1_MME              = "192.168.18.196/24";
+        GNB_INTERFACE_NAME_FOR_S1U               = "eth0";
+        GNB_IPV4_ADDRESS_FOR_S1U                 = "192.168.18.196/24";
+        GNB_PORT_FOR_S1U                         = 2152; # Spec 2152
+        GNB_IPV4_ADDRESS_FOR_X2C                 = "192.168.18.196/24";
+        GNB_PORT_FOR_X2C                         = 36422; # Spec 36422
+    };
+  }
+);
+
+MACRLCs = (
+	{
+	num_cc = 1;
+	tr_s_preference = "local_L1";
+	tr_n_preference = "local_RRC";
+        }  
+);
+
+L1s = (
+    	{
+	num_cc = 1;
+	tr_n_preference = "local_mac";
+        }  
+);
+
+RUs = (
+    {		  
+       local_rf       = "yes"
+         nb_tx          = 1
+         nb_rx          = 1
+         att_tx         = 0
+         att_rx         = 0;
+         bands          = [7];
+         max_pdschReferenceSignalPower = -27;
+         max_rxgain                    = 75;
+         eNB_instances  = [0];
+	 sdr_addrs = "addr=192.168.10.2,mgmt_addr=192.168.10.2,second_addr=192.168.20.2";
+         clock_src = "external";
+	 time_src = "external";
+    }
+);  
+
+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";
+    #parallel_config    = "PARALLEL_SINGLE_THREAD";
+    #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
+    worker_config      = "WORKER_ENABLE";
+  }
+);
+
+     log_config :
+     {
+       global_log_level                      ="info";
+       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";
+    };
+
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
index 4d890200770a33f8f7bb88d59cd1be1d7ded2a90..e3b9797105a40bc187d374cd8ac2a47a7d128529 100644
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -2675,6 +2675,15 @@ void set_function_spec_param(RU_t *ru) {
         exit(-1);
       }
 
+      if (ru->ifdevice.get_internal_parameter != NULL) {
+        void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in");
+        if (t != NULL)
+          ru->fh_south_in = t;
+        t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out");
+        if (t != NULL)
+          ru->fh_south_out = t;
+      }
+
       malloc_IF4p5_buffer(ru);
       break;
 
diff --git a/targets/RT/USER/rfsim.c b/targets/RT/USER/rfsim.c
index a9a091243334e1690cb402eab15a8bba469de8e0..eb380b95186ae78ed8ec7143bb91615e7d964c31 100644
--- a/targets/RT/USER/rfsim.c
+++ b/targets/RT/USER/rfsim.c
@@ -337,6 +337,7 @@ void init_ue_devices(PHY_VARS_UE *UE) {
 void init_ocm(void) {
   module_id_t UE_id, ru_id;
   int CC_id;
+  double DS_TDL = .03;
   randominit(0);
   set_taus_seed(0);
   init_channelmod();
@@ -357,6 +358,7 @@ void init_ocm(void) {
                                AWGN,
                                N_RB2sampling_rate(RC.ru[ru_id]->frame_parms->N_RB_DL),
                                N_RB2channel_bandwidth(RC.ru[ru_id]->frame_parms->N_RB_DL),
+                               DS_TDL,
                                0.0,
                                0,
                                0);
@@ -369,6 +371,7 @@ void init_ocm(void) {
                                AWGN,
                                N_RB2sampling_rate(RC.ru[ru_id]->frame_parms->N_RB_UL),
                                N_RB2channel_bandwidth(RC.ru[ru_id]->frame_parms->N_RB_UL),
+                               DS_TDL,
                                0.0,
                                0,
                                0);