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 0c7508039856bb00cff9b70ad7a8eb96d4266589..835e334bbb5fcc50c6af67ceae64e757d467dfc3 100644
--- a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf
+++ b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf
@@ -219,7 +219,7 @@ RUs = (
          ## beamforming 4x4 matrix:
          #bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000, 0x00000000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00007fff];
 
-         sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2,mgmt_addr=192.168.18.85";
+         sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
     }
 );  
 
diff --git a/ci-scripts/datalog_rt_stats.2x2.yaml b/ci-scripts/datalog_rt_stats.2x2.yaml
index a93ef6aa8c879cee167e27360709511a1233ac97..eccde746cc773bba350961a45ce4bbb8ea1c2d4c 100644
--- a/ci-scripts/datalog_rt_stats.2x2.yaml
+++ b/ci-scripts/datalog_rt_stats.2x2.yaml
@@ -16,7 +16,7 @@ Ref :
   L1 Rx processing : 175.0
   PUSCH inner-receiver : 100.0
   PUSCH decoding : 180.0 
-  DL & UL scheduling timing stats : 37.0
+  DL & UL scheduling timing : 37.0
   UL Indication : 38.0
 Threshold :
   feprx : 1.25
@@ -28,5 +28,5 @@ Threshold :
   L1 Rx processing : 1.25
   PUSCH inner-receiver : 1.25
   PUSCH decoding : 1.25
-  DL & UL scheduling timing stats : 1.25
+  DL & UL scheduling timing : 1.25
   UL Indication : 1.25
diff --git a/ci-scripts/datalog_rt_stats.default.yaml b/ci-scripts/datalog_rt_stats.default.yaml
index 0da04dcaed23dc9d4a4869bee4fd2075d94636d8..97591a766dcd1cc8a18a831b0a48d6c481695473 100644
--- a/ci-scripts/datalog_rt_stats.default.yaml
+++ b/ci-scripts/datalog_rt_stats.default.yaml
@@ -17,7 +17,7 @@ Ref :
   PUSCH inner-receiver : 100.0
   #PUSCH decoding : 180.0
   PUSCH decoding : 240.0
-  DL & UL scheduling timing stats : 37.0
+  DL & UL scheduling timing : 37.0
   UL Indication : 38.0
 Threshold :
   feprx : 1.25
@@ -29,5 +29,5 @@ Threshold :
   L1 Rx processing : 1.25
   PUSCH inner-receiver : 1.25
   PUSCH decoding : 1.25
-  DL & UL scheduling timing stats : 1.25
+  DL & UL scheduling timing : 1.25
   UL Indication : 1.25
diff --git a/ci-scripts/stats_monitor_conf.yaml b/ci-scripts/stats_monitor_conf.yaml
index 9a2ececd1833b93072844d6668a8120ecb50a307..4e1f87ed176e2dd1350bd82eb0742a46924b2b81 100644
--- a/ci-scripts/stats_monitor_conf.yaml
+++ b/ci-scripts/stats_monitor_conf.yaml
@@ -25,7 +25,7 @@ gnb :
     L1 Rx processing:
     PUSCH inner-receiver:
     PUSCH decoding:
-    DL & UL scheduling timing stats:
+    DL & UL scheduling timing:
     UL Indication:
   graph : 
     page1:
@@ -45,5 +45,5 @@ gnb :
     page4:
       rt.PUSCH inner-receiver:
       rt.PUSCH decoding:
-      rt.DL & UL scheduling timing stats:
+      rt.DL & UL scheduling timing:
       rt.UL Indication:
diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml
index a2c68e9ef6a31d6f560006d43f17847b82c654e1..1fdc3446d9ce19d0a85abeeca4a04db77ec37b25 100755
--- a/cmake_targets/autotests/test_case_list.xml
+++ b/cmake_targets/autotests/test_case_list.xml
@@ -1134,7 +1134,7 @@
                   -n100 -s2 -U 2 1 3
                   -n10 -s20 -U 3 0 0 2 -gR -x1 -y4 -z4
                   -n10 -s20 -U 3 0 0 2 -gR -x2 -y4 -z4
-                  -n100 -m0 -e0 -R25 -b25 -i</main_exec_args>
+                  -n100 -m0 -e0 -R25 -b25 -i 2 1 0</main_exec_args>
       <tags>nr_dlsim.test1 nr_dlsim.test2 nr_dlsim.test3 nr_dlsim.test4 nr_dlsim.test5 nr_dlsim.test6 nr_dlsim.test7 nr_dlsim.test8 nr_dlsim.test9 nr_dlsim.test10 nr_dlsim.test11 nr_dlsim.test12 nr_dlsim.test13 nr_dlsim.test14 nr_dlsim.test15 nr_dlsim.test16 nr_dlsim.test17 nr_dlsim.test18 nr_dlsim.test19 nr_dlsim.test20 nr_dlsim.test21 nr_dlsim.test22 nr_dlsim.test23</tags>
       <search_expr_true>PDSCH test OK</search_expr_true>
       <search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
@@ -1311,7 +1311,10 @@
                                  (Test15: MCS 19 50 PRBs 2 RX_Antenna),
                                  (Test16: MCS 9 106 PRBs MIMO 2 layers),
                                  (Test17: MCS 9 106 PRBs MIMO 4 layers),
-                                 (Test18: 25 PRBs, 15 kHz SCS)</desc>
+                                 (Test18: 25 PRBs, 15 kHz SCS),
+                                 (Test19: 3GPP G-FR1-A4-13 2 RX Antennas Requirements Test),
+                                 (Test20: 3GPP G-FR1-A4-13 4 RX Antennas Requirements Test),
+                                 (Test21: 3GPP G-FR1-A4-13 8 RX Antennas Requirements Test)</desc>
       <pre_compile_prog></pre_compile_prog>
       <compile_prog>$OPENAIR_DIR/cmake_targets/build_oai</compile_prog>
       <compile_prog_args> --phy_simulators  -c </compile_prog_args>
@@ -1323,20 +1326,24 @@
                       -n100 -m28 -s20
                       -n100 -m9 -R217 -r217 -s5
                       -n100 -m9 -R273 -r273 -s5
-                      -n100 -s5 -U 2 0 1
-                      -n100 -s5 -T 2 1 2 -U 2 0 2
-                      -n100 -s5 -T 2 2 2 -U 2 1 2
-                      -n100 -s5 -a4 -b8 -T 2 1 2 -U 2 1 3
-                      -n100 -Z -s5
+                      -n100 -s5 -U 4 0 1 1 1
+                      -n100 -s5 -T 2 1 2 -U 4 0 2 1 1
+                      -n100 -s5 -T 2 2 2 -U 4 1 2 1 1
+                      -n100 -s5 -a4 -b8 -T 2 1 2 -U 4 1 3 1 1
+                      -n100 -s5 -Z
                       -n100 -s5 -Z -r75
                       -n50 -s5 -Z -r216 -R217
                       -n50 -s5 -Z -r270 -R273
-                      -n100 -s5 -Z -U 2 0 2
+                      -n100 -s5 -Z -U 4 0 2 1 2
                       -n100 -m19 -s10 -S15 -z2
                       -n100 -m9 -r106 -s10 -W2 -y2 -z2
                       -n100 -m9 -r106 -s20 -W4 -y4 -z4
-                      -n100 -u0 -m0 -R25 -r25 -i</main_exec_args>
-      <tags>nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11 nr_ulsim.test12 nr_ulsim.test13 nr_ulsim.test14 nr_ulsim.test15 nr_ulsim.test16 nr_ulsim.test17 nr_ulsim.test18</tags>
+                      -n100 -u0 -m0 -R25 -r25 -i 2 1 0
+                      -m16 -r106 -s8.8 -S9.4 -z2 -n200 -U 4 1 1 1 2 -gI -b14 -t70 -I15 -i 2 1 0
+                      -m16 -r106 -s5.4 -S6 -z4 -n200 -U 4 1 1 1 2 -gI -b14 -t70 -I15 -i 2 1 0
+                      -m16 -r106 -s3.4 -S3.8 -z8 -n200 -U 4 1 1 1 2 -gI -b14 -t70 -I15 -i 2 1 0</main_exec_args>
+
+      <tags>nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8 nr_ulsim.test9 nr_ulsim.test10 nr_ulsim.test11 nr_ulsim.test12 nr_ulsim.test13 nr_ulsim.test14 nr_ulsim.test15 nr_ulsim.test16 nr_ulsim.test17 nr_ulsim.test18 nr_ulsim.test19 nr_ulsim.test20 nr_ulsim.test21</tags>
       <search_expr_true>PUSCH test OK</search_expr_true>
       <search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
       <nruns>3</nruns>
diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c
index af31c83d6e1f5dce62d2b54818a74dab3fac8c16..6add03c324db9f3d6903cd341c425511f47f5500 100644
--- a/common/utils/nr/nr_common.c
+++ b/common/utils/nr/nr_common.c
@@ -191,6 +191,19 @@ int PRBalloc_to_locationandbandwidth(int NPRB,int RBstart) {
   return(PRBalloc_to_locationandbandwidth0(NPRB,RBstart,275));
 }
 
+int cce_to_reg_interleaving(const int R, int k, int n_shift, const int C, int L, const int N_regs) {
+
+  int f;  // interleaving function
+  if(R==0)
+    f = k;
+  else {
+    int c = k/R;
+     int r = k%R;
+     f = (r*C + c + n_shift)%(N_regs/L);
+  }
+  return f;
+}
+
 void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset) {
 
   uint8_t count=0, start=0, start_set=0;
diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h
index 5258ce8809b66a45f737f032057a50ea88414db1..5f7f670ce92938f058410d0f698f61e9fde2fa8e 100644
--- a/common/utils/nr/nr_common.h
+++ b/common/utils/nr/nr_common.h
@@ -57,7 +57,7 @@ static inline int get_num_dmrs(uint16_t dmrs_mask ) {
   return(num_dmrs);
 }
 
-
+int cce_to_reg_interleaving(const int R, int k, int n_shift, const int C, int L, const int N_regs);
 int get_SLIV(uint8_t S, uint8_t L);
 void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset);
 uint16_t config_bandwidth(int mu, int nb_rb, int nr_band);
diff --git a/common/utils/time_meas.c b/common/utils/time_meas.c
index df2bfd64de32b6c8b97c3450170e2ff5f9cc71a5..9d1215b5e5b255e979401dc2fa8089c2bd903bcb 100644
--- a/common/utils/time_meas.c
+++ b/common/utils/time_meas.c
@@ -111,13 +111,15 @@ void print_meas(time_stats_t *ts,
   }
 }
 
-int print_meas_log(time_stats_t *ts,
-                const char *name,
-                time_stats_t *total_exec_time,
-                time_stats_t *sf_exec_time,
-                char *output)
+size_t print_meas_log(time_stats_t *ts,
+                      const char *name,
+                      time_stats_t *total_exec_time,
+                      time_stats_t *sf_exec_time,
+                      char *output,
+                      size_t outputlen)
 {
-  int stroff = 0;
+  const char *begin = output;
+  const char *end = output + outputlen;
   static int first_time = 0;
   static double cpu_freq_GHz = 0.0;
 
@@ -128,30 +130,49 @@ int print_meas_log(time_stats_t *ts,
     first_time=1;
 
     if ((total_exec_time == NULL) || (sf_exec_time== NULL))
-      stroff += sprintf(output, "%25s  %25s  %25s  %25s %25s %6f\n","Name","Total","Per Trials",   "Num Trials","CPU_F_GHz", cpu_freq_GHz);
+      output += snprintf(output,
+                         end - output,
+                         "%25s  %25s  %25s  %25s %25s %6f\n",
+                         "Name",
+                         "Total",
+                         "Per Trials",
+                         "Num Trials",
+                         "CPU_F_GHz",
+                         cpu_freq_GHz);
     else
-      stroff += sprintf(output+stroff, "%25s  %25s  %25s  %20s %15s %6f\n","Name","Total","Average/Frame","Trials",    "CPU_F_GHz", cpu_freq_GHz);
+      output += snprintf(output,
+                         end - output,
+                         "%25s  %25s  %25s  %20s %15s %6f\n",
+                         "Name",
+                         "Total",
+                         "Average/Frame",
+                         "Trials",
+                         "CPU_F_GHz",
+                         cpu_freq_GHz);
   }
 
   if (ts->trials>0) {
-    //printf("%20s: total: %10.3f ms, average: %10.3f us (%10d trials)\n", name, ts->diff/cpu_freq_GHz/1000000.0, ts->diff/ts->trials/cpu_freq_GHz/1000.0, ts->trials);
     if ((total_exec_time == NULL) || (sf_exec_time== NULL)) {
-      stroff += sprintf(output+stroff, "%25s:  %15.3f us; %15d; %15.3f us;\n",
-              name,
-              (ts->diff/ts->trials/cpu_freq_GHz/1000.0),
-              ts->trials,
-              ts->max/cpu_freq_GHz/1000.0);
+      output += snprintf(output,
+                         end - output,
+                         "%25s:  %15.3f us; %15d; %15.3f us;\n",
+                         name,
+                         ts->diff / ts->trials / cpu_freq_GHz / 1000.0,
+                         ts->trials,
+                         ts->max / cpu_freq_GHz / 1000.0);
     } else {
-      stroff += sprintf(output+stroff, "%25s:  %15.3f ms (%5.2f%%); %15.3f us (%5.2f%%); %15d;\n",
-              name,
-              (ts->diff/cpu_freq_GHz/1000000.0),
-              ((ts->diff/cpu_freq_GHz/1000000.0)/(total_exec_time->diff/cpu_freq_GHz/1000000.0))*100,  // percentage
-              (ts->diff/ts->trials/cpu_freq_GHz/1000.0),
-              ((ts->diff/ts->trials/cpu_freq_GHz/1000.0)/(sf_exec_time->diff/sf_exec_time->trials/cpu_freq_GHz/1000.0))*100,  // percentage
-              ts->trials);
+      output += snprintf(output,
+                         end - output,
+                         "%25s:  %15.3f ms (%5.2f%%); %15.3f us (%5.2f%%); %15d;\n",
+                         name,
+                         ts->diff / cpu_freq_GHz / 1000000.0,
+                         ((ts->diff / cpu_freq_GHz / 1000000.0) / (total_exec_time->diff / cpu_freq_GHz / 1000000.0))*100,  // percentage
+                         ts->diff / ts->trials / cpu_freq_GHz / 1000.0,
+                         ((ts->diff / ts->trials / cpu_freq_GHz / 1000.0) / (sf_exec_time->diff / sf_exec_time->trials / cpu_freq_GHz / 1000.0)) * 100,  // percentage
+                         ts->trials);
     }
   }
-  return stroff;
+  return output - begin;
 }
 
 double get_time_meas_us(time_stats_t *ts)
diff --git a/common/utils/time_meas.h b/common/utils/time_meas.h
index 382dd7455a0e4a5d44146b4c6054c971071d7809..fded7f1a9c9a3195535f8c5b279d0124c8ed1c1c 100644
--- a/common/utils/time_meas.h
+++ b/common/utils/time_meas.h
@@ -83,7 +83,12 @@ static inline void stop_meas(time_stats_t *ts) __attribute__((always_inline));
 
 void print_meas_now(time_stats_t *ts, const char *name, FILE *file_name);
 void print_meas(time_stats_t *ts, const char *name, time_stats_t *total_exec_time, time_stats_t *sf_exec_time);
-int print_meas_log(time_stats_t *ts, const char *name, time_stats_t *total_exec_time, time_stats_t *sf_exec_time, char *output);
+size_t print_meas_log(time_stats_t *ts,
+                      const char *name,
+                      time_stats_t *total_exec_time,
+                      time_stats_t *sf_exec_time,
+                      char *output,
+                      size_t outputlen);
 double get_time_meas_us(time_stats_t *ts);
 double get_cpu_freq_GHz(void);
 
diff --git a/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md
new file mode 100644
index 0000000000000000000000000000000000000000..1110a5bc6cd8ca5b25aaf3326894384e0c6c41a3
--- /dev/null
+++ b/doc/NR_SA_CN5G_gNB_B210_COTS_UE_Tutorial.md
@@ -0,0 +1,234 @@
+<table style="border-collapse: collapse; border: none;">
+  <tr style="border-collapse: collapse; border: none;">
+    <td style="border-collapse: collapse; border: none;">
+      <a href="http://www.openairinterface.org/">
+         <img src="./images/oai_final_logo.png" alt="" border=3 height=50 width=150>
+         </img>
+      </a>
+    </td>
+    <td style="border-collapse: collapse; border: none; vertical-align: center;">
+      <b><font size = "5">OAI 5G SA tutorial</font></b>
+    </td>
+  </tr>
+</table>
+
+**TABLE OF CONTENTS**
+
+1. [Scenario](#1-scenario)
+2. [OAI CN5G](#2-oai-cn5g)
+    1. [OAI CN5G pre-requisites](#21-oai-cn5g-pre-requisites)
+    2. [OAI CN5G Setup](#22-oai-cn5g-setup)
+    3. [OAI CN5G Configuration files](#23-oai-cn5g-configuration-files)
+    4. [SIM Card](#24-sim-card)
+3. [OAI gNB](#3-oai-gnb)
+    1. [OAI gNB pre-requisites](#31-oai-gnb-pre-requisites)
+    2. [Build OAI gNB](#32-build-oai-gnb)
+4. [Run OAI CN5G and OAI gNB with USRP B210](#4-run-oai-cn5g-and-oai-gnb-with-usrp-b210)
+    1. [Run OAI CN5G](#41-run-oai-cn5g)
+    2. [Run OAI gNB](#42-run-oai-gnb)
+5. [Testing with QUECTEL RM500Q](#5-testing-with-quectel-rm500q)
+    1. [Setup QUECTEL](#51-setup-quectel)
+    2. [Ping test](#52-ping-test)
+    3. [Downlink iPerf test](#53-downlink-iperf-test)
+
+
+# 1. Scenario
+In this tutorial we describe how to configure and run a 5G end-to-end setup with OAI CN5G, OAI gNB and COTS UE.
+
+Minimum hardware requirements:
+- Laptop/Desktop/Server for OAI CN5G and OAI gNB
+    - Operating System: [Ubuntu 20.04.4 LTS](https://releases.ubuntu.com/20.04.4/ubuntu-20.04.4-desktop-amd64.iso)
+    - CPU: 8 cores x86_64 @ 3.5 GHz
+    - RAM: 32 GB
+- Laptop for UE
+    - Operating System: Microsoft Windows 10 x64
+    - CPU: 4 cores x86_64
+    - RAM: 8 GB
+    - Windows driver for Quectel MUST be equal or higher than version **2.2.4**
+- [USRP B210](https://www.ettus.com/all-products/ub210-kit/)
+- Quectel RM500Q
+    - Module, M.2 to USB adapter, antennas and SIM card
+    - Firmware version of Quectel MUST be equal or higher than **RM500QGLABR11A06M4G**
+
+
+# 2. OAI CN5G
+
+## 2.1 OAI CN5G pre-requisites
+
+```bash
+sudo apt install -y git net-tools putty
+
+sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
+curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
+sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu  $(lsb_release -cs)  stable"
+sudo apt update
+sudo apt install -y docker docker-ce
+
+# Add your username to the docker group, otherwise you will have to run in sudo mode.
+sudo usermod -a -G docker $(whoami)
+reboot
+
+# https://docs.docker.com/compose/install/
+sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
+sudo chmod +x /usr/local/bin/docker-compose
+
+docker network create --driver=bridge --subnet=192.168.70.128/26 -o "com.docker.network.bridge.name"="demo-oai" demo-oai-public-net
+sudo service docker restart
+
+```
+
+## 2.2 OAI CN5G Setup
+
+```bash
+# Git oai-cn5g-fed repository
+git clone https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-fed.git ~/oai-cn5g-fed
+cd ~/oai-cn5g-fed
+git checkout master
+./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop
+
+docker pull oaisoftwarealliance/oai-amf:develop
+docker pull oaisoftwarealliance/oai-nrf:develop
+docker pull oaisoftwarealliance/oai-smf:develop
+docker pull oaisoftwarealliance/oai-udr:develop
+docker pull oaisoftwarealliance/oai-udm:develop
+docker pull oaisoftwarealliance/oai-ausf:develop
+docker pull oaisoftwarealliance/oai-upf-vpp:develop
+docker pull oaisoftwarealliance/oai-spgwu-tiny:develop
+docker pull oaisoftwarealliance/oai-nssf:develop
+
+docker image tag oaisoftwarealliance/oai-amf:develop oai-amf:develop
+docker image tag oaisoftwarealliance/oai-nrf:develop oai-nrf:develop
+docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop
+docker image tag oaisoftwarealliance/oai-udr:develop oai-udr:develop
+docker image tag oaisoftwarealliance/oai-udm:develop oai-udm:develop
+docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop
+docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop
+docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop
+docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop
+```
+
+## 2.3 OAI CN5G Configuration files
+Download and copy the configuration files to ~/oai-cn5g-fed/docker-compose:
+- [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml)
+- [oai_db.sql](tutorial_resources/oai_db.sql)
+
+Change permissions on oai_db.sql to prevent mysql permission denied error:
+```bash
+chmod 644 ~/oai-cn5g-fed/docker-compose/oai_db.sql
+```
+
+## 2.4 SIM Card
+Program SIM Card with [Open Cells Project](https://open-cells.com/) application [uicc-v2.6](https://open-cells.com/d5138782a8739209ec5760865b1e53b0/uicc-v2.6.tgz).
+
+```bash
+sudo ./program_uicc --adm 12345678 --imsi 208990000000001 --isdn 00000001 --acc 0001 --key fec86ba6eb707ed08905757b1bb44b8f --opc C42449363BBAD02B66D16BC975D77CC1 -spn "OpenAirInterface" --authenticate
+```
+
+
+# 3. OAI gNB
+
+## 3.1 OAI gNB pre-requisites
+
+### Build UHD from source
+```bash
+sudo apt install -y libboost-all-dev libusb-1.0-0-dev doxygen python3-docutils python3-mako python3-numpy python3-requests python3-ruamel.yaml python3-setuptools cmake build-essential
+
+git clone https://github.com/EttusResearch/uhd.git ~/uhd
+cd ~/uhd
+git checkout v4.0.0.0
+cd host
+mkdir build
+cd build
+cmake ../
+make -j 4
+make test # This step is optional
+sudo make install
+sudo ldconfig
+sudo uhd_images_downloader
+```
+
+## 3.2 Build OAI gNB
+
+```bash
+# Get openairinterface5g source code
+git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g
+cd ~/openairinterface5g
+git checkout develop
+
+# Install dependencies in Ubuntu 20.04
+cd ~/openairinterface5g
+source oaienv
+cd cmake_targets
+./build_oai -I
+
+# Build OAI gNB
+cd ~/openairinterface5g
+source oaienv
+cd cmake_targets
+./build_oai -w USRP --nrUE --gNB --build-lib all -c
+```
+
+
+# 4. Run OAI CN5G and OAI gNB with USRP B210
+
+## 4.1 Run OAI CN5G
+
+```bash
+cd ~/oai-cn5g-fed/docker-compose
+python3 core-network.py --type start-basic --fqdn yes --scenario 1
+```
+
+## 4.2 Run OAI gNB
+
+```bash
+cd ~/openairinterface5g
+source oaienv
+cd cmake_targets/ran_build/build
+sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --sa -E --continuous-tx
+```
+
+Make sure that during USRP initialization, it shows that USB 3 is used.
+
+# 5. Testing with Quectel RM500Q
+
+## 5.1 Setup Quectel
+With [PuTTY](https://the.earth.li/~sgtatham/putty/latest/w64/putty.exe), send the following AT commands to the module using a serial interface (ex: COM2) at 115200 bps:
+```bash
+# MUST be sent at least once everytime there is a firmware upgrade!
+AT+QMBNCFG="Select","ROW_Commercial"
+AT+QMBNCFG="AutoSel",0
+AT+CFUN=1,1
+AT+CGDCONT=1
+AT+CGDCONT=2
+AT+CGDCONT=3
+AT+CGDCONT=1,"IP","oai"
+
+# (Optional, debug only, AT commands) Activate PDP context, retrieve IP address and test with ping
+AT+CGACT=1,1
+AT+CGPADDR=1
+AT+QPING=1,"openairinterface.org"
+```
+
+## 5.2 Ping test
+- UE host
+```bash
+ping 192.168.70.135 -n 1000 -S 12.1.1.2
+```
+- CN5G host
+```bash
+docker exec -it oai-ext-dn ping 12.1.1.2
+```
+
+## 5.3 Downlink iPerf test
+- UE host
+    - Download iPerf for Microsoft Windows from [here](https://iperf.fr/download/windows/iperf-2.0.9-win64.zip).
+    - Extract to Desktop and run with Command Prompt:
+```bash
+cd C:\Users\User\Desktop\iPerf\iperf-2.0.9-win64\iperf-2.0.9-win64
+iperf -s -u -i 1 -B 12.1.1.2
+```
+
+- CN5G host
+```bash
+docker exec -it oai-ext-dn iperf -u -t 86400 -i 1 -fk -B 192.168.70.135 -b 125M -c 12.1.1.2
+```
diff --git a/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md
new file mode 100644
index 0000000000000000000000000000000000000000..ed917e09eaf2a0769754ff7e736d1cde3655da67
--- /dev/null
+++ b/doc/NR_SA_CN5G_gNB_N300_COTS_UE_Tutorial.md
@@ -0,0 +1,251 @@
+<table style="border-collapse: collapse; border: none;">
+  <tr style="border-collapse: collapse; border: none;">
+    <td style="border-collapse: collapse; border: none;">
+      <a href="http://www.openairinterface.org/">
+         <img src="./images/oai_final_logo.png" alt="" border=3 height=50 width=150>
+         </img>
+      </a>
+    </td>
+    <td style="border-collapse: collapse; border: none; vertical-align: center;">
+      <b><font size = "5">OAI 5G SA tutorial</font></b>
+    </td>
+  </tr>
+</table>
+
+**TABLE OF CONTENTS**
+
+1. [Scenario](#1-scenario)
+2. [OAI CN5G](#2-oai-cn5g)
+    1. [OAI CN5G pre-requisites](#21-oai-cn5g-pre-requisites)
+    2. [OAI CN5G Setup](#22-oai-cn5g-setup)
+    3. [OAI CN5G Configuration files](#23-oai-cn5g-configuration-files)
+    4. [SIM Card](#24-sim-card)
+3. [OAI gNB](#3-oai-gnb)
+    1. [OAI gNB pre-requisites](#31-oai-gnb-pre-requisites)
+    2. [Build OAI gNB](#32-build-oai-gnb)
+    3. [N300 Ethernet Tuning](#33-n300-ethernet-tuning)
+4. [Run OAI CN5G and OAI gNB with USRP N300](#4-run-oai-cn5g-and-oai-gnb-with-usrp-n300)
+    1. [Run OAI CN5G](#41-run-oai-cn5g)
+    2. [Run OAI gNB](#42-run-oai-gnb)
+5. [Testing with QUECTEL RM500Q](#5-testing-with-quectel-rm500q)
+    1. [Setup QUECTEL](#51-setup-quectel)
+    2. [Ping test](#52-ping-test)
+    3. [Downlink iPerf test](#53-downlink-iperf-test)
+
+
+#  1. Scenario
+In this tutorial we describe how to configure and run a 5G end-to-end setup with OAI CN5G, OAI gNB and COTS UE.
+
+Minimum hardware requirements:
+- Laptop/Desktop/Server for OAI CN5G and OAI gNB
+    - Operating System: [Ubuntu 20.04.4 LTS](https://releases.ubuntu.com/20.04.4/ubuntu-20.04.4-desktop-amd64.iso)
+    - CPU: 8 cores x86_64 @ 3.5 GHz
+    - RAM: 32 GB
+- Laptop for UE
+    - Operating System: Microsoft Windows 10 x64
+    - CPU: 4 cores x86_64
+    - RAM: 8 GB
+    - Windows driver for Quectel MUST be equal or higher than version **2.2.4**
+- [USRP N300](https://www.ettus.com/all-products/USRP-N300/): Please identify the network interface(s) on which the N300 is connected.
+- Quectel RM500Q
+    - Module, M.2 to USB adapter, antennas and SIM card
+    - Firmware version of Quectel MUST be equal or higher than **RM500QGLABR11A06M4G**
+
+
+# 2. OAI CN5G
+
+## 2.1 OAI CN5G pre-requisites
+
+```bash
+sudo apt install -y git net-tools putty
+
+sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
+curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
+sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu  $(lsb_release -cs)  stable"
+sudo apt update
+sudo apt install -y docker docker-ce
+
+# Add your username to the docker group, otherwise you will have to run in sudo mode.
+sudo usermod -a -G docker $(whoami)
+reboot
+
+# https://docs.docker.com/compose/install/
+sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
+sudo chmod +x /usr/local/bin/docker-compose
+
+docker network create --driver=bridge --subnet=192.168.70.128/26 -o "com.docker.network.bridge.name"="demo-oai" demo-oai-public-net
+sudo service docker restart
+
+```
+
+## 2.2 OAI CN5G Setup
+
+```bash
+# Git oai-cn5g-fed repository
+git clone https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-fed.git ~/oai-cn5g-fed
+cd ~/oai-cn5g-fed
+git checkout master
+./scripts/syncComponents.sh --nrf-branch develop --amf-branch develop --smf-branch develop --spgwu-tiny-branch develop --ausf-branch develop --udm-branch develop --udr-branch develop --upf-vpp-branch develop --nssf-branch develop
+
+docker pull oaisoftwarealliance/oai-amf:develop
+docker pull oaisoftwarealliance/oai-nrf:develop
+docker pull oaisoftwarealliance/oai-smf:develop
+docker pull oaisoftwarealliance/oai-udr:develop
+docker pull oaisoftwarealliance/oai-udm:develop
+docker pull oaisoftwarealliance/oai-ausf:develop
+docker pull oaisoftwarealliance/oai-upf-vpp:develop
+docker pull oaisoftwarealliance/oai-spgwu-tiny:develop
+docker pull oaisoftwarealliance/oai-nssf:develop
+
+docker image tag oaisoftwarealliance/oai-amf:develop oai-amf:develop
+docker image tag oaisoftwarealliance/oai-nrf:develop oai-nrf:develop
+docker image tag oaisoftwarealliance/oai-smf:develop oai-smf:develop
+docker image tag oaisoftwarealliance/oai-udr:develop oai-udr:develop
+docker image tag oaisoftwarealliance/oai-udm:develop oai-udm:develop
+docker image tag oaisoftwarealliance/oai-ausf:develop oai-ausf:develop
+docker image tag oaisoftwarealliance/oai-upf-vpp:develop oai-upf-vpp:develop
+docker image tag oaisoftwarealliance/oai-spgwu-tiny:develop oai-spgwu-tiny:develop
+docker image tag oaisoftwarealliance/oai-nssf:develop oai-nssf:develop
+```
+
+## 2.3 OAI CN5G Configuration files
+Download and copy the configuration files to ~/oai-cn5g-fed/docker-compose:
+- [docker-compose-basic-nrf.yaml](tutorial_resources/docker-compose-basic-nrf.yaml)
+- [oai_db.sql](tutorial_resources/oai_db.sql)
+
+Change permissions on oai_db.sql to prevent mysql permission denied error:
+```bash
+chmod 644 ~/oai-cn5g-fed/docker-compose/oai_db.sql
+```
+
+## 2.4  SIM Card
+Program SIM Card with [Open Cells Project](https://open-cells.com/) application [uicc-v2.6](https://open-cells.com/d5138782a8739209ec5760865b1e53b0/uicc-v2.6.tgz).
+
+```bash
+sudo ./program_uicc --adm 12345678 --imsi 208990000000001 --isdn 00000001 --acc 0001 --key fec86ba6eb707ed08905757b1bb44b8f --opc C42449363BBAD02B66D16BC975D77CC1 -spn "OpenAirInterface" --authenticate
+```
+
+
+# 3. OAI gNB
+
+## 3.1 OAI gNB pre-requisites
+
+### Build UHD from source
+```bash
+sudo apt install -y libboost-all-dev libusb-1.0-0-dev doxygen python3-docutils python3-mako python3-numpy python3-requests python3-ruamel.yaml python3-setuptools cmake build-essential
+
+git clone https://github.com/EttusResearch/uhd.git ~/uhd
+cd ~/uhd
+git checkout v4.0.0.0
+cd host
+mkdir build
+cd build
+cmake ../
+make -j 4
+make test # This step is optional
+sudo make install
+sudo ldconfig
+sudo uhd_images_downloader
+```
+
+## 3.2 Build OAI gNB
+
+```bash
+# Get openairinterface5g source code
+git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g
+cd ~/openairinterface5g
+git checkout develop
+
+# Install dependencies in Ubuntu 20.04
+cd ~/openairinterface5g
+source oaienv
+cd cmake_targets
+./build_oai -I
+
+# Build OAI gNB
+cd ~/openairinterface5g
+source oaienv
+cd cmake_targets
+./build_oai -w USRP --nrUE --gNB --build-lib all -c
+```
+
+## 3.3 N300 Ethernet Tuning
+
+Please also refer to the official [USRP Host Performance Tuning Tips and Tricks](https://kb.ettus.com/USRP_Host_Performance_Tuning_Tips_and_Tricks) tuning guide.
+
+The following steps are recommended. Please change the network interface(s) as required. Also, you should have 10Gbps interface(s): if you use two cables, you should have the XG interface. Refer to the [N300 Getting Started Guide](https://kb.ettus.com/USRP_N300/N310/N320/N321_Getting_Started_Guide) for more information.
+
+* Use an MTU of 9000: how to change this depends on the network management tool. In the case of Network Manager, this can be done from the GUI.
+* Increase the kernel socket buffer (also done by the USRP driver in OAI):
+  ```
+  sysctl -w net.core.rmem_max=8388608
+  sysctl -w net.core.wmem_max=8388608
+  sysctl -w net.core.rmem_default=65536
+  sysctl -w net.core.wmem_default=65536
+  ```
+* Increase Ethernet Ring Buffers: `sudo ethtool -G <ifname> rx 4096 tx 4096`
+* Disable hyper-threading in the BIOS
+* Disable KPTI Protections for Spectre/Meltdown for more performance. **This is a security risk.** Add `mitigations=off nosmt` in your grub config and update grub.
+
+# 4. Run OAI CN5G and OAI gNB with USRP N300
+
+## 4.1 Run OAI CN5G
+
+```bash
+cd ~/oai-cn5g-fed/docker-compose
+python3 core-network.py --type start-basic --fqdn yes --scenario 1
+```
+
+## 4.2 Run OAI gNB
+
+```bash
+cd ~/openairinterface5g
+source oaienv
+cd cmake_targets/ran_build/build
+sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf --sa --usrp-tx-thread-config 1
+```
+
+
+# 5. Testing with Quectel RM500Q
+
+## 5.1 Setup Quectel
+With [PuTTY](https://the.earth.li/~sgtatham/putty/latest/w64/putty.exe), send the following AT commands to the module using a serial interface (ex: COM2) at 115200 bps:
+```bash
+# MUST be sent at least once everytime there is a firmware upgrade!
+AT+QMBNCFG="Select","ROW_Commercial"
+AT+QMBNCFG="AutoSel",0
+AT+CFUN=1,1
+AT+CGDCONT=1
+AT+CGDCONT=2
+AT+CGDCONT=3
+AT+CGDCONT=1,"IP","oai"
+
+# (Optional, debug only, AT commands) Activate PDP context, retrieve IP address and test with ping
+AT+CGACT=1,1
+AT+CGPADDR=1
+AT+QPING=1,"openairinterface.org"
+```
+
+## 5.2 Ping test
+- UE host
+```bash
+ping 192.168.70.135 -n 1000 -S 12.1.1.2
+```
+- CN5G host
+```bash
+docker exec -it oai-ext-dn ping 12.1.1.2
+```
+
+## 5.3 Downlink iPerf test
+- UE host
+    - Download iPerf for Microsoft Windows from [here](https://iperf.fr/download/windows/iperf-2.0.9-win64.zip).
+    - Extract to Desktop and run with Command Prompt:
+```bash
+cd C:\Users\User\Desktop\iPerf\iperf-2.0.9-win64\iperf-2.0.9-win64
+iperf -s -u -i 1 -B 12.1.1.2
+```
+
+- CN5G host
+```bash
+docker exec -it oai-ext-dn iperf -u -t 86400 -i 1 -fk -B 192.168.70.135 -b 200M -c 12.1.1.2
+```
diff --git a/doc/tutorial_resources/docker-compose-basic-nrf.yaml b/doc/tutorial_resources/docker-compose-basic-nrf.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6750cb78bec7d39448a0f5cc562ff76f61e87ada
--- /dev/null
+++ b/doc/tutorial_resources/docker-compose-basic-nrf.yaml
@@ -0,0 +1,316 @@
+version: '3.8'
+services:
+    mysql:
+        container_name: "mysql"
+        image: mysql:5.7
+        volumes:
+            - ./oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql
+            - ./mysql-healthcheck2.sh:/tmp/mysql-healthcheck.sh
+        environment:
+            - TZ=Europe/Paris
+            - MYSQL_DATABASE=oai_db
+            - MYSQL_USER=test
+            - MYSQL_PASSWORD=test
+            - MYSQL_ROOT_PASSWORD=linux
+        healthcheck:
+            test: /bin/bash -c "/tmp/mysql-healthcheck.sh"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+        networks:
+            public_net:
+                ipv4_address: 192.168.70.131
+    oai-udr:
+        container_name: oai-udr
+        image: oai-udr:develop
+        environment:
+            - TZ=Europe/Paris
+            - INSTANCE=0
+            - PID_DIRECTORY=/var/run
+            - UDR_INTERFACE_NAME_FOR_NUDR=eth0
+            - UDR_INTERFACE_PORT_FOR_NUDR=80
+            - UDR_INTERFACE_HTTP2_PORT_FOR_NUDR=8080
+            - UDR_API_VERSION=v1
+            - MYSQL_IPV4_ADDRESS=192.168.70.131
+            - MYSQL_USER=test
+            - MYSQL_PASS=test
+            - MYSQL_DB=oai_db
+            - WAIT_MYSQL=120
+        depends_on:
+            - mysql
+        networks:
+            public_net:
+                ipv4_address: 192.168.70.136
+        volumes:
+            - ./udr-healthcheck.sh:/openair-udr/bin/udr-healthcheck.sh
+        healthcheck:
+            test: /bin/bash -c "/openair-udr/bin/udr-healthcheck.sh"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+    oai-udm:
+        container_name: oai-udm
+        image: oai-udm:develop
+        environment:
+            - TZ=Europe/Paris
+            - INSTANCE=0
+            - PID_DIRECTORY=/var/run
+            - UDM_NAME=OAI_UDM
+            - SBI_IF_NAME=eth0
+            - SBI_PORT=80
+            - UDM_VERSION_NB=v1
+            - USE_FQDN_DNS=yes
+            - UDR_IP_ADDRESS=192.168.70.136
+            - UDR_PORT=80
+            - UDR_VERSION_NB=v1
+            - UDR_FQDN=oai-udr
+        depends_on:
+            - oai-udr
+        networks:
+            public_net:
+                ipv4_address: 192.168.70.137
+        volumes:
+            - ./udm-healthcheck.sh:/openair-udm/bin/udm-healthcheck.sh
+        healthcheck:
+            test: /bin/bash -c "/openair-udm/bin/udm-healthcheck.sh"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+    oai-ausf:
+        container_name: oai-ausf
+        image: oai-ausf:develop
+        environment:
+            - TZ=Europe/Paris
+            - INSTANCE_ID=0
+            - PID_DIR=/var/run
+            - AUSF_NAME=OAI_AUSF
+            - SBI_IF_NAME=eth0
+            - SBI_PORT=80
+            - USE_FQDN_DNS=yes
+            - UDM_IP_ADDRESS=192.168.70.137
+            - UDM_PORT=80
+            - UDM_VERSION_NB=v1
+            - UDM_FQDN=oai-udm
+        depends_on:
+            - oai-udm
+        networks:
+            public_net:
+                ipv4_address: 192.168.70.138
+        volumes:
+            - ./ausf-healthcheck.sh:/openair-ausf/bin/ausf-healthcheck.sh
+        healthcheck:
+            test: /bin/bash -c "/openair-ausf/bin/ausf-healthcheck.sh"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+    oai-nrf:
+        container_name: "oai-nrf"
+        image: oai-nrf:develop
+        environment:
+            - NRF_INTERFACE_NAME_FOR_SBI=eth0
+            - NRF_INTERFACE_PORT_FOR_SBI=80
+            - NRF_INTERFACE_HTTP2_PORT_FOR_SBI=9090
+            - NRF_API_VERSION=v1
+            - INSTANCE=0
+            - PID_DIRECTORY=/var/run
+        networks:
+            public_net:
+                ipv4_address: 192.168.70.130
+        volumes:
+            - ./nrf-healthcheck.sh:/openair-nrf/bin/nrf-healthcheck.sh
+        healthcheck:
+            test: /bin/bash -c "/openair-nrf/bin/nrf-healthcheck.sh"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+    oai-amf:
+        container_name: "oai-amf"
+        image: oai-amf:develop
+        environment:
+            - TZ=Europe/paris
+            - INSTANCE=0
+            - PID_DIRECTORY=/var/run
+            - MCC=208
+            - MNC=99
+            - REGION_ID=128
+            - AMF_SET_ID=1
+            - SERVED_GUAMI_MCC_0=208
+            - SERVED_GUAMI_MNC_0=99
+            - SERVED_GUAMI_REGION_ID_0=128
+            - SERVED_GUAMI_AMF_SET_ID_0=1
+            - SERVED_GUAMI_MCC_1=460
+            - SERVED_GUAMI_MNC_1=11
+            - SERVED_GUAMI_REGION_ID_1=10
+            - SERVED_GUAMI_AMF_SET_ID_1=1
+            - PLMN_SUPPORT_MCC=208
+            - PLMN_SUPPORT_MNC=99
+            - PLMN_SUPPORT_TAC=0x0001
+            - SST_0=1
+            - SD_0=1
+            - SST_1=1
+            - SD_1=12
+            - AMF_INTERFACE_NAME_FOR_NGAP=eth0
+            - AMF_INTERFACE_NAME_FOR_N11=eth0
+            - SMF_INSTANCE_ID_0=1
+            - SMF_FQDN_0=oai-smf
+            - SMF_IPV4_ADDR_0=192.168.70.133
+            - SMF_HTTP_VERSION_0=v1
+            - SELECTED_0=true
+            - SMF_INSTANCE_ID_1=2
+            - SMF_FQDN_1=oai-smf
+            - SMF_IPV4_ADDR_1=0.0.0.0
+            - SMF_HTTP_VERSION_1=v1
+            - SELECTED_1=false
+            - MYSQL_SERVER=192.168.70.131
+            - MYSQL_USER=root
+            - MYSQL_PASS=linux
+            - MYSQL_DB=oai_db
+            - OPERATOR_KEY=1006020f0a478bf6b699f15c062e42b3
+            - NRF_IPV4_ADDRESS=192.168.70.130
+            - NRF_PORT=80
+            - NF_REGISTRATION=yes
+            - SMF_SELECTION=yes
+            - USE_FQDN_DNS=yes
+            - EXTERNAL_AUSF=yes
+            - NRF_API_VERSION=v1
+            - NRF_FQDN=oai-nrf
+            - AUSF_IPV4_ADDRESS=192.168.70.138
+            - AUSF_PORT=80
+            - AUSF_API_VERSION=v1
+            - AUSF_FQDN=oai-ausf
+        depends_on:
+            - mysql
+            - oai-nrf
+            - oai-ausf
+        volumes:
+            - ./amf-healthcheck.sh:/openair-amf/bin/amf-healthcheck.sh
+        healthcheck:
+            test: /bin/bash -c "/openair-amf/bin/amf-healthcheck.sh"
+            interval: 10s
+            timeout: 15s
+            retries: 5
+        networks:
+            public_net:
+                ipv4_address: 192.168.70.132
+    oai-smf:
+        container_name: "oai-smf"
+        image: oai-smf:develop
+        environment:
+            - TZ=Europe/Paris
+            - INSTANCE=0
+            - PID_DIRECTORY=/var/run
+            - SMF_INTERFACE_NAME_FOR_N4=eth0
+            - SMF_INTERFACE_NAME_FOR_SBI=eth0
+            - SMF_INTERFACE_PORT_FOR_SBI=80
+            - SMF_INTERFACE_HTTP2_PORT_FOR_SBI=9090
+            - SMF_API_VERSION=v1
+            - DEFAULT_DNS_IPV4_ADDRESS=8.8.8.8
+            - DEFAULT_DNS_SEC_IPV4_ADDRESS=4.4.4.4
+            - AMF_IPV4_ADDRESS=192.168.70.132
+            - AMF_PORT=80
+            - AMF_API_VERSION=v1
+            - AMF_FQDN=oai-amf
+            - UDM_IPV4_ADDRESS=192.168.70.137
+            - UDM_PORT=80
+            - UDM_API_VERSION=v1
+            - UDM_FQDN=oai-udm
+            - UPF_IPV4_ADDRESS=192.168.70.134
+            - UPF_FQDN_0=oai-spgwu
+            - NRF_IPV4_ADDRESS=192.168.70.130
+            - NRF_PORT=80
+            - NRF_API_VERSION=v1
+            - USE_LOCAL_SUBSCRIPTION_INFO=yes
+            - NRF_FQDN=oai-nrf
+            - REGISTER_NRF=yes
+            - DISCOVER_UPF=yes
+            - USE_FQDN_DNS=yes
+            - DNN_RANGE1=12.1.1.2 - 12.1.1.128
+            - DNN_RANGE0=12.2.1.2 - 12.2.1.128
+            - DNN_NI1=oai
+        depends_on:
+            - oai-nrf
+            - oai-amf
+        volumes:
+            - ./smf-healthcheck.sh:/openair-smf/bin/smf-healthcheck.sh
+        healthcheck:
+            test: /bin/bash -c "/openair-smf/bin/smf-healthcheck.sh"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+        networks:
+            public_net:
+                ipv4_address: 192.168.70.133
+    oai-spgwu:
+        container_name: "oai-spgwu"
+        image: oai-spgwu-tiny:develop
+        environment:
+            - TZ=Europe/Paris
+            - PID_DIRECTORY=/var/run
+            - SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP=eth0
+            - SGW_INTERFACE_NAME_FOR_SX=eth0
+            - PGW_INTERFACE_NAME_FOR_SGI=eth0
+            - NETWORK_UE_NAT_OPTION=yes
+            - NETWORK_UE_IP=12.1.1.0/24
+            - SPGWC0_IP_ADDRESS=192.168.70.133
+            - BYPASS_UL_PFCP_RULES=no
+            - MCC=208
+            - MNC=99
+            - MNC03=099
+            - TAC=1
+            - GW_ID=1
+            - REALM=openairinterface.org
+            - ENABLE_5G_FEATURES=yes
+            - REGISTER_NRF=yes
+            - USE_FQDN_NRF=no
+            - UPF_FQDN_5G=oai-spgwu
+            - NRF_IPV4_ADDRESS=192.168.70.130
+            - NRF_PORT=80
+            - NRF_API_VERSION=v1
+            - NRF_FQDN=oai-nrf
+            - NSSAI_SST_0=1
+            - NSSAI_SD_0=1
+            - DNN_0=oai
+        depends_on:
+            - oai-nrf
+            - oai-smf
+        cap_add:
+            - NET_ADMIN
+            - SYS_ADMIN
+        cap_drop:
+            - ALL
+        privileged: true
+        volumes:
+            - ./spgwu-healthcheck.sh:/openair-spgwu-tiny/bin/spgwu-healthcheck.sh
+        healthcheck:
+            test: /bin/bash -c "/openair-spgwu-tiny/bin/spgwu-healthcheck.sh"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+        networks:
+            public_net:
+                ipv4_address: 192.168.70.134
+    oai-ext-dn:
+        image: ubuntu:bionic
+        privileged: true
+        container_name: oai-ext-dn
+        entrypoint: /bin/bash -c \
+              "apt update; apt install -y iptables iproute2 iperf iperf3 iputils-ping;"\
+              "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
+              "ip route add 12.1.1.0/24 via 192.168.70.134 dev eth0; sleep infinity"
+        depends_on:
+            - oai-spgwu
+        networks:
+            public_net:
+                ipv4_address: 192.168.70.135
+networks:
+    public_net:
+        external:
+            name: demo-oai-public-net
+#    public_net:
+#        driver: bridge
+#        name: demo-oai-public-net
+#        ipam:
+#            config:
+#                - subnet: 192.168.70.128/26
+#        driver_opts:
+#            com.docker.network.bridge.name: "demo-oai"
diff --git a/doc/tutorial_resources/oai_db.sql b/doc/tutorial_resources/oai_db.sql
new file mode 100644
index 0000000000000000000000000000000000000000..e019c60e8623b9779e3f6d43053fd3ed69a31472
--- /dev/null
+++ b/doc/tutorial_resources/oai_db.sql
@@ -0,0 +1,312 @@
+-- phpMyAdmin SQL Dump
+-- version 5.1.0
+-- https://www.phpmyadmin.net/
+--
+-- Host: 172.16.200.10:3306
+-- Generation Time: Mar 22, 2021 at 10:31 AM
+-- Server version: 5.7.33
+-- PHP Version: 7.4.15
+
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
+START TRANSACTION;
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8mb4 */;
+
+--
+-- Database: `oai_db`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `AccessAndMobilitySubscriptionData`
+--
+
+CREATE TABLE `AccessAndMobilitySubscriptionData` (
+  `ueid` varchar(15) NOT NULL,
+  `servingPlmnid` varchar(15) NOT NULL,
+  `supportedFeatures` varchar(50) DEFAULT NULL,
+  `gpsis` json DEFAULT NULL,
+  `internalGroupIds` json DEFAULT NULL,
+  `sharedVnGroupDataIds` json DEFAULT NULL,
+  `subscribedUeAmbr` json DEFAULT NULL,
+  `nssai` json DEFAULT NULL,
+  `ratRestrictions` json DEFAULT NULL,
+  `forbiddenAreas` json DEFAULT NULL,
+  `serviceAreaRestriction` json DEFAULT NULL,
+  `coreNetworkTypeRestrictions` json DEFAULT NULL,
+  `rfspIndex` int(10) DEFAULT NULL,
+  `subsRegTimer` int(10) DEFAULT NULL,
+  `ueUsageType` int(10) DEFAULT NULL,
+  `mpsPriority` tinyint(1) DEFAULT NULL,
+  `mcsPriority` tinyint(1) DEFAULT NULL,
+  `activeTime` int(10) DEFAULT NULL,
+  `sorInfo` json DEFAULT NULL,
+  `sorInfoExpectInd` tinyint(1) DEFAULT NULL,
+  `sorafRetrieval` tinyint(1) DEFAULT NULL,
+  `sorUpdateIndicatorList` json DEFAULT NULL,
+  `upuInfo` json DEFAULT NULL,
+  `micoAllowed` tinyint(1) DEFAULT NULL,
+  `sharedAmDataIds` json DEFAULT NULL,
+  `odbPacketServices` json DEFAULT NULL,
+  `serviceGapTime` int(10) DEFAULT NULL,
+  `mdtUserConsent` json DEFAULT NULL,
+  `mdtConfiguration` json DEFAULT NULL,
+  `traceData` json DEFAULT NULL,
+  `cagData` json DEFAULT NULL,
+  `stnSr` varchar(50) DEFAULT NULL,
+  `cMsisdn` varchar(50) DEFAULT NULL,
+  `nbIoTUePriority` int(10) DEFAULT NULL,
+  `nssaiInclusionAllowed` tinyint(1) DEFAULT NULL,
+  `rgWirelineCharacteristics` varchar(50) DEFAULT NULL,
+  `ecRestrictionDataWb` json DEFAULT NULL,
+  `ecRestrictionDataNb` tinyint(1) DEFAULT NULL,
+  `expectedUeBehaviourList` json DEFAULT NULL,
+  `primaryRatRestrictions` json DEFAULT NULL,
+  `secondaryRatRestrictions` json DEFAULT NULL,
+  `edrxParametersList` json DEFAULT NULL,
+  `ptwParametersList` json DEFAULT NULL,
+  `iabOperationAllowed` tinyint(1) DEFAULT NULL,
+  `wirelineForbiddenAreas` json DEFAULT NULL,
+  `wirelineServiceAreaRestriction` json DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `Amf3GppAccessRegistration`
+--
+
+CREATE TABLE `Amf3GppAccessRegistration` (
+  `ueid` varchar(15) NOT NULL,
+  `amfInstanceId` varchar(50) NOT NULL,
+  `supportedFeatures` varchar(50) DEFAULT NULL,
+  `purgeFlag` tinyint(1) DEFAULT NULL,
+  `pei` varchar(50) DEFAULT NULL,
+  `imsVoPs` json DEFAULT NULL,
+  `deregCallbackUri` varchar(50) NOT NULL,
+  `amfServiceNameDereg` json DEFAULT NULL,
+  `pcscfRestorationCallbackUri` varchar(50) DEFAULT NULL,
+  `amfServiceNamePcscfRest` json DEFAULT NULL,
+  `initialRegistrationInd` tinyint(1) DEFAULT NULL,
+  `guami` json NOT NULL,
+  `backupAmfInfo` json DEFAULT NULL,
+  `drFlag` tinyint(1) DEFAULT NULL,
+  `ratType` json NOT NULL,
+  `urrpIndicator` tinyint(1) DEFAULT NULL,
+  `amfEeSubscriptionId` varchar(50) DEFAULT NULL,
+  `epsInterworkingInfo` json DEFAULT NULL,
+  `ueSrvccCapability` tinyint(1) DEFAULT NULL,
+  `registrationTime` varchar(50) DEFAULT NULL,
+  `vgmlcAddress` json DEFAULT NULL,
+  `contextInfo` json DEFAULT NULL,
+  `noEeSubscriptionInd` tinyint(1) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `AuthenticationStatus`
+--
+
+CREATE TABLE `AuthenticationStatus` (
+  `ueid` varchar(20) NOT NULL,
+  `nfInstanceId` varchar(50) NOT NULL,
+  `success` tinyint(1) NOT NULL,
+  `timeStamp` varchar(50) NOT NULL,
+  `authType` varchar(25) NOT NULL,
+  `servingNetworkName` varchar(50) NOT NULL,
+  `authRemovalInd` tinyint(1) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `AuthenticationSubscription`
+--
+
+CREATE TABLE `AuthenticationSubscription` (
+  `ueid` varchar(20) NOT NULL,
+  `authenticationMethod` varchar(25) NOT NULL,
+  `encPermanentKey` varchar(50) DEFAULT NULL,
+  `protectionParameterId` varchar(50) DEFAULT NULL,
+  `sequenceNumber` json DEFAULT NULL,
+  `authenticationManagementField` varchar(50) DEFAULT NULL,
+  `algorithmId` varchar(50) DEFAULT NULL,
+  `encOpcKey` varchar(50) DEFAULT NULL,
+  `encTopcKey` varchar(50) DEFAULT NULL,
+  `vectorGenerationInHss` tinyint(1) DEFAULT NULL,
+  `n5gcAuthMethod` varchar(15) DEFAULT NULL,
+  `rgAuthenticationInd` tinyint(1) DEFAULT NULL,
+  `supi` varchar(20) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `AuthenticationSubscription`
+--
+
+INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES
+('208950000000031', '5G_AKA', '0C0A34601D4F07677303652C0462535B', '0C0A34601D4F07677303652C0462535B', '{\"sqn\": \"000000000020\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', '63bfa50ee6523365ff14c1f45f88737d', NULL, NULL, NULL, NULL, '208950000000031');
+
+INSERT INTO `AuthenticationSubscription` (`ueid`, `authenticationMethod`, `encPermanentKey`, `protectionParameterId`, `sequenceNumber`, `authenticationManagementField`, `algorithmId`, `encOpcKey`, `encTopcKey`, `vectorGenerationInHss`, `n5gcAuthMethod`, `rgAuthenticationInd`, `supi`) VALUES
+('208990000000001', '5G_AKA', 'fec86ba6eb707ed08905757b1bb44b8f', 'fec86ba6eb707ed08905757b1bb44b8f', '{\"sqn\": \"000000000020\", \"sqnScheme\": \"NON_TIME_BASED\", \"lastIndexes\": {\"ausf\": 0}}', '8000', 'milenage', 'C42449363BBAD02B66D16BC975D77CC1', NULL, NULL, NULL, NULL, '208990000000001');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `SdmSubscriptions`
+--
+
+CREATE TABLE `SdmSubscriptions` (
+  `ueid` varchar(15) NOT NULL,
+  `subsId` int(10) UNSIGNED NOT NULL,
+  `nfInstanceId` varchar(50) NOT NULL,
+  `implicitUnsubscribe` tinyint(1) DEFAULT NULL,
+  `expires` varchar(50) DEFAULT NULL,
+  `callbackReference` varchar(50) NOT NULL,
+  `amfServiceName` json DEFAULT NULL,
+  `monitoredResourceUris` json NOT NULL,
+  `singleNssai` json DEFAULT NULL,
+  `dnn` varchar(50) DEFAULT NULL,
+  `subscriptionId` varchar(50) DEFAULT NULL,
+  `plmnId` json DEFAULT NULL,
+  `immediateReport` tinyint(1) DEFAULT NULL,
+  `report` json DEFAULT NULL,
+  `supportedFeatures` varchar(50) DEFAULT NULL,
+  `contextInfo` json DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `SessionManagementSubscriptionData`
+--
+
+CREATE TABLE `SessionManagementSubscriptionData` (
+  `ueid` varchar(15) NOT NULL,
+  `servingPlmnid` varchar(15) NOT NULL,
+  `singleNssai` json NOT NULL,
+  `dnnConfigurations` json DEFAULT NULL,
+  `internalGroupIds` json DEFAULT NULL,
+  `sharedVnGroupDataIds` json DEFAULT NULL,
+  `sharedDnnConfigurationsId` varchar(50) DEFAULT NULL,
+  `odbPacketServices` json DEFAULT NULL,
+  `traceData` json DEFAULT NULL,
+  `sharedTraceDataId` varchar(50) DEFAULT NULL,
+  `expectedUeBehavioursList` json DEFAULT NULL,
+  `suggestedPacketNumDlList` json DEFAULT NULL,
+  `3gppChargingCharacteristics` varchar(50) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `SmfRegistrations`
+--
+
+CREATE TABLE `SmfRegistrations` (
+  `ueid` varchar(15) NOT NULL,
+  `subpduSessionId` int(10) NOT NULL,
+  `smfInstanceId` varchar(50) NOT NULL,
+  `smfSetId` varchar(50) DEFAULT NULL,
+  `supportedFeatures` varchar(50) DEFAULT NULL,
+  `pduSessionId` int(10) NOT NULL,
+  `singleNssai` json NOT NULL,
+  `dnn` varchar(50) DEFAULT NULL,
+  `emergencyServices` tinyint(1) DEFAULT NULL,
+  `pcscfRestorationCallbackUri` varchar(50) DEFAULT NULL,
+  `plmnId` json NOT NULL,
+  `pgwFqdn` varchar(50) DEFAULT NULL,
+  `epdgInd` tinyint(1) DEFAULT NULL,
+  `deregCallbackUri` varchar(50) DEFAULT NULL,
+  `registrationReason` json DEFAULT NULL,
+  `registrationTime` varchar(50) DEFAULT NULL,
+  `contextInfo` json DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `SmfSelectionSubscriptionData`
+--
+
+CREATE TABLE `SmfSelectionSubscriptionData` (
+  `ueid` varchar(15) NOT NULL,
+  `servingPlmnid` varchar(15) NOT NULL,
+  `supportedFeatures` varchar(50) DEFAULT NULL,
+  `subscribedSnssaiInfos` json DEFAULT NULL,
+  `sharedSnssaiInfosId` varchar(50) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Indexes for dumped tables
+--
+
+--
+-- Indexes for table `AccessAndMobilitySubscriptionData`
+--
+ALTER TABLE `AccessAndMobilitySubscriptionData`
+  ADD PRIMARY KEY (`ueid`,`servingPlmnid`) USING BTREE;
+
+--
+-- Indexes for table `Amf3GppAccessRegistration`
+--
+ALTER TABLE `Amf3GppAccessRegistration`
+  ADD PRIMARY KEY (`ueid`);
+
+--
+-- Indexes for table `AuthenticationStatus`
+--
+ALTER TABLE `AuthenticationStatus`
+  ADD PRIMARY KEY (`ueid`);
+
+--
+-- Indexes for table `AuthenticationSubscription`
+--
+ALTER TABLE `AuthenticationSubscription`
+  ADD PRIMARY KEY (`ueid`);
+
+--
+-- Indexes for table `SdmSubscriptions`
+--
+ALTER TABLE `SdmSubscriptions`
+  ADD PRIMARY KEY (`subsId`,`ueid`) USING BTREE;
+
+--
+-- Indexes for table `SessionManagementSubscriptionData`
+--
+ALTER TABLE `SessionManagementSubscriptionData`
+  ADD PRIMARY KEY (`ueid`,`servingPlmnid`) USING BTREE;
+
+--
+-- Indexes for table `SmfRegistrations`
+--
+ALTER TABLE `SmfRegistrations`
+  ADD PRIMARY KEY (`ueid`,`subpduSessionId`) USING BTREE;
+
+--
+-- Indexes for table `SmfSelectionSubscriptionData`
+--
+ALTER TABLE `SmfSelectionSubscriptionData`
+  ADD PRIMARY KEY (`ueid`,`servingPlmnid`) USING BTREE;
+
+--
+-- AUTO_INCREMENT for dumped tables
+--
+
+--
+-- AUTO_INCREMENT for table `SdmSubscriptions`
+--
+ALTER TABLE `SdmSubscriptions`
+  MODIFY `subsId` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
+COMMIT;
+
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+
diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c
index 8ea7f167121c080d52a2ff4bd20d06f29cc4a7c9..327c01af6a29a80a7051253e08299847351e2961 100644
--- a/executables/nr-gnb.c
+++ b/executables/nr-gnb.c
@@ -304,32 +304,36 @@ void rx_func(void *param) {
        );
 #endif
 }
-static void dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output) {
-  int stroff = 0;
-  stroff += print_meas_log(&gNB->phy_proc_tx, "L1 Tx processing", NULL, NULL, output);
-  stroff += print_meas_log(&gNB->dlsch_encoding_stats, "DLSCH encoding", NULL, NULL, output+stroff);
-  stroff += print_meas_log(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL, output+stroff);
-  stroff += print_meas_log(&gNB->ul_indication_stats, "UL Indication", NULL, NULL, output+stroff);
-  stroff += print_meas_log(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output+stroff);
-  stroff += print_meas_log(&gNB->ulsch_decoding_stats, "PUSCH decoding", NULL, NULL, output+stroff);
-  stroff += print_meas_log(&gNB->schedule_response_stats, "Schedule Response",NULL,NULL, output+stroff);
-  if (ru->feprx) stroff += print_meas_log(&ru->ofdm_demod_stats,"feprx",NULL,NULL, output+stroff);
+static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size_t outputlen) {
+  const char *begin = output;
+  const char *end = output + outputlen;
+  output += print_meas_log(&gNB->phy_proc_tx, "L1 Tx processing", NULL, NULL, output, end - output);
+  output += print_meas_log(&gNB->dlsch_encoding_stats, "DLSCH encoding", NULL, NULL, output, end - output);
+  output += print_meas_log(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL, output, end - output);
+  output += print_meas_log(&gNB->ul_indication_stats, "UL Indication", NULL, NULL, output, end - output);
+  output += print_meas_log(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output, end - output);
+  output += print_meas_log(&gNB->ulsch_decoding_stats, "PUSCH decoding", NULL, NULL, output, end - output);
+  output += print_meas_log(&gNB->schedule_response_stats, "Schedule Response", NULL, NULL, output, end - output);
+  if (ru->feprx)
+    output += print_meas_log(&ru->ofdm_demod_stats, "feprx", NULL, NULL, output, end - output);
 
   if (ru->feptx_ofdm) {
-    stroff += print_meas_log(&ru->precoding_stats,"feptx_prec",NULL,NULL, output+stroff);
-    stroff += print_meas_log(&ru->txdataF_copy_stats,"txdataF_copy",NULL,NULL, output+stroff);
-    stroff += print_meas_log(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL, output+stroff);
-    stroff += print_meas_log(&ru->ofdm_total_stats,"feptx_total",NULL,NULL, output+stroff);
+    output += print_meas_log(&ru->precoding_stats,"feptx_prec",NULL,NULL, output, end - output);
+    output += print_meas_log(&ru->txdataF_copy_stats,"txdataF_copy",NULL,NULL, output, end - output);
+    output += print_meas_log(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL, output, end - output);
+    output += print_meas_log(&ru->ofdm_total_stats,"feptx_total",NULL,NULL, output, end - output);
   }
 
-  if (ru->fh_north_asynch_in) stroff += print_meas_log(&ru->rx_fhaul,"rx_fhaul",NULL,NULL, output+stroff);
+  if (ru->fh_north_asynch_in)
+    output += print_meas_log(&ru->rx_fhaul,"rx_fhaul",NULL,NULL, output, end - output);
 
-  stroff += print_meas_log(&ru->tx_fhaul,"tx_fhaul",NULL,NULL, output+stroff);
+  output += print_meas_log(&ru->tx_fhaul,"tx_fhaul",NULL,NULL, output, end - output);
 
   if (ru->fh_north_out) {
-    stroff += print_meas_log(&ru->compression,"compression",NULL,NULL, output+stroff);
-    stroff += print_meas_log(&ru->transport,"transport",NULL,NULL, output+stroff);
+    output += print_meas_log(&ru->compression,"compression",NULL,NULL, output, end - output);
+    output += print_meas_log(&ru->transport,"transport",NULL,NULL, output, end - output);
   }
+  return output - begin;
 }
 
 void *nrL1_stats_thread(void *param) {
@@ -355,7 +359,7 @@ void *nrL1_stats_thread(void *param) {
     dump_nr_I0_stats(fd,gNB);
     dump_pdsch_stats(fd,gNB);
     dump_pusch_stats(fd,gNB);
-    dump_L1_meas_stats(gNB, ru, output);
+    dump_L1_meas_stats(gNB, ru, output, L1STATSSTRLEN);
     fprintf(fd,"%s\n",output);
     fflush(fd);
     fseek(fd,0,SEEK_SET);
@@ -380,7 +384,7 @@ void *tx_reorder_thread(void* param) {
     if (resL1Reserve) {
        resL1=resL1Reserve;
        if (((processingData_L1tx_t *)NotifiedFifoData(resL1))->slot != next_tx_slot) {
-         LOG_E(PHY,"order mistake");
+         LOG_E(PHY,"order mistake\n");
 	 resL1Reserve=NULL;
 	 resL1 = pullTpool(gNB->L1_tx_out, gNB->threadPool);
        }
@@ -600,7 +604,8 @@ void init_gNB(int single_thread_flag,int wait_for_sync) {
     gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list;*/
 
     gNB->prach_energy_counter = 0;
-    gNB->prb_interpolation = get_softmodem_params()->prb_interpolation;
+    gNB->chest_time = get_softmodem_params()->chest_time;
+    gNB->chest_freq = get_softmodem_params()->chest_freq;
   }
   
 
diff --git a/executables/nr-ue.c b/executables/nr-ue.c
index 6e1864f290b9d13d61f91598eeb414c7d5d8ac39..01e6c6213845563d4618848c7a34d1dedb7b66e9 100644
--- a/executables/nr-ue.c
+++ b/executables/nr-ue.c
@@ -106,23 +106,24 @@ queue_t nr_rach_ind_queue;
 
 static void *NRUE_phy_stub_standalone_pnf_task(void *arg);
 
-static int dump_L1_UE_meas_stats(PHY_VARS_NR_UE *ue, char *output, int max_len)
+static size_t dump_L1_UE_meas_stats(PHY_VARS_NR_UE *ue, char *output, size_t max_len)
 {
-  int stroff = 0;
-  stroff += print_meas_log(&ue->phy_proc_tx, "L1 TX processing", NULL, NULL, output);
-  stroff += print_meas_log(&ue->ulsch_encoding_stats, "ULSCH encoding", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->phy_proc_rx[0], "L1 RX processing t0", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->phy_proc_rx[1], "L1 RX processing t1", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->ue_ul_indication_stats, "UL Indication", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->rx_pdsch_stats, "PDSCH receiver", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->dlsch_decoding_stats[0], "PDSCH decoding t0", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->dlsch_decoding_stats[1], "PDSCH decoding t1", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->dlsch_deinterleaving_stats, " -> Deinterleive", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->dlsch_rate_unmatching_stats, " -> Rate Unmatch", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->dlsch_ldpc_decoding_stats, " ->  LDPC Decode", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->dlsch_unscrambling_stats, "PDSCH unscrambling", NULL, NULL, output + stroff);
-  stroff += print_meas_log(&ue->dlsch_rx_pdcch_stats, "PDCCH handling", NULL, NULL, output + stroff);
-  return stroff;
+  const char *begin = output;
+  const char *end = output + max_len;
+  output += print_meas_log(&ue->phy_proc_tx, "L1 TX processing", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->ulsch_encoding_stats, "ULSCH encoding", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->phy_proc_rx[0], "L1 RX processing t0", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->phy_proc_rx[1], "L1 RX processing t1", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->ue_ul_indication_stats, "UL Indication", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->rx_pdsch_stats, "PDSCH receiver", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->dlsch_decoding_stats[0], "PDSCH decoding t0", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->dlsch_decoding_stats[1], "PDSCH decoding t1", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->dlsch_deinterleaving_stats, " -> Deinterleive", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->dlsch_rate_unmatching_stats, " -> Rate Unmatch", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->dlsch_ldpc_decoding_stats, " ->  LDPC Decode", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->dlsch_unscrambling_stats, "PDSCH unscrambling", NULL, NULL, output, end - output);
+  output += print_meas_log(&ue->dlsch_rx_pdcch_stats, "PDCCH handling", NULL, NULL, output, end - output);
+  return output - begin;
 }
 
 static void *nrL1_UE_stats_thread(void *param)
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
index 234705540273ac85571d27a216ac910a0e9c2dde..de3c1088412f657081a73ea4978ba5ad657e20d0 100644
--- a/executables/nr-uesoftmodem.c
+++ b/executables/nr-uesoftmodem.c
@@ -259,13 +259,11 @@ void init_tpools(uint8_t nun_dlsch_threads) {
 }
 static void get_options(void) {
 
-  nrUE_params.ofdm_offset_divisor = 8;
   paramdef_t cmdline_params[] =CMDLINE_NRUEPARAMS_DESC ;
   int numparams = sizeof(cmdline_params)/sizeof(paramdef_t);
+  config_get(cmdline_params,numparams,NULL);
   config_process_cmdline( cmdline_params,numparams,NULL);
 
-
-
   if (vcdflag > 0)
     ouput_vcd = 1;
 }
@@ -317,8 +315,8 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
   UE->rf_map.card          = card_offset;
   UE->rf_map.chain         = CC_id + chain_offset;
 
-  LOG_I(PHY,"Set UE mode %d, UE_fo_compensation %d, UE_scan_carrier %d, UE_no_timing_correction %d \n, do_prb_interpolation %d\n",
-  	   UE->mode, UE->UE_fo_compensation, UE->UE_scan_carrier, UE->no_timing_correction, UE->prb_interpolation);
+  LOG_I(PHY,"Set UE mode %d, UE_fo_compensation %d, UE_scan_carrier %d, UE_no_timing_correction %d \n, chest-freq %d\n",
+  	   UE->mode, UE->UE_fo_compensation, UE->UE_scan_carrier, UE->no_timing_correction, UE->chest_freq);
 
   // Set FP variables
 
@@ -330,6 +328,7 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
   LOG_I(PHY, "Set UE nb_rx_antenna %d, nb_tx_antenna %d, threequarter_fs %d, ssb_start_subcarrier %d\n", fp->nb_antennas_rx, fp->nb_antennas_tx, fp->threequarter_fs, fp->ssb_start_subcarrier);
 
   fp->ofdm_offset_divisor = nrUE_params.ofdm_offset_divisor;
+  UE->max_ldpc_iterations = nrUE_params.max_ldpc_iterations;
 
 }
 
diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h
index 95914678e5ba84418d7d65ab1c04510e9b664fc6..995d81f19c7aff8dcea7120ef1354e2047b1a3a2 100644
--- a/executables/nr-uesoftmodem.h
+++ b/executables/nr-uesoftmodem.h
@@ -7,10 +7,11 @@
 
 
 
-#define  CONFIG_HLP_IF_FREQ                "IF frequency for RF, if needed"
-#define  CONFIG_HLP_IF_FREQ_OFF            "UL IF frequency offset for RF, if needed"
+#define  CONFIG_HLP_IF_FREQ                "IF frequency for RF, if needed\n"
+#define  CONFIG_HLP_IF_FREQ_OFF            "UL IF frequency offset for RF, if needed\n"
 #define  CONFIG_HLP_DLSCH_PARA             "number of threads for dlsch processing 0 for no parallelization\n"
 #define  CONFIG_HLP_OFFSET_DIV             "Divisor for computing OFDM symbol offset in Rx chain (num samples in CP/<the value>). Default value is 8. To set the sample offset to 0, set this value ~ 10e6\n"
+#define  CONFIG_HLP_MAX_LDPC_ITERATIONS    "Maximum LDPC decoder iterations\n"
 /***************************************************************************************************************************************/
 /* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument
    when calling config_get or config_getlist functions                                                                                 */
@@ -30,8 +31,9 @@
 #define CMDLINE_NRUEPARAMS_DESC {  \
     {"usrp-args",                CONFIG_HLP_USRP_ARGS,   0,               strptr:(char **)&usrp_args,         defstrval:"type=b200", TYPE_STRING,   0},    \
     {"single-thread-disable",    CONFIG_HLP_NOSNGLT,     PARAMFLAG_BOOL,  iptr:&single_thread_flag,           defintval:1,           TYPE_INT,    0}, \
-    {"dlsch-parallel",           CONFIG_HLP_DLSCH_PARA,  0,               iptr:(int32_t *)&nrUE_params.nr_dlsch_parallel,       defintval:0,           TYPE_UINT8,  0}, \
-    {"offset-divisor",           CONFIG_HLP_OFFSET_DIV,  0,               uptr:(uint32_t *)&nrUE_params.ofdm_offset_divisor,    defuintval:UINT_MAX,           TYPE_UINT32,  0}, \
+    {"dlsch-parallel",           CONFIG_HLP_DLSCH_PARA,  0,               u8ptr:&nrUE_params.nr_dlsch_parallel,       defintval:0,           TYPE_UINT8,  0}, \
+    {"offset-divisor",           CONFIG_HLP_OFFSET_DIV,  0,               uptr:&nrUE_params.ofdm_offset_divisor,    defuintval:8,           TYPE_UINT32,  0}, \
+    {"max-ldpc-iterations",      CONFIG_HLP_MAX_LDPC_ITERATIONS, 0,       u8ptr:&nrUE_params.max_ldpc_iterations,    defuintval:5,       TYPE_UINT8, 0}, \
     {"nr-dlsch-demod-shift",     CONFIG_HLP_DLSHIFT,     0,               iptr:(int32_t *)&nr_dlsch_demod_shift,    defintval:0,     TYPE_INT,    0}, \
     {"V" ,                       CONFIG_HLP_VCD,         PARAMFLAG_BOOL,  iptr:&vcdflag,                      defintval:0,     TYPE_INT,    0}, \
     {"uecap_file",               CONFIG_HLP_UECAP_FILE,  0,               strptr:(char **)&uecap_file,        defstrval:"./uecap.xml", TYPE_STRING, 0}, \
@@ -67,7 +69,8 @@
     {"T" ,                       CONFIG_HLP_TDD,         PARAMFLAG_BOOL,  iptr:&tddflag,                      defintval:0,           TYPE_INT,   0}, \
     {"if_freq" ,                 CONFIG_HLP_IF_FREQ,     0,               u64ptr:&(UE->if_freq),              defuintval:0,          TYPE_UINT64,0}, \
     {"if_freq_off" ,             CONFIG_HLP_IF_FREQ_OFF, 0,               iptr:&(UE->if_freq_off),            defuintval:0,          TYPE_INT,   0}, \
-    {"do-prb-interpolation",     CONFIG_HLP_PRBINTER,    PARAMFLAG_BOOL,  iptr:&(UE->prb_interpolation),      defintval:0,           TYPE_INT,   0}, \
+    {"chest-freq",               CONFIG_HLP_CHESTFREQ,   0,               iptr:&(UE->chest_freq),             defintval:0,           TYPE_INT,   0}, \
+    {"chest-time",               CONFIG_HLP_CHESTTIME,   0,               iptr:&(UE->chest_time),             defintval:0,           TYPE_INT,   0}, \
     {"ue-timing-correction-disable", CONFIG_HLP_DISABLETIMECORR, PARAMFLAG_BOOL, iptr:&(UE->no_timing_correction), defintval:0,      TYPE_INT,   0}, \
 }
 
@@ -76,6 +79,7 @@ typedef struct {
   uint64_t       optmask;   //mask to store boolean config options
   uint32_t       ofdm_offset_divisor; // Divisor for sample offset computation for each OFDM symbol
   uint8_t        nr_dlsch_parallel; // number of threads for dlsch decoding, 0 means no parallelization
+  uint8_t        max_ldpc_iterations; // number of maximum LDPC iterations
   tpool_t        Tpool;             // thread pool 
 } nrUE_params_t;
 extern uint64_t get_nrUE_optmask(void);
diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h
index 72a9491f27f5817337f81961dc01ee368db96488..6c5c6107238921949ce0cf3e447683c60fb582c7 100644
--- a/executables/softmodem-common.h
+++ b/executables/softmodem-common.h
@@ -72,7 +72,8 @@ extern "C"
 #define CONFIG_HLP_DLMCS         "Set the maximum downlink MCS\n"
 #define CONFIG_HLP_STMON         "Enable processing timing measurement of lte softmodem on per subframe basis \n"
 #define CONFIG_HLP_256QAM        "Use the 256 QAM mcs table for PDSCH\n"
-#define CONFIG_HLP_PRBINTER       "Do PRB based averaging of channel estimates. Frequency domain linear interpolation by default\n"
+#define CONFIG_HLP_CHESTFREQ     "Set channel estimation type in frequency domain. 0-Linear interpolation (default). 1-PRB based averaging of channel estimates in frequency. \n"
+#define CONFIG_HLP_CHESTTIME     "Set channel estimation type in time domain. 0-Symbols take estimates of the last preceding DMRS symbol (default). 1-Symbol based averaging of channel estimates in time. \n"
 
 #define CONFIG_HLP_NONSTOP       "Go back to frame sync mode after 100 consecutive PBCH failures\n"
 //#define CONFIG_HLP_NUMUES        "Set the number of UEs for the emulation"
@@ -122,7 +123,8 @@ extern "C"
 #define TUNE_OFFSET         softmodem_params.tune_offset
 #define SEND_DMRSSYNC       softmodem_params.send_dmrs_sync
 #define USIM_TEST           softmodem_params.usim_test
-#define PRB_INTERPOLATION   softmodem_params.prb_interpolation
+#define CHEST_FREQ          softmodem_params.chest_freq
+#define CHEST_TIME          softmodem_params.chest_time
 #define NFAPI               softmodem_params.nfapi
 #define NSA                 softmodem_params.nsa
 #define NODE_NUMBER         softmodem_params.node_number
@@ -160,10 +162,11 @@ extern int usrp_tx_thread;
     {"rfsim",                CONFIG_HLP_RFSIM,        PARAMFLAG_BOOL, uptr:&rfsim,                        defintval:0,           TYPE_INT,    0},                     \
     {"nokrnmod",             CONFIG_HLP_NOKRNMOD,     PARAMFLAG_BOOL, uptr:&nokrnmod,                     defintval:0,           TYPE_INT,    0},                     \
     {"nbiot-disable",        CONFIG_HLP_DISABLNBIOT,  PARAMFLAG_BOOL, uptr:&nonbiot,                      defuintval:0,          TYPE_INT,    0},                     \
+    {"chest-freq",           CONFIG_HLP_CHESTFREQ,    0,              iptr:&CHEST_FREQ,                   defintval:0,           TYPE_INT,    0},                     \
+    {"chest-time",           CONFIG_HLP_CHESTTIME,    0,              iptr:&CHEST_TIME,                   defintval:0,           TYPE_INT,    0},                     \
     {"nsa",                  CONFIG_HLP_NSA,          PARAMFLAG_BOOL, iptr:&NSA,                          defintval:0,           TYPE_INT,    0},                     \
     {"node-number",          NULL,                    0,              u16ptr:&NODE_NUMBER,                defuintval:0,          TYPE_UINT16, 0},                     \
     {"usrp-tx-thread-config", CONFIG_HLP_USRP_THREAD, 0,              iptr:&usrp_tx_thread,               defstrval:0,           TYPE_INT,    0},                     \
-    {"do-prb-interpolation", CONFIG_HLP_PRBINTER,     PARAMFLAG_BOOL, iptr:&PRB_INTERPOLATION,            defintval:0,           TYPE_INT,    0},                     \
     {"nfapi",                CONFIG_HLP_NFAPI,        0,              u8ptr:&nfapi_mode,                  defintval:0,           TYPE_UINT8,  0},                     \
     {"non-stop",             CONFIG_HLP_NONSTOP,      PARAMFLAG_BOOL, iptr:&NON_STOP,                     defintval:0,           TYPE_INT,    0},                     \
     {"emulate-l1",           CONFIG_L1_EMULATOR,      PARAMFLAG_BOOL, iptr:&EMULATE_L1,                   defintval:0,           TYPE_INT,    0},                     \
@@ -251,7 +254,9 @@ typedef struct {
   double         tune_offset;
   int            hw_timing_advance;
   uint32_t       send_dmrs_sync;
-  int            prb_interpolation;
+  int            use_256qam_table;
+  int            chest_time;
+  int            chest_freq;
   uint8_t        nfapi;
   int            nsa;
   uint16_t       node_number;
diff --git a/openair1/PHY/CODING/coding_defs.h b/openair1/PHY/CODING/coding_defs.h
index 9972a47ee7d9369eabdd7852ac10093cab9cc940..1854f28fa788f6602366f959b191486a861340ec 100644
--- a/openair1/PHY/CODING/coding_defs.h
+++ b/openair1/PHY/CODING/coding_defs.h
@@ -38,7 +38,6 @@
 #define MAX_TURBO_ITERATIONS_MBSFN 8
 #define MAX_TURBO_ITERATIONS max_turbo_iterations
 
-#define MAX_LDPC_ITERATIONS 5
 #define MAX_LDPC_ITERATIONS_MBSFN 4
 
 #define LTE_NULL 2
diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c
index 56327a9b0fb7e3bb337abf7b3ecf45592f2b3372..e2139a9903c22871cfca7292c544b0a97a424fba 100644
--- a/openair1/PHY/INIT/nr_init.c
+++ b/openair1/PHY/INIT/nr_init.c
@@ -544,8 +544,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
   gNB->nr_gold_pdsch_dmrs = (uint32_t ****)malloc16(fp->slots_per_frame*sizeof(uint32_t ***));
   uint32_t ****pdsch_dmrs             = gNB->nr_gold_pdsch_dmrs;
 
-  // ceil(((NB_RB*6(k)*2(QPSK)/32) // 3 RE *2(QPSK)
-  int pdsch_dmrs_init_length =  ((fp->N_RB_DL*12)>>5)+1;
+  // ceil(((NB_RB*12(k)*2(QPSK)/32) // 3 RE *2(QPSK)
+  const int pdsch_dmrs_init_length =  ((fp->N_RB_DL*24)>>5)+1;
   for (int slot=0; slot<fp->slots_per_frame; slot++) {
     pdsch_dmrs[slot] = (uint32_t ***)malloc16(fp->symbols_per_slot*sizeof(uint32_t **));
     AssertFatal(pdsch_dmrs[slot]!=NULL, "NR init: pdsch_dmrs for slot %d - malloc failed\n", slot);
@@ -1050,7 +1050,7 @@ void init_nr_transport(PHY_VARS_gNB *gNB) {
 
     LOG_I(PHY,"Allocating Transport Channel Buffers for ULSCH  %d/%d\n",i,gNB->number_of_nr_ulsch_max);
 
-    gNB->ulsch[i] = new_gNB_ulsch(MAX_LDPC_ITERATIONS, fp->N_RB_UL);
+    gNB->ulsch[i] = new_gNB_ulsch(gNB->max_ldpc_iterations, fp->N_RB_UL);
 
     if (!gNB->ulsch[i]) {
       LOG_E(PHY,"Can't get gNB ulsch structures\n");
diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c
index b1a01fb3dc8531e6cdd6aa22a493f738b97f177c..c96aeab432477c356d5762cbd2e7d62f0d146383 100644
--- a/openair1/PHY/INIT/nr_init_ru.c
+++ b/openair1/PHY/INIT/nr_init_ru.c
@@ -60,7 +60,7 @@ int nr_phy_init_RU(RU_t *ru) {
 
     for (i=0; i<ru->nb_tx; i++) {
       // Allocate 10 subframes of I/Q TX signal data (time) if not
-      ru->common.txdata[i]  = (int32_t*)malloc16_clear( ru->sf_extension + (fp->samples_per_frame*sizeof(int32_t) ));
+      ru->common.txdata[i]  = (int32_t*)malloc16_clear((ru->sf_extension +fp->samples_per_frame) *sizeof(int32_t));
       LOG_I(PHY,"[INIT] common.txdata[%d] = %p (%lu bytes,sf_extension %d)\n",i,ru->common.txdata[i],
 	     (ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t),ru->sf_extension);
       ru->common.txdata[i] =  &ru->common.txdata[i][ru->sf_extension];
diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c
index 95ca53e85f3efef289a774a1e2b6e2f56fa17429..077302b20795bdea4b59187f54cff6b1452ec411 100644
--- a/openair1/PHY/INIT/nr_init_ue.c
+++ b/openair1/PHY/INIT/nr_init_ue.c
@@ -587,7 +587,7 @@ void init_nr_ue_transport(PHY_VARS_NR_UE *ue) {
   for (int i = 0; i < NUMBER_OF_CONNECTED_gNB_MAX; i++) {
     for (int j=0; j<num_codeword; j++) {
       for (int k=0; k<RX_NB_TH_MAX; k++) {
-        AssertFatal((ue->dlsch[k][i][j]  = new_nr_ue_dlsch(1,NR_MAX_DLSCH_HARQ_PROCESSES,NSOFT,MAX_LDPC_ITERATIONS,ue->frame_parms.N_RB_DL))!=NULL,"Can't get ue dlsch structures\n");
+        AssertFatal((ue->dlsch[k][i][j]  = new_nr_ue_dlsch(1,NR_MAX_DLSCH_HARQ_PROCESSES,NSOFT,ue->max_ldpc_iterations,ue->frame_parms.N_RB_DL))!=NULL,"Can't get ue dlsch structures\n");
         LOG_D(PHY,"dlsch[%d][%d][%d] => %p\n",k,i,j,ue->dlsch[k][i][j]);
         if (j==0) {
           AssertFatal((ue->ulsch[k][i] = new_nr_ue_ulsch(ue->frame_parms.N_RB_UL, NR_MAX_ULSCH_HARQ_PROCESSES,&ue->frame_parms))!=NULL,"Can't get ue ulsch structures\n");
@@ -596,8 +596,8 @@ void init_nr_ue_transport(PHY_VARS_NR_UE *ue) {
       }
     }
 
-    ue->dlsch_SI[i]  = new_nr_ue_dlsch(1,1,NSOFT,MAX_LDPC_ITERATIONS,ue->frame_parms.N_RB_DL);
-    ue->dlsch_ra[i]  = new_nr_ue_dlsch(1,1,NSOFT,MAX_LDPC_ITERATIONS,ue->frame_parms.N_RB_DL);
+    ue->dlsch_SI[i]  = new_nr_ue_dlsch(1,1,NSOFT,ue->max_ldpc_iterations,ue->frame_parms.N_RB_DL);
+    ue->dlsch_ra[i]  = new_nr_ue_dlsch(1,1,NSOFT,ue->max_ldpc_iterations,ue->frame_parms.N_RB_DL);
     ue->transmission_mode[i] = ue->frame_parms.nb_antenna_ports_gNB==1 ? 1 : 2;
   }
 
diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
index 7b526876da771e997b4343a2413b6ce15f12fef4..cd3b535b3fd8024b1a3040bd1d1ecd53823bb446 100644
--- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
+++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c
@@ -92,6 +92,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
   int16_t *fl,*fm,*fr,*fml,*fmr,*fmm,*fdcl,*fdcr,*fdclh,*fdcrh;
   int ch_offset,symbol_offset ;
   int32_t **ul_ch_estimates_time =  gNB->pusch_vars[ul_id]->ul_ch_estimates_time;
+  int chest_freq = gNB->chest_freq;
   __m128i *ul_ch_128;
 
 #ifdef DEBUG_CH
@@ -225,8 +226,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
     LOG_I(PHY, "In %s ul_ch addr %p nushift %d\n", __FUNCTION__, ul_ch, nushift);
 #endif
 
-    if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && gNB->prb_interpolation == 0) {
-
+    if (pusch_pdu->dmrs_config_type == pusch_dmrs_type1 && chest_freq == 0){
       LOG_D(PHY,"PUSCH estimation DMRS type 1, Freq-domain interpolation");
 
       // For configuration type 1: k = 4*n + 2*k' + delta,
@@ -329,7 +329,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
       }
 #endif    
     }
-    else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2 && gNB->prb_interpolation == 0) { //pusch_dmrs_type2  |p_r,p_l,d,d,d,d,p_r,p_l,d,d,d,d|
+    else if (pusch_pdu->dmrs_config_type == pusch_dmrs_type2 && chest_freq == 0) { //pusch_dmrs_type2  |p_r,p_l,d,d,d,d,p_r,p_l,d,d,d,d|
       LOG_D(PHY,"PUSCH estimation DMRS type 2, Freq-domain interpolation");
       // Treat first DMRS specially (left edge)
 
diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.c b/openair1/PHY/NR_REFSIG/dmrs_nr.c
index ca901e1452c698b5ec1b0a3dadf755dfd11e62e3..1fd502a93e1369526ac012dd7905a24b6a94e3a8 100644
--- a/openair1/PHY/NR_REFSIG/dmrs_nr.c
+++ b/openair1/PHY/NR_REFSIG/dmrs_nr.c
@@ -338,3 +338,81 @@ int8_t get_valid_dmrs_idx_for_channel_est(uint16_t  dmrs_symb_pos, uint8_t count
   }
   return symbIdx;
 }
+
+/* perform averaging of channel estimates and store result in first symbol buffer */
+void nr_chest_time_domain_avg(NR_DL_FRAME_PARMS *frame_parms,
+                              int **ch_est,
+                              uint8_t num_symbols,
+                              uint8_t start_symbol,
+                              uint16_t dmrs_bitmap,
+                              uint16_t num_rbs)
+{
+  __m128i *ul_ch128_0;
+  __m128i *ul_ch128_1;
+  int16_t *ul_ch16_0;
+  int total_symbols = start_symbol + num_symbols;
+  int num_dmrs_symb = get_dmrs_symbols_in_slot(dmrs_bitmap, total_symbols);
+  int first_dmrs_symb = get_next_dmrs_symbol_in_slot(dmrs_bitmap, start_symbol, total_symbols);
+  AssertFatal(first_dmrs_symb > -1, "No DMRS symbol present in this slot\n");
+  for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
+    for (int symb = first_dmrs_symb+1; symb < total_symbols; symb++) {
+      ul_ch128_0 = (__m128i *)&ch_est[aarx][first_dmrs_symb*frame_parms->ofdm_symbol_size];
+      if ((dmrs_bitmap >> symb) & 0x01) {
+        ul_ch128_1 = (__m128i *)&ch_est[aarx][symb*frame_parms->ofdm_symbol_size];
+        for (int rbIdx = 0; rbIdx < num_rbs; rbIdx++) {
+          ul_ch128_0[0] = _mm_adds_epi16(ul_ch128_0[0], ul_ch128_1[0]);
+          ul_ch128_0[1] = _mm_adds_epi16(ul_ch128_0[1], ul_ch128_1[1]);
+          ul_ch128_0[2] = _mm_adds_epi16(ul_ch128_0[2], ul_ch128_1[2]);
+          ul_ch128_0 += 3;
+          ul_ch128_1 += 3;
+        }
+      }
+    }
+    ul_ch128_0 = (__m128i *)&ch_est[aarx][first_dmrs_symb*frame_parms->ofdm_symbol_size];
+    if (num_dmrs_symb == 2) {
+      for (int rbIdx = 0; rbIdx < num_rbs; rbIdx++) {
+        ul_ch128_0[0] = _mm_srai_epi16(ul_ch128_0[0], 1);
+        ul_ch128_0[1] = _mm_srai_epi16(ul_ch128_0[1], 1);
+        ul_ch128_0[2] = _mm_srai_epi16(ul_ch128_0[2], 1);
+        ul_ch128_0 += 3;
+      }
+    } else if (num_dmrs_symb == 4) {
+      for (int rbIdx = 0; rbIdx < num_rbs; rbIdx++) {
+        ul_ch128_0[0] = _mm_srai_epi16(ul_ch128_0[0], 2);
+        ul_ch128_0[1] = _mm_srai_epi16(ul_ch128_0[1], 2);
+        ul_ch128_0[2] = _mm_srai_epi16(ul_ch128_0[2], 2);
+        ul_ch128_0 += 3;
+      }
+    } else if (num_dmrs_symb == 3) {
+      ul_ch16_0 = (int16_t *)&ch_est[aarx][first_dmrs_symb*frame_parms->ofdm_symbol_size];
+      for (int rbIdx = 0; rbIdx < num_rbs; rbIdx++) {
+        ul_ch16_0[0] /= 3;
+        ul_ch16_0[1] /= 3;
+        ul_ch16_0[2] /= 3;
+        ul_ch16_0[3] /= 3;
+        ul_ch16_0[4] /= 3;
+        ul_ch16_0[5] /= 3;
+        ul_ch16_0[6] /= 3;
+        ul_ch16_0[7] /= 3;
+        ul_ch16_0[8] /= 3;
+        ul_ch16_0[9] /= 3;
+        ul_ch16_0[10] /= 3;
+        ul_ch16_0[11] /= 3;
+        ul_ch16_0[12] /= 3;
+        ul_ch16_0[13] /= 3;
+        ul_ch16_0[14] /= 3;
+        ul_ch16_0[15] /= 3;
+        ul_ch16_0[16] /= 3;
+        ul_ch16_0[17] /= 3;
+        ul_ch16_0[18] /= 3;
+        ul_ch16_0[19] /= 3;
+        ul_ch16_0[20] /= 3;
+        ul_ch16_0[21] /= 3;
+        ul_ch16_0[22] /= 3;
+        ul_ch16_0[23] /= 3;
+        ul_ch16_0 += 24;
+      }
+    } else AssertFatal((num_dmrs_symb < 5) && (num_dmrs_symb > 0), "Illegal number of DMRS symbols in the slot\n");
+  }
+}
+
diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.h b/openair1/PHY/NR_REFSIG/dmrs_nr.h
index 13a83be53f770932e8f350710a65aed371711212..1297a0cc2ff7b2f95c65ccb2259fc77681094ed9 100644
--- a/openair1/PHY/NR_REFSIG/dmrs_nr.h
+++ b/openair1/PHY/NR_REFSIG/dmrs_nr.h
@@ -65,6 +65,12 @@ void nr_gen_ref_conj_symbols(uint32_t *in, uint32_t length, int16_t *output, uin
 int8_t get_next_dmrs_symbol_in_slot(uint16_t  ul_dmrs_symb_pos, uint8_t counter, uint8_t end_symbol);
 uint8_t get_dmrs_symbols_in_slot(uint16_t l_prime_mask,  uint16_t nb_symb);
 int8_t get_valid_dmrs_idx_for_channel_est(uint16_t  dmrs_symb_pos, uint8_t counter);
+void nr_chest_time_domain_avg(NR_DL_FRAME_PARMS *frame_parms,
+                              int **ch_est,
+                              uint8_t num_symbols,
+                              uint8_t start_symbol,
+                              uint16_t dmrs_bitmap,
+                              uint16_t num_rbs);
 
 static inline uint8_t is_dmrs_symbol(uint8_t l, uint16_t dmrsSymbMask ) { return ((dmrsSymbMask >> l) & 0x1); }
 #undef EXTERN
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c
index 3a95ba49b0c42f41d3320286d81761ff9d714d5e..dc1ed47e0ffd4f7698201a05082a559f4830940e 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dci.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c
@@ -73,7 +73,6 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
                      NR_DL_FRAME_PARMS *frame_parms,
                      int slot) {
 
-  int16_t mod_dmrs[NR_MAX_CSET_DURATION][NR_MAX_PDCCH_DMRS_LENGTH>>1] __attribute__((aligned(16))); // 3 for the max coreset duration
   uint16_t cset_start_sc;
   uint8_t cset_start_symb, cset_nsymb;
   int k,l,k_prime,dci_idx, dmrs_idx;
@@ -82,13 +81,14 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
     
   int rb_offset;
   int n_rb;
-
   // compute rb_offset and n_prb based on frequency allocation
   nr_cce_t cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL];
-  nr_fill_cce_list(cce_list,0,pdcch_pdu_rel15);
+  nr_fill_cce_list(cce_list, pdcch_pdu_rel15);
   get_coreset_rballoc(pdcch_pdu_rel15->FreqDomainResource,&n_rb,&rb_offset);
   cset_start_sc = frame_parms->first_carrier_offset + (pdcch_pdu_rel15->BWPStart + rb_offset) * NR_NB_SC_PER_RB;
 
+  int16_t mod_dmrs[pdcch_pdu_rel15->StartSymbolIndex+pdcch_pdu_rel15->DurationSymbols][(n_rb+rb_offset)*6] __attribute__((aligned(16))); // 3 for the max coreset duration
+
   for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++) {
     /*The coreset is initialised
      * in frequency: the first subcarrier is obtained by adding the first CRB overlapping the SSB and the rb_offset for coreset 0
@@ -119,7 +119,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
       
     /// DMRS QPSK modulation
     for (int symb=cset_start_symb; symb<cset_start_symb + pdcch_pdu_rel15->DurationSymbols; symb++) {
-      
+
       nr_modulation(gold_pdcch_dmrs[symb], dmrs_length, DMRS_MOD_ORDER, mod_dmrs[symb]); //Qm = 2 as DMRS is QPSK modulated
       
 #ifdef DEBUG_PDCCH_DMRS
@@ -179,8 +179,10 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
 
     // Get cce_list indices by reg_idx in ascending order
     int reg_list_index = 0;
+    int N_regs = n_rb*pdcch_pdu_rel15->DurationSymbols; // nb of REGs per coreset
+    int N_cces = N_regs / NR_NB_REG_PER_CCE; // nb of cces in coreset
     int reg_list_order[NR_MAX_PDCCH_AGG_LEVEL] = {};
-    for (int p = 0; p < NR_MAX_PDCCH_AGG_LEVEL; p++) {
+    for (int p = 0; p < N_cces; p++) {
       for(int p2 = 0; p2 < dci_pdu->AggregationLevel; p2++) {
         if(cce_list[d][p2].reg_list[0].reg_idx == p * NR_NB_REG_PER_CCE) {
           reg_list_order[reg_list_index] = p2;
@@ -192,24 +194,25 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
 
     /*Mapping the encoded DCI along with the DMRS */
     for(int symbol_idx = 0; symbol_idx < pdcch_pdu_rel15->DurationSymbols; symbol_idx++) {
-      for (int cce_count = 0; cce_count < dci_pdu->AggregationLevel; cce_count+=pdcch_pdu_rel15->DurationSymbols) {
+      for (int cce_count = 0; cce_count < dci_pdu->AggregationLevel; cce_count++) {
 
         int8_t cce_idx = reg_list_order[cce_count];
 
-        for (int reg_in_cce_idx = 0; reg_in_cce_idx < NR_NB_REG_PER_CCE; reg_in_cce_idx++) {
+        for (int reg_in_cce_idx = 0; reg_in_cce_idx < NR_NB_REG_PER_CCE; reg_in_cce_idx+=pdcch_pdu_rel15->DurationSymbols) {
 
           k = cset_start_sc + cce_list[d][cce_idx].reg_list[reg_in_cce_idx].start_sc_idx;
-
+          LOG_D(PHY,"CCE %d REG %d k %d\n",cce_idx,reg_in_cce_idx+symbol_idx,k);
           if (k >= frame_parms->ofdm_symbol_size)
             k -= frame_parms->ofdm_symbol_size;
 
           l = cset_start_symb + symbol_idx;
 
           // dmrs index depends on reference point for k according to 38.211 7.4.1.3.2
+          int eff_reg_idx = cce_list[d][cce_idx].reg_list[reg_in_cce_idx].reg_idx/pdcch_pdu_rel15->DurationSymbols;
           if (pdcch_pdu_rel15->CoreSetType == NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG)
-            dmrs_idx = (cce_list[d][cce_idx].reg_list[reg_in_cce_idx].reg_idx) * 3;
+            dmrs_idx = eff_reg_idx * 3;
           else
-            dmrs_idx = (cce_list[d][cce_idx].reg_list[reg_in_cce_idx].reg_idx + rb_offset) * 3;
+            dmrs_idx = (eff_reg_idx + rb_offset) * 3;
 
           k_prime = 0;
 
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.h b/openair1/PHY/NR_TRANSPORT/nr_dci.h
index 490a8b528682fa3d64b7a8d0de5f7a8f223372cb..0bf6932bb50685c622236c2b4dfdd095f1ae0e49 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dci.h
+++ b/openair1/PHY/NR_TRANSPORT/nr_dci.h
@@ -55,6 +55,6 @@ void nr_fill_ul_dci(PHY_VARS_gNB *gNB,
 		    int slot,
 		    nfapi_nr_ul_dci_request_pdus_t *pdcch_pdu);
 
-void nr_fill_cce_list(nr_cce_t cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL], uint8_t m,nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15);
+void nr_fill_cce_list(nr_cce_t cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL], nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15);
 
 #endif //__PHY_NR_TRANSPORT_DCI__H
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c
index 8d5eb4a66072ca56684ebee75c12cc2f69c07a47..e9d3010ce7c4c884ab9c68025ed59be389e21d47 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dci_tools.c
@@ -37,89 +37,8 @@
 
 #include "nr_dlsch.h"
 
-/*
-  Original version to keep code for Y that needs to be moved to MAC
-
-void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint16_t n_shift, uint8_t m) {
-
-  nr_cce_t* cce;
-  nr_reg_t* reg;
-  nfapi_nr_dl_config_pdcch_pdu_rel15_t* pdcch_pdu = gNB->pdcch_pdu.pdcch;
-
-  uint8_t L = dci_alloc->L;
-  uint8_t bsize = pdcch_params->reg_bundle_size;
-  uint8_t R = pdcch_params->interleaver_size;
-  uint16_t N_reg = pdcch_params->n_rb * pdcch_params->n_symb;
-  uint16_t Y, N_cce, M_s_max, n_CI=0, tmp, C=0;
-  uint16_t n_RNTI = (pdcch_params->search_space_type == NFAPI_NR_SEARCH_SPACE_TYPE_UE_SPECIFIC)? pdcch_params->rnti:0;
-  uint32_t A[3]={39827,39829,39839};
-
-  if (pdcch_params->config_type == NFAPI_NR_CSET_CONFIG_MIB_SIB1)
-    AssertFatal(L>=4, "Invalid aggregation level for SIB1 configured PDCCH %d\n", L);
-
-  N_cce = N_reg / NR_NB_REG_PER_CCE;
-  //Max number of candidates per aggregation level -- SIB1 configured search space only
-  M_s_max = (L==4)?4:(L==8)?2:1;
-
-  if (pdcch_params->search_space_type == NFAPI_NR_SEARCH_SPACE_TYPE_COMMON)
-    Y = 0;
-  else { //NFAPI_NR_SEARCH_SPACE_TYPE_UE_SPECIFIC
-    Y = (A[0]*n_RNTI)%65537; // Candidate 0, antenna port 0
-  }
-
-  if (pdcch_params->cr_mapping_type == NFAPI_NR_CCE_REG_MAPPING_INTERLEAVED) {
-	  uint16_t assertFatalCond = (N_reg%(bsize*R));
-	  AssertFatal(assertFatalCond == 0,"CCE to REG interleaving: Invalid configuration leading to non integer C (N_reg %us, bsize %d R %d)\n",N_reg, bsize, R);
-	  C = N_reg/(bsize*R);
-  }
-
-  tmp = L * (( Y + (m*N_cce)/(L*M_s_max) + n_CI ) % CEILIDIV(N_cce,L));
-
-  LOG_D(PHY, "CCE list generation for candidate %d: bundle size %d ilv size %d tmp %d\n", m, bsize, R, tmp);
-  for (uint8_t cce_idx=0; cce_idx<L; cce_idx++) {
-    cce = &dci_alloc->cce_list[cce_idx];
-    cce->cce_idx = tmp + cce_idx;
-    LOG_D(PHY, "cce_idx %d\n", cce->cce_idx);
-
-    if (pdcch_params->cr_mapping_type == NFAPI_NR_CCE_REG_MAPPING_INTERLEAVED) {
-      LOG_D(PHY, "Interleaved CCE to REG mapping\n");
-      uint8_t j = cce->cce_idx, j_prime;
-      uint8_t r,c,idx;
-
-      for (uint8_t bundle_idx=0; bundle_idx<NR_NB_REG_PER_CCE/bsize; bundle_idx++) {
-        j_prime = 6*j/bsize + bundle_idx;
-        r = j_prime%R;
-        c = (j_prime-r)/R;
-        idx = (r*C + c + n_shift)%(N_reg/bsize);
-        LOG_D(PHY, "bundle idx = %d \n j = %d \t j_prime = %d \t r = %d \t c = %d\n", idx, j , j_prime, r, c);
-
-        for (uint8_t reg_idx=0; reg_idx<bsize; reg_idx++) {
-          reg = &cce->reg_list[reg_idx];
-          reg->reg_idx = bsize*idx + reg_idx;
-          reg->start_sc_idx = (reg->reg_idx/pdcch_params->n_symb) * NR_NB_SC_PER_RB;
-          reg->symb_idx = reg->reg_idx % pdcch_params->n_symb;
-          LOG_D(PHY, "reg %d symbol %d start subcarrier %d\n", reg->reg_idx, reg->symb_idx, reg->start_sc_idx);
-        }
-      }
-    }
-    else { // NFAPI_NR_CCE_REG_MAPPING_NON_INTERLEAVED
-      LOG_D(PHY, "Non interleaved CCE to REG mapping\n");
-      for (uint8_t reg_idx=0; reg_idx<NR_NB_REG_PER_CCE; reg_idx++) {
-        reg = &cce->reg_list[reg_idx];
-        reg->reg_idx = cce->cce_idx*NR_NB_REG_PER_CCE + reg_idx;
-        reg->start_sc_idx = (reg->reg_idx/pdcch_params->n_symb) * NR_NB_SC_PER_RB;
-        reg->symb_idx = reg->reg_idx % pdcch_params->n_symb;
-        LOG_D(PHY, "reg %d symbol %d start subcarrier %d\n", reg->reg_idx, reg->symb_idx, reg->start_sc_idx);
-      }
-
-    }
 
-  }
-}
-
-*/
-
-void nr_fill_cce_list(nr_cce_t cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL], uint8_t m,  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15) {
+void nr_fill_cce_list(nr_cce_t cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL], nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15) {
 
   nr_cce_t* cce;
   nr_reg_t* reg;
@@ -128,71 +47,51 @@ void nr_fill_cce_list(nr_cce_t cce_list[MAX_DCI_CORESET][NR_MAX_PDCCH_AGG_LEVEL]
   int R = pdcch_pdu_rel15->InterleaverSize;
   int n_shift = pdcch_pdu_rel15->ShiftIndex;
 
-
   //Max number of candidates per aggregation level -- SIB1 configured search space only
 
-
   int n_rb,rb_offset;
 
   get_coreset_rballoc(pdcch_pdu_rel15->FreqDomainResource,&n_rb,&rb_offset);
 
-
-  int N_reg = n_rb;
-  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[d].AggregationLevel;
+    int dur = pdcch_pdu_rel15->DurationSymbols;
+    int N_regs = n_rb*dur; // nb of REGs per coreset
+    AssertFatal(N_regs > 0,"N_reg cannot be 0\n");
 
     if (pdcch_pdu_rel15->CoreSetType == NFAPI_NR_CSET_CONFIG_MIB_SIB1)
       AssertFatal(L>=4, "Invalid aggregation level for SIB1 configured PDCCH %d\n", L);
-    
+
+    int C = 0;
+
     if (pdcch_pdu_rel15->CceRegMappingType == NFAPI_NR_CCE_REG_MAPPING_INTERLEAVED) {
-      uint16_t assertFatalCond = (N_reg%(bsize*R));
-      AssertFatal(assertFatalCond == 0,"CCE to REG interleaving: Invalid configuration leading to non integer C (N_reg %us, bsize %d R %d)\n",N_reg, bsize, R);
-      C = N_reg/(bsize*R);
+      uint16_t assertFatalCond = (N_regs%(bsize*R));
+      AssertFatal(assertFatalCond == 0,"CCE to REG interleaving: Invalid configuration leading to non integer C (N_reg %us, bsize %d R %d)\n",N_regs, bsize, R);
+      C = N_regs/(bsize*R);
     }
-    
-    if (pdcch_pdu_rel15->dci_pdu[d].RNTI != 0xFFFF) LOG_D(PHY, "CCE list generation for candidate %d: bundle size %d ilv size %d CceIndex %d\n", m, bsize, R, pdcch_pdu_rel15->dci_pdu[d].CceIndex);
+
+    if (pdcch_pdu_rel15->dci_pdu[d].RNTI != 0xFFFF)
+      LOG_D(PHY, "CCE list generation for candidate %d: bundle size %d ilv size %d CceIndex %d\n", d, bsize, R, pdcch_pdu_rel15->dci_pdu[d].CceIndex);
+
     for (uint8_t cce_idx=0; cce_idx<L; cce_idx++) {
       cce = &cce_list[d][cce_idx];
       cce->cce_idx = pdcch_pdu_rel15->dci_pdu[d].CceIndex + cce_idx;
       LOG_D(PHY, "cce_idx %d\n", cce->cce_idx);
-      
-      if (pdcch_pdu_rel15->CceRegMappingType == NFAPI_NR_CCE_REG_MAPPING_INTERLEAVED) {
-	LOG_D(PHY, "Interleaved CCE to REG mapping\n");
-	uint8_t j = cce->cce_idx, j_prime;
-	uint8_t r,c,idx;
-	
-	for (uint8_t bundle_idx=0; bundle_idx<NR_NB_REG_PER_CCE/bsize; bundle_idx++) {
-	  j_prime = 6*j/bsize + bundle_idx;
-	  r = j_prime%R;
-	  c = (j_prime-r)/R;
-	  idx = (r*C + c + n_shift)%(N_reg/bsize);
-	  LOG_D(PHY, "bundle idx = %d \n j = %d \t j_prime = %d \t r = %d \t c = %d\n", idx, j , j_prime, r, c);
-	  
-	  for (uint8_t reg_idx=0; reg_idx<bsize; reg_idx++) {
-	    reg = &cce->reg_list[reg_idx];
-	    reg->reg_idx = bsize*idx + reg_idx;
-	    reg->start_sc_idx = reg->reg_idx * NR_NB_SC_PER_RB;
-	    reg->symb_idx = 0;
-	    LOG_D(PHY, "reg %d symbol %d start subcarrier %d\n", reg->reg_idx, reg->symb_idx, reg->start_sc_idx);
-	  }
-	}
-      }
-      else { // NFAPI_NR_CCE_REG_MAPPING_NON_INTERLEAVED
-	LOG_D(PHY, "Non interleaved CCE to REG mapping\n");
-	for (uint8_t reg_idx=0; reg_idx<NR_NB_REG_PER_CCE; reg_idx++) {
+
+      uint8_t j = cce->cce_idx;
+      for (int k=6*j/bsize; k<(6*j/bsize+6/bsize); k++) { // loop over REG bundles
+
+        int f = cce_to_reg_interleaving(R, k, n_shift, C, bsize, N_regs);
+
+	for (uint8_t reg_idx=0; reg_idx<bsize; reg_idx++) {
 	  reg = &cce->reg_list[reg_idx];
-	  reg->reg_idx = cce->cce_idx*NR_NB_REG_PER_CCE + reg_idx;
-	  reg->start_sc_idx = reg->reg_idx * NR_NB_SC_PER_RB;
-	  reg->symb_idx = 0;
+	  reg->reg_idx = bsize*f + reg_idx;
+	  reg->start_sc_idx = (reg->reg_idx/dur) * NR_NB_SC_PER_RB;
+	  reg->symb_idx = reg_idx%dur;
 	  LOG_D(PHY, "reg %d symbol %d start subcarrier %d\n", reg->reg_idx, reg->symb_idx, reg->start_sc_idx);
 	}
-	
       }
-      
     }
   }
 }
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
index 260bfbdfbc32d333da0e3af015e66c310700b61a..4b8315e1ce488b4f43dde0acfca721deb5bed1c0 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c
@@ -1963,6 +1963,17 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
       }
     }
   }
+
+  if (gNB->chest_time == 1) { // averaging time domain channel estimates
+    nr_chest_time_domain_avg(frame_parms,
+                             gNB->pusch_vars[ulsch_id]->ul_ch_estimates,
+                             rel15_ul->nr_of_symbols,
+                             rel15_ul->start_symbol_index,
+                             rel15_ul->ul_dmrs_symb_pos,
+                             rel15_ul->rb_size);
+
+    gNB->pusch_vars[ulsch_id]->dmrs_symbol = get_next_dmrs_symbol_in_slot(rel15_ul->ul_dmrs_symb_pos, rel15_ul->start_symbol_index, rel15_ul->nr_of_symbols);
+  }
   stop_meas(&gNB->ulsch_channel_estimation_stats);
 
 #ifdef __AVX2__
@@ -1978,7 +1989,8 @@ int nr_rx_pusch(PHY_VARS_gNB *gNB,
       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");
 
-      gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol;
+      if (gNB->chest_time == 0) // Non averaging time domain channel estimates
+        gNB->pusch_vars[ulsch_id]->dmrs_symbol = symbol;
 
       if (rel15_ul->dmrs_config_type == 0) {
         // if no data in dmrs cdm group is 1 only even REs have no data
diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
index 037851be0c388f218e7561e2252a1787ba79e4ad..082370dff49f8a4470bf9f9aa57c19d54aef9a86 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c
@@ -683,7 +683,7 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
   int ch_offset,symbol_offset;
 
   uint8_t nushift;
-  int **dl_ch_estimates  =ue->pdsch_vars[proc->thread_id][gNB_id]->dl_ch_estimates;
+  int **dl_ch_estimates = ue->pdsch_vars[proc->thread_id][gNB_id]->dl_ch_estimates;
   int **rxdataF=ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF;
 
   ch_offset     = ue->frame_parms.ofdm_symbol_size*symbol;
@@ -808,7 +808,7 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
     printf("rxF addr %p p %d\n", rxF,p);
     printf("dl_ch addr %p nushift %d\n",dl_ch,nushift);
 #endif
-    if (config_type == NFAPI_NR_DMRS_TYPE1 && ue->prb_interpolation == 0) {
+    if (config_type == NFAPI_NR_DMRS_TYPE1 && ue->chest_freq == 0) {
 
       // Treat first 2 pilots specially (left edge)
       ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15);
@@ -985,7 +985,7 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
                      8);
         }
       }
-    } else if (config_type == NFAPI_NR_DMRS_TYPE2 && ue->prb_interpolation == 0){ //pdsch_dmrs_type2  |dmrs_r,dmrs_l,0,0,0,0,dmrs_r,dmrs_l,0,0,0,0|
+    } else if (config_type == NFAPI_NR_DMRS_TYPE2 && ue->chest_freq == 0){ //pdsch_dmrs_type2  |dmrs_r,dmrs_l,0,0,0,0,dmrs_r,dmrs_l,0,0,0,0|
 
       // Treat first 4 pilots specially (left edge)
       ch_l[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15);
diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
index 336d388d40d794644f9774418bcbfe92399abd78..45eadd2c955f99efd579c6cecffc077d79a99b13 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
@@ -142,7 +142,8 @@ static void nr_pdcch_demapping_deinterleaving(uint32_t *llr,
 
   int B_rb = reg_bundle_size_L/coreset_time_dur; // nb of RBs occupied by each REG bundle
   int num_bundles_per_cce = 6/reg_bundle_size_L;
-  int max_bundles = NR_MAX_PDCCH_AGG_LEVEL*num_bundles_per_cce;
+  int n_cce = N_regs/6;
+  int max_bundles = n_cce*num_bundles_per_cce;
   int f_bundle_j_list[max_bundles];
 
   // for each bundle
@@ -359,10 +360,7 @@ void nr_pdcch_extract_rbs_single(int32_t **rxdataF,
    * According to this equations, DM-RS PDCCH are mapped on k where k%12==1 || k%12==5 || k%12==9
    *
    */
-  // the bitmap coreset_frq_domain contains 45 bits
-#define CORESET_FREQ_DOMAIN_BITMAP_SIZE   45
-  // each bit is associated to 6 RBs
-#define BIT_TO_NBR_RB_CORESET_FREQ_DOMAIN  6
+
 #define NBR_RE_PER_RB_WITH_DMRS           12
   // after removing the 3 DMRS RE, the RB contains 9 RE with PDCCH
 #define NBR_RE_PER_RB_WITHOUT_DMRS         9
@@ -686,9 +684,9 @@ int32_t nr_rx_pdcch(PHY_VARS_NR_UE *ue,
 
   // Pointers to extracted PDCCH symbols in frequency-domain.
   int32_t rx_size = 4*273*12;
-  int32_t rxdataF_ext[4*frame_parms->nb_antennas_rx][rx_size];
-  int32_t rxdataF_comp[4*frame_parms->nb_antennas_rx][rx_size];
-  int32_t pdcch_dl_ch_estimates_ext[4*frame_parms->nb_antennas_rx][rx_size];
+  __attribute__ ((aligned(32))) int32_t rxdataF_ext[4*frame_parms->nb_antennas_rx][rx_size];
+  __attribute__ ((aligned(32))) int32_t rxdataF_comp[4*frame_parms->nb_antennas_rx][rx_size];
+  __attribute__ ((aligned(32))) int32_t pdcch_dl_ch_estimates_ext[4*frame_parms->nb_antennas_rx][rx_size];
 
   // Pointer to llrs, 4-bit resolution.
   int32_t llr_size = 2*4*100*12;
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
index 14da6229394227872946c5cbedf544d85ffba3e0..19a680c6be90ebb3fc409984ae1bd74e2691d30a 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
@@ -319,7 +319,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                        dlsch0_harq->n_dmrs_cdm_groups,
                        dlsch0_harq->Nl,
                        frame_parms,
-                       dlsch0_harq->dlDmrsSymbPos);
+                       dlsch0_harq->dlDmrsSymbPos,
+                       ue->chest_time);
   stop_meas(&ue->generic_stat_bis[proc->thread_id][slot]);
   if (cpumeas(CPUMEAS_GETSTATE))
     LOG_D(PHY, "[AbsSFN %u.%d] Slot%d Symbol %d type %d: Pilot/Data extraction %5.2f \n",
@@ -1610,7 +1611,8 @@ unsigned short nr_dlsch_extract_rbs_single(int **rxdataF,
                                            unsigned short nb_rb_pdsch,
                                            uint8_t n_dmrs_cdm_groups,
                                            NR_DL_FRAME_PARMS *frame_parms,
-                                           uint16_t dlDmrsSymbPos)
+                                           uint16_t dlDmrsSymbPos,
+                                           int chest_time_type)
 {
   if (config_type == NFAPI_NR_DMRS_TYPE1) {
     AssertFatal(n_dmrs_cdm_groups == 1 || n_dmrs_cdm_groups == 2,
@@ -1621,7 +1623,12 @@ unsigned short nr_dlsch_extract_rbs_single(int **rxdataF,
   }
 
   const unsigned short start_re = (frame_parms->first_carrier_offset + start_rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;
-  const int8_t validDmrsEst     = get_valid_dmrs_idx_for_channel_est(dlDmrsSymbPos, symbol);
+  int8_t validDmrsEst;
+
+  if (chest_time_type == 0)
+    validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlDmrsSymbPos,symbol);
+  else
+    validDmrsEst = get_next_dmrs_symbol_in_slot(dlDmrsSymbPos,0,14); // get first dmrs symbol index
 
   for (unsigned char aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) {
 
@@ -1708,7 +1715,8 @@ void nr_dlsch_extract_rbs(int **rxdataF,
                           uint8_t n_dmrs_cdm_groups,
                           uint8_t Nl,
                           NR_DL_FRAME_PARMS *frame_parms,
-                          uint16_t dlDmrsSymbPos)
+                          uint16_t dlDmrsSymbPos,
+                          int chest_time_type)
 {
 
   unsigned short k,rb;
@@ -1726,7 +1734,10 @@ void nr_dlsch_extract_rbs(int **rxdataF,
     nushift = (n_dmrs_cdm_groups -1)<<1;//delta in Table 7.4.1.1.2-2
   }
 
-  validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlDmrsSymbPos,symbol);
+  if (chest_time_type == 0)
+    validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlDmrsSymbPos,symbol);
+  else
+    validDmrsEst = get_next_dmrs_symbol_in_slot(dlDmrsSymbPos,0,14); // get first dmrs symbol index
 
   for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
index 48b08d761ece8f76e29eb3f1e737f8a686ac4393..78e4a8a4e811ad7a1609ac3e2d231a365e7e661e 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
@@ -430,8 +430,8 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
 
   for (symbol=1; symbol<4; symbol++) {
     const uint16_t nb_re=symbol == 2 ? 72 : 180;
-    struct complex16 rxdataF_ext[frame_parms->nb_antennas_rx][PBCH_MAX_RE_PER_SYMBOL];
-    struct complex16 dl_ch_estimates_ext[frame_parms->nb_antennas_rx][PBCH_MAX_RE_PER_SYMBOL];
+    __attribute__ ((aligned(32))) struct complex16 rxdataF_ext[frame_parms->nb_antennas_rx][PBCH_MAX_RE_PER_SYMBOL];
+    __attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_ext[frame_parms->nb_antennas_rx][PBCH_MAX_RE_PER_SYMBOL];
     memset(dl_ch_estimates_ext,0, sizeof  dl_ch_estimates_ext);
     nr_pbch_extract(nr_ue_common_vars->common_vars_rx_data_per_thread[proc->thread_id].rxdataF,
                     estimateSz,
@@ -456,7 +456,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
 #ifdef DEBUG_PBCH
     LOG_I(PHY,"[PHY] PBCH log2_maxh = %d (%d)\n",nr_ue_pbch_vars->log2_maxh,max_h);
 #endif
-    struct complex16 rxdataF_comp[frame_parms->nb_antennas_rx][PBCH_MAX_RE_PER_SYMBOL];
+    __attribute__ ((aligned(32))) struct complex16 rxdataF_comp[frame_parms->nb_antennas_rx][PBCH_MAX_RE_PER_SYMBOL];
     nr_pbch_channel_compensation(rxdataF_ext,
                                  dl_ch_estimates_ext,
                                  nb_re,
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 b38caa680478c71e617e6dd0523cc3787552c126..30bc0ffe9203fd1e5d0b07f2fbbf4884c254e63c 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
@@ -709,7 +709,8 @@ unsigned short nr_dlsch_extract_rbs_single(int **rxdataF,
                                         unsigned short nb_rb_pdsch,
                                         uint8_t n_dmrs_cdm_groups,
                                         NR_DL_FRAME_PARMS *frame_parms,
-                                        uint16_t dlDmrsSymbPos);
+                                        uint16_t dlDmrsSymbPos,
+                                        int chest_time_type);
 
 /** \fn dlsch_extract_rbs_multiple(int32_t **rxdataF,
     int32_t **dl_ch_estimates,
@@ -747,7 +748,8 @@ void nr_dlsch_extract_rbs(int **rxdataF,
                                         uint8_t n_dmrs_cdm_groups,
                                         uint8_t Nl,
                                         NR_DL_FRAME_PARMS *frame_parms,
-                                        uint16_t dlDmrsSymbPos);
+                                        uint16_t dlDmrsSymbPos,
+                                        int chest_time_type);
 
 /** \fn dlsch_extract_rbs_TM7(int32_t **rxdataF,
     int32_t **dl_bf_ch_estimates,
diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h
index ace4cf120b3ec87d51104365b5a142c477c9bb3e..f805aec552a5b5a42e3c07fd6dd979a608c849f2 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -826,7 +826,11 @@ typedef struct PHY_VARS_gNB_s {
   int              **dl_precoder_SgNB[3];
   char             log2_maxp; /// holds the maximum channel/precoder coefficient
 
-  int  prb_interpolation;
+  int max_ldpc_iterations;
+  /// indicate the channel estimation technique in time domain
+  int chest_time;
+  /// indicate the channel estimation technique in freq domain
+  int chest_freq;
 
   /// if ==0 enables phy only test mode
   int mac_enabled;
diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h
index 259367a994f69f408be9520bea8bee4db695a9b9..8ba87b7a67aa790539fb502891d83ff9204c0a08 100644
--- a/openair1/PHY/defs_nr_UE.h
+++ b/openair1/PHY/defs_nr_UE.h
@@ -777,7 +777,8 @@ typedef struct {
   uint32_t perfect_ce;
   // flag to activate PRB based averaging of channel estimates
   // when off, defaults to frequency domain interpolation
-  int prb_interpolation;
+  int chest_freq;
+  int chest_time;
   int generate_ul_signal[NUMBER_OF_CONNECTED_gNB_MAX];
 
   UE_NR_SCAN_INFO_t scan_info[NB_BANDS_MAX];
@@ -865,6 +866,8 @@ typedef struct {
   /// N0 (used for abstraction)
   double N0;
 
+  uint8_t max_ldpc_iterations;
+
   /// PDSCH Varaibles
   PDSCH_CONFIG_DEDICATED pdsch_config_dedicated[NUMBER_OF_CONNECTED_gNB_MAX];
 
diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
index 9c607cb8b794dc963c8eca41242a0111add1d5e1..0d54caceb3c26f503996903deeb9f6af76b4d181 100644
--- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c
+++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
@@ -793,10 +793,14 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) {
                    dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot),
                    dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot),gNB->pusch_thres);
              gNB->pusch_vars[ULSCH_id]->ulsch_power_tot = gNB->pusch_vars[ULSCH_id]->ulsch_noise_power_tot;
-             nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1);
              gNB->pusch_vars[ULSCH_id]->DTX=1;
              if (stats) stats->DTX++;
-             return 1;
+             if (!get_softmodem_params()->phy_test) {
+               /* in case of phy_test mode, we still want to decode to measure execution time. 
+                  Therefore, we don't yet call nr_fill_indication, it will be called later */
+               nr_fill_indication(gNB,frame_rx, slot_rx, ULSCH_id, harq_pid, 1,1);
+               return 1;
+             }
           } else {
             LOG_D(PHY, "PUSCH detected in %d.%d (%d,%d,%d)\n",frame_rx,slot_rx,
                   dB_fixed_x10(gNB->pusch_vars[ULSCH_id]->ulsch_power_tot),
@@ -856,10 +860,6 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) {
   }
 
   stop_meas(&gNB->phy_proc_rx);
-  // 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) {
-    LOG_I(NR_PHY, "Number of bad PUCCH received: %lu\n", gNB->bad_pucch);
-  }
 
   if (pucch_decode_done || pusch_decode_done) {
     T(T_GNB_PHY_PUCCH_PUSCH_IQ, T_INT(frame_rx), T_INT(slot_rx), T_BUFFER(&gNB->common_vars.rxdataF[0][0], gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size * 4));
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index d522271a60f1067d2d28055b25a56fd02834edca..739f6010d48dc326425a8c46a4f1cf7338a17b55 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -36,6 +36,7 @@
 #include "assertions.h"
 #include "defs.h"
 #include "PHY/defs_nr_UE.h"
+#include "PHY/NR_REFSIG/dmrs_nr.h"
 #include "PHY/phy_extern_nr_ue.h"
 #include "PHY/MODULATION/modulation_UE.h"
 #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h"
@@ -615,6 +616,15 @@ int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, int gNB_
       }
     }
 
+    if (ue->chest_time == 1) { // averaging time domain channel estimates
+      nr_chest_time_domain_avg(&ue->frame_parms,
+                               ue->pdsch_vars[proc->thread_id][gNB_id]->dl_ch_estimates,
+                               dlsch0_harq->nb_symbols,
+                               dlsch0_harq->start_symbol,
+                               dlsch0_harq->dlDmrsSymbPos,
+                               pdsch_nb_rb);
+    }
+
     uint16_t first_symbol_with_data = s0;
     uint32_t dmrs_data_re;
 
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index 99236c9a43cc9f3a2c3cad1737cb00fe64e71fe3..bab67e442616fb2b4d2bf060a2e151d74f78ab73 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -66,6 +66,7 @@
 #include "NR_RRCReconfiguration.h"
 #define inMicroS(a) (((double)(a))/(get_cpu_freq_GHz()*1000.0))
 #include "SIMULATION/LTE_PHY/common_sim.h"
+#include "PHY/NR_REFSIG/dmrs_nr.h"
 
 #include <openair2/LAYER2/MAC/mac_vars.h>
 #include <openair2/RRC/LTE/rrc_vars.h>
@@ -263,26 +264,35 @@ void update_ptrs_config(NR_CellGroupConfig_t *secondaryCellGroup, uint16_t *rbSi
 void update_dmrs_config(NR_CellGroupConfig_t *scg, int8_t* dmrs_arg);
 extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration
 
-/* specific dlsim DL preprocessor: uses rbStart/rbSize/mcs/nrOfLayers from command line of
-   dlsim, does not search for CCE/PUCCH occasion but simply sets to 0 */
+/* specific dlsim DL preprocessor: uses rbStart/rbSize/mcs/nrOfLayers from command line of dlsim */
 int g_mcsIndex = -1, g_mcsTableIdx = 0, g_rbStart = -1, g_rbSize = -1, g_nrOfLayers = 1;
 void nr_dlsim_preprocessor(module_id_t module_id,
                            frame_t frame,
                            sub_frame_t slot) {
+
   NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.list[0];
   AssertFatal(RC.nrmac[module_id]->UE_info.list[1]==NULL, "can have only a single UE\n");
   NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl;
   NR_ServingCellConfigCommon_t *scc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon;
 
-  /* manually set free CCE to 0 */
   const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
   sched_ctrl->search_space = get_searchspace(NULL, scc, sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Dedicated : NULL, target_ss);
   uint8_t nr_of_candidates;
   find_aggregation_candidates(&sched_ctrl->aggregation_level,
                               &nr_of_candidates,
                               sched_ctrl->search_space,4);
+
   sched_ctrl->coreset = get_coreset(RC.nrmac[module_id], scc, sched_ctrl->active_bwp->bwp_Dedicated, sched_ctrl->search_space, target_ss);
-  sched_ctrl->cce_index = 0;
+  uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE_info->rnti);
+  int CCEIndex = find_pdcch_candidate(RC.nrmac[module_id],
+                                      /* CC_id = */ 0,
+                                      sched_ctrl->aggregation_level,
+                                      nr_of_candidates,
+                                      &sched_ctrl->sched_pdcch,
+                                      sched_ctrl->coreset,
+                                      Y);
+  AssertFatal(CCEIndex>=0, "%4d.%2d could not find CCE for DL DCI UE %d/RNTI %04x\n", frame, slot, 0, UE_info->rnti);
+  sched_ctrl->cce_index = CCEIndex;
 
   NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static;
 
@@ -434,7 +444,8 @@ int main(int argc, char **argv)
   uint16_t rbSize = 106;
   uint8_t  mcsIndex = 9;
   uint8_t  dlsch_threads = 0;
-  int      prb_inter = 0;
+  int      chest_type[2] = {0};
+  uint8_t  max_ldpc_iterations = 5;
   if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0) {
     exit_fun("[NR_DLSIM] Error, configuration module init failed\n");
   }
@@ -445,7 +456,7 @@ int main(int argc, char **argv)
 
   FILE *scg_fd=NULL;
   
-  while ((c = getopt (argc, argv, "f:hA:pf:g:in:s:S:t:x:y:z:M:N:F:GR:dPIL:Ea:b:d:e:q:m:w:T:U:X:")) != -1) {
+  while ((c = getopt (argc, argv, "f:hA:pf:g:i:n:s:S:t:x:y:z:M:N:F:GR:dPI:L:Ea:b:d:e:m:w:T:U:q:X:Y")) != -1) {
     switch (c) {
     case 'f':
       scg_fd = fopen(optarg,"r");
@@ -502,7 +513,9 @@ int main(int argc, char **argv)
       break;
 
     case 'i':
-      prb_inter=1;
+      for(i=0; i < atoi(optarg); i++){
+        chest_type[i] = atoi(argv[optind++]);
+      }
       break;
 
     case 'n':
@@ -589,9 +602,7 @@ int main(int argc, char **argv)
       break;
       
     case 'I':
-      run_initial_sync=1;
-      //target_error_rate=0.1;
-      slot = 0;
+      max_ldpc_iterations = atoi(optarg);
       break;
 
     case 'L':
@@ -655,6 +666,12 @@ int main(int argc, char **argv)
       gNBthreads[sizeof(gNBthreads)-1]=0;
       break;
 
+    case 'Y':
+      run_initial_sync=1;
+      //target_error_rate=0.1;
+      slot = 0;
+      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 -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",
@@ -670,7 +687,7 @@ int main(int argc, char **argv)
       printf("-g [A,B,C,D,E,F,G,R] Use 3GPP SCM (A,B,C,D) or 36-101 (E-EPA,F-EVA,G-ETU) models or R for MIMO model (ignores delay spread and Ricean factor)\n");
       printf("-y Number of TX antennas used in gNB\n");
       printf("-z Number of RX antennas used in UE\n");
-      printf("-i Activate PRB based averaging for channel estimation. Frequncy domain interpolation by default.\n");
+      printf("-i Change channel estimation technique. Arguments list: Frequency domain {0:Linear interpolation, 1:PRB based averaging}, Time domain {0:Estimates of last DMRS symbol, 1:Average of DMRS symbols}\n");
       //printf("-j Relative strength of second intefering gNB (in dB) - cell_id mod 3 = 2\n");
       printf("-R N_RB_DL\n");
       printf("-O oversampling factor (1,2,4,8,16)\n");
@@ -687,12 +704,14 @@ int main(int argc, char **argv)
       printf("-e MSC index\n");
       printf("-q MCS Table index\n");
       printf("-t Acceptable effective throughput (in percentage)\n");
+      printf("-I Maximum LDPC decoder iterations\n");
       printf("-T Enable PTRS, arguments list L_PTRS{0,1,2} K_PTRS{2,4}, e.g. -T 2 0 2 \n");
       printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:2} DMRS ConfType{1:2}, e.g. -U 3 0 2 1 \n");
       printf("-P Print DLSCH performances\n");
       printf("-w Write txdata to binary file (one frame)\n");
       printf("-d number of dlsch threads, 0: no dlsch parallelization\n");
-      printf("-X gNB thread pool configuration, n => no threads");
+      printf("-X gNB thread pool configuration, n => no threads\n");
+      printf("-Y Run initial sync in UE\n");
       exit (-1);
       break;
     }
@@ -948,6 +967,7 @@ int main(int argc, char **argv)
   PHY_vars_UE_g[0][0] = UE;
   memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
   UE->frame_parms.nb_antennas_rx = n_rx;
+  UE->max_ldpc_iterations = max_ldpc_iterations;
 
   if (run_initial_sync==1)  UE->is_synchronized = 0;
   else                      {UE->is_synchronized = 1; UE->UE_mode[0]=PUSCH;}
@@ -982,8 +1002,8 @@ int main(int argc, char **argv)
   UE->if_inst->phy_config_request = nr_ue_phy_config_request;
   UE->if_inst->dl_indication = nr_ue_dl_indication;
   UE->if_inst->ul_indication = dummy_nr_ue_ul_indication;
-  UE->prb_interpolation = prb_inter;
-
+  UE->chest_freq = chest_type[0];
+  UE->chest_time = chest_type[1];
 
   UE_mac->if_module = nr_ue_if_module_init(0);
 
@@ -1103,14 +1123,9 @@ int main(int argc, char **argv)
       while ((round<num_rounds) && (UE_harq_process->ack==0)) {
 
         clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot);
-
         UE_info->UE_sched_ctrl.harq_processes[harq_pid].ndi = !(trial&1);
-
-
         UE_info->UE_sched_ctrl.harq_processes[harq_pid].round = round;
-        for (int i=0; i<MAX_NUM_CORESET; i++)
-          gNB_mac->pdcch_cand[i] = 0;
-      
+
         if (css_flag == 0) {
           nr_schedule_ue_spec(0, frame, slot);
         } else {
diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c
index 8a0a2d51441b383715a3ebae1f968b3b639025f3..5392424285729463be925948ee877d336209cc7d 100644
--- a/openair1/SIMULATION/NR_PHY/ulschsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulschsim.c
@@ -141,6 +141,7 @@ int main(int argc, char **argv)
   uint16_t nb_rb = 50;
   uint8_t Imcs = 9;
   uint8_t Nl = 1;
+  uint8_t max_ldpc_iterations = 5;
 
   double DS_TDL = .03;
 
@@ -395,6 +396,8 @@ int main(int argc, char **argv)
   frame_parms->N_RB_DL = N_RB_DL;
   frame_parms->N_RB_UL = N_RB_UL;
   frame_parms->Ncp = extended_prefix_flag ? EXTENDED : NORMAL;
+  gNB->max_ldpc_iterations = max_ldpc_iterations;
+
   crcTableInit();
 
   memcpy(&gNB->frame_parms, frame_parms, sizeof(NR_DL_FRAME_PARMS));
diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c
index 9a3b29a637588485547a82027df24a76e7349b14..2a3730c1d4695bc556a01bca018558c69e847461 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -312,16 +312,15 @@ int main(int argc, char **argv)
   float roundStats[100];
   double effRate[100]; 
   double effTP[100]; 
-  float eff_tp_check = 0.7;
+  float eff_tp_check = 100;
   uint8_t snrRun;
-  int prb_inter = 0;
+  int chest_type[2] = {0};
 
   int enable_ptrs = 0;
   int modify_dmrs = 0;
   /* L_PTRS = ptrs_arg[0], K_PTRS = ptrs_arg[1] */
   int ptrs_arg[2] = {-1,-1};// Invalid values
-  /* mapping type = dmrs_arg[0], Add Pos = dmrs_arg[1], dmrs config type = dmrs_arg[2] */
-  int dmrs_arg[3] = {-1,-1,-1};// Invalid values
+  int dmrs_arg[4] = {-1,-1,-1,-1};// Invalid values
   uint16_t ptrsSymPos = 0;
   uint16_t ptrsSymbPerSlot = 0;
   uint16_t ptrsRePerSymb = 0;
@@ -338,6 +337,7 @@ int main(int argc, char **argv)
   int ibwps=24;
   int ibwp_rboffset=41;
   int params_from_file = 0;
+  int max_ldpc_iterations = 5;
   if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0 ) {
     exit_fun("[NR_ULSIM] Error, configuration module init failed\n");
   }
@@ -348,7 +348,7 @@ int main(int argc, char **argv)
   /* initialize the sin-cos table */
    InitSinLUT();
 
-  while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:ikl:m:n:p:r:s:t:u:w:y:z:F:G:H:M:N:PR:S:T:U:L:Z:W:")) != -1) {
+  while ((c = getopt(argc, argv, "a:b:c:d:ef:g:h:i:kl:m:n:p:q:r:s:t:u:w:y:z:F:G:H:I:M:N:PR:S:T:U:L:ZW:")) != -1) {
     printf("handling optarg %c\n",c);
     switch (c) {
 
@@ -441,7 +441,9 @@ int main(int argc, char **argv)
       break;
       
     case 'i':
-      prb_inter=1;
+      for(i=0; i < atoi(optarg); i++){
+        chest_type[i] = atoi(argv[optind++]);
+      }
       break;
 	
     case 'k':
@@ -468,6 +470,10 @@ int main(int argc, char **argv)
     case 'p':
       extended_prefix_flag = 1;
       break;
+
+    case 'q':
+      mcs_table = atoi(optarg);
+      break;
       
     case 'r':
       nb_rb = atoi(optarg);
@@ -487,7 +493,7 @@ int main(int argc, char **argv)
       break;
 
     case 't':
-      eff_tp_check = (float)atoi(optarg)/100;
+      eff_tp_check = (float)atoi(optarg);
       break;
 
       /*
@@ -519,7 +525,7 @@ int main(int argc, char **argv)
         exit(-1);
       }
       break;
-      
+
     case 'F':
       input_fd = fopen(optarg, "r");
       if (input_fd == NULL) {
@@ -536,6 +542,10 @@ int main(int argc, char **argv)
       slot = atoi(optarg);
       break;
 
+    case 'I':
+      max_ldpc_iterations = atoi(optarg);
+      break;
+
     case 'M':
      // SSB_positions = atoi(optarg);
       break;
@@ -597,13 +607,14 @@ int main(int argc, char **argv)
       printf("-f Number of frames to simulate\n");
       printf("-g [A,B,C,D,E,F,G] Use 3GPP SCM (A,B,C,D) or 36-101 (E-EPA,F-EVA,G-ETU) models (ignores delay spread and Ricean factor)\n");
       printf("-h This message\n");
-      printf("-i Activate PRB based averaging for channel estimation. Frequncy domain interpolation by default.\n");
+      printf("-i Change channel estimation technique. Arguments list: Number of arguments=2, Frequency domain {0:Linear interpolation, 1:PRB based averaging}, Time domain {0:Estimates of last DMRS symbol, 1:Average of DMRS symbols}. e.g. -i 2 1 0\n");
       //printf("-j Relative strength of second intefering eNB (in dB) - cell_id mod 3 = 2\n");
       printf("-s Starting SNR, runs from SNR0 to SNR0 + 10 dB if ending SNR isn't given\n");
       printf("-m MCS value\n");
       printf("-n Number of trials to simulate\n");
       printf("-p Use extended prefix mode\n");
-      //printf("-t Delay spread for multipath channel\n");
+      printf("-q MCS table\n");
+      printf("-t Delay spread for multipath channel\n");
       printf("-u Set the numerology\n");
       printf("-w Start PRB for PUSCH\n");
       //printf("-x Transmission mode (1,2,6 for the moment)\n");
@@ -613,7 +624,8 @@ int main(int argc, char **argv)
       //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n");
       printf("-F Input filename (.txt format) for RX conformance testing\n");
       printf("-G Offset of samples to read from file (0 default)\n");
-      printf("-L <log level, 0(errors), 1(warning), 2(info) 3(debug) 4 (trace)>\n");
+      printf("-L <log level, 0(errors), 1(warning), 2(info) 3(debug) 4 (trace)>\n"); 
+      printf("-I Maximum LDPC decoder iterations\n");
       printf("-M Multiple SSB positions in burst\n");
       printf("-N Nid_cell\n");
       printf("-O oversampling factor (1,2,4,8,16)\n");
@@ -621,8 +633,8 @@ int main(int argc, char **argv)
       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");
-      printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:3}, e.g. -U 2 0 2 \n");
+      printf("-T Enable PTRS, arguments list: Number of arguments=2 L_PTRS{0,1,2} K_PTRS{2,4}, e.g. -T 2 0 2 \n");
+      printf("-U Change DMRS Config, arguments list: Number of arguments=4, DMRS Mapping Type{0=A,1=B}, DMRS AddPos{0:3}, DMRS Config Type{1,2}, Number of CDM groups without data{1,2,3} e.g. -U 4 0 2 0 1 \n");
       printf("-Q If -F used, read parameters from file\n");
       printf("-Z If -Z is used, SC-FDMA or transform precoding is enabled in Uplink \n");
       printf("-W Num of layer for PUSCH\n");
@@ -717,7 +729,7 @@ int main(int argc, char **argv)
   gNB->UL_INFO.crc_ind.crc_list = (nfapi_nr_crc_t *)malloc(NB_UE_INST*sizeof(nfapi_nr_crc_t));
   gNB->UL_INFO.rx_ind.number_of_pdus = 0;
   gNB->UL_INFO.crc_ind.number_crcs = 0;
-  gNB->prb_interpolation = prb_inter;
+  gNB->max_ldpc_iterations = max_ldpc_iterations;
   frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
 
   frame_parms->N_RB_DL = N_RB_DL;
@@ -781,6 +793,8 @@ int main(int argc, char **argv)
   cfg->carrier_config.num_tx_ant.value = 1;
   cfg->carrier_config.num_rx_ant.value = n_rx;
 //  nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,0,0x01);
+  gNB->chest_freq = chest_type[0];
+  gNB->chest_time = chest_type[1];
   phy_init_nr_gNB(gNB,0,1);
   N_RB_DL = gNB->frame_parms.N_RB_DL;
 
@@ -796,7 +810,7 @@ int main(int argc, char **argv)
   PHY_vars_UE_g[0][0] = UE;
   memcpy(&UE->frame_parms, frame_parms, sizeof(NR_DL_FRAME_PARMS));
   UE->frame_parms.nb_antennas_tx = n_tx;
-  UE->frame_parms.nb_antennas_rx = 1;
+  UE->frame_parms.nb_antennas_rx = 0;
 
   if (init_nr_ue_signal(UE, 1) != 0) {
     printf("Error at UE NR initialisation\n");
@@ -895,6 +909,7 @@ int main(int argc, char **argv)
       dmrs_config_type = pusch_dmrs_type1;
     else if(dmrs_arg[2] == 2)
       dmrs_config_type = pusch_dmrs_type2;
+    num_dmrs_cdm_grps_no_data = dmrs_arg[3];
   }
 
   uint8_t  length_dmrs         = pusch_len1;
@@ -983,7 +998,6 @@ int main(int argc, char **argv)
   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);
   
@@ -1011,18 +1025,21 @@ int main(int argc, char **argv)
       printf("harq_pid %d\n",harq_pid);
     }
     fseek(input_fd,file_offset*sizeof(int16_t)*2,SEEK_SET);
-    read_errors+=fread((void*)&gNB->common_vars.rxdata[0][slot_offset-delay],
-    sizeof(int16_t),
-    slot_length<<1,
-    input_fd);
-    if (read_errors==0) {
-      printf("error reading file\n");
-      exit(1);
+    for (int irx=0; irx<frame_parms->nb_antennas_rx; irx++) {
+      fseek(input_fd,irx*(slot_length+15)*sizeof(int16_t)*2,SEEK_SET); // matlab adds samlples to the end to emulate channel delay
+      read_errors+=fread((void*)&gNB->common_vars.rxdata[irx][slot_offset-delay],
+      sizeof(int16_t),
+      slot_length<<1,
+      input_fd);
+      if (read_errors==0) {
+        printf("error reading file\n");
+        exit(1);
+      }
+      for (int i=0;i<16;i+=2) printf("slot_offset %d : %d,%d\n",
+             slot_offset,
+             ((int16_t*)&gNB->common_vars.rxdata[irx][slot_offset])[i],
+             ((int16_t*)&gNB->common_vars.rxdata[irx][slot_offset])[1+i]);
     }
-    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]);
 
     mod_order = nr_get_Qm_ul(Imcs, mcs_table);
     code_rate = nr_get_code_rate_ul(Imcs, mcs_table);
@@ -1389,11 +1406,11 @@ int main(int argc, char **argv)
             &gNB->pusch_vars[0]->llr_layers[0][0],(nb_symb_sch-1)*NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,1,0);
 
       if (precod_nbr_layers==2) {
-         LOG_M("rxsigF1_ext.m","rxsF1_ext",
-            &gNB->pusch_vars[0]->rxdataF_ext[1][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("rxsigF1_ext.m","rxsF1_ext",
+             &gNB->pusch_vars[0]->rxdataF_ext[1][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("chestF3.m","chF3",
-            &gNB->pusch_vars[0]->ul_ch_estimates[3][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1);
+             &gNB->pusch_vars[0]->ul_ch_estimates[3][start_symbol*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1);
 
         LOG_M("chestF3_ext.m","chF3_ext",
         &gNB->pusch_vars[0]->ul_ch_estimates_ext[3][(start_symbol+1)*(off+(NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
@@ -1553,7 +1570,12 @@ int main(int argc, char **argv)
 	   roundStats[snrRun],effRate[snrRun],effTP[snrRun],TBS);
 
     FILE *fd=fopen("nr_ulsim.log","w");
+    if (fd == NULL) {
+      printf("Problem with filename %s\n", "nr_ulsim.log");
+      exit(-1);
+    }
     dump_pusch_stats(fd,gNB);
+    fclose(fd);
 
     printf("*****************************************\n");
     printf("\n");
@@ -1583,7 +1605,7 @@ int main(int argc, char **argv)
     if(n_trials==1)
       break;
 
-    if (effRate[snrRun] > (eff_tp_check*TBS)) {
+    if ((float)effTP[snrRun] >= eff_tp_check) {
       printf("*************\n");
       printf("PUSCH test OK\n");
       printf("*************\n");
@@ -1613,17 +1635,19 @@ int main(int argc, char **argv)
           length_dmrs,
           num_dmrs_cdm_grps_no_data);
               
-  LOG_M("ulsimStats.m","SNR",snrStats,snrRun,1,7);
-  LOG_MM("ulsimStats.m","BLER_round0",blerStats[0],snrRun,1,7);
-  LOG_MM("ulsimStats.m","BLER_round1",blerStats[1],snrRun,1,7);
-  LOG_MM("ulsimStats.m","BLER_round2",blerStats[2],snrRun,1,7);
-  LOG_MM("ulsimStats.m","BLER_round3",blerStats[3],snrRun,1,7);
-  LOG_MM("ulsimStats.m","BER_round0",berStats[0],snrRun,1,7);
-  LOG_MM("ulsimStats.m","BER_round1",berStats[1],snrRun,1,7);
-  LOG_MM("ulsimStats.m","BER_round2",berStats[2],snrRun,1,7);
-  LOG_MM("ulsimStats.m","BER_round3",berStats[3],snrRun,1,7);
-  LOG_MM("ulsimStats.m","EffRate",effRate,snrRun,1,7);
-  LOG_MM("ulsimStats.m","EffTP",effTP,snrRun,1,7);
+  char opStatsFile[50];
+  sprintf(opStatsFile, "ulsimStats_z%d.m", n_rx);
+  LOG_M(opStatsFile,"SNR",snrStats,snrRun,1,7);
+  LOG_MM(opStatsFile,"BLER_round0",blerStats[0],snrRun,1,7);
+  LOG_MM(opStatsFile,"BLER_round1",blerStats[1],snrRun,1,7);
+  LOG_MM(opStatsFile,"BLER_round2",blerStats[2],snrRun,1,7);
+  LOG_MM(opStatsFile,"BLER_round3",blerStats[3],snrRun,1,7);
+  LOG_MM(opStatsFile,"BER_round0",berStats[0],snrRun,1,7);
+  LOG_MM(opStatsFile,"BER_round1",berStats[1],snrRun,1,7);
+  LOG_MM(opStatsFile,"BER_round2",berStats[2],snrRun,1,7);
+  LOG_MM(opStatsFile,"BER_round3",berStats[3],snrRun,1,7);
+  LOG_MM(opStatsFile,"EffRate",effRate,snrRun,1,7);
+  LOG_MM(opStatsFile,"EffTP",effTP,snrRun,1,7);
   free(test_input_bit);
   free(estimated_output_bit);
 
diff --git a/openair2/GNB_APP/L1_nr_paramdef.h b/openair2/GNB_APP/L1_nr_paramdef.h
index 90cd9aae2900054567423a3bcadc822b7c6eedab..1e5122956e0a4532ec79bff7b6083a5b1ed7cdcc 100644
--- a/openair2/GNB_APP/L1_nr_paramdef.h
+++ b/openair2/GNB_APP/L1_nr_paramdef.h
@@ -51,6 +51,7 @@
 #define CONFIG_STRING_L1_PUCCH0_DTX_THRESHOLD              "pucch0_dtx_threshold"
 #define CONFIG_STRING_L1_PRACH_DTX_THRESHOLD               "prach_dtx_threshold"
 #define CONFIG_STRING_L1_PUSCH_DTX_THRESHOLD               "pusch_dtx_threshold"
+#define CONFIG_STRING_L1_MAX_LDPC_ITERATIONS               "max_ldpc_iterations"
 /*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 /*                                            L1 configuration parameters                                                                             */
 /*   optname                                         helpstr   paramflags    XXXptr              defXXXval                  type           numelt     */
@@ -69,7 +70,8 @@
 {CONFIG_STRING_L1_OFDM_OFFSET_DIVISOR,               NULL,      0,         uptr:NULL,           defuintval:8,              TYPE_UINT,     0},         \
 {CONFIG_STRING_L1_PUCCH0_DTX_THRESHOLD,              NULL,      0,         uptr:NULL,           defintval:100,             TYPE_UINT,     0},         \
 {CONFIG_STRING_L1_PRACH_DTX_THRESHOLD,               NULL,      0,         uptr:NULL,           defintval:150,             TYPE_UINT,     0},         \
-{CONFIG_STRING_L1_PUSCH_DTX_THRESHOLD,               NULL,      0,         uptr:NULL,           defintval:50,              TYPE_UINT,     0}          \
+{CONFIG_STRING_L1_PUSCH_DTX_THRESHOLD,               NULL,      0,         uptr:NULL,           defintval:50,              TYPE_UINT,     0},         \
+{CONFIG_STRING_L1_MAX_LDPC_ITERATIONS,               NULL,      0,         uptr:NULL,           defintval:5,               TYPE_UINT,     0},          \
 }
 #define L1_CC_IDX                                          0
 #define L1_TRANSPORT_N_PREFERENCE_IDX                      1
@@ -85,6 +87,7 @@
 #define L1_PUCCH0_DTX_THRESHOLD                            11
 #define L1_PRACH_DTX_THRESHOLD                             12
 #define L1_PUSCH_DTX_THRESHOLD                             13
+#define L1_MAX_LDPC_ITERATIONS                             14
 
 /*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 #endif
diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c
index 6ceab3b97d1ea0fb7fad61d2004e5ca403a19d14..21655a74d52e9975eb605578b9cde94309669319 100644
--- a/openair2/GNB_APP/gnb_config.c
+++ b/openair2/GNB_APP/gnb_config.c
@@ -727,6 +727,7 @@ void RCconfig_NR_L1(void) {
       RC.gNB[j]->pucch0_thres       = *(L1_ParamList.paramarray[j][L1_PUCCH0_DTX_THRESHOLD].uptr);
       RC.gNB[j]->prach_thres        = *(L1_ParamList.paramarray[j][L1_PRACH_DTX_THRESHOLD].uptr);
       RC.gNB[j]->pusch_thres        = *(L1_ParamList.paramarray[j][L1_PUSCH_DTX_THRESHOLD].uptr);
+      RC.gNB[j]->max_ldpc_iterations = *(L1_ParamList.paramarray[j][L1_MAX_LDPC_ITERATIONS].uptr);
       RC.gNB[j]->num_ulprbbl        = num_prbbl;
       RC.gNB[j]->ap_N1              = N1;
       RC.gNB[j]->ap_N2              = N2;
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
index 217f9d74a793ea1de5f26bf599ec78d8c9a6dad8..e2a7efcaa0559f5f15b10e5703455b9e1b8662cb 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
@@ -3498,6 +3498,22 @@ void csi_period_offset(NR_CSI_ReportConfig_t *csirep,
   }
 }
 
+uint32_t get_Y(NR_SearchSpace_t *ss, int slot, rnti_t rnti) {
+
+  if(ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common)
+    return 0;
+
+  const int cid = *ss->controlResourceSetId%3;
+  const uint32_t A[3] = {39827, 39829, 39839};
+  const uint32_t D = 65537;
+  uint32_t Y;
+
+  Y = (A[cid] * rnti) % D;
+  for (int s = 0; s < slot; s++)
+    Y = (A[cid] * Y) % D;
+
+  return Y;
+}
 
 void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config,
                                            frame_t frameP,
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
index 102e56ee57907bd9292ec10fc35848f6e00beaa0..2b8d3c6652770bb5df056a1d3c77319f096d2b91 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
@@ -37,6 +37,8 @@
 #include "nr_mac.h"
 #include "openair1/PHY/impl_defs_nr.h"
 
+uint32_t get_Y(NR_SearchSpace_t *ss, int slot, rnti_t rnti);
+
 uint64_t from_nrarfcn(int nr_bandP, uint8_t scs_index, uint32_t dl_nrarfcn);
 
 uint32_t to_nrarfcn(int nr_bandP, uint64_t dl_CarrierFreq, uint8_t scs_index, uint32_t bw);
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
index f7a21cd80c584b23b558896ce512e6c84c8d0fe6..da39d3e0ed68ccefcaf789b4caa289360bb7007c 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
@@ -563,7 +563,6 @@ typedef struct ssb_list_info {
 } ssb_list_info_t;
 
 void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, fapi_nr_dl_config_request_t *dl_config, int rnti_type, int ss_id);
-void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15);
 
 /*@}*/
 #endif /*__LAYER2_MAC_DEFS_H__ */
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
index 6ff2c78efbd443af5615ec4d56affd190e45c5b7..01673c22d6f5956744d5b035b792c33782ef7f5e 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
@@ -250,10 +250,7 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce,
                           uint16_t *crnti,
                           NR_BSR_SHORT *truncated_bsr,
                           NR_BSR_SHORT *short_bsr,
-                          NR_BSR_LONG  *long_bsr
-						  );
-
-void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15);
+                          NR_BSR_LONG  *long_bsr);
 
 void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, fapi_nr_dl_config_request_t *dl_config, int rnti_type, int ss_id);
 
@@ -276,7 +273,7 @@ uint8_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac,
                             uint64_t *dci_pdu,
                             dci_pdu_rel15_t *nr_pdci_info_extracted);
 
-NR_PUSCH_TimeDomainResourceAllocationList_t *choose_ul_tda_list(NR_PUSCH_Config_t *pusch_Config,NR_PUSCH_ConfigCommon_t *pusch_ConfigCommon);
+NR_PUSCH_TimeDomainResourceAllocationList_t *choose_ul_tda_list(const NR_PUSCH_Config_t *pusch_Config,NR_PUSCH_ConfigCommon_t *pusch_ConfigCommon);
 NR_PDSCH_TimeDomainResourceAllocationList_t *choose_dl_tda_list(NR_PDSCH_Config_t *pdsch_Config,NR_PDSCH_ConfigCommon_t *pdsch_ConfigCommon);
 
 int8_t nr_ue_process_dci_time_dom_resource_assignment(NR_UE_MAC_INST_t *mac,
@@ -455,7 +452,7 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p
                                                       uint16_t riv);
 
 void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, fapi_nr_dl_config_request_t *dl_config, int rnti_type, int ss_id);
-void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15);
+void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, int slot, int rnti);
 
 void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac);
 
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c
index 0dfbbf2be333c03053be355e2d48b61a93f90915..9b618cdbfb4fda6696a86f305551f2fbb9a56ec1 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c
@@ -49,7 +49,9 @@
 
 //#define DEBUG_DCI
 
-void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15) {
+void fill_dci_search_candidates(NR_SearchSpace_t *ss,
+                                fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15,
+                                int slot, int rnti) {
 
   LOG_D(NR_MAC,"Filling search candidates for DCI\n");
 
@@ -57,6 +59,9 @@ void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pd
   uint8_t number_of_candidates=0;
   rel15->number_of_candidates=0;
   int i=0;
+  uint32_t Y = 0;
+  if (slot >= 0)
+    Y = get_Y(ss, slot, rnti);
   for (int maxL=16;maxL>0;maxL>>=1) {
     find_aggregation_candidates(&aggregation,
                                 &number_of_candidates,
@@ -65,8 +70,17 @@ void fill_dci_search_candidates(NR_SearchSpace_t *ss,fapi_nr_dl_config_dci_dl_pd
     if (number_of_candidates>0) {
       LOG_D(NR_MAC,"L %d, number of candidates %d, aggregation %d\n",maxL,number_of_candidates,aggregation);
       rel15->number_of_candidates += number_of_candidates;
+      int N_cce_sym = 0; // nb of rbs of coreset per symbol
+      for (int i=0;i<6;i++) {
+        for (int t=0;t<8;t++) {
+          N_cce_sym+=((rel15->coreset.frequency_domain_resource[i]>>t)&1);
+        }
+      }
+      int N_cces = N_cce_sym*rel15->coreset.duration;
       for (int j=0; j<number_of_candidates; i++,j++) {
-        rel15->CCE[i] = j*aggregation;
+        int first_cce = aggregation * (( Y + CEILIDIV((j*N_cces),(aggregation*number_of_candidates)) + 0 ) % CEILIDIV(N_cces,aggregation));
+        LOG_D(NR_MAC,"Candidate %d of %d first_cce %d (L %d N_cces %d Y %d)\n", j, number_of_candidates, first_cce, aggregation, N_cces, Y);
+        rel15->CCE[i] = first_cce;
         rel15->L[i] = aggregation;
       }
     }
@@ -305,14 +319,14 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
 		  } else {
 		    config_dci_pdu(mac, rel15, dl_config, NR_RNTI_RA, ss_id);
 		  }
-		  fill_dci_search_candidates(ss, rel15);
+		  fill_dci_search_candidates(ss, rel15, -1, -1);
 		  break;
 		case WAIT_CONTENTION_RESOLUTION:
 		  LOG_D(NR_MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in Type1-PDCCH common random access search space (RA-Msg4)\n");
 		  rel15->num_dci_options = 1;
 		  rel15->dci_format_options[0] = NR_DL_DCI_FORMAT_1_0;
 		  config_dci_pdu(mac, rel15, dl_config, NR_RNTI_TC, -1);
-		  fill_dci_search_candidates(ss, rel15);
+		  fill_dci_search_candidates(ss, rel15, -1, -1);
 		  break;
 		default:
 		  break;
@@ -384,7 +398,7 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
             rel15->dci_format_options[0] = NR_DL_DCI_FORMAT_1_1;
             rel15->dci_format_options[1] = NR_UL_DCI_FORMAT_0_1;
             config_dci_pdu(mac, rel15, dl_config, NR_RNTI_C, ss_id);
-            fill_dci_search_candidates(ss, rel15);
+            fill_dci_search_candidates(ss, rel15, slot, mac->crnti);
 
 //#ifdef DEBUG_DCI
 		LOG_D(NR_MAC, "[DCI_CONFIG] ss %d ue_Specific %p searchSpaceType->present %d dci_Formats %d\n",
@@ -420,19 +434,4 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
 
     AssertFatal(1==0,"Handle DCI searching when CellGroup without dedicated BWP\n");
   }
-  // Search space 0, CORESET ID 0
-  if (!get_softmodem_params()->nsa) {
-    NR_SearchSpace_t *ss0 = mac->search_space_zero;
-    if(ss0) {
-      fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15 = &dl_config->dl_config_list[dl_config->number_pdus].dci_config_pdu.dci_config_rel15;
-      rel15->num_dci_options = 1;
-      rel15->dci_format_options[0] = NR_DL_DCI_FORMAT_1_0;
-      config_dci_pdu(mac,
-                     rel15,
-                     dl_config,
-                     ((frame%2==mac->type0_PDCCH_CSS_config.sfn_c)&&(slot==mac->type0_PDCCH_CSS_config.n_0)) ? NR_RNTI_SI : NR_RNTI_C,
-                     -1);
-      fill_dci_search_candidates(ss0, rel15);
-    }
-  }
 }
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index da6b45ab67c6fd6409e8da4476d66999b29264b2..8004286413e09cb145347597b0770492da13b2cc 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -253,7 +253,7 @@ NR_PDSCH_TimeDomainResourceAllocationList_t *choose_dl_tda_list(NR_PDSCH_Config_
     return(pdsch_TimeDomainAllocationList);
 }
 
-NR_PUSCH_TimeDomainResourceAllocationList_t *choose_ul_tda_list(NR_PUSCH_Config_t *pusch_Config,NR_PUSCH_ConfigCommon_t *pusch_ConfigCommon) {
+NR_PUSCH_TimeDomainResourceAllocationList_t *choose_ul_tda_list(const NR_PUSCH_Config_t *pusch_Config,NR_PUSCH_ConfigCommon_t *pusch_ConfigCommon) {
 
     NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList=NULL;
 
@@ -579,7 +579,7 @@ int8_t nr_ue_process_dci_time_dom_resource_assignment(NR_UE_MAC_INST_t *mac,
   if(pusch_config_pdu != NULL){
     if (pusch_TimeDomainAllocationList && use_default==false) {
       if (time_domain_ind >= pusch_TimeDomainAllocationList->list.count) {
-        LOG_E(MAC, "time_domain_ind %d >= pusch->TimeDomainAllocationList->list.count %d\n",
+        LOG_E(NR_MAC, "time_domain_ind %d >= pusch->TimeDomainAllocationList->list.count %d\n",
               time_domain_ind, pusch_TimeDomainAllocationList->list.count);
         pusch_config_pdu->start_symbol_index=0;
         pusch_config_pdu->nr_of_symbols=0;
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
index 49aebb7daa7781684aaceaf64978b22a6315aab5..140fde407fa5caade817e09df6467ae36fd26455 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
@@ -697,8 +697,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
     pusch_config_pdu->bwp_start = NRRIV2PRBOFFSET(ubwpc->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
     pusch_config_pdu->bwp_size = n_RB_ULBWP;
 
-    AssertFatal(ubwpd->pusch_Config != NULL,"pusch_Config shouldn't be null\n");
-    NR_PUSCH_Config_t *pusch_Config = ubwpd->pusch_Config->choice.setup;
+    const NR_PUSCH_Config_t *pusch_Config = ubwpd? ubwpd->pusch_Config->choice.setup : NULL;
 
     // Basic sanity check for MCS value to check for a false or erroneous DCI
     if (dci->mcs > 28) {
@@ -776,10 +775,10 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
                 pusch_config_pdu->dfts_ofdm.low_papr_group_number);
     }
     else {
-      if (pusch_config_pdu->scid == 0 &&
+      if (pusch_config_pdu->scid == 0 && NR_DMRS_ulconfig &&
           NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID0)
         pusch_config_pdu->ul_dmrs_scrambling_id = *NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID0;
-      if (pusch_config_pdu->scid == 1 &&
+      if (pusch_config_pdu->scid == 1 && NR_DMRS_ulconfig &&
           NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID1)
         pusch_config_pdu->ul_dmrs_scrambling_id = *NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID1;
     }
@@ -1100,7 +1099,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in
         if (mac->ra.ra_state == WAIT_CONTENTION_RESOLUTION)
           rel15->dci_format_options[1] = NR_UL_DCI_FORMAT_0_0; // msg3 retransmission
         config_dci_pdu(mac, rel15, dl_config, mac->ra.ra_state == WAIT_RAR ? NR_RNTI_RA : NR_RNTI_TC , mac->ra.ss->searchSpaceId);
-        fill_dci_search_candidates(mac->ra.ss, rel15);
+        fill_dci_search_candidates(mac->ra.ss, rel15, -1 , -1);
         dl_config->number_pdus = 1;
         LOG_D(MAC,"mac->cg %p: Calling fill_scheduled_response rnti %x, type0_pdcch, num_pdus %d\n",mac->cg,rel15->rnti,dl_config->number_pdus);
         fill_scheduled_response(&scheduled_response, dl_config, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->thread_id, dl_info->phy_data);
@@ -2790,7 +2789,7 @@ void nr_ue_sib1_scheduler(module_id_t module_idP,
   rel15->num_dci_options = 1;
   rel15->dci_format_options[0] = NR_DL_DCI_FORMAT_1_0;
   config_dci_pdu(mac, rel15, dl_config, NR_RNTI_SI, -1);
-  fill_dci_search_candidates(mac->search_space_zero, rel15);
+  fill_dci_search_candidates(mac->search_space_zero, rel15, -1, -1);
 
   if(mac->type0_PDCCH_CSS_config.type0_pdcch_ss_mux_pattern == 1){
     // same frame as ssb
diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c
index 7dda0ab5ebc0525a429392095e4a30e52205e06a..b0718067a91543b9c8572f422ca85acb0f5feca1 100644
--- a/openair2/LAYER2/NR_MAC_gNB/config.c
+++ b/openair2/LAYER2/NR_MAC_gNB/config.c
@@ -646,13 +646,11 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
       ra->msg3_dcch_dtch = false;
       LOG_I(NR_MAC,"Added new RA process for UE RNTI %04x with initial CellGroup\n", rnti);
     } else { // CellGroup has been updated
-      NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels[0].ServingCellConfigCommon;
       NR_UE_info_t * UE = find_nr_UE(&RC.nrmac[Mod_idP]->UE_info,rnti);
       if (!UE) {
         LOG_E(NR_MAC, "Can't find UE %04x\n", rnti);
         return -1;
       }
-      int target_ss;
 
       UE->CellGroup = CellGroup;
       LOG_I(NR_MAC,"Modified rnti %04x with CellGroup\n",rnti);
@@ -664,30 +662,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
         // add all available DL HARQ processes for this UE in SA
         create_dl_harq_list(sched_ctrl, pdsch);
       }
-      // update coreset/searchspace
-      void *bwpd = NULL;
-      NR_BWP_t *genericParameters = NULL;
-      target_ss = NR_SearchSpace__searchSpaceType_PR_common;
-      if ((sched_ctrl->active_bwp)) {
-        target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
-        bwpd = (void*)sched_ctrl->active_bwp->bwp_Dedicated;
-        genericParameters = &sched_ctrl->active_bwp->bwp_Common->genericParameters;
-      }
-      else if (CellGroup->spCellConfig &&
-                 CellGroup->spCellConfig->spCellConfigDedicated &&
-                 (CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)) {
-        target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
-        bwpd = (void*)CellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP;
-        genericParameters = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
-      }
-      sched_ctrl->search_space = get_searchspace(sib1 ? sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL, scc, bwpd, target_ss);
-      sched_ctrl->coreset = get_coreset(RC.nrmac[Mod_idP], scc, bwpd, sched_ctrl->search_space, target_ss);
-      sched_ctrl->sched_pdcch = set_pdcch_structure(RC.nrmac[Mod_idP],
-                                                    sched_ctrl->search_space,
-                                                    sched_ctrl->coreset,
-                                                    scc,
-                                                    genericParameters,
-                                                    RC.nrmac[Mod_idP]->type0_PDCCH_CSS_config);
+
       sched_ctrl->maxL = 2;
 
       if (CellGroup->spCellConfig &&
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
index d7e2c78c3513472468e05fe22691722e964603a4..385cf5af16fe8fee26171a29008f4891b2e6090f 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
@@ -117,8 +117,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
   protocol_ctxt_t   ctxt={0};
   PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frame, slot,module_idP);
 
-  char stats_output[16384];
-
   gNB_MAC_INST *gNB = RC.nrmac[module_idP];
   NR_COMMON_channels_t *cc = gNB->common_channels;
   NR_ServingCellConfigCommon_t        *scc     = cc->ServingCellConfigCommon;
@@ -146,8 +144,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
     nr_rrc_trigger(&ctxt, 0 /*CC_id*/, frame, slot >> *scc->ssbSubcarrierSpacing);
   }
 
-  for (int i=0; i<MAX_NUM_CORESET; i++)
-    RC.nrmac[module_idP]->pdcch_cand[i] = 0;
   for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
     //mbsfn_status[CC_id] = 0;
 
@@ -180,9 +176,10 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
 
 
   if ((slot == 0) && (frame & 127) == 0) {
-     stats_output[0]='\0';
-     dump_mac_stats(RC.nrmac[module_idP],stats_output,16384,true);
-     LOG_I(NR_MAC,"Frame.Slot %d.%d\n%s\n",frame,slot,stats_output);
+    char stats_output[16384];
+    stats_output[0] = '\0';
+    dump_mac_stats(RC.nrmac[module_idP], stats_output, sizeof(stats_output), true);
+    LOG_I(NR_MAC, "Frame.Slot %d.%d\n%s\n", frame, slot, stats_output);
   }
 
   nr_mac_update_timers(module_idP, frame, slot);
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
index eb05ec5e83569751a8f1bc6711bd8fb28217c265..e3d3a5409d706dd6251f728afdd7f06f2ef3b83f 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
@@ -537,167 +537,164 @@ void nr_initiate_ra_proc(module_id_t module_idP,
   }
 
   for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
+
     NR_RA_t *ra = &cc->ra[i];
-    pr_found = 0;
-    const NR_UE_info_t * UE = find_nr_UE(&nr_mac->UE_info, ra->rnti);
-    if (UE) {
-      // the UE is already registered
-      LOG_W(NR_MAC, "Received RA for existing RNTI %04x\n", ra->rnti);
+    if (ra->state != RA_IDLE)
       continue;
-    }
-    if (ra->state == RA_IDLE) {
-      for(int j = 0; j < ra->preambles.num_preambles; j++) {
-        //check if the preamble received correspond to one of the listed or configured preambles
-        if (preamble_index == ra->preambles.preamble_list[j]) {
-          if (ra->rnti == 0 && get_softmodem_params()->nsa)
-            continue;
-          pr_found=1;
-          break;
-        }
-      }
-      if (pr_found == 0) {
-         continue;
+
+    pr_found = 0;
+
+    for(int j = 0; j < ra->preambles.num_preambles; j++) {
+      //check if the preamble received correspond to one of the listed or configured preambles
+      if (preamble_index == ra->preambles.preamble_list[j]) {
+        if (ra->rnti == 0 && get_softmodem_params()->nsa)
+          continue;
+        pr_found=1;
+        break;
       }
+    }
+    if (pr_found == 0) {
+       continue;
+    }
 
-      uint16_t ra_rnti;
+    uint16_t ra_rnti;
 
-      // ra_rnti from 5.1.3 in 38.321
-      // FK: in case of long PRACH the phone seems to expect the subframe number instead of the slot number here.
-      if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present
-          == NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l839)
-        ra_rnti = 1 + symbol + (9 /*slotP*/ * 14) + (freq_index * 14 * 80) + (ul_carrier_id * 14 * 80 * 8);
-      else
-        ra_rnti = 1 + symbol + (slotP * 14) + (freq_index * 14 * 80) + (ul_carrier_id * 14 * 80 * 8);
-
-      // This should be handled differently when we use the initialBWP for RA
-      ra->dl_bwp_id = 0;//TODO
-      ra->ul_bwp_id = 0;
-      NR_BWP_Downlink_t *bwp=NULL;
-      if (ra->CellGroup && ra->CellGroup->spCellConfig && ra->CellGroup->spCellConfig->spCellConfigDedicated) {
-        if (ra->CellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id &&
-          ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) {
-          ra->dl_bwp_id = *ra->CellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id;
-          bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->dl_bwp_id - 1];
-        }
-        if (ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig &&
-            ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id)
-          ra->ul_bwp_id = *ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id;
-     }
+    // ra_rnti from 5.1.3 in 38.321
+    // FK: in case of long PRACH the phone seems to expect the subframe number instead of the slot number here.
+    if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present
+        == NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l839)
+      ra_rnti = 1 + symbol + (9 /*slotP*/ * 14) + (freq_index * 14 * 80) + (ul_carrier_id * 14 * 80 * 8);
+    else
+      ra_rnti = 1 + symbol + (slotP * 14) + (freq_index * 14 * 80) + (ul_carrier_id * 14 * 80 * 8);
+
+    // This should be handled differently when we use the initialBWP for RA
+    ra->dl_bwp_id = 0;//TODO
+    ra->ul_bwp_id = 0;
+    NR_BWP_Downlink_t *bwp=NULL;
+    if (ra->CellGroup && ra->CellGroup->spCellConfig && ra->CellGroup->spCellConfig->spCellConfigDedicated) {
+      if (ra->CellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id &&
+        ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) {
+        ra->dl_bwp_id = *ra->CellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id;
+        bwp = ra->CellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->dl_bwp_id - 1];
+      }
+      if (ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig &&
+          ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id)
+        ra->ul_bwp_id = *ra->CellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id;
+   }
 
-      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1);
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1);
 
-      LOG_D(NR_MAC,
-            "[gNB %d][RAPROC] CC_id %d Frame %d, Slot %d  Initiating RA procedure for preamble index %d\n",
+    LOG_D(NR_MAC,
+          "[gNB %d][RAPROC] CC_id %d Frame %d, Slot %d  Initiating RA procedure for preamble index %d\n",
+          module_idP,
+          CC_id,
+          frameP,
+          slotP,
+          preamble_index);
+
+    uint8_t beam_index = ssb_index_from_prach(module_idP, frameP, slotP, preamble_index, freq_index, symbol);
+
+    // the UE sent a RACH either for starting RA procedure or RA procedure failed and UE retries
+    if (ra->cfra) {
+      // if the preamble received correspond to one of the listed
+      if (!(preamble_index == ra->preambles.preamble_list[beam_index])) {
+        LOG_E(
+            NR_MAC,
+            "[gNB %d][RAPROC] FAILURE: preamble %d does not correspond to any of the ones in rach_ConfigDedicated\n",
             module_idP,
-            CC_id,
-            frameP,
-            slotP,
             preamble_index);
-
-      uint8_t beam_index = ssb_index_from_prach(module_idP, frameP, slotP, preamble_index, freq_index, symbol);
-
-      // the UE sent a RACH either for starting RA procedure or RA procedure failed and UE retries
-      if (ra->cfra) {
-        // if the preamble received correspond to one of the listed
-        if (!(preamble_index == ra->preambles.preamble_list[beam_index])) {
-          LOG_E(
-              NR_MAC,
-              "[gNB %d][RAPROC] FAILURE: preamble %d does not correspond to any of the ones in rach_ConfigDedicated\n",
-              module_idP,
-              preamble_index);
-          continue; // if the PRACH preamble does not correspond to any of the ones sent through RRC abort RA proc
-        }
+        continue; // if the PRACH preamble does not correspond to any of the ones sent through RRC abort RA proc
       }
-      LOG_D(NR_MAC, "Frame %d, Slot %d: Activating RA process \n", frameP, slotP);
-      ra->state = Msg2;
-      ra->timing_offset = timing_offset;
-      ra->preamble_slot = slotP;
-
-      NR_SearchSpaceId_t	ra_SearchSpace = 0;
-      struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = NULL;
-      NR_BWP_t *genericParameters = NULL;
-      if(bwp) {
-        commonSearchSpaceList = bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList;
-        ra_SearchSpace = *bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace;
-        genericParameters = &bwp->bwp_Common->genericParameters;
-      } else {
-        commonSearchSpaceList = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList;
-        ra_SearchSpace = *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->ra_SearchSpace;
-        genericParameters = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
-      }
-      AssertFatal(commonSearchSpaceList->list.count > 0, "common SearchSpace list has 0 elements\n");
+    }
+    LOG_D(NR_MAC, "Frame %d, Slot %d: Activating RA process \n", frameP, slotP);
+    ra->state = Msg2;
+    ra->timing_offset = timing_offset;
+    ra->preamble_slot = slotP;
 
-      // Common SearchSpace list
-      for (int i = 0; i < commonSearchSpaceList->list.count; i++) {
-        ss = commonSearchSpaceList->list.array[i];
-        if (ss->searchSpaceId == ra_SearchSpace)
-          ra->ra_ss = ss;
-      }
+    NR_SearchSpaceId_t	ra_SearchSpace = 0;
+    struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = NULL;
+    NR_BWP_t *genericParameters = NULL;
+    if(bwp) {
+      commonSearchSpaceList = bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList;
+      ra_SearchSpace = *bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace;
+      genericParameters = &bwp->bwp_Common->genericParameters;
+    } else {
+      commonSearchSpaceList = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList;
+      ra_SearchSpace = *scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->ra_SearchSpace;
+      genericParameters = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
+    }
+    AssertFatal(commonSearchSpaceList->list.count > 0, "common SearchSpace list has 0 elements\n");
 
-      AssertFatal(ra->ra_ss!=NULL,"SearchSpace cannot be null for RA\n");
-
-      ra->coreset = get_coreset(nr_mac, scc, bwp, ra->ra_ss, NR_SearchSpace__searchSpaceType_PR_common);
-      ra->sched_pdcch = set_pdcch_structure(nr_mac,
-                                            ra->ra_ss,
-                                            ra->coreset,
-                                            scc,
-                                            genericParameters,
-                                            &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]);
-
-      // retrieving ra pdcch monitoring period and offset
-      find_monitoring_periodicity_offset_common(ra->ra_ss, &monitoring_slot_period, &monitoring_offset);
-
-      nr_schedule_msg2(frameP,
-                       slotP,
-                       &msg2_frame,
-                       &msg2_slot,
-                       scc,
-                       frame_type,
-                       monitoring_slot_period,
-                       monitoring_offset,
-                       beam_index,
-                       cc->num_active_ssb,
-                       nr_mac->tdd_beam_association,
-		       nr_mac->if_inst->sl_ahead);
-
-      ra->Msg2_frame = msg2_frame;
-      ra->Msg2_slot = msg2_slot;
-
-      LOG_D(NR_MAC, "%s() Msg2[%04d%d] SFN/SF:%04d%d\n", __FUNCTION__, ra->Msg2_frame, ra->Msg2_slot, frameP, slotP);
-
-      int loop = 0;
-      if (ra->rnti == 0) { // This condition allows for the usage of a preconfigured rnti for the CFRA
-        do {
-          ra->rnti = (taus() % 65518) + 1;
-          loop++;
-        } while (loop != 100
-                 && !((find_nr_UE(&nr_mac->UE_info, ra->rnti) == NULL) && (find_nr_RA_id(module_idP, CC_id, ra->rnti) == -1)
-                      && ra->rnti >= 1 && ra->rnti <= 65519));
-        if (loop == 100) {
-          LOG_E(NR_MAC, "%s:%d:%s: [RAPROC] initialisation random access aborted\n", __FILE__, __LINE__, __FUNCTION__);
-          abort();
-        }
-      }
+    // Common SearchSpace list
+    for (int i = 0; i < commonSearchSpaceList->list.count; i++) {
+      ss = commonSearchSpaceList->list.array[i];
+      if (ss->searchSpaceId == ra_SearchSpace)
+        ra->ra_ss = ss;
+    }
 
-      ra->RA_rnti = ra_rnti;
-      ra->preamble_index = preamble_index;
-      ra->beam_id = beam_index;
+    AssertFatal(ra->ra_ss!=NULL,"SearchSpace cannot be null for RA\n");
+
+    ra->coreset = get_coreset(nr_mac, scc, bwp, ra->ra_ss, NR_SearchSpace__searchSpaceType_PR_common);
+    ra->sched_pdcch = set_pdcch_structure(nr_mac,
+                                          ra->ra_ss,
+                                          ra->coreset,
+                                          scc,
+                                          genericParameters,
+                                          &nr_mac->type0_PDCCH_CSS_config[ra->beam_id]);
+
+    // retrieving ra pdcch monitoring period and offset
+    find_monitoring_periodicity_offset_common(ra->ra_ss, &monitoring_slot_period, &monitoring_offset);
+
+    nr_schedule_msg2(frameP,
+                     slotP,
+                     &msg2_frame,
+                     &msg2_slot,
+                     scc,
+                     frame_type,
+                     monitoring_slot_period,
+                     monitoring_offset,
+                     beam_index,
+                     cc->num_active_ssb,
+                     nr_mac->tdd_beam_association,
+         nr_mac->if_inst->sl_ahead);
+
+    ra->Msg2_frame = msg2_frame;
+    ra->Msg2_slot = msg2_slot;
+
+    LOG_D(NR_MAC, "%s() Msg2[%04d%d] SFN/SF:%04d%d\n", __FUNCTION__, ra->Msg2_frame, ra->Msg2_slot, frameP, slotP);
+
+    int loop = 0;
+    if (ra->rnti == 0) { // This condition allows for the usage of a preconfigured rnti for the CFRA
+      do {
+        ra->rnti = (taus() % 65518) + 1;
+        loop++;
+      } while (loop != 100
+               && !((find_nr_UE(&nr_mac->UE_info, ra->rnti) == NULL) && (find_nr_RA_id(module_idP, CC_id, ra->rnti) == -1)
+                    && ra->rnti >= 1 && ra->rnti <= 65519));
+      if (loop == 100) {
+        LOG_E(NR_MAC, "%s:%d:%s: [RAPROC] initialisation random access aborted\n", __FILE__, __LINE__, __FUNCTION__);
+        abort();
+      }
+    }
 
-      LOG_I(NR_MAC,
-            "[gNB %d][RAPROC] CC_id %d Frame %d Activating Msg2 generation in frame %d, slot %d using RA rnti %x SSB, new rnti %04x "
-            "index %u RA index %d\n",
-            module_idP,
-            CC_id,
-            frameP,
-            ra->Msg2_frame,
-            ra->Msg2_slot,
-            ra->RA_rnti,
-	    ra->rnti,
-            cc->ssb_index[beam_index],
-            i);
+    ra->RA_rnti = ra_rnti;
+    ra->preamble_index = preamble_index;
+    ra->beam_id = beam_index;
+
+    LOG_I(NR_MAC,
+          "[gNB %d][RAPROC] CC_id %d Frame %d Activating Msg2 generation in frame %d, slot %d using RA rnti %x SSB, new rnti %04x "
+          "index %u RA index %d\n",
+          module_idP,
+          CC_id,
+          frameP,
+          ra->Msg2_frame,
+          ra->Msg2_slot,
+          ra->RA_rnti,
+    ra->rnti,
+          cc->ssb_index[beam_index],
+          i);
 
-      return;
-    }
+    return;
   }
   LOG_E(NR_MAC, "[gNB %d][RAPROC] FAILURE: CC_id %d Frame %d initiating RA procedure for preamble index %d\n", module_idP, CC_id, frameP, preamble_index);
 
@@ -787,8 +784,9 @@ void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t
 
     uint16_t *vrb_map_UL = &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE];
 
-    int BWPStart = nr_mac->type0_PDCCH_CSS_config[ra->beam_id].cset_start_rb;
-    int BWPSize  = nr_mac->type0_PDCCH_CSS_config[ra->beam_id].num_rbs;
+    const int BWPSize = NRRIV2BW(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
+    const int BWPStart = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
+
     int rbStart = 0;
     for (int i = 0; (i < ra->msg3_nb_rb) && (rbStart <= (BWPSize - ra->msg3_nb_rb)); i++) {
       if (vrb_map_UL[rbStart + BWPStart + i]&SL_to_bitmap(StartSymbolIndex, NrOfSymbols)) {
@@ -1326,7 +1324,7 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
     dl_req->nPDUs+=1;
     nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15;
 
-    LOG_D(NR_MAC,"[gNB %d][RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg2 DCI, rnti 0x%x, state %d, CoreSetType %d\n",
+    LOG_A(NR_MAC,"[gNB %d][RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg2 DCI, rnti 0x%x, state %d, CoreSetType %d\n",
           module_idP, CC_id, frameP, slotP, ra->RA_rnti, ra->state,pdcch_pdu_rel15->CoreSetType);
 
     // SCF222: PDU index incremented for each PDSCH PDU sent in TX control message. This is used to associate control
@@ -1787,7 +1785,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
     dl_req->nPDUs+=1;
     nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15;
 
-    LOG_D(NR_MAC, "[gNB %d] [RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg4 DCI, state %d\n", module_idP, CC_id, frameP, slotP, ra->state);
+    LOG_A(NR_MAC, "[gNB %d] [RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg4 DCI, state %d\n", module_idP, CC_id, frameP, slotP, ra->state);
 
     // SCF222: PDU index incremented for each PDSCH PDU sent in TX control message. This is used to associate control
     // information to data and is reset every slot.
@@ -1952,7 +1950,7 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
 
     if(ra->msg3_dcch_dtch) {
       // If the UE used MSG3 to transfer a DCCH or DTCH message, then contention resolution is successful upon transmission of PDCCH
-      LOG_I(NR_MAC, "(ue rnti 0x%04x) CBRA procedure succeeded!\n", ra->rnti);
+      LOG_A(NR_MAC, "(ue rnti 0x%04x) CBRA procedure succeeded!\n", ra->rnti);
       nr_clear_ra_proc(module_idP, CC_id, frameP, ra);
       UE->Msg4_ACKed = true;
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
index 9b736955825c332b5ec76c7e2d8552b111b4b43a..c502975f7c279863dacfff41d2cee35ed37ba570 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
@@ -489,8 +489,8 @@ bool allocate_dl_retransmission(module_id_t module_id,
   }
 
   /* Find a free CCE */
-  const int cid = sched_ctrl->coreset->controlResourceSetId;
-  const uint16_t Y = get_Y(cid%3, slot, UE->rnti);
+
+  const uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE->rnti);
   uint8_t nr_of_candidates;
 
   for (int i=0; i<5; i++) {
@@ -528,7 +528,6 @@ bool allocate_dl_retransmission(module_id_t module_id,
           UE->rnti,
           frame,
           slot);
-    RC.nrmac[module_id]->pdcch_cand[cid]--;
     return false;
   }
 
@@ -692,8 +691,7 @@ void pf_dl(module_id_t module_id,
     }
 
     /* Find a free CCE */
-    const int cid = sched_ctrl->coreset->controlResourceSetId;
-    const uint16_t Y = get_Y(cid%3, slot, iterator->UE->rnti);
+    const uint32_t Y = get_Y(sched_ctrl->search_space, slot, iterator->UE->rnti);
     uint8_t nr_of_candidates;
 
     for (int i=0; i<5; i++) {
@@ -732,7 +730,6 @@ void pf_dl(module_id_t module_id,
             rnti,
             frame,
             slot);
-      mac->pdcch_cand[cid]--;
       iterator++;
       continue;
     }
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
index 56d14b1458490b7e829cf25dd875427660361917..808fc613f1a854d7b410b7a5e28b82ea05aeaa3f 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
@@ -263,8 +263,7 @@ void nr_preprocessor_phytest(module_id_t module_id,
   }
   AssertFatal(nr_of_candidates>0,"nr_of_candidates is 0\n");
 
-  const int cid = sched_ctrl->coreset->controlResourceSetId;
-  const uint16_t Y = get_Y(cid%3, slot, UE->rnti);
+  const uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE->rnti);
 
   int CCEIndex = find_pdcch_candidate(RC.nrmac[module_id],
                                       CC_id,
@@ -288,7 +287,6 @@ void nr_preprocessor_phytest(module_id_t module_id,
           rnti,
           frame,
           slot);
-    RC.nrmac[module_id]->pdcch_cand[cid]--;
     return;
   }
 
@@ -310,6 +308,7 @@ void nr_preprocessor_phytest(module_id_t module_id,
   sched_pdsch->rbSize = rbSize;
 
   sched_pdsch->mcs = target_dl_mcs;
+  sched_ctrl->dl_bler_stats.mcs = target_dl_mcs; /* for logging output */
   sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, ps->mcsTableIdx);
   sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, ps->mcsTableIdx);
   sched_pdsch->tb_size = nr_compute_tbs(sched_pdsch->Qm,
@@ -439,8 +438,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_
   }
   AssertFatal(nr_of_candidates>0,"nr_of_candidates is 0\n");
 
-  const int cid = sched_ctrl->coreset->controlResourceSetId;
-  const uint16_t Y = get_Y(cid%3, slot, UE->rnti);
+  const uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE->rnti);
 
   int CCEIndex = find_pdcch_candidate(nr_mac,
                                       CC_id,
@@ -452,7 +450,6 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_
 
   if (CCEIndex < 0) {
     LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__);
-    nr_mac->pdcch_cand[cid]--;
     return false;
   }
 
@@ -461,6 +458,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_
   const int mcs = target_ul_mcs;
   NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
   sched_pusch->mcs = mcs;
+  sched_ctrl->ul_bler_stats.mcs = mcs; /* for logging output */
   sched_pusch->rbStart = rbStart;
   sched_pusch->rbSize = rbSize;
   /* get the PID of a HARQ process awaiting retransmission, or -1 for "any new" */
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index 4ce4180fa578eaa47027809ce775ad6fa01cace4..c2066f943fee0f5ec5c7bd1667fa9d0ad3cc8192 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -440,36 +440,17 @@ NR_sched_pdcch_t set_pdcch_structure(gNB_MAC_INST *gNB_mac,
 }
 
 
-int cce_to_reg_interleaving(const int R, int k, int n_shift, const int C, int L, const int N_regs) {
-
-  int f;  // interleaving function
-  if(R==0)
-    f = k;
-  else {
-    int c = k/R;
-     int r = k%R;
-     f = (r*C + c + n_shift)%(N_regs/L);
-  }
-  return f;
-}
-
 int find_pdcch_candidate(gNB_MAC_INST *mac,
                          int cc_id,
                          int aggregation,
                          int nr_of_candidates,
                          NR_sched_pdcch_t *pdcch,
                          NR_ControlResourceSet_t *coreset,
-                         uint16_t Y){
+                         uint32_t Y){
 
   uint16_t *vrb_map = mac->common_channels[cc_id].vrb_map;
-  const int next_cand = mac->pdcch_cand[coreset->controlResourceSetId];
   const int N_ci = 0;
 
-  if(next_cand>=nr_of_candidates) {
-    LOG_D(NR_MAC,"No more available candidates for this coreset\n");
-    return -1;
-  }
-
   const int N_rb = pdcch->n_rb;  // nb of rbs of coreset per symbol
   const int N_symb = coreset->duration; // nb of coreset symbols
   const int N_regs = N_rb*N_symb; // nb of REGs per coreset
@@ -481,9 +462,10 @@ int find_pdcch_candidate(gNB_MAC_INST *mac,
 
   // loop over all the available candidates
   // this implements TS 38.211 Sec. 7.3.2.2
-  for(int m=next_cand; m<nr_of_candidates; m++) { // loop over candidates
+  for(int m=0; m<nr_of_candidates; m++) { // loop over candidates
     bool taken = false; // flag if the resource for a given candidate are taken
     int first_cce = aggregation * (( Y + CEILIDIV((m*N_cces),(aggregation*nr_of_candidates)) + N_ci ) % CEILIDIV(N_cces,aggregation));
+    LOG_D(NR_MAC,"Candidate %d of %d first_cce %d (L %d N_cces %d Y %d)\n", m, nr_of_candidates, first_cce, aggregation, N_cces, Y);
     for (int j=first_cce; (j<first_cce+aggregation) && !taken; j++) { // loop over CCEs
       for (int k=6*j/L; (k<(6*j/L+6/L)) && !taken; k++) { // loop over REG bundles
         int f = cce_to_reg_interleaving(R, k, pdcch->ShiftIndex, C, L, N_regs);
@@ -495,10 +477,8 @@ int find_pdcch_candidate(gNB_MAC_INST *mac,
         }
       }
     }
-    if(!taken){
-      mac->pdcch_cand[coreset->controlResourceSetId] = m++; // using candidate m, next available is m+1
+    if(!taken)
       return first_cce;
-    }
   }
   return -1;
 }
@@ -1133,7 +1113,7 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu,
   for (int i=0;i<6;i++)
     pdcch_pdu->FreqDomainResource[i] = coreset->frequencyDomainResources.buf[i];
 
-  LOG_D(MAC,"Coreset : BWPstart %d, BWPsize %d, SCS %d, freq %x, , duration %d,  \n",
+  LOG_D(MAC,"Coreset : BWPstart %d, BWPsize %d, SCS %d, freq %x, , duration %d\n",
         pdcch_pdu->BWPStart,pdcch_pdu->BWPSize,(int)pdcch_pdu->SubcarrierSpacing,(int)coreset->frequencyDomainResources.buf[0],(int)coreset->duration);
 
   pdcch_pdu->CceRegMappingType = pdcch->CceRegMappingType;
@@ -2265,30 +2245,17 @@ void remove_front_nr_list(NR_list_t *listP)
 
 NR_UE_info_t *find_nr_UE(NR_UEs_t *UEs, rnti_t rntiP)
 {
+
   UE_iterator(UEs->list, UE) {
     if (UE->rnti == rntiP) {
       LOG_D(NR_MAC,"Search and found rnti: %04x\n", rntiP);
       return UE;
     }
   }
-  LOG_W(NR_MAC,"Search for not existing rnti: %04x\n", rntiP);
+  LOG_W(NR_MAC,"Search for not existing rnti (ignore for RA): %04x\n", rntiP);
   return NULL;
 }
 
-uint16_t get_Y(int cid, int slot, rnti_t rnti) {
-
-  const int A[3] = {39827, 39829, 39839};
-  const int D = 65537;
-  int Y;
-
-  Y = (A[cid] * rnti) % D;
-
-  for (int s = 0; s < slot; s++)
-    Y = (A[cid] * Y) % D;
-
-  return Y;
-}
-
 int find_nr_RA_id(module_id_t mod_idP, int CC_idP, rnti_t rntiP) {
 //------------------------------------------------------------------------------
   int RA_id;
@@ -2936,6 +2903,30 @@ void nr_mac_update_timers(module_id_t module_id,
                                            cg->spCellConfig->spCellConfigDedicated ?
                                            cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP : NULL;
 
+        // update coreset/searchspace
+        int target_ss = NR_SearchSpace__searchSpaceType_PR_common;
+        NR_BWP_t *genericParameters = NULL;
+        if (sched_ctrl->active_bwp) {
+          target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+          bwpd = (void*)sched_ctrl->active_bwp->bwp_Dedicated;
+          genericParameters = &sched_ctrl->active_bwp->bwp_Common->genericParameters;
+        }
+        else if (cg->spCellConfig &&
+                 cg->spCellConfig->spCellConfigDedicated &&
+                 (cg->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)) {
+          target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+          genericParameters = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
+        }
+        NR_BCCH_DL_SCH_Message_t *SIB1 = RC.nrmac[module_id]->common_channels[0].sib1;
+        sched_ctrl->search_space = get_searchspace(SIB1 ? SIB1->message.choice.c1->choice.systemInformationBlockType1 : NULL, scc, bwpd, target_ss);
+        sched_ctrl->coreset = get_coreset(RC.nrmac[module_id], scc, bwpd, sched_ctrl->search_space, target_ss);
+        sched_ctrl->sched_pdcch = set_pdcch_structure(RC.nrmac[module_id],
+                                                      sched_ctrl->search_space,
+                                                      sched_ctrl->coreset,
+                                                      scc,
+                                                      genericParameters,
+                                                      RC.nrmac[module_id]->type0_PDCCH_CSS_config);
+
         NR_pdsch_semi_static_t *ps = &sched_ctrl->pdsch_semi_static;
 
         const uint8_t layers = set_dl_nrOfLayers(sched_ctrl);
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
index 76c49b825798f92a1cc7b1ce285c66fb3b396033..0a47f523858c0c3a0efea682d0a4f5364150b800 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
@@ -413,7 +413,7 @@ void tci_handling(NR_UE_info_t *UE, frame_t frame, slot_t slot) {
   uint8_t idx = 0;
 
   NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
-  const int bwp_id = sched_ctrl->active_bwp ? 1 : 0;
+  const int bwp_id = sched_ctrl->active_bwp ? sched_ctrl->active_bwp->bwp_Id : 0;
   NR_CellGroupConfig_t *CellGroup = UE->CellGroup;
 
   //bwp indicator
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
index 5fe7c18b7b0818b5723a9e4e724696d118bf70a5..693656d7829e7057f2deeca7ba5150674a356a47 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
@@ -932,8 +932,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
   }
 
   /* Find a free CCE */
-  const int cid = sched_ctrl->coreset->controlResourceSetId;
-  const uint16_t Y = get_Y(cid%3, slot, UE->rnti);
+  const uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE->rnti);
   uint8_t nr_of_candidates;
   for (int i=0; i<5; i++) {
     // for now taking the lowest value among the available aggregation levels
@@ -1102,8 +1101,7 @@ void pf_ul(module_id_t module_id,
     if (B == 0 && do_sched) {
       /* if no data, pre-allocate 5RB */
       /* Find a free CCE */
-      const int cid = sched_ctrl->coreset->controlResourceSetId;
-      const uint16_t Y = get_Y(cid%3, slot, UE->rnti);
+      const uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE->rnti);
       uint8_t nr_of_candidates;
       for (int i=0; i<5; i++) {
         // for now taking the lowest value among the available aggregation levels
@@ -1218,8 +1216,7 @@ void pf_ul(module_id_t module_id,
 
     NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl;
 
-    const int cid = sched_ctrl->coreset->controlResourceSetId;
-    const uint16_t Y = get_Y(cid%3, slot, iterator->UE->rnti);
+    const uint32_t Y = get_Y(sched_ctrl->search_space, slot, iterator->UE->rnti);
     uint8_t nr_of_candidates;
     for (int i=0; i<5; i++) {
       // for now taking the lowest value among the available aggregation levels
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index 0368d0186e366d442000bf19aa9306e1407694ab..59db2740e5f66bc0702f4c332a4bae7b8129f0b8 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -290,7 +290,7 @@ int find_pdcch_candidate(gNB_MAC_INST *mac,
                          int nr_of_candidates,
                          NR_sched_pdcch_t *pdcch,
                          NR_ControlResourceSet_t *coreset,
-                         uint16_t Y);
+                         uint32_t Y);
 
 void fill_pdcch_vrb_map(gNB_MAC_INST *mac,
                         int CC_id,
@@ -373,8 +373,6 @@ void nr_set_pusch_semi_static(const NR_SIB1_t *sib1,
                               uint8_t nrOfLayers,
                               NR_pusch_semi_static_t *ps);
 
-uint16_t get_Y(int cid, int slot, rnti_t rnti);
-
 uint8_t nr_get_tpc(int target, uint8_t cqi, int incr);
 
 int get_spf(nfapi_nr_config_request_scf_t *cfg);
@@ -412,14 +410,6 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti);
 
 void nr_mac_remove_ra_rnti(module_id_t mod_id, rnti_t rnti);
 
-int allocate_nr_CCEs(gNB_MAC_INST *nr_mac,
-                     NR_BWP_Downlink_t *bwp,
-                     NR_ControlResourceSet_t *coreset,
-                     int aggregation,
-                     uint16_t Y,
-                     int m,
-                     int nr_of_candidates);
-
 int nr_get_default_pucch_res(int pucch_ResourceCommon);
 
 int get_dlscs(nfapi_nr_config_request_t *cfg);
@@ -532,7 +522,7 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options,
 
 void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t frameP, sub_frame_t slotP);
 
-void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp);
+size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp);
 
 void process_CellGroup(NR_CellGroupConfig_t *CellGroup, NR_UE_sched_ctrl_t *sched_ctrl);
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c
index 6547544a68c76990b1eda25aede0194bf35eeecf..9b9fd4e76cbed3900730877eca4af3d13ecde5c0 100644
--- a/openair2/LAYER2/NR_MAC_gNB/main.c
+++ b/openair2/LAYER2/NR_MAC_gNB/main.c
@@ -45,25 +45,31 @@
 extern RAN_CONTEXT_t RC;
 
 
-#define MACSTATSSTRLEN 16384
+#define MACSTATSSTRLEN 65536
 
 void *nrmac_stats_thread(void *arg) {
 
   gNB_MAC_INST *gNB = (gNB_MAC_INST *)arg;
 
-  char output[MACSTATSSTRLEN];
-  memset(output,0,MACSTATSSTRLEN);
-  FILE *fd=fopen("nrMAC_stats.log","w");
-  AssertFatal(fd!=NULL,"Cannot open nrMAC_stats.log, error %s\n",strerror(errno));
+  char output[MACSTATSSTRLEN] = {0};
+  const char *end = output + MACSTATSSTRLEN;
+  FILE *file = fopen("nrMAC_stats.log","w");
+  AssertFatal(file!=NULL,"Cannot open nrMAC_stats.log, error %s\n",strerror(errno));
 
   while (oai_exit == 0) {
-    dump_mac_stats(gNB,output,MACSTATSSTRLEN,false);
-     fprintf(fd,"%s\n",output);
-     fflush(fd);
-     usleep(200000);
-     fseek(fd,0,SEEK_SET);
+    char *p = output;
+    p += dump_mac_stats(gNB, p, end - p, false);
+    p += snprintf(p, end - p, "\n");
+    p += print_meas_log(&gNB->eNB_scheduler, "DL & UL scheduling timing", NULL, NULL, p, end - p);
+    p += print_meas_log(&gNB->schedule_dlsch, "dlsch scheduler", NULL, NULL, p, end - p);
+    p += print_meas_log(&gNB->rlc_data_req, "rlc_data_req", NULL, NULL, p, end - p);
+    p += print_meas_log(&gNB->rlc_status_ind, "rlc_status_ind", NULL, NULL, p, end - p);
+    fwrite(output, p - output, 1, file);
+    fflush(file);
+    sleep(1);
+    fseek(file,0,SEEK_SET);
   }
-  fclose(fd);
+  fclose(file);
   return NULL;
 }
 
@@ -73,11 +79,12 @@ void clear_mac_stats(gNB_MAC_INST *gNB) {
   }
 }
 
-void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp)
+size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp)
 {
   int num = 1;
+  const char *begin = output;
+  const char *end = output + strlen;
  
-  int stroff=0;
   pthread_mutex_lock(&gNB->UE_info.mutex);
   UE_iterator(gNB->UE_info.list, UE) {
     NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
@@ -85,63 +92,77 @@ void dump_mac_stats(gNB_MAC_INST *gNB, char *output, int strlen, bool reset_rsrp
     const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0;
 
 
-    stroff+=sprintf(output+stroff,"UE RNTI %04x (%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n",
-		    UE->rnti,
-		    num++,
-		    sched_ctrl->ph,
-		    sched_ctrl->pcmax,
-		    avg_rsrp,
-		    stats->num_rsrp_meas);
-    stroff+=sprintf(output+stroff,"UE %04x: CQI %d, RI %d, PMI (%d,%d)\n",
-                    UE->rnti,
-                    UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb,
-                    UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.ri+1,
-                    UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1,
-                    UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2);
-    
-    stroff+=sprintf(output+stroff,"UE %04x: dlsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS %d\n",
-                    UE->rnti,
-
-                    stats->dl.rounds[0], stats->dl.rounds[1],
-                    stats->dl.rounds[2], stats->dl.rounds[3],
-                    stats->dl.errors,
-                    stats->pucch0_DTX,
-                    sched_ctrl->dl_bler_stats.bler,
-                    sched_ctrl->dl_bler_stats.mcs);
+    output += snprintf(output,
+                       end - output,
+                       "UE RNTI %04x (%d) PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n",
+                       UE->rnti,
+                       num++,
+                       sched_ctrl->ph,
+                       sched_ctrl->pcmax,
+                       avg_rsrp,
+                       stats->num_rsrp_meas);
+    output += snprintf(output,
+                       end - output,
+                       "UE %04x: CQI %d, RI %d, PMI (%d,%d)\n",
+                       UE->rnti,
+                       UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb,
+                       UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.ri+1,
+                       UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1,
+                       UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2);
+
+    output += snprintf(output,
+                       end - output,
+                       "UE %04x: dlsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS %d\n",
+                       UE->rnti,
+                       stats->dl.rounds[0], stats->dl.rounds[1],
+                       stats->dl.rounds[2], stats->dl.rounds[3],
+                       stats->dl.errors,
+                       stats->pucch0_DTX,
+                       sched_ctrl->dl_bler_stats.bler,
+                       sched_ctrl->dl_bler_stats.mcs);
     if (reset_rsrp) {
       stats->num_rsrp_meas = 0;
       stats->cumul_rsrp = 0;
     }
-    stroff+=sprintf(output+stroff,"UE %04x: dlsch_total_bytes %"PRIu64"\n", UE->rnti, stats->dl.total_bytes);
-    stroff+=sprintf(output+stroff,"UE %04x: ulsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", ulsch_DTX %d, ulsch_errors %"PRIu64", BLER %.5f MCS %d\n",
-                    UE->rnti,
-                    stats->ul.rounds[0], stats->ul.rounds[1],
-                    stats->ul.rounds[2], stats->ul.rounds[3],
-                    stats->ulsch_DTX,
-                    stats->ul.errors,
-                    sched_ctrl->ul_bler_stats.bler,
-                    sched_ctrl->ul_bler_stats.mcs);
-    stroff+=sprintf(output+stroff,
-                    "UE %04x: ulsch_total_bytes_scheduled %"PRIu64", ulsch_total_bytes_received %"PRIu64"\n",
-                    UE->rnti,
-                    stats->ulsch_total_bytes_scheduled, stats->ul.total_bytes);
+    output += snprintf(output,
+                       end - output,
+                       "UE %04x: dlsch_total_bytes %"PRIu64"\n",
+                       UE->rnti,
+                       stats->dl.total_bytes);
+    output += snprintf(output,
+                       end - output,
+                       "UE %04x: ulsch_rounds %"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64", ulsch_DTX %d, ulsch_errors %"PRIu64", BLER %.5f MCS %d\n",
+                       UE->rnti,
+                       stats->ul.rounds[0], stats->ul.rounds[1],
+                       stats->ul.rounds[2], stats->ul.rounds[3],
+                       stats->ulsch_DTX,
+                       stats->ul.errors,
+                       sched_ctrl->ul_bler_stats.bler,
+                       sched_ctrl->ul_bler_stats.mcs);
+    output += snprintf(output,
+                       end - output,
+                      "UE %04x: ulsch_total_bytes_scheduled %"PRIu64", ulsch_total_bytes_received %"PRIu64"\n",
+                      UE->rnti,
+                      stats->ulsch_total_bytes_scheduled, stats->ul.total_bytes);
     for (int lc_id = 0; lc_id < 63; lc_id++) {
-      if (stats->dl.lc_bytes[lc_id] > 0) {
-        stroff+=sprintf(output+stroff, "UE %04x: LCID %d: %"PRIu64" bytes TX\n", UE->rnti, lc_id, stats->dl.lc_bytes[lc_id]);
-	LOG_D(NR_MAC, "UE %04x: LCID %d: %"PRIu64" bytes TX\n", UE->rnti, lc_id, stats->dl.lc_bytes[lc_id]);
-      }
-      if (stats->ul.lc_bytes[lc_id] > 0) {
-        stroff+=sprintf(output+stroff, "UE %04x: LCID %d: %"PRIu64" bytes RX\n", UE->rnti, lc_id, stats->ul.lc_bytes[lc_id]);
-	LOG_D(NR_MAC, "UE %04x: LCID %d: %"PRIu64" bytes RX\n", UE->rnti, lc_id, stats->ul.lc_bytes[lc_id]);
-
-      }
+      if (stats->dl.lc_bytes[lc_id] > 0)
+        output += snprintf(output,
+                           end - output,
+                           "UE %04x: LCID %d: %"PRIu64" bytes TX\n",
+                           UE->rnti,
+                           lc_id,
+                           stats->dl.lc_bytes[lc_id]);
+      if (stats->ul.lc_bytes[lc_id] > 0)
+        output += snprintf(output,
+                           end - output,
+                           "UE %04x: LCID %d: %"PRIu64" bytes RX\n",
+                           UE->rnti,
+                           lc_id,
+                           stats->ul.lc_bytes[lc_id]);
     }
   }
   pthread_mutex_unlock(&gNB->UE_info.mutex);
-  print_meas(&gNB->eNB_scheduler, "DL & UL scheduling timing stats", NULL, NULL);
-  print_meas(&gNB->schedule_dlsch,"dlsch scheduler",NULL,NULL);
-  print_meas(&gNB->rlc_data_req, "rlc_data_req",NULL,NULL);
-  print_meas(&gNB->rlc_status_ind,"rlc_status_ind",NULL,NULL);
+  return output - begin;
 }
 
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index ff66f8ab6368fba8c67f8e6c431ec7e350437211..afc441c29d0699fa896662ff5b40acc7d5ed27c6 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -756,7 +756,7 @@ typedef struct gNB_MAC_INST_s {
   nfapi_nr_ul_dci_request_t         UL_dci_req[NFAPI_CC_MAX];
   /// NFAPI DL PDU structure
   nfapi_nr_tx_data_request_t        TX_req[NFAPI_CC_MAX];
-  int pdcch_cand[MAX_NUM_CORESET];
+
   NR_UEs_t UE_info;
 
   /// UL handle
diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
index 8d4de8823bca20f5cd9a365e4c3246a2a9b9b516..ac0e48a91073db86c74f50a7eb22378e53b5d090 100644
--- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
@@ -77,7 +77,7 @@ void handle_nr_rach(NR_UL_IND_t *UL_info)
   bool in_timewindow = frame_diff == 0 || (frame_diff == 1 && UL_info->slot < 7);
 
   if (UL_info->rach_ind.number_of_pdus > 0 && in_timewindow) {
-    LOG_D(MAC,"UL_info[Frame %d, Slot %d] Calling initiate_ra_proc RACH:SFN/SLOT:%d/%d\n",
+    LOG_A(MAC,"UL_info[Frame %d, Slot %d] Calling initiate_ra_proc RACH:SFN/SLOT:%d/%d\n",
           UL_info->frame, UL_info->slot, UL_info->rach_ind.sfn, UL_info->rach_ind.slot);
     for (int i = 0; i < UL_info->rach_ind.number_of_pdus; i++) {
       UL_info->rach_ind.number_of_pdus--;
diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c
index 36d45a490548735170a7d2c011cdf57b231703f6..c332bd703a44c0fa71f581d6ab1f6bac15f59503 100755
--- a/openair2/RRC/NR/MESSAGES/asn1_msg.c
+++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c
@@ -1041,61 +1041,8 @@ void fill_default_downlinkBWP(NR_BWP_Downlink_t *bwp,
   int curr_bwp = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,MAX_BWP_SIZE);
 
   NR_ControlResourceSet_t *coreset = calloc(1,sizeof(*coreset));
-  coreset->controlResourceSetId=(bwp->bwp_Id<<1); // To uniquely identify each Coreset lets derive it from the BWPId
-  // frequency domain resources depends on BWP size
-  // options are 24, 48 or 96
-  coreset->frequencyDomainResources.buf = calloc(1,6);
-  if (0) {
-    if (curr_bwp < 48)
-      coreset->frequencyDomainResources.buf[0] = 0xf0;
-    else
-      coreset->frequencyDomainResources.buf[0] = 0xff;
-    if (curr_bwp < 96)
-      coreset->frequencyDomainResources.buf[1] = 0;
-    else
-      coreset->frequencyDomainResources.buf[1] = 0xff;
-  } else {
-    coreset->frequencyDomainResources.buf[0] = 0xf0;
-    coreset->frequencyDomainResources.buf[1] = 0;
-  }
-  coreset->frequencyDomainResources.buf[2] = 0;
-  coreset->frequencyDomainResources.buf[3] = 0;
-  coreset->frequencyDomainResources.buf[4] = 0;
-  coreset->frequencyDomainResources.buf[5] = 0;
-  coreset->frequencyDomainResources.size = 6;
-  coreset->frequencyDomainResources.bits_unused = 3;
-  coreset->duration=1;
-  coreset->cce_REG_MappingType.present = NR_ControlResourceSet__cce_REG_MappingType_PR_nonInterleaved;
-  coreset->precoderGranularity = NR_ControlResourceSet__precoderGranularity_sameAsREG_bundle;
-
-  coreset->tci_StatesPDCCH_ToAddList=calloc(1,sizeof(*coreset->tci_StatesPDCCH_ToAddList));
-  uint64_t bitmap=0;
-  switch (scc->ssb_PositionsInBurst->present) {
-    case 1 :
-      bitmap = ((uint64_t) scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0])<<56;
-      break;
-    case 2 :
-      bitmap = ((uint64_t) scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0])<<56;
-      break;
-    case 3 :
-      for (int i=0; i<8; i++) {
-        bitmap |= (((uint64_t) scc->ssb_PositionsInBurst->choice.longBitmap.buf[i])<<((7-i)*8));
-      }
-      break;
-    default:
-      AssertFatal(1==0,"SSB bitmap size value %d undefined (allowed values 1,2,3) \n", scc->ssb_PositionsInBurst->present);
-  }
-  NR_TCI_StateId_t *tci[64];
-  for (int i=0;i<64;i++) {
-    if ((bitmap>>(63-i))&0x01){
-      tci[i]=calloc(1,sizeof(*tci[i]));
-      *tci[i] = i;
-      ASN_SEQUENCE_ADD(&coreset->tci_StatesPDCCH_ToAddList->list,tci[i]);
-    }
-  }
-  coreset->tci_StatesPDCCH_ToReleaseList = NULL;
-  coreset->tci_PresentInDCI = NULL;
-  coreset->pdcch_DMRS_ScramblingID = NULL;
+  uint64_t bitmap = get_ssb_bitmap(scc);
+  rrc_coreset_config(coreset, bwp->bwp_Id, curr_bwp, bitmap);
 
   bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet = coreset;
   bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->searchSpaceZero=NULL;
@@ -1153,36 +1100,7 @@ void fill_default_downlinkBWP(NR_BWP_Downlink_t *bwp,
   bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList = calloc(1,sizeof(*bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList));
 
   NR_ControlResourceSet_t *coreset2 = calloc(1,sizeof(*coreset2));
-  coreset2->controlResourceSetId=(bwp->bwp_Id<<1)+1; // To uniquely identify each Coreset lets derive it from the BWPId
-  // frequency domain resources depends on BWP size
-  // options are 24, 48 or 96
-  coreset2->frequencyDomainResources.buf = calloc(1,6);
-  if (0) {
-    if (curr_bwp < 48)
-      coreset2->frequencyDomainResources.buf[0] = 0xf0;
-    else
-      coreset2->frequencyDomainResources.buf[0] = 0xff;
-    if (curr_bwp < 96)
-      coreset2->frequencyDomainResources.buf[1] = 0;
-    else
-      coreset2->frequencyDomainResources.buf[1] = 0xff;
-  } else {
-    coreset2->frequencyDomainResources.buf[0] = 0xf0;
-    coreset2->frequencyDomainResources.buf[1] = 0;
-  }
-  coreset2->frequencyDomainResources.buf[2] = 0;
-  coreset2->frequencyDomainResources.buf[3] = 0;
-  coreset2->frequencyDomainResources.buf[4] = 0;
-  coreset2->frequencyDomainResources.buf[5] = 0;
-  coreset2->frequencyDomainResources.size = 6;
-  coreset2->frequencyDomainResources.bits_unused = 3;
-  coreset2->duration=1;
-  coreset2->cce_REG_MappingType.present = NR_ControlResourceSet__cce_REG_MappingType_PR_nonInterleaved;
-  coreset2->precoderGranularity = NR_ControlResourceSet__precoderGranularity_sameAsREG_bundle;
-  coreset2->tci_StatesPDCCH_ToAddList=NULL;
-  coreset2->tci_StatesPDCCH_ToReleaseList = NULL;
-  coreset2->tci_PresentInDCI = NULL;
-  coreset2->pdcch_DMRS_ScramblingID = NULL;
+  rrc_coreset_config(coreset2, bwp->bwp_Id, curr_bwp, bitmap);
   ASN_SEQUENCE_ADD(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list, coreset2);
 
   bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList = calloc(1,sizeof(*bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList));
@@ -1832,37 +1750,9 @@ void fill_initial_SpCellConfig(int uid,
   bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList = calloc(1,sizeof(*bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList));
 
   NR_ControlResourceSet_t *coreset = calloc(1,sizeof(*coreset));
-  coreset->controlResourceSetId=1;
-  // frequency domain resources depends on BWP size
-  // options are 24, 48 or 96
-  coreset->frequencyDomainResources.buf = calloc(1,6);
-  if (0) {
-     if (curr_bwp < 48)
-       coreset->frequencyDomainResources.buf[0] = 0xf0;
-     else
-       coreset->frequencyDomainResources.buf[0] = 0xff;
-     if (curr_bwp < 96)
-       coreset->frequencyDomainResources.buf[1] = 0;
-     else
-       coreset->frequencyDomainResources.buf[1] = 0xff;
-  } else {
-     coreset->frequencyDomainResources.buf[0] = 0xf0;
-     coreset->frequencyDomainResources.buf[1] = 0;
-  }
-  coreset->frequencyDomainResources.buf[2] = 0;
-  coreset->frequencyDomainResources.buf[3] = 0;
-  coreset->frequencyDomainResources.buf[4] = 0;
-  coreset->frequencyDomainResources.buf[5] = 0;
-  coreset->frequencyDomainResources.size = 6;
-  coreset->frequencyDomainResources.bits_unused = 3;
-  coreset->duration=1;
-  coreset->cce_REG_MappingType.present = NR_ControlResourceSet__cce_REG_MappingType_PR_nonInterleaved;
-  coreset->precoderGranularity = NR_ControlResourceSet__precoderGranularity_sameAsREG_bundle;
-
-  coreset->tci_StatesPDCCH_ToAddList=NULL;
-  coreset->tci_StatesPDCCH_ToReleaseList = NULL;
-  coreset->tci_PresentInDCI = NULL;
-  coreset->pdcch_DMRS_ScramblingID = NULL;
+
+  uint64_t bitmap = get_ssb_bitmap(scc);
+  rrc_coreset_config(coreset, 0, curr_bwp, bitmap);
 
   ASN_SEQUENCE_ADD(&bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list,
                    coreset);
@@ -1873,7 +1763,7 @@ void fill_initial_SpCellConfig(int uid,
  
   ss2->searchSpaceId=2;
   ss2->controlResourceSetId=calloc(1,sizeof(*ss2->controlResourceSetId));
-  *ss2->controlResourceSetId=1;
+  *ss2->controlResourceSetId=coreset->controlResourceSetId;
   ss2->monitoringSlotPeriodicityAndOffset=calloc(1,sizeof(*ss2->monitoringSlotPeriodicityAndOffset));
   ss2->monitoringSlotPeriodicityAndOffset->present = NR_SearchSpace__monitoringSlotPeriodicityAndOffset_PR_sl1;
   ss2->monitoringSlotPeriodicityAndOffset->choice.sl1=(NULL_t)0;
diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c
index c89761e5c7edaeedf5d37bc48a6928e924f53958..6b82fec20d41ba9fdf42c688c7e4b2a9a24d6431 100644
--- a/openair2/RRC/NR/nr_rrc_config.c
+++ b/openair2/RRC/NR/nr_rrc_config.c
@@ -34,6 +34,63 @@
 const uint8_t slotsperframe[5] = {10, 20, 40, 80, 160};
 
 
+void rrc_coreset_config(NR_ControlResourceSet_t *coreset,
+                        int bwp_id,
+                        int curr_bwp,
+                        uint64_t ssb_bitmap) {
+
+
+  // frequency domain resources depending on BWP size
+  coreset->frequencyDomainResources.buf = calloc(1,6);
+  coreset->frequencyDomainResources.buf[0] = (curr_bwp < 48) ? 0xf0 : 0xff;
+  coreset->frequencyDomainResources.buf[1] = (curr_bwp < 96) ? 0x00 : 0xff;
+  coreset->frequencyDomainResources.buf[2] = (curr_bwp < 144) ? 0x00 : 0xff;
+  coreset->frequencyDomainResources.buf[3] = (curr_bwp < 192) ? 0x00 : 0xff;
+  coreset->frequencyDomainResources.buf[4] = (curr_bwp < 240) ? 0x00 : 0xff;
+  coreset->frequencyDomainResources.buf[5] = 0x00;
+  coreset->frequencyDomainResources.size = 6;
+  coreset->frequencyDomainResources.bits_unused = 3;
+  coreset->duration = (curr_bwp < 48) ? 2 : 1;
+  coreset->cce_REG_MappingType.present = NR_ControlResourceSet__cce_REG_MappingType_PR_nonInterleaved;
+  coreset->precoderGranularity = NR_ControlResourceSet__precoderGranularity_sameAsREG_bundle;
+
+  // The ID space is used across the BWPs of a Serving Cell as per 38.331
+  coreset->controlResourceSetId = bwp_id + 1;
+
+  coreset->tci_StatesPDCCH_ToAddList=calloc(1,sizeof(*coreset->tci_StatesPDCCH_ToAddList));
+  NR_TCI_StateId_t *tci[64];
+  for (int i=0;i<64;i++) {
+    if ((ssb_bitmap>>(63-i))&0x01){
+      tci[i]=calloc(1,sizeof(*tci[i]));
+      *tci[i] = i;
+      ASN_SEQUENCE_ADD(&coreset->tci_StatesPDCCH_ToAddList->list,tci[i]);
+    }
+  }
+  coreset->tci_StatesPDCCH_ToReleaseList = NULL;
+  coreset->tci_PresentInDCI = NULL;
+  coreset->pdcch_DMRS_ScramblingID = NULL;
+}
+
+uint64_t get_ssb_bitmap(NR_ServingCellConfigCommon_t *scc) {
+  uint64_t bitmap=0;
+  switch (scc->ssb_PositionsInBurst->present) {
+    case 1 :
+      bitmap = ((uint64_t) scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0])<<56;
+      break;
+    case 2 :
+      bitmap = ((uint64_t) scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0])<<56;
+      break;
+    case 3 :
+      for (int i=0; i<8; i++) {
+        bitmap |= (((uint64_t) scc->ssb_PositionsInBurst->choice.longBitmap.buf[i])<<((7-i)*8));
+      }
+      break;
+    default:
+      AssertFatal(1==0,"SSB bitmap size value %d undefined (allowed values 1,2,3) \n", scc->ssb_PositionsInBurst->present);
+  }
+  return bitmap;
+}
+
 void set_csirs_periodicity(NR_NZP_CSI_RS_Resource_t *nzpcsi0, int uid, int nb_slots_per_period) {
 
   nzpcsi0->periodicityAndOffset = calloc(1,sizeof(*nzpcsi0->periodicityAndOffset));
diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h
index 3d241640b319fa18e493bf5c5071abc990aa240c..dfddafb229bb83ce150a359af244f07c9a4b207a 100644
--- a/openair2/RRC/NR/nr_rrc_config.h
+++ b/openair2/RRC/NR/nr_rrc_config.h
@@ -111,6 +111,11 @@ typedef struct physicalcellgroup_s{
   long        RNTI_Value[MAX_NUM_CCs];
 }physicalcellgroup_t;
 
+uint64_t get_ssb_bitmap(NR_ServingCellConfigCommon_t *scc);
+void rrc_coreset_config(NR_ControlResourceSet_t *coreset,
+                        int bwp_id,
+                        int curr_bwp,
+                        uint64_t ssb_bitmap);
 void nr_rrc_config_dl_tda(NR_ServingCellConfigCommon_t *scc,
                           NR_PDSCH_TimeDomainResourceAllocationList_t	*pdsch_TimeDomainAllocationList,
                           int curr_bwp);
diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c
index de62035b4889748bd27462f96866e86647838053..0118778582d93feaf09aac3ab450b3a931c21335 100644
--- a/openair2/RRC/NR/rrc_gNB_reconfig.c
+++ b/openair2/RRC/NR/rrc_gNB_reconfig.c
@@ -119,39 +119,7 @@ void fill_default_nsa_downlinkBWP(NR_BWP_Downlink_t *bwp,
   int curr_bwp = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,275);
 
   NR_ControlResourceSet_t *coreset = calloc(1,sizeof(*coreset));
-  coreset->controlResourceSetId=bwp->bwp_Id+1; // To uniquely identify each Coreset lets derive it from the BWPId
-  // frequency domain resources depends on BWP size
-  // options are 24, 48 or 96
-  coreset->frequencyDomainResources.buf = calloc(1,6);
-  if (curr_bwp < 48)
-    coreset->frequencyDomainResources.buf[0] = 0xf0;
-  else
-    coreset->frequencyDomainResources.buf[0] = 0xff;
-  if (curr_bwp < 96)
-    coreset->frequencyDomainResources.buf[1] = 0;
-  else
-    coreset->frequencyDomainResources.buf[1] = 0xff;
-  coreset->frequencyDomainResources.buf[2] = 0;
-  coreset->frequencyDomainResources.buf[3] = 0;
-  coreset->frequencyDomainResources.buf[4] = 0;
-  coreset->frequencyDomainResources.buf[5] = 0;
-  coreset->frequencyDomainResources.size = 6;
-  coreset->frequencyDomainResources.bits_unused = 3;
-  coreset->duration=1;
-  coreset->cce_REG_MappingType.present = NR_ControlResourceSet__cce_REG_MappingType_PR_nonInterleaved;
-  coreset->precoderGranularity = NR_ControlResourceSet__precoderGranularity_sameAsREG_bundle;
-  coreset->tci_StatesPDCCH_ToAddList=calloc(1,sizeof(*coreset->tci_StatesPDCCH_ToAddList));
-  NR_TCI_StateId_t *tci[64];
-  for (int i=0;i<64;i++) {
-    if ((bitmap>>(63-i))&0x01){
-      tci[i]=calloc(1,sizeof(*tci[i]));
-      *tci[i] = i;
-      ASN_SEQUENCE_ADD(&coreset->tci_StatesPDCCH_ToAddList->list,tci[i]);
-    }
-  }
-  coreset->tci_StatesPDCCH_ToReleaseList = NULL;
-  coreset->tci_PresentInDCI = NULL;
-  coreset->pdcch_DMRS_ScramblingID = NULL;
+  rrc_coreset_config(coreset, bwp->bwp_Id, curr_bwp, bitmap);
   bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet = coreset;
 
   bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->searchSpaceZero=NULL;
@@ -663,25 +631,9 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
   // where the startPosition = 2 or 3 and sl160 = 17, 17, 27 ... 157 only give us 30 different allocations.
   AssertFatal(uid>=0 && uid<30, "gNB cannot allocate the SRS resources\n");
 
+  uint64_t bitmap = get_ssb_bitmap(servingcellconfigcommon);
   fix_servingcellconfigdedicated(servingcellconfigdedicated);
 
-  uint64_t bitmap=0;
-  switch (servingcellconfigcommon->ssb_PositionsInBurst->present) {
-    case 1 :
-      bitmap = ((uint64_t) servingcellconfigcommon->ssb_PositionsInBurst->choice.shortBitmap.buf[0])<<56;
-      break;
-    case 2 :
-      bitmap = ((uint64_t) servingcellconfigcommon->ssb_PositionsInBurst->choice.mediumBitmap.buf[0])<<56;
-      break;
-    case 3 :
-      for (int i=0; i<8; i++) {
-        bitmap |= (((uint64_t) servingcellconfigcommon->ssb_PositionsInBurst->choice.longBitmap.buf[i])<<((7-i)*8));
-      }
-      break;
-    default:
-      AssertFatal(1==0,"SSB bitmap size value %d undefined (allowed values 1,2,3) \n", servingcellconfigcommon->ssb_PositionsInBurst->present);
-  }
-
   memset(secondaryCellGroup,0,sizeof(NR_CellGroupConfig_t));
   secondaryCellGroup->cellGroupId = scg_id;
   NR_RLC_BearerConfig_t *RLC_BearerConfig = calloc(1,sizeof(*RLC_BearerConfig));
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 1773e1fb7921be8a563c70001243c37e547b2e44..909c54b858b5042ce33a250132cdaa7dbf881365 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
@@ -182,11 +182,11 @@ gNBs =
 );
 
 MACRLCs = (
-	{
-	num_cc = 1;
-	tr_s_preference = "local_L1";
-	tr_n_preference = "local_RRC";
-	}
+  {
+  num_cc = 1;
+  tr_s_preference = "local_L1";
+  tr_n_preference = "local_RRC";
+  }
 );
 
 L1s = (
@@ -194,6 +194,7 @@ L1s = (
   num_cc = 1;
   tr_n_preference = "local_mac";
   thread_pool_size = 8;
+  max_ldpc_iterations = 5;
   ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
 }
 );