diff --git a/ci-scripts/args_parse.py b/ci-scripts/args_parse.py
index cc2a473be417170d10173d7faa1027dfc6c53536..18aa047e7c0989b564bcae8cd62e5b4f3f26897c 100644
--- a/ci-scripts/args_parse.py
+++ b/ci-scripts/args_parse.py
@@ -40,7 +40,7 @@ import constants as CONST
 #-----------------------------------------------------------
 
 
-def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
+def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP):
 
 
     py_param_file_present = False
@@ -78,6 +78,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
             RAN.ranRepository=matchReg.group(1)
             HTML.ranRepository=matchReg.group(1)
             ldpc.ranRepository=matchReg.group(1)
+            CONTAINERS.ranRepository=matchReg.group(1)
         elif re.match('^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE)
@@ -89,6 +90,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
                 CiTestObj.ranAllowMerge = True
                 RAN.ranAllowMerge=True
                 HTML.ranAllowMerge=True
+                CONTAINERS.ranAllowMerge=True
         elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE)
@@ -98,6 +100,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
             RAN.ranBranch=matchReg.group(1)
             HTML.ranBranch=matchReg.group(1)
             ldpc.ranBranch=matchReg.group(1)
+            CONTAINERS.ranBranch=matchReg.group(1)
         elif re.match('^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE)
@@ -107,6 +110,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
             RAN.ranCommitID=matchReg.group(1)
             HTML.ranCommitID=matchReg.group(1)
             ldpc.ranCommitID=matchReg.group(1)
+            CONTAINERS.ranCommitID=matchReg.group(1)
         elif re.match('^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE)
@@ -116,50 +120,63 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,HELP):
             RAN.ranTargetBranch=matchReg.group(1)
             HTML.ranTargetBranch=matchReg.group(1)
             ldpc.ranTargetBranch=matchReg.group(1)
+            CONTAINERS.ranTargetBranch=matchReg.group(1)
         elif re.match('^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNBIPAddress=matchReg.group(1)
                 ldpc.eNBIpAddr=matchReg.group(1)
+                CONTAINERS.eNBIPAddress=matchReg.group(1)
             elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1IPAddress=matchReg.group(1)
+                CONTAINERS.eNB1IPAddress=matchReg.group(1)
             elif re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB2IPAddress=matchReg.group(1)
+                CONTAINERS.eNB2IPAddress=matchReg.group(1)
         elif re.match('^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNBUserName=matchReg.group(1)
                 ldpc.eNBUserName=matchReg.group(1)
+                CONTAINERS.eNBUserName=matchReg.group(1)
             elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1UserName=matchReg.group(1)
+                CONTAINERS.eNB1UserName=matchReg.group(1)
             elif re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB2UserName=matchReg.group(1)
+                CONTAINERS.eNB2UserName=matchReg.group(1)
         elif re.match('^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNBPassword=matchReg.group(1)
                 ldpc.eNBPassWord=matchReg.group(1)
+                CONTAINERS.eNBPassword=matchReg.group(1)
             elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1Password=matchReg.group(1)
+                CONTAINERS.eNB1Password=matchReg.group(1)
             elif re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB2Password=matchReg.group(1)
+                CONTAINERS.eNB2Password=matchReg.group(1)
         elif re.match('^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNBSourceCodePath=matchReg.group(1)
                 ldpc.eNBSourceCodePath=matchReg.group(1)
+                CONTAINERS.eNBSourceCodePath=matchReg.group(1)
             elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1SourceCodePath=matchReg.group(1)
+                CONTAINERS.eNB1SourceCodePath=matchReg.group(1)
             elif re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB2SourceCodePath=matchReg.group(1)
+                CONTAINERS.eNB2SourceCodePath=matchReg.group(1)
         elif re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE):
             matchReg = re.match('^\-\-EPCIPAddress=(.+)$', myArgv, re.IGNORECASE)
             EPC.IPAddress=matchReg.group(1)
diff --git a/ci-scripts/build_fr1_from_yaml.py b/ci-scripts/build_fr1_from_yaml.py
new file mode 100755
index 0000000000000000000000000000000000000000..a5492df6f6bc2d009ce010965c99a407a096081e
--- /dev/null
+++ b/ci-scripts/build_fr1_from_yaml.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jul  7 23:04:51 2020
+
+@author: hardy
+"""
+
+
+
+import yaml
+import sys
+import subprocess
+
+      
+
+def main():
+  f_yaml=sys.argv[1]
+  f_sh=sys.argv[2]
+  #filename='py_params_template.yaml'
+  with open(f_yaml,'r') as file:
+    # The FullLoader parameter handles the conversion from YAML
+    # scalar values to Python the dictionary format
+    print('Loading '+f_yaml)
+    params = yaml.load(file,Loader=yaml.FullLoader)
+
+
+  with open(f_sh,'w') as f:
+    f.write('#!/bin/sh\n')
+    for i in range (0, len(params['steps'])):
+      step=params['steps'][i].split(',')
+      mode=step[0]
+      f_xml=step[1]
+      line='python3 main.py ' + \
+           '--mode='+ mode + ' ' + \
+           '--ranRepository=' + params['ranRepository'] + ' ' + \
+           '--ranBranch=' + params['ranBranch'] + ' ' + \
+           '--ranCommitID=' + params['ranCommitID'] + ' ' + \
+           '--ranAllowMerge=' + params['ranAllowMerge'] + ' ' + \
+           '--ranTargetBranch=' + params['ranTargetBranch'] + ' ' + \
+           \
+           '--ADBIPAddress=' + params['ADB']['ADBIPAddress'] + ' ' + \
+           '--ADBUserName=' + params['ADB']['ADBUserName'] + ' ' + \
+           '--ADBPassword=' + params['ADB']['ADBPassword'] + ' ' + \
+           \
+           '--UEIPAddress=' + params['UE']['UEIPAddress'] + ' ' + \
+           '--UEUserName=' + params['UE']['UEUserName'] + ' ' + \
+           '--UEPassword=' + params['UE']['UEPassword'] + ' ' + \
+           '--UESourceCodePath=' + params['UE']['UESourceCodePath'] + ' ' + \
+           \
+           '--EPCIPAddress=' + params['EPC']['EPCIPAddress'] + ' ' + \
+           '--EPCUserName=' + params['EPC']['EPCUserName'] + ' ' + \
+           '--EPCPassword=' + params['EPC']['EPCPassword'] + ' ' + \
+           '--EPCSourceCodePath=' + params['EPC']['EPCSourceCodePath'] + ' ' + \
+           '--EPCType=' + params['EPC']['EPCType'] + ' ' + \
+           \
+           '--eNBIPAddress=' + params['RAN'][0]['eNBIPAddress'] + ' ' + \
+           '--eNBUserName=' + params['RAN'][0]['eNBUserName'] + ' ' + \
+           '--eNBPassword=' + params['RAN'][0]['eNBPassword'] + ' ' + \
+           '--eNBSourceCodePath=' + params['RAN'][0]['eNBSourceCodePath'] + ' ' + \
+           \
+           '--eNB1IPAddress=' + params['RAN'][1]['eNB1IPAddress'] + ' ' + \
+           '--eNB1UserName=' + params['RAN'][1]['eNB1UserName'] + ' ' + \
+           '--eNB1Password=' + params['RAN'][1]['eNB1Password'] + ' ' + \
+           '--eNB1SourceCodePath=' + params['RAN'][1]['eNB1SourceCodePath'] + ' '
+      if mode!="InitiateHtml":
+         line+='--XMLTestFile=' + f_xml
+      #if mode is InitiateHTML we have a special processing to mention all xml files from the list
+      #loop starting at 1 to avoid the xml file mentioned with InitiateHtml in yaml file (file is none)
+      else:
+         for i in range (1, len(params['steps'])):
+            step=params['steps'][i].split(',')
+            f_xml=step[1]
+            line+='--XMLTestFile=' + f_xml+' '
+      line+='\n'
+      print(line)
+      f.write(line)
+  subprocess.call(['chmod','777',f_sh])
+
+if __name__ == "__main__":
+    main()
+
+
diff --git a/ci-scripts/build_fr1_template.yaml b/ci-scripts/build_fr1_template.yaml
new file mode 100755
index 0000000000000000000000000000000000000000..2a8f9cc6a02a3e7a798f90c6d0a9f02c292fbf7f
--- /dev/null
+++ b/ci-scripts/build_fr1_template.yaml
@@ -0,0 +1,46 @@
+
+ranRepository : https://gitlab.eurecom.fr/oai/openairinterface5g.git
+ranBranch : BRANCH_NAME 
+ranCommitID : COMMIT_ID 
+ranAllowMerge : 'true' 
+ranTargetBranch : develop
+
+steps:
+  - InitiateHtml,none
+  - TesteNB,xml_files/fr1_multi_node_build.xml
+  - TesteNB,xml_files/fr1_epc_start.xml
+  - TesteNB,xml_files/fr1_ran_ue_base.xml #ue toggle, nodes initialize, ue toggle, ping, nodes terminate
+  - TesteNB,xml_files/fr1_epc_closure.xml
+
+
+ADB: #on Caracal
+  ADBIPAddress : 192.168.18.196
+  ADBUserName : oaici
+  ADBPassword : KkexF6CErOi1fNuebCPsuIVK
+
+RAN:
+    - eNBIPAddress : 192.168.18.199 #eNB on Minimassive
+      eNBUserName : oaicicd
+      eNBPassword : HzB*nkryaITdVd08TKlT#2Z5a!7M#~qn
+      eNBSourceCodePath : /tmp/CI-FR1-eNB
+    - eNB1IPAddress : 192.168.18.198 #gNB on Mozart
+      eNB1UserName : oaicicd
+      eNB1Password : 7zkDOFgh@w3HvRBMPTMh@BAx
+      eNB1SourceCodePath : /tmp/CI-FR1-gNB
+
+
+EPC: #on Nikaia 
+  EPCIPAddress : 192.168.18.99
+  EPCUserName : nikaia
+  EPCPassword : linux
+  EPCSourceCodePath : /tmp/CI-FR1-EPC
+  EPCType : ltebox
+
+
+UE:
+  UEIPAddress : none
+  UEUserName : none
+  UEPassword : none
+  UESourceCodePath : none
+
+
diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f95d2602f5daa0f0defea20f77af09f911f014f
--- /dev/null
+++ b/ci-scripts/cls_containerize.py
@@ -0,0 +1,410 @@
+#/*
+# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+# * contributor license agreements.  See the NOTICE file distributed with
+# * this work for additional information regarding copyright ownership.
+# * The OpenAirInterface Software Alliance licenses this file to You under
+# * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+# * except in compliance with the License.
+# * You may obtain a copy of the License at
+# *
+# *      http://www.openairinterface.org/?page_id=698
+# *
+# * Unless required by applicable law or agreed to in writing, software
+# * distributed under the License is distributed on an "AS IS" BASIS,
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# * See the License for the specific language governing permissions and
+# * limitations under the License.
+# *-------------------------------------------------------------------------------
+# * For more information about the OpenAirInterface (OAI) Software Alliance:
+# *      contact@openairinterface.org
+# */
+#---------------------------------------------------------------------
+# Python for CI of OAI-eNB + COTS-UE
+#
+#   Required Python Version
+#     Python 3.x
+#
+#   Required Python Package
+#     pexpect
+#---------------------------------------------------------------------
+
+#-----------------------------------------------------------
+# Import
+#-----------------------------------------------------------
+import sys              # arg
+import re               # reg
+import logging
+import os
+import time
+from multiprocessing import Process, Lock, SimpleQueue
+
+#-----------------------------------------------------------
+# OAI Testing modules
+#-----------------------------------------------------------
+import sshconnection as SSH
+import helpreadme as HELP
+import constants as CONST
+
+#-----------------------------------------------------------
+# Class Declaration
+#-----------------------------------------------------------
+class Containerize():
+
+	def __init__(self):
+		
+		self.ranRepository = ''
+		self.ranBranch = ''
+		self.ranAllowMerge = False
+		self.ranCommitID = ''
+		self.ranTargetBranch = ''
+		self.eNBIPAddress = ''
+		self.eNBUserName = ''
+		self.eNBPassword = ''
+		self.eNBSourceCodePath = ''
+		self.eNB1IPAddress = ''
+		self.eNB1UserName = ''
+		self.eNB1Password = ''
+		self.eNB1SourceCodePath = ''
+		self.eNB2IPAddress = ''
+		self.eNB2UserName = ''
+		self.eNB2Password = ''
+		self.eNB2SourceCodePath = ''
+		self.forcedWorkspaceCleanup = False
+		self.imageKind = ''
+		self.eNB_instance = 0
+		self.eNB_serverId = ['', '', '']
+		self.yamlPath = ['', '', '']
+		self.eNB_logFile = ['', '', '']
+
+		self.testCase_id = ''
+
+		self.flexranCtrlDeployed = False
+		self.flexranCtrlIpAddress = ''
+
+#-----------------------------------------------------------
+# Container management functions
+#-----------------------------------------------------------
+
+	def BuildImage(self, HTML):
+		if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		if self.eNB_serverId[self.eNB_instance] == '0':
+			lIpAddr = self.eNBIPAddress
+			lUserName = self.eNBUserName
+			lPassWord = self.eNBPassword
+			lSourcePath = self.eNBSourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '1':
+			lIpAddr = self.eNB1IPAddress
+			lUserName = self.eNB1UserName
+			lPassWord = self.eNB1Password
+			lSourcePath = self.eNB1SourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '2':
+			lIpAddr = self.eNB2IPAddress
+			lUserName = self.eNB2UserName
+			lPassWord = self.eNB2Password
+			lSourcePath = self.eNB2SourceCodePath
+		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		logging.debug('Building on server: ' + lIpAddr)
+		mySSH = SSH.SSHConnection()
+		mySSH.open(lIpAddr, lUserName, lPassWord)
+
+		imageNames = []
+		result = re.search('eNB', self.imageKind)
+		# Creating a tupple with the imageName and the DockerFile prefix pattern
+		if result is not None:
+			imageNames.append(('oai-enb', 'eNB'))
+		else:
+			result = re.search('gNB', self.imageKind)
+			if result is not None:
+				imageNames.append(('oai-gnb', 'gNB'))
+			else:
+				result = re.search('all', self.imageKind)
+				if result is not None:
+					imageNames.append(('oai-enb', 'eNB'))
+					imageNames.append(('oai-gnb', 'gNB'))
+					imageNames.append(('oai-lte-ue', 'lteUE'))
+					imageNames.append(('oai-nr-ue', 'nrUE'))
+		if len(imageNames) == 0:
+			imageNames.append(('oai-enb', 'eNB'))
+		# Workaround for some servers, we need to erase completely the workspace
+		if self.forcedWorkspaceCleanup:
+			mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15)
+		self.testCase_id = HTML.testCase_id
+		# on RedHat/CentOS .git extension is mandatory
+		result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
+		if result is not None:
+			full_ran_repo_name = self.ranRepository
+		else:
+			full_ran_repo_name = self.ranRepository + '.git'
+		mySSH.command('mkdir -p ' + lSourcePath, '\$', 5)
+		mySSH.command('cd ' + lSourcePath, '\$', 5)
+		mySSH.command('if [ ! -e .git ]; then stdbuf -o0 git clone ' + full_ran_repo_name + ' .; else stdbuf -o0 git fetch --prune; fi', '\$', 600)
+		# Raphael: here add a check if git clone or git fetch went smoothly
+		mySSH.command('git config user.email "jenkins@openairinterface.org"', '\$', 5)
+		mySSH.command('git config user.name "OAI Jenkins"', '\$', 5)
+
+		mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30)
+		mySSH.command('mkdir -p cmake_targets/log', '\$', 5)
+		# if the commit ID is provided use it to point to it
+		if self.ranCommitID != '':
+			mySSH.command('git checkout -f ' + self.ranCommitID, '\$', 5)
+		# if the branch is not develop, then it is a merge request and we need to do 
+		# the potential merge. Note that merge conflicts should already been checked earlier
+		imageTag = 'develop'
+		if (self.ranAllowMerge):
+			imageTag = 'ci-temp'
+			if self.ranTargetBranch == '':
+				if (self.ranBranch != 'develop') and (self.ranBranch != 'origin/develop'):
+					mySSH.command('git merge --ff origin/develop -m "Temporary merge for CI"', '\$', 5)
+			else:
+				logging.debug('Merging with the target branch: ' + self.ranTargetBranch)
+				mySSH.command('git merge --ff origin/' + self.ranTargetBranch + ' -m "Temporary merge for CI"', '\$', 5)
+		# Let's remove any previous run artifacts if still there
+		mySSH.command('docker image prune --force', '\$', 5)
+		mySSH.command('docker image rm ran-build:' + imageTag, '\$', 5)
+		for image,pattern in imageNames:
+			mySSH.command('docker image rm ' + image + ':' + imageTag, '\$', 5)
+		# Build the shared image
+		mySSH.command('docker build --target ran-build --tag ran-build:' + imageTag + ' --file docker/Dockerfile.ran.ubuntu18 --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . > cmake_targets/log/ran-build.log 2>&1', '\$', 800)
+		# Build the target image(s)
+		previousImage='ran-build:' + imageTag
+		danglingShaOnes=[]
+		for image,pattern in imageNames:
+			# the archived Dockerfiles have "ran-build:latest" as base image
+			# we need to update them with proper tag
+			mySSH.command('sed -i -e "s#ran-build:latest#ran-build:' + imageTag + '#" docker/Dockerfile.' + pattern + '.ubuntu18', '\$', 5)
+			mySSH.command('docker build --target ' + image + ' --tag ' + image + ':' + imageTag + ' --file docker/Dockerfile.' + pattern + '.ubuntu18 . > cmake_targets/log/' + image + '.log 2>&1', '\$', 600)
+			# Retrieving the dangling image(s) for the log collection
+			mySSH.command('docker images --filter "dangling=true" --filter "since=' + previousImage + '" -q | sed -e "s#^#sha=#"', '\$', 5)
+			result = re.search('sha=(?P<imageShaOne>[a-zA-Z0-9\-\_]+)', mySSH.getBefore())
+			if result is not None:
+				danglingShaOnes.append((image, result.group('imageShaOne')))
+			previousImage=image + ':' + imageTag
+
+		imageTag = 'ci-temp'
+		# First verify if images were properly created.
+		status = True
+		mySSH.command('docker image inspect --format=\'Size = {{.Size}} bytes\' ran-build:' + imageTag, '\$', 5)
+		if mySSH.getBefore().count('No such object') != 0:
+			logging.error('Could not build properly ran-build')
+			status = False
+		else:
+			result = re.search('Size = (?P<size>[0-9\-]+) bytes', mySSH.getBefore())
+			if result is not None:
+				imageSize = float(result.group('size'))
+				imageSize = imageSize / 1000
+				if imageSize < 1000:
+					logging.debug('\u001B[1m   ran-build size is ' + ('%.0f' % imageSize) + ' kbytes\u001B[0m')
+				else:
+					imageSize = imageSize / 1000
+					if imageSize < 1000:
+						logging.debug('\u001B[1m   ran-build size is ' + ('%.0f' % imageSize) + ' Mbytes\u001B[0m')
+					else:
+						imageSize = imageSize / 1000
+						logging.debug('\u001B[1m   ran-build size is ' + ('%.3f' % imageSize) + ' Gbytes\u001B[0m')
+			else:
+				logging.debug('ran-build size is unknown')
+		for image,pattern in imageNames:
+			mySSH.command('docker image inspect --format=\'Size = {{.Size}} bytes\' ' + image + ':' + imageTag, '\$', 5)
+			if mySSH.getBefore().count('No such object') != 0:
+				logging.error('Could not build properly ' + image)
+				status = False
+			else:
+				result = re.search('Size = (?P<size>[0-9\-]+) bytes', mySSH.getBefore())
+				if result is not None:
+					imageSize = float(result.group('size'))
+					imageSize = imageSize / 1000
+					if imageSize < 1000:
+						logging.debug('\u001B[1m   ' + image + ' size is ' + ('%.0f' % imageSize) + ' kbytes\u001B[0m')
+					else:
+						imageSize = imageSize / 1000
+						if imageSize < 1000:
+							logging.debug('\u001B[1m   ' + image + ' size is ' + ('%.0f' % imageSize) + ' Mbytes\u001B[0m')
+						else:
+							imageSize = imageSize / 1000
+							logging.debug('\u001B[1m   ' + image + ' size is ' + ('%.3f' % imageSize) + ' Gbytes\u001B[0m')
+				else:
+					logging.debug('ran-build size is unknown')
+		if not status:
+			mySSH.close()
+			logging.error('\u001B[1m Building OAI Images Failed\u001B[0m')
+			HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK)
+			HTML.CreateHtmlTabFooter(False)
+			sys.exit(1)
+
+		# Recover build logs, for the moment only possible when build is successful
+		mySSH.command('docker create --name test ran-build:' + imageTag, '\$', 5)
+		mySSH.command('mkdir -p cmake_targets/log/ran-build', '\$', 5)
+		mySSH.command('docker cp test:/oai-ran/cmake_targets/log/. cmake_targets/log/ran-build', '\$', 5)
+		mySSH.command('docker rm -f test', '\$', 5)
+		for image,shaone in danglingShaOnes:
+			mySSH.command('mkdir -p cmake_targets/log/' + image, '\$', 5)
+			mySSH.command('docker create --name test ' + shaone, '\$', 5)
+			mySSH.command('docker cp test:/oai-ran/cmake_targets/log/. cmake_targets/log/' + image, '\$', 5)
+			mySSH.command('docker rm -f test', '\$', 5)
+		mySSH.command('docker image prune --force', '\$', 5)
+		mySSH.command('cd cmake_targets', '\$', 5)
+		mySSH.command('mkdir -p build_log_' + self.testCase_id, '\$', 5)
+		mySSH.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5)
+		mySSH.close()
+
+		logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m')
+		HTML.CreateHtmlTestRow(self.imageKind, 'OK', CONST.ALL_PROCESSES_OK)
+
+	def DeployObject(self, HTML, EPC):
+		if self.eNB_serverId[self.eNB_instance] == '0':
+			lIpAddr = self.eNBIPAddress
+			lUserName = self.eNBUserName
+			lPassWord = self.eNBPassword
+			lSourcePath = self.eNBSourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '1':
+			lIpAddr = self.eNB1IPAddress
+			lUserName = self.eNB1UserName
+			lPassWord = self.eNB1Password
+			lSourcePath = self.eNB1SourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '2':
+			lIpAddr = self.eNB2IPAddress
+			lUserName = self.eNB2UserName
+			lPassWord = self.eNB2Password
+			lSourcePath = self.eNB2SourceCodePath
+		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		logging.debug('\u001B[1m Deploying OAI Object on server: ' + lIpAddr + '\u001B[0m')
+		mySSH = SSH.SSHConnection()
+		mySSH.open(lIpAddr, lUserName, lPassWord)
+		# Putting the CPUs in a good state, we do that only on a few servers
+		mySSH.command('hostname', '\$', 5)
+		result = re.search('obelix|asterix',  mySSH.getBefore())
+		if result is not None:
+			mySSH.command('if command -v cpupower &> /dev/null; then echo ' + lPassWord + ' | sudo -S cpupower idle-set -D 0; fi', '\$', 5)
+			time.sleep(5)
+		
+		mySSH.command('cd ' + lSourcePath + '/' + self.yamlPath[self.eNB_instance], '\$', 5)
+		mySSH.command('cp docker-compose.yml ci-docker-compose.yml', '\$', 5)
+		imageTag = 'develop'
+		if (self.ranAllowMerge):
+			imageTag = 'ci-temp'
+		mySSH.command('sed -i -e "s/image: oai-enb:latest/image: oai-enb:' + imageTag + '/" ci-docker-compose.yml', '\$', 2)
+		localMmeIpAddr = EPC.MmeIPAddress
+		mySSH.command('sed -i -e "s/CI_MME_IP_ADDR/' + localMmeIpAddr + '/" ci-docker-compose.yml', '\$', 2)
+		if self.flexranCtrlDeployed:
+			mySSH.command('sed -i -e \'s/FLEXRAN_ENABLED:.*/FLEXRAN_ENABLED: "yes"/\' ci-docker-compose.yml', '\$', 2)
+			mySSH.command('sed -i -e "s/CI_FLEXRAN_CTL_IP_ADDR/' + self.flexranCtrlIpAddress + '/" ci-docker-compose.yml', '\$', 2)
+		else:
+			mySSH.command('sed -i -e "s/FLEXRAN_ENABLED:.*$/FLEXRAN_ENABLED: \"no\"/" ci-docker-compose.yml', '\$', 2)
+			mySSH.command('sed -i -e "s/CI_FLEXRAN_CTL_IP_ADDR/127.0.0.1/" ci-docker-compose.yml', '\$', 2)
+		# Currently support only one
+		mySSH.command('docker-compose --file ci-docker-compose.yml config --services | sed -e "s@^@service=@"', '\$', 2)
+		result = re.search('service=(?P<svc_name>[a-zA-Z0-9\_]+)', mySSH.getBefore())
+		if result is not None:
+			svcName = result.group('svc_name')
+			mySSH.command('docker-compose --file ci-docker-compose.yml up -d ' + svcName, '\$', 2)
+
+		# Checking Status
+		mySSH.command('docker-compose --file ci-docker-compose.yml config', '\$', 5)
+		result = re.search('container_name: (?P<container_name>[a-zA-Z0-9\-\_]+)', mySSH.getBefore())
+		unhealthyNb = 0
+		healthyNb = 0
+		startingNb = 0
+		containerName = ''
+		if result is not None:
+			containerName = result.group('container_name')
+			time.sleep(5)
+			cnt = 0
+			while (cnt < 3):
+				mySSH.command('docker inspect --format=\'{{.State.Health.Status}}\' ' + containerName, '\$', 5)
+				unhealthyNb = mySSH.getBefore().count('unhealthy')
+				healthyNb = mySSH.getBefore().count('healthy') - unhealthyNb
+				startingNb = mySSH.getBefore().count('starting')
+				if healthyNb == 1:
+					cnt = 10
+				else:
+					time.sleep(10)
+					cnt += 1
+		logging.debug(' -- ' + str(healthyNb) + ' healthy container(s)')
+		logging.debug(' -- ' + str(unhealthyNb) + ' unhealthy container(s)')
+		logging.debug(' -- ' + str(startingNb) + ' still starting container(s)')
+
+		status = False
+		if healthyNb == 1:
+			cnt = 0
+			while (cnt < 20):
+				mySSH.command('docker logs ' + containerName + ' | egrep --text --color=never -i "wait|sync|Starting"', '\$', 30) 
+				result = re.search('got sync|Starting F1AP at CU', mySSH.getBefore())
+				if result is None:
+					time.sleep(6)
+					cnt += 1
+				else:
+					cnt = 100
+					status = True
+					logging.info('\u001B[1m Deploying OAI object Pass\u001B[0m')
+					time.sleep(10)
+		mySSH.close()
+
+		self.testCase_id = HTML.testCase_id
+		self.eNB_logFile[self.eNB_instance] = 'enb_' + self.testCase_id + '.log'
+
+		if status:
+			HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+		else:
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK)
+
+	def UndeployObject(self, HTML, RAN):
+		logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m')
+		if self.eNB_serverId[self.eNB_instance] == '0':
+			lIpAddr = self.eNBIPAddress
+			lUserName = self.eNBUserName
+			lPassWord = self.eNBPassword
+			lSourcePath = self.eNBSourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '1':
+			lIpAddr = self.eNB1IPAddress
+			lUserName = self.eNB1UserName
+			lPassWord = self.eNB1Password
+			lSourcePath = self.eNB1SourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '2':
+			lIpAddr = self.eNB2IPAddress
+			lUserName = self.eNB2UserName
+			lPassWord = self.eNB2Password
+			lSourcePath = self.eNB2SourceCodePath
+		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		logging.debug('\u001B[1m Deploying OAI Object on server: ' + lIpAddr + '\u001B[0m')
+		mySSH = SSH.SSHConnection()
+		mySSH.open(lIpAddr, lUserName, lPassWord)
+		mySSH.command('cd ' + lSourcePath + '/' + self.yamlPath[self.eNB_instance], '\$', 5)
+		# Currently support only one
+		mySSH.command('docker-compose --file ci-docker-compose.yml config', '\$', 5)
+		result = re.search('container_name: (?P<container_name>[a-zA-Z0-9\-\_]+)', mySSH.getBefore())
+		if result is not None:
+			containerName = result.group('container_name')
+			mySSH.command('docker kill --signal INT ' + containerName, '\$', 30)
+			time.sleep(5)
+			mySSH.command('docker logs ' + containerName + ' > ' + lSourcePath + '/cmake_targets/' + self.eNB_logFile[self.eNB_instance], '\$', 30)
+			mySSH.command('docker rm -f ' + containerName, '\$', 30)
+
+		# Putting the CPUs back in a idle state, we do that only on a few servers
+		mySSH.command('hostname', '\$', 5)
+		result = re.search('obelix|asterix',  mySSH.getBefore())
+		if result is not None:
+			mySSH.command('if command -v cpupower &> /dev/null; then echo ' + lPassWord + ' | sudo -S cpupower idle-set -E; fi', '\$', 5)
+		mySSH.close()
+
+		# Analyzing log file!
+		copyin_res = mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + self.eNB_logFile[self.eNB_instance], '.')
+		nodeB_prefix = 'e'
+		if (copyin_res == -1):
+			HTML.htmleNBFailureMsg='Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!'
+			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
+		else:
+			logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + self.eNB_logFile[self.eNB_instance])
+			logStatus = RAN.AnalyzeLogFile_eNB(self.eNB_logFile[self.eNB_instance], HTML)
+			if (logStatus < 0):
+				HTML.CreateHtmlTestRow(RAN.runtime_stats, 'KO', logStatus)
+			else:
+				HTML.CreateHtmlTestRow(RAN.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+
diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py
index 37d648a5b065becafa5218c756de3cc654f4bc61..7da829b7f7dc401fb423875b1cfd6f0af08fced0 100644
--- a/ci-scripts/cls_oaicitest.py
+++ b/ci-scripts/cls_oaicitest.py
@@ -42,6 +42,7 @@ import xml.etree.ElementTree as ET
 import logging
 import datetime
 import signal
+import statistics as stat
 from multiprocessing import Process, Lock, SimpleQueue
 logging.basicConfig(
 	level=logging.DEBUG,
@@ -53,6 +54,52 @@ import helpreadme as HELP
 import constants as CONST
 import sshconnection
 
+
+
+
+#-----------------------------------------------------------
+# Utility functions
+#-----------------------------------------------------------
+
+def GetPingTimeAnalysis(ping_log_file):
+	#ping time values read from file
+	t_ping=[]
+	#ping stats (dictionary) to be returned by the function
+	ping_stat={}
+	if (os.path.isfile(ping_log_file)):
+		with open(ping_log_file,"r") as f:
+			for line in f:
+				#looking for time=xxx ms field
+				result=re.match('^.+time=(?P<ping_time>[0-9\.]+)',line)
+				if result != None:
+					t_ping.append(float(result.group('ping_time')))
+
+		#initial stats
+		ping_stat['min_0']=min(t_ping)
+		ping_stat['mean_0']=stat.mean(t_ping)
+		ping_stat['median_0']=stat.median(t_ping)
+		ping_stat['max_0']=max(t_ping)
+
+		#get index of max value
+		
+		max_loc=t_ping.index(max(t_ping))
+		ping_stat['max_loc']=max_loc
+		#remove it
+		t_ping.pop(max_loc)
+		#new stats after removing max value
+		ping_stat['min_1']=min(t_ping)
+		ping_stat['mean_1']=stat.mean(t_ping)
+		ping_stat['median_1']=stat.median(t_ping)
+		ping_stat['max_1']=max(t_ping)
+
+		return ping_stat
+
+	else:
+		logging.error("Ping log file does not exist")
+		return -1
+
+	
+
 #-----------------------------------------------------------
 # OaiCiTest Class Definition
 #-----------------------------------------------------------
@@ -216,7 +263,7 @@ class OaiCiTest():
 			HTML.CreateHtmlTabFooter(False)
 			self.ConditionalExit()
 
-	def CheckFlexranCtrlInstallation(self,RAN,EPC):
+	def CheckFlexranCtrlInstallation(self,RAN,EPC,CONTAINERS):
 		if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '':
 			return
 		SSH = sshconnection.SSHConnection()
@@ -225,7 +272,18 @@ class OaiCiTest():
 		result = re.search('/opt/flexran_rtc/build/rt_controller', SSH.getBefore())
 		if result is not None:
 			RAN.flexranCtrlInstalled=True
+			RAN.flexranCtrlIpAddress=EPC.IPAddress
 			logging.debug('Flexran Controller is installed')
+		else:
+			# Maybe flexran-rtc is deployed into a container
+			SSH.command('docker inspect --format="FLEX_RTC_IP_ADDR = {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" prod-flexran-rtc', '\$', 5)
+			result = re.search('FLEX_RTC_IP_ADDR = (?P<flex_ip_addr>[0-9\.]+)', SSH.getBefore())
+			if result is not None:
+				RAN.flexranCtrlDeployed=True
+				RAN.flexranCtrlIpAddress=result.group('flex_ip_addr')
+				CONTAINERS.flexranCtrlDeployed=True
+				CONTAINERS.flexranCtrlIpAddress=result.group('flex_ip_addr')
+				logging.debug('Flexran Controller is deployed: ' + RAN.flexranCtrlIpAddress)
 		SSH.close()
 
 	def InitializeFlexranCtrl(self, HTML,RAN,EPC):
@@ -547,7 +605,7 @@ class OaiCiTest():
 				HTML.htmlUEFailureMsg='nr-uesoftmodem did NOT synced'
 				HTML.CreateHtmlTestRow(self.air_interface + ' ' +  self.Initialize_OAI_UE_args, 'KO', CONST.OAI_UE_PROCESS_COULD_NOT_SYNC, 'OAI UE')
 			logging.error('\033[91mInitialize OAI UE Failed! \033[0m')
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def checkDevTTYisUnlocked(self):
 		SSH = sshconnection.SSHConnection()
@@ -625,7 +683,7 @@ class OaiCiTest():
 		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
 		self.checkDevTTYisUnlocked()
 
-	def AttachCatM(self,HTML,RAN,COTS_UE):
+	def AttachCatM(self,HTML,RAN,COTS_UE,EPC):
 		if self.ADBIPAddress == '' or self.ADBUserName == '' or self.ADBPassword == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
@@ -698,7 +756,7 @@ class OaiCiTest():
 			html_cell = '<pre style="background-color:white">CAT-M module Attachment Failed</pre>'
 			html_queue.put(html_cell)
 			HTML.CreateHtmlTestRowQueue('N/A', 'KO', 1, html_queue)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def PingCatM(self,HTML,RAN,EPC,COTS_UE):
 		if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.SourceCodePath == '':
@@ -709,7 +767,7 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		try:
 			statusQueue = SimpleQueue()
@@ -730,7 +788,7 @@ class OaiCiTest():
 					moduleIPAddr = result.group('ipaddr')
 				else:
 					HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
-					self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+					self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 					return
 			ping_time = re.findall("-c (\d+)",str(self.ping_args))
 			device_id = 'catm'
@@ -794,7 +852,7 @@ class OaiCiTest():
 				HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', 1, statusQueue)
 			else:
 				HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', 1, statusQueue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 		except:
 			os.kill(os.getppid(),signal.SIGUSR1)
 
@@ -895,7 +953,7 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow('N/A', 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		multi_jobs = []
 		status_queue = SimpleQueue()
@@ -914,7 +972,7 @@ class OaiCiTest():
 
 		if (status_queue.empty()):
 			HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ALL_PROCESSES_OK)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		else:
 			attach_status = True
@@ -943,7 +1001,7 @@ class OaiCiTest():
 					time.sleep(5)
 			else:
 				HTML.CreateHtmlTestRowQueue('N/A', 'KO', len(self.UEDevices), html_queue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def DetachUE_common(self, device_id, idx,COTS_UE):
 		try:
@@ -976,7 +1034,7 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow('N/A', 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		multi_jobs = []
 		cnt = 0
@@ -1227,6 +1285,8 @@ class OaiCiTest():
 				if lDataConnectionState == 3:
 					dataConnectionState = 'Data State:    SUSPENDED'
 			result = re.search('mDataConnectionReason=(?P<dataConnectionReason>[0-9a-zA-Z_]+)', SSH.getBefore())
+			time.sleep(1)
+			SSH.close()
 			dataConnectionReason = 'Data Reason:   UNKNOWN'
 			if result is not None:
 				dataConnectionReason = 'Data Reason:   ' + result.group('dataConnectionReason')
@@ -1240,7 +1300,6 @@ class OaiCiTest():
 			qMsg = serviceState + '\n' + dataConnectionState + '\n' + dataConnectionReason
 			statusQueue.put(qMsg)
 			lock.release()
-			SSH.close()
 		except:
 			os.kill(os.getppid(),signal.SIGUSR1)
 
@@ -1267,12 +1326,12 @@ class OaiCiTest():
 			i += 1
 		for job in multi_jobs:
 			job.join()
-		if RAN.flexranCtrlInstalled and RAN.flexranCtrlStarted:
+		if (RAN.flexranCtrlInstalled and RAN.flexranCtrlStarted) or RAN.flexranCtrlDeployed:
 			SSH = sshconnection.SSHConnection()
 			SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
-			SSH.command('cd /opt/flexran_rtc', '\$', 5)
-			SSH.command('curl http://localhost:9999/stats | jq \'.\' > log/check_status_' + self.testCase_id + '.log 2>&1', '\$', 5)
-			SSH.command('cat log/check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5)
+			SSH.command('cd ' + EPC.SourceCodePath + '/scripts', '\$', 5)
+			SSH.command('curl http://' + RAN.flexranCtrlIpAddress + ':9999/stats | jq \'.\' > check_status_' + self.testCase_id + '.log 2>&1', '\$', 5)
+			SSH.command('cat check_status_' + self.testCase_id + '.log | jq \'.eNB_config[0].UE\' | grep -c rnti | sed -e "s#^#Nb Connected UE = #"', '\$', 5)
 			result = re.search('Nb Connected UE = (?P<nb_ues>[0-9]+)', SSH.getBefore())
 			passStatus = True
 			if result is not None:
@@ -1291,7 +1350,7 @@ class OaiCiTest():
 
 		if (status_queue.empty()):
 			HTML.CreateHtmlTestRow(htmlOptions, 'KO', CONST.ALL_PROCESSES_OK)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 		else:
 			check_status = True
 			html_queue = SimpleQueue()
@@ -1307,7 +1366,7 @@ class OaiCiTest():
 				HTML.CreateHtmlTestRowQueue(htmlOptions, 'OK', len(self.UEDevices), html_queue)
 			else:
 				HTML.CreateHtmlTestRowQueue(htmlOptions, 'KO', len(self.UEDevices), html_queue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def GetAllUEIPAddresses(self):
 		SSH = sshconnection.SSHConnection()
@@ -1397,17 +1456,26 @@ class OaiCiTest():
 				if re.match('OAI-Rel14-Docker', EPC.Type, re.IGNORECASE):
 					launchFromTrfContainer = True
 				if launchFromTrfContainer:
-					ping_status = SSH.command('docker exec -it prod-trf-gen /bin/bash -c "ping ' + self.ping_args + ' ' + UE_IPAddress + '" 2>&1 | tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5)
+					ping_status = SSH.command('docker exec -it prod-trf-gen /bin/bash -c "ping ' + self.ping_args + ' ' + UE_IPAddress + '" 2>&1 | tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5)				
 				else:
 					ping_status = SSH.command('stdbuf -o0 ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5)
+				#copy the ping log file to have it locally for analysis (ping stats)
+				SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, EPC.SourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '.')				
 			else:
+				#ping log file is on the python executor
 				cmd = 'ping ' + self.ping_args + ' ' + UE_IPAddress + ' 2>&1 > ping_' + self.testCase_id + '_' + device_id + '.log' 
 				message = cmd + '\n'
 				logging.debug(cmd)
 				ret = subprocess.run(cmd, shell=True)
 				ping_status = ret.returncode
+				#copy the ping log file to an other folder for log collection (source and destination are EPC)
 				SSH.copyout(EPC.IPAddress, EPC.UserName, EPC.Password, 'ping_' + self.testCase_id + '_' + device_id + '.log', EPC.SourceCodePath + '/scripts')
+                #copy the ping log file to have it locally for analysis (ping stats)
+				logging.debug(EPC.SourceCodePath + 'ping_' + self.testCase_id + '_' + device_id + '.log')
+				SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, EPC.SourceCodePath  +'/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '.')
+
 				SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
+				#cat is executed on EPC
 				SSH.command('cat ' + EPC.SourceCodePath + '/scripts/ping_' + self.testCase_id + '_' + device_id + '.log', '\$', 5)
 			# TIMEOUT CASE
 			if ping_status < 0:
@@ -1416,6 +1484,7 @@ class OaiCiTest():
 				SSH.close()
 				self.ping_iperf_wrong_exit(lock, UE_IPAddress, device_id, statusQueue, message)
 				return
+			#search is done on cat result
 			result = re.search(', (?P<packetloss>[0-9\.]+)% packet loss, time [0-9\.]+ms', SSH.getBefore())
 			if result is None:
 				message = 'Packet Loss Not Found!'
@@ -1450,7 +1519,27 @@ class OaiCiTest():
 			logging.debug('\u001B[1;34m    ' + min_msg + '\u001B[0m')
 			logging.debug('\u001B[1;34m    ' + avg_msg + '\u001B[0m')
 			logging.debug('\u001B[1;34m    ' + max_msg + '\u001B[0m')
-			qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg
+
+			#adding extra ping stats from local file
+			ping_log_file='ping_' + self.testCase_id + '_' + device_id + '.log'
+			logging.debug('Analyzing Ping log file : ' + os.getcwd() + '/' + ping_log_file)
+			ping_stat=GetPingTimeAnalysis(ping_log_file)
+			ping_stat_msg=''
+			if (ping_stat!=-1) and (len(ping_stat)!=0):
+				ping_stat_msg+='Ping stats before removing largest value : \n'
+				ping_stat_msg+='RTT(Min)    : ' + str("{:.2f}".format(ping_stat['min_0'])) + 'ms \n'
+				ping_stat_msg+='RTT(Mean)   : ' + str("{:.2f}".format(ping_stat['mean_0'])) + 'ms \n'
+				ping_stat_msg+='RTT(Median) : ' + str("{:.2f}".format(ping_stat['median_0'])) + 'ms \n'
+				ping_stat_msg+='RTT(Max)    : ' + str("{:.2f}".format(ping_stat['max_0'])) + 'ms \n'
+				ping_stat_msg+='Max Index   : ' + str(ping_stat['max_loc']) + '\n'
+				ping_stat_msg+='Ping stats after removing largest value : \n'
+				ping_stat_msg+='RTT(Min)    : ' + str("{:.2f}".format(ping_stat['min_1'])) + 'ms \n'
+				ping_stat_msg+='RTT(Mean)   : ' + str("{:.2f}".format(ping_stat['mean_1'])) + 'ms \n'
+				ping_stat_msg+='RTT(Median) : ' + str("{:.2f}".format(ping_stat['median_1'])) + 'ms \n'
+				ping_stat_msg+='RTT(Max)    : ' + str("{:.2f}".format(ping_stat['max_1'])) + 'ms \n'
+
+			#building html message
+			qMsg = pal_msg + '\n' + min_msg + '\n' + avg_msg + '\n' + max_msg + '\n' + ping_stat_msg
 			packetLossOK = True
 			if packetloss is not None:
 				if float(packetloss) > float(self.ping_packetloss_threshold):
@@ -1485,7 +1574,7 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		ping_from_eNB = re.search('oaitun_enb1', str(self.ping_args))
 		if ping_from_eNB is not None:
@@ -1587,12 +1676,12 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.ping_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		ueIpStatus = self.GetAllUEIPAddresses()
 		if (ueIpStatus < 0):
 			HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		multi_jobs = []
 		i = 0
@@ -1610,7 +1699,7 @@ class OaiCiTest():
 
 		if (status_queue.empty()):
 			HTML.CreateHtmlTestRow(self.ping_args, 'KO', CONST.ALL_PROCESSES_OK)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 		else:
 			ping_status = True
 			html_queue = SimpleQueue()
@@ -1627,7 +1716,7 @@ class OaiCiTest():
 				HTML.CreateHtmlTestRowQueue(self.ping_args, 'OK', len(self.UEDevices), html_queue)
 			else:
 				HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', len(self.UEDevices), html_queue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def Iperf_ComputeTime(self):
 		result = re.search('-t (?P<iperf_time>\d+)', str(self.iperf_args))
@@ -1934,15 +2023,34 @@ class OaiCiTest():
 			ret = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8')
 			if ret.stdout is not None:
 				EPC_Iperf_UE_IPAddress = ret.stdout.strip()
+		# When using a docker-based deployment, IPERF client shall be launched from trf container
+		launchFromTrfContainer = False
+		if re.match('OAI-Rel14-Docker', EPC.Type, re.IGNORECASE):
+			launchFromTrfContainer = True
+			SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
+			SSH.command('docker inspect --format="TRF_IP_ADDR = {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" prod-trf-gen', '\$', 5)
+			result = re.search('TRF_IP_ADDR = (?P<trf_ip_addr>[0-9\.]+)', SSH.getBefore())
+			if result is not None:
+				EPC_Iperf_UE_IPAddress = result.group('trf_ip_addr')
+			SSH.close()
 		port = 5001 + idx
+		udpOptions = ''
+		if udpIperf:
+			udpOptions = '-u '
 		if launchFromEpc:
 			SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
 			SSH.command('cd ' + EPC.SourceCodePath + '/scripts', '\$', 5)
 			SSH.command('rm -f iperf_server_' + self.testCase_id + '_' + device_id + '.log', '\$', 5)
-			if udpIperf:
-				SSH.command('echo $USER; nohup iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.UserName, 5)
+			if launchFromTrfContainer:
+				if self.ueIperfVersion == self.dummyIperfVersion:
+					prefix = ''
+				else:
+					prefix = ''
+					if self.ueIperfVersion == '2.0.5':
+						prefix = '/iperf-2.0.5/bin/'
+				SSH.command('docker exec -d prod-trf-gen /bin/bash -c "nohup ' + prefix + 'iperf ' + udpOptions + '-s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &"', '\$', 5)
 			else:
-				SSH.command('echo $USER; nohup iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.UserName, 5)
+				SSH.command('echo $USER; nohup iperf ' + udpOptions + '-s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log &', EPC.UserName, 5)
 			SSH.close()
 		else:
 			if self.ueIperfVersion == self.dummyIperfVersion:
@@ -1951,10 +2059,7 @@ class OaiCiTest():
 				prefix = ''
 				if self.ueIperfVersion == '2.0.5':
 					prefix = '/opt/iperf-2.0.5/bin/'
-			if udpIperf:
-				cmd = 'nohup ' + prefix + 'iperf -u -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &'
-			else:
-				cmd = 'nohup ' + prefix + 'iperf -s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &'
+			cmd = 'nohup ' + prefix + 'iperf ' + udpOptions + '-s -i 1 -p ' + str(port) + ' > iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 &'
 			logging.debug(cmd)
 			subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8')
 		time.sleep(0.5)
@@ -2000,13 +2105,16 @@ class OaiCiTest():
 		# Kill iperf server on EPC side
 		if launchFromEpc:
 			SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
-			SSH.command('killall --signal SIGKILL iperf', EPC.UserName, 5)
+			if launchFromTrfContainer:
+				SSH.command('docker exec -it prod-trf-gen /bin/bash -c "killall --signal SIGKILL iperf"', '\$', 5)
+			else:
+				SSH.command('killall --signal SIGKILL iperf', EPC.UserName, 5)
 			SSH.close()
 		else:
 			cmd = 'killall --signal SIGKILL iperf'
 			logging.debug(cmd)
 			subprocess.run(cmd, shell=True)
-			time.sleep(1)			
+			time.sleep(1)
 			SSH.copyout(EPC.IPAddress, EPC.UserName, EPC.Password, 'iperf_server_' + self.testCase_id + '_' + device_id + '.log', EPC.SourceCodePath + '/scripts')
 		# in case of failure, retrieve server log
 		if (clientStatus == -1) or (clientStatus == -2):
@@ -2014,6 +2122,10 @@ class OaiCiTest():
 				time.sleep(1)
 				if (os.path.isfile('iperf_server_' + self.testCase_id + '_' + device_id + '.log')):
 					os.remove('iperf_server_' + self.testCase_id + '_' + device_id + '.log')
+				if launchFromTrfContainer:
+					SSH.open(EPC.IPAddress, EPC.UserName, EPC.Password)
+					SSH.command('docker cp prod-trf-gen:/iperf-2.0.5/iperf_server_' + self.testCase_id + '_' + device_id + '.log ' + EPC.SourceCodePath + '/scripts', '\$', 5)
+					SSH.close()
 				SSH.copyin(EPC.IPAddress, EPC.UserName, EPC.Password, EPC.SourceCodePath+ '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.')
 			self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options)
 		# in case of OAI-UE 
@@ -2212,8 +2324,16 @@ class OaiCiTest():
 				else:
 					SSH.copyin(self.ADBIPAddress, self.ADBUserName, self.ADBPassword, EPC.SourceCodePath + '/scripts/iperf_server_' + self.testCase_id + '_' + device_id + '.log', '.')
 				# fromdos has to be called on the python executor not on ADB server
-				cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log'
-				subprocess.run(cmd, shell=True)
+				cmd = 'fromdos -o iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 > /dev/null'
+				try:
+					subprocess.run(cmd, shell=True)
+				except:
+					pass
+				cmd = 'dos2unix -o iperf_server_' + self.testCase_id + '_' + device_id + '.log 2>&1 > /dev/null'
+				try:
+					subprocess.run(cmd, shell=True)
+				except:
+					pass
 				self.Iperf_analyzeV2Server(lock, UE_IPAddress, device_id, statusQueue, modified_options)
 
 			# in case of OAI UE: 
@@ -2237,7 +2357,7 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		server_on_enb = re.search('-R', str(self.iperf_args))
 		if server_on_enb is not None:
@@ -2335,7 +2455,7 @@ class OaiCiTest():
 			HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue)
 		else:
 			HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def Iperf(self,HTML,RAN,EPC,COTS_UE):
 		result = re.search('noS1', str(RAN.Initialize_eNB_args))
@@ -2353,13 +2473,13 @@ class OaiCiTest():
 		pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
 		if (pStatus < 0):
 			HTML.CreateHtmlTestRow(self.iperf_args, 'KO', pStatus)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 		ueIpStatus = self.GetAllUEIPAddresses()
 		if (ueIpStatus < 0):
 			logging.debug('going here')
 			HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.UE_IP_ADDRESS_ISSUE)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			return
 
 		self.dummyIperfVersion = '2.0.10'
@@ -2390,7 +2510,7 @@ class OaiCiTest():
 
 		if (status_queue.empty()):
 			HTML.CreateHtmlTestRow(self.iperf_args, 'KO', CONST.ALL_PROCESSES_OK)
-			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+			self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 		else:
 			iperf_status = True
 			iperf_noperf = False
@@ -2412,7 +2532,7 @@ class OaiCiTest():
 				HTML.CreateHtmlTestRowQueue(self.iperf_args, 'OK', len(self.UEDevices), html_queue)
 			else:
 				HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', len(self.UEDevices), html_queue)
-				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+				self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 
 	def CheckProcessExist(self, check_eNB, check_OAI_UE,RAN,EPC):
 		multi_jobs = []
@@ -2832,7 +2952,7 @@ class OaiCiTest():
 			job.join()
 		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
 
-	def TerminateOAIUE(self,HTML,RAN,COTS_UE):
+	def TerminateOAIUE(self,HTML,RAN,COTS_UE,EPC):
 		SSH = sshconnection.SSHConnection()
 		SSH.open(self.UEIPAddress, self.UEUserName, self.UEPassword)
 		SSH.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5)
@@ -2873,11 +2993,11 @@ class OaiCiTest():
 					# Not an error then
 					if (logStatus != CONST.OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'):
 						self.Initialize_OAI_UE_args = ''
-						self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+						self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 				else:
 					if (logStatus == CONST.OAI_UE_PROCESS_COULD_NOT_SYNC):
 						self.Initialize_OAI_UE_args = ''
-						self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE)
+						self.AutoTerminateUEandeNB(HTML,RAN,COTS_UE,EPC)
 			else:
 				logging.debug('\u001B[1m' + ueAction + ' Completed \u001B[0m')
 				HTML.htmlUEFailureMsg='<b>' + ueAction + ' Completed</b>\n' + HTML.htmlUEFailureMsg
@@ -2886,7 +3006,7 @@ class OaiCiTest():
 		else:
 			HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
 
-	def AutoTerminateUEandeNB(self,HTML,RAN,COTS_UE):
+	def AutoTerminateUEandeNB(self,HTML,RAN,COTS_UE,EPC):
 		if (self.ADBIPAddress != 'none'):
 			self.testCase_id = 'AUTO-KILL-UE'
 			HTML.testCase_id=self.testCase_id
@@ -2900,15 +3020,19 @@ class OaiCiTest():
 			self.desc = 'Automatic Termination of OAI-UE'
 			HTML.desc='Automatic Termination of OAI-UE'
 			self.ShowTestID()
-			self.TerminateOAIUE(HTML,RAN,COTS_UE)
+			self.TerminateOAIUE(HTML,RAN,COTS_UE,EPC)
 		if (RAN.Initialize_eNB_args != ''):
-			self.testCase_id = 'AUTO-KILL-eNB'
+			self.testCase_id = 'AUTO-KILL-RAN'
 			HTML.testCase_id=self.testCase_id
-			self.desc = 'Automatic Termination of eNB'
-			HTML.desc='Automatic Termination of eNB'
+			self.desc = 'Automatic Termination of all RAN nodes'
+			HTML.desc='Automatic Termination of RAN nodes'
 			self.ShowTestID()
-			RAN.eNB_instance=0
-			RAN.TerminateeNB()
+			#terminate all RAN nodes eNB/gNB/OCP
+			for instance in range(0, len(RAN.air_interface)):
+				if RAN.air_interface[instance]!='':
+					logging.debug('Auto Termination of Instance ' + str(instance) + ' : ' + RAN.air_interface[instance])
+					RAN.eNB_instance=instance
+					RAN.TerminateeNB(HTML,EPC)
 		if RAN.flexranCtrlInstalled and RAN.flexranCtrlStarted:
 			self.testCase_id = 'AUTO-KILL-flexran-ctl'
 			HTML.testCase_id=self.testCase_id
@@ -3050,7 +3174,7 @@ class OaiCiTest():
 		SSH.command('cd ' + SourceCodePath, '\$', 5)
 		SSH.command('cd cmake_targets', '\$', 5)
 		SSH.command('rm -f build.log.zip', '\$', 5)
-		SSH.command('zip build.log.zip build_log_*/*', '\$', 60)
+		SSH.command('zip -r build.log.zip build_log_*/*', '\$', 60)
 		SSH.close()
 
 	def LogCollectPing(self,EPC):
diff --git a/ci-scripts/conf_files/cu.band7.tm1.100PRB.conf b/ci-scripts/conf_files/cu.band7.tm1.100PRB.conf
index 42cade271c0da45f4a067ec5d9ce5a7c7f1a2e0e..e2c94b14ab176b9273373f7631ae3ac188a547c4 100644
--- a/ci-scripts/conf_files/cu.band7.tm1.100PRB.conf
+++ b/ci-scripts/conf_files/cu.band7.tm1.100PRB.conf
@@ -215,7 +215,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/cu.band7.tm1.25PRB.conf b/ci-scripts/conf_files/cu.band7.tm1.25PRB.conf
index 51f727726709dd95cb0ce01d15fa6136a8034f6e..5b994ed29b15cb99f374d7b11fb5e2fc20cc7ab4 100644
--- a/ci-scripts/conf_files/cu.band7.tm1.25PRB.conf
+++ b/ci-scripts/conf_files/cu.band7.tm1.25PRB.conf
@@ -215,7 +215,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/cu.band7.tm1.50PRB.conf b/ci-scripts/conf_files/cu.band7.tm1.50PRB.conf
index 9946713c3adb89dd2f63a7c59af337af7e3cac73..148c5a9903f2e435cf17bd884c0234ca6be686e0 100644
--- a/ci-scripts/conf_files/cu.band7.tm1.50PRB.conf
+++ b/ci-scripts/conf_files/cu.band7.tm1.50PRB.conf
@@ -215,7 +215,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/du.band7.tm1.100PRB.usrpb210.conf b/ci-scripts/conf_files/du.band7.tm1.100PRB.usrpb210.conf
index 7167bffa6d1724d9cd48a42306b9281ade3d30fb..a3ecffb9be7b349cfe35a940483bbf558c0b1856 100644
--- a/ci-scripts/conf_files/du.band7.tm1.100PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/du.band7.tm1.100PRB.usrpb210.conf
@@ -112,7 +112,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/du.band7.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/du.band7.tm1.25PRB.usrpb210.conf
index 3c951a2a6e908e591b31911802bdd856cbaf438c..1920992d70c608a764529c747e3115e274e970ac 100644
--- a/ci-scripts/conf_files/du.band7.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/du.band7.tm1.25PRB.usrpb210.conf
@@ -112,7 +112,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/du.band7.tm1.50PRB.usrpb210.conf b/ci-scripts/conf_files/du.band7.tm1.50PRB.usrpb210.conf
index 4726269312cbbead4fdb7a3e15d46bc853d39447..5df8da05a3aeca11bb4c9c4148f0b00b1bbb0c38 100644
--- a/ci-scripts/conf_files/du.band7.tm1.50PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/du.band7.tm1.50PRB.usrpb210.conf
@@ -112,7 +112,7 @@ log_config = {
 NETWORK_CONTROLLER : {
   FLEXRAN_ENABLED        = "no";
   FLEXRAN_INTERFACE_NAME = "lo";
-  FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+  FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
   FLEXRAN_PORT           = 2210;
   FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
   FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf
index 0c247e9ef9a39e181291b9d371043b052cfc9aa2..e70ca782050be7e67afa529540d178608a7b523b 100644
--- a/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf
@@ -239,7 +239,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf b/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf
index f560958e152ca2a8c3505cfb48bc54872f64a80c..400d1a6c9d8099fbf1beb09ac4c2cce18a61286b 100644
--- a/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf
+++ b/ci-scripts/conf_files/enb.band13.tm1.50PRB.emtc.conf
@@ -448,7 +448,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf
index ba81f832db38f6da06e99dc7d15a01b41af0a50a..bd2999b5d549037804d4f6f16d1de2aa0129adcd 100644
--- a/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band17.tm1.25PRB.usrpb210.conf
@@ -251,7 +251,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf
index 79bbd7ee6f3e8dc800693b5fba603324d751ffe7..19ef6d07972c60cfece101229bd8d5436e51da74 100644
--- a/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band17.tm1.mbms.25PRB.usrpb210.conf
@@ -395,7 +395,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band40.tm1.100PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/enb.band40.tm1.100PRB.FairScheduler.usrpb210.conf
index b5fd1255bbb8c57384532e919c39240d18620ee2..f34878c5691efa7def3f353cbb7922b6a98e8feb 100644
--- a/ci-scripts/conf_files/enb.band40.tm1.100PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band40.tm1.100PRB.FairScheduler.usrpb210.conf
@@ -228,7 +228,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band40.tm1.25PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/enb.band40.tm1.25PRB.FairScheduler.usrpb210.conf
index 552dfd637b9388a0fb4a58436c3e9e63a292a7bc..e2e482a7c7d98496635bb6d2f2f89b71237d0bfc 100644
--- a/ci-scripts/conf_files/enb.band40.tm1.25PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band40.tm1.25PRB.FairScheduler.usrpb210.conf
@@ -228,7 +228,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band40.tm1.50PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/enb.band40.tm1.50PRB.FairScheduler.usrpb210.conf
index d95d2b6ac1ac4ffb69880599312164a2bae15f3b..bfea139e92147d58a8b44e2803e899072ff3121f 100644
--- a/ci-scripts/conf_files/enb.band40.tm1.50PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band40.tm1.50PRB.FairScheduler.usrpb210.conf
@@ -228,7 +228,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band40.tm2.25PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/enb.band40.tm2.25PRB.FairScheduler.usrpb210.conf
index e466a23ab0b2aa47b5a4939e33ed66f6805e1dcc..4e0025770b4a645805b9ff17f0b6eccfcf11a777 100644
--- a/ci-scripts/conf_files/enb.band40.tm2.25PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band40.tm2.25PRB.FairScheduler.usrpb210.conf
@@ -226,7 +226,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf
index e3cdb033c93976a1dbff96a27687e1d3b87a847f..1627d21e1aefba2c49c003ef85f6c20994ec37b9 100644
--- a/ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.100PRB.usrpb210.conf
@@ -247,7 +247,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf
index f95530b251ef009e4a55923b507c860ece8c72dd..efa1fa64b8004325aea95792c11c3f82635a075b 100644
--- a/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.25PRB.slave.usrpb210.conf
@@ -256,7 +256,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf
index eddb34a5791dabc06b0404485ab459e36e14916b..f29fc163b3d0459df1e633c397f3b67fb0711575 100644
--- a/ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.25PRB.usrpb210.conf
@@ -28,83 +28,85 @@ eNBs =
       node_function             = "3GPP_eNODEB";
       node_timing               = "synch_to_ext_device";
       node_synch_ref            = 0;
-      frame_type					      = "FDD";
-      tdd_config 					      = 3;
-      tdd_config_s            			      = 0;
-      prefix_type             			      = "NORMAL";
-      eutra_band              			      = 7;
-      downlink_frequency      			      = 2680000000L;
-      uplink_frequency_offset 			      = -120000000;
-      Nid_cell					      = 0;
-      N_RB_DL                 			      = 25;
-      Nid_cell_mbsfn          			      = 0;
-      nb_antenna_ports                                = 1;
-      nb_antennas_tx          			      = 1;
-      nb_antennas_rx          			      = 1;
-      tx_gain                                            = 90;
-      rx_gain                                            = 125;
-      pbch_repetition                                 = "FALSE";
-      prach_root              			      = 0;
-      prach_config_index      			      = 0;
-      prach_high_speed        			      = "DISABLE";
-      prach_zero_correlation  			      = 1;
-      prach_freq_offset       			      = 2;
-      pucch_delta_shift       			      = 1;
-      pucch_nRB_CQI           			      = 0;
-      pucch_nCS_AN            			      = 0;
-      pucch_n1_AN             			      = 0;
-      pdsch_referenceSignalPower 			      = -25;
-      pdsch_p_b                  			      = 0;
-      pusch_n_SB                 			      = 1;
-      pusch_enable64QAM          			      = "DISABLE";
-      pusch_hoppingMode                                  = "interSubFrame";
-      pusch_hoppingOffset                                = 0;
-      pusch_groupHoppingEnabled  			      = "ENABLE";
-      pusch_groupAssignment      			      = 0;
-      pusch_sequenceHoppingEnabled		   	      = "DISABLE";
-      pusch_nDMRS1                                       = 1;
-      phich_duration                                     = "NORMAL";
-      phich_resource                                     = "ONESIXTH";
-      srs_enable                                         = "DISABLE";
-      /*  srs_BandwidthConfig                                =;
-      srs_SubframeConfig                                 =;
-      srs_ackNackST                                      =;
-      srs_MaxUpPts                                       =;*/
-
-      pusch_p0_Nominal                                   = -96;
-      pusch_alpha                                        = "AL1";
-      pucch_p0_Nominal                                   = -104;
-      msg3_delta_Preamble                                = 6;
-      pucch_deltaF_Format1                               = "deltaF2";
-      pucch_deltaF_Format1b                              = "deltaF3";
-      pucch_deltaF_Format2                               = "deltaF0";
-      pucch_deltaF_Format2a                              = "deltaF0";
-      pucch_deltaF_Format2b		    	      = "deltaF0";
-
-      rach_numberOfRA_Preambles                          = 64;
-      rach_preamblesGroupAConfig                         = "DISABLE";
+      frame_type                = "FDD";
+      tdd_config                = 3;
+      tdd_config_s              = 0;
+      prefix_type               = "NORMAL";
+      eutra_band                = 7;
+      downlink_frequency        = 2680000000L;
+      uplink_frequency_offset   = -120000000;
+      Nid_cell                  = 0;
+      N_RB_DL                   = 25;
+      Nid_cell_mbsfn            = 0;
+      nb_antenna_ports          = 1;
+      nb_antennas_tx            = 1;
+      nb_antennas_rx            = 1;
+      tx_gain                   = 90;
+      rx_gain                   = 125;
+      pbch_repetition           = "FALSE";
+      prach_root                = 0;
+      prach_config_index        = 0;
+      prach_high_speed          = "DISABLE";
+      prach_zero_correlation    = 1;
+      prach_freq_offset         = 2;
+      pucch_delta_shift         = 1;
+      pucch_nRB_CQI             = 0;
+      pucch_nCS_AN              = 0;
+      pucch_n1_AN               = 0;
+      pdsch_referenceSignalPower= -25;
+      pdsch_p_b                 = 0;
+      pusch_n_SB                = 1;
+      pusch_enable64QAM         = "DISABLE";
+      pusch_hoppingMode         = "interSubFrame";
+      pusch_hoppingOffset       = 0;
+      pusch_groupHoppingEnabled = "ENABLE";
+      pusch_groupAssignment     = 0;
+      pusch_sequenceHoppingEnabled = "DISABLE";
+      pusch_nDMRS1              = 1;
+      phich_duration            = "NORMAL";
+      phich_resource            = "ONESIXTH";
+      srs_enable                = "DISABLE";
       /*
-      rach_sizeOfRA_PreamblesGroupA                      = ;
-      rach_messageSizeGroupA                             = ;
-      rach_messagePowerOffsetGroupB                      = ;
+      srs_BandwidthConfig       =;
+      srs_SubframeConfig        =;
+      srs_ackNackST             =;
+      srs_MaxUpPts              =;
       */
-      rach_powerRampingStep                              = 4;
-      rach_preambleInitialReceivedTargetPower            = -108;
-      rach_preambleTransMax                              = 10;
-      rach_raResponseWindowSize                          = 10;
-      rach_macContentionResolutionTimer                  = 48;
-      rach_maxHARQ_Msg3Tx                                = 4;
-
-      pcch_default_PagingCycle                           = 128;
-      pcch_nB                                            = "oneT";
-      bcch_modificationPeriodCoeff			      = 2;
-      ue_TimersAndConstants_t300			      = 1000;
-      ue_TimersAndConstants_t301			      = 1000;
-      ue_TimersAndConstants_t310			      = 1000;
-      ue_TimersAndConstants_t311			      = 10000;
-      ue_TimersAndConstants_n310			      = 20;
-      ue_TimersAndConstants_n311			      = 1;
-      ue_TransmissionMode                                    = 1;
+
+      pusch_p0_Nominal          = -96;
+      pusch_alpha               = "AL1";
+      pucch_p0_Nominal          = -104;
+      msg3_delta_Preamble       = 6;
+      pucch_deltaF_Format1      = "deltaF2";
+      pucch_deltaF_Format1b     = "deltaF3";
+      pucch_deltaF_Format2      = "deltaF0";
+      pucch_deltaF_Format2a     = "deltaF0";
+      pucch_deltaF_Format2b     = "deltaF0";
+
+      rach_numberOfRA_Preambles                = 64;
+      rach_preamblesGroupAConfig               = "DISABLE";
+      /*
+      rach_sizeOfRA_PreamblesGroupA            = ;
+      rach_messageSizeGroupA                   = ;
+      rach_messagePowerOffsetGroupB            = ;
+      */
+      rach_powerRampingStep                    = 4;
+      rach_preambleInitialReceivedTargetPower  = -108;
+      rach_preambleTransMax                    = 10;
+      rach_raResponseWindowSize                = 10;
+      rach_macContentionResolutionTimer        = 48;
+      rach_maxHARQ_Msg3Tx                      = 4;
+
+      pcch_default_PagingCycle                 = 128;
+      pcch_nB                                  = "oneT";
+      bcch_modificationPeriodCoeff             = 2;
+      ue_TimersAndConstants_t300               = 1000;
+      ue_TimersAndConstants_t301               = 1000;
+      ue_TimersAndConstants_t310               = 1000;
+      ue_TimersAndConstants_t311               = 10000;
+      ue_TimersAndConstants_n310               = 20;
+      ue_TimersAndConstants_n311               = 1;
+      ue_TransmissionMode                      = 1;
 
       //Parameters for SIB18
       rxPool_sc_CP_Len                                       = "normal";
@@ -116,27 +118,28 @@ eNBs =
       rxPool_ResourceConfig_offsetIndicator_present          = "prSmall";
       rxPool_ResourceConfig_offsetIndicator_choice           = 0;
       rxPool_ResourceConfig_subframeBitmap_present           = "prBs40";
-      rxPool_ResourceConfig_subframeBitmap_choice_bs_buf              = "00000000000000000000";
-      rxPool_ResourceConfig_subframeBitmap_choice_bs_size             = 5;
-      rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused      = 0;
-/*    rxPool_dataHoppingConfig_hoppingParameter                       = 0;
-      rxPool_dataHoppingConfig_numSubbands                            = "ns1";
-      rxPool_dataHoppingConfig_rbOffset                               = 0;
-      rxPool_commTxResourceUC-ReqAllowed                              = "TRUE";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_buf     = "00000000000000000000";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_size    = 5;
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0;
+/*
+      rxPool_dataHoppingConfig_hoppingParameter              = 0;
+      rxPool_dataHoppingConfig_numSubbands                   = "ns1";
+      rxPool_dataHoppingConfig_rbOffset                      = 0;
+      rxPool_commTxResourceUC-ReqAllowed                     = "TRUE";
 */
       // Parameters for SIB19
-      discRxPool_cp_Len                                               = "normal"
-      discRxPool_discPeriod                                           = "rf32"
-      discRxPool_numRetx                                              = 1;
-      discRxPool_numRepetition                                        = 2;
-      discRxPool_ResourceConfig_prb_Num                               = 5;
-      discRxPool_ResourceConfig_prb_Start                             = 3;
-      discRxPool_ResourceConfig_prb_End                               = 21;
-      discRxPool_ResourceConfig_offsetIndicator_present               = "prSmall";
-      discRxPool_ResourceConfig_offsetIndicator_choice                = 0;
-      discRxPool_ResourceConfig_subframeBitmap_present                = "prBs40";
-      discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf          = "f0ffffffff";
-      discRxPool_ResourceConfig_subframeBitmap_choice_bs_size         = 5;
+      discRxPool_cp_Len                                      = "normal"
+      discRxPool_discPeriod                                  = "rf32"
+      discRxPool_numRetx                                     = 1;
+      discRxPool_numRepetition                               = 2;
+      discRxPool_ResourceConfig_prb_Num                      = 5;
+      discRxPool_ResourceConfig_prb_Start                    = 3;
+      discRxPool_ResourceConfig_prb_End                      = 21;
+      discRxPool_ResourceConfig_offsetIndicator_present      = "prSmall";
+      discRxPool_ResourceConfig_offsetIndicator_choice       = 0;
+      discRxPool_ResourceConfig_subframeBitmap_present       = "prBs40";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_size= 5;
       discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused  = 0;
 
       }
@@ -204,40 +207,43 @@ eNBs =
   }
 );
 
-MACRLCs = (
-	{
-	num_cc = 1;
-	tr_s_preference = "local_L1";
-	tr_n_preference = "local_RRC";
-	phy_test_mode = 0;
-        puSch10xSnr     =  160;
-        puCch10xSnr     =  160;
-        }  
+MACRLCs =
+(
+  {
+    num_cc          = 1;
+    tr_s_preference = "local_L1";
+    tr_n_preference = "local_RRC";
+    phy_test_mode   = 0;
+    puSch10xSnr     =  160;
+    puCch10xSnr     =  160;
+  }  
 );
 
-L1s = (
-    	{
-	num_cc = 1;
-	tr_n_preference = "local_mac";
-        }  
+L1s =
+(
+  {
+    num_cc = 1;
+    tr_n_preference = "local_mac";
+  }  
 );
 
-RUs = (
-    {		  
-       local_rf       = "yes"
-         nb_tx          = 1
-         nb_rx          = 1
-         att_tx         = 0
-         att_rx         = 0;
-         bands          = [7];
-         max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 125;
-         eNB_instances  = [0];
-
-    }
+RUs =
+(
+  {
+    local_rf                      = "yes"
+    nb_tx                         = 1
+    nb_rx                         = 1
+    att_tx                        = 0
+    att_rx                        = 0;
+    bands                         = [7];
+    max_pdschReferenceSignalPower = -27;
+    max_rxgain                    = 125;
+    eNB_instances                 = [0];
+  }
 );  
 
-THREAD_STRUCT = (
+THREAD_STRUCT =
+(
   {
     #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
     parallel_config    = "PARALLEL_SINGLE_THREAD";
@@ -250,27 +256,27 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
 };
 
-     log_config :
-     {
-       global_log_level                      ="info";
-       global_log_verbosity                  ="medium";
-       hw_log_level                          ="info";
-       hw_log_verbosity                      ="medium";
-       phy_log_level                         ="info";
-       phy_log_verbosity                     ="medium";
-       mac_log_level                         ="info";
-       mac_log_verbosity                     ="high";
-       rlc_log_level                         ="info";
-       rlc_log_verbosity                     ="medium";
-       pdcp_log_level                        ="info";
-       pdcp_log_verbosity                    ="medium";
-       rrc_log_level                         ="info";
-       rrc_log_verbosity                     ="medium";
-    };
+log_config :
+{
+    global_log_level                      ="info";
+    global_log_verbosity                  ="medium";
+    hw_log_level                          ="info";
+    hw_log_verbosity                      ="medium";
+    phy_log_level                         ="info";
+    phy_log_verbosity                     ="medium";
+    mac_log_level                         ="info";
+    mac_log_verbosity                     ="high";
+    rlc_log_level                         ="info";
+    rlc_log_verbosity                     ="medium";
+    pdcp_log_level                        ="info";
+    pdcp_log_verbosity                    ="medium";
+    rrc_log_level                         ="info";
+    rrc_log_verbosity                     ="medium";
+};
 
diff --git a/ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf
index b5d7f35a76e9218390cbe650a79e252e928a006a..4d89ad96daa3708d0e67b8bb12ca163870f472f1 100644
--- a/ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.50PRB.usrpb210.conf
@@ -255,7 +255,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf
old mode 100755
new mode 100644
index 19e4abdcb028166a8c899fdb6d4193fe74c5a8f4..33aae14dac1cb781a814f5d90e0626cbe3e7f000
--- a/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf
@@ -266,7 +266,7 @@ RUs = (
     max_pdschReferenceSignalPower = -27;
     max_rxgain                    = 118;
     eNB_instances  = [0];
-    clock_src      = "external";
+#    clock_src      = "external";
   }
 );  
 
diff --git a/ci-scripts/conf_files/enb.band7.tm2.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band7.tm2.25PRB.usrpb210.conf
index 67cc5706aec87266a8406e2332d7c37fe06d39de..72754165d06319d5e38dec4eecafd0ee933d2b5a 100644
--- a/ci-scripts/conf_files/enb.band7.tm2.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.band7.tm2.25PRB.usrpb210.conf
@@ -249,7 +249,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf
index 1b5376644b67e82bf7ff7bd33843f5b2d2251c24..da65aad775e4154d95f8ff2ea9c7d571c556d89e 100644
--- a/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf
@@ -244,7 +244,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "eth0";
-    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf
old mode 100755
new mode 100644
index 0d9691966bea56f5c2efc3525d21898e47f66f6d..259a2466ad862387335d729315b5c5580011002e
--- a/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf
@@ -1,6 +1,8 @@
 Active_gNBs = ( "gNB-Eurecom-5GNRBox");
 # Asn1_verbosity, choice in: none, info, annoying
 Asn1_verbosity = "none";
+Num_Threads_PUSCH = 8
+
 
 gNBs =
 (
@@ -21,7 +23,10 @@ gNBs =
 
     ssb_SubcarrierOffset                                      = 31; //0;
     pdsch_AntennaPorts                                        = 1;
-  
+    pusch_TargetSNRx10                                        = 200; 
+    pucch_TargetSNRx10                                        = 200;
+
+ 
     servingCellConfigCommon = (
     {
  #spCellConfigCommon
@@ -260,7 +265,7 @@ RUs = (
          max_pdschReferenceSignalPower = -27;
          max_rxgain                    = 114;
          eNB_instances  = [0];
-         clock_src = "external";
+#         clock_src = "external";
     }
 );  
 
diff --git a/ci-scripts/conf_files/rcc.band40.tm1.100PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/rcc.band40.tm1.100PRB.FairScheduler.usrpb210.conf
index 2bf79a3d7e027d9257c608901b66b2b890751a19..d01e4e1c4e039ba4e77888b8b29537b9798c16a0 100644
--- a/ci-scripts/conf_files/rcc.band40.tm1.100PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band40.tm1.100PRB.FairScheduler.usrpb210.conf
@@ -235,7 +235,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band40.tm1.25PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/rcc.band40.tm1.25PRB.FairScheduler.usrpb210.conf
index 6b0e7de659006601a6e6486fc3bff11a91485bb5..419598647b123e8d151037127fea63f3fbc6393e 100644
--- a/ci-scripts/conf_files/rcc.band40.tm1.25PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band40.tm1.25PRB.FairScheduler.usrpb210.conf
@@ -235,7 +235,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band40.tm1.50PRB.FairScheduler.usrpb210.conf b/ci-scripts/conf_files/rcc.band40.tm1.50PRB.FairScheduler.usrpb210.conf
index 6b41d785066a73ec7dae03af05f65401980ad43f..d4f2eb9ef2f46def7cb4e273ee1f8ce9e303e6e2 100644
--- a/ci-scripts/conf_files/rcc.band40.tm1.50PRB.FairScheduler.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band40.tm1.50PRB.FairScheduler.usrpb210.conf
@@ -235,7 +235,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.100PRB.usrpb210.conf b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.100PRB.usrpb210.conf
index 5df8f16f78e137858c3d2847951210fbefe05bae..683fff0bc800106c28dd84f51c6df3a5d7036d07 100644
--- a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.100PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.100PRB.usrpb210.conf
@@ -254,7 +254,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.25PRB.usrpb210.conf b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.25PRB.usrpb210.conf
index ad753bb11408f1f9d9122bdd13a0cd5990172c66..2c3c11b84f287cc237922114166ecf9809863331 100644
--- a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.25PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.25PRB.usrpb210.conf
@@ -254,7 +254,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.50PRB.usrpb210.conf b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.50PRB.usrpb210.conf
index dbe3aff3dcc5cc283cbcdc03fecb926bed9a2f2f..49365a1f616e58a44e7641c68b2a4d153fab9664 100644
--- a/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.50PRB.usrpb210.conf
+++ b/ci-scripts/conf_files/rcc.band7.tm1.if4p5.lo.50PRB.usrpb210.conf
@@ -254,7 +254,7 @@ NETWORK_CONTROLLER :
 {
     FLEXRAN_ENABLED        = "no";
     FLEXRAN_INTERFACE_NAME = "lo";
-    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_IPV4_ADDRESS   = "CI_FLEXRAN_CTL_IP_ADDR";
     FLEXRAN_PORT           = 2210;
     FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
     FLEXRAN_AWAIT_RECONF   = "no";
diff --git a/ci-scripts/conf_files/rru.fdd.band7.conf b/ci-scripts/conf_files/rru.fdd.band7.conf
index ea923ae3718a6a61ed08481d16e1f91df8f1db5b..057f518046573be0b8de1bfc15096792bbe38964 100644
--- a/ci-scripts/conf_files/rru.fdd.band7.conf
+++ b/ci-scripts/conf_files/rru.fdd.band7.conf
@@ -1,23 +1,25 @@
-RUs = (
-    {
-        local_if_name                    = "lo";
-        remote_address                   = "127.0.0.1"
-        local_address                    = "127.0.0.2";
-        local_portc                       = 50000;
-        remote_portc                      = 50000;
-        local_portd                       = 50001;
-        remote_portd                      = 50001;
-        local_rf                         = "yes"
-        tr_preference                    = "udp_if4p5";
-        nb_tx                            = 1;
-        nb_rx                            = 1;
-        max_pdschReferenceSignalPower    = -27;
-        max_rxgain                       = 115;
-        bands                            = [7];
-    }
+RUs =
+(
+  {
+    local_if_name                 = "lo";
+    remote_address                = "127.0.0.1"
+    local_address                 = "127.0.0.2";
+    local_portc                   = 50000;
+    remote_portc                  = 50000;
+    local_portd                   = 50001;
+    remote_portd                  = 50001;
+    local_rf                      = "yes"
+    tr_preference                 = "udp_if4p5";
+    nb_tx                         = 1;
+    nb_rx                         = 1;
+    max_pdschReferenceSignalPower = -27;
+    max_rxgain                    = 115;
+    bands                         = [7];
+  }
 );
 
-THREAD_STRUCT = (
+THREAD_STRUCT =
+(
   {
     #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
     parallel_config    = "PARALLEL_SINGLE_THREAD";
@@ -26,19 +28,20 @@ THREAD_STRUCT = (
   }
 );
 
-log_config = {
-      global_log_level                      ="error";
-      global_log_verbosity                  ="medium";
-      hw_log_level                          ="error";
-      hw_log_verbosity                      ="medium";
-      phy_log_level                         ="error";
-      phy_log_verbosity                     ="medium";
-      mac_log_level                         ="error";
-      mac_log_verbosity                     ="high";
-      rlc_log_level                         ="error";
-      rlc_log_verbosity                     ="medium";
-      pdcp_log_level                        ="error";
-      pdcp_log_verbosity                    ="medium";
-      rrc_log_level                         ="error";
-      rrc_log_verbosity                     ="medium";
+log_config =
+{
+  global_log_level      ="error";
+  global_log_verbosity  ="medium";
+  hw_log_level          ="error";
+  hw_log_verbosity      ="medium";
+  phy_log_level         ="error";
+  phy_log_verbosity     ="medium";
+  mac_log_level         ="error";
+  mac_log_verbosity     ="high";
+  rlc_log_level         ="error";
+  rlc_log_verbosity     ="medium";
+  pdcp_log_level        ="error";
+  pdcp_log_verbosity    ="medium";
+  rrc_log_level         ="error";
+  rrc_log_verbosity     ="medium";
 };
diff --git a/ci-scripts/conf_files/rru.tdd.band40.conf b/ci-scripts/conf_files/rru.tdd.band40.conf
index 904f8c95989efadaedeb94755688cd1c6bb4a717..5ce3a515f58987b63d4a578925eb24a7cf5de4d2 100644
--- a/ci-scripts/conf_files/rru.tdd.band40.conf
+++ b/ci-scripts/conf_files/rru.tdd.band40.conf
@@ -1,23 +1,25 @@
-RUs = (
-    {
-        local_if_name                    = "lo";
-        remote_address                   = "127.0.0.1"
-        local_address                    = "127.0.0.2";
-        local_portc                       = 50000;
-        remote_portc                      = 50000;
-        local_portd                       = 50001;
-        remote_portd                      = 50001;
-        local_rf                         = "yes"
-        tr_preference                    = "udp_if4p5";
-        nb_tx                            = 1;
-        nb_rx                            = 1;
-        max_pdschReferenceSignalPower    = -27;
-        max_rxgain                       = 115;
-        bands                            = [40];
-    }
+RUs =
+(
+  {
+    local_if_name                 = "lo";
+    remote_address                = "127.0.0.1"
+    local_address                 = "127.0.0.2";
+    local_portc                   = 50000;
+    remote_portc                  = 50000;
+    local_portd                   = 50001;
+    remote_portd                  = 50001;
+    local_rf                      = "yes"
+    tr_preference                 = "udp_if4p5";
+    nb_tx                         = 1;
+    nb_rx                         = 1;
+    max_pdschReferenceSignalPower = -27;
+    max_rxgain                    = 115;
+    bands                         = [40];
+  }
 );
 
-THREAD_STRUCT = (
+THREAD_STRUCT =
+(
   {
     #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
     parallel_config    = "PARALLEL_SINGLE_THREAD";
@@ -26,19 +28,20 @@ THREAD_STRUCT = (
   }
 );
 
-log_config = {
-      global_log_level                      ="error";
-      global_log_verbosity                  ="medium";
-      hw_log_level                          ="error";
-      hw_log_verbosity                      ="medium";
-      phy_log_level                         ="error";
-      phy_log_verbosity                     ="medium";
-      mac_log_level                         ="error";
-      mac_log_verbosity                     ="high";
-      rlc_log_level                         ="error";
-      rlc_log_verbosity                     ="medium";
-      pdcp_log_level                        ="error";
-      pdcp_log_verbosity                    ="medium";
-      rrc_log_level                         ="error";
-      rrc_log_verbosity                     ="medium";
+log_config =
+{
+  global_log_level      ="error";
+  global_log_verbosity  ="medium";
+  hw_log_level          ="error";
+  hw_log_verbosity      ="medium";
+  phy_log_level         ="error";
+  phy_log_verbosity     ="medium";
+  mac_log_level         ="error";
+  mac_log_verbosity     ="high";
+  rlc_log_level         ="error";
+  rlc_log_verbosity     ="medium";
+  pdcp_log_level        ="error";
+  pdcp_log_verbosity    ="medium";
+  rrc_log_level         ="error";
+  rrc_log_verbosity     ="medium";
 };
diff --git a/ci-scripts/constants.py b/ci-scripts/constants.py
index c5698c5a3ef38dee1ad100933b3a63bbef1b7478..a0e1ac5c45c57490db5edf3115e39e25098d667f 100644
--- a/ci-scripts/constants.py
+++ b/ci-scripts/constants.py
@@ -59,6 +59,7 @@ OAI_UE_PROCESS_NO_TUNNEL_INTERFACE = -24
 OAI_UE_PROCESS_SEG_FAULT = -25
 OAI_UE_PROCESS_NO_MBMS_MSGS = -26
 OAI_UE_PROCESS_OK = +6
+INVALID_PARAMETER = -50
 
 UE_STATUS_DETACHED = 0
 UE_STATUS_DETACHING = 1
diff --git a/ci-scripts/epc.py b/ci-scripts/epc.py
index a1994c5ac31b5b30d9f2e40acba29505dc8517e4..cd5a74765435065df2b8643b47e17b7917a5f86c 100644
--- a/ci-scripts/epc.py
+++ b/ci-scripts/epc.py
@@ -46,7 +46,6 @@ from multiprocessing import Process, Lock, SimpleQueue
 import sshconnection as SSH 
 import helpreadme as HELP
 import constants as CONST
-import html
 
 #-----------------------------------------------------------
 # Class Declaration
@@ -61,18 +60,18 @@ class EPCManagement():
 		self.SourceCodePath = ''
 		self.Type = ''
 		self.PcapFileName = ''
-		self.htmlObj = None
 		self.testCase_id = ''
 		self.MmeIPAddress = ''
 		self.containerPrefix = 'prod'
 		self.mmeConfFile = 'mme.conf'
+		self.yamlPath = ''
 
 
 #-----------------------------------------------------------
 # EPC management functions
 #-----------------------------------------------------------
 
-	def InitializeHSS(self):
+	def InitializeHSS(self, HTML):
 		if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '':
 			HELP.GenericHelp(CONST.Version)
 			HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type)
@@ -114,10 +113,9 @@ class EPCManagement():
 		else:
 			logging.error('This option should not occur!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
 
-	def InitializeMME(self):
+	def InitializeMME(self, HTML):
 		if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '':
 			HELP.GenericHelp(CONST.Version)
 			HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type)
@@ -153,8 +151,7 @@ class EPCManagement():
 		else:
 			logging.error('This option should not occur!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
 
 	def SetMmeIPAddress(self):
 		# Not an error if we don't need an EPC
@@ -175,7 +172,7 @@ class EPCManagement():
 		else:
 			self.MmeIPAddress = self.IPAddress
 
-	def InitializeSPGW(self):
+	def InitializeSPGW(self, HTML):
 		if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '':
 			HELP.GenericHelp(CONST.Version)
 			HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type)
@@ -212,15 +209,14 @@ class EPCManagement():
 		else:
 			logging.error('This option should not occur!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
 
 	def CheckHSSProcess(self, status_queue):
 		try:
 			mySSH = SSH.SSHConnection() 
 			mySSH.open(self.IPAddress, self.UserName, self.Password)
 			if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-				mySSH.command('docker exec -it ' + self.containerPrefix + '-oai-hss /bin/bash -c "ps aux | grep oai_hss"', '\$', 5)
+				mySSH.command('docker top ' + self.containerPrefix + '-oai-hss', '\$', 5)
 			else:
 				mySSH.command('stdbuf -o0 ps -aux | grep --color=never hss | grep -v grep', '\$', 5)
 			if re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -245,7 +241,7 @@ class EPCManagement():
 			mySSH = SSH.SSHConnection() 
 			mySSH.open(self.IPAddress, self.UserName, self.Password)
 			if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-				mySSH.command('docker exec -it ' + self.containerPrefix + '-oai-mme /bin/bash -c "ps aux | grep oai_mme"', '\$', 5)
+				mySSH.command('docker top ' + self.containerPrefix + '-oai-mme', '\$', 5)
 			else:
 				mySSH.command('stdbuf -o0 ps -aux | grep --color=never mme | grep -v grep', '\$', 5)
 			if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -272,11 +268,11 @@ class EPCManagement():
 			mySSH = SSH.SSHConnection() 
 			mySSH.open(self.IPAddress, self.UserName, self.Password)
 			if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-				mySSH.command('docker exec -it ' + self.containerPrefix + '-oai-spgwc /bin/bash -c "ps aux | grep oai_spgwc"', '\$', 5)
-				result = re.search('oai_spgwc -o -c ', mySSH.getBefore())
+				mySSH.command('docker top ' + self.containerPrefix + '-oai-spgwc', '\$', 5)
+				result = re.search('oai_spgwc -', mySSH.getBefore())
 				if result is not None:
-					mySSH.command('docker exec -it ' + self.containerPrefix + '-oai-spgwu-tiny /bin/bash -c "ps aux | grep oai_spgwu"', '\$', 5)
-					result = re.search('oai_spgwu -o -c ', mySSH.getBefore())
+					mySSH.command('docker top ' + self.containerPrefix + '-oai-spgwu-tiny', '\$', 5)
+					result = re.search('oai_spgwu -', mySSH.getBefore())
 			elif re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE):
 				mySSH.command('stdbuf -o0 ps -aux | grep --color=never spgw | grep -v grep', '\$', 5)
 				result = re.search('spgwu -c ', mySSH.getBefore())
@@ -297,7 +293,7 @@ class EPCManagement():
 		except:
 			os.kill(os.getppid(),signal.SIGUSR1)
 
-	def TerminateHSS(self):
+	def TerminateHSS(self, HTML):
 		mySSH = SSH.SSHConnection() 
 		mySSH.open(self.IPAddress, self.UserName, self.Password)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -330,10 +326,9 @@ class EPCManagement():
 		else:
 			logging.error('This should not happen!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
 
-	def TerminateMME(self):
+	def TerminateMME(self, HTML):
 		mySSH = SSH.SSHConnection() 
 		mySSH.open(self.IPAddress, self.UserName, self.Password)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -357,10 +352,9 @@ class EPCManagement():
 		else:
 			logging.error('This should not happen!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
 
-	def TerminateSPGW(self):
+	def TerminateSPGW(self, HTML):
 		mySSH = SSH.SSHConnection() 
 		mySSH.open(self.IPAddress, self.UserName, self.Password)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
@@ -401,8 +395,155 @@ class EPCManagement():
 		else:
 			logging.error('This should not happen!')
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+
+	def DeployEpc(self, HTML):
+		logging.debug('Trying to deploy')
+		if not re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+			HTML.CreateHtmlTabFooter(False)
+			sys.exit('Deploy not possible with this EPC type: ' + self.Type)
+
+		if self.IPAddress == '' or self.UserName == '' or self.Password == '' or self.SourceCodePath == '' or self.Type == '':
+			HELP.GenericHelp(CONST.Version)
+			HELP.EPCSrvHelp(self.IPAddress, self.UserName, self.Password, self.SourceCodePath, self.Type)
+			sys.exit('Insufficient EPC Parameters')
+		mySSH = SSH.SSHConnection() 
+		mySSH.open(self.IPAddress, self.UserName, self.Password)
+		mySSH.command('docker-compose --version', '\$', 5)
+		result = re.search('docker-compose version 1', mySSH.getBefore())
+		if result is None:
+			mySSH.close()
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+			HTML.CreateHtmlTabFooter(False)
+			sys.exit('docker-compose not installed on ' + self.IPAddress)
+
+		mySSH.command('if [ -d ' + self.SourceCodePath + '/scripts ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/scripts ; fi', '\$', 5)
+		mySSH.command('if [ -d ' + self.SourceCodePath + '/logs ]; then echo ' + self.Password + ' | sudo -S rm -Rf ' + self.SourceCodePath + '/logs ; fi', '\$', 5)
+		mySSH.command('mkdir -p ' + self.SourceCodePath + '/scripts ' + self.SourceCodePath + '/logs', '\$', 5)
+
+		# deploying and configuring the cassandra database
+		# container names and services are currently hard-coded.
+		# they could be recovered by:
+		# - docker-compose config --services
+		# - docker-compose config | grep container_name
+		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
+		mySSH.copyout(self.IPAddress, self.UserName, self.Password, './' + self.yamlPath + '/docker-compose.yml', self.SourceCodePath + '/scripts')
+		mySSH.command('wget --quiet --tries=3 --retry-connrefused https://raw.githubusercontent.com/OPENAIRINTERFACE/openair-hss/develop/src/hss_rel14/db/oai_db.cql', '\$', 30)
+		mySSH.command('docker-compose down', '\$', 60)
+		mySSH.command('docker-compose up -d db_init', '\$', 60)
+
+		# databases take time...
+		time.sleep(10)
+		cnt = 0
+		db_init_status = False
+		while (cnt < 10):
+			mySSH.command('docker logs prod-db-init', '\$', 5)
+			result = re.search('OK', mySSH.getBefore())
+			if result is not None:
+				cnt = 10
+				db_init_status = True
+			else:
+				time.sleep(5)
+				cnt += 1
+		mySSH.command('docker rm -f prod-db-init', '\$', 5)
+		if not db_init_status:
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+			HTML.CreateHtmlTabFooter(False)
+			sys.exit('Cassandra DB deployment/configuration went wrong!')
+
+		# deploying EPC cNFs
+		mySSH.command('docker-compose up -d oai_spgwu', '\$', 60)
+		listOfContainers = 'prod-cassandra prod-oai-hss prod-oai-mme prod-oai-spgwc prod-oai-spgwu-tiny'
+		expectedHealthyContainers = 5
+
+		# Checking for additional services
+		mySSH.command('docker-compose config', '\$', 5)
+		configResponse = mySSH.getBefore()
+		if configResponse.count('flexran_rtc') == 1:
+			mySSH.command('docker-compose up -d flexran_rtc', '\$', 60)
+			listOfContainers += ' prod-flexran-rtc'
+			expectedHealthyContainers += 1
+		if configResponse.count('trf_gen') == 1:
+			mySSH.command('docker-compose up -d trf_gen', '\$', 60)
+			listOfContainers += ' prod-trf-gen'
+			expectedHealthyContainers += 1
+
+		# Checking if all are healthy
+		cnt = 0
+		while (cnt < 3):
+			mySSH.command('docker inspect --format=\'{{.State.Health.Status}}\' ' + listOfContainers, '\$', 10)
+			unhealthyNb = mySSH.getBefore().count('unhealthy')
+			healthyNb = mySSH.getBefore().count('healthy') - unhealthyNb
+			startingNb = mySSH.getBefore().count('starting')
+			if healthyNb == expectedHealthyContainers:
+				cnt = 10
+			else:
+				time.sleep(10)
+				cnt += 1
+		logging.debug(' -- ' + str(healthyNb) + ' healthy container(s)')
+		logging.debug(' -- ' + str(unhealthyNb) + ' unhealthy container(s)')
+		logging.debug(' -- ' + str(startingNb) + ' still starting container(s)')
+		if healthyNb == expectedHealthyContainers:
+			mySSH.command('docker exec -d prod-oai-hss /bin/bash -c "nohup tshark -i any -f \'port 9042 or port 3868\' -w /tmp/hss_check_run.pcap 2>&1 > /dev/null"', '\$', 5)
+			mySSH.command('docker exec -d prod-oai-mme /bin/bash -c "nohup tshark -i any -f \'port 3868 or port 2123 or port 36412\' -w /tmp/mme_check_run.pcap 2>&1 > /dev/null"', '\$', 10)
+			mySSH.command('docker exec -d prod-oai-spgwc /bin/bash -c "nohup tshark -i any -f \'port 2123 or port 8805\' -w /tmp/spgwc_check_run.pcap 2>&1 > /dev/null"', '\$', 10)
+			# on SPGW-U, not capturing on SGI to avoid huge file
+			mySSH.command('docker exec -d prod-oai-spgwu-tiny /bin/bash -c "nohup tshark -i any -f \'port 8805\'  -w /tmp/spgwu_check_run.pcap 2>&1 > /dev/null"', '\$', 10)
+			mySSH.close()
+			logging.debug('Deployment OK')
+			HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+		else:
+			mySSH.close()
+			logging.debug('Deployment went wrong')
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
+
+	def UndeployEpc(self, HTML):
+		logging.debug('Trying to undeploy')
+		# No check down, we suppose everything done before.
+
+		mySSH = SSH.SSHConnection() 
+		mySSH.open(self.IPAddress, self.UserName, self.Password)
+		# Recovering logs and pcap files
+		mySSH.command('cd ' + self.SourceCodePath + '/logs', '\$', 5)
+		mySSH.command('docker exec -it prod-oai-hss /bin/bash -c "killall --signal SIGINT oai_hss tshark"', '\$', 5)
+		mySSH.command('docker exec -it prod-oai-mme /bin/bash -c "killall --signal SIGINT tshark"', '\$', 5)
+		mySSH.command('docker exec -it prod-oai-spgwc /bin/bash -c "killall --signal SIGINT oai_spgwc tshark"', '\$', 5)
+		mySSH.command('docker exec -it prod-oai-spgwu-tiny /bin/bash -c "killall --signal SIGINT tshark"', '\$', 5)
+		mySSH.command('docker logs prod-oai-hss > hss_' + self.testCase_id + '.log', '\$', 5)
+		mySSH.command('docker logs prod-oai-mme > mme_' + self.testCase_id + '.log', '\$', 5)
+		mySSH.command('docker logs prod-oai-spgwc > spgwc_' + self.testCase_id + '.log', '\$', 5)
+		mySSH.command('docker logs prod-oai-spgwu-tiny > spgwu_' + self.testCase_id + '.log', '\$', 5)
+		mySSH.command('docker cp prod-oai-hss:/tmp/hss_check_run.pcap hss_' + self.testCase_id + '.pcap', '\$', 60)
+		mySSH.command('docker cp prod-oai-mme:/tmp/mme_check_run.pcap mme_' + self.testCase_id + '.pcap', '\$', 60)
+		mySSH.command('docker cp prod-oai-spgwc:/tmp/spgwc_check_run.pcap spgwc_' + self.testCase_id + '.pcap', '\$', 60)
+		mySSH.command('docker cp prod-oai-spgwu-tiny:/tmp/spgwu_check_run.pcap spgwu_' + self.testCase_id + '.pcap', '\$', 60)
+		# Remove all
+		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
+		listOfContainers = 'prod-cassandra prod-oai-hss prod-oai-mme prod-oai-spgwc prod-oai-spgwu-tiny'
+		nbContainers = 5
+		# Checking for additional services
+		mySSH.command('docker-compose config', '\$', 5)
+		configResponse = mySSH.getBefore()
+		if configResponse.count('flexran_rtc') == 1:
+			listOfContainers += ' prod-flexran-rtc'
+			nbContainers += 1
+		if configResponse.count('trf_gen') == 1:
+			listOfContainers += ' prod-trf-gen'
+			nbContainers += 1
+
+		mySSH.command('docker-compose down', '\$', 60)
+		mySSH.command('docker inspect --format=\'{{.State.Health.Status}}\' ' + listOfContainers, '\$', 10)
+		noMoreContainerNb = mySSH.getBefore().count('No such object')
+		mySSH.command('docker inspect --format=\'{{.Name}}\' prod-oai-public-net prod-oai-private-net', '\$', 10)
+		noMoreNetworkNb = mySSH.getBefore().count('No such object')
+		mySSH.close()
+		if noMoreContainerNb == nbContainers and noMoreNetworkNb == 2:
+			logging.debug('Undeployment OK')
+			HTML.CreateHtmlTestRow(self.Type, 'OK', CONST.ALL_PROCESSES_OK)
+		else:
+			logging.debug('Undeployment went wrong')
+			HTML.CreateHtmlTestRow(self.Type, 'KO', CONST.INVALID_PARAMETER)
 
 	def LogCollectHSS(self):
 		mySSH = SSH.SSHConnection() 
@@ -410,9 +551,17 @@ class EPCManagement():
 		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
 		mySSH.command('rm -f hss.log.zip', '\$', 5)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-hss:/openair-hss/hss_check_run.log .', '\$', 60)
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-hss:/tmp/hss_check_run.pcap .', '\$', 60)
-			mySSH.command('zip hss.log.zip hss_check_run.*', '\$', 60)
+			mySSH.command('docker inspect prod-oai-hss', '\$', 10)
+			result = re.search('No such object', mySSH.getBefore())
+			if result is not None:
+				mySSH.command('cd ../logs', '\$', 5)
+				mySSH.command('rm -f hss.log.zip', '\$', 5)
+				mySSH.command('zip hss.log.zip hss_*.*', '\$', 60)
+				mySSH.command('mv hss.log.zip ../scripts', '\$', 60)
+			else:
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-hss:/openair-hss/hss_check_run.log .', '\$', 60)
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-hss:/tmp/hss_check_run.pcap .', '\$', 60)
+				mySSH.command('zip hss.log.zip hss_check_run.*', '\$', 60)
 		elif re.match('OAI', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE):
 			mySSH.command('zip hss.log.zip hss*.log', '\$', 60)
 			mySSH.command('echo ' + self.Password + ' | sudo -S rm hss*.log', '\$', 5)
@@ -432,9 +581,17 @@ class EPCManagement():
 		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
 		mySSH.command('rm -f mme.log.zip', '\$', 5)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-mme:/openair-mme/mme_check_run.log .', '\$', 60)
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-mme:/tmp/mme_check_run.pcap .', '\$', 60)
-			mySSH.command('zip mme.log.zip mme_check_run.*', '\$', 60)
+			mySSH.command('docker inspect prod-oai-mme', '\$', 10)
+			result = re.search('No such object', mySSH.getBefore())
+			if result is not None:
+				mySSH.command('cd ../logs', '\$', 5)
+				mySSH.command('rm -f mme.log.zip', '\$', 5)
+				mySSH.command('zip mme.log.zip mme_*.*', '\$', 60)
+				mySSH.command('mv mme.log.zip ../scripts', '\$', 60)
+			else:
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-mme:/openair-mme/mme_check_run.log .', '\$', 60)
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-mme:/tmp/mme_check_run.pcap .', '\$', 60)
+				mySSH.command('zip mme.log.zip mme_check_run.*', '\$', 60)
 		elif re.match('OAI', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE):
 			mySSH.command('zip mme.log.zip mme*.log', '\$', 60)
 			mySSH.command('echo ' + self.Password + ' | sudo -S rm mme*.log', '\$', 5)
@@ -451,11 +608,19 @@ class EPCManagement():
 		mySSH.command('cd ' + self.SourceCodePath + '/scripts', '\$', 5)
 		mySSH.command('rm -f spgw.log.zip', '\$', 5)
 		if re.match('OAI-Rel14-Docker', self.Type, re.IGNORECASE):
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwc:/openair-spgwc/spgwc_check_run.log .', '\$', 60)
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwu-tiny:/openair-spgwu-tiny/spgwu_check_run.log .', '\$', 60)
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwc:/tmp/spgwc_check_run.pcap .', '\$', 60)
-			mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwu-tiny:/tmp/spgwu_check_run.pcap .', '\$', 60)
-			mySSH.command('zip spgw.log.zip spgw*_check_run.*', '\$', 60)
+			mySSH.command('docker inspect prod-oai-mme', '\$', 10)
+			result = re.search('No such object', mySSH.getBefore())
+			if result is not None:
+				mySSH.command('cd ../logs', '\$', 5)
+				mySSH.command('rm -f spgw.log.zip', '\$', 5)
+				mySSH.command('zip spgw.log.zip spgw*.*', '\$', 60)
+				mySSH.command('mv spgw.log.zip ../scripts', '\$', 60)
+			else:
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwc:/openair-spgwc/spgwc_check_run.log .', '\$', 60)
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwu-tiny:/openair-spgwu-tiny/spgwu_check_run.log .', '\$', 60)
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwc:/tmp/spgwc_check_run.pcap .', '\$', 60)
+				mySSH.command('docker cp ' + self.containerPrefix + '-oai-spgwu-tiny:/tmp/spgwu_check_run.pcap .', '\$', 60)
+				mySSH.command('zip spgw.log.zip spgw*_check_run.*', '\$', 60)
 		elif re.match('OAI', self.Type, re.IGNORECASE) or re.match('OAI-Rel14-CUPS', self.Type, re.IGNORECASE):
 			mySSH.command('zip spgw.log.zip spgw*.log', '\$', 60)
 			mySSH.command('echo ' + self.Password + ' | sudo -S rm spgw*.log', '\$', 5)
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 0358a056db9c5d02e1a265ab606d31d7fb6756ae..3625f4e38ed0f2317a1e594c28c54c0eac4258d4 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -41,6 +41,7 @@ import constants as CONST
 import cls_oaicitest		#main class for OAI CI test framework
 import cls_physim           #class PhySim for physical simulators build and test
 import cls_cots_ue			#class CotsUe for Airplane mode control
+import cls_containerize     #class Containerize for all container-based operations on RAN/UE objects
 
 
 import sshconnection 
@@ -97,24 +98,34 @@ def AssignParams(params_dict):
 
 
 def GetParametersFromXML(action):
-	if action == 'Build_eNB':
+	if action == 'Build_eNB' or action == 'Build_Image':
 		RAN.Build_eNB_args=test.findtext('Build_eNB_args')
+		CONTAINERS.imageKind=test.findtext('kind')
 		forced_workspace_cleanup = test.findtext('forced_workspace_cleanup')
 		if (forced_workspace_cleanup is None):
 			RAN.Build_eNB_forced_workspace_cleanup=False
+			CONTAINERS.forcedWorkspaceCleanup=False
 		else:
 			if re.match('true', forced_workspace_cleanup, re.IGNORECASE):
 				RAN.Build_eNB_forced_workspace_cleanup=True
+				CONTAINERS.forcedWorkspaceCleanup=True
 			else:
-				RAN.Build_eNB_forced_workspace_cleanup=False
+				RAN.Build_eNB_forced_workspace_cleanup=True
+				CONTAINERS.forcedWorkspaceCleanup=False
 		eNB_instance=test.findtext('eNB_instance')
 		if (eNB_instance is None):
 			RAN.eNB_instance=0
+			CONTAINERS.eNB_instance=0
 		else:
 			RAN.eNB_instance=int(eNB_instance)
-		RAN.eNB_serverId=test.findtext('eNB_serverId')
-		if (RAN.eNB_serverId is None):
-			RAN.eNB_serverId='0'
+			CONTAINERS.eNB_instance=int(eNB_instance)
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			RAN.eNB_serverId[RAN.eNB_instance]='0'
+			CONTAINERS.eNB_serverId[RAN.eNB_instance]='0'
+		else:
+			RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId
+			CONTAINERS.eNB_serverId[CONTAINERS.eNB_instance]=eNB_serverId
 		xmlBgBuildField = test.findtext('backgroundBuild')
 		if (xmlBgBuildField is None):
 			RAN.backgroundBuild=False
@@ -131,9 +142,11 @@ def GetParametersFromXML(action):
 			RAN.eNB_instance=0
 		else:
 			RAN.eNB_instance=int(eNB_instance)
-		RAN.eNB_serverId=test.findtext('eNB_serverId')
-		if (RAN.eNB_serverId is None):
-			RAN.eNB_serverId='0'
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			RAN.eNB_serverId[RAN.eNB_instance]='0'
+		else:
+			RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId
 
 	elif action == 'Initialize_eNB':
 		RAN.Initialize_eNB_args=test.findtext('Initialize_eNB_args')
@@ -142,9 +155,11 @@ def GetParametersFromXML(action):
 			RAN.eNB_instance=0
 		else:
 			RAN.eNB_instance=int(eNB_instance)
-		RAN.eNB_serverId=test.findtext('eNB_serverId')
-		if (RAN.eNB_serverId is None):
-			RAN.eNB_serverId='0'
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			RAN.eNB_serverId[RAN.eNB_instance]='0'
+		else:
+			RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId
 			
 		#local variable air_interface
 		air_interface = test.findtext('air_interface')		
@@ -161,10 +176,12 @@ def GetParametersFromXML(action):
 			RAN.eNB_instance=0
 		else:
 			RAN.eNB_instance=int(eNB_instance)
-		RAN.eNB_serverId=test.findtext('eNB_serverId')
-		if (RAN.eNB_serverId is None):
-			RAN.eNB_serverId='0'
-			
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			RAN.eNB_serverId[RAN.eNB_instance]='0'
+		else:
+			RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId
+
 		#local variable air_interface
 		air_interface = test.findtext('air_interface')		
 		if (air_interface is None) or (air_interface.lower() not in ['nr','lte','ocp']):
@@ -287,6 +304,27 @@ def GetParametersFromXML(action):
 		if (string_field is not None):
 			EPC.mmeConfFile = string_field
 
+	elif action == 'Deploy_EPC':
+		string_field = test.findtext('parameters')
+		if (string_field is not None):
+			EPC.yamlPath = string_field
+
+	elif action == 'Deploy_Object' or action == 'Undeploy_Object':
+		eNB_instance=test.findtext('eNB_instance')
+		if (eNB_instance is None):
+			CONTAINERS.eNB_instance=0
+		else:
+			CONTAINERS.eNB_instance=int(eNB_instance)
+		eNB_serverId=test.findtext('eNB_serverId')
+		if (eNB_serverId is None):
+			CONTAINERS.eNB_serverId[CONTAINERS.eNB_instance]='0'
+		else:
+			CONTAINERS.eNB_serverId[CONTAINERS.eNB_instance]=eNB_serverId
+		string_field = test.findtext('yaml_path')
+		if (string_field is not None):
+			CONTAINERS.yamlPath[CONTAINERS.eNB_instance] = string_field
+
+
 	else: # ie action == 'Run_PhySim':
 		ldpc.runargs = test.findtext('physim_run_args')
 		
@@ -338,11 +376,7 @@ SSH = sshconnection.SSHConnection()
 EPC = epc.EPCManagement()
 RAN = ran.RANManagement()
 HTML = html.HTMLManagement()
-
-EPC.htmlObj=HTML
-RAN.htmlObj=HTML
-RAN.epcObj=EPC
-
+CONTAINERS = cls_containerize.Containerize()
 
 ldpc=cls_physim.PhySim()    #create an instance for LDPC test using GPU or CPU build
 
@@ -353,7 +387,7 @@ ldpc=cls_physim.PhySim()    #create an instance for LDPC test using GPU or CPU b
 #-----------------------------------------------------------
 
 import args_parse
-py_param_file_present, py_params, mode = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,EPC,ldpc,HELP)
+py_param_file_present, py_params, mode = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP)
 
 
 
@@ -382,10 +416,10 @@ if re.match('^TerminateeNB$', mode, re.IGNORECASE):
 	if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '':
 		HELP.GenericHelp(CONST.Version)
 		sys.exit('Insufficient Parameter')
-	RAN.eNB_serverId='0'
 	RAN.eNB_instance=0
+	RAN.eNB_serverId[0]='0'
 	RAN.eNBSourceCodePath='/tmp/'
-	RAN.TerminateeNB()
+	RAN.TerminateeNB(HTML, EPC)
 elif re.match('^TerminateUE$', mode, re.IGNORECASE):
 	if (CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == ''):
 		HELP.GenericHelp(CONST.Version)
@@ -397,22 +431,22 @@ elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE):
 		HELP.GenericHelp(CONST.Version)
 		sys.exit('Insufficient Parameter')
 	signal.signal(signal.SIGUSR1, receive_signal)
-	CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE)
+	CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE,EPC)
 elif re.match('^TerminateHSS$', mode, re.IGNORECASE):
 	if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.Type == '' or EPC.SourceCodePath == '':
 		HELP.GenericHelp(CONST.Version)
 		sys.exit('Insufficient Parameter')
-	EPC.TerminateHSS()
+	EPC.TerminateHSS(HTML)
 elif re.match('^TerminateMME$', mode, re.IGNORECASE):
 	if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.Type == '' or EPC.SourceCodePath == '':
 		HELP.GenericHelp(CONST.Version)
 		sys.exit('Insufficient Parameter')
-	EPC.TerminateMME()
+	EPC.TerminateMME(HTML)
 elif re.match('^TerminateSPGW$', mode, re.IGNORECASE):
 	if EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.Type == '' or EPC.SourceCodePath== '':
 		HELP.GenericHelp(CONST.Version)
 		sys.exit('Insufficient Parameter')
-	EPC.TerminateSPGW()
+	EPC.TerminateSPGW(HTML)
 elif re.match('^LogCollectBuild$', mode, re.IGNORECASE):
 	if (RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '') and (CiTestObj.UEIPAddress == '' or CiTestObj.UEUserName == '' or CiTestObj.UEPassword == '' or CiTestObj.UESourceCodePath == ''):
 		HELP.GenericHelp(CONST.Version)
@@ -494,7 +528,7 @@ elif re.match('^FinalizeHtml$', mode, re.IGNORECASE):
 	HTML.CreateHtmlFooter(CiTestObj.finalStatus)
 elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE):
 	logging.debug('\u001B[1m----------------------------------------\u001B[0m')
-	logging.debug('\u001B[1m  Starting Scenario \u001B[0m')
+	logging.debug('\u001B[1m  Starting Scenario: ' + CiTestObj.testXMLfiles[0] + '\u001B[0m')
 	logging.debug('\u001B[1m----------------------------------------\u001B[0m')
 	if re.match('^TesteNB$', mode, re.IGNORECASE):
 		if RAN.eNBIPAddress == '' or RAN.ranRepository == '' or RAN.ranBranch == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '' or EPC.IPAddress == '' or EPC.UserName == '' or EPC.Password == '' or EPC.Type == '' or EPC.SourceCodePath == '' or CiTestObj.ADBIPAddress == '' or CiTestObj.ADBUserName == '' or CiTestObj.ADBPassword == '':
@@ -565,7 +599,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 			logging.debug('ERROR: requested test is invalidly formatted: ' + test)
 			sys.exit(1)
 	if (EPC.IPAddress != '') and (EPC.IPAddress != 'none'):
-		CiTestObj.CheckFlexranCtrlInstallation(RAN,EPC)
+		CiTestObj.CheckFlexranCtrlInstallation(RAN,EPC,CONTAINERS)
 		EPC.SetMmeIPAddress()
 
 	#get the list of tests to be done
@@ -625,17 +659,16 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 							RAN.prematureExit = True
 							break
 				if action == 'Build_eNB':
-					RAN.BuildeNB()
+					RAN.BuildeNB(HTML)
 				elif action == 'WaitEndBuild_eNB':
-					RAN.WaitBuildeNBisFinished()
+					RAN.WaitBuildeNBisFinished(HTML)
 				elif action == 'Initialize_eNB':
 					check_eNB = False
 					check_OAI_UE = False
 					RAN.pStatus=CiTestObj.CheckProcessExist(check_eNB, check_OAI_UE,RAN,EPC)
-
-					RAN.InitializeeNB()
+					RAN.InitializeeNB(HTML, EPC)
 				elif action == 'Terminate_eNB':
-					RAN.TerminateeNB()
+					RAN.TerminateeNB(HTML, EPC)
 				elif action == 'Initialize_UE':
 					CiTestObj.InitializeUE(HTML,COTS_UE)
 				elif action == 'Terminate_UE':
@@ -655,17 +688,17 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 				elif action == 'Initialize_OAI_UE':
 					CiTestObj.InitializeOAIUE(HTML,RAN,EPC,COTS_UE)
 				elif action == 'Terminate_OAI_UE':
-					CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE)
+					CiTestObj.TerminateOAIUE(HTML,RAN,COTS_UE,EPC)
 				elif action == 'Initialize_CatM_module':
 					CiTestObj.InitializeCatM(HTML)
 				elif action == 'Terminate_CatM_module':
 					CiTestObj.TerminateCatM(HTML)
 				elif action == 'Attach_CatM_module':
-					CiTestObj.AttachCatM(HTML,RAN,COTS_UE)
+					CiTestObj.AttachCatM(HTML,RAN,COTS_UE,EPC)
 				elif action == 'Detach_CatM_module':
 					CiTestObj.TerminateCatM(HTML)
 				elif action == 'Ping_CatM_module':
-					CiTestObj.PingCatM(HTML,RAN,EPC,COTS_UE)
+					CiTestObj.PingCatM(HTML,RAN,EPC,COTS_UE,EPC)
 				elif action == 'Ping':
 					CiTestObj.Ping(HTML,RAN,EPC,COTS_UE)
 				elif action == 'Iperf':
@@ -673,17 +706,21 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 				elif action == 'Reboot_UE':
 					CiTestObj.RebootUE(HTML,RAN,EPC)
 				elif action == 'Initialize_HSS':
-					EPC.InitializeHSS()
+					EPC.InitializeHSS(HTML)
 				elif action == 'Terminate_HSS':
-					EPC.TerminateHSS()
+					EPC.TerminateHSS(HTML)
 				elif action == 'Initialize_MME':
-					EPC.InitializeMME()
+					EPC.InitializeMME(HTML)
 				elif action == 'Terminate_MME':
-					EPC.TerminateMME()
+					EPC.TerminateMME(HTML)
 				elif action == 'Initialize_SPGW':
-					EPC.InitializeSPGW()
+					EPC.InitializeSPGW(HTML)
 				elif action == 'Terminate_SPGW':
-					EPC.TerminateSPGW()
+					EPC.TerminateSPGW(HTML)
+				elif action == 'Deploy_EPC':
+					EPC.DeployEpc(HTML)
+				elif action == 'Undeploy_EPC':
+					EPC.UndeployEpc(HTML)
 				elif action == 'Initialize_FlexranCtrl':
 					CiTestObj.InitializeFlexranCtrl(HTML,RAN,EPC)
 				elif action == 'Terminate_FlexranCtrl':
@@ -697,6 +734,12 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 					if ldpc.exitStatus==1:sys.exit()
 				elif action == 'Run_PhySim':
 					HTML=ldpc.Run_PhySim(HTML,CONST,id)
+				elif action == 'Build_Image':
+					CONTAINERS.BuildImage(HTML)
+				elif action == 'Deploy_Object':
+					CONTAINERS.DeployObject(HTML, EPC)
+				elif action == 'Undeploy_Object':
+					CONTAINERS.UndeployObject(HTML, RAN)
 				else:
 					sys.exit('Invalid class (action) from xml')
 				if not RAN.prematureExit:
@@ -706,14 +749,14 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 						HTML.testStabilityPointReached = True
 		CiTestObj.FailReportCnt += 1
 	if CiTestObj.FailReportCnt == CiTestObj.repeatCounts[0] and RAN.prematureExit:
-		logging.debug('Testsuite failed ' + str(CiTestObj.FailReportCnt) + ' time(s)')
+		logging.debug('Scenario failed ' + str(CiTestObj.FailReportCnt) + ' time(s)')
 		HTML.CreateHtmlTabFooter(False)
 		if CiTestObj.testUnstable and (CiTestObj.testStabilityPointReached or CiTestObj.testMinStableId == '999999'):
 			logging.debug('Scenario has reached minimal stability point -- Not a Failure')
 		else:
 			sys.exit('Failed Scenario')
 	else:
-		logging.info('Testsuite passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)')
+		logging.info('Scenario passed after ' + str(CiTestObj.FailReportCnt) + ' time(s)')
 		HTML.CreateHtmlTabFooter(True)
 elif re.match('^LoadParams$', mode, re.IGNORECASE):
 	pass
diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py
index 4f0844d8fb1a73a8d55c0a5f666f4c874cdbfa0f..7fc50e48430fde487675929d5288ae12a4e2c878 100644
--- a/ci-scripts/ran.py
+++ b/ci-scripts/ran.py
@@ -42,10 +42,8 @@ from multiprocessing import Process, Lock, SimpleQueue
 # OAI Testing modules
 #-----------------------------------------------------------
 import sshconnection as SSH
-import epc 
 import helpreadme as HELP
 import constants as CONST
-import html
 
 #-----------------------------------------------------------
 # Class Declaration
@@ -77,19 +75,20 @@ class RANManagement():
 		self.backgroundBuildTestId = ['', '', '']
 		self.Build_eNB_forced_workspace_cleanup = False
 		self.Initialize_eNB_args = ''
+		self.imageKind = ''
 		self.air_interface = ['', '', ''] #changed from 'lte' to '' may lead to side effects in main
 		self.eNB_instance = 0
-		self.eNB_serverId = ''
+		self.eNB_serverId = ['', '', '']
 		self.eNBLogFiles = ['', '', '']
 		self.eNBOptions = ['', '', '']
 		self.eNBmbmsEnables = [False, False, False]
 		self.eNBstatuses = [-1, -1, -1]
 		self.flexranCtrlInstalled = False
 		self.flexranCtrlStarted = False
+		self.flexranCtrlDeployed = False
+		self.flexranCtrlIpAddress = ''
 		self.testCase_id = ''
 		self.epcPcapFile = ''
-		self.htmlObj = None
-		self.epcObj = None
 		self.runtime_stats= ''
 
 
@@ -98,21 +97,21 @@ class RANManagement():
 # RAN management functions
 #-----------------------------------------------------------
 
-	def BuildeNB(self):
+	def BuildeNB(self, HTML):
 		if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
-		if self.eNB_serverId == '0':
+		if self.eNB_serverId[self.eNB_instance] == '0':
 			lIpAddr = self.eNBIPAddress
 			lUserName = self.eNBUserName
 			lPassWord = self.eNBPassword
 			lSourcePath = self.eNBSourceCodePath
-		elif self.eNB_serverId == '1':
+		elif self.eNB_serverId[self.eNB_instance] == '1':
 			lIpAddr = self.eNB1IPAddress
 			lUserName = self.eNB1UserName
 			lPassWord = self.eNB1Password
 			lSourcePath = self.eNB1SourceCodePath
-		elif self.eNB_serverId == '2':
+		elif self.eNB_serverId[self.eNB_instance] == '2':
 			lIpAddr = self.eNB2IPAddress
 			lUserName = self.eNB2UserName
 			lPassWord = self.eNB2Password
@@ -120,6 +119,7 @@ class RANManagement():
 		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
+		logging.debug('Building on server: ' + lIpAddr)
 		mySSH = SSH.SSHConnection()
 		mySSH.open(lIpAddr, lUserName, lPassWord)
 		
@@ -137,10 +137,7 @@ class RANManagement():
 		# Worakround for some servers, we need to erase completely the workspace
 		if self.Build_eNB_forced_workspace_cleanup:
 			mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf ' + lSourcePath, '\$', 15)
-		if self.htmlObj is not None:
-			self.testCase_id = self.htmlObj.testCase_id
-		else:
-			self.testCase_id = '000000'
+		self.testCase_id = HTML.testCase_id
 		# on RedHat/CentOS .git extension is mandatory
 		result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository)
 		if result is not None:
@@ -181,8 +178,7 @@ class RANManagement():
 						mismatch = True
 				if not mismatch:
 					mySSH.close()
-					if self.htmlObj is not None:
-						self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
+					HTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
 					return
 
 		mySSH.command('echo ' + lPassWord + ' | sudo -S git clean -x -d -ff', '\$', 30)
@@ -209,26 +205,25 @@ class RANManagement():
 			mySSH.command('echo ' + lPassWord + ' | sudo -S ls', '\$', 5)
 			mySSH.command('echo $USER; nohup sudo -E ./my-lte-softmodem-build.sh' + ' > ' + lSourcePath + '/cmake_targets/compile_oai_enb.log ' + ' 2>&1 &', lUserName, 5)
 			mySSH.close()
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
+			HTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
 			self.backgroundBuildTestId[int(self.eNB_instance)] = self.testCase_id
 			return
 		mySSH.command('stdbuf -o0 ./build_oai ' + self.Build_eNB_args + ' 2>&1 | stdbuf -o0 tee compile_oai_enb.log', 'Bypassing the Tests|build have failed', 1500)
 		mySSH.close()
-		self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id)
+		self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.testCase_id, HTML)
 
-	def WaitBuildeNBisFinished(self):
-		if self.eNB_serverId == '0':
+	def WaitBuildeNBisFinished(self, HTML):
+		if self.eNB_serverId[self.eNB_instance] == '0':
 			lIpAddr = self.eNBIPAddress
 			lUserName = self.eNBUserName
 			lPassWord = self.eNBPassword
 			lSourcePath = self.eNBSourceCodePath
-		elif self.eNB_serverId == '1':
+		elif self.eNB_serverId[self.eNB_instance] == '1':
 			lIpAddr = self.eNB1IPAddress
 			lUserName = self.eNB1UserName
 			lPassWord = self.eNB1Password
 			lSourcePath = self.eNB1SourceCodePath
-		elif self.eNB_serverId == '2':
+		elif self.eNB_serverId[self.eNB_instance] == '2':
 			lIpAddr = self.eNB2IPAddress
 			lUserName = self.eNB2UserName
 			lPassWord = self.eNB2Password
@@ -236,6 +231,7 @@ class RANManagement():
 		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
+		logging.debug('Waiting for end of build on server: ' + lIpAddr)
 		mySSH = SSH.SSHConnection()
 		mySSH.open(lIpAddr, lUserName, lPassWord)
 		count = 40
@@ -249,11 +245,10 @@ class RANManagement():
 				count -= 1
 				time.sleep(30)
 		mySSH.close()
-		self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)])
+		self.checkBuildeNB(lIpAddr, lUserName, lPassWord, lSourcePath, self.backgroundBuildTestId[int(self.eNB_instance)], HTML)
 
-	def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId):
-		if self.htmlObj is not None:
-			self.htmlObj.testCase_id=testcaseId
+	def checkBuildeNB(self, lIpAddr, lUserName, lPassWord, lSourcePath, testcaseId, HTML):
+		HTML.testCase_id=testcaseId
 
 		mySSH = SSH.SSHConnection()
 		mySSH.open(lIpAddr, lUserName, lPassWord)
@@ -284,7 +279,7 @@ class RANManagement():
 		mySSH.command('mkdir -p build_log_' + testcaseId, '\$', 5)
 		mySSH.command('mv log/* ' + 'build_log_' + testcaseId, '\$', 5)
 		mySSH.command('mv compile_oai_enb.log ' + 'build_log_' + testcaseId, '\$', 5)
-		if self.eNB_serverId != '0':
+		if self.eNB_serverId[self.eNB_instance] != '0':
 			mySSH.command('cd cmake_targets', '\$', 5)
 			mySSH.command('if [ -e tmp_build' + testcaseId + '.zip ]; then rm -f tmp_build' + testcaseId + '.zip; fi', '\$', 5)
 			mySSH.command('zip -r -qq tmp_build' + testcaseId + '.zip build_log_' + testcaseId, '\$', 5)
@@ -307,27 +302,25 @@ class RANManagement():
 		#generate logging info depending on buildStatus and air interface
 		if buildStatus:
 			logging.info('\u001B[1m Building OAI ' + self.air_interface[self.eNB_instance] + ' Pass\u001B[0m')
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)		
+			HTML.CreateHtmlTestRow(self.Build_eNB_args, 'OK', CONST.ALL_PROCESSES_OK)
 		else:
 			logging.error('\u001B[1m Building OAI ' + self.air_interface[self.eNB_instance] + ' Failed\u001B[0m')
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.Build_eNB_args, 'KO', CONST.ALL_PROCESSES_OK)
-				self.htmlObj.CreateHtmlTabFooter(False)
+			HTML.CreateHtmlTestRow(self.Build_eNB_args, 'KO', CONST.ALL_PROCESSES_OK)
+			HTML.CreateHtmlTabFooter(False)
 			sys.exit(1)
 
-	def InitializeeNB(self):
-		if self.eNB_serverId == '0':
+	def InitializeeNB(self, HTML, EPC):
+		if self.eNB_serverId[self.eNB_instance] == '0':
 			lIpAddr = self.eNBIPAddress
 			lUserName = self.eNBUserName
 			lPassWord = self.eNBPassword
 			lSourcePath = self.eNBSourceCodePath
-		elif self.eNB_serverId == '1':
+		elif self.eNB_serverId[self.eNB_instance] == '1':
 			lIpAddr = self.eNB1IPAddress
 			lUserName = self.eNB1UserName
 			lPassWord = self.eNB1Password
 			lSourcePath = self.eNB1SourceCodePath
-		elif self.eNB_serverId == '2':
+		elif self.eNB_serverId[self.eNB_instance] == '2':
 			lIpAddr = self.eNB2IPAddress
 			lUserName = self.eNB2UserName
 			lPassWord = self.eNB2Password
@@ -335,24 +328,21 @@ class RANManagement():
 		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
+		logging.debug('Starting eNB/gNB on server: ' + lIpAddr)
 
-		if self.htmlObj is not None:
-			self.testCase_id = self.htmlObj.testCase_id
-		else:
-			self.testCase_id = '000000'
+		self.testCase_id = HTML.testCase_id
 		mySSH = SSH.SSHConnection()
 		
 		if (self.pStatus < 0):
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' ' + self.Initialize_eNB_args, 'KO', self.pStatus)
-				self.htmlObj.CreateHtmlTabFooter(False)
+			HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' ' + self.Initialize_eNB_args, 'KO', self.pStatus)
+			HTML.CreateHtmlTabFooter(False)
 			sys.exit(1)
 		# If tracer options is on, running tshark on EPC side and capture traffic b/ EPC and eNB
 		result = re.search('T_stdout', str(self.Initialize_eNB_args))
-		if (result is not None) and (self.epcObj is not None):
-			localEpcIpAddr = self.epcObj.IPAddress
-			localEpcUserName = self.epcObj.UserName
-			localEpcPassword = self.epcObj.Password
+		if (result is not None):
+			localEpcIpAddr = EPC.IPAddress
+			localEpcUserName = EPC.UserName
+			localEpcPassword = EPC.Password
 			mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword)
 			mySSH.command('ip addr show | awk -f /tmp/active_net_interfaces.awk | egrep -v "lo|tun"', '\$', 5)
 			result = re.search('interfaceToUse=(?P<eth_interface>[a-zA-Z0-9\-\_]+)done', mySSH.getBefore())
@@ -400,17 +390,17 @@ class RANManagement():
 				mySSH.command('echo ' + lPassWord + ' | sudo -S uhd_find_devices', '\$', 60)
 		# Make a copy and adapt to EPC / eNB IP addresses
 		mySSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5)
-		if self.epcObj is not None:
-			localMmeIpAddr = self.epcObj.MmeIPAddress
-			mySSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + localMmeIpAddr + '/\' ' + ci_full_config_file, '\$', 2);
+		localMmeIpAddr = EPC.MmeIPAddress
+		mySSH.command('sed -i -e \'s/CI_MME_IP_ADDR/' + localMmeIpAddr + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_GNB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2);
 		mySSH.command('sed -i -e \'s/CI_FR1_CTL_ENB_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2);
-		if self.flexranCtrlInstalled and self.flexranCtrlStarted:
+		if (self.flexranCtrlInstalled and self.flexranCtrlStarted) or self.flexranCtrlDeployed:
 			mySSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED        = "yes";/\' ' + ci_full_config_file, '\$', 2);
+			mySSH.command('sed -i -e \'s/CI_FLEXRAN_CTL_IP_ADDR/' + self.flexranCtrlIpAddress + '/\' ' + ci_full_config_file, '\$', 2);
 		else:
 			mySSH.command('sed -i -e \'s/FLEXRAN_ENABLED.*;/FLEXRAN_ENABLED        = "no";/\' ' + ci_full_config_file, '\$', 2);
 		self.eNBmbmsEnables[int(self.eNB_instance)] = False
@@ -452,14 +442,13 @@ class RANManagement():
 				mySSH.close()
 				doLoop = False
 				logging.error('\u001B[1;37;41m eNB/gNB/ocp-eNB logging system did not show got sync! \u001B[0m')
-				if self.htmlObj is not None:
-					self.htmlObj.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK)
+				HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK)
 				# In case of T tracer recording, we need to kill tshark on EPC side
 				result = re.search('T_stdout', str(self.Initialize_eNB_args))
-				if (result is not None) and (self.epcObj is not None):
-					localEpcIpAddr = self.epcObj.IPAddress
-					localEpcUserName = self.epcObj.UserName
-					localEpcPassword = self.epcObj.Password
+				if (result is not None):
+					localEpcIpAddr = EPC.IPAddress
+					localEpcUserName = EPC.UserName
+					localEpcPassword = EPC.Password
 					mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword)
 					logging.debug('\u001B[1m Stopping tshark \u001B[0m')
 					mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5)
@@ -507,11 +496,10 @@ class RANManagement():
 				else:
 					logging.error('\u001B[1m oaitun_enm1 interface is either NOT mounted or NOT configured\u001B[0m')
 		if enbDidSync:
-			self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId)
+			self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId[self.eNB_instance])
 
 		mySSH.close()
-		if self.htmlObj is not None:
-			self.htmlObj.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'OK', CONST.ALL_PROCESSES_OK)
 		logging.debug('\u001B[1m Initialize eNB/gNB/ocp-eNB Completed\u001B[0m')
 
 	def CheckeNBProcess(self, status_queue):
@@ -546,18 +534,18 @@ class RANManagement():
 		except:
 			os.kill(os.getppid(),signal.SIGUSR1)
 
-	def TerminateeNB(self):
-		if self.eNB_serverId == '0':
+	def TerminateeNB(self, HTML, EPC):
+		if self.eNB_serverId[self.eNB_instance] == '0':
 			lIpAddr = self.eNBIPAddress
 			lUserName = self.eNBUserName
 			lPassWord = self.eNBPassword
 			lSourcePath = self.eNBSourceCodePath
-		elif self.eNB_serverId == '1':
+		elif self.eNB_serverId[self.eNB_instance] == '1':
 			lIpAddr = self.eNB1IPAddress
 			lUserName = self.eNB1UserName
 			lPassWord = self.eNB1Password
 			lSourcePath = self.eNB1SourceCodePath
-		elif self.eNB_serverId == '2':
+		elif self.eNB_serverId[self.eNB_instance] == '2':
 			lIpAddr = self.eNB2IPAddress
 			lUserName = self.eNB2UserName
 			lPassWord = self.eNB2Password
@@ -565,6 +553,7 @@ class RANManagement():
 		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
 			HELP.GenericHelp(CONST.Version)
 			sys.exit('Insufficient Parameter')
+		logging.debug('Stopping eNB/gNB on server: ' + lIpAddr)
 		mySSH = SSH.SSHConnection()
 		mySSH.open(lIpAddr, lUserName, lPassWord)
 		mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5)
@@ -586,10 +575,10 @@ class RANManagement():
 		mySSH.close()
 		# If tracer options is on, stopping tshark on EPC side
 		result = re.search('T_stdout', str(self.Initialize_eNB_args))
-		if (result is not None) and (self.epcObj is not None):
-			localEpcIpAddr = self.epcObj.IPAddress
-			localEpcUserName = self.epcObj.UserName
-			localEpcPassword = self.epcObj.Password
+		if (result is not None):
+			localEpcIpAddr = EPC.IPAddress
+			localEpcUserName = EPC.UserName
+			localEpcPassword = EPC.Password
 			mySSH.open(localEpcIpAddr, localEpcUserName, localEpcPassword)
 			logging.debug('\u001B[1m Stopping tshark \u001B[0m')
 			mySSH.command('echo ' + localEpcPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5)
@@ -613,9 +602,8 @@ class RANManagement():
 			mySSH.close()
 			mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.')
 			logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m')
-			logStatus = self.AnalyzeLogFile_eNB(extracted_log_file)
-			if self.htmlObj is not None:
-				self.htmlObj.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+			logStatus = self.AnalyzeLogFile_eNB(extracted_log_file, HTML)
+			HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
 			self.eNBLogFiles[int(self.eNB_instance)] = ''
 		else:
 			analyzeFile = False
@@ -627,27 +615,23 @@ class RANManagement():
 				copyin_res = mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.')
 				if (copyin_res == -1):
 					logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m')
-					if self.htmlObj is not None:
-						self.htmlObj.htmleNBFailureMsg='Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!'
-						self.htmlObj.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
+					HTML.htmleNBFailureMsg='Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!'
+					HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE)
 					self.eNBmbmsEnables[int(self.eNB_instance)] = False
 					return
-				if self.eNB_serverId != '0':
+				if self.eNB_serverId[self.eNB_instance] != '0':
 					mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/')
 				logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze)
-				logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze)
+				logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze, HTML)
 				if (logStatus < 0):
-					if self.htmlObj is not None:
-						self.htmlObj.CreateHtmlTestRow('N/A', 'KO', logStatus)
+					HTML.CreateHtmlTestRow('N/A', 'KO', logStatus)
 					self.preamtureExit = True
 					self.eNBmbmsEnables[int(self.eNB_instance)] = False
 					return
 				else:
-					if self.htmlObj is not None:
-						self.htmlObj.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+					HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
 			else:
-				if self.htmlObj is not None:
-					self.htmlObj.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+				HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
 		self.eNBmbmsEnables[int(self.eNB_instance)] = False
 		self.eNBstatuses[int(self.eNB_instance)] = -1
 
@@ -661,7 +645,7 @@ class RANManagement():
 		mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5)
 		mySSH.close()
 
-	def AnalyzeLogFile_eNB(self, eNBlogFile):
+	def AnalyzeLogFile_eNB(self, eNBlogFile, HTML):
 		if (not os.path.isfile('./' + eNBlogFile)):
 			return -1
 		enb_log_file = open('./' + eNBlogFile, 'r')
@@ -709,7 +693,11 @@ class RANManagement():
 		NSA_RAPROC_PUSCH_check = 0
 		#dlsch and ulsch statistics (dictionary)
 		dlsch_ulsch_stats = {}
-		
+		#count "L1 thread not ready" msg 	
+		L1_thread_not_ready_cnt = 0
+		#count "problem receiving samples" msg
+		pb_receiving_samples_cnt = 0
+	
 		for line in enb_log_file.readlines():
 			# Runtime statistics
 			result = re.search('Run time:' ,str(line))
@@ -874,6 +862,15 @@ class RANManagement():
 				if result is not None:
 					#remove 1- all useless char before relevant info (ulsch or dlsch) 2- trailing char
 					dlsch_ulsch_stats[k]=re.sub(r'^.*\]\s+', r'' , line.rstrip())
+			#count "L1 thread not ready" msg
+			result = re.search('\[PHY\]\s+L1_thread isn\'t ready', str(line))
+			if result is not None:
+				L1_thread_not_ready_cnt += 1	
+			#count "problem receiving samples" msg
+			result = re.search('\[PHY\]\s+problem receiving samples', str(line))
+			if result is not None:
+				pb_receiving_samples_cnt += 1				
+
 		enb_log_file.close()
 		logging.debug('   File analysis completed')
 		if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'):
@@ -902,6 +899,17 @@ class RANManagement():
 				htmlMsg = statMsg+'\n'
 			logging.debug(statMsg)
 			htmleNBFailureMsg += htmlMsg
+			#L1 thread not ready log
+			statMsg = '[PHY] L1 thread is not ready msg count =  '+str(L1_thread_not_ready_cnt)
+			htmlMsg = statMsg+'\n'
+			logging.debug(statMsg)
+			htmleNBFailureMsg += htmlMsg
+			#problem receiving samples log
+			statMsg = '[PHY] problem receiving samples msg count =  '+str(pb_receiving_samples_cnt)
+			htmlMsg = statMsg+'\n'
+			logging.debug(statMsg)
+			htmleNBFailureMsg += htmlMsg
+
 			#ulsch and dlsch statistics
 			if len(dlsch_ulsch_stats)!=0: #check if dictionary is not empty
 				statMsg=''
@@ -1017,8 +1025,7 @@ class RANManagement():
 			logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m')
 			htmleNBFailureMsg += rlcMsg + '\n'
 			global_status = CONST.ENB_PROCESS_REALTIME_ISSUE
-		if self.htmlObj is not None:
-			self.htmlObj.htmleNBFailureMsg=htmleNBFailureMsg
+		HTML.htmleNBFailureMsg=htmleNBFailureMsg
 		# Runtime statistics for console output and HTML
 		if runTime != '':
 			logging.debug(runTime)
diff --git a/ci-scripts/runTestOnVM.sh b/ci-scripts/runTestOnVM.sh
index 6c87f5dac33bdee9d67078413c75f0f60a1ff2d5..70eabb7b695ecc4218c2d80143e47f3ff8124b0b 100755
--- a/ci-scripts/runTestOnVM.sh
+++ b/ci-scripts/runTestOnVM.sh
@@ -2200,7 +2200,7 @@ function run_test_on_vm {
             mkdir --parents $ARCHIVES_LOC
         fi
 
-        local try_cnt="0"
+        local try_cnt=0
         NR_STATUS=0
 
         ######### start of RA TEST loop
@@ -2232,7 +2232,7 @@ function run_test_on_vm {
                 scp -o StrictHostKeyChecking=no ubuntu@$GNB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_GNB_LOG_FILE $ARCHIVES_LOC
                 scp -o StrictHostKeyChecking=no ubuntu@$NR_UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_NR_UE_LOG_FILE $ARCHIVES_LOC
                 SYNC_STATUS=-1
-                try_cnt=$[$try_cnt+1]
+                try_cnt=$((try_cnt+1))
                 continue
             fi
 
@@ -2255,9 +2255,10 @@ function run_test_on_vm {
             if [ $RA_STATUS -ne 0 ]
             then
                 echo "RA test NOT OK"
-                try_cnt=$[$try_cnt+1]
+                echo "try_cnt = " $try_cnt
+                try_cnt=$((try_cnt+1))
             else
-                try_cnt=$[$try_cnt+10]
+                try_cnt=$((try_cnt+10))
             fi
         done
         ########### end RA test
@@ -2266,7 +2267,7 @@ function run_test_on_vm {
 
 
         ######### start of PHY TEST loop
-        try_cnt="0"
+        try_cnt=0
         while [ $try_cnt -lt 4 ]
         do
 
@@ -2297,7 +2298,7 @@ function run_test_on_vm {
                 scp -o StrictHostKeyChecking=no ubuntu@$GNB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_GNB_LOG_FILE $ARCHIVES_LOC
                 scp -o StrictHostKeyChecking=no ubuntu@$NR_UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_NR_UE_LOG_FILE $ARCHIVES_LOC
                 SYNC_STATUS=-1
-                try_cnt=$[$try_cnt+1]
+                try_cnt=$((try_cnt+1))
                 continue
             fi
 
@@ -2337,7 +2338,7 @@ function run_test_on_vm {
                 terminate_enb_ue_basic_sim $GNB_VM_CMDS $GNB_VM_IP_ADDR 1
                 scp -o StrictHostKeyChecking=no ubuntu@$GNB_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_GNB_LOG_FILE $ARCHIVES_LOC
                 scp -o StrictHostKeyChecking=no ubuntu@$NR_UE_VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_NR_UE_LOG_FILE $ARCHIVES_LOC
-                try_cnt=$[$try_cnt+1]
+                try_cnt=$((try_cnt+1))
                 continue
             fi
 
@@ -2363,9 +2364,9 @@ function run_test_on_vm {
             if [ $IPERF_STATUS -ne 0 ]
             then
                 echo "UL test not OK"
-                try_cnt=$[$try_cnt+1]
+                try_cnt=$((try_cnt+1))
             else
-                try_cnt=$[$try_cnt+10]
+                try_cnt=$((try_cnt+10))
             fi
         done
         ######### end of loop
diff --git a/ci-scripts/tcp_iperf_stats.awk b/ci-scripts/tcp_iperf_stats.awk
index 3a00e4555f744fa8cf2ce87c9baad3067ddc3bc1..b21bf16a2ff7e2b2b0f8c85759671766fd501f24 100644
--- a/ci-scripts/tcp_iperf_stats.awk
+++ b/ci-scripts/tcp_iperf_stats.awk
@@ -21,7 +21,11 @@
 BEGIN{max=0;min=10000}
 {
     if ($0 ~/Mbits/) {
-        split($0,a,"MBytes")
+        if ($0 ~/KBytes/) {
+            split($0,a,"KBytes")
+        } else {
+            split($0,a,"MBytes")
+        }
         split(a[2],b)
         if (b[1]>max) {
             max=b[1]
diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml
index 2c20988851e7e6565f99d553b27455be53f62e85..0e00a2e7d413da5784e7c88210335bfa335406ec 100755
--- a/ci-scripts/xml_class_list.yml
+++ b/ci-scripts/xml_class_list.yml
@@ -19,6 +19,8 @@
   - Reboot_UE
   - Initialize_FlexranCtrl
   - Terminate_FlexranCtrl
+  - Deploy_EPC
+  - Undeploy_EPC
   - Initialize_HSS
   - Terminate_HSS
   - Initialize_MME
@@ -32,3 +34,6 @@
   - Ping_CatM_module
   - IdleSleep
   - Perform_X2_Handover
+  - Build_Image
+  - Deploy_Object
+  - Undeploy_Object
diff --git a/ci-scripts/xml_files/fr1_image_build.xml b/ci-scripts/xml_files/fr1_image_build.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9dd386b646cd6e1975882e62f49852700efd5cf8
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_image_build.xml
@@ -0,0 +1,40 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>build-tab</htmlTabRef>
+	<htmlTabName>Build</htmlTabName>
+	<htmlTabIcon>wrench</htmlTabIcon>
+	<TestCaseRequestedList>
+ 000001
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="000001">
+		<class>Build_Image</class>
+		<desc>Build eNB Image</desc>
+		<kind>all</kind>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/fr1_oai_cn_deploy.xml b/ci-scripts/xml_files/fr1_oai_cn_deploy.xml
new file mode 100644
index 0000000000000000000000000000000000000000..919def7aa39c2ec33891132ffe01d83f493049fc
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_oai_cn_deploy.xml
@@ -0,0 +1,39 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>epc-deploy-tab</htmlTabRef>
+	<htmlTabName>EPC-Deploy</htmlTabName>
+	<htmlTabIcon>log-in</htmlTabIcon>
+	<TestCaseRequestedList>
+ 000100
+	</TestCaseRequestedList>
+	<TestCaseExclusionList>
+	</TestCaseExclusionList>
+
+	<testCase id="000100">
+		<class>Deploy_EPC</class>
+		<desc>Deploy all EPC containers</desc>
+		<parameters>yaml_files/fr1_epc_tim</parameters>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/fr1_oai_cn_undeploy.xml b/ci-scripts/xml_files/fr1_oai_cn_undeploy.xml
new file mode 100644
index 0000000000000000000000000000000000000000..76192efea14f0e5b0c9b48fb30fe0f6b9756fd61
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_oai_cn_undeploy.xml
@@ -0,0 +1,38 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>epc-undeploy-tab</htmlTabRef>
+	<htmlTabName>EPC-Undeploy</htmlTabName>
+	<htmlTabIcon>log-out</htmlTabIcon>
+	<TestCaseRequestedList>
+ 000200
+	</TestCaseRequestedList>
+	<TestCaseExclusionList>
+	</TestCaseExclusionList>
+
+	<testCase id="000200">
+		<class>Undeploy_EPC</class>
+		<desc>Undeploy all EPC containers</desc>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/fr1_ran_ue_base.xml b/ci-scripts/xml_files/fr1_ran_ue_base.xml
new file mode 100644
index 0000000000000000000000000000000000000000..847967f81e9f9808d982f89615eed1c1be9a079d
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_ran_ue_base.xml
@@ -0,0 +1,150 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>TEST-FR1-TM1</htmlTabRef>
+	<htmlTabName>FR1</htmlTabName>
+	<htmlTabIcon>tasks</htmlTabIcon>
+	<TestCaseRequestedList>
+ 010000
+ 030000
+ 040000
+ 010001
+ 000001
+ 050000
+ 050001
+ 050002
+ 050002
+ 000001
+ 060000
+ 060001
+ 000001
+ 010002
+ 000001
+ 070001
+ 070000
+ 010003
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="010000">
+		<class>Initialize_UE</class>
+		<desc>Initialize UE</desc>
+	</testCase>
+
+	<testCase id="010003">
+		<class>Terminate_UE</class>
+		<desc>Terminate UE</desc>
+	</testCase>
+
+	<testCase id="010001">
+		<class>Attach_UE</class>
+		<desc>Attach UE</desc>
+	</testCase>
+
+	<testCase id="010002">
+		<class>Detach_UE</class>
+		<desc>Detach UE</desc>
+	</testCase>
+
+
+	<testCase id="030000">
+		<class>Initialize_eNB</class>
+		<desc>Initialize eNB</desc>
+		<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf</Initialize_eNB_args>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+		<air_interface>lte</air_interface>
+   </testCase>
+
+
+	<testCase id="040000">
+		<class>Initialize_eNB</class>
+		<desc>Initialize gNB</desc>
+		<Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf -E</Initialize_eNB_args>
+		<eNB_instance>1</eNB_instance>
+		<eNB_serverId>1</eNB_serverId>
+		<air_interface>nr</air_interface>
+	</testCase>
+
+	<testCase id="000001">
+		<class>IdleSleep</class>
+		<desc>Sleep</desc>
+		<idle_sleep_time_in_sec>20</idle_sleep_time_in_sec>
+	</testCase>
+
+	<testCase id="050000">
+		<class>Ping</class>
+		<desc>Ping: 20pings in 20sec</desc>
+		<ping_args>-c 20</ping_args>
+		<ping_packetloss_threshold>50</ping_packetloss_threshold>
+	</testCase>
+
+	<testCase id="050001">
+		<class>Ping</class>
+		<desc>Ping: 5pings in 1sec</desc>
+		<ping_args>-c 5 -i 0.2</ping_args>
+		<ping_packetloss_threshold>50</ping_packetloss_threshold>
+	</testCase>
+
+	<testCase id="050002">
+		<class>Ping</class>
+		<desc>Ping: 100pings in 20sec</desc>
+		<ping_args>-c 100 -i 0.2</ping_args>
+		<ping_packetloss_threshold>50</ping_packetloss_threshold>
+	</testCase>
+
+
+	<testCase id="060000">
+		<class>Iperf</class>
+		<desc>iperf (DL/1Mbps/UDP)(30 sec)(single-ue profile)</desc>
+		<iperf_args>-u -b 1M -t 30 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="060001">
+		<class>Iperf</class>
+		<desc>iperf (UL/1Mbps/UDP)(30 sec)(single-ue profile)</desc>
+		<iperf_args>-u -b 1M -t 30 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="070000">
+		<class>Terminate_eNB</class>
+		<desc>Terminate eNB</desc>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+		<air_interface>lte</air_interface>
+	</testCase>
+
+	<testCase id="070001">
+		<class>Terminate_eNB</class>
+		<desc>Terminate gNB</desc>
+		<eNB_instance>1</eNB_instance>
+		<eNB_serverId>1</eNB_serverId>
+		<air_interface>nr</air_interface>
+	</testCase>
+
+</testCaseList>
+
diff --git a/ci-scripts/xml_files/fr1_ran_ue_proc.xml b/ci-scripts/xml_files/fr1_ran_ue_iperf.xml
similarity index 81%
rename from ci-scripts/xml_files/fr1_ran_ue_proc.xml
rename to ci-scripts/xml_files/fr1_ran_ue_iperf.xml
index 446433ec306a34b88da01b573ab6ff80ea1a3d8b..8ead3afc62ee152e39cc03bc389c53b4409b3be9 100644
--- a/ci-scripts/xml_files/fr1_ran_ue_proc.xml
+++ b/ci-scripts/xml_files/fr1_ran_ue_iperf.xml
@@ -31,9 +31,9 @@
  010001
  000001
  050000
- 050001
- 050002
- 050003
+ 000001
+ 060000
+ 060001
  000001
  010002
  000001
@@ -93,29 +93,25 @@
 		<class>Ping</class>
 		<desc>Ping: 20pings in 20sec</desc>
 		<ping_args>-c 20</ping_args>
-		<ping_packetloss_threshold>0</ping_packetloss_threshold>
+		<ping_packetloss_threshold>50</ping_packetloss_threshold>
 	</testCase>
 
-	<testCase id="050001">
-		<class>Ping</class>
-		<desc>Ping: 5pings in 1sec</desc>
-		<ping_args>-c 5 -i 0.2</ping_args>
-		<ping_packetloss_threshold>0</ping_packetloss_threshold>
-	</testCase>
 
-	<testCase id="050002">
-		<class>Ping</class>
-		<desc>Ping: 100pings in 20sec</desc>
-		<ping_args>-c 100 -i 0.2</ping_args>
-		<ping_packetloss_threshold>0</ping_packetloss_threshold>
+	<testCase id="060000">
+		<class>Iperf</class>
+		<desc>iperf (DL/2.5Mbps/UDP)(60 sec)(single-ue profile)</desc>
+		<iperf_args>-u -b 2.5M -t 60 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
 	</testCase>
 
-	<testCase id="050003">$
-	<class>Ping</class>$
-	<desc>Ping: 100pings in 20sec size 1000</desc>$
-	<ping_args>-c 100 -i 0.2 -s 1000</ping_args>$
-	<ping_packetloss_threshold>0</ping_packetloss_threshold>$
-	</testCase>$
+	<testCase id="060001">
+		<class>Iperf</class>
+		<desc>iperf (UL/1.5Mbps/UDP)(60 sec)(single-ue profile)</desc>
+		<iperf_args>-u -b 1.5M -t 60 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
 
 	<testCase id="070000">
 		<class>Terminate_eNB</class>
diff --git a/ci-scripts/xml_files/fr1_usrp210_band7_deploy_test_05mhz_tm1.xml b/ci-scripts/xml_files/fr1_usrp210_band7_deploy_test_05mhz_tm1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3d04fdeb2997e03d63152c017307144cf3c80f46
--- /dev/null
+++ b/ci-scripts/xml_files/fr1_usrp210_band7_deploy_test_05mhz_tm1.xml
@@ -0,0 +1,133 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>test-deploy-enb-mono</htmlTabRef>
+	<htmlTabName>Test-Deploy-eNB-Mono</htmlTabName>
+	<htmlTabIcon>tasks</htmlTabIcon>
+	<repeatCount>1</repeatCount>
+	<TestCaseRequestedList>
+ 040101
+ 030101 000020 040301 000021 040501 040601 040611 040641 040651 040401 040201 030201
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="000001">
+		<class>IdleSleep</class>
+		<desc>Waiting for 60 seconds</desc>
+		<idle_sleep_time_in_sec>60</idle_sleep_time_in_sec>
+	</testCase>
+
+	<testCase id="000002">
+		<class>IdleSleep</class>
+		<desc>Waiting for 10 seconds</desc>
+		<idle_sleep_time_in_sec>10</idle_sleep_time_in_sec>
+	</testCase>
+
+    <testCase id="000020">
+        <class>CheckStatusUE</class>
+        <desc>Check UE(s) status before attachment</desc>
+        <expectedNbOfConnectedUEs>0</expectedNbOfConnectedUEs>
+    </testCase>
+
+    <testCase id="000021">
+        <class>CheckStatusUE</class>
+        <desc>Check UE(s) status after attachment</desc>
+        <expectedNbOfConnectedUEs>1</expectedNbOfConnectedUEs>
+    </testCase>
+
+	<testCase id="030101">
+		<class>Deploy_Object</class>
+		<desc>Deploy eNB (FDD/Band7/5MHz) in a container</desc>
+		<yaml_path>ci-scripts/yaml_files/fr1_enb_mono_fdd_tim</yaml_path>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+	<testCase id="030201">
+		<class>Undeploy_Object</class>
+		<desc>Undeploy eNB</desc>
+		<yaml_path>ci-scripts/yaml_files/fr1_enb_mono_fdd_tim</yaml_path>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+	<testCase id="040101">
+		<class>Initialize_UE</class>
+		<desc>Initialize UE</desc>
+	</testCase>
+
+	<testCase id="040201">
+		<class>Terminate_UE</class>
+		<desc>Terminate UE</desc>
+	</testCase>
+
+	<testCase id="040301">
+		<class>Attach_UE</class>
+		<desc>Attach UE</desc>
+	</testCase>
+
+	<testCase id="040401">
+		<class>Detach_UE</class>
+		<desc>Detach UE</desc>
+	</testCase>
+
+	<testCase id="040501">
+		<class>Ping</class>
+		<desc>ping (5MHz - 20 sec)</desc>
+		<ping_args>-c 20</ping_args>
+		<ping_packetloss_threshold>5</ping_packetloss_threshold>
+	</testCase>
+
+	<testCase id="040601">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - DL/15Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 15M -t 30 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040611">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - DL/TCP)(30 sec)</desc>
+		<iperf_args>-t 30 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040641">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - UL/7.5Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 7.5M -t 30 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040651">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - UL/TCP)(30 sec)</desc>
+		<iperf_args>-t 30 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/yaml_files/fr1_enb_mono_fdd_tim/docker-compose.yml b/ci-scripts/yaml_files/fr1_enb_mono_fdd_tim/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2df277d78baa8c43a6cdb15cbda2735e7d2eb9e5
--- /dev/null
+++ b/ci-scripts/yaml_files/fr1_enb_mono_fdd_tim/docker-compose.yml
@@ -0,0 +1,49 @@
+version: '3.8'
+
+services:
+    enb_mono_fdd:
+        image: oai-enb:latest
+        privileged: true
+        container_name: prod-enb-mono-fdd
+        environment:
+            USE_FDD_MONO: 'yes'
+            USE_B2XX: 'yes'
+            ENB_NAME: eNB-in-docker
+            MCC: '222'
+            MNC: '01'
+            MNC_LENGTH: 2
+            TAC: 1
+            UTRA_BAND_ID: 7
+            DL_FREQUENCY_IN_MHZ: 2680
+            UL_FREQUENCY_OFFSET_IN_MHZ: 120
+            NID_CELL: 10
+            NB_PRB: 25
+            MME_S1C_IP_ADDRESS: CI_MME_IP_ADDR
+            ENB_S1C_IF_NAME: eth0
+            ENB_S1C_IP_ADDRESS: 192.168.61.30
+            ENB_S1U_IF_NAME: eth0
+            ENB_S1U_IP_ADDRESS: 192.168.61.30
+            ENB_X2_IP_ADDRESS: 192.168.61.30
+            FLEXRAN_ENABLED: 'no'
+            FLEXRAN_INTERFACE_NAME: eth0
+            FLEXRAN_IPV4_ADDRESS: CI_FLEXRAN_CTL_IP_ADDR
+            USE_ADDITIONAL_OPTIONS: '--RUs.[0].max_rxgain 115 --RUs.[0].max_pdschReferenceSignalPower -27 --eNBs.[0].component_carriers.[0].pucch_p0_Nominal -96'
+        volumes:
+            - /dev:/dev
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.30
+        healthcheck:
+            # pgrep does NOT work
+            test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+networks:
+    public_net:
+        name: prod-oai-public-net
+        ipam:
+            config:
+                - subnet: 192.168.61.0/26
+
diff --git a/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml b/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..28ae154838aed5b750eb9954ef7467f05318198d
--- /dev/null
+++ b/ci-scripts/yaml_files/fr1_epc_tim/docker-compose.yml
@@ -0,0 +1,203 @@
+version: '3.8'
+
+services:
+    cassandra:
+        image: cassandra:2.1
+        container_name: prod-cassandra
+        networks:
+            private_net:
+                ipv4_address: 192.168.68.2
+        environment:
+            CASSANDRA_CLUSTER_NAME: "OAI HSS Cluster"
+            CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
+        healthcheck:
+            test: /bin/bash -c "nodetool status"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    db_init:
+        image: cassandra:2.1
+        container_name: prod-db-init
+        depends_on: [cassandra]
+        deploy:
+            restart_policy:
+                condition: on-failure
+                max_attempts: 10
+        networks:
+            private_net:
+                ipv4_address: 192.168.68.4
+        volumes:
+            - ./oai_db.cql:/home/oai_db.cql
+        entrypoint: /bin/bash -c "cqlsh --file /home/oai_db.cql 192.168.68.2 && echo 'OK'"
+
+    oai_hss:
+        image: oai-hss:production
+        container_name: prod-oai-hss
+        privileged: true
+        depends_on: [cassandra]
+        networks:
+            private_net:
+                ipv4_address: 192.168.68.3
+            public_net:
+                ipv4_address: 192.168.61.2
+        environment:
+            REALM: openairinterface.org
+            HSS_FQDN: hss.openairinterface.org
+            PREFIX: /openair-hss/etc
+            cassandra_Server_IP: 192.168.68.2
+            OP_KEY: 1006020f0a478bf6b699f15c062e42b3
+            LTE_K: fec86ba6eb707ed08905757b1bb44b8f
+            APN1: oai.ipv4
+            APN2: internet
+            FIRST_IMSI: 222010100001120
+            NB_USERS: 10
+        healthcheck:
+            test: /bin/bash -c "pgrep oai_hss"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    oai_mme:
+        image: oai-mme:production
+        container_name: prod-oai-mme
+        privileged: true
+        depends_on: [oai_hss]
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.3
+        environment:
+            REALM: openairinterface.org
+            PREFIX: /openair-mme/etc
+            INSTANCE: 1
+            PID_DIRECTORY: /var/run
+            HSS_IP_ADDR: 192.168.61.2
+            HSS_HOSTNAME: hss
+            HSS_FQDN: hss.openairinterface.org
+            HSS_REALM: openairinterface.org
+            MCC: '222'
+            MNC: '01'
+            MME_GID: 32768
+            MME_CODE: 3
+            TAC_0: 1
+            TAC_1: 2
+            TAC_2: 3
+            MME_FQDN: mme.openairinterface.org
+            MME_S6A_IP_ADDR: 192.168.61.3
+            MME_INTERFACE_NAME_FOR_S1_MME: eth0
+            MME_IPV4_ADDRESS_FOR_S1_MME: 192.168.61.3
+            MME_INTERFACE_NAME_FOR_S11: eth0
+            MME_IPV4_ADDRESS_FOR_S11: 192.168.61.3
+            MME_INTERFACE_NAME_FOR_S10: lo
+            MME_IPV4_ADDRESS_FOR_S10: 127.0.0.10
+            OUTPUT: CONSOLE
+            SGW_IPV4_ADDRESS_FOR_S11_0: 192.168.61.4
+            PEER_MME_IPV4_ADDRESS_FOR_S10_0: 0.0.0.0
+            PEER_MME_IPV4_ADDRESS_FOR_S10_1: 0.0.0.0
+            MCC_SGW_0: '222'
+            MNC3_SGW_0: '001'
+            TAC_LB_SGW_0: '01'
+            TAC_HB_SGW_0: '00'
+            MCC_MME_0: '222'
+            MNC3_MME_0: '001'
+            TAC_LB_MME_0: '02'
+            TAC_HB_MME_0: '00'
+            MCC_MME_1: '222'
+            MNC3_MME_1: '001'
+            TAC_LB_MME_1: '03'
+            TAC_HB_MME_1: '00'
+            TAC_LB_SGW_TEST_0: '03'
+            TAC_HB_SGW_TEST_0: '00'
+            SGW_IPV4_ADDRESS_FOR_S11_TEST_0: 0.0.0.0
+        healthcheck:
+            test: /bin/bash -c "pgrep oai_mme"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    oai_spgwc:
+        image: oai-spgwc:production
+        privileged: true
+        depends_on: [oai_mme]
+        container_name: prod-oai-spgwc
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.4
+        environment:
+            PID_DIRECTORY: /var/run
+            SGW_INTERFACE_NAME_FOR_S11: eth0
+            SGW_IP_FOR_S5_S8_CP: 127.0.0.11/8
+            PGW_IP_FOR_S5_S8_CP: 127.0.0.12/8
+            PGW_INTERFACE_NAME_FOR_SX: eth0
+            DEFAULT_APN: oai.ipv4
+            DEFAULT_DNS_IPV4_ADDRESS: 192.168.18.129
+            DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4
+            UE_IP_ADDRESS_POOL: '12.1.1.2 - 12.1.1.254'
+            PUSH_PROTOCOL_OPTION: 'yes'
+        healthcheck:
+            test: /bin/bash -c "pgrep oai_spgwc"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    oai_spgwu:
+        image: oai-spgwu-tiny:production
+        privileged: true
+        container_name: prod-oai-spgwu-tiny
+        depends_on: [oai_spgwc]
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.5
+        environment:
+            PID_DIRECTORY: /var/run
+            INSTANCE: 1
+            SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP: eth0
+            PGW_INTERFACE_NAME_FOR_SGI: eth0
+            SGW_INTERFACE_NAME_FOR_SX: eth0
+            SPGWC0_IP_ADDRESS: 192.168.61.4
+            NETWORK_UE_IP: '12.1.1.0/24'
+            NETWORK_UE_NAT_OPTION: 'yes'
+        healthcheck:
+            test: /bin/bash -c "pgrep oai_spgwu"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    flexran_rtc:
+        image: flexran-rtc:production
+        privileged: true
+        container_name: prod-flexran-rtc
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.10
+        healthcheck:
+            test: /bin/bash -c "pgrep rt_controller"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+    trf_gen:
+        image: trf-gen:production
+        privileged: true
+        container_name: prod-trf-gen
+        networks:
+            public_net:
+                ipv4_address: 192.168.61.11
+        entrypoint: /bin/bash -c "ip route add 12.1.1.0/24 via 192.168.61.5 dev eth0; sleep infinity"
+        healthcheck:
+            test: /bin/bash -c "ping -c 2 192.168.61.5"
+            interval: 10s
+            timeout: 5s
+            retries: 5
+
+networks:
+    private_net:
+        name: prod-oai-private-net
+        ipam:
+            config:
+                - subnet: 192.168.68.0/26
+    public_net:
+        name: prod-oai-public-net
+        ipam:
+            config:
+                - subnet: 192.168.61.0/26
diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 1828fba821cc7d17d07c9e9a4c56032e3041b1a0..b3f6d0a94c1c87c2a6821aba980295b138f8f249 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1968,6 +1968,7 @@ set(NR_PDCP_SRC
   ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
   ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_entity.c
   ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c
+  ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c
   )
 
 set(L2_SRC
@@ -3452,7 +3453,7 @@ if (${T_TRACER})
         SECU_OSA SECU_CN SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB default_sched remote_sched RAL
         NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_VNF_LIB NFAPI_USER_LIB
         PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX
-        L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_NR MAC_UE_NR
+        L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_NR MAC_UE_NR NGAP_GNB
         CN_UTILS GTPV1U NR_GTPV1U SCTP_CLIENT MME_APP UDP LIB_NAS_UE NB_IoT LFDS LFDS7 SIMU_COMMON SIMU SIMU_ETH OPENAIR0_LIB
         ldpc_orig ldpc_optim ldpc_optim8seg ldpc PROTO_AGENT dfts)
     if (TARGET ${i})
diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml
index 0c31ba8ea68da0de7761dda17c37064dd121f235..e081a4186ed957302af5c035bcf2c4013dacf122 100644
--- a/cmake_targets/autotests/test_case_list.xml
+++ b/cmake_targets/autotests/test_case_list.xml
@@ -1098,7 +1098,9 @@
                                  (Test13: HARQ test 50% TP (2 rounds),
                                  (Test14: 3 PTRS, 8 Interpolated Symbols),
                                  (Test15: 6 PTRS, 5 Interpolated Symbols),
-                                 (Test16: 11 PTRS, 0 Interpolated Symbols)</desc>
+                                 (Test16: 11 PTRS, 0 Interpolated Symbols),
+                                 (Test17: 2 DMRS Symbols),
+                                 (Test18: 3 DMRS Symbols)</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>
@@ -1120,8 +1122,10 @@
                   -n100 -s1 -t50
                   -n100 -s5 -T 2 2 2
                   -n100 -s5 -T 2 1 2
-                  -n100 -s5 -T 2 0 4</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</tags>
+                  -n100 -s5 -T 2 0 4
+                  -n100 -s2 -U 2 0 1
+                  -n100 -s2 -U 2 0 2</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</tags>
       <search_expr_true>PDSCH test OK</search_expr_true>
       <search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
       <nruns>3</nruns>
diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper
index f76eae7f284684ca0794af3b7ff96c47e54ffcdc..674d4a0cacf5312336a5df55376ba7e2af3aec30 100755
--- a/cmake_targets/tools/build_helper
+++ b/cmake_targets/tools/build_helper
@@ -114,6 +114,8 @@ check_supported_distribution() {
         "rhel7.7")     return 0 ;;
         "rhel7.8")     return 0 ;;
         "rhel8.2")     return 0 ;;
+        "rhel8.3")     return 0 ;;
+        "rhel8.4")     return 0 ;;
         "centos7")     return 0 ;;
     esac
     return 1
diff --git a/doc/BASIC_SIM.md b/doc/BASIC_SIM.md
index ab4c3489d9a3562cbb20acc59e0e101e84d922f6..1bfc6e76d203c222d520a190a4053590fc6e1d96 100644
--- a/doc/BASIC_SIM.md
+++ b/doc/BASIC_SIM.md
@@ -27,7 +27,7 @@ $ cd cmake_targets
 $ ./build_oai --eNB --UE
 ```
 
-Both eNB (lte-softmodem) and UE (lte-uesoftmodem) are present on `cmake_targets/lte_build_oai/build` folder.
+Both eNB (lte-softmodem) and UE (lte-uesoftmodem) are present on `cmake_targets/ran_build/build` folder.
 
 More details are available on the [build page](BUILD.md).
 
@@ -50,7 +50,7 @@ Example 1: running in FDD mode with EPC.
 
 ```bash
 $ source oaienv
-$ cd cmake_targets/lte_build_oai/build
+$ cd cmake_targets/ran_build/build
 $ ENODEB=1 sudo -E ./lte-softmodem -O $OPENAIR_HOME/ci-scripts/conf_files/lte-fdd-basic-sim.conf --basicsim
 ```
 
@@ -64,7 +64,7 @@ Example 2: running in TDD mode without any EPC.
 
 ```bash
 $ source oaienv
-$ cd cmake_targets/lte_build_oai/build
+$ cd cmake_targets/ran_build/build
 $ ENODEB=1 sudo -E ./lte-softmodem -O $OPENAIR_HOME/ci-scripts/conf_files/lte-tdd-basic-sim.conf --basicsim --noS1
 ```
 
@@ -79,7 +79,7 @@ You need to set the correct OPC, USIM_API_K, MSIN (this is the end par of the IM
 ```bash
 $ source oaienv
 # Edit openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf
-$ cd cmake_targets/lte_build_oai/build
+$ cd cmake_targets/ran_build/build
 $ ../../nas_sim_tools/build/conf2uedata -c $OPENAIR_HOME/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf -o .
 $ sudo -E ./lte-uesoftmodem -C 2625000000 -r 25 --ue-rxgain 140 --basicsim [--noS1]
 ```
diff --git a/doc/BUILD.md b/doc/BUILD.md
index ba5db55cab38822d97d0a41710c6ca2a0e2cab17..bbb06a1e6985adbc28b55b25a87d8e61c350aabd 100644
--- a/doc/BUILD.md
+++ b/doc/BUILD.md
@@ -51,6 +51,19 @@ Calling the `build_oai` script with the -h option gives the list of all availabl
 
 # Building PHY Simulators
 
+The PHY layer simulators (LTE and NR) can be built as follows:  
+
+```
+cd <your oai installation directory>/openairinterface5g/
+source oaienv
+cd cmake_targets/
+./build_oai -I --phy_simulators
+```
+
+After completing the build, the binaries are available in the cmake_targets/phy_simulators/build directory.  
+A copy is also available in the target/bin directory, with all binaries suffixed by the 3GPP release number, today **.Rel15**.  
+
+
 Detailed information about these simulators can be found [in this dedicated page](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/OpenAirLTEPhySimul)
 
 # Building UEs, eNodeB and gNodeB Executables
diff --git a/doc/SW_archi.md b/doc/SW_archi.md
index dba884dcec837ed5671e20443d84b4c8c4836fb2..412dad402d90816ad53c5f48428824f6407052dd 100644
--- a/doc/SW_archi.md
+++ b/doc/SW_archi.md
@@ -70,7 +70,7 @@ if the input is a UE RACH detection
     * nr_schedule_msg2()
 {: .func4}
 * handle_nr_uci()  
-????	      
+handles uplink control information, i.e., for the moment HARQ feedback.
 {: .func4}
 * handle_nr_ulsch()  
 handles ulsch data prepared by nr_fill_indication()
@@ -143,7 +143,8 @@ the samples numbers are the future time for these samples emission on-air
 {: .func3}
 
 # Scheduler
-The scheduler is called by the chain: nr_ul_indication()=>gNB_dlsch_ulsch_scheduler()
+
+The main scheduler function  is called by the chain: nr_ul_indication()=>gNB_dlsch_ulsch_scheduler()
 It calls sub functions to process each physical channel (rach, ...)  
 The scheduler uses and internal map of used RB: vrb_map and vrb_map_UL, so each specific channel scheduler can see the already filled RB in each subframe (the function gNB_dlsch_ulsch_scheduler() clears these two arrays when it starts)   
 
@@ -153,16 +154,71 @@ it sends a iiti message to activate the thread for RRC, the answer will be async
 
 Calls schedule_nr_mib() that calls mac_rrc_nr_data_req() to fill MIB,  
 
-Calls each channel allocation: schedule SI, schedule_ul, schedule_dl, ...  
-this is a major entry for "phy-test" mode: in this mode, the allocation is fixed  
-all these channels goes to mac_rrc_nr_data_req() to get the data to transmit  
-
-nr_schedule_ue_spec() is called  
-* calls nr_simple_dlsch_preprocessor()=> mac_rlc_status_ind() mac_rlc_status_ind() locks and checks directly inside rlc data the quantity of waiting data. So, the scheduler can allocate RBs
-* calls nr_update_pucch_scheduling()  
-    * get_pdsch_to_harq_feedback() to schedule retransmission in DL
-
-Calls nr_fill_nfapi_dl_pdu() to actually populate what should be done by the lower layers to make the Tx subframe
+Calls schedule_nr_prach() which schedules the (fixed) PRACH region one frame in
+advance.
+
+Calls nr_csi_meas_reporting() to check when to schedule CSI in PUCCH.
+
+Calls nr_schedule_RA(): checks RA process 0's state. Schedules Msg.2 via
+nr_generate_Msg2() if an RA process is ongoing, and pre-allocates the Msg. 3
+for PUSCH as well.
+
+Calls nr_schedule_ulsch(): It is divided into the "preprocessor" and the
+"postprocessor": the first makes the scheduling decisions, the second fills
+nFAPI structures to indicate to the PHY what it is supposed to do. To signal
+which users have how many resources, the preprocessor populates the
+NR_sched_pusch_t (for values changing every TTI, e.g., frequency domain
+allocation) and NR_sched_pusch_save_t (for values changing less frequently, at
+least in FR1 [to my understanding], e.g., DMRS fields when the time domain
+allocation stays between TTIs) structures. Furthermore, the preprocessor is an
+exchangeable module that might schedule differently, e.g., one user for
+phytest, multiple users in FR1, or maybe FR2: phytest is in
+nr_ul_preprocessor_phytest(), for FR1 is nr_simple_ulsch_preprocessor() [under
+development], for FR2 does not exist yet.
+* calls preprocessor via pre_processor_ul(): the preprocessor is responsible
+  for allocating CCEs (using allocate_nr_CCEs()). Note that we do not yet have
+  scheduling requests or buffer status reports, and only one UE. E.g.,
+  nr_simple_ulsch_preprocessor():
+  1)  check whether the current frame/slot plus K2 is an UL slot, and return if
+      not.
+  2)  Find first free start RB in vrb_map_UL, and as many free consecutive RBs
+      as possible.
+  3)  allocate a CCE for the UE (and return if it is not possible)
+  4)  Calculate DMRS stuff (nr_save_pusch_fields()) and the TBS.
+  5)  Mark used resources in vrb_map_UL.
+* loop through all users: get a free HARQ PID using select_ul_harq_pid() and
+  update statistics. Fill nFAPI structures directly for PUSCH, and call
+  config_uldci() and fill_dci_pdu_rel15() for DCI filling and PDCCH messages.
+
+Calls nr_schedule_ue_spec(). It is divided into the "preprocessor" and the
+"postprocessor": the first makes the scheduling decisions, the second fills
+nFAPI structures to indicate to the PHY what it is supposed to do. To signal
+which users have how many resources, the preprocessor populates the
+NR_UE_sched_ctrl_t structure of affected users. In particular, the field rbSize
+decides whether a user is to be allocated. Furthermore, the preprocessor is an
+exchangeable module that might schedule differently, e.g., one user for
+phytest, multiple users in FR1, or maybe FR2: phytest is in
+nr_preprocessor_phytest(), for FR1 is nr_simple_dlsch_preprocessor() [under
+development], for FR2 does not exist yet.
+* calls preprocessor via pre_processor_dl(): the preprocessor is responsible
+  for allocating CCEs and PUCCH (using allocate_nr_CCEs() and
+  nr_acknack_scheduling()) and deciding on the frequency/time domain
+  allocation. E.g., nr_simple_dlsch_preprocessor():
+  1)  mac_rlc_status_ind() locks and checks directly inside rlc data the
+      quantity of waiting data.
+  2)  return from the preprocessor if there is no data and no timing advance to
+      send,
+  3)  otherwise, allocate a CCE for the UE (and return if it is not possible)
+  4)  find a PUCCH occasion for HARQ
+  5a) check if there is a retransmission: if yes, find free resources to
+      transmit using the same resources, else
+  5b) calculate the necessary RBs needed to get a TBS large enough to hold all
+      data, or until no more resources are available
+  6)  Mark taken resources in the vrb_map
+* loop through all users: check if a new TA is necessary. Then, if a user has
+  allocated resources, compute its TBS, and fill nFAPI structures
+  (nr_fill_nfapi_dl_pdu() to populate what should be done by the lower layers
+  to make the Tx subframe). Update statistics (round, sent bytes).
 
 # RRC
 RRC is a regular thread with itti loop on queue: TASK_RRC_GNB
diff --git a/docker/Dockerfile.eNB.rhel8.2 b/docker/Dockerfile.eNB.rhel8.2
index 363b070934b903bc2978a1e88e4db48daadddfd2..5fcd5a7b9f07d041f66d3aa92dca8a3c72c57c83 100644
--- a/docker/Dockerfile.eNB.rhel8.2
+++ b/docker/Dockerfile.eNB.rhel8.2
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --eNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.eNB.rhel8.2.oc4-4 b/docker/Dockerfile.eNB.rhel8.2.oc4-4
index 039183a0f22675a62e308744596e9e4e109e6b7d..5b784c08a28f0c47d79e384c08bc46f3834ade68 100644
--- a/docker/Dockerfile.eNB.rhel8.2.oc4-4
+++ b/docker/Dockerfile.eNB.rhel8.2.oc4-4
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --eNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.eNB.ubuntu18 b/docker/Dockerfile.eNB.ubuntu18
index 9b6e5cb47d818f65493fc478b41cf4916b7e8781..cdfb37ebfc343637e2bfbdce2ff3d2f0f147a09c 100644
--- a/docker/Dockerfile.eNB.ubuntu18
+++ b/docker/Dockerfile.eNB.ubuntu18
@@ -32,9 +32,14 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --eNB --ninja -w USRP
 
+RUN apt-get install -y python3-pip && \
+    pip3 install --ignore-installed pyyaml && \
+    python3 ./docker/scripts/generateTemplate.py ./docker/scripts/enb_parameters.yaml
+
 # debug
 #RUN ldconfig -v && ldd /oai-ran/targets/bin/lte-softmodem.Rel15
 #RUN ls -ls /oai-ran/targets/bin
@@ -73,6 +78,7 @@ RUN apt-get update && \
 
 WORKDIR /opt/oai-enb/bin
 COPY --from=enb-build /oai-ran/targets/bin/lte-softmodem.Rel15 .
+COPY --from=enb-build /oai-ran/docker/scripts/enb_entrypoint.sh entrypoint.sh
 
 WORKDIR /usr/local/lib/
 COPY --from=enb-build /oai-ran/targets/bin/liboai_eth_transpro.so.Rel15 .
@@ -104,21 +110,17 @@ RUN ldconfig
 
 # Copy the relevant configuration files for eNB
 WORKDIR /opt/oai-enb/etc
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/enb.* ./
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/rcc.* ./
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/cu.* ./
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/du.* ./
-COPY --from=enb-build /oai-ran/ci-scripts/conf_files/rru.* ./
+COPY --from=enb-build /oai-ran/docker/etc .
 
 WORKDIR /opt/oai-enb
 
-#EXPOSE 2152/udp  # S1U, GTP/UDP
+# 2152 --> S1U, GTP/UDP
+# 36412 --> S1C, SCTP/UDP
+# 36422 --> X2C, SCTP/UDP
+EXPOSE 2152/udp 36412/udp 36422/udp
 #EXPOSE 22100/tcp # ?
-#EXPOSE 36412/udp # S1C, SCTP/UDP
-#EXPOSE 36422/udp # X2C, SCTP/UDP
 #EXPOSE 50000/udp # IF5 / ORI (control)
 #EXPOSE 50001/udp # IF5 / ECPRI (data)
 
-#CMD ["/opt/oai-enb/bin/lte-softmodem", "-O", "/opt/oai-enb/etc/enb.conf"]
-#ENTRYPOINT ["/opt/oai-enb/bin/entrypoint.sh"]
-CMD ["sleep", "infinity"]
+ENTRYPOINT ["/opt/oai-enb/bin/entrypoint.sh"]
+CMD ["/opt/oai-enb/bin/lte-softmodem.Rel15", "-O", "/opt/oai-enb/etc/enb.conf"]
diff --git a/docker/Dockerfile.gNB.rhel8.2 b/docker/Dockerfile.gNB.rhel8.2
index 901df9757ccca49449948019d1931139f1ab18dc..fb9ade927f8db1a1c7d559b3ddb26db4cb6af8df 100644
--- a/docker/Dockerfile.gNB.rhel8.2
+++ b/docker/Dockerfile.gNB.rhel8.2
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --gNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.gNB.rhel8.2.oc4-4 b/docker/Dockerfile.gNB.rhel8.2.oc4-4
index 197bc2a92ad9c69b0b1e139e84f674b8f78cb363..1e1eba016e34c503f9b87ae3c26f5cbf2df21430 100644
--- a/docker/Dockerfile.gNB.rhel8.2.oc4-4
+++ b/docker/Dockerfile.gNB.rhel8.2.oc4-4
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --gNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.gNB.ubuntu18 b/docker/Dockerfile.gNB.ubuntu18
index 4135b0e785f73928724d0531a56fda4c6ea92c09..d43ad4709dbedcef7c76861cc2677a38c95dc8d4 100644
--- a/docker/Dockerfile.gNB.ubuntu18
+++ b/docker/Dockerfile.gNB.ubuntu18
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --gNB --ninja -w USRP
 
diff --git a/docker/Dockerfile.lteUE.rhel8.2 b/docker/Dockerfile.lteUE.rhel8.2
index 6b64fdec1e1950dbc4e8e4067074e6dd64929ac4..0a853dcd6b5dc211a730cf0a82f074e9118eea61 100644
--- a/docker/Dockerfile.lteUE.rhel8.2
+++ b/docker/Dockerfile.lteUE.rhel8.2
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --UE --ninja -w USRP
 
diff --git a/docker/Dockerfile.lteUE.rhel8.2.oc4-4 b/docker/Dockerfile.lteUE.rhel8.2.oc4-4
index c390e01e3b9210672a1ba21cf90826c26f301c94..1339d18de62c244d7db97b6bdd5bf3a292e1d1ca 100644
--- a/docker/Dockerfile.lteUE.rhel8.2.oc4-4
+++ b/docker/Dockerfile.lteUE.rhel8.2.oc4-4
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --UE --ninja -w USRP
 
diff --git a/docker/Dockerfile.lteUE.ubuntu18 b/docker/Dockerfile.lteUE.ubuntu18
index f1233d6a01440feffc4f2aa93a65dbf7caf49cdf..8793cc54f79d87e470a46a4520b7f2ee519d1865 100644
--- a/docker/Dockerfile.lteUE.ubuntu18
+++ b/docker/Dockerfile.lteUE.ubuntu18
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --UE --ninja -w USRP
 
diff --git a/docker/Dockerfile.nrUE.rhel8.2 b/docker/Dockerfile.nrUE.rhel8.2
index 466eeedd403dabdfb1835136720003d3c2a387eb..f9f3f8e4bfcdfd4e95d3d8ae10ed206788f7af53 100644
--- a/docker/Dockerfile.nrUE.rhel8.2
+++ b/docker/Dockerfile.nrUE.rhel8.2
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --nrUE --ninja -w USRP
 
diff --git a/docker/Dockerfile.nrUE.rhel8.2.oc4-4 b/docker/Dockerfile.nrUE.rhel8.2.oc4-4
index 3b09b18b552eb5b20c13b3890d509c2e049bfadd..d900fff998d633eccaa0685dc71bad20820de92a 100644
--- a/docker/Dockerfile.nrUE.rhel8.2.oc4-4
+++ b/docker/Dockerfile.nrUE.rhel8.2.oc4-4
@@ -33,6 +33,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --nrUE --ninja -w USRP
 
diff --git a/docker/Dockerfile.nrUE.ubuntu18 b/docker/Dockerfile.nrUE.ubuntu18
index eecadacb507b89b584b1b9dc3d5c3eda9c6e7648..5450194f3539ad83663017e31e53e10185dc9a37 100644
--- a/docker/Dockerfile.nrUE.ubuntu18
+++ b/docker/Dockerfile.nrUE.ubuntu18
@@ -32,6 +32,7 @@ WORKDIR /oai-ran
 #run build_oai to build the target image
 RUN /bin/sh oaienv && \ 
     cd cmake_targets && \
+    rm -Rf log && \
     mkdir -p log && \
     ./build_oai --nrUE --ninja -w USRP
 
diff --git a/docker/scripts/enb_entrypoint.sh b/docker/scripts/enb_entrypoint.sh
new file mode 100755
index 0000000000000000000000000000000000000000..31d99b2a676e2393ee16d4107fbd902943d145b2
--- /dev/null
+++ b/docker/scripts/enb_entrypoint.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# Based another env var, pick one template to use
+if [[ -v USE_FDD_CU ]]; then ln -s /opt/oai-enb/etc/cu.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_FDD_DU ]]; then ln -s /opt/oai-enb/etc/du.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_FDD_MONO ]]; then ln -s /opt/oai-enb/etc/enb.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_TDD_MONO ]]; then ln -s /opt/oai-enb/etc/enb.tdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_FDD_RCC ]]; then ln -s /opt/oai-enb/etc/rcc.if4p5.enb.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_FDD_RRU ]]; then ln -s /opt/oai-enb/etc/rru.fdd.conf /opt/oai-enb/etc/enb.conf; fi
+if [[ -v USE_TDD_RRU ]]; then ln -s /opt/oai-enb/etc/rru.tdd.conf /opt/oai-enb/etc/enb.conf; fi
+
+# Only this template will be manipulated
+CONFIG_FILES=`ls /opt/oai-enb/etc/enb.conf`
+
+for c in ${CONFIG_FILES}; do
+    # grep variable names (format: ${VAR}) from template to be rendered
+    VARS=$(grep -oP '@[a-zA-Z0-9_]+@' ${c} | sort | uniq | xargs)
+
+    # create sed expressions for substituting each occurrence of ${VAR}
+    # with the value of the environment variable "VAR"
+    EXPRESSIONS=""
+    for v in ${VARS}; do
+        NEW_VAR=`echo $v | sed -e "s#@##g"`
+        if [[ "${!NEW_VAR}x" == "x" ]]; then
+            echo "Error: Environment variable '${NEW_VAR}' is not set." \
+                "Config file '$(basename $c)' requires all of $VARS."
+            exit 1
+        fi
+        EXPRESSIONS="${EXPRESSIONS};s|${v}|${!NEW_VAR}|g"
+    done
+    EXPRESSIONS="${EXPRESSIONS#';'}"
+
+    # render template and inline replace config file
+    sed -i "${EXPRESSIONS}" ${c}
+done
+
+# Load the USRP binaries
+if [[ -v USE_B2XX ]]; then
+    /usr/lib/uhd/utils/uhd_images_downloader.py -t b2xx
+elif [[ -v USE_X3XX ]]; then
+    /usr/lib/uhd/utils/uhd_images_downloader.py -t x3xx
+elif [[ -v USE_N3XX ]]; then
+    /usr/lib/uhd/utils/uhd_images_downloader.py -t n3xx
+fi
+
+echo "=================================="
+echo "== Starting eNB soft modem"
+if [[ -v USE_ADDITIONAL_OPTIONS ]]; then
+    echo "Additional option(s): ${USE_ADDITIONAL_OPTIONS}"
+    new_args=()
+    while [[ $# -gt 0 ]]; do
+        new_args+=("$1")
+        shift
+    done
+    for word in ${USE_ADDITIONAL_OPTIONS}; do
+        new_args+=("$word")
+    done
+    echo "${new_args[@]}"
+    exec "${new_args[@]}"
+else
+    echo "$@"
+    exec "$@"
+fi
diff --git a/docker/scripts/enb_parameters.yaml b/docker/scripts/enb_parameters.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a60fc20e29434725379d3fbe8172dd33c22e2f3f
--- /dev/null
+++ b/docker/scripts/enb_parameters.yaml
@@ -0,0 +1,248 @@
+#/*
+# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+# * contributor license agreements.  See the NOTICE file distributed with
+# * this work for additional information regarding copyright ownership.
+# * The OpenAirInterface Software Alliance licenses this file to You under
+# * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+# * except in compliance with the License.
+# * You may obtain a copy of the License at
+# *
+# *      http://www.openairinterface.org/?page_id=698
+# *
+# * Unless required by applicable law or agreed to in writing, software
+# * distributed under the License is distributed on an "AS IS" BASIS,
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# * See the License for the specific language governing permissions and
+# * limitations under the License.
+# *-------------------------------------------------------------------------------
+# * For more information about the OpenAirInterface (OAI) Software Alliance:
+# *      contact@openairinterface.org
+# */
+
+---
+- paths:
+    source_dir: "ci-scripts/conf_files/"
+    dest_dir: docker/etc
+    
+- configurations:
+  - filePrefix: cu
+    outputfilename: "cu.fdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: local_s_if_name
+      env: "@F1_IF_NAME@"
+    - key: remote_s_address
+      env: "@F1_DU_IP_ADDRESS@"
+    - key: local_s_address
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+    - key: ipv4
+      env: "@MME_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1_MME
+      env: "@S1C_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1_MME
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1U
+      env: "@S1U_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1U
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_IPV4_ADDRESS_FOR_X2C
+      env: "@F1_CU_IP_ADDRESS@"
+      
+  - filePrefix: du
+    outputfilename: "du.fdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: local_n_if_name
+      env: "@F1_IF_NAME@"
+    - key: remote_n_address
+      env: "@F1_DU_IP_ADDRESS@"
+    - key: local_n_address
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+      
+  - filePrefix: rru.fdd
+    outputfilename: "rru.fdd.conf"
+    config:
+    - key: local_if_name
+      env: "@RRU_IF4P5_IF_NAME@"
+    - key: remote_address
+      env: "@RCC_REMOTE_IP_ADDRESS@"
+    - key: local_address
+      env: "@RRU_LOCAL_IP_ADDRESS@"
+    - key: bands
+      env: "@UTRA_BAND_ID@"
+      
+  - filePrefix: rru.tdd
+    outputfilename: "rru.tdd.conf"
+    config:
+    - key: local_if_name
+      env: "@RRU_IF4P5_IF_NAME@"
+    - key: remote_address
+      env: "@RCC_REMOTE_IP_ADDRESS@"
+    - key: local_address
+      env: "@RRU_LOCAL_IP_ADDRESS@"
+    - key: bands
+      env: "@UTRA_BAND_ID@"
+      
+  - filePrefix: enb.band7.tm1.25PRB.usrpb210
+    outputfilename: "enb.fdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+    - key: ipv4
+      env: "@MME_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1_MME
+      env: "@ENB_S1C_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1_MME
+      env: "@ENB_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1U
+      env: "@ENB_S1U_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1U
+      env: "@ENB_S1U_IP_ADDRESS@"
+    - key: ENB_IPV4_ADDRESS_FOR_X2C
+      env: "@ENB_X2_IP_ADDRESS@"
+    - key: FLEXRAN_ENABLED
+      env: "@FLEXRAN_ENABLED@"
+    - key: FLEXRAN_INTERFACE_NAME
+      env: "@FLEXRAN_INTERFACE_NAME@"
+    - key: FLEXRAN_IPV4_ADDRESS
+      env: "@FLEXRAN_IPV4_ADDRESS@"
+      
+  - filePrefix: enb.band40.tm1.25PRB.FairScheduler.usrpb210
+    outputfilename: "enb.tdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+    - key: ipv4
+      env: "@MME_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1_MME
+      env: "@S1C_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1_MME
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1U
+      env: "@S1U_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1U
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_IPV4_ADDRESS_FOR_X2C
+      env: "@F1_CU_IP_ADDRESS@"
+      
+  - filePrefix: "rcc.band7.tm1.nfapi"
+    outputfilename: "rcc.if4p5.enb.fdd.conf"
+    config:
+    - key: Active_eNBs
+      env: "@ENB_NAME@"
+    - key: eNB_name
+      env: "@ENB_NAME@"
+    - key: plmn_list
+      env:
+        mcc: "@MCC@"
+        mnc: "@MNC@"
+        mnc_length: "@MNC_LENGTH@"
+    - key: tracking_area_code
+      env: "@TAC@"
+    - key: local_s_if_name
+      env: "@F1_IF_NAME@"
+    - key: remote_s_address
+      env: "@F1_DU_IP_ADDRESS@"
+    - key: local_s_address
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: eutra_band
+      env: "@UTRA_BAND_ID@"
+    - key: downlink_frequency
+      env: "@DL_FREQUENCY_IN_MHZ@000000"
+    - key: uplink_frequency_offset
+      env: "@UL_FREQUENCY_OFFSET_IN_MHZ@000000"
+    - key: Nid_cell
+      env: "@NID_CELL@"
+    - key: N_RB_DL
+      env: "@NB_PRB@"
+    - key: ipv4
+      env: "@MME_S1C_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1_MME
+      env: "@S1C_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1_MME
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_INTERFACE_NAME_FOR_S1U
+      env: "@S1U_IF_NAME@"
+    - key: ENB_IPV4_ADDRESS_FOR_S1U
+      env: "@F1_CU_IP_ADDRESS@"
+    - key: ENB_IPV4_ADDRESS_FOR_X2C
+      env: "@F1_CU_IP_ADDRESS@"
+
diff --git a/docker/scripts/generateTemplate.py b/docker/scripts/generateTemplate.py
new file mode 100644
index 0000000000000000000000000000000000000000..4949e9cf21531849fd3fa72d4adb18d8fa0c950a
--- /dev/null
+++ b/docker/scripts/generateTemplate.py
@@ -0,0 +1,89 @@
+#/*
+# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+# * contributor license agreements.  See the NOTICE file distributed with
+# * this work for additional information regarding copyright ownership.
+# * The OpenAirInterface Software Alliance licenses this file to You under
+# * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+# * except in compliance with the License.
+# * You may obtain a copy of the License at
+# *
+# *      http://www.openairinterface.org/?page_id=698
+# *
+# * Unless required by applicable law or agreed to in writing, software
+# * distributed under the License is distributed on an "AS IS" BASIS,
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# * See the License for the specific language governing permissions and
+# * limitations under the License.
+# *-------------------------------------------------------------------------------
+# * For more information about the OpenAirInterface (OAI) Software Alliance:
+# *      contact@openairinterface.org
+# */
+#---------------------------------------------------------------------
+
+#-----------------------------------------------------------
+# Import
+#-----------------------------------------------------------
+import re
+import yaml
+import os
+import sys
+
+
+def main():
+  #read yaml input parameters
+  f = open(f'{sys.argv[1]}',)
+  data = yaml.full_load(f)
+  dir = os.listdir(f'{data[0]["paths"]["source_dir"]}')
+
+
+  #identify configs, read and replace corresponding values
+  for config in data[1]["configurations"]:
+    filePrefix = config["filePrefix"]
+    outputfilename = config["outputfilename"]
+    for inputfile in dir:
+      if inputfile.find(filePrefix) >=0:
+        prefix_outputfile = {"cu": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', 
+                             "du": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "rru.fdd": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "rru.tdd": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "enb.band7.tm1.25PRB.usrpb210": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "enb.band40.tm1.25PRB.FairScheduler.usrpb210": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "rcc.band7.tm1.nfapi": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}'
+                             }
+        if filePrefix in prefix_outputfile:
+          outputfile1 = prefix_outputfile[filePrefix]  
+      
+        directory = f'{data[0]["paths"]["dest_dir"]}'
+        if not os.path.exists(directory):
+          os.makedirs(directory, exist_ok=True)
+
+        with open(f'{data[0]["paths"]["source_dir"]}{inputfile}', mode='r') as inputfile, \
+             open(outputfile1, mode='w') as outputfile:
+          for line in inputfile:
+            count = 0
+            for key in config["config"]:
+              if line.find(key["key"]) >= 0:
+                count += 1
+                if re.search(r'preference', line):
+                  templine = line
+                elif re.search(r'plmn_list', line):
+                  templine = re.sub(r'[0-9]+', '""', line)
+                  templine = re.sub(r'\"\"', key["env"]["mcc"], templine, 1)
+                  templine = re.sub(r'\"\"', key["env"]["mnc"], templine, 1) 
+                  templine = re.sub(r'\"\"', key["env"]["mnc_length"], templine, 1)               
+                elif re.search('downlink_frequency', line):
+                  templine = re.sub(r'[0-9]+', key["env"], line)
+                elif re.search('uplink_frequency_offset', line):
+                  templine = re.sub(r'[0-9]+', key["env"], line)
+               
+                elif re.search(r'"(.*?)"', line):
+                  templine = re.sub(r'(?<=")[^"]*(?=")', key["env"], line)    
+                elif re.search(r'[0-9]', line):
+                  templine = re.sub(r'\d+', key["env"], line)
+                outputfile.write(templine)
+            
+            if count == 0:
+              outputfile.write(line)
+              
+if __name__ == "__main__":
+    main()
diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c
index 51175424b19cc230b908bd0e6336373df3ca14b8..59cacea56465b688b4fe94b72f6f81cb3d7d5a13 100644
--- a/executables/nr-gnb.c
+++ b/executables/nr-gnb.c
@@ -72,6 +72,7 @@
 #include "common/utils/LOG/vcd_signal_dumper.h"
 #include "UTIL/OPT/opt.h"
 #include "enb_config.h"
+#include "gnb_paramdef.h"
 
 
 #ifndef OPENAIR2
@@ -101,6 +102,7 @@ extern int transmission_mode;
 
 extern uint16_t sf_ahead;
 extern uint16_t sl_ahead;
+
 //pthread_t                       main_gNB_thread;
 
 time_stats_t softmodem_stats_mt; // main thread
@@ -884,7 +886,18 @@ void init_gNB_proc(int inst) {
 
   gNB->threadPool = (tpool_t*)malloc(sizeof(tpool_t));
   gNB->respDecode = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t));
-  char ul_pool[] = "-1,-1";
+  int numCPU = sysconf(_SC_NPROCESSORS_ONLN);
+  uint32_t num_threads_pusch;
+  paramdef_t PUSCHThreads[] = NUM_THREADS_DESC;
+  config_get( PUSCHThreads,sizeof(PUSCHThreads)/sizeof(paramdef_t),NULL);
+  int threadCnt = min(numCPU, num_threads_pusch);
+  char ul_pool[80];
+  sprintf(ul_pool,"-1");
+  int s_offset = 0;
+  for (int icpu=1; icpu<threadCnt; icpu++) {
+    sprintf(ul_pool+2+s_offset,",-1");
+    s_offset += 3;
+  }
   initTpool(ul_pool, gNB->threadPool, false);
   initNotifiedFIFO(gNB->respDecode);
 }
diff --git a/executables/nr-ue.c b/executables/nr-ue.c
index e5eafe9f330e37fab8244372a20ee7b72e3b93ad..9098fa763fc07582bd5742145213cef369f35f82 100644
--- a/executables/nr-ue.c
+++ b/executables/nr-ue.c
@@ -422,12 +422,10 @@ void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
     //printf(">>> nr_ue_pdcch_procedures ended\n");
 #endif
 
-    if(IS_SOFTMODEM_NOS1){ //&& proc->nr_slot_rx==1
-      //Hardcoded rnti value
+    if(IS_SOFTMODEM_NOS1){
+      NR_UE_MAC_INST_t *mac = get_mac_inst(0);
       protocol_ctxt_t ctxt;
-      PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, UE->Mod_id, ENB_FLAG_NO,
-				     0x1234, proc->frame_rx,
-				     proc->nr_slot_rx, 0);
+      PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, UE->Mod_id, ENB_FLAG_NO, mac->crnti, proc->frame_rx, proc->nr_slot_rx, 0);
       pdcp_run(&ctxt);
     }
   }
@@ -468,32 +466,13 @@ void UE_processing(void *arg) {
   processingData_t *rxtxD = (processingData_t *) arg;
   UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
   PHY_VARS_NR_UE    *UE   = rxtxD->UE;
+  int slot_tx = proc->nr_slot_tx;
+  int frame_tx = proc->frame_tx;
 
   processSlotRX(UE, proc);
   processSlotTX(UE, proc);
+  ue_ta_procedures(UE, slot_tx, frame_tx);
 
-  /* UL time alignment
-  // If the current tx frame and slot match the TA configuration in ul_time_alignment
-  // then timing advance is processed and set to be applied in the next UL transmission */
-  if (UE->mac_enabled == 1) {
-    uint8_t gNB_id = 0;
-    NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &UE->ul_time_alignment[gNB_id];
-    int slot_tx = proc->nr_slot_tx;
-    int frame_tx = proc->frame_tx;
-
-    if (frame_tx == ul_time_alignment->ta_frame && slot_tx == ul_time_alignment->ta_slot) {
-      uint8_t numerology = UE->frame_parms.numerology_index;
-      uint16_t bwp_ul_NB_RB = UE->frame_parms.N_RB_UL;
-
-      LOG_D(PHY,"Applying timing advance -- frame %d -- slot %d\n", frame_tx, slot_tx);
-
-      //if (nfapi_mode!=3){
-      nr_process_timing_advance(UE->Mod_id, UE->CC_id, ul_time_alignment->ta_command, numerology, bwp_ul_NB_RB);
-      ul_time_alignment->ta_frame = -1;
-      ul_time_alignment->ta_slot = -1;
-      //}
-    }
-  }
 }
 
 void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
@@ -605,7 +584,7 @@ void *UE_thread(void *arg) {
   //this thread should be over the processing thread to keep in real time
   PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg;
   //  int tx_enabled = 0;
-  openair0_timestamp timestamp;
+  openair0_timestamp timestamp, writeTimestamp;
   void *rxp[NB_ANTENNAS_RX], *txp[NB_ANTENNAS_TX];
   int start_rx_stream = 0;
   AssertFatal(0== openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), "");
@@ -736,11 +715,6 @@ void *UE_thread(void *arg) {
                      UE->rx_offset_diff;
     }
 
-    if (UE->timing_advance != timing_advance) {
-      writeBlockSize -= UE->timing_advance - timing_advance;
-      timing_advance = UE->timing_advance;
-    }
-
     AssertFatal(readBlockSize ==
                 UE->rfdevice.trx_read_func(&UE->rfdevice,
                                            &timestamp,
@@ -788,12 +762,19 @@ void *UE_thread(void *arg) {
       LOG_E(PHY,"Decoded frame index (%d) is not compatible with current context (%d), UE should go back to synch mode\n",
             decoded_frame_rx, curMsg->proc.frame_rx  );
 
+    // use previous timing_advance value to compute writeTimestamp
+    writeTimestamp = timestamp + UE->frame_parms.get_samples_slot_timestamp(slot_nr, &UE->frame_parms,DURATION_RX_TO_TX - RX_NB_TH) -
+                     firstSymSamp - openair0_cfg[0].tx_sample_advance - UE->N_TA_offset - timing_advance;
+
+    // but use current UE->timing_advance value to compute writeBlockSize
+    if (UE->timing_advance != timing_advance) {
+      writeBlockSize -= UE->timing_advance - timing_advance;
+      timing_advance = UE->timing_advance;
+    }
+
     AssertFatal( writeBlockSize ==
                  UE->rfdevice.trx_write_func(&UE->rfdevice,
-                     timestamp+
-                     UE->frame_parms.get_samples_slot_timestamp(slot_nr,
-                     &UE->frame_parms,DURATION_RX_TO_TX - RX_NB_TH) - firstSymSamp -
-                     openair0_cfg[0].tx_sample_advance - UE->N_TA_offset - UE->timing_advance,
+                     writeTimestamp,
                      txp,
                      writeBlockSize,
                      UE->frame_parms.nb_antennas_tx,
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
index 12d60c09dd0df120855c0aed105f58eca108e8bf..ab3a0ced8b78706fbfeb52055a473a09d1da4151 100644
--- a/executables/nr-uesoftmodem.c
+++ b/executables/nr-uesoftmodem.c
@@ -152,6 +152,7 @@ double            cpuf;
 runmode_t            mode = normal_txrx;
 int               UE_scan = 0;
 int          chain_offset = 0;
+int           card_offset = 0;
 uint64_t num_missed_slots = 0; // counter for the number of missed slots
 int     transmission_mode = 1;
 int            numerology = 0;
@@ -307,6 +308,9 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
   UE->rx_total_gain_dB     = (int)rx_gain[CC_id][0] + rx_gain_off;
   UE->tx_total_gain_dB     = (int)tx_gain[CC_id][0];
   UE->tx_power_max_dBm     = tx_max_power[CC_id];
+  UE->rf_map.card          = card_offset;
+  UE->rf_map.chain         = CC_id + chain_offset;
+  UE->timing_advance       = timing_advance;
 
   LOG_I(PHY,"Set UE mode %d, UE_fo_compensation %d, UE_scan %d, UE_scan_carrier %d, UE_no_timing_correction %d \n", mode, UE_fo_compensation, UE_scan, UE_scan_carrier, UE_no_timing_correction);
 
@@ -576,12 +580,6 @@ int main( int argc, char **argv ) {
     load_softscope("nr",PHY_vars_UE_g[0][0]);
   }     
 
-  for(int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
-    PHY_vars_UE_g[0][CC_id]->rf_map.card=0;
-    PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+chain_offset;
-    PHY_vars_UE_g[0][CC_id]->timing_advance = timing_advance;
-  }
-
   init_NR_UE_threads(1);
   printf("UE threads created by %ld\n", gettid());
   
diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h
index feb020154b4f2cc53bba83c8634b1fc9d9216aa2..f8e9b0959fa57617617e0f2ec979e9c802e57a34 100644
--- a/executables/softmodem-common.h
+++ b/executables/softmodem-common.h
@@ -70,7 +70,7 @@ extern "C"
 #define CONFIG_HLP_ITTIL         "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n"
 #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_NUMUES        "Set the number of UEs for the emulation"
 #define CONFIG_HLP_MSLOTS        "Skip the missed slots/subframes \n"
@@ -109,6 +109,7 @@ extern "C"
 #define TIMING_SOURCE       softmodem_params.timing_source
 #define SEND_DMRSSYNC       softmodem_params.send_dmrs_sync
 #define USIM_TEST           softmodem_params.usim_test
+#define USE_256QAM_TABLE    softmodem_params.use_256qam_table
 
 #define DEFAULT_RFCONFIG_FILE    "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat";
 
@@ -137,6 +138,7 @@ extern "C"
     {"basicsim",             CONFIG_HLP_RFSIM,        PARAMFLAG_BOOL, uptr:&basicsim,                     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},                     \
+    {"use-256qam-table",     CONFIG_HLP_256QAM,       PARAMFLAG_BOOL, iptr:&USE_256QAM_TABLE,             defintval:0,           TYPE_INT,    0},                     \
   }
 
   
@@ -222,6 +224,7 @@ typedef struct {
   uint32_t       timing_source;
   int            hw_timing_advance;
   uint32_t       send_dmrs_sync;
+  int            use_256qam_table;
 } softmodem_params_t;
 
 extern uint64_t get_softmodem_optmask(void);
diff --git a/openair1/PHY/CODING/nr_rate_matching.c b/openair1/PHY/CODING/nr_rate_matching.c
index efa5abdc90004cae6cd8eab61ab899f43c5347aa..1afe82497a3b0ed6d02477605468fd623f5d25bb 100644
--- a/openair1/PHY/CODING/nr_rate_matching.c
+++ b/openair1/PHY/CODING/nr_rate_matching.c
@@ -347,13 +347,13 @@ void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f)
     }
     break;
   case 8:
-    e1=e+(E/6);
-    e2=e1+(E/6);
-    e3=e2+(E/6);
-    e4=e3+(E/6);
-    e5=e4+(E/6);
-    e6=e5+(E/6);
-    e7=e6+(E/6);
+    e1=e+(E/8);
+    e2=e1+(E/8);
+    e3=e2+(E/8);
+    e4=e3+(E/8);
+    e5=e4+(E/8);
+    e6=e5+(E/8);
+    e7=e6+(E/8);
     for (int j = 0,j2=0; j< E/8; j++,j2+=8){
       e[j]  = f[j2];
       e1[j] = f[j2+1];
@@ -407,8 +407,16 @@ int nr_rate_matching_ldpc(uint8_t Ilbrm,
 #ifdef RM_DEBUG
   printf("nr_rate_matching_ldpc: E %d, F %d, Foffset %d, k0 %d, Ncb %d, rvidx %d\n", E, F, Foffset,ind, Ncb, rvidx);
 #endif
-  AssertFatal(Foffset <= E,"Foffset %d > E %d\n",Foffset,E); 
-  AssertFatal(Foffset <= Ncb,"Foffset %d > Ncb %d\n",Foffset,Ncb); 
+  AssertFatal(Foffset <= E,
+              "Foffset %d > E %d "
+              "(Ilbrm %d, Tbslbrm %d, Z %d, BG %d, C %d)\n",
+              Foffset, E,
+              Ilbrm, Tbslbrm, Z, BG, C);
+  AssertFatal(Foffset <= Ncb,
+              "Foffset %d > Ncb %d "
+              "(Ilbrm %d, Tbslbrm %d, Z %d, BG %d, C %d)\n",
+              Foffset, Ncb,
+              Ilbrm, Tbslbrm, Z, BG, C);
 
   if (ind >= Foffset && ind < (F+Foffset)) ind = F+Foffset;
 
diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c
index 9c74f3dba4b560bdc2665c4a913a77dc79480c4e..cf93c41ee0aa5d83c8c0af60bd5cbbe2a0cba726 100644
--- a/openair1/PHY/INIT/nr_init_ue.c
+++ b/openair1/PHY/INIT/nr_init_ue.c
@@ -393,6 +393,7 @@ void phy_init_nr_ue__PDSCH(NR_UE_PDSCH *const pdsch,
   //pdsch->dl_ch_rho2_ext         = (int32_t**)malloc16_clear( 8*sizeof(int32_t*) );
   pdsch->dl_ch_mag0             = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) );
   pdsch->dl_ch_magb0            = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) );
+  pdsch->dl_ch_magr0            = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) );
   pdsch->ptrs_phase_per_slot    = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) );
   pdsch->ptrs_re_per_slot       = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) );
   pdsch->dl_ch_ptrs_estimates_ext = (int32_t **)malloc16_clear( 8*sizeof(int32_t *) );
@@ -416,6 +417,7 @@ void phy_init_nr_ue__PDSCH(NR_UE_PDSCH *const pdsch,
       //pdsch->dl_ch_rho2_ext[idx]          = (int32_t*)malloc16_clear( sizeof(int32_t) * num );
       pdsch->dl_ch_mag0[idx]              = (int32_t *)malloc16_clear( sizeof(int32_t) * num );
       pdsch->dl_ch_magb0[idx]             = (int32_t *)malloc16_clear( sizeof(int32_t) * num );
+      pdsch->dl_ch_magr0[idx]             = (int32_t *)malloc16_clear( sizeof(int32_t) * num );
       pdsch->ptrs_re_per_slot[idx]        = (int32_t *)malloc16_clear(sizeof(int32_t) * 14);
       pdsch->ptrs_phase_per_slot[idx]     = (int32_t *)malloc16_clear( sizeof(int32_t) * 14 );
       pdsch->dl_ch_ptrs_estimates_ext[idx]= (int32_t *)malloc16_clear( sizeof(int32_t) * num);
@@ -472,6 +474,10 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
     ue->total_TBS_last[eNB_id] = 0;
     ue->bitrate[eNB_id] = 0;
     ue->total_received_bits[eNB_id] = 0;
+
+    ue->ul_time_alignment[eNB_id].apply_ta = 0;
+    ue->ul_time_alignment[eNB_id].ta_frame = -1;
+    ue->ul_time_alignment[eNB_id].ta_slot  = -1;
   }
   // init NR modulation lookup tables
   nr_generate_modulation_table();
diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c
index 171980d343d56b56d10c748231ba614da27e33d4..ba4147e5cdbec204adc746698dc37694a49c0c71 100644
--- a/openair1/PHY/INIT/nr_parms.c
+++ b/openair1/PHY/INIT/nr_parms.c
@@ -41,38 +41,32 @@ int nr_get_ssb_start_symbol(NR_DL_FRAME_PARMS *fp)
   int case_E[8] = {8, 12, 16, 20, 32, 36, 40, 44};
 
   switch(mu) {
-
-	case NR_MU_0: // case A
-	    n = i_ssb >> 1;
-	    symbol = case_AC[i_ssb % 2] + 14*n;
-	break;
-
-	case NR_MU_1: 
-	    if (type == 1){ // case B
-		n = i_ssb >> 2;
-	    	symbol = case_BD[i_ssb % 4] + 28*n;
-	    }
-	    if (type == 2){ // case C
-		n = i_ssb >> 1;
-		symbol = case_AC[i_ssb % 2] + 14*n;
-	    }
-	 break;
-
-	 case NR_MU_3: // case D
-	    n_temp = i_ssb >> 2; 
-	    n = n_temp + (n_temp >> 2);
-	    symbol = case_BD[i_ssb % 4] + 28*n;
-	 break;
-
-	 case NR_MU_4:  // case E
-	    n_temp = i_ssb >> 3; 
-	    n = n_temp + (n_temp >> 2);
-	    symbol = case_E[i_ssb % 8] + 56*n;
-	 break;
-
-
-	 default:
-	      AssertFatal(0==1, "Invalid numerology index %d for the synchronization block\n", mu);
+    case NR_MU_0: // case A
+      n = i_ssb >> 1;
+      symbol = case_AC[i_ssb % 2] + 14*n;
+      break;
+    case NR_MU_1:
+      if (type == 1){ // case B
+        n = i_ssb >> 2;
+        symbol = case_BD[i_ssb % 4] + 28*n;
+       }
+       if (type == 2){ // case C
+         n = i_ssb >> 1;
+         symbol = case_AC[i_ssb % 2] + 14*n;
+       }
+       break;
+     case NR_MU_3: // case D
+       n_temp = i_ssb >> 2;
+       n = n_temp + (n_temp >> 2);
+       symbol = case_BD[i_ssb % 4] + 28*n;
+       break;
+     case NR_MU_4:  // case E
+       n_temp = i_ssb >> 3;
+       n = n_temp + (n_temp >> 2);
+       symbol = case_E[i_ssb % 8] + 56*n;
+       break;
+     default:
+       AssertFatal(0==1, "Invalid numerology index %d for the synchronization block\n", mu);
   }
 
   if (half_frame_index)
diff --git a/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c b/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c
index a881773910c70a2719fc47cd178d786372e23e93..2d79158920bb821d71e126822e193c7d50f20fcd 100644
--- a/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c
+++ b/openair1/PHY/LTE_ESTIMATION/lte_eNB_measurements.c
@@ -47,6 +47,7 @@ void lte_eNB_I0_measurements(PHY_VARS_eNB *eNB,
   uint32_t rb;
   int32_t *ul_ch;
   int32_t n0_power_tot;
+  int64_t n0_power_tot2;
   int len;
   int offset;
   // noise measurements
@@ -75,43 +76,47 @@ void lte_eNB_I0_measurements(PHY_VARS_eNB *eNB,
 
   }
 
+  n0_power_tot2=0;
+  int nb_rb=0;
   for (rb=0; rb<frame_parms->N_RB_UL; rb++) {
 
-    n0_power_tot=0;
+    n0_power_tot=0; 
+    int offset0= (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size;
+
     if ((rb_mask[rb>>5]&(1<<(rb&31))) == 0) {  // check that rb was not used in this subframe
+      nb_rb++;
       for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
-
+        measurements->n0_subband_power[aarx][rb] = 0;
+        for (int s=0;s<14-(frame_parms->Ncp<<1);s++) {
       // select the 7th symbol in an uplink subframe
-	offset = (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size;
-	offset += (7*frame_parms->ofdm_symbol_size);
-	ul_ch  = &common_vars->rxdataF[aarx][offset];
-	len = 12;
+	  offset = offset0 + (s*frame_parms->ofdm_symbol_size);
+	  ul_ch  = &common_vars->rxdataF[aarx][offset];
+	  len = 12;
 	// just do first half of middle PRB for odd number of PRBs
-	if (((frame_parms->N_RB_UL&1) == 1) && 
-	    (rb==(frame_parms->N_RB_UL>>1))) {
-	  len=6;
-	}
-	if (clear == 1)
-	  measurements->n0_subband_power[aarx][rb]=0;
+	  if (((frame_parms->N_RB_UL&1) == 1) && 
+	      (rb==(frame_parms->N_RB_UL>>1))) {
+	    len=6;
+	  }
 
-	AssertFatal(ul_ch, "RX signal buffer (freq) problem");
+	  AssertFatal(ul_ch, "RX signal buffer (freq) problem");
 
 
-	measurements->n0_subband_power[aarx][rb] = signal_energy_nodc(ul_ch,len);
-	//((k1*(signal_energy_nodc(ul_ch,len))) 
-	  //  + (k2*measurements->n0_subband_power[aarx][rb]));  
+	  measurements->n0_subband_power[aarx][rb] += signal_energy_nodc(ul_ch,len);
 	  
-	measurements->n0_subband_power_dB[aarx][rb] = dB_fixed(measurements->n0_subband_power[aarx][rb]);
-	//		printf("subframe %d (%d): eNB %d, aarx %d, rb %d len %d: energy %d (%d dB)\n",subframe,offset,eNB_id,aarx,rb,len,signal_energy_nodc(ul_ch,len),  
-	//	       measurements->n0_subband_power_dB[aarx][rb]);
-	n0_power_tot += measurements->n0_subband_power[aarx][rb];
+        }
+        measurements->n0_subband_power[aarx][rb]/=(14-(frame_parms->Ncp<<1));
+        measurements->n0_subband_power_dB[aarx][rb] = dB_fixed(measurements->n0_subband_power[aarx][rb]);
+        n0_power_tot += measurements->n0_subband_power[aarx][rb];
+
       }
-      
-      measurements->n0_subband_power_tot_dB[rb] = dB_fixed(n0_power_tot);
+      n0_power_tot/=frame_parms->nb_antennas_rx;
+      n0_power_tot2 += n0_power_tot;
+      measurements->n0_subband_power_tot_dB[rb] = dB_fixed(n0_power_tot/frame_parms->nb_antennas_rx);
       measurements->n0_subband_power_tot_dBm[rb] = measurements->n0_subband_power_tot_dB[rb] - eNB->rx_total_gain_dB - dB_fixed(frame_parms->N_RB_UL);
       
     }
   }
+  if (nb_rb>0) measurements->n0_subband_power_avg_dB = dB_fixed(n0_power_tot2/nb_rb);
 }
 
 void lte_eNB_srs_measurements(PHY_VARS_eNB *eNB,
diff --git a/openair1/PHY/LTE_TRANSPORT/if5_tools.c b/openair1/PHY/LTE_TRANSPORT/if5_tools.c
index 1e0dd9db1b7af5110b3c30425ec33de7c5755912..f39f3ef872021d12fb73273f7a165e104d59cf75 100644
--- a/openair1/PHY/LTE_TRANSPORT/if5_tools.c
+++ b/openair1/PHY/LTE_TRANSPORT/if5_tools.c
@@ -1070,6 +1070,8 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 );
   if (packet_type == IF5_RRH_GW_DL) {    
     if (eth->compression == ALAW_COMPRESS) {
+     AssertFatal(1==0,"IF5 compression needs reworking\n");
+/*
       if (eth->flags == ETH_RAW_MODE) {
         data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES + MAC_HEADER_SIZE_BYTES);
       } else {
@@ -1100,28 +1102,31 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
         LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp));
         VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 0 );
       }
+*/
     } else if (eth->compression == NO_COMPRESS) {
 
-      for (i=0; i < fp->nb_antennas_tx; i++)
-        txp[i] = (void*)&ru->common.txdata[i][subframe*fp->samples_per_tti];
+      for (i=0; i < ru->nb_tx; i++)
+        txp[i] = (int32_t*)&ru->common.txdata[i][subframe*fp->samples_per_tti];
     
       for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) {
-        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 );
-        clock_gettime( CLOCK_MONOTONIC, &start_comp);
-        ru->ifdevice.trx_write_func(&ru->ifdevice,
-				    (proc_timestamp + packet_id*spp_eth),
-				    (void**)txp,
-				    spp_eth,
-				    fp->nb_antennas_tx,
-				    0);
-        clock_gettime( CLOCK_MONOTONIC, &end_comp);
-        LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp));
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 0 );  
-        for (i=0; i < fp->nb_antennas_tx; i++)
-          txp[i] += spp_eth;
+        for (int aid=0; aid<ru->nb_tx;aid++) {
+          //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
+          //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 );
+          clock_gettime( CLOCK_MONOTONIC, &start_comp);
+          ru->ifdevice.trx_write_func2(&ru->ifdevice,
+	  			       (proc_timestamp + packet_id*spp_eth-500)*(30720/spsf),
+				       (void*)txp[aid],
+				       spp_eth,
+				       aid,
+				       0); 
+          LOG_D(HW,"SF %d : packet %d, TS %llu\n",subframe,packet_id,(unsigned long long)(proc_timestamp+packet_id*spp_eth));
+          clock_gettime( CLOCK_MONOTONIC, &end_comp);
+          LOG_D(HW,"[SF %d] IF_Write_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp));
+          //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 0 );  
+	  txp[aid] += spp_eth;
 
-      }
+        }
+     }
     }
   } else if (packet_type == IF5_RRH_GW_UL) {
     if (eth->compression == ALAW_COMPRESS) {
@@ -1131,8 +1136,8 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
         data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES);
       }
       for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) {
-        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 1 );
+        //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 1 );
         clock_gettime( CLOCK_MONOTONIC, &start_comp);
         for (i=0; i < fp->nb_antennas_rx; i++) {
           for (element_id=0; element_id< spp_eth; element_id++){
@@ -1142,8 +1147,8 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
         }
         clock_gettime( CLOCK_MONOTONIC, &end_comp);
         LOG_D(HW,"[SF %d] Compress_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_comp, end_comp));
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 0 );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_COMPR_IF, 0 );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_IF0, 1 );
         clock_gettime( CLOCK_MONOTONIC, &start_comp);
         ru->ifdevice.trx_write_func(&ru->ifdevice,
                                      (proc_timestamp + packet_id*spp_eth),
@@ -1310,9 +1315,9 @@ void send_IF5(RU_t *ru, openair0_timestamp proc_timestamp, int subframe, uint8_t
 void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16_t packet_type) {
 
   LTE_DL_FRAME_PARMS *fp=ru->frame_parms;
-  int32_t *txp[fp->nb_antennas_tx], *rxp[fp->nb_antennas_rx]; 
+  int32_t *txp[ru->nb_tx], *rxp[ru->nb_rx]; 
 
-  uint16_t packet_id=0, i=0, element_id=0;
+  uint16_t packet_id=0, i=0;
 #ifdef DEBUG_UL_MOBIPASS
   //int8_t dummy_buffer_rx[fp->samples_per_tti*2];
   uint8_t rxe;
@@ -1321,11 +1326,12 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
 
   int32_t spp_eth  = (int32_t) ru->ifdevice.openair0_cfg->samples_per_packet;
   int32_t spsf     = (int32_t) ru->ifdevice.openair0_cfg->samples_per_frame/10;
-  void    *alaw_buffer = ru->ifbuffer.rx; 
-  uint16_t *data_block = NULL;
-  uint16_t *j      = NULL;
 
-  openair0_timestamp timestamp[spsf / spp_eth];
+  openair0_timestamp timestamp[ru->nb_rx*spsf / spp_eth];
+  long timein[ru->nb_rx*spsf/spp_eth];
+  long timeout[ru->nb_rx*spsf/spp_eth];
+  struct timespec if_time;
+ 
   memset(timestamp, 0, sizeof(timestamp));
   eth_state_t *eth = (eth_state_t*) (ru->ifdevice.priv);
 
@@ -1333,6 +1339,9 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
   
   if (packet_type == IF5_RRH_GW_DL) {
     if (eth->compression == ALAW_COMPRESS) {
+     AssertFatal(1==0,"IF5 compression needs reworking\n");
+
+/*
       if (eth->flags == ETH_RAW_MODE) {
         data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES + MAC_HEADER_SIZE_BYTES);
       } else {
@@ -1364,13 +1373,14 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
         LOG_D(HW,"[SF %d] Decomperss_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
         VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_DECOMPR_IF, 0 );
       }
+*/
     } else if (eth->compression == NO_COMPRESS) {
       for (i=0; i < fp->nb_antennas_tx; i++)
         txp[i] = (void*)&ru->common.txdata[i][subframe*fp->samples_per_tti];
     
       for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) {
-        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RECV_IF5_PKT_ID, packet_id );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 1 );  
+        //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RECV_IF5_PKT_ID, packet_id );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 1 );  
         clock_gettime( CLOCK_MONOTONIC, &start_decomp);
         ru->ifdevice.trx_read_func(&ru->ifdevice,
 				   &timestamp[packet_id],
@@ -1379,7 +1389,7 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
 				   fp->nb_antennas_tx);
         clock_gettime( CLOCK_MONOTONIC, &end_decomp);
         LOG_D(HW,"[SF %d] IF_Read_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 0 );  
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 0 );  
         for (i=0; i < fp->nb_antennas_tx; i++)
           txp[i] += spp_eth;
 
@@ -1389,6 +1399,8 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
     
   } else if (packet_type == IF5_RRH_GW_UL) { 
     if (eth->compression == ALAW_COMPRESS) {
+     AssertFatal(1==0,"IF5 compression needs reworking\n");
+/*
       if (eth->flags == ETH_RAW_MODE) {
         data_block = (uint16_t*)(alaw_buffer + APP_HEADER_SIZE_BYTES + MAC_HEADER_SIZE_BYTES);
       } else {
@@ -1419,197 +1431,55 @@ void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16
         LOG_D(HW,"[SF %d] Decomperss_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
         VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_DECOMPR_IF, 0 );
       }
+*/
     } else if (eth->compression == NO_COMPRESS) {
-      for (i=0; i < fp->nb_antennas_rx; i++)
-        rxp[i] = (void*)&ru->common.rxdata[i][subframe*fp->samples_per_tti];
-    
-      for (packet_id=0; packet_id < spsf / spp_eth; packet_id++) {
-        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 1 );
-        clock_gettime( CLOCK_MONOTONIC, &start_decomp);
-        ru->ifdevice.trx_read_func(&ru->ifdevice,
+      int16_t temp_rx[spp_eth*2] __attribute__((aligned(32))); 
+      for (i=0; i < ru->nb_rx; i++)
+        rxp[i] = &ru->common.rxdata[i][subframe*fp->samples_per_tti];
+      int aid;
+      int firstTS=1;
+      openair0_timestamp oldTS=0;
+
+      for (packet_id=0; packet_id < ru->nb_rx*spsf / spp_eth; packet_id++) {
+        //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SEND_IF5_PKT_ID, packet_id );
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 1 );
+        clock_gettime( CLOCK_MONOTONIC, &if_time);
+        timein[packet_id] = if_time.tv_nsec;
+        ru->ifdevice.trx_read_func2(&ru->ifdevice,
 				   &timestamp[packet_id],
-				   (void**)rxp,
+				   (void*)temp_rx,
 				   spp_eth,
-				   fp->nb_antennas_rx);
-        clock_gettime( CLOCK_MONOTONIC, &end_decomp);
-        LOG_D(HW,"[SF %d] IF_Read_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
-        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 0 );            
-        for (i=0; i < fp->nb_antennas_rx; i++)
-          rxp[i] += spp_eth;
-
-      }
-    }
-    *proc_timestamp = timestamp[0];
-      
-  } else if (packet_type == IF5_MOBIPASS) {
-    if (ru->if_timing == synch_to_mobipass_standalone) {
-      uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
-      openair0_timestamp timestamp_mobipass[fp->samples_per_tti/db_fulllength];
-      int32_t *rx_buffer=NULL;
-      __m128i *data_block=NULL, *data_block_head=NULL;
-      __m128i *rxp128;
-      __m128i r0;
-
-      unsigned char _rx_buffer[MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t)];
-      rx_buffer = (int32_t *)_rx_buffer;
-      data_block_head = (__m128i *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
-
-      rxp[0] = (void*)&ru->common.rxdata[0][subframe*ru->frame_parms->samples_per_tti];
-      rxp128 = (__m128i *) (rxp[0]);
-
-      packet_id=0;
-      while(packet_id<fp->samples_per_tti/db_fulllength) {
-        data_block = data_block_head;
-
-        ru->ifdevice.trx_read_func(&ru->ifdevice,
-                                         &timestamp_mobipass[packet_id],
-                                         (void**)&rx_buffer,
-                                         db_fulllength,
-                                          1
-                                          );
-
-          //store rxdata and increase packet_id
-          rxp[0] = (void*)&ru->common.rxdata[0][(subframe*ru->frame_parms->samples_per_tti)+packet_id*db_fulllength];
-          rxp128 = (__m128i *) (rxp[0]);
-          for (i=0; i<db_fulllength>>2; i+=2) {
-            r0 = _mm_loadu_si128(data_block++);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
-          }
-          packet_id++;
-      }//end while
-
-      *proc_timestamp = ntohl(timestamp_mobipass[0]);
-    } else {
-      
-      uint16_t db_fulllength = PAYLOAD_MOBIPASS_NUM_SAMPLES;
-      openair0_timestamp timestamp_mobipass[fp->samples_per_tti/db_fulllength];
-#ifdef DEBUG_UL_MOBIPASS
-      int lower_offset = 0;
-      int  upper_offset = 70000;
-#endif
-      int subframe_skip = 0;
-      int reset_flag = 0;
-      int32_t *rx_buffer=NULL;
-      __m128i *data_block=NULL, *data_block_head=NULL;
-      __m128i *rxp128;
-      __m128i r0;
-
-      //rx_buffer = memalign(16, MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
-      rx_buffer = malloc(MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + db_fulllength*sizeof(int16_t));
-      IF5_mobipass_header_t *header = (IF5_mobipass_header_t *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES);
-      data_block_head = (__m128i *)((uint8_t *)rx_buffer + MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t);
-   
-      rxp[0] = (void*)&ru->common.rxdata[0][subframe*ru->frame_parms->samples_per_tti];
-      rxp128 = (__m128i *) (rxp[0]);
-   
-      RU_proc_t *proc = &ru->proc;
-/*
-   //   while(packet_id<fp->samples_per_tti/db_fulllength) {
-        data_block = data_block_head;
-
-        eNB->ifdevice.trx_read_func(&eNB->ifdevice,
-                                         &ts0,
-                                         (void**)&rx_buffer,
-                                         db_fulllength,
-                                          1
-                                          );
+				   &aid);
+        clock_gettime( CLOCK_MONOTONIC, &if_time);
+        timeout[packet_id] = if_time.tv_nsec;
+        timestamp[packet_id] /= (30720/spsf);
+        LOG_D(PHY,"subframe %d: Received packet %d: aid %d, TS %llu, oldTS %llu, diff %lld, \n",subframe,packet_id,aid,(unsigned long long)timestamp[packet_id],(unsigned long long)oldTS,(unsigned long long)(timestamp[packet_id]-timestamp[0]));
+        if (aid==0) {
+           if (firstTS==1) firstTS=0;
+           else if (oldTS + 256 != timestamp[packet_id]) {
+              LOG_I(PHY,"oldTS %llu, newTS %llu, diff %llu, timein %lu, timeout %lu\n",(long long unsigned int)oldTS,(long long unsigned int)timestamp[packet_id],(long long unsigned int)timestamp[packet_id]-oldTS,timein[packet_id],timeout[packet_id]); 
+              for (int i=0;i<=packet_id;i++) LOG_I(PHY,"packet %d TS %llu, timein %lu, timeout %lu\n",i,(long long unsigned int)timestamp[i],timein[i],timeout[i]);
+              AssertFatal(1==0,"fronthaul problem\n");
+           }
 
-        if ((header->seqno == 1)&&(first_packet==1))  { 
-           first_packet = 0;  //ignore the packets before synchnorization
-           packet_id = 0;
-          ts_offset = ntohl(ts0);
-        } 
-        if (first_packet==0) { 
-          packet_cnt++;
-          ts = ntohl(ts0);
-          packet_id = (ts-ts_offset)/db_fulllength;
-          packet_id = packet_id % (fp->samples_per_tti/db_fulllength);
-
-          printf("[IF5_tools]packet_id:%d\n", packet_id);
-          // if (ts_stored == 0) {
-          //   ts_stored = 1;
-          *proc_timestamp = ntohl(ts - (packet_id*db_fulllength));
-          // }
-          rxp[0] = (void*)&eNB->common_vars.rxdata[0][0][(subframe*eNB->frame_parms.samples_per_tti)+packet_id*db_fulllength];
-          rxp128 = (__m128i *) (rxp[0]);
-
-          for (i=0; i<db_fulllength>>2; i+=2) {
-            r0 = _mm_loadu_si128(data_block++);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
-          }
+           oldTS = timestamp[packet_id];
         }
-    //  }//end while
-*/
    
 
-      packet_id=0; 
-      while(packet_id<fp->samples_per_tti/db_fulllength) {
-        data_block = data_block_head;
-
-	
-	ru->ifdevice.trx_read_func(&ru->ifdevice,
-				 &timestamp_mobipass[packet_id],
-				 (void**)&rx_buffer,
-				 db_fulllength,
-				 1
-				 );
-#ifdef DEBUG_UL_MOBIPASS
-        if (((proc->timestamp_tx + lower_offset) > ntohl(timestamp_mobipass[packet_id])) || ((proc->timestamp_tx + upper_offset) < ntohl(timestamp_mobipass[packet_id]))) {
-          //ignore the packet
-          subframe_skip_extra = (subframe_skip_extra + 1)%67;         
-         LOG_D("[Mobipass] ignored packet, id:[%d,%d], proc->timestamp_tx:%llu, proc->timestamp_rx:%llu, seqno:%d\n", packet_id,subframe_skip_extra, proc->timestamp_tx, ntohl(timestamp_mobipass[packet_id]), header->seqno);
-        }             
-#endif
-        //skip SUBFRAME_SKIP_NUM_MOBIPASS additional UL packets
-        if ((start_flag == 1) && (subframe_skip < SUBFRAME_SKIP_NUM_MOBIPASS)){
-          subframe_skip++;
-          offset_cnt = header->seqno;
-        } else {
-          if ((offset_cnt != header->seqno) && (start_flag == 0) && (proc->first_rx > 3)){
-#ifdef DEBUG_UL_MOBIPASS
-             LOG_D(PHY,"[Mobipass] Reset sequence number, offset_cnt:%d, header->seqno:%d, packet_id:%d\n", offset_cnt, header->seqno, packet_id);
-#endif
-             reset_flag=1;
-          }
-          if ((reset_flag == 1) && (proc->first_rx > 3 ) && (start_flag == 0) && (packet_id == 0)) {
-             packet_id = 1;  
-             reset_flag = 0;
-          }
-          start_flag = 0;
-
-          //store rxdata and increase packet_id
-          rxp[0] = (void*)&ru->common.rxdata[0][(subframe*ru->frame_parms->samples_per_tti)+packet_id*db_fulllength];
-          rxp128 = (__m128i *) (rxp[0]);
-          for (i=0; i<db_fulllength>>2; i+=2) {
-            r0 = _mm_loadu_si128(data_block++);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpacklo_epi8(r0,r0),8),4);
-            *rxp128++ =_mm_slli_epi16(_mm_srai_epi16(_mm_unpackhi_epi8(r0,r0),8),4);
-          }   
-          packet_id++; 
-          offset_cnt = (header->seqno+1)&255;
-        }
-      }//end while
-    
-        *proc_timestamp = ntohl(timestamp_mobipass[0]); 
-#ifdef DEBUG_UL_MOBIPASS
-	LOG_I(PHY,"[Mobipass][Recv_MOBIPASS] timestamp: %llu\n ",  *proc_timestamp);
-	if (eNB->CC_id>0) {
-	  rxe = dB_fixed(signal_energy(rxp[0],fp->samples_per_tti)); 
-	  if (rxe > 0){
-	    LOG_I(PHY,"[Mobipass] frame:%d, subframe:%d, energy %d\n", (*proc_timestamp/(10*fp->samples_per_tti))&1023,subframe, rxe);
-	    
-	    //    LOG_M("rxsigmb.m","rxs",(void*)dummy_buffer_rx, fp->samples_per_tti,1, 5); 
-	    //    exit(-1);
-	  }
-	}
-#endif
-      free(rx_buffer);
+        // HYPOTHESIS: first packet per subframe has lowest timestamp of subframe
+        // should detect out of order and act accordingly ....
+        AssertFatal(aid==0 || aid==1,"aid %d != 0 or 1\n",aid);
+        //LOG_I(PHY,"rxp[%d] %p, dest %p, offset %d (%lld,%lld)\n",aid,rxp[aid],rxp[aid]+(timestamp[packet_id]-timestamp[0]),(timestamp[packet_id]-timestamp[0]),timestamp[packet_id],timestamp[0]);
+        memcpy((void*)(rxp[aid]+(timestamp[packet_id]-timestamp[0])),
+               (void*)temp_rx,
+               spp_eth<<2);
+        clock_gettime( CLOCK_MONOTONIC, &end_decomp);
+        LOG_D(HW,"[SF %d] IF_Read_Time: %"PRId64"\n",subframe,clock_difftime_ns(start_decomp, end_decomp));
+        //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_IF0, 0 );            
 
-     
+      }
     }
+    *proc_timestamp = timestamp[0];
   } else {
     AssertFatal(1==0, "recv_IF5 - Unknown packet_type %x", packet_type);     
   }  
diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c
index d3ed2ed4391b04a3272107817204edceaae54e5b..31e97741fdb22e36ee2189206357d75a067626b0 100644
--- a/openair1/PHY/LTE_TRANSPORT/prach.c
+++ b/openair1/PHY/LTE_TRANSPORT/prach.c
@@ -89,7 +89,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
   int32_t *prach_ifft=(int32_t *)NULL;
   int32_t **prach_ifftp=(int32_t **)NULL;
   int prach_ifft_cnt=0;
-
+  int exit_flag=0;
   LTE_DL_FRAME_PARMS *fp;
   int nb_rx;
   if(eNB)  {
@@ -177,32 +177,33 @@ void rx_prach0(PHY_VARS_eNB *eNB,
   }
 
   AssertFatal(ru!=NULL,"ru is null\n");
-
+  int8_t dBEn0=0;
   for (aa=0; aa<nb_rx; aa++) {
-    if (ru->if_south == LOCAL_RF) { // set the time-domain signal if we have to use it in this node
+    if (ru->if_south == LOCAL_RF || ru->function == NGFI_RAU_IF5) { // set the time-domain signal if we have to use it in this node
       // DJP - indexing below in subframe zero takes us off the beginning of the array???
       prach[aa] = (int16_t *)&ru->common.rxdata[aa][(subframe*fp->samples_per_tti)-ru->N_TA_offset];
 
       if (LOG_DUMPFLAG(PRACH)) {
         int32_t en0=signal_energy((int32_t *)prach[aa],fp->samples_per_tti);
-        int8_t dbEn0 = dB_fixed(en0);
-        int8_t rach_dBm = dbEn0 - ru->rx_total_gain_dB;
+        dBEn0 = dB_fixed(en0);
+        int8_t rach_dBm = dBEn0 - ru->rx_total_gain_dB;
         char buffer[80];
 
-        if (dbEn0>32 && prach[0]!= NULL) {
+        if (dBEn0>30 && prach[0]!= NULL) {
           static int counter=0;
-          sprintf(buffer, "%s%d", "/tmp/prach_rx",counter);
-          LOG_M(buffer,"prach_rx",prach[0],fp->samples_per_tti,1,13);
+          sprintf(buffer, "%s%d", "/tmp/prach_rx.m",counter);
+          LOG_M(buffer,"prach_rx",prach[0],fp->samples_per_tti,1,1);
+          exit_flag=1;
         }
 
-        if (dB_fixed(en0)>32) {
+        if (dBEn0>30) {
           sprintf(buffer, "rach_dBm:%d",rach_dBm);
 
-          if (prach[0]!= NULL) LOG_M("prach_rx","prach_rx",prach[0],fp->samples_per_tti,1,1);
+          if (prach[0]!= NULL) LOG_M("prach_rx.m","prach_rx",prach[0],fp->samples_per_tti,1,1);
 
           LOG_I(PHY,"RU %d, br_flag %d ce_level %d frame %d subframe %d per_tti:%d prach:%p (energy %d) TA:%d %s rxdata:%p index:%d\n",
                 ru->idx,br_flag,ce_level,frame_prach,subframe,fp->samples_per_tti,
-                prach[aa],dbEn0,ru->N_TA_offset,buffer,ru->common.rxdata[aa],
+                prach[aa],dBEn0,ru->N_TA_offset,buffer,ru->common.rxdata[aa],
                 (subframe*fp->samples_per_tti)-ru->N_TA_offset);
         }
       }
@@ -415,7 +416,7 @@ void rx_prach0(PHY_VARS_eNB *eNB,
     if ( LOG_DEBUGFLAG(PRACH)) {
       int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-      if ((en > 60)&&(br_flag==1)) LOG_I(PHY,"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",br_flag,ce_level,n_ra_prb,k,frame_prach,subframe,en);
+      if ((en > 10)&&(br_flag==1)) LOG_I(PHY,"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",br_flag,ce_level,n_ra_prb,k,frame_prach,subframe,en);
     }
   }
 
@@ -454,9 +455,9 @@ void rx_prach0(PHY_VARS_eNB *eNB,
 
   for (preamble_index=0 ; preamble_index<64 ; preamble_index++) {
     if (LOG_DEBUGFLAG(PRACH)) {
-      int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
+    //  int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-      if (en>60) LOG_I(PHY,"frame %d, subframe %d : Trying preamble %d (br_flag %d)\n",frame_prach,subframe,preamble_index,br_flag);
+      if (dBEn0>30) LOG_I(PHY,"frame %d, subframe %d : Trying preamble %d (br_flag %d)\n",frame_prach,subframe,preamble_index,br_flag);
     }
 
     if (restricted_set == 0) {
@@ -539,10 +540,10 @@ void rx_prach0(PHY_VARS_eNB *eNB,
 
     // Compute DFT of RX signal (conjugate input, results in conjugate output) for each new rootSequenceIndex
     if (LOG_DEBUGFLAG(PRACH)) {
-      int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
+      //en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-      if (en>60) LOG_I(PHY,"frame %d, subframe %d : preamble index %d: offset %d, preamble shift %d (br_flag %d, en %d)\n",
-                         frame_prach,subframe,preamble_index,preamble_offset,preamble_shift,br_flag,en);
+      if (dBEn0>30) LOG_I(PHY,"frame %d, subframe %d : preamble index %d: offset %d, preamble shift %d (br_flag %d, en %d)\n",
+                         frame_prach,subframe,preamble_index,preamble_offset,preamble_shift,br_flag,dBEn0);
     }
 
     log2_ifft_size = 10;
@@ -564,13 +565,13 @@ void rx_prach0(PHY_VARS_eNB *eNB,
 
       memset(prachF, 0, sizeof(int16_t)*2*1024 );
 
-      if (LOG_DUMPFLAG(PRACH)) {
+    if (LOG_DUMPFLAG(PRACH)) {
         if (prach[0]!= NULL) LOG_M("prach_rx0.m","prach_rx0",prach[0],6144+792,1,1);
 
         LOG_M("prach_rx1.m","prach_rx1",prach[1],6144+792,1,1);
         LOG_M("prach_rxF0.m","prach_rxF0",rxsigF[0],12288,1,1);
         LOG_M("prach_rxF1.m","prach_rxF1",rxsigF[1],12288,1,1);
-      }
+    }
 
       for (aa=0; aa<nb_rx; aa++) {
         // Do componentwise product with Xu* on each antenna
@@ -633,9 +634,9 @@ void rx_prach0(PHY_VARS_eNB *eNB,
           *max_preamble         = preamble_index;
 
           if (LOG_DEBUGFLAG(PRACH)) {
-            int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
+        //    int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-            if ((en>60) && (br_flag==1))
+            if (dBEn0>30)
               LOG_D(PHY,"frame %d, subframe %d : max_preamble_energy %d, max_preamble_delay %d, max_preamble %d (br_flag %d,ce_level %d, levdB %d, lev %d)\n",
                     frame_prach,subframe,
                     *max_preamble_energy,*max_preamble_delay,
@@ -648,10 +649,10 @@ void rx_prach0(PHY_VARS_eNB *eNB,
 
   *avg_preamble_energy=dB_fixed(avg_en/64);
 
-  if (LOG_DUMPFLAG(PRACH)) {
+  if (exit_flag==1) {
     int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840));
 
-    if (en>60) {
+    if (en>30) {
       k = (12*n_ra_prb) - 6*fp->N_RB_UL;
 
       if (k<0) k+=fp->ofdm_symbol_size;
@@ -665,19 +666,20 @@ void rx_prach0(PHY_VARS_eNB *eNB,
         LOG_M("prach_rxF_comp0.m","prach_rxF_comp0",prachF,1024,1,1);
         LOG_M("Xu.m","xu",Xu,N_ZC,1,1);
         LOG_M("prach_ifft0.m","prach_t0",prach_ifft,1024,1,1);
-        exit(-1);
+        LOG_M("SF2_3.m","sf2_3",&ru->common.rxdata[0][2*fp->samples_per_tti],2*fp->samples_per_tti,1,1);
       } else {
         LOG_E(PHY,"Dumping prach (br_flag %d), k = %d (n_ra_prb %d)\n",br_flag,k,n_ra_prb);
         LOG_M("rxsigF_br.m","prach_rxF_br",&rxsigF[0][0],12288,1,1);
         LOG_M("prach_rxF_comp0_br.m","prach_rxF_comp0_br",prachF,1024,1,1);
         LOG_M("Xu_br.m","xu_br",Xu,N_ZC,1,1);
         LOG_M("prach_ifft0_br.m","prach_t0_br",prach_ifft,1024,1,1);
-        exit(-1);
       }
     }
   } /* LOG_DUMPFLAG(PRACH) */
 
   if (eNB) stop_meas(&eNB->rx_prach);
+  AssertFatal(exit_flag==0,"exiting\n");
+
 }
 
 
diff --git a/openair1/PHY/MODULATION/ofdm_mod.c b/openair1/PHY/MODULATION/ofdm_mod.c
index 92aea419af0064e43a0083b208c1183c7008a4fc..2d86b46742449b308ee24c93de1225b5ebe19a66 100644
--- a/openair1/PHY/MODULATION/ofdm_mod.c
+++ b/openair1/PHY/MODULATION/ofdm_mod.c
@@ -90,9 +90,8 @@ void PHY_ofdm_mod(int *input,                       /// pointer to complex input
 
   if(nb_symbols == 0) return;
 
-  short temp[2*2*6144*4] __attribute__((aligned(32)));
-  unsigned short i,j;
-  short k;
+  int16_t temp[2*2*6144*4] __attribute__((aligned(32)));
+  int i,j;
 
   volatile int *output_ptr=(int*)0;
 
@@ -190,18 +189,9 @@ void PHY_ofdm_mod(int *input,                       /// pointer to complex input
       if (fftsize==128) 
 #endif
       {
-        /*for (j=0; j<fftsize ; j++) {
-          output_ptr[j] = temp_ptr[j];
-        }*/
-        memcpy1((void*)output_ptr,(void*)temp_ptr,fftsize<<2);
+        memcpy((void*)output_ptr,(void*)temp_ptr,fftsize<<2);
       }
-
-      j=fftsize;
-
-      for (k=-1; k>=-nb_prefix_samples; k--) {
-        output_ptr[k] = output_ptr[--j];
-      }
-
+      memcpy((void*)&output_ptr[-nb_prefix_samples],(void*)&output_ptr[fftsize-nb_prefix_samples],nb_prefix_samples<<2);
       break;
 
     case CYCLIC_SUFFIX:
diff --git a/openair1/PHY/NR_REFSIG/nr_gold_ue.c b/openair1/PHY/NR_REFSIG/nr_gold_ue.c
index 414582a31d800d26b342dbb222a4184ddd9cb278..09528d5dbd82cec7f01d1ab0f918fbec730e6672 100644
--- a/openair1/PHY/NR_REFSIG/nr_gold_ue.c
+++ b/openair1/PHY/NR_REFSIG/nr_gold_ue.c
@@ -107,9 +107,10 @@ void nr_gold_pdcch(PHY_VARS_NR_UE* ue,
 }
 
 void nr_gold_pdsch(PHY_VARS_NR_UE* ue,
+                   unsigned char ns,
                    unsigned short *n_idDMRS)
 {
-  unsigned char ns,l;
+  unsigned char l;
   unsigned int n,x1,x2,x2tmp0;
   int nscid;
   unsigned int nid;
@@ -122,40 +123,35 @@ void nr_gold_pdsch(PHY_VARS_NR_UE* ue,
       nid = n_idDMRS[nscid];
     else
       nid = ue->frame_parms.Nid_cell;
-      
-      //printf("gold pdsch nid %d lbar %d\n",nid,lbar);
-
-    for (ns=0; ns<20; ns++) {
 
-      for (l=0; l<14; l++) {
+    //printf("gold pdsch nid %d lbar %d\n",nid,lbar);
 
-        x2tmp0 = ((14*ns+l+1)*((nid<<1)+1))<<17;
-        x2 = (x2tmp0+(nid<<1)+nscid)%(1<<31);  //cinit
-        LOG_D(PHY,"UE DMRS slot %d, symb %d, x2 %x, nscid %d\n",ns,l,x2,nscid);
-        //printf("ns %d gold pdsch x2 %d\n",ns,x2);
+    for (l=0; l<14; l++) {
+      x2tmp0 = ((14*ns+l+1)*((nid<<1)+1))<<17;
+      x2 = (x2tmp0+(nid<<1)+nscid)%(1<<31);  //cinit
+      LOG_D(PHY,"UE DMRS slot %d, symb %d, x2 %x, nscid %d\n",ns,l,x2,nscid);
+      //printf("ns %d gold pdsch x2 %d\n",ns,x2);
 
-        x1 = 1+ (1<<31);
-        x2=x2 ^ ((x2 ^ (x2>>1) ^ (x2>>2) ^ (x2>>3))<<31);
-
-        // skip first 50 double words (1600 bits)
-        for (n=1; n<50; n++) {
-          x1 = (x1>>1) ^ (x1>>4);
-          x1 = x1 ^ (x1<<31) ^ (x1<<28);
-          x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4);
-          x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28);
-          //printf("x1 : %x, x2 : %x\n",x1,x2);
-        }
+      x1 = 1+ (1<<31);
+      x2=x2 ^ ((x2 ^ (x2>>1) ^ (x2>>2) ^ (x2>>3))<<31);
 
-        for (n=0; n<NR_MAX_PDSCH_DMRS_INIT_LENGTH_DWORD; n++) {
-          x1 = (x1>>1) ^ (x1>>4);
-          x1 = x1 ^ (x1<<31) ^ (x1<<28);
-          x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4);
-          x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28);
-          ue->nr_gold_pdsch[nscid][ns][l][n] = x1^x2;
-          // if ((ns==2)&&(l==0))
-          //printf("n=%d : c %x\n",n,x1^x2);
-        }
+      // skip first 50 double words (1600 bits)
+      for (n=1; n<50; n++) {
+        x1 = (x1>>1) ^ (x1>>4);
+        x1 = x1 ^ (x1<<31) ^ (x1<<28);
+        x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4);
+        x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28);
+        //printf("x1 : %x, x2 : %x\n",x1,x2);
+      }
 
+      for (n=0; n<NR_MAX_PDSCH_DMRS_INIT_LENGTH_DWORD; n++) {
+        x1 = (x1>>1) ^ (x1>>4);
+        x1 = x1 ^ (x1<<31) ^ (x1<<28);
+        x2 = (x2>>1) ^ (x2>>2) ^ (x2>>3) ^ (x2>>4);
+        x2 = x2 ^ (x2<<31) ^ (x2<<30) ^ (x2<<29) ^ (x2<<28);
+        ue->nr_gold_pdsch[nscid][ns][l][n] = x1^x2;
+        // if ((ns==2)&&(l==0))
+        //printf("n=%d : c %x\n",n,x1^x2);
       }
     }
   }
diff --git a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h
index f349cfcd9880ada8d7e63a6efc84a0154dc58850..83b43c54a0820bb087caa088a58172cfd8433685 100644
--- a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h
+++ b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h
@@ -61,6 +61,7 @@ void nr_gold_pdcch(PHY_VARS_NR_UE* ue,
                    unsigned short length_dmrs);
 
 void nr_gold_pdsch(PHY_VARS_NR_UE* ue,
+                   unsigned char ns,
                    unsigned short *n_idDMRS);
 
 void nr_init_pusch_dmrs(PHY_VARS_NR_UE* ue,
diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
index a528eb734ce53349bc77a15429817878e941b8a0..d990176d79d03847f5d729068cd0a917dbe2eb32 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
@@ -292,7 +292,7 @@ void nr_processULSegment(void* arg) {
   int no_iteration_ldpc;
   int Kr;
   int Kr_bytes;
-  int K_bytes_F;
+  int K_bits_F;
   uint8_t crc_type;
   int i;
   int j;
@@ -318,8 +318,7 @@ void nr_processULSegment(void* arg) {
 
   Kr = ulsch_harq->K;
   Kr_bytes = Kr>>3;
-
-  K_bytes_F = Kr_bytes-(ulsch_harq->F>>3);
+  K_bits_F = Kr-ulsch_harq->F;
 
   t_nrLDPC_time_stats procTime;
   t_nrLDPC_time_stats* p_procTime     = &procTime ;
@@ -402,23 +401,19 @@ void nr_processULSegment(void* arg) {
 
   //start_meas(&phy_vars_gNB->ulsch_ldpc_decoding_stats);
 
-  memset(pv,0,2*ulsch_harq->Z*sizeof(int16_t));
-  memset((pv+K_bytes_F),127,ulsch_harq->F*sizeof(int16_t));
-
-  for (i=((2*p_decoderParms->Z)>>3), j = 0; i < K_bytes_F; i++, j++) {
-    pv[i]= _mm_loadu_si128((__m128i*)(&ulsch_harq->d[r][8*j]));
-  }
-
-  AssertFatal(kc!=255,"");
-  j+=(ulsch_harq->F>>3);
-  for (i=Kr_bytes; i < ((kc*p_decoderParms->Z)>>3); i++, j++) {
-    pv[i]= _mm_loadu_si128((__m128i*)(&ulsch_harq->d[r][8*j]));
-  }
-
-  for (i=0, j=0; j < ((kc*p_decoderParms->Z)>>4);  i+=2, j++) {
+  //set first 2*Z_c bits to zeros
+  memset(&z[0],0,2*ulsch_harq->Z*sizeof(int16_t));
+  //set Filler bits
+  memset((&z[0]+K_bits_F),127,ulsch_harq->F*sizeof(int16_t));
+  //Move coded bits before filler bits
+  memcpy((&z[0]+2*ulsch_harq->Z),ulsch_harq->d[r],(K_bits_F-2*ulsch_harq->Z)*sizeof(int16_t));
+  //skip filler bits
+  memcpy((&z[0]+Kr),ulsch_harq->d[r]+(Kr-2*ulsch_harq->Z),(kc*ulsch_harq->Z-Kr)*sizeof(int16_t));
+  //Saturate coded bits before decoding into 8 bits values
+  for (i=0, j=0; j < ((kc*ulsch_harq->Z)>>4)+1;  i+=2, j++)
+  {
     pl[j] = _mm_packs_epi16(pv[i],pv[i+1]);
   }
-
   //////////////////////////////////////////////////////////////////////////////////////////
 
 
@@ -523,31 +518,27 @@ uint32_t nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
   
   if ((A <=292) || ((A<=3824) && (Coderate <= 0.6667)) || Coderate <= 0.25){
     p_decParams->BG = 2;
+    kc = 52;
     if (Coderate < 0.3333) {
       p_decParams->R = 15;
-      kc = 52;
     }
     else if (Coderate <0.6667) {
       p_decParams->R = 13;
-      kc = 32;
     }
     else {
       p_decParams->R = 23;
-      kc = 17;
     }
   } else {
     p_decParams->BG = 1;
+    kc = 68;
     if (Coderate < 0.6667) {
       p_decParams->R = 13;
-      kc = 68;
     }
     else if (Coderate <0.8889) {
       p_decParams->R = 23;
-      kc = 35;
     }
     else {
       p_decParams->R = 89;
-      kc = 27;
     }
   }
   
diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_gain.c b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_gain.c
index 161408254f796d63e7f41fc968cdf14a6ec7eb5d..4a884b964b016a77833bf154d7668c9b46c46af5 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_gain.c
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_gain.c
@@ -27,7 +27,7 @@ void
 phy_adjust_gain_nr (PHY_VARS_NR_UE *ue, uint32_t rx_power_fil_dB, uint8_t eNB_id)
 {
 
-  LOG_I(PHY,"Gain control: rssi %d (%d,%d)\n",
+  LOG_D(PHY,"Gain control: rssi %d (%d,%d)\n",
 	rx_power_fil_dB,
 	ue->measurements.rssi,
 	ue->measurements.rx_power_avg_dB[eNB_id]
@@ -61,7 +61,7 @@ phy_adjust_gain_nr (PHY_VARS_NR_UE *ue, uint32_t rx_power_fil_dB, uint8_t eNB_id
     ue->rx_total_gain_dB = MIN_RF_GAIN;
   }
 
-  LOG_I(PHY,"Gain control: rx_total_gain_dB = %d TARGET_RX_POWER %d (max %d,rxpf %d)\n",ue->rx_total_gain_dB,TARGET_RX_POWER,MAX_RF_GAIN,rx_power_fil_dB);
+  LOG_D(PHY,"Gain control: rx_total_gain_dB = %d TARGET_RX_POWER %d (max %d,rxpf %d)\n",ue->rx_total_gain_dB,TARGET_RX_POWER,MAX_RF_GAIN,rx_power_fil_dB);
 
 #ifdef DEBUG_PHY
   /*  if ((ue->frame%100==0) || (ue->frame < 10))
diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c
index 143871e2be09839394e1be128ae0055880df67be..4b36180b58f73fd42a7b38c56b52ba54fd877857 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_synch_ue.c
@@ -33,12 +33,12 @@
 // last channel estimate of the receiver
 
 void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
-                      PHY_VARS_NR_UE *ue,
-                      module_id_t gNB_id,
-                      uint8_t frame,
-                      uint8_t subframe,
-                      unsigned char clear,
-                      short coef)
+                        PHY_VARS_NR_UE *ue,
+                        module_id_t gNB_id,
+                        uint8_t frame,
+                        uint8_t subframe,
+                        unsigned char clear,
+                        short coef)
 {
 
   static int max_pos_fil = 0;
@@ -47,6 +47,7 @@ void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
   int temp = 0, i, aa, max_val = 0, max_pos = 0;
   int diff;
   short Re,Im,ncoef;
+  uint8_t sync_offset = 0;
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_IN);
 
@@ -80,11 +81,14 @@ void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
   // do not filter to have proactive timing adjustment
   //max_pos_fil = max_pos;
 
-  if(subframe == 0)
-  {
       diff = max_pos_fil - (frame_parms->nb_prefix_samples>>3);
 
-      if ( abs(diff) < SYNCH_HYST )
+      if (frame_parms->freq_range==nr_FR2) 
+		sync_offset = 2;
+      else
+		sync_offset = 0;
+	
+      if ( abs(diff) < (SYNCH_HYST+sync_offset) )
           ue->rx_offset = 0;
       else
           ue->rx_offset = diff;
@@ -134,5 +138,5 @@ void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
       #endif //DEBUG_PHY
 
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_OUT);
-  }
+
 }
diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h
index 419f84d4180ce3a35b9d657d5182a6e96e36c070..b295c74099a5914f4865d3fa225716ad256ac842 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h
@@ -86,17 +86,17 @@ void nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
                       
 void nr_ue_measurements(PHY_VARS_NR_UE *ue,
                         UE_nr_rxtx_proc_t *proc,
-                        unsigned int subframe_offset,
-                        unsigned char N0_symbol,
-                        unsigned char abstraction_flag,
-                        unsigned char rank_adaptation,
-                        uint8_t subframe);
+                        uint8_t slot);
 
 void nr_ue_rsrp_measurements(PHY_VARS_NR_UE *ue,
                              UE_nr_rxtx_proc_t *proc,
                              uint8_t slot,
                              uint8_t abstraction_flag);
 
+void nr_ue_rrc_measurements(PHY_VARS_NR_UE *ue,
+                            UE_nr_rxtx_proc_t *proc,
+                            uint8_t slot);
+
 void phy_adjust_gain_nr(PHY_VARS_NR_UE *ue,
                         uint32_t rx_power_fil_dB,
                         uint8_t eNB_id);
diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c
index 4757872c28922cdb190c19aeff69e3c2070f25b9..eebce03d834a279b4c8f0bf0c976104f030398cd 100644
--- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c
+++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c
@@ -19,6 +19,18 @@
  *      contact@openairinterface.org
  */
 
+/*! \file nr_ue_measurements.c
+ * \brief UE measurements routines
+ * \author  R. Knopp, G. Casati
+ * \date 2020
+ * \version 0.1
+ * \company Eurecom, Fraunhofer IIS
+ * \email: knopp@eurecom.fr, guido.casati@iis.fraunhofer.de
+ * \note
+ * \warning
+ */
+
+#include "nr-softmodem-common.h"
 #include "PHY/defs_nr_UE.h"
 #include "PHY/phy_extern_nr_ue.h"
 #include "common/utils/LOG/log.h"
@@ -33,29 +45,6 @@
 //#define DEBUG_MEAS_UE
 //#define DEBUG_RANK_EST
 
-#if 0
-int16_t cond_num_threshold = 0;
-
-void print_shorts(char *s,short *x)
-{
-
-
-  printf("%s  : %d,%d,%d,%d,%d,%d,%d,%d\n",s,
-         x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7]
-        );
-
-}
-void print_ints(char *s,int *x)
-{
-
-
-  printf("%s  : %d,%d,%d,%d\n",s,
-         x[0],x[1],x[2],x[3]
-        );
-
-}
-#endif
-
 int16_t get_nr_PL(uint8_t Mod_id, uint8_t CC_id, uint8_t gNB_index){
 
   PHY_VARS_NR_UE *ue = PHY_vars_UE_g[Mod_id][CC_id];
@@ -105,117 +94,84 @@ float_t get_nr_RSRP(module_id_t Mod_id,uint8_t CC_id,uint8_t gNB_index)
   return -140.0;
 }
 
-
 void nr_ue_measurements(PHY_VARS_NR_UE *ue,
                         UE_nr_rxtx_proc_t *proc,
-                        unsigned int subframe_offset,
-                        unsigned char N0_symbol,
-                        unsigned char abstraction_flag,
-                        unsigned char rank_adaptation,
-                        uint8_t subframe)
+                        uint8_t slot)
 {
-  int aarx,aatx,eNB_id=0; //,gain_offset=0;
-  //int rx_power[NUMBER_OF_CONNECTED_eNB_MAX];
-
-/*#if defined(__x86_64__) || defined(__i386__)
-  __m128i *dl_ch0_128, *dl_ch1_128;
-#elif defined(__arm__)
-  int16x8_t *dl_ch0_128, *dl_ch1_128get_PL;
-#endif*/
-
+  int aarx, aatx, gNB_id = 0;
   NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
-  //unsigned int limit, subband;
-  //int nb_subbands, subband_size, last_subband_size, *dl_ch0, *dl_ch1, N_RB_DL = frame_parms->N_RB_DL;
-
-  int ch_offset, rank_tm3_tm4 = 0;
+  int ch_offset = frame_parms->ofdm_symbol_size*2;
+  NR_UE_DLSCH_t *dlsch = ue->dlsch[proc->thread_id][gNB_id][0];
+  uint8_t harq_pid = dlsch->current_harq_pid;
+  int N_RB_DL = dlsch->harq_processes[harq_pid]->nb_rb;
 
   ue->measurements.nb_antennas_rx = frame_parms->nb_antennas_rx;
-  
-  /*int16_t *dl_ch;
-  dl_ch = (int16_t *)&ue->pdsch_vars[proc->thread_id][0]->dl_ch_estimates[eNB_id][ch_offset];*/
-
-  ch_offset = ue->frame_parms.ofdm_symbol_size*2;
 
-//printf("testing measurements\n");
   // signal measurements
+  for (gNB_id = 0; gNB_id < ue->n_connected_eNB; gNB_id++){
+
+    ue->measurements.rx_power_tot[gNB_id] = 0;
 
-  for (eNB_id=0; eNB_id<ue->n_connected_eNB; eNB_id++) {
-    for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
-      for (aatx=0; aatx<frame_parms->nb_antenna_ports_gNB; aatx++) {
-        ue->measurements.rx_spatial_power[eNB_id][aatx][aarx] =
-          (signal_energy_nodc(&ue->pdsch_vars[proc->thread_id][0]->dl_ch_estimates[eNB_id][ch_offset],
-                              (50*12)));
-        //- ue->measurements.n0_power[aarx];
+    for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++){
 
-        if (ue->measurements.rx_spatial_power[eNB_id][aatx][aarx]<0)
-          ue->measurements.rx_spatial_power[eNB_id][aatx][aarx] = 0; //ue->measurements.n0_power[aarx];
+      ue->measurements.rx_power[gNB_id][aarx] = 0;
 
-        ue->measurements.rx_spatial_power_dB[eNB_id][aatx][aarx] = (unsigned short) dB_fixed(ue->measurements.rx_spatial_power[eNB_id][aatx][aarx]);
+      for (aatx = 0; aatx < frame_parms->nb_antenna_ports_gNB; aatx++){
 
-        if (aatx==0)
-          ue->measurements.rx_power[eNB_id][aarx] = ue->measurements.rx_spatial_power[eNB_id][aatx][aarx];
-        else
-          ue->measurements.rx_power[eNB_id][aarx] += ue->measurements.rx_spatial_power[eNB_id][aatx][aarx];
-      } //aatx
+        ue->measurements.rx_spatial_power[gNB_id][aatx][aarx] = (signal_energy_nodc(&ue->pdsch_vars[proc->thread_id][0]->dl_ch_estimates[gNB_id][ch_offset], N_RB_DL*NR_NB_SC_PER_RB));
 
-      ue->measurements.rx_power_dB[eNB_id][aarx] = (unsigned short) dB_fixed(ue->measurements.rx_power[eNB_id][aarx]);
+        if (ue->measurements.rx_spatial_power[gNB_id][aatx][aarx]<0)
+          ue->measurements.rx_spatial_power[gNB_id][aatx][aarx] = 0;
 
-      if (aarx==0)
-        ue->measurements.rx_power_tot[eNB_id] = ue->measurements.rx_power[eNB_id][aarx];
-      else
-        ue->measurements.rx_power_tot[eNB_id] += ue->measurements.rx_power[eNB_id][aarx];
-    } //aarx
+        ue->measurements.rx_spatial_power_dB[gNB_id][aatx][aarx] = (unsigned short) dB_fixed(ue->measurements.rx_spatial_power[gNB_id][aatx][aarx]);
+        ue->measurements.rx_power[gNB_id][aarx] += ue->measurements.rx_spatial_power[gNB_id][aatx][aarx];
 
-    ue->measurements.rx_power_tot_dB[eNB_id] = (unsigned short) dB_fixed(ue->measurements.rx_power_tot[eNB_id]);
+      }
 
-  } //eNB_id
-  
-  //printf("ue measurement addr dlch %p\n", dl_ch);
+      ue->measurements.rx_power_dB[gNB_id][aarx] = (unsigned short) dB_fixed(ue->measurements.rx_power[gNB_id][aarx]);
+      ue->measurements.rx_power_tot[gNB_id] += ue->measurements.rx_power[gNB_id][aarx];
 
-  eNB_id=0;
+    }
 
-  if (ue->transmission_mode[eNB_id]!=4 && ue->transmission_mode[eNB_id]!=3)
-    ue->measurements.rank[eNB_id] = 0;
-  else
-    ue->measurements.rank[eNB_id] = rank_tm3_tm4;
-  //  printf ("tx mode %d\n", ue->transmission_mode[eNB_id]);
-  //  printf ("rank %d\n", ue->PHY_measurements.rank[eNB_id]);
+    ue->measurements.rx_power_tot_dB[gNB_id] = (unsigned short) dB_fixed(ue->measurements.rx_power_tot[gNB_id]);
+
+  }
 
   // filter to remove jitter
   if (ue->init_averaging == 0) {
-    for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++)
-      ue->measurements.rx_power_avg[eNB_id] = (int)
-          (((k1*((long long int)(ue->measurements.rx_power_avg[eNB_id]))) +
-            (k2*((long long int)(ue->measurements.rx_power_tot[eNB_id]))))>>10);
-
-    //LOG_I(PHY,"Noise Power Computation: k1 %d k2 %d n0 avg %d n0 tot %d\n", k1, k2, ue->measurements.n0_power_avg,
-     //   ue->measurements.n0_power_tot);
-    ue->measurements.n0_power_avg = (int)
-        (((k1*((long long int) (ue->measurements.n0_power_avg))) +
-          (k2*((long long int) (ue->measurements.n0_power_tot))))>>10);
+
+    for (gNB_id = 0; gNB_id < ue->n_connected_eNB; gNB_id++)
+      ue->measurements.rx_power_avg[gNB_id] = (int)(((k1*((long long int)(ue->measurements.rx_power_avg[gNB_id]))) + (k2*((long long int)(ue->measurements.rx_power_tot[gNB_id])))) >> 10);
+
+    ue->measurements.n0_power_avg = (int)(((k1*((long long int) (ue->measurements.n0_power_avg))) + (k2*((long long int) (ue->measurements.n0_power_tot))))>>10);
+
+    LOG_D(PHY, "Noise Power Computation: k1 %lld k2 %lld n0 avg %u n0 tot %u\n", k1, k2, ue->measurements.n0_power_avg, ue->measurements.n0_power_tot);
+
   } else {
-    for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++)
-      ue->measurements.rx_power_avg[eNB_id] = ue->measurements.rx_power_tot[eNB_id];
+
+    for (gNB_id = 0; gNB_id < ue->n_connected_eNB; gNB_id++)
+      ue->measurements.rx_power_avg[gNB_id] = ue->measurements.rx_power_tot[gNB_id];
 
     ue->measurements.n0_power_avg = ue->measurements.n0_power_tot;
     ue->init_averaging = 0;
+
   }
 
-  for (eNB_id = 0; eNB_id < ue->n_connected_eNB; eNB_id++) {
-    ue->measurements.rx_power_avg_dB[eNB_id] = dB_fixed( ue->measurements.rx_power_avg[eNB_id]);
-    ue->measurements.wideband_cqi_tot[eNB_id] = dB_fixed2(ue->measurements.rx_power_tot[eNB_id],ue->measurements.n0_power_tot);
-    ue->measurements.wideband_cqi_avg[eNB_id] = dB_fixed2(ue->measurements.rx_power_avg[eNB_id],ue->measurements.n0_power_avg);
-    ue->measurements.rx_rssi_dBm[eNB_id] = ue->measurements.rx_power_avg_dB[eNB_id] - ue->rx_total_gain_dB;
-//#ifdef DEBUG_MEAS_UE
-      LOG_D(PHY,"[eNB %d] Subframe %d, RSSI %d dBm, RSSI (digital) %d dB, WBandCQI %d dB, rxPwrAvg %d, n0PwrAvg %d\n",
-            eNB_id,
-            subframe,
-            ue->measurements.rx_rssi_dBm[eNB_id],
-            ue->measurements.rx_power_avg_dB[eNB_id],
-            ue->measurements.wideband_cqi_avg[eNB_id],
-            ue->measurements.rx_power_avg[eNB_id],
-            ue->measurements.n0_power_tot);
-//#endif
+  for (gNB_id = 0; gNB_id < ue->n_connected_eNB; gNB_id++) {
+
+    ue->measurements.rx_power_avg_dB[gNB_id] = dB_fixed( ue->measurements.rx_power_avg[gNB_id]);
+    ue->measurements.wideband_cqi_tot[gNB_id] = dB_fixed2(ue->measurements.rx_power_tot[gNB_id], ue->measurements.n0_power_tot);
+    ue->measurements.wideband_cqi_avg[gNB_id] = dB_fixed2(ue->measurements.rx_power_avg[gNB_id], ue->measurements.n0_power_avg);
+    ue->measurements.rx_rssi_dBm[gNB_id] = ue->measurements.rx_power_avg_dB[gNB_id] - ue->rx_total_gain_dB;
+
+    LOG_D(PHY, "[gNB %d] Slot %d, RSSI %d dBm, RSSI (digital) %d dB, WBandCQI %d dB, rxPwrAvg %d, n0PwrAvg %d\n",
+      gNB_id,
+      slot,
+      ue->measurements.rx_rssi_dBm[gNB_id],
+      ue->measurements.rx_power_avg_dB[gNB_id],
+      ue->measurements.wideband_cqi_avg[gNB_id],
+      ue->measurements.rx_power_avg[gNB_id],
+      ue->measurements.n0_power_tot);
   }
 
 #if defined(__x86_64__) || defined(__i386__)
@@ -243,7 +199,7 @@ void nr_ue_rsrp_measurements(PHY_VARS_NR_UE *ue,
 	unsigned int  ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier;
 	if (ssb_offset>= ue->frame_parms.ofdm_symbol_size) ssb_offset-=ue->frame_parms.ofdm_symbol_size;
 	
-	symbol_offset = ue->frame_parms.ofdm_symbol_size*(ue->symbol_offset+1);
+	symbol_offset = ue->frame_parms.ofdm_symbol_size*((ue->symbol_offset+1)%(ue->frame_parms.symbols_per_slot));
 
     ue->measurements.rsrp[eNB_offset] = 0;
 
@@ -286,7 +242,7 @@ void nr_ue_rsrp_measurements(PHY_VARS_NR_UE *ue,
 
       if (eNB_offset == 0)
 
-      LOG_I(PHY,"[UE %d] slot %d RRC Measurements (idx %d, Cell id %d) => rsrp: %3.1f dBm/RE (%d)\n",
+      LOG_D(PHY,"[UE %d] slot %d RSRP Measurements (idx %d, Cell id %d) => rsrp: %3.1f dBm/RE (%d)\n",
             ue->Mod_id,
             slot,eNB_offset,
             (eNB_offset>0) ? ue->measurements.adj_cell_id[eNB_offset-1] : ue->frame_parms.Nid_cell,
@@ -294,3 +250,66 @@ void nr_ue_rsrp_measurements(PHY_VARS_NR_UE *ue,
             ue->measurements.rsrp[eNB_offset]);
 
 }
+
+void nr_ue_rrc_measurements(PHY_VARS_NR_UE *ue,
+                            UE_nr_rxtx_proc_t *proc,
+                            uint8_t slot){
+
+  uint8_t k;
+  int aarx, nb_nulls;
+  int16_t *rxF_sss;
+  uint8_t k_left = 48;
+  uint8_t k_right = 183;
+  uint8_t k_length = 8;
+  uint8_t l_sss = ue->symbol_offset + 2;
+  unsigned int ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier;
+  ue->measurements.n0_power_tot = 0;
+
+  LOG_D(PHY, "In %s doing measurements for ssb_offset %d l_sss %d \n", __FUNCTION__, ssb_offset, l_sss);
+
+  for (aarx = 0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
+
+    nb_nulls = 0;
+    ue->measurements.n0_power[aarx] = 0;
+    rxF_sss = (int16_t *)&ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF[aarx][(l_sss*ue->frame_parms.ofdm_symbol_size) + ssb_offset];
+
+    //-ve spectrum from SSS
+    for(k = k_left; k < k_left + k_length; k++){
+
+      #ifdef DEBUG_MEAS_RRC
+      LOG_I(PHY, "In %s -rxF_sss %d %d\n", __FUNCTION__, rxF_sss[k*2], rxF_sss[k*2 + 1]);
+      #endif
+
+      ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[k*2]*rxF_sss[k*2]) + ((int32_t)rxF_sss[k*2 + 1]*rxF_sss[k*2 + 1]));
+      nb_nulls++;
+
+    }
+
+    //+ve spectrum from SSS
+    for(k = k_right; k < k_right + k_length; k++){
+
+      #ifdef DEBUG_MEAS_RRC
+      LOG_I(PHY, "In %s +rxF_sss %d %d\n", __FUNCTION__, rxF_sss[k*2], rxF_sss[k*2 + 1]);
+      #endif
+
+      ue->measurements.n0_power[aarx] += (((int32_t)rxF_sss[k*2]*rxF_sss[k*2]) + ((int32_t)rxF_sss[k*2 + 1]*rxF_sss[k*2 + 1]));
+      nb_nulls++;
+
+    }
+
+    ue->measurements.n0_power[aarx] /= nb_nulls;
+    ue->measurements.n0_power_dB[aarx] = (unsigned short) dB_fixed(ue->measurements.n0_power[aarx]);
+    ue->measurements.n0_power_tot += ue->measurements.n0_power[aarx];
+
+  }
+
+  ue->measurements.n0_power_tot_dB = (unsigned short) dB_fixed(ue->measurements.n0_power_tot/aarx);
+
+  #ifdef DEBUG_MEAS_RRC
+  int nf_usrp = ue->measurements.n0_power_tot_dB + 30 - ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) - 90 - (-174 + dB_fixed(30000/*scs*/) + dB_fixed(ue->frame_parms.ofdm_symbol_size));
+  LOG_D(PHY, "In %s slot %d NF USRP %d dBm\n", __FUNCTION__, nf_usrp);
+  #endif
+
+  LOG_D(PHY, "In %s slot %d Noise Level %d ue->measurements.n0_power_tot_dB %d \n", __FUNCTION__, slot, ue->measurements.n0_power_tot, ue->measurements.n0_power_tot_dB);
+
+}
diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
index 9bfc11d64a35ade377b30e2ba972887df56a1219..169942825d2979c637f8a3c96246a07c1056bd1d 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
@@ -154,9 +154,11 @@ void nr_pdcch_demapping_deinterleaving(uint32_t *llr,
 
     for (int i=0; i<9; i++) {
       z[index_z + i] = llr[index_llr + i];
+#ifdef NR_PDCCH_DCI_DEBUG
       LOG_D(PHY,"[reg=%d,bundle_j=%d] z[%d]=(%d,%d) <-> \t[f_reg=%d,fbundle_j=%d] llr[%d]=(%d,%d) \n",
              reg,bundle_j,(index_z + i),*(int16_t *) &z[index_z + i],*(1 + (int16_t *) &z[index_z + i]),
              f_reg,f_bundle_j,(index_llr + i),*(int16_t *) &llr[index_llr + i], *(1 + (int16_t *) &llr[index_llr + i]));
+#endif
     }
 
     if ((reg%reg_bundle_size_L) == 0) r++;
@@ -373,7 +375,10 @@ void nr_pdcch_extract_rbs_single(int32_t **rxdataF,
     for (int rb=0;rb<coreset_nbr_rb;rb++,c_rb++) {
       c_rb_by6 = c_rb/6;
       // skip zeros in frequency domain bitmap
-      while ((coreset_freq_dom[c_rb_by6>>3] & (1<<(c_rb_by6&7))) == 0) c_rb+=6;
+      while ((coreset_freq_dom[c_rb_by6>>3] & (1<<(7-(c_rb_by6&7)))) == 0) {
+	  c_rb+=6;
+	  c_rb_by6 = c_rb/6;
+	}
 
       LOG_DDD("c_rb=%d\n",c_rb);
       rxF=NULL;
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
index 75cb6ff91b1cf2f0c700cb29304cbfc2d5545194..808b21b40a5a9c4b85a64faee3b58f59af714cce 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
@@ -241,7 +241,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
   uint32_t G;
   uint32_t ret,offset;
   int32_t no_iteration_ldpc, length_dec;
-  uint32_t r,r_offset=0,Kr=8424,Kr_bytes,K_bytes_F,err_flag=0;
+  uint32_t r,r_offset=0,Kr=8424,Kr_bytes,K_bits_F,err_flag=0;
   uint8_t crc_type;
   int8_t llrProcBuf[NR_LDPC_MAX_NUM_LLR] __attribute__ ((aligned(32)));
   t_nrLDPC_dec_params decParams;
@@ -349,32 +349,28 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
   if ((A <=292) || ((A<=3824) && (Coderate <= 0.6667)) || Coderate <= 0.25)
   {
     p_decParams->BG = 2;
+    kc = 52;
     if (Coderate < 0.3333){
       p_decParams->R = 15;
-      kc = 52;
     }
     else if (Coderate <0.6667){
       p_decParams->R = 13;
-      kc = 32;
     }
     else {
       p_decParams->R = 23;
-      kc = 17;
     }
   }
   else{
     p_decParams->BG = 1;
+    kc = 68;
     if (Coderate < 0.6667){
       p_decParams->R = 13;
-      kc = 68;
     }
     else if (Coderate <0.8889){
       p_decParams->R = 23;
-      kc = 35;
     }
     else {
       p_decParams->R = 89;
-      kc = 27;
     }
   }
 
@@ -434,8 +430,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
 
   Kr = harq_process->K; // [hna] overwrites this line "Kr = p_decParams->Z*kb"
   Kr_bytes = Kr>>3;
-
-  K_bytes_F = Kr_bytes-(harq_process->F>>3);
+  K_bits_F = Kr-harq_process->F;
 
   for (r=0; r<harq_process->C; r++) {
 
@@ -558,24 +553,16 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
 
       //printf("harq process dr iteration %d\n", p_decParams->numMaxIter);
 
-      memset(pv,0,2*harq_process->Z*sizeof(int16_t));
-      //memset(pl,0,2*p_decParams->Z*sizeof(int8_t));
-      memset((pv+K_bytes_F),127,harq_process->F*sizeof(int16_t));
-
-
-      for (i=((2*p_decParams->Z)>>3), j = 0; i < K_bytes_F; i++, j++)
-      {
-        pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j]));
-      }
-      // Kbytes_F = Kr_bytes - F>>3
-      j+=(harq_process->F>>3);
-      //      for (i=Kr_bytes,j=K_bytes_F-((2*p_decParams->Z)>>3); i < ((kc*p_decParams->Z)>>3); i++, j++)
-      for (i=Kr_bytes; i < ((kc*p_decParams->Z)>>3); i++,j++)
-      {
-        pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j]));
-      }
-
-      for (i=0, j=0; j < ((kc*p_decParams->Z)>>4);  i+=2, j++)
+      //set first 2*Z_c bits to zeros
+      memset(&z[0],0,2*harq_process->Z*sizeof(int16_t));
+      //set Filler bits
+      memset((&z[0]+K_bits_F),127,harq_process->F*sizeof(int16_t));
+      //Move coded bits before filler bits
+      memcpy((&z[0]+2*harq_process->Z),harq_process->d[r],(K_bits_F-2*harq_process->Z)*sizeof(int16_t));
+      //skip filler bits
+      memcpy((&z[0]+Kr),harq_process->d[r]+(Kr-2*harq_process->Z),(kc*harq_process->Z-Kr)*sizeof(int16_t));
+      //Saturate coded bits before decoding into 8 bits values
+      for (i=0, j=0; j < ((kc*harq_process->Z)>>4)+1;  i+=2, j++)
       {
         pl[j] = _mm_packs_epi16(pv[i],pv[i+1]);
       }
@@ -776,7 +763,7 @@ uint32_t  nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue,
   uint32_t A,E;
   uint32_t G;
   uint32_t ret,offset;
-  uint32_t r,r_offset=0,Kr=8424,Kr_bytes,err_flag=0,K_bytes_F;
+  uint32_t r,r_offset=0,Kr=8424,Kr_bytes,err_flag=0,K_bits_F;
   uint8_t crc_type;
   //UE_rxtx_proc_t *proc = &phy_vars_ue->proc;
   int32_t no_iteration_ldpc,length_dec;
@@ -895,32 +882,28 @@ uint32_t  nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue,
   if ((A <=292) || ((A<=3824) && (Coderate <= 0.6667)) || Coderate <= 0.25)
   {
     p_decParams->BG = 2;
+    kc = 52;
     if (Coderate < 0.3333){
       p_decParams->R = 15;
-      kc = 52;
     }
     else if (Coderate <0.6667){
       p_decParams->R = 13;
-      kc = 32;
     }
     else {
       p_decParams->R = 23;
-      kc = 17;
     }
   }
   else{
     p_decParams->BG = 1;
+    kc = 68;
     if (Coderate < 0.6667){
       p_decParams->R = 13;
-      kc = 68;
     }
     else if (Coderate <0.8889){
       p_decParams->R = 23;
-      kc = 35;
     }
     else {
       p_decParams->R = 89;
-      kc = 27;
     }
   }
 
@@ -1020,7 +1003,7 @@ uint32_t  nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue,
 
     Kr = harq_process->K;
     Kr_bytes = Kr>>3;
-    K_bytes_F = Kr_bytes-(harq_process->F>>3);
+    K_bits_F = Kr-harq_process->F;
 
     E = nr_get_E(G, harq_process->C, harq_process->Qm, harq_process->Nl, r);
 
@@ -1152,24 +1135,16 @@ uint32_t  nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue,
         inv_d[cnt] = (1)*harq_process->d[r][cnt];
       }*/
 
-      memset(pv,0,2*p_decParams->Z*sizeof(int16_t));
-      //memset(pl,0,2*p_decParams->Z*sizeof(int8_t));
-      memset((pv+K_bytes_F),127,harq_process->F*sizeof(int16_t));
-
-
-      for (i=((2*p_decParams->Z)>>3), j = 0; i < K_bytes_F; i++, j++)
-      {
-        pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j]));
-      }
-
-      j+=(harq_process->F>>3);
-      //      for (i=Kr_bytes,j=K_bytes_F-((2*p_decParams->Z)>>3); i < ((kc*p_decParams->Z)>>3); i++, j++)
-      for (i=Kr_bytes; i < ((kc*p_decParams->Z)>>3); i++,j++)
-      {
-        pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j]));
-      }
-      
-      for (i=0, j=0; j < ((kc*p_decParams->Z)>>4);  i+=2, j++)
+      //set first 2*Z_c bits to zeros
+      memset(&z[0],0,2*harq_process->Z*sizeof(int16_t));
+      //set Filler bits
+      memset((&z[0]+K_bits_F),127,harq_process->F*sizeof(int16_t));
+      //Move coded bits before filler bits
+      memcpy((&z[0]+2*harq_process->Z),harq_process->d[r],(K_bits_F-2*harq_process->Z)*sizeof(int16_t));
+      //skip filler bits
+      memcpy((&z[0]+Kr),harq_process->d[r]+(Kr-2*harq_process->Z),(kc*harq_process->Z-Kr)*sizeof(int16_t));
+      //Saturate coded bits before decoding into 8 bits values
+      for (i=0, j=0; j < ((kc*harq_process->Z)>>4)+1;  i+=2, j++)
       {
         pl[j] = _mm_packs_epi16(pv[i],pv[i+1]);
       }
@@ -1395,7 +1370,7 @@ void nr_dlsch_decoding_process(void *arg)
   uint32_t A,E;
   uint32_t G;
   uint32_t ret,offset;
-  uint32_t r,r_offset=0,Kr,Kr_bytes,err_flag=0,K_bytes_F;
+  uint32_t r,r_offset=0,Kr,Kr_bytes,err_flag=0,K_bits_F;
   uint8_t crc_type;
   uint8_t C,Cprime;
   uint8_t Qm;
@@ -1457,32 +1432,28 @@ void nr_dlsch_decoding_process(void *arg)
   if ((A <=292) || ((A<=3824) && (Coderate <= 0.6667)) || Coderate <= 0.25)
   {
     p_decParams->BG = 2;
+    kc = 52;
     if (Coderate < 0.3333){
       p_decParams->R = 15;
-      kc = 52;
     }
     else if (Coderate <0.6667){
       p_decParams->R = 13;
-      kc = 32;
     }
     else {
       p_decParams->R = 23;
-      kc = 17;
     }
   }
   else{
     p_decParams->BG = 1;
+    kc = 68;
     if (Coderate < 0.6667){
       p_decParams->R = 13;
-      kc = 68;
     }
     else if (Coderate <0.8889){
       p_decParams->R = 23;
-      kc = 35;
     }
     else {
       p_decParams->R = 89;
-      kc = 27;
     }
   }    
 
@@ -1561,7 +1532,7 @@ void nr_dlsch_decoding_process(void *arg)
 
   Kr = harq_process->K;
   Kr_bytes = Kr>>3;
-  K_bytes_F = Kr_bytes-(harq_process->F>>3);
+  K_bits_F = Kr-harq_process->F;
 
   E = nr_get_E(G, harq_process->C, harq_process->Qm, harq_process->Nl, r);
 
@@ -1681,23 +1652,16 @@ void nr_dlsch_decoding_process(void *arg)
               }
 */
 
-        memset(pv,0,2*p_decParams->Z*sizeof(int16_t));
-        //memset(pl,0,2*p_decParams->Z*sizeof(int8_t));
-        memset((pv+K_bytes_F),127,harq_process->F*sizeof(int16_t));
-
-        for (i=((2*p_decParams->Z)>>3), j = 0; i < K_bytes_F; i++, j++)
-        {
-          pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j]));
-        }
-
-        j+=(harq_process->F>>3);
-        //      for (i=Kr_bytes,j=K_bytes_F-((2*p_decParams->Z)>>3); i < ((kc*p_decParams->Z)>>3); i++, j++)
-        for (i=Kr_bytes; i < ((kc*p_decParams->Z)>>3); i++,j++)
-        {
-         pv[i]= _mm_loadu_si128((__m128i*)(&harq_process->d[r][8*j]));
-        }
-
-        for (i=0, j=0; j < ((kc*p_decParams->Z)>>4);  i+=2, j++)
+        //set first 2*Z_c bits to zeros
+        memset(&z[0],0,2*harq_process->Z*sizeof(int16_t));
+        //set Filler bits
+        memset((&z[0]+K_bits_F),127,harq_process->F*sizeof(int16_t));
+        //Move coded bits before filler bits
+        memcpy((&z[0]+2*harq_process->Z),harq_process->d[r],(K_bits_F-2*harq_process->Z)*sizeof(int16_t));
+        //skip filler bits
+        memcpy((&z[0]+Kr),harq_process->d[r]+(Kr-2*harq_process->Z),(kc*harq_process->Z-Kr)*sizeof(int16_t));
+        //Saturate coded bits before decoding into 8 bits values
+        for (i=0, j=0; j < ((kc*harq_process->Z)>>4)+1;  i+=2, j++)
         {
           pl[j] = _mm_packs_epi16(pv[i],pv[i+1]);
         }
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
index 81349f202cc58b7a76f5ee42549dcba3c221c133..8e6fed864cfca8e91af1d62e8ce0dd83aa69714e 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
@@ -546,6 +546,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
                                pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                pdsch_vars[eNB_id]->dl_ch_mag0,
                                pdsch_vars[eNB_id]->dl_ch_magb0,
+                               pdsch_vars[eNB_id]->dl_ch_magr0,
                                pdsch_vars[eNB_id]->rxdataF_comp0,
                                (aatx>1) ? pdsch_vars[eNB_id]->rho : NULL,
                                frame_parms,
@@ -860,6 +861,7 @@ void nr_dlsch_channel_compensation(int **rxdataF_ext,
                                 int **dl_ch_estimates_ext,
                                 int **dl_ch_mag,
                                 int **dl_ch_magb,
+                                int **dl_ch_magr,
                                 int **rxdataF_comp,
                                 int **rho,
                                 NR_DL_FRAME_PARMS *frame_parms,
@@ -876,17 +878,23 @@ void nr_dlsch_channel_compensation(int **rxdataF_ext,
 
   unsigned short rb;
   unsigned char aatx,aarx;
-  __m128i *dl_ch128,*dl_ch128_2,*dl_ch_mag128,*dl_ch_mag128b,*rxdataF128,*rxdataF_comp128,*rho128;
-  __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3,QAM_amp128,QAM_amp128b;
+  __m128i *dl_ch128,*dl_ch128_2,*dl_ch_mag128,*dl_ch_mag128b,*dl_ch_mag128r,*rxdataF128,*rxdataF_comp128,*rho128;
+  __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3,QAM_amp128,QAM_amp128b,QAM_amp128r;
   QAM_amp128b = _mm_setzero_si128();
 
   for (aatx=0; aatx<frame_parms->nb_antenna_ports_gNB; aatx++) {
     if (mod_order == 4) {
       QAM_amp128 = _mm_set1_epi16(QAM16_n1);  // 2/sqrt(10)
       QAM_amp128b = _mm_setzero_si128();
+      QAM_amp128r = _mm_setzero_si128();
     } else if (mod_order == 6) {
       QAM_amp128  = _mm_set1_epi16(QAM64_n1); //
       QAM_amp128b = _mm_set1_epi16(QAM64_n2);
+      QAM_amp128r = _mm_setzero_si128();
+    } else if (mod_order == 8) {
+      QAM_amp128 = _mm_set1_epi16(QAM256_n1);
+      QAM_amp128b = _mm_set1_epi16(QAM256_n2);
+      QAM_amp128r = _mm_set1_epi16(QAM256_n3);
     }
 
     //    printf("comp: rxdataF_comp %p, symbol %d\n",rxdataF_comp[0],symbol);
@@ -896,6 +904,7 @@ void nr_dlsch_channel_compensation(int **rxdataF_ext,
       dl_ch128          = (__m128i *)&dl_ch_estimates_ext[(aatx<<1)+aarx][symbol*nb_rb*12];
       dl_ch_mag128      = (__m128i *)&dl_ch_mag[(aatx<<1)+aarx][symbol*nb_rb*12];
       dl_ch_mag128b     = (__m128i *)&dl_ch_magb[(aatx<<1)+aarx][symbol*nb_rb*12];
+      dl_ch_mag128r     = (__m128i *)&dl_ch_magr[(aatx<<1)+aarx][symbol*nb_rb*12];
       rxdataF128        = (__m128i *)&rxdataF_ext[aarx][symbol*nb_rb*12];
       rxdataF_comp128   = (__m128i *)&rxdataF_comp[(aatx<<1)+aarx][symbol*nb_rb*12];
 
@@ -916,6 +925,7 @@ void nr_dlsch_channel_compensation(int **rxdataF_ext,
 
           dl_ch_mag128[0] = _mm_unpacklo_epi16(mmtmpD0,mmtmpD0);
           dl_ch_mag128b[0] = dl_ch_mag128[0];
+          dl_ch_mag128r[0] = dl_ch_mag128[0];
           dl_ch_mag128[0] = _mm_mulhi_epi16(dl_ch_mag128[0],QAM_amp128);
           dl_ch_mag128[0] = _mm_slli_epi16(dl_ch_mag128[0],1);
     //print_ints("Re(ch):",(int16_t*)&mmtmpD0);
@@ -923,6 +933,7 @@ void nr_dlsch_channel_compensation(int **rxdataF_ext,
     //print_shorts("mag:",(int16_t*)&dl_ch_mag128[0]);
           dl_ch_mag128[1] = _mm_unpackhi_epi16(mmtmpD0,mmtmpD0);
           dl_ch_mag128b[1] = dl_ch_mag128[1];
+          dl_ch_mag128r[1] = dl_ch_mag128[1];
           dl_ch_mag128[1] = _mm_mulhi_epi16(dl_ch_mag128[1],QAM_amp128);
           dl_ch_mag128[1] = _mm_slli_epi16(dl_ch_mag128[1],1);
 
@@ -933,6 +944,7 @@ void nr_dlsch_channel_compensation(int **rxdataF_ext,
 
             dl_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpD1,mmtmpD1);
             dl_ch_mag128b[2] = dl_ch_mag128[2];
+            dl_ch_mag128r[2] = dl_ch_mag128[2];
 
             dl_ch_mag128[2] = _mm_mulhi_epi16(dl_ch_mag128[2],QAM_amp128);
             dl_ch_mag128[2] = _mm_slli_epi16(dl_ch_mag128[2],1);
@@ -945,9 +957,18 @@ void nr_dlsch_channel_compensation(int **rxdataF_ext,
           dl_ch_mag128b[1] = _mm_mulhi_epi16(dl_ch_mag128b[1],QAM_amp128b);
           dl_ch_mag128b[1] = _mm_slli_epi16(dl_ch_mag128b[1],1);
 
+          dl_ch_mag128r[0] = _mm_mulhi_epi16(dl_ch_mag128r[0],QAM_amp128r);
+          dl_ch_mag128r[0] = _mm_slli_epi16(dl_ch_mag128r[0],1);
+
+          dl_ch_mag128r[1] = _mm_mulhi_epi16(dl_ch_mag128r[1],QAM_amp128r);
+          dl_ch_mag128r[1] = _mm_slli_epi16(dl_ch_mag128r[1],1);
+
           if (pilots==0) {
             dl_ch_mag128b[2] = _mm_mulhi_epi16(dl_ch_mag128b[2],QAM_amp128b);
             dl_ch_mag128b[2] = _mm_slli_epi16(dl_ch_mag128b[2],1);
+
+            dl_ch_mag128r[2] = _mm_mulhi_epi16(dl_ch_mag128r[2],QAM_amp128r);
+            dl_ch_mag128r[2] = _mm_slli_epi16(dl_ch_mag128r[2],1);
           }
         }
 
@@ -1015,12 +1036,14 @@ void nr_dlsch_channel_compensation(int **rxdataF_ext,
           dl_ch128+=3;
           dl_ch_mag128+=3;
           dl_ch_mag128b+=3;
+          dl_ch_mag128r+=3;
           rxdataF128+=3;
           rxdataF_comp128+=3;
         } else { // we have a smaller PDSCH in symbols with pilots so skip last group of 4 REs and increment less
           dl_ch128+=2;
           dl_ch_mag128+=2;
           dl_ch_mag128b+=2;
+          dl_ch_mag128r+=2;
           rxdataF128+=2;
           rxdataF_comp128+=2;
         }
@@ -2620,6 +2643,29 @@ static int nr_dlsch_llr(NR_UE_PDSCH **pdsch_vars,
       }
     }
     break;
+  case 8:
+    if ((rx_type==rx_standard) || (codeword_TB1 == -1))  {
+      nr_dlsch_256qam_llr(frame_parms,
+                      pdsch_vars[eNB_id]->rxdataF_comp0,
+                      (int16_t*)pllr_symbol_cw0,
+                      pdsch_vars[eNB_id]->dl_ch_mag0,
+                      pdsch_vars[eNB_id]->dl_ch_magb0,
+                      pdsch_vars[eNB_id]->dl_ch_magr0,
+                      symbol,len,first_symbol_flag,nb_rb,
+                      pdsch_vars[eNB_id]->llr_offset[symbol],
+                      beamforming_mode);
+    } else if (codeword_TB0 == -1){
+      nr_dlsch_256qam_llr(frame_parms,
+                      pdsch_vars[eNB_id]->rxdataF_comp0,
+                      pllr_symbol_cw1,
+                      pdsch_vars[eNB_id]->dl_ch_mag0,
+                      pdsch_vars[eNB_id]->dl_ch_magb0,
+                      pdsch_vars[eNB_id]->dl_ch_magr0,
+                      symbol,len,first_symbol_flag,nb_rb,
+                      pdsch_vars[eNB_id]->llr_offset[symbol],
+                      beamforming_mode);
+    }
+    break;
   default:
     LOG_W(PHY,"rx_dlsch.c : Unknown mod_order!!!!\n");
     return(-1);
@@ -2660,6 +2706,19 @@ static int nr_dlsch_llr(NR_UE_PDSCH **pdsch_vars,
                              beamforming_mode);
         }
         break;
+    case 8 :
+      if (rx_type==rx_standard) {
+        nr_dlsch_256qam_llr(frame_parms,
+                            pdsch_vars[eNB_id]->rxdataF_comp0,
+                            pllr_symbol_cw0,
+                            pdsch_vars[eNB_id]->dl_ch_mag0,
+                            pdsch_vars[eNB_id]->dl_ch_magb0,
+                            pdsch_vars[eNB_id]->dl_ch_magr0,
+                            symbol,len,first_symbol_flag,nb_rb,
+                            pdsch_vars[eNB_id]->llr_offset[symbol],
+                            beamforming_mode);
+      }
+        break;
       default:
         LOG_W(PHY,"rx_dlsch.c : Unknown mod_order!!!!\n");
         return(-1);
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c
index e0b24a033a1c8cbef832bb186d7b97ae324c4f9b..68a206e7c746ec709312e4cb29bee5e7824ff4c3 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c
@@ -1089,6 +1089,108 @@ void nr_dlsch_64qam_llr_SIC(NR_DL_FRAME_PARMS *frame_parms,
   }
 }
 //#endif
+
+//----------------------------------------------------------------------------------------------
+// 256-QAM
+//----------------------------------------------------------------------------------------------
+
+void nr_dlsch_256qam_llr(NR_DL_FRAME_PARMS *frame_parms,
+                     int32_t **rxdataF_comp,
+                     int16_t *dlsch_llr,
+                     int32_t **dl_ch_mag,
+                     int32_t **dl_ch_magb,
+                     int32_t **dl_ch_magr,
+                     uint8_t symbol,
+                     uint32_t len,
+                     uint8_t first_symbol_flag,
+                     uint16_t nb_rb,
+                     uint32_t llr_offset,
+                     uint8_t beamforming_mode)
+{
+  __m128i *rxF = (__m128i*)&rxdataF_comp[0][(symbol*nb_rb*12)];
+  __m128i *ch_mag,*ch_magb,*ch_magr;
+
+  int i,len2;
+  unsigned char len_mod4;
+  short *llr;
+  int16_t *llr2;
+  int8_t *pllr_symbol;
+
+  /*
+  if (first_symbol_flag==1)
+    llr = dlsch_llr;
+  else
+    llr = *llr_save;
+  */
+  llr = dlsch_llr;
+
+  pllr_symbol = (int8_t*)dlsch_llr;
+  pllr_symbol += llr_offset;
+
+  ch_mag = (__m128i*)&dl_ch_mag[0][(symbol*nb_rb*12)];
+  ch_magb = (__m128i*)&dl_ch_magb[0][(symbol*nb_rb*12)];
+  ch_magr = (__m128i*)&dl_ch_magr[0][(symbol*nb_rb*12)];
+  llr2 = llr;
+  llr += (len*8);
+
+  len_mod4 =len&3;
+  len2=len>>2;  // length in quad words (4 REs)
+  len2+=((len_mod4==0)?0:1);
+
+  for (i=0; i<len2; i++) {
+    xmm1 = _mm_abs_epi16(rxF[i]);
+    xmm1 = _mm_subs_epi16(ch_mag[i],xmm1);
+    xmm2 = _mm_abs_epi16(xmm1);
+    xmm2 = _mm_subs_epi16(ch_magb[i],xmm2);
+    xmm3 = _mm_abs_epi16(xmm2);
+    xmm3 = _mm_subs_epi16(ch_magr[i], xmm3);
+
+    llr2[0] = ((short *)&rxF[i])[0];
+    llr2[1] = ((short *)&rxF[i])[1];
+    llr2[2] = _mm_extract_epi16(xmm1,0);
+    llr2[3] = _mm_extract_epi16(xmm1,1);//((short *)&xmm1)[j+1];
+    llr2[4] = _mm_extract_epi16(xmm2,0);//((short *)&xmm2)[j];
+    llr2[5] = _mm_extract_epi16(xmm2,1);//((short *)&xmm2)[j+1];
+    llr2[6] = _mm_extract_epi16(xmm3,0);
+    llr2[7] = _mm_extract_epi16(xmm3,1);
+
+    llr2+=8;
+    llr2[0] = ((short *)&rxF[i])[2];
+    llr2[1] = ((short *)&rxF[i])[3];
+    llr2[2] = _mm_extract_epi16(xmm1,2);
+    llr2[3] = _mm_extract_epi16(xmm1,3);//((short *)&xmm1)[j+1];
+    llr2[4] = _mm_extract_epi16(xmm2,2);//((short *)&xmm2)[j];
+    llr2[5] = _mm_extract_epi16(xmm2,3);//((short *)&xmm2)[j+1];
+    llr2[6] = _mm_extract_epi16(xmm3,2);
+    llr2[7] = _mm_extract_epi16(xmm3,3);
+
+    llr2+=8;
+    llr2[0] = ((short *)&rxF[i])[4];
+    llr2[1] = ((short *)&rxF[i])[5];
+    llr2[2] = _mm_extract_epi16(xmm1,4);
+    llr2[3] = _mm_extract_epi16(xmm1,5);//((short *)&xmm1)[j+1];
+    llr2[4] = _mm_extract_epi16(xmm2,4);//((short *)&xmm2)[j];
+    llr2[5] = _mm_extract_epi16(xmm2,5);//((short *)&xmm2)[j+1];
+    llr2[6] = _mm_extract_epi16(xmm3,4);
+    llr2[7] = _mm_extract_epi16(xmm3,5);
+
+    llr2+=8;
+    llr2[0] = ((short *)&rxF[i])[6];
+    llr2[1] = ((short *)&rxF[i])[7];
+    llr2[2] = _mm_extract_epi16(xmm1,6);
+    llr2[3] = _mm_extract_epi16(xmm1,7);//((short *)&xmm1)[j+1];
+    llr2[4] = _mm_extract_epi16(xmm2,6);//((short *)&xmm2)[j];
+    llr2[5] = _mm_extract_epi16(xmm2,7);//((short *)&xmm2)[j+1];
+    llr2[6] = _mm_extract_epi16(xmm3,6);
+    llr2[7] = _mm_extract_epi16(xmm3,7);
+    llr2+=8;
+
+  }
+
+  _mm_empty();
+  _m_empty();
+}
+
 //==============================================================================================
 // DUAL-STREAM
 //==============================================================================================
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
index 460dcfadb07648a7a6a946f29f9a7a730a54ea3b..b5ab563c2695b51fe4ba1c35ca79487c3f005ee2 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
@@ -304,8 +304,11 @@ int nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, runmode_t mode,
       if (ret == 0) {
         // sync at symbol ue->symbol_offset
         // computing the offset wrt the beginning of the frame
-        sync_pos_frame = (fp->ofdm_symbol_size + fp->nb_prefix_samples0)+((ue->symbol_offset)-1)*(fp->ofdm_symbol_size + fp->nb_prefix_samples);
-
+        int mu = fp->numerology_index;
+        // number of symbols with different prefix length
+        // every 7*(1<<mu) symbols there is a different prefix length (38.211 5.3.1)
+        int n_symb_prefix0 = (ue->symbol_offset/(7*(1<<mu)))+1;
+        sync_pos_frame = n_symb_prefix0*(fp->ofdm_symbol_size + fp->nb_prefix_samples0)+(ue->symbol_offset-n_symb_prefix0)*(fp->ofdm_symbol_size + fp->nb_prefix_samples);
         if (ue->ssb_offset < sync_pos_frame)
           ue->rx_offset = fp->samples_per_frame - sync_pos_frame + ue->ssb_offset;
         else
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
index 813e737563ad2dd9358744dbeb35d19f0fb386af..4d21fe782bce86371c899ebf9090c18b8571fff9 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
@@ -62,7 +62,7 @@ uint16_t nr_pbch_extract(int **rxdataF,
   unsigned int  rx_offset = frame_parms->first_carrier_offset + frame_parms->ssb_start_subcarrier; //and
 
  // if (rx_offset>= frame_parms->ofdm_symbol_size) rx_offset-=frame_parms->ofdm_symbol_size;
-          rx_offset=(rx_offset)%(frame_parms->ofdm_symbol_size);
+ rx_offset=(rx_offset)%(frame_parms->ofdm_symbol_size);
 
   AssertFatal(symbol>=1 && symbol<5,
               "symbol %d illegal for PBCH extraction\n",
@@ -538,6 +538,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
   M =  NR_POLAR_PBCH_E;
   nushift = (Lmax==4)? i_ssb&3 : i_ssb&7;
   uint32_t unscrambling_mask = (Lmax==64)?0x100006D:0x1000041;
+
   nr_pbch_unscrambling(nr_ue_pbch_vars,frame_parms->Nid_cell,nushift,M,NR_POLAR_PBCH_E,0,0);
   //polar decoding de-rate matching
   const t_nrPolar_params *currentPtr = nr_polar_params( NR_POLAR_PBCH_MESSAGE_TYPE, NR_POLAR_PBCH_PAYLOAD_BITS, NR_POLAR_PBCH_AGGREGATION_LEVEL,1,&ue->polarList);
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
index c74d887101b8d57a4d46b025fd19c3a8e0972a4f..6648197153605845805c9292506a19d198baaddb 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
@@ -564,6 +564,18 @@ void nr_dlsch_64qam_llr(NR_DL_FRAME_PARMS *frame_parms,
                      uint32_t llr_offset,
                      uint8_t beamforming_mode);
 
+void nr_dlsch_256qam_llr(NR_DL_FRAME_PARMS *frame_parms,
+                     int32_t **rxdataF_comp,
+                     int16_t *dlsch_llr,
+                     int32_t **dl_ch_mag,
+                     int32_t **dl_ch_magb,
+                     int32_t **dl_ch_magr,
+                     uint8_t symbol,
+                     uint32_t len,
+                     uint8_t first_symbol_flag,
+                     uint16_t nb_rb,
+                     uint32_t llr_offset,
+                     uint8_t beamforming_mode);
 
 /** \fn dlsch_siso(NR_DL_FRAME_PARMS *frame_parms,
     int32_t **rxdataF_comp,
@@ -798,6 +810,7 @@ void nr_dlsch_channel_compensation(int32_t **rxdataF_ext,
                                 int32_t **dl_ch_estimates_ext,
                                 int32_t **dl_ch_mag,
                                 int32_t **dl_ch_magb,
+                                int32_t **dl_ch_magr,
                                 int32_t **rxdataF_comp,
                                 int32_t **rho,
                                 NR_DL_FRAME_PARMS *frame_parms,
diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h
index 557b8bfc30e0108105f79f7d3328ee6bf2b05bc7..f1021ead9b2ab9fb2bc36a4e59e051e492aec26a 100644
--- a/openair1/PHY/defs_eNB.h
+++ b/openair1/PHY/defs_eNB.h
@@ -389,6 +389,8 @@ typedef struct {
   short n0_subband_power_tot_dB[100];
   //! estimated avg noise power per RB (dBm)
   short n0_subband_power_tot_dBm[100];
+  //! etimated avg noise power over all RB (dB)
+  short n0_subband_power_avg_dB;
   // eNB measurements (per user)
   //! estimated received spatial signal power (linear)
   unsigned int   rx_spatial_power[NUMBER_OF_UE_MAX][2][2];
diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h
index cf5f74856ec6c29968b853d318f76c2b7954b8d6..7b33b2040fe33a503e90c60736d834d39d7a7cd8 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -626,32 +626,33 @@ typedef struct {
   short n0_subband_power_tot_dB[275];
   //! estimated avg noise power per RB (dBm)
   short n0_subband_power_tot_dBm[275];
+
   // gNB measurements (per user)
   //! estimated received spatial signal power (linear)
-  unsigned int   rx_spatial_power[NUMBER_OF_NR_DLSCH_MAX][2][2];
+  unsigned int   rx_spatial_power[NUMBER_OF_NR_ULSCH_MAX][NB_ANTENNAS_TX][NB_ANTENNAS_RX];
   //! estimated received spatial signal power (dB)
-  unsigned short rx_spatial_power_dB[NUMBER_OF_NR_DLSCH_MAX][2][2];
+  unsigned short rx_spatial_power_dB[NUMBER_OF_NR_ULSCH_MAX][NB_ANTENNAS_TX][NB_ANTENNAS_RX];
   //! estimated rssi (dBm)
-  short          rx_rssi_dBm[NUMBER_OF_NR_DLSCH_MAX];
+  short          rx_rssi_dBm[NUMBER_OF_NR_ULSCH_MAX];
   //! estimated correlation (wideband linear) between spatial channels (computed in dlsch_demodulation)
-  int            rx_correlation[NUMBER_OF_NR_DLSCH_MAX][2];
+  int            rx_correlation[NUMBER_OF_NR_ULSCH_MAX][2];
   //! estimated correlation (wideband dB) between spatial channels (computed in dlsch_demodulation)
-  int            rx_correlation_dB[NUMBER_OF_NR_DLSCH_MAX][2];
+  int            rx_correlation_dB[NUMBER_OF_NR_ULSCH_MAX][2];
 
   /// Wideband CQI (= SINR)
-  int            wideband_cqi[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB];
+  int            wideband_cqi[NUMBER_OF_NR_ULSCH_MAX][MAX_NUM_RU_PER_gNB];
   /// Wideband CQI in dB (= SINR dB)
-  int            wideband_cqi_dB[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB];
+  int            wideband_cqi_dB[NUMBER_OF_NR_ULSCH_MAX][MAX_NUM_RU_PER_gNB];
   /// Wideband CQI (sum of all RX antennas, in dB)
-  char           wideband_cqi_tot[NUMBER_OF_NR_DLSCH_MAX];
+  char           wideband_cqi_tot[NUMBER_OF_NR_ULSCH_MAX];
   /// Subband CQI per RX antenna and RB (= SINR)
-  int            subband_cqi[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][275];
+  int            subband_cqi[NUMBER_OF_NR_ULSCH_MAX][MAX_NUM_RU_PER_gNB][275];
   /// Total Subband CQI and RB (= SINR)
-  int            subband_cqi_tot[NUMBER_OF_NR_DLSCH_MAX][275];
+  int            subband_cqi_tot[NUMBER_OF_NR_ULSCH_MAX][275];
   /// Subband CQI in dB and RB (= SINR dB)
-  int            subband_cqi_dB[NUMBER_OF_NR_DLSCH_MAX][MAX_NUM_RU_PER_gNB][275];
+  int            subband_cqi_dB[NUMBER_OF_NR_ULSCH_MAX][MAX_NUM_RU_PER_gNB][275];
   /// Total Subband CQI and RB
-  int            subband_cqi_tot_dB[NUMBER_OF_NR_DLSCH_MAX][275];
+  int            subband_cqi_tot_dB[NUMBER_OF_NR_ULSCH_MAX][275];
   /// PRACH background noise level
   int            prach_I0;
 } PHY_MEASUREMENTS_gNB;
diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h
index 4a685bfeb9014b3b8dda4567060731daefa49b58..ce10d2d6b1a4aff2271f1c89df694e7ceb4c0839 100644
--- a/openair1/PHY/defs_nr_UE.h
+++ b/openair1/PHY/defs_nr_UE.h
@@ -212,10 +212,8 @@ typedef struct {
   unsigned short rx_spatial_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][2][2];
 
   /// estimated received signal power (sum over all TX antennas)
-  //int            wideband_cqi[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX];
   int            rx_power[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX];
   /// estimated received signal power (sum over all TX antennas)
-  //int            wideband_cqi_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX];
   unsigned short rx_power_dB[NUMBER_OF_CONNECTED_eNB_MAX][NB_ANTENNAS_RX];
 
   /// estimated received signal power (sum over all TX/RX antennas)
@@ -379,6 +377,8 @@ typedef struct {
   /// - first index: ? [0..7] (hard coded) FIXME! accessed via \c nb_antennas_rx
   /// - second index: ? [0..168*N_RB_DL[
   int32_t **dl_ch_magb1[8][8];
+  /// \brief Magnitude of Downlink Channel, first layer (256QAM level).
+  int32_t **dl_ch_magr0;
   /// \brief Cross-correlation of two eNB signals.
   /// - first index: rx antenna [0..nb_antennas_rx[
   /// - second index: symbol [0..]
diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h
index e5678f894d7c0faa7399af59770a0fb71df45bc6..89c6a2d9c845b2068523fa746493d7c10a8a9f91 100644
--- a/openair1/PHY/defs_nr_common.h
+++ b/openair1/PHY/defs_nr_common.h
@@ -228,7 +228,7 @@ typedef struct {
   /// Pointer to Msg3 payload for UL-grant
   uint8_t *Msg3;
   /// Frame of last completed synch
-  uint8_t sync_frame;
+  uint16_t sync_frame;
   /// Flag to indicate that prach is ready to start: it is enabled with an initial delay after the sync
   uint8_t init_msg1;
 } NR_PRACH_RESOURCES_t;
diff --git a/openair1/PHY/impl_defs_top.h b/openair1/PHY/impl_defs_top.h
index 6c3d97838d7b9337021b801143c0462de235462a..a8548af8dc983f1f5cc2490efa953a40dc7d0dc5 100644
--- a/openair1/PHY/impl_defs_top.h
+++ b/openair1/PHY/impl_defs_top.h
@@ -219,6 +219,13 @@
 ///Third Amplitude for QAM64 (\f$ 2^{15} \times 1/\sqrt{42}\f$)
 #define QAM64_n3 5056
 
+///First Amplitude for QAM256 (\f$ 2^{15} \times 8/\sqrt{170}\f$)
+#define QAM256_n1 20106
+///Second Amplitude for QAM256 (\f$ 2^{15} \times 4/\sqrt{170}\f$)
+#define QAM256_n2 10053
+///Third Amplitude for QAM256 (\f$ 2^{15} \times 2/\sqrt{170}\f$)
+#define QAM256_n3 5026
+
 /// First Amplitude for QAM16 for TM5 (\f$ 2^{15} \times 2/sqrt(20)\f$)
 #define QAM16_TM5_n1 14654
 /// Second Amplitude for QAM16 for TM5 Receiver (\f$ 2^{15} \times 1/\sqrt{20}\f$)
diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c
index 5f0ff6cff09d71602204424d2604f776e3019b41..a37f95bcb341b7d7470d6606003d91e1a08b7d3e 100644
--- a/openair1/SCHED/phy_procedures_lte_eNb.c
+++ b/openair1/SCHED/phy_procedures_lte_eNb.c
@@ -757,8 +757,8 @@ void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int
   //  pdu->rx_ue_information.handle                       = handle;
   pdu->rx_ue_information.tl.tag                       = NFAPI_RX_UE_INFORMATION_TAG;
   pdu->rx_ue_information.rnti                         = rnti;
-  int SNRtimes10 = dB_fixed_times10(stat) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
-  LOG_D(PHY,"stat %d subbandpower %d, SNRtimes10 %d\n", stat, eNB->measurements.n0_subband_power_dB[0][0], SNRtimes10);
+  int SNRtimes10 = dB_fixed_times10(stat) - 10 * eNB->measurements.n0_subband_power_avg_dB;
+  LOG_D(PHY,"stat %d subband n0 %d, SNRtimes10 %d\n", stat, eNB->measurements.n0_subband_power_avg_dB, SNRtimes10);
   pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
 
   if      (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0;
@@ -1604,8 +1604,8 @@ void fill_rx_indication(PHY_VARS_eNB *eNB,
     timing_advance_update = 63;
 
   pdu->rx_indication_rel8.timing_advance = timing_advance_update;
-  // estimate UL_CQI for MAC (from antenna port 0 only)
-  int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0]) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
+  // estimate UL_CQI for MAC 
+  int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0] + ((eNB->frame_parms.nb_antennas_rx>1) ?eNB->pusch_vars[UE_id]->ulsch_power[1] : 0 )) - 10 * eNB->measurements.n0_subband_power_avg_dB;
 
   if (SNRtimes10 < -640)
     pdu->rx_indication_rel8.ul_cqi = 0;
@@ -1614,8 +1614,8 @@ void fill_rx_indication(PHY_VARS_eNB *eNB,
   else
     pdu->rx_indication_rel8.ul_cqi = (640 + SNRtimes10) / 5;
 
-  LOG_D(PHY,"[PUSCH %d] Frame %d Subframe %d Filling RX_indication with SNR %d (%d), timing_advance %d (update %d)\n",
-        harq_pid,frame,subframe,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,pdu->rx_indication_rel8.timing_advance,
+  LOG_D(PHY,"[PUSCH %d] Frame %d Subframe %d Filling RX_indication with SNR %d (%d,%d), timing_advance %d (update %d)\n",
+        harq_pid,frame,subframe,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,eNB->measurements.n0_subband_power_avg_dB,pdu->rx_indication_rel8.timing_advance,
         timing_advance_update);
   eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus++;
   eNB->UL_INFO.rx_ind.sfn_sf = frame<<4 | subframe;
@@ -1919,7 +1919,7 @@ void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, in
   pdu->rx_ue_information.rnti                         = uci->rnti;
   // estimate UL_CQI for MAC (from antenna port 0 only)
   pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
-  int SNRtimes10 = dB_fixed_times10(uci->stat) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
+  int SNRtimes10 = dB_fixed_times10(uci->stat) - 10 * eNB->measurements.n0_subband_power_avg_dB;
 
   if (SNRtimes10 < -100)
     LOG_I (PHY, "uci->stat %d \n", uci->stat);
@@ -2132,17 +2132,17 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
 
   lte_eNB_I0_measurements (eNB, subframe, 0, eNB->first_run_I0_measurements);
   int min_I0=1000,max_I0=0;
-
-  if ((frame==0) && (subframe==4)) {
+  int amin=0,amax=0;
+  if ((frame==0) && (subframe==3)) {
     for (int i=0; i<eNB->frame_parms.N_RB_UL; i++) {
       if (i==(eNB->frame_parms.N_RB_UL>>1) - 1) i+=2;
 
-      if (eNB->measurements.n0_subband_power_tot_dB[i]<min_I0) min_I0 = eNB->measurements.n0_subband_power_tot_dB[i];
+      if (eNB->measurements.n0_subband_power_tot_dB[i]<min_I0) {min_I0 = eNB->measurements.n0_subband_power_tot_dB[i]; amin=i;}
 
-      if (eNB->measurements.n0_subband_power_tot_dB[i]>max_I0) max_I0 = eNB->measurements.n0_subband_power_tot_dB[i];
+      if (eNB->measurements.n0_subband_power_tot_dB[i]>max_I0) {max_I0 = eNB->measurements.n0_subband_power_tot_dB[i]; amax=i;}
     }
 
-    LOG_I (PHY, "max_I0 %d, min_I0 %d\n", max_I0, min_I0);
+    LOG_I (PHY, "max_I0 %d (rb %d), min_I0 %d (rb %d), avg I0 %d\n", max_I0, amax, min_I0, amin, eNB->measurements.n0_subband_power_avg_dB);
   }
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 0 );
diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h
index b74494a4041581b5534681725e425351e108fe11..6a3d2c02b3fb6b1be4666f4a975c2c517150126e 100644
--- a/openair1/SCHED_NR_UE/defs.h
+++ b/openair1/SCHED_NR_UE/defs.h
@@ -296,6 +296,13 @@ uint16_t nr_get_Np(uint8_t N_RB_DL,uint8_t nCCE,uint8_t plus1);
 
 int8_t nr_find_ue(uint16_t rnti, PHY_VARS_eNB *phy_vars_eNB);
 
+/*! \brief UL time alignment procedures for TA application
+  @param PHY_VARS_NR_UE ue
+  @param int slot_tx
+  @param int frame_tx
+*/
+void ue_ta_procedures(PHY_VARS_NR_UE *ue, int slot_tx, int frame_tx);
+
 /*! \brief Compute the timing adjustment at UE side from the old TA offset and the new received TA command
   @param Mod_id Local UE index on which to act
   @param CC_id Component Carrier Index
diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
index 1f7f7e93ebf8ab67be163932d387bb4ca89a44e8..748a3ce3ea41958d5d8bd09f1275d55d72744af7 100644
--- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
+++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
@@ -61,13 +61,14 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){
     if(scheduled_response->dl_config != NULL){
       fapi_nr_dl_config_request_t *dl_config = scheduled_response->dl_config;
 
-      LOG_D(PHY,"Received %d DL pdus\n",dl_config->number_pdus);
+      LOG_D(PHY,"Received %d DL pdus:\n",dl_config->number_pdus);
       pdcch_vars->nb_search_space = 0;
 
       for (i = 0; i < dl_config->number_pdus; ++i){
 
         if (dl_config->dl_config_list[i].pdu_type == FAPI_NR_DL_CONFIG_TYPE_DCI) {
 
+          LOG_D(PHY,"FAPI_NR_DL_CONFIG_TYPE_DCI\n");
           fapi_nr_dl_config_dci_dl_pdu_rel15_t *pdcch_config = &dl_config->dl_config_list[i].dci_config_pdu.dci_config_rel15;
           memcpy((void*)&pdcch_vars->pdcch_config[pdcch_vars->nb_search_space],(void*)pdcch_config,sizeof(*pdcch_config));
           pdcch_vars->nb_search_space = pdcch_vars->nb_search_space + 1;
@@ -76,9 +77,11 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){
         } else {
 
           if (dl_config->dl_config_list[i].pdu_type == FAPI_NR_DL_CONFIG_TYPE_DLSCH){
+            LOG_D(PHY,"FAPI_NR_DL_CONFIG_TYPE_DLSCH\n");
             dlsch0 = PHY_vars_UE_g[module_id][cc_id]->dlsch[thread_id][0][0];
           }
           else if (dl_config->dl_config_list[i].pdu_type == FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH){
+            LOG_D(PHY,"FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH\n");
             dlsch0 = PHY_vars_UE_g[module_id][cc_id]->dlsch_ra[0];
           }
 
@@ -91,6 +94,8 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){
           dlsch0->rnti = dl_config->dl_config_list[i].dlsch_config_pdu.rnti;
           dlsch0_harq = dlsch0->harq_processes[current_harq_pid];
 
+          LOG_D(PHY,"current_harq_pid = %d\n", current_harq_pid);
+
           if (dlsch0_harq){
 
             dlsch0_harq->BWPStart = dlsch_config_pdu->BWPStart;
@@ -118,8 +123,7 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){
             dlsch0_harq->nEpreRatioOfPDSCHToPTRS = dlsch_config_pdu->nEpreRatioOfPDSCHToPTRS;
             dlsch0_harq->PTRSReOffset = dlsch_config_pdu->PTRSReOffset;
             dlsch0_harq->pduBitmap = dlsch_config_pdu->pduBitmap;
-            LOG_D(MAC, ">>>> \tdlsch0->g_pucch = %d\tdlsch0_harq.mcs = %d\n", dlsch0->g_pucch, dlsch0_harq->mcs);
-		
+            LOG_D(MAC, ">>>> \tdlsch0->g_pucch = %d\tdlsch0_harq.mcs = %d\tpdsch_to_harq_feedback_time_ind = %d\tslot_for_feedback_ack = %d\n", dlsch0->g_pucch, dlsch0_harq->mcs, dlsch_config_pdu->pdsch_to_harq_feedback_time_ind, dlsch0_harq->harq_ack.slot_for_feedback_ack);
           }
         }
       }
diff --git a/openair1/SCHED_NR_UE/harq_nr.c b/openair1/SCHED_NR_UE/harq_nr.c
index 1083823e6ac8e8716b82d32ca0c76f6ef9c0b91e..85f6d90bbedb3a62a07d7671289d5525dcbc24d1 100644
--- a/openair1/SCHED_NR_UE/harq_nr.c
+++ b/openair1/SCHED_NR_UE/harq_nr.c
@@ -302,7 +302,7 @@ harq_result_t uplink_harq_process(NR_UE_ULSCH_t *ulsch, int harq_pid, int ndi, u
 
     result_harq = NEW_TRANSMISSION_HARQ;
 
-    NR_TST_PHY_PRINTF("[HARQ-UL-PUSCH harqId : %d] first new transmission \n", harq_pid);
+    LOG_D(PHY, "[HARQ-UL-PUSCH harqId : %d] first new transmission \n", harq_pid);
   }
   /* 38.321 5.4.2.1  2> if the received grant was not addressed to a Temporary C-RNTI on PDCCH, and the NDI provided in the associated HARQ */
   /* information has been toggled compared to the value in the previous transmission of this TB of this HARQ process */
@@ -313,7 +313,7 @@ harq_result_t uplink_harq_process(NR_UE_ULSCH_t *ulsch, int harq_pid, int ndi, u
 
     result_harq = NEW_TRANSMISSION_HARQ;
 
-    NR_TST_PHY_PRINTF("[HARQ-UL-PUSCH harqId : %d] new transmission due to toogle of ndi \n", harq_pid);
+    LOG_D(PHY, "[HARQ-UL-PUSCH harqId : %d] new transmission due to toogle of ndi \n", harq_pid);
    }
    /* 38.321 5.4.2.1 2> else (i.e. retransmission): */
    else {
@@ -322,7 +322,7 @@ harq_result_t uplink_harq_process(NR_UE_ULSCH_t *ulsch, int harq_pid, int ndi, u
 
      result_harq = RETRANSMISSION_HARQ;
 
-     NR_TST_PHY_PRINTF("[HARQ-UL-PUSCH harqId : %d] retransmission \n", harq_pid);
+     LOG_D(PHY, "[HARQ-UL-PUSCH harqId : %d] retransmission \n", harq_pid);
    }
 
   return (result_harq);
@@ -476,7 +476,7 @@ harq_result_t downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int
 
     result_harq = NEW_TRANSMISSION_HARQ;
 
-    NR_TST_PHY_PRINTF("[HARQ-DL-PDSCH harqId : %d] first new reception \n", harq_pid);
+    LOG_D(PHY, "[HARQ-DL-PDSCH harqId : %d] first new reception \n", harq_pid);
   }
   else if (dl_harq->DCINdi != ndi) {
     dl_harq->round = 0;
@@ -485,7 +485,7 @@ harq_result_t downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int
 
     result_harq = NEW_TRANSMISSION_HARQ;
 
-    NR_TST_PHY_PRINTF("[HARQ-DL-PDSCH harqId : %d] new reception due to toogle of ndi \n", harq_pid);
+    LOG_D(PHY, "[HARQ-DL-PDSCH harqId : %d] new reception due to toogle of ndi \n", harq_pid);
   }
   else {
 
@@ -495,7 +495,7 @@ harq_result_t downlink_harq_process(NR_DL_UE_HARQ_t *dl_harq, int harq_pid, int
 
     result_harq = RETRANSMISSION_HARQ;
 
-    NR_TST_PHY_PRINTF("[HARQ-DL-PDSCH harqId : %d] reception of a retransmission \n", harq_pid);
+    LOG_D(PHY, "[HARQ-DL-PDSCH harqId : %d] reception of a retransmission \n", harq_pid);
   }
 
   return (result_harq);
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index 653fd8eb7d1e3cf95aad93e68a1ee892a66f5a59..95a7923d6c3edcad36a0cd08d969e0bfec2184dd 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -134,10 +134,10 @@ UE_MODE_t get_nrUE_mode(uint8_t Mod_id,uint8_t CC_id,uint8_t gNB_id){
   return(PHY_vars_UE_g[Mod_id][CC_id]->UE_mode[gNB_id]);
 }
 
-uint16_t get_bw_scaling(uint16_t bwp_ul_NB_RB){
+// scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size
+uint16_t get_bw_scaling(uint16_t nb_rb){
   uint16_t bw_scaling;
-  // scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size
-  switch (bwp_ul_NB_RB) {
+  switch (nb_rb) {
     case 32:  bw_scaling =  4; break;
     case 66:  bw_scaling =  8; break;
     case 106: bw_scaling = 16; break;
@@ -149,6 +149,32 @@ uint16_t get_bw_scaling(uint16_t bwp_ul_NB_RB){
   return bw_scaling;
 }
 
+/* UL time alignment
+// If the current tx frame and slot match the TA configuration in ul_time_alignment
+// then timing advance is processed and set to be applied in the next UL transmission */
+void ue_ta_procedures(PHY_VARS_NR_UE *ue, int slot_tx, int frame_tx){
+
+  if (ue->mac_enabled == 1) {
+
+    uint8_t gNB_id = 0;
+    NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &ue->ul_time_alignment[gNB_id];
+
+    if (frame_tx == ul_time_alignment->ta_frame && slot_tx == ul_time_alignment->ta_slot) {
+
+      uint8_t numerology = ue->frame_parms.numerology_index;
+      uint16_t bwp_ul_NB_RB = ue->frame_parms.N_RB_UL;
+
+      LOG_D(PHY, "In %s: applying timing advance -- frame %d -- slot %d\n", __FUNCTION__, frame_tx, slot_tx);
+
+      nr_process_timing_advance(ue->Mod_id, ue->CC_id, ul_time_alignment->ta_command, numerology, bwp_ul_NB_RB);
+
+      ul_time_alignment->ta_frame = -1;
+      ul_time_alignment->ta_slot = -1;
+
+    }
+  }
+}
+
 void nr_process_timing_advance(module_id_t Mod_id, uint8_t CC_id, uint8_t ta_command, uint8_t mu, uint16_t bwp_ul_NB_RB){
 
   // 3GPP TS 38.213 p4.2
@@ -178,10 +204,8 @@ void nr_process_timing_advance_rar(PHY_VARS_NR_UE *ue, int frame_rx, int nr_slot
 void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue,
                             UE_nr_rxtx_proc_t *proc,
                             uint8_t gNB_id) {
-  //int32_t ulsch_start=0;
   int slot_tx = proc->nr_slot_tx;
   int frame_tx = proc->frame_tx;
-  uint8_t harq_pid = 0;
   runmode_t mode = normal_txrx;
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX,VCD_FUNCTION_IN);
@@ -194,18 +218,20 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue,
   start_meas(&ue->phy_proc_tx);
 #endif
 
-  if (ue->UE_mode[gNB_id] <= PUSCH || get_softmodem_params()->phy_test == 1){
+  if (ue->UE_mode[gNB_id] <= PUSCH){
 
-   if (ue->ulsch[proc->thread_id][gNB_id][0]->harq_processes[harq_pid]->status == ACTIVE)
-     nr_ue_ulsch_procedures(ue, harq_pid, frame_tx, slot_tx, proc->thread_id, gNB_id);
+    for (uint8_t harq_pid = 0; harq_pid < ue->ulsch[proc->thread_id][gNB_id][0]->number_harq_processes_for_pusch; harq_pid++) {
+      if (ue->ulsch[proc->thread_id][gNB_id][0]->harq_processes[harq_pid]->status == ACTIVE)
+        nr_ue_ulsch_procedures(ue, harq_pid, frame_tx, slot_tx, proc->thread_id, gNB_id);
+    }
 
-   if (get_softmodem_params()->usim_test==0) {
+    if (get_softmodem_params()->usim_test==0) {
       LOG_D(PHY, "Generating PUCCH\n");
       pucch_procedures_ue_nr(ue,
                              gNB_id,
                              proc,
                              FALSE);
-   }
+    }
 
     LOG_D(PHY, "Sending Uplink data \n");
     nr_ue_pusch_common_procedures(ue,
@@ -230,14 +256,12 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue,
 
 }
 
-void nr_ue_measurement_procedures(uint16_t l,    // symbol index of each slot [0..6]
-								  PHY_VARS_NR_UE *ue,
-								  UE_nr_rxtx_proc_t *proc,
-								  uint8_t eNB_id,
-								  uint16_t slot, // slot index of each radio frame [0..19]
-								  runmode_t mode)
-{
-  LOG_D(PHY,"ue_measurement_procedures l %u Ncp %d\n",l,ue->frame_parms.Ncp);
+void nr_ue_measurement_procedures(uint16_t l,
+                                  PHY_VARS_NR_UE *ue,
+                                  UE_nr_rxtx_proc_t *proc,
+                                  uint8_t eNB_id,
+                                  uint16_t slot,
+                                  runmode_t mode){
 
   NR_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;
   int frame_rx   = proc->frame_rx;
@@ -245,18 +269,14 @@ void nr_ue_measurement_procedures(uint16_t l,    // symbol index of each slot [0
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_MEASUREMENT_PROCEDURES, VCD_FUNCTION_IN);
 
   if (l==2) {
-    // UE measurements on symbol 0
-    LOG_D(PHY,"Calling measurements nr_slot_rx %d, rxdata %p\n",nr_slot_rx,ue->common_vars.rxdata);
-/*
-    nr_ue_measurements(ue,
-                       proc,
-                       0,
-                       0,
-                       0,
-                       0,
-                       nr_slot_rx);
-*/
-			  //(nr_slot_rx*frame_parms->samples_per_slot+ue->rx_offset) % frame_parms->samples_per_frame
+
+    LOG_D(PHY,"Doing UE measurement procedures in symbol l %u Ncp %d nr_slot_rx %d, rxdata %p\n",
+      l,
+      ue->frame_parms.Ncp,
+      nr_slot_rx,
+      ue->common_vars.rxdata);
+
+    nr_ue_measurements(ue, proc, nr_slot_rx);
 
 #if T_TRACER
     if(slot == 0)
@@ -270,21 +290,6 @@ void nr_ue_measurement_procedures(uint16_t l,    // symbol index of each slot [0
 	T_INT((int)ue->common_vars.freq_offset));
 #endif
   }
-#if 0
-  if (l==(6-ue->frame_parms.Ncp)) {
-
-    // make sure we have signal from PSS/SSS for N0 measurement
-    // LOG_I(PHY," l==(6-ue->frame_parms.Ncp) ue_rrc_measurements\n");
-
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_RRC_MEASUREMENTS, VCD_FUNCTION_IN);
-    ue_rrc_measurements(ue,
-			slot,
-			abstraction_flag);
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_RRC_MEASUREMENTS, VCD_FUNCTION_OUT);
-
-
-  }
-#endif
 
   // accumulate and filter timing offset estimation every subframe (instead of every frame)
   if (( slot == 2) && (l==(2-frame_parms->Ncp))) {
@@ -311,7 +316,6 @@ void nr_ue_pbch_procedures(uint8_t gNB_id,
 {
   //  int i;
   //int pbch_tx_ant=0;
-  //uint8_t pbch_phase;
   int ret = 0;
   //static uint8_t first_run = 1;
   //uint8_t pbch_trials = 0;
@@ -323,7 +327,7 @@ void nr_ue_pbch_procedures(uint8_t gNB_id,
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PBCH_PROCEDURES, VCD_FUNCTION_IN);
 
-  //LOG_I(PHY,"[UE  %d] Frame %d, Trying PBCH %d (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,pbch_phase,ue->frame_parms.Nid_cell,gNB_id);
+  LOG_D(PHY,"[UE  %d] Frame %d, Trying PBCH (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,ue->frame_parms.Nid_cell,gNB_id);
 
   ret = nr_rx_pbch(ue, proc,
 		   ue->pbch_vars[gNB_id],
@@ -946,7 +950,7 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
   uint16_t ofdm_symbol_size = ue->frame_parms.ofdm_symbol_size;
   uint16_t nb_prefix_samples = ue->frame_parms.nb_prefix_samples;
   uint32_t t_subframe = 1; // subframe duration of 1 msec
-  uint16_t bw_scaling, start_symbol;
+  uint16_t start_symbol;
   float tc_factor;
 
   is_cw0_active = dlsch0->harq_processes[harq_pid]->status;
@@ -1257,16 +1261,7 @@ void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
 
       if (ue->mac_enabled == 1) {
 
-        // scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size
-        switch (ue->frame_parms.N_RB_DL) {
-          case 32:  bw_scaling =  4; break;
-          case 66:  bw_scaling =  8; break;
-          case 106: bw_scaling = 16; break;
-          case 217: bw_scaling = 32; break;
-          case 245: bw_scaling = 32; break;
-          case 273: bw_scaling = 32; break;
-          default: abort();
-        }
+        uint16_t bw_scaling = get_bw_scaling(ue->frame_parms.N_RB_DL);
 
         /* Time Alignment procedure
         // - UE processing capability 1
@@ -1710,15 +1705,13 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
   int frame_rx = proc->frame_rx;
   int nr_slot_rx = proc->nr_slot_rx;
   int slot_pbch;
-  //int slot_ssb;
+  int slot_ssb;
   NR_UE_PDCCH *pdcch_vars  = ue->pdcch_vars[proc->thread_id][0];
   fapi_nr_config_request_t *cfg = &ue->nrUE_config;
 
   uint8_t nb_symb_pdcch = pdcch_vars->nb_search_space > 0 ? pdcch_vars->pdcch_config[0].coreset.duration : 0;
   uint8_t dci_cnt = 0;
   NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
-
-  //NR_UE_MAC_INST_t *mac = get_mac_inst(0);
   
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN);
 
@@ -1734,38 +1727,38 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
 
   if (pdcch_vars->nb_search_space > 0)
     get_coreset_rballoc(pdcch_vars->pdcch_config[0].coreset.frequency_domain_resource,&coreset_nb_rb,&coreset_start_rb);
-  
+
   slot_pbch = is_pbch_in_slot(cfg, frame_rx, nr_slot_rx, fp);
-  //slot_ssb = is_ssb_in_slot(cfg, frame_rx, nr_slot_rx, fp);
+  slot_ssb  = is_ssb_in_slot(cfg, frame_rx, nr_slot_rx, fp);
 
   // looking for pbch only in slot where it is supposed to be
-  if ((ue->decode_MIB == 1) && slot_pbch)
-    {
-      LOG_D(PHY," ------  PBCH ChannelComp/LLR: frame.slot %d.%d ------  \n", frame_rx%1024, nr_slot_rx);
-      for (int i=1; i<4; i++) {
+  if (slot_ssb) {
+    LOG_D(PHY," ------  PBCH ChannelComp/LLR: frame.slot %d.%d ------  \n", frame_rx%1024, nr_slot_rx);
+    for (int i=1; i<4; i++) {
 
-        nr_slot_fep(ue,
-                    proc,
-                    (ue->symbol_offset+i)%(fp->symbols_per_slot),
-                    nr_slot_rx,
-                    0,
-                    0);
+      nr_slot_fep(ue,
+                  proc,
+                  (ue->symbol_offset+i)%(fp->symbols_per_slot),
+                  nr_slot_rx,
+                  0,
+                  0);
 
 #if UE_TIMING_TRACE
-        start_meas(&ue->dlsch_channel_estimation_stats);
+      start_meas(&ue->dlsch_channel_estimation_stats);
 #endif
-        nr_pbch_channel_estimation(ue,proc,0,nr_slot_rx,(ue->symbol_offset+i)%(fp->symbols_per_slot),i-1,(fp->ssb_index)&7,fp->half_frame_bit);
+      nr_pbch_channel_estimation(ue,proc,0,nr_slot_rx,(ue->symbol_offset+i)%(fp->symbols_per_slot),i-1,(fp->ssb_index)&7,fp->half_frame_bit);
 #if UE_TIMING_TRACE
-        stop_meas(&ue->dlsch_channel_estimation_stats);
+      stop_meas(&ue->dlsch_channel_estimation_stats);
 #endif
+    }
 
-      }
-      
-      //if (mac->csirc->reportQuantity.choice.ssb_Index_RSRP){ 
-        nr_ue_rsrp_measurements(ue, proc, nr_slot_rx, 0);
-      //}
-	
+    //if (mac->csirc->reportQuantity.choice.ssb_Index_RSRP){
+    nr_ue_rsrp_measurements(ue,proc,nr_slot_rx,0);
+    //}
 
+    if ((ue->decode_MIB == 1) && slot_pbch) {
+
+      LOG_D(PHY," ------  Decode MIB: frame.slot %d.%d ------  \n", frame_rx%1024, nr_slot_rx);
       nr_ue_pbch_procedures(gNB_id, ue, proc, 0);
 
       if (ue->no_timing_correction==0) {
@@ -1778,7 +1771,11 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
                            0,
                            16384);
       }
+
+      LOG_D(PHY, "Doing N0 measurements in %s\n", __FUNCTION__);
+      nr_ue_rrc_measurements(ue, proc, nr_slot_rx);
     }
+  }
 
   if ((frame_rx%64 == 0) && (nr_slot_rx==0)) {
     printf("============================================\n");
@@ -1791,7 +1788,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
 
   LOG_D(PHY," ------ --> PDCCH ChannelComp/LLR Frame.slot %d.%d ------  \n", frame_rx%1024, nr_slot_rx);
   for (uint16_t l=0; l<nb_symb_pdcch; l++) {
-    
+
 #if UE_TIMING_TRACE
     start_meas(&ue->ofdm_demod_stats);
 #endif
@@ -1850,8 +1847,8 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
 
       for (int i=0;i<4;i++) if (((1<<i)&dlsch0_harq->dlDmrsSymbPos) > 0) {symb_dmrs=i;break;}
       AssertFatal(symb_dmrs>=0,"no dmrs in 0..3\n");
-      LOG_D(PHY,"Initializing dmrs for symb %d DMRS mask %x\n",symb_dmrs,dlsch0_harq->dlDmrsSymbPos);
-      nr_gold_pdsch(ue,0);
+      LOG_D(PHY,"Initializing dmrs for slot %d DMRS mask %x\n", nr_slot_rx, dlsch0_harq->dlDmrsSymbPos);
+      nr_gold_pdsch(ue, nr_slot_rx, 0);
     
       for (uint16_t m=start_symb_sch;m<(nb_symb_sch+start_symb_sch) ; m++){
         nr_slot_fep(ue,
@@ -1882,19 +1879,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
 			   ue->dlsch[proc->thread_id][gNB_id][0],
 			   NULL);
 
-    //printf("phy procedure pdsch start measurement\n"); 
-    nr_ue_measurement_procedures(2,ue,proc,gNB_id,nr_slot_rx,mode);
-
-    /*
-    write_output("rxF.m","rxF",&ue->common_vars.common_vars_rx_data_per_thread[proc->thread_id].rxdataF[0][0],fp->ofdm_symbol_size*14,1,1);
-    write_output("rxF_ch.m","rxFch",&ue->pdsch_vars[proc->thread_id][gNB_id]->dl_ch_estimates[0][0],fp->ofdm_symbol_size*14,1,1);
-    write_output("rxF_ch_ext.m","rxFche",&ue->pdsch_vars[proc->thread_id][gNB_id]->dl_ch_estimates_ext[0][2*50*12],50*12,1,1);
-    write_output("rxF_ext.m","rxFe",&ue->pdsch_vars[proc->thread_id][gNB_id]->rxdataF_ext[0][0],50*12*14,1,1);
-    write_output("rxF_comp.m","rxFc",&ue->pdsch_vars[proc->thread_id][gNB_id]->rxdataF_comp0[0][0],fp->N_RB_DL*12*14,1,1);
-    write_output("rxF_llr.m","rxFllr",ue->pdsch_vars[proc->thread_id][gNB_id]->llr[0],(nb_symb_sch-1)*50*12+50*6,1,0);
-    */
-
-    //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT);
+    nr_ue_measurement_procedures(2, ue, proc, gNB_id, nr_slot_rx, mode);
   }
 
   // do procedures for SI-RNTI
@@ -2165,7 +2150,7 @@ void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_IN);
 
-  if (!prach_resources->init_msg1 && (frame_tx == (ue->prach_resources[gNB_id]->sync_frame + 150) % MAX_FRAME_NUMBER)){
+  if (!prach_resources->init_msg1 && ((MAX_FRAME_NUMBER+frame_tx-ue->prach_resources[gNB_id]->sync_frame)% MAX_FRAME_NUMBER)>150){
     ue->prach_cnt = 0;
     prach_resources->init_msg1 = 1;
   }
diff --git a/openair1/SCHED_NR_UE/pucch_power_control_ue_nr.c b/openair1/SCHED_NR_UE/pucch_power_control_ue_nr.c
index e2e21432873c9f81abe4b8dec0d135f1f9630547..f43f4d98c99f9c33bd8504b3acd11face872df20 100644
--- a/openair1/SCHED_NR_UE/pucch_power_control_ue_nr.c
+++ b/openair1/SCHED_NR_UE/pucch_power_control_ue_nr.c
@@ -98,7 +98,7 @@ int16_t get_pucch_tx_power_ue(PHY_VARS_NR_UE *ue,
   }
   else {
     G_b_f_c = ue->dlsch[proc->thread_id][gNB_id][0]->g_pucch;
-    LOG_W(PHY,"PUCCH Transmit power control command not yet implemented for NR : at line %d in function %s of file %s \n", LINE_FILE , __func__, __FILE__);
+    LOG_D(PHY,"PUCCH Transmit power control command not yet implemented for NR : at line %d in function %s of file %s \n", LINE_FILE , __func__, __FILE__);
     return (PUCCH_POWER_DEFAULT);
   }
 
diff --git a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c
index 6b1e9f62de2f006c89d1a4af8dc2ca406096544b..2035564ad8b8ccf7710a0bb5e2fec178c00cad0b 100644
--- a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c
+++ b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c
@@ -33,6 +33,7 @@
 *
 **************************************************************************/
 
+#include "executables/softmodem-common.h"
 #include "PHY/NR_REFSIG/ss_pbch_nr.h"
 #include "PHY/defs_nr_UE.h"
 #include <openair1/SCHED/sched_common.h>
@@ -228,13 +229,11 @@ bool pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_
   int       pucch_resource_indicator = MAX_PUCCH_RESOURCE_INDICATOR;
   int       n_HARQ_ACK;
 
-  uint16_t crnti=0x1234;
   int dmrs_scrambling_id=0,data_scrambling_id=0;
 
-
   NR_UE_MAC_INST_t *mac = get_mac_inst(0);
   NR_PUCCH_Resource_t *pucch_resource;
-  //NR_UE_MAC_INST_t *mac = get_mac_inst(0);
+  uint16_t crnti = mac->crnti;
 
   /* update current context */
 
@@ -248,6 +247,8 @@ bool pucch_procedures_ue_nr(PHY_VARS_NR_UE *ue, uint8_t gNB_id, UE_nr_rxtx_proc_
     pucch_resource_indicator = ue->dlsch[proc->thread_id][gNB_id][0]->harq_processes[dl_harq_pid]->harq_ack.pucch_resource_indicator;
   }
 
+  LOG_D(PHY, "PUCCH: %d.%d dl_harq_pid = %d, pucch_resource_indicator = %d\n", frame_tx, nr_slot_tx, dl_harq_pid, pucch_resource_indicator);
+
   /* Part - I
    * Collect feedback that should be transmitted at this nr_slot_tx :
    * - ACK/NACK, SR, CSI (CQI, RI, ...)
diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c
index 12aace577c72e1f8aa7b34c7022f46cf71c02706..d3f55785c9f7e9940b70c6d46dc99d1c3bfc009b 100644
--- a/openair1/SIMULATION/LTE_PHY/dlsim.c
+++ b/openair1/SIMULATION/LTE_PHY/dlsim.c
@@ -487,7 +487,7 @@ int n_ch_rlz = 1;
 int rx_sample_offset = 0;
 int xforms=0;
 int dump_table=0;
-int loglvl=OAILOG_WARNING;
+int loglvl=OAILOG_INFO;
 int mcs1=0,mcs2=0,mcs_i=0,dual_stream_UE = 0,awgn_flag=0;
 int two_thread_flag=0;
 int num_rounds = 4;//,fix_rounds=0;
@@ -670,7 +670,7 @@ int main(int argc, char **argv) {
     { "XForms", "Display the soft scope", PARAMFLAG_BOOL, iptr:&xforms,  defintval:0, TYPE_INT, 0 },
     { "Yperfect_ce","Perfect CE", PARAMFLAG_BOOL, iptr:&perfect_ce,  defintval:0, TYPE_INT, 0 },
     { "Zdump", "dump table",PARAMFLAG_BOOL,  iptr:&dump_table, defintval:0, TYPE_INT, 0 },
-    { "Loglvl", "log level",0, iptr:&loglvl,  defintval:OAILOG_DEBUG, TYPE_INT, 0 },
+    { "Loglvl", "log level",0, iptr:&loglvl,  defintval:OAILOG_INFO, TYPE_INT, 0 },
     { "zn_rx", "Number of RX antennas used in UE",0, iptr:NULL,  defintval:2, TYPE_INT, 0 },
     { "gchannel", "[A:M] Use 3GPP 25.814 SCM-A/B/C/D('A','B','C','D') or 36-101 EPA('E'), EVA ('F'),ETU('G') models (ignores delay spread and Ricean factor), Rayghleigh8 ('H'), Rayleigh1('I'), Rayleigh1_corr('J'), Rayleigh1_anticorr ('K'),  Rice8('L'), Rice1('M')",0, strptr:NULL,  defstrval:NULL, TYPE_STRING, 0 },
     { "verbose", "display debug text", PARAMFLAG_BOOL,  iptr:&verbose, defintval:0, TYPE_INT, 0 },
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index 26f03f9c189991cef0d1e79b1aa11d4f19828459..63a2da6cbba5e18b83299f3a0447409d7d379645 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -153,7 +153,7 @@ void update_dmrs_config(NR_CellGroupConfig_t *scg,PHY_VARS_NR_UE *ue, int8_t* dm
 
 /* specific dlsim DL preprocessor: uses rbStart/rbSize/mcs from command line of
    dlsim, does not search for CCE/PUCCH occasion but simply sets to 0 */
-int g_mcsIndex = -1, g_rbStart = -1, g_rbSize = -1;
+int g_mcsIndex = -1, g_mcsTableIdx = 0, g_rbStart = -1, g_rbSize = -1;
 void nr_dlsim_preprocessor(module_id_t module_id,
                            frame_t frame,
                            sub_frame_t slot,
@@ -181,10 +181,11 @@ void nr_dlsim_preprocessor(module_id_t module_id,
   sched_ctrl->rbSize = g_rbSize;
   sched_ctrl->mcs = g_mcsIndex;
   sched_ctrl->time_domain_allocation = 2;
-  sched_ctrl->mcsTableIdx = 0;
+  sched_ctrl->mcsTableIdx = g_mcsTableIdx;
   AssertFatal(sched_ctrl->rbStart >= 0, "invalid rbStart %d\n", sched_ctrl->rbStart);
   AssertFatal(sched_ctrl->rbSize > 0, "invalid rbSize %d\n", sched_ctrl->rbSize);
   AssertFatal(sched_ctrl->mcs >= 0, "invalid sched_ctrl->mcs %d\n", sched_ctrl->mcs);
+  AssertFatal(sched_ctrl->mcsTableIdx >= 0 && sched_ctrl->mcsTableIdx <= 2, "invalid sched_ctrl->mcsTableIdx %d\n", sched_ctrl->mcsTableIdx);
   sched_ctrl->numDmrsCdmGrpsNoData = 1;
 }
 
@@ -280,7 +281,7 @@ int main(int argc, char **argv)
 
   FILE *scg_fd=NULL;
   
-  while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:s:S:t:x:y:z:M:N:F:GR:dPIL:Ea:b:e:m:w:T:U:")) != -1) {
+  while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:s:S:t:x:y:z:M:N:F:GR:dPIL:Ea:b:e:m:w:T:U:q")) != -1) {
     switch (c) {
     case 'f':
       scg_fd = fopen(optarg,"r");
@@ -452,6 +453,11 @@ int main(int argc, char **argv)
       g_mcsIndex = atoi(optarg);
       break;
 
+    case 'q':
+      g_mcsTableIdx = 1;
+      get_softmodem_params()->use_256qam_table = 1;
+      break;
+
     case 'm':
       mu = atoi(optarg);
       break;
@@ -507,6 +513,7 @@ int main(int argc, char **argv)
       printf("-c Start symbol for PDSCH (fixed for now)\n");
       printf("-j Number of symbols for PDSCH (fixed for now)\n");
       printf("-e MSC index\n");
+      printf("-q Use 2nd MCS table (256 QAM table) for PDSCH\n");
       printf("-t Acceptable effective throughput (in percentage)\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}, e.g. -U 2 0 2 \n");
@@ -860,7 +867,6 @@ int main(int argc, char **argv)
 
 
         UE_info->UE_sched_ctrl[0].harq_processes[harq_pid].round = round;
-        UE_info->UE_sched_ctrl[0].current_harq_pid = harq_pid;
         gNB->dlsch[0][0]->harq_processes[harq_pid]->round = round;
         for (int i=0; i<MAX_NUM_CORESET; i++)
           gNB_mac->UE_info.num_pdcch_cand[0][i] = 0;
@@ -878,7 +884,7 @@ int main(int argc, char **argv)
         Sched_INFO.frame     = frame;
         Sched_INFO.slot      = slot;
         Sched_INFO.DL_req    = &gNB_mac->DL_req[0];
-        Sched_INFO.UL_tti_req    = &gNB_mac->UL_tti_req[0];
+        Sched_INFO.UL_tti_req    = gNB_mac->UL_tti_req_ahead[slot];
         Sched_INFO.UL_dci_req  = NULL;
         Sched_INFO.TX_req    = &gNB_mac->TX_req[0];
         nr_schedule_response(&Sched_INFO);
diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c
index 5c33c79488bc34cb486d39d9186d41d52c1812b9..8fb58b1f7b231fe0b3ee0fa0c9e0948d45418a69 100644
--- a/openair2/GNB_APP/gnb_config.c
+++ b/openair2/GNB_APP/gnb_config.c
@@ -233,8 +233,8 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) {
       scc->ssb_PositionsInBurst->choice.shortBitmap.buf[0] |= curr_bit<<i;   
     }
   }else if(ssbmaplen==NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap){
-	  scc->ssb_PositionsInBurst->choice.mediumBitmap.size = 1;
-	  scc->ssb_PositionsInBurst->choice.mediumBitmap.bits_unused = 0;
+    scc->ssb_PositionsInBurst->choice.mediumBitmap.size = 1;
+    scc->ssb_PositionsInBurst->choice.mediumBitmap.bits_unused = 0;
     scc->ssb_PositionsInBurst->choice.mediumBitmap.buf = CALLOC(1,1);
     scc->ssb_PositionsInBurst->choice.mediumBitmap.buf[0] = 0;
     for (int i=0; i<8; i++)
@@ -244,10 +244,10 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc,uint64_t ssbmap) {
     scc->ssb_PositionsInBurst->choice.longBitmap.bits_unused = 0;
     scc->ssb_PositionsInBurst->choice.longBitmap.buf = CALLOC(1,8);
     for (int j=0; j<8; j++) {
-       scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-j] = 0;
+       scc->ssb_PositionsInBurst->choice.longBitmap.buf[j] = 0;
        curr_bit = (ssbmap>>(j<<3))&(0xff);
        for (int i=0; i<8; i++)
-         scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-j] |= (((curr_bit>>(7-i))&0x01)<<i);
+         scc->ssb_PositionsInBurst->choice.longBitmap.buf[j] |= (((curr_bit>>(7-i))&0x01)<<i);
     }
   }
 
diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h
index 35bc762c8859b9c372e5fead9b61572f362e2649..69c55bc06c4d0e12f2f39a5ac73078dba852d8e1 100644
--- a/openair2/GNB_APP/gnb_paramdef.h
+++ b/openair2/GNB_APP/gnb_paramdef.h
@@ -83,6 +83,7 @@ typedef enum {
 /* global parameters, not under a specific section   */
 #define GNB_CONFIG_STRING_ASN1_VERBOSITY                   "Asn1_verbosity"
 #define GNB_CONFIG_STRING_ACTIVE_GNBS                      "Active_gNBs"
+#define GNB_CONFIG_PUSCH_THREADS                           "Num_Threads_PUSCH"
 /*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/
 /*                                            global configuration parameters                                                                                   */
 /*   optname                                   helpstr   paramflags    XXXptr        defXXXval                                        type           numelt     */
@@ -91,6 +92,11 @@ typedef enum {
 {GNB_CONFIG_STRING_ASN1_VERBOSITY,             NULL,     0,        uptr:NULL,   defstrval:GNB_CONFIG_STRING_ASN1_VERBOSITY_NONE,   TYPE_STRING,      0},   \
 {GNB_CONFIG_STRING_ACTIVE_GNBS,                NULL,     0,        uptr:NULL,   defstrval:NULL, 				   TYPE_STRINGLIST,  0}    \
 }
+
+#define NUM_THREADS_DESC { \
+{GNB_CONFIG_PUSCH_THREADS,                     NULL,     0,        uptr:&num_threads_pusch,   defuintval:1, 				   TYPE_UINT,  0}    \
+}
+
 #define GNB_ASN1_VERBOSITY_IDX                     0
 #define GNB_ACTIVE_GNBS_IDX                        1
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
index 997fc6691e7da517f8430319029e7ef62b8a76f2..b62df74082faa98060dbede5563095dd0cd5b9ed 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
@@ -182,7 +182,7 @@ rx_sdu(const module_id_t enb_mod_idP,
         UE_template_ptr->scheduled_ul_bytes = 0;
       }
     } else {  // sduP == NULL => error
-      LOG_W(MAC, "[eNB %d][PUSCH %d] CC_id %d %d.%d ULSCH in error in round %d, ul_cqi %d, UE_id %d, RNTI %x (len %d)\n",
+      LOG_D(MAC, "[eNB %d][PUSCH %d] CC_id %d %d.%d ULSCH in error in round %d, ul_cqi %d, UE_id %d, RNTI %x (len %d)\n",
             enb_mod_idP,
             harq_pid,
             CC_idP,
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
index 2e00c6ebe30ff89bf65b87cb90bf847854f4ccc9..5006364290b4cbd3c0777d5d58115a85db728648 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
@@ -937,14 +937,22 @@ int64_t table_6_3_3_2_4_prachConfig_Index [256][10] = {
 
 
 int get_format0(uint8_t index,
-                uint8_t unpaired){
+                uint8_t unpaired,
+		frequency_range_t frequency_range){
 
   uint16_t format;
-  if (unpaired)
-    format = table_6_3_3_2_3_prachConfig_Index[index][0];
-  else
-    format = table_6_3_3_2_2_prachConfig_Index[index][0];
-
+  if (unpaired) {
+    if (frequency_range==FR1)
+      format = table_6_3_3_2_3_prachConfig_Index[index][0];
+    else
+      format = table_6_3_3_2_4_prachConfig_Index[index][0];
+  }
+  else {
+    if (frequency_range==FR1)
+      format = table_6_3_3_2_2_prachConfig_Index[index][0];
+    else
+      AssertFatal(0==1,"no paired spectrum for FR2\n");
+  }
   return format;
 }
 
@@ -1402,11 +1410,12 @@ uint16_t table_63313[838] = {
 
 uint8_t compute_nr_root_seq(NR_RACH_ConfigCommon_t *rach_config,
                             uint8_t nb_preambles,
-                            uint8_t unpaired) {
+                            uint8_t unpaired,
+			    frequency_range_t frequency_range) {
 
   uint8_t config_index = rach_config->rach_ConfigGeneric.prach_ConfigurationIndex;
   uint8_t ncs_index = rach_config->rach_ConfigGeneric.zeroCorrelationZoneConfig;
-  uint16_t format0 = get_format0(config_index, unpaired);
+  uint16_t format0 = get_format0(config_index, unpaired, frequency_range);
   uint16_t NCS = get_NCS(ncs_index, format0, rach_config->restrictedSetConfig);
   uint16_t L_ra = (rach_config->prach_RootSequenceIndex.present==NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l139) ? 139 : 839;
   uint16_t r,u,index,q,d_u,n_shift_ra,n_shift_ra_bar,d_start;
@@ -2122,6 +2131,10 @@ int get_num_dmrs(uint16_t dmrs_mask ) {
   for (int i=0;i<16;i++) num_dmrs+=((dmrs_mask>>i)&1);
   return(num_dmrs);
 }
+/* returns the total DMRS symbols in a slot*/
+uint8_t get_num_dmrs_symbols(NR_PDSCH_Config_t *pdsch_Config,int dmrs_TypeA_Position,int NrOfSymbols){
+  return get_num_dmrs(fill_dmrs_mask(pdsch_Config,dmrs_TypeA_Position,NrOfSymbols));
+}
 
 // Table 5.1.2.2.1-1 38.214
 uint8_t getRBGSize(uint16_t bwp_size, long rbg_size_config) {
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
index 11544afd42bcfe25b314a7d5471464ac8782d98b..9a15ff5cf22e713f4b4dae727fd0e83a5cf726e9 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
@@ -44,6 +44,11 @@
 #define MAX_TDM (7) // Maximum nb of PRACH occasions TDMed in a slot
 #define MAX_FDM (8) // Maximum nb of PRACH occasions FDMed in a slot
 
+typedef enum frequency_range_e {
+    FR1 = 0, 
+    FR2
+} frequency_range_t;
+
 // PRACH occasion details
 typedef struct prach_occasion_info {
   uint8_t start_symbol; // 0 - 13 (14 symbols in a slot)
@@ -159,11 +164,12 @@ uint8_t get_pusch_mcs_table(long *mcs_Table,
 
 uint8_t compute_nr_root_seq(NR_RACH_ConfigCommon_t *rach_config,
                             uint8_t nb_preambles,
-                            uint8_t unpaired);
+                            uint8_t unpaired,
+			    frequency_range_t);
 
 int ul_ant_bits(NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig,long transformPrecoder);
 
-int get_format0(uint8_t index, uint8_t unpaired);
+int get_format0(uint8_t index, uint8_t unpaired,frequency_range_t);
 
 int64_t *get_prach_config_info(uint32_t pointa,
                                uint8_t index,
@@ -186,4 +192,7 @@ bool set_dl_ptrs_values(NR_PTRS_DownlinkConfig_t *ptrs_config,
                         uint8_t *nERatio,uint8_t *reOffset,
                         uint8_t NrOfSymbols);
 void get_band(uint64_t downlink_frequency, uint16_t *current_band, int32_t *current_offset, lte_frame_type_t *current_type);
+
+uint8_t get_num_dmrs_symbols(NR_PDSCH_Config_t *pdsch_Config,int dmrs_TypeA_Position,int NrOfSymbols);
+
 #endif
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h
index 5c714e4a93a9e7558fcfc30cb44b694d1c67ae40..6f2b0f89fce8677fdb970f41928e669ac6f660d0 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_extern.h
@@ -37,6 +37,8 @@
 
 /*#include "PHY/defs_common.h"*/
 
+extern const uint8_t nr_slots_per_frame[5];
+
 /* extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE];
 extern const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE];
 extern const uint8_t cqi2fmt0_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE];
diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c
index 7f98af2453867c86bb18cc1196e539f5abad073e..66308e46fe36cb0092bbcb4b43542852e2e71c30 100755
--- a/openair2/LAYER2/NR_MAC_UE/config_ue.c
+++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c
@@ -147,7 +147,6 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
   fapi_nr_config_request_t        *cfg = &mac->phy_config.config_req;
   NR_ServingCellConfigCommon_t    *scc = mac->scc;
   int i;
-  lte_frame_type_t frame_type;
 
   mac->phy_config.Mod_id = module_id;
   mac->phy_config.CC_id = cc_idP;
@@ -201,6 +200,10 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
     }
   }
 
+  uint32_t band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
+  frequency_range_t  frequency_range = band<100?FR1:FR2;
+ 
+  lte_frame_type_t frame_type;
   get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing, &frame_type);
 
   // cell config
@@ -236,8 +239,8 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
       cfg->ssb_table.ssb_mask_list[0].ssb_mask = 0;
       cfg->ssb_table.ssb_mask_list[1].ssb_mask = 0;
       for (i=0; i<4; i++) {
-        cfg->ssb_table.ssb_mask_list[0].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]<<i*8);
-        cfg->ssb_table.ssb_mask_list[1].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<<i*8);
+        cfg->ssb_table.ssb_mask_list[0].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[3-i]<<i*8);
+        cfg->ssb_table.ssb_mask_list[1].ssb_mask += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-i]<<i*8);
       }
       break;
     default:
@@ -310,7 +313,7 @@ void config_common_ue(NR_UE_MAC_INST_t *mac,
 
     cfg->prach_config.num_prach_fd_occasions_list[i].k1 = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FrequencyStart;
     cfg->prach_config.num_prach_fd_occasions_list[i].prach_zero_corr_conf = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig;
-    cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences = compute_nr_root_seq(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup, nb_preambles, frame_type);
+    cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences = compute_nr_root_seq(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup, nb_preambles, frame_type,frequency_range);
     //cfg->prach_config.num_prach_fd_occasions_list[i].num_unused_root_sequences = ???
   }
 
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
index e97695e20185bcf536363c833b360d326979437c..6d9904c94bd6f223964163af8c47eb9823253ad8 100755
--- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
@@ -205,7 +205,7 @@ typedef struct {
   /// Random-access procedure flag
   uint8_t RA_active;
   /// Random-access window counter
-  int8_t RA_window_cnt;
+  int16_t RA_window_cnt;
   /// Random-access Msg3 size in bytes
   uint8_t RA_Msg3_size;
   /// Random-access prachMaskIndex
@@ -292,10 +292,6 @@ typedef enum channel_bandwidth_e {
     bw_100MHz = 0x32
 } channel_bandwidth_t;
 
-typedef enum frequency_range_e {
-    FR1 = 0, 
-    FR2
-} frequency_range_t;
 
 typedef struct {
   uint8_t identifier_dci_formats          ; // 0  IDENTIFIER_DCI_FORMATS:
diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
index 20e73073b9b605e80fcccad687953545944bf059..18ad3526b3cac8bfe39b81db23186dd9be08838e 100644
--- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
+++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
@@ -37,8 +37,6 @@
 #include "assertions.h"
 #include "PHY/types.h"
 #include "PHY/defs_UE.h"
-#include "openair2/LAYER2/RLC/rlc.h"
-#include "openair2/LAYER2/PDCP_v10.1.0/pdcp.h"
 #include "openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h"
 #include "executables/softmodem-common.h"
 
@@ -56,11 +54,9 @@ NR_UE_MAC_INST_t * nr_l2_init_ue(NR_UE_RRC_INST_t* rrc_inst)
       nr_rrc_mac_config_req_ue(0,0,0,NULL,rrc_inst->cell_group_config);
       
       if (IS_SOFTMODEM_NOS1){
-        if (rlc_module_init(0) != 0) {
-          LOG_I(RLC, "Problem at RLC initiation \n");
-        }
+        AssertFatal(rlc_module_init(0) == 0, "%s: Could not initialize RLC layer\n", __FUNCTION__);
         pdcp_layer_init();
-        nr_DRB_preconfiguration();
+        nr_DRB_preconfiguration(nr_ue_mac_inst->crnti);
       }
 
       // Allocate memory for ul_config_request in the mac instance. This is now a pointer and will
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
index cc26184c134ec645b11618a28e40d9d30df83bd3..4eaa6ff63790f2c0e515b875fba21f26b6b7e8e3 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
@@ -63,7 +63,6 @@
 #include "LAYER2/NR_MAC_UE/mac_proto.h"
 
 extern int64_t table_6_3_3_2_3_prachConfig_Index [256][9];
-extern const uint8_t nr_slots_per_frame[5];
 
 //extern uint8_t  nfapi_mode;
 
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c
index 36a4c5fceb76d3bd05f6b46cc8f2a0cc8823d265..0e6b6afbe660faedbc4449e696f9edd37f3bdaba 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c
@@ -171,8 +171,8 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_dci_dl_pdu_rel15_t
       rel15->BWPSize,
       rel15->BWPStart,
       rel15->SubcarrierSpacing,
-      rel15->dci_format,
-      rel15->dci_length,
+      rel15->dci_format_options[0],
+      rel15->dci_length_options[0],
       sps,
       monitoringSymbolsWithinSlot);
   #endif
@@ -213,9 +213,9 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
         // check available SS IDs
         if (pdcch_ConfigCommon->choice.setup->ra_SearchSpace){
           if (ss->searchSpaceId == *pdcch_ConfigCommon->choice.setup->ra_SearchSpace){
-            LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in Type1-PDCCH common random access search space\n");
             switch(mac->ra_state){
               case WAIT_RAR:
+              LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in Type1-PDCCH common random access search space\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_RA, ss_id);
@@ -287,7 +287,7 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
       if (ss->searchSpaceType->choice.ue_Specific){
         if(ss->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_1_And_1_1){
           // Monitors DCI 01 and 11 scrambled with C-RNTI, or CS-RNTI(s), or SP-CSI-RNTI
-          if (get_softmodem_params()->phy_test == 1 && mac->crnti > 0) {
+          if ((mac->ra_state == RA_SUCCEEDED || get_softmodem_params()->phy_test) && mac->crnti > 0) {
             LOG_D(MAC, "[DCI_CONFIG] Configure monitoring of PDCCH candidates in the user specific search space\n");
             rel15->num_dci_options = 2;
             rel15->dci_format_options[0] = NR_DL_DCI_FORMAT_1_1;
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index 5e615b49f47dd31a3c028bb2123609dc5ef0cc9a..53bc5f31b9b02823945c9d3aefbaa63f254e8fff 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -142,7 +142,6 @@ static ssb_list_info_t ssb_list;
 
 extern int bwp_id;
 extern dci_pdu_rel15_t *def_dci_pdu_rel15;
-extern const uint8_t nr_slots_per_frame[5];
 
 extern void mac_rlc_data_ind     (
 				  const module_id_t         module_idP,
@@ -971,35 +970,30 @@ int8_t nr_ue_decode_mib(module_id_t module_id,
   uint16_t frame_number_4lsb = 0;
   for (int i=0; i<4; i++)
     frame_number_4lsb |= ((extra_bits>>i)&1)<<(3-i);
-  //uint8_t half_frame_bit = ( extra_bits >> 4 ) & 0x1;               //	extra bits[4]
+  uint8_t half_frame_bit = ( extra_bits >> 4 ) & 0x1;               //	extra bits[4]
   uint8_t ssb_subcarrier_offset_msb = ( extra_bits >> 5 ) & 0x1;    //	extra bits[5]
   uint8_t ssb_subcarrier_offset = (uint8_t)mac->mib->ssb_SubcarrierOffset;
 
-  //uint32_t ssb_index = 0;    //  TODO: ssb_index should obtain from L1 in case Lssb != 64
-
   frame = frame << 4;
   frame = frame | frame_number_4lsb;
-
   if(ssb_length == 64){
-    ssb_index = ssb_index & (( extra_bits >> 2 ) & 0x1C );    //	{ extra_bits[5:7], ssb_index[2:0] }
+    for (int i=0; i<3; i++)
+      ssb_index += (((extra_bits>>(7-i))&0x01)<<(3+i));
   }else{
     if(ssb_subcarrier_offset_msb){
       ssb_subcarrier_offset = ssb_subcarrier_offset | 0x10;
     }
   }
 
-#ifdef DEBUG_MIB
-  LOG_I(MAC,"system frame number(6 MSB bits): %d\n",  mac->mib->systemFrameNumber.buf[0]);
-  LOG_I(MAC,"system frame number(with LSB): %d\n", (int)frame);
-  LOG_I(MAC,"subcarrier spacing (0=15or60, 1=30or120): %d\n", (int)mac->mib->subCarrierSpacingCommon);
-  LOG_I(MAC,"ssb carrier offset(with MSB):  %d\n", (int)ssb_subcarrier_offset);
-  LOG_I(MAC,"dmrs type A position (0=pos2,1=pos3): %d\n", (int)mac->mib->dmrs_TypeA_Position);
-  LOG_I(MAC,"pdcch config sib1:             %d\n", (int)mac->mib->pdcch_ConfigSIB1);
-  LOG_I(MAC,"cell barred (0=barred,1=notBarred): %d\n", (int)mac->mib->cellBarred);
-  LOG_I(MAC,"intra frequency reselection (0=allowed,1=notAllowed): %d\n", (int)mac->mib->intraFreqReselection);
-  LOG_I(MAC,"half frame bit(extra bits):    %d\n", (int)half_frame_bit);
-  LOG_I(MAC,"ssb index(extra bits):         %d\n", (int)ssb_index);
-#endif
+  LOG_D(MAC,"system frame number(6 MSB bits): %d\n",  mac->mib->systemFrameNumber.buf[0]);
+  LOG_D(MAC,"system frame number(with LSB): %d\n", (int)frame);
+  LOG_D(MAC,"subcarrier spacing (0=15or60, 1=30or120): %d\n", (int)mac->mib->subCarrierSpacingCommon);
+  LOG_D(MAC,"ssb carrier offset(with MSB):  %d\n", (int)ssb_subcarrier_offset);
+  LOG_D(MAC,"dmrs type A position (0=pos2,1=pos3): %d\n", (int)mac->mib->dmrs_TypeA_Position);
+  LOG_D(MAC,"cell barred (0=barred,1=notBarred): %d\n", (int)mac->mib->cellBarred);
+  LOG_D(MAC,"intra frequency reselection (0=allowed,1=notAllowed): %d\n", (int)mac->mib->intraFreqReselection);
+  LOG_D(MAC,"half frame bit(extra bits):    %d\n", (int)half_frame_bit);
+  LOG_D(MAC,"ssb index(extra bits):         %d\n", (int)ssb_index);
 
   subcarrier_spacing_t scs_ssb = scs_30kHz;      //  default for 
   //const uint32_t scs_index = 0;
@@ -1022,8 +1016,8 @@ int8_t nr_ue_decode_mib(module_id_t module_id,
   int32_t num_rbs = -1;
   int32_t num_symbols = -1;
   int32_t rb_offset = -1;
-  //LOG_I(MAC,"<<<<<<<<<configSIB1 %d index_4msb %d index_4lsb %d scs_ssb %d scs_pdcch %d switch %d ",
-  //mac->mib->pdcch_ConfigSIB1,index_4msb,index_4lsb,scs_ssb,scs_pdcch, (scs_ssb << 5)|scs_pdcch);
+  LOG_D(MAC,"<<<<<<<<<configSIB1: controlResourceSetZero %d searchSpaceZero %d scs_ssb %d scs_pdcch %d switch %d ",
+        index_4msb,index_4lsb,scs_ssb,scs_pdcch, (scs_ssb << 5)|scs_pdcch);
 
   //  type0-pdcch coreset
   switch( (scs_ssb << 5)|scs_pdcch ){
@@ -1066,7 +1060,7 @@ int8_t nr_ue_decode_mib(module_id_t module_id,
       num_rbs     = table_38213_13_4_c2[index_4msb];
       num_symbols = table_38213_13_4_c3[index_4msb];
       rb_offset   = table_38213_13_4_c4[index_4msb];
-      LOG_I(MAC,"<<<<<<<<<index_4msb %d num_rbs %d num_symb %d rb_offset %d\n",index_4msb,num_rbs,num_symbols,rb_offset );
+      LOG_D(MAC,"<<<<<<<<<index_4msb %d num_rbs %d num_symb %d rb_offset %d\n",index_4msb,num_rbs,num_symbols,rb_offset );
     }else if(min_channel_bw & bw_40MHz){
       AssertFatal(index_4msb < 10, "38.213 Table 13-6 4 MSB out of range\n");
       mac->type0_pdcch_ss_mux_pattern = 1;
@@ -1426,6 +1420,7 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in
     // check type0 from 38.213 13 if we have no CellGroupConfig
     // TODO: implementation to be completed
     if (mac->scg == NULL) {
+
       if(dl_info->ssb_index != -1){
 
         if(mac->type0_pdcch_ss_mux_pattern == 1){
@@ -1507,8 +1502,10 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in
     }
   } else if (ul_info) {
 
-    // ULSCH is handled only in phy-test mode (consistently with OAI gNB)
-    if (get_softmodem_params()->phy_test) {
+    module_id_t mod_id    = ul_info->module_id;
+    NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
+
+    if (mac->ra_state == RA_SUCCEEDED || get_softmodem_params()->phy_test) {
 
       uint8_t nb_dmrs_re_per_rb;
       uint8_t ulsch_input_buffer[MAX_ULSCH_PAYLOAD_BYTES];
@@ -1517,14 +1514,12 @@ NR_UE_L2_STATE_t nr_ue_scheduler(nr_downlink_indication_t *dl_info, nr_uplink_in
       uint32_t TBS;
       int i, N_PRB_oh;
 
-      module_id_t mod_id    = ul_info->module_id;
       uint32_t gNB_index    = ul_info->gNB_index;
       int cc_id             = ul_info->cc_id;
       frame_t rx_frame      = ul_info->frame_rx;
       slot_t rx_slot        = ul_info->slot_rx;
       frame_t frame_tx      = ul_info->frame_tx;
       slot_t slot_tx        = ul_info->slot_tx;
-      NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
       uint8_t access_mode   = SCHEDULED_ACCESS;
 
       fapi_nr_ul_config_request_t *ul_config_req = get_ul_config_request(mac, slot_tx);
@@ -3707,6 +3702,8 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
       dlsch_config_pdu_1_0->n_dmrs_cdm_groups = 2;
     /* VRB_TO_PRB_MAPPING */
     dlsch_config_pdu_1_0->vrb_to_prb_mapping = (dci->vrb_to_prb_mapping.val == 0) ? vrb_to_prb_mapping_non_interleaved:vrb_to_prb_mapping_interleaved;
+    /* MCS TABLE INDEX */
+    dlsch_config_pdu_1_0->mcs_table = (pdsch_config->mcs_Table) ? (*pdsch_config->mcs_Table + 1) : 0;
     /* MCS */
     dlsch_config_pdu_1_0->mcs = dci->mcs;
     // Basic sanity check for MCS value to check for a false or erroneous DCI
@@ -4010,7 +4007,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
             
     dl_config->number_pdus = dl_config->number_pdus + 1;
     /* TODO same calculation for MCS table as done in UL */
-    dlsch_config_pdu_1_1->mcs_table = 0;
+    dlsch_config_pdu_1_1->mcs_table = (pdsch_config->mcs_Table) ? (*pdsch_config->mcs_Table + 1) : 0;
     /*PTRS configuration */
     if(mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS != NULL) {
       valid_ptrs_setup = set_dl_ptrs_values(mac->DLbwp[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup,
@@ -4939,7 +4936,7 @@ void nr_ue_process_mac_pdu(module_id_t module_idP,
                   if (rx_lcid < NB_RB_MAX && rx_lcid >= DL_SCH_LCID_DTCH) {
 
                     mac_rlc_data_ind(module_idP,
-                                     0x1234,
+                                     mac->crnti,
                                      gNB_index,
                                      frameP,
                                      ENB_FLAG_NO,
@@ -5151,6 +5148,7 @@ nr_ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
   uint8_t ulsch_sdus[MAX_ULSCH_PAYLOAD_BYTES];
   uint16_t sdu_length_total = 0;
   //unsigned short post_padding = 0;
+  NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP);
 
   rlc_buffer_occupancy_t lcid_buffer_occupancy_old =
     0, lcid_buffer_occupancy_new = 0;
@@ -5159,23 +5157,13 @@ nr_ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
         module_idP, frameP, subframe, buflen);
   AssertFatal(CC_id == 0,
               "Transmission on secondary CCs is not supported yet\n");
-#if UE_TIMING_TRACE
-  start_meas(&UE_mac_inst[module_idP].tx_ulsch_sdu);
-#endif
-
-  //NR_UE_MAC_INST_t *nr_ue_mac_inst = get_mac_inst(0);
 
   // Check for DCCH first
   // TO DO: Multiplex in the order defined by the logical channel prioritization
   for (lcid = UL_SCH_LCID_SRB1;
        lcid < NR_MAX_NUM_LCID; lcid++) {
 
-      lcid_buffer_occupancy_old =
-    		  //TODO: Replace static value with CRNTI
-        mac_rlc_get_buffer_occupancy_ind(module_idP,
-        								 0x1234, eNB_index, frameP, //nr_ue_mac_inst->crnti
-                                         subframe, ENB_FLAG_NO,
-                                         lcid);
+      lcid_buffer_occupancy_old = mac_rlc_get_buffer_occupancy_ind(module_idP, mac->crnti, eNB_index, frameP, subframe, ENB_FLAG_NO, lcid);
       lcid_buffer_occupancy_new = lcid_buffer_occupancy_old;
 
       if(lcid_buffer_occupancy_new){
@@ -5191,17 +5179,17 @@ nr_ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
 
         while(buflen_remain > 0 && lcid_buffer_occupancy_new){
 
-        //TODO: Replace static value with CRNTI
         sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
-        						0x1234, eNB_index, //nr_ue_mac_inst->crnti
+                                mac->crnti,
+                                eNB_index,
                                 frameP,
                                 ENB_FLAG_NO,
                                 MBMS_FLAG_NO,
                                 lcid,
                                 buflen_remain,
                                 (char *)&ulsch_sdus[sdu_length_total],0,
-                                0
-                                                );
+                                0);
+
         AssertFatal(buflen_remain >= sdu_lengths[num_sdus],
                     "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n",
                     lcid, sdu_lengths[num_sdus], buflen_remain);
@@ -5217,14 +5205,13 @@ nr_ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
         }
 
         /* Get updated BO after multiplexing this PDU */
-        //TODO: Replace static value with CRNTI
-
-        lcid_buffer_occupancy_new =
-          mac_rlc_get_buffer_occupancy_ind(module_idP,
-                                           0x1234, //nr_ue_mac_inst->crnti
-                                           eNB_index, frameP,
-                                           subframe, ENB_FLAG_NO,
-                                           lcid);
+        lcid_buffer_occupancy_new = mac_rlc_get_buffer_occupancy_ind(module_idP,
+                                                                     mac->crnti,
+                                                                     eNB_index,
+                                                                     frameP,
+                                                                     subframe,
+                                                                     ENB_FLAG_NO,
+                                                                     lcid);
         buflen_remain =
                   buflen - (total_rlc_pdu_header_len + sdu_length_total + MAX_RLC_SDU_SUBHEADER_SIZE);
         }
@@ -5240,7 +5227,7 @@ nr_ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
                                          sdu_lengths, // sdu length
                                          sdu_lcids, // sdu lcid
                                          0, // power_headroom
-                                         0, // crnti
+                                         mac->crnti, // crnti
                                          0, // truncated_bsr
                                          0, // short_bsr
                                          0, // long_bsr
diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c
index 5dfdde0816c348dcc485b844e49651f4b071de1a..e24ea915cc4dfb8579fb725d63823b7801b58133 100644
--- a/openair2/LAYER2/NR_MAC_gNB/config.c
+++ b/openair2/LAYER2/NR_MAC_gNB/config.c
@@ -124,6 +124,9 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
     }
   }
 
+  uint32_t band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
+  frequency_range_t frequency_range = band<100?FR1:FR2;
+
   lte_frame_type_t frame_type;
   get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing, &frame_type);
   RC.nrmac[Mod_idP]->common_channels[0].frame_type = frame_type;
@@ -213,7 +216,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
     cfg->prach_config.num_prach_fd_occasions_list[i].prach_zero_corr_conf.value = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig;
     cfg->prach_config.num_prach_fd_occasions_list[i].prach_zero_corr_conf.tl.tag = NFAPI_NR_CONFIG_PRACH_ZERO_CORR_CONF_TAG;
     cfg->num_tlv++;
-    cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences.value = compute_nr_root_seq(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup,nb_preambles, frame_type);
+    cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences.value = compute_nr_root_seq(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup,nb_preambles, frame_type, frequency_range);
     cfg->prach_config.num_prach_fd_occasions_list[i].num_root_sequences.tl.tag = NFAPI_NR_CONFIG_NUM_ROOT_SEQUENCES_TAG;
     cfg->num_tlv++;
     cfg->prach_config.num_prach_fd_occasions_list[i].num_unused_root_sequences.value = 1;
@@ -252,8 +255,8 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
       cfg->ssb_table.ssb_mask_list[0].ssb_mask.value = 0;
       cfg->ssb_table.ssb_mask_list[1].ssb_mask.value = 0;
       for (i=0; i<4; i++) {
-        cfg->ssb_table.ssb_mask_list[0].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i+4]<<i*8);
-        cfg->ssb_table.ssb_mask_list[1].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[i]<<i*8);
+        cfg->ssb_table.ssb_mask_list[0].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[3-i]<<i*8);
+        cfg->ssb_table.ssb_mask_list[1].ssb_mask.value += (scc->ssb_PositionsInBurst->choice.longBitmap.buf[7-i]<<i*8);
       }
       break;
     default:
@@ -311,6 +314,7 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
 
 
 
+extern uint16_t sl_ahead;
 int rrc_mac_config_req_gNB(module_id_t Mod_idP, 
 			   int ssb_SubcarrierOffset,
                            int pdsch_AntennaPorts,
@@ -324,6 +328,30 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
   if (scc != NULL ) {
     AssertFatal((scc->ssb_PositionsInBurst->present > 0) && (scc->ssb_PositionsInBurst->present < 4), "SSB Bitmap type %d is not valid\n",scc->ssb_PositionsInBurst->present);
 
+    /* dimension UL_tti_req_ahead for number of slots in frame */
+    const uint8_t slots_per_frame[5] = {10, 20, 40, 80, 160};
+    const int n = slots_per_frame[*scc->ssbSubcarrierSpacing];
+    RC.nrmac[Mod_idP]->UL_tti_req_ahead[0] = calloc(n, sizeof(nfapi_nr_ul_tti_request_t));
+    AssertFatal(RC.nrmac[Mod_idP]->UL_tti_req_ahead[0],
+                "could not allocate memory for RC.nrmac[]->UL_tti_req_ahead[]\n");
+    /* fill in slot/frame numbers: slot is fixed, frame will be updated by
+     * scheduler */
+    for (int i = 0; i < n; ++i) {
+      nfapi_nr_ul_tti_request_t *req = &RC.nrmac[Mod_idP]->UL_tti_req_ahead[0][i];
+      /* consider that scheduler runs sl_ahead: the first sl_ahead slots are
+       * already "in the past" and thus we put frame 1 instead of 0!  Note that
+       * variable sl_ahead seems to not be correctly initialized, but I leave
+       * it for information purposes here (the fix would always put 0, what
+       * happens now, too) */
+      req->SFN = i < sl_ahead;
+      req->Slot = i;
+    }
+
+    RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL =
+        calloc(n * 275, sizeof(uint16_t));
+    AssertFatal(RC.nrmac[Mod_idP]->common_channels[0].vrb_map_UL,
+                "could not allocate memory for RC.nrmac[]->common_channels[0].vrb_map_UL\n");
+
     LOG_I(MAC,"Configuring common parameters from NR ServingCellConfig\n");
 
     config_common(Mod_idP,
@@ -371,6 +399,12 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
                   bwpList->list.count);
       const int bwp_id = 1;
       UE_info->UE_sched_ctrl[UE_id].active_bwp = bwpList->list.array[bwp_id - 1];
+      struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList =
+          secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList;
+      AssertFatal(ubwpList->list.count == 1,
+                  "uplinkBWP_ToAddModList has %d BWP!\n",
+                  ubwpList->list.count);
+      UE_info->UE_sched_ctrl[UE_id].active_ubwp = ubwpList->list.array[bwp_id - 1];
       LOG_I(PHY,"Added new UE_id %d/%x with initial secondaryCellGroup\n",UE_id,rnti);
     } else if (add_ue == 1 && !get_softmodem_params()->phy_test) {
       /* TODO: should check for free RA process */
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
index 31a85180a2532b1b38fce7754b71c430b7e838c0..d557db2851bfdcfc87a988cb921ad11a73c40b84 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
@@ -32,9 +32,7 @@
 
 #include "assertions.h"
 
-#include "LAYER2/MAC/mac.h"
 #include "NR_MAC_COMMON/nr_mac_extern.h"
-#include "LAYER2/MAC/mac_proto.h"
 #include "NR_MAC_gNB/mac_proto.h"
 
 #include "common/utils/LOG/log.h"
@@ -51,15 +49,11 @@
 #include "openair1/PHY/defs_gNB.h"
 #include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h"
 
-//Agent-related headers
-#include "flexran_agent_extern.h"
-#include "flexran_agent_mac.h"
-
 #include "intertask_interface.h"
 
 #include "executables/softmodem-common.h"
+#include "nfapi/oai_integration/vendor_ext.h"
 
-const uint8_t slots_per_frame[5] = {10, 20, 40, 80, 160};
 uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 };
 
 void clear_mac_stats(gNB_MAC_INST *gNB) {
@@ -92,9 +86,12 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
                                 int CC_idP,
                                 frame_t frameP,
                                 sub_frame_t slotP){
+  NR_ServingCellConfigCommon_t *scc = gNB->common_channels->ServingCellConfigCommon;
+  const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
 
   nfapi_nr_dl_tti_request_t    *DL_req = &gNB->DL_req[0];
-  nfapi_nr_ul_tti_request_t    *UL_tti_req = &gNB->UL_tti_req[0];
+  nfapi_nr_ul_tti_request_t    *future_ul_tti_req =
+      &gNB->UL_tti_req_ahead[CC_idP][(slotP + num_slots - 1) % num_slots];
   nfapi_nr_ul_dci_request_t    *UL_dci_req = &gNB->UL_dci_req[0];
   nfapi_nr_tx_data_request_t   *TX_req = &gNB->TX_req[0];
 
@@ -112,12 +109,17 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
     UL_dci_req[CC_idP].Slot                        = slotP;
     UL_dci_req[CC_idP].numPdus                     = 0;
 
-    UL_tti_req[CC_idP].SFN                         = frameP;
-    UL_tti_req[CC_idP].Slot                        = slotP;
-    UL_tti_req[CC_idP].n_pdus                      = 0;
-    UL_tti_req[CC_idP].n_ulsch                     = 0;
-    UL_tti_req[CC_idP].n_ulcch                     = 0;
-    UL_tti_req[CC_idP].n_group                     = 0;
+    /* advance last round's future UL_tti_req to be ahead of current frame/slot */
+    future_ul_tti_req->SFN = (slotP == 0 ? frameP : frameP + 1) % 1024;
+    /* future_ul_tti_req->Slot is fixed! */
+    future_ul_tti_req->n_pdus = 0;
+    future_ul_tti_req->n_ulsch = 0;
+    future_ul_tti_req->n_ulcch = 0;
+    future_ul_tti_req->n_group = 0;
+
+    /* UL_tti_req is a simple pointer into the current UL_tti_req_ahead, i.e.,
+     * it walks over UL_tti_req_ahead in a circular fashion */
+    gNB->UL_tti_req[CC_idP] = &gNB->UL_tti_req_ahead[CC_idP][slotP];
 
     TX_req[CC_idP].Number_of_PDUs                  = 0;
 
@@ -285,58 +287,6 @@ void schedule_nr_SRS(module_id_t module_idP, frame_t frameP, sub_frame_t subfram
 */
 
 
-/*
-void copy_nr_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
-{
-  int CC_id;
-  gNB_MAC_INST *mac = RC.nrmac[module_idP];
-
-  for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
-
-    nfapi_ul_config_request_t *ul_req                 = &mac->UL_tti_req[CC_id];
-
-    *ul_req = *ul_req_tmp;
-
-    // Restore the pointer
-    ul_req->ul_config_request_body.ul_config_pdu_list = ul_req_pdu;
-    ul_req->sfn_sf                                    = (frameP<<7) + slotP;
-    ul_req_tmp->ul_config_request_body.number_of_pdus = 0;
-
-    if (ul_req->ul_config_request_body.number_of_pdus>0)
-      {
-        LOG_D(PHY, "%s() active NOW (frameP:%d slotP:%d) pdus:%d\n", __FUNCTION__, frameP, slotP, ul_req->ul_config_request_body.number_of_pdus);
-      }
-
-    memcpy((void*)ul_req->ul_config_request_body.ul_config_pdu_list,
-     (void*)ul_req_tmp->ul_config_request_body.ul_config_pdu_list,
-     ul_req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t));
-  }
-}
-*/
-
-void nr_schedule_pusch(int Mod_idP,
-                       int UE_id,
-                       int num_slots_per_tdd,
-                       int ul_slots,
-                       frame_t frameP,
-                       sub_frame_t slotP) {
-
-  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
-  NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info;
-  int k = slotP + ul_slots - num_slots_per_tdd;
-  NR_sched_pusch *pusch = &UE_info->UE_sched_ctrl[UE_id].sched_pusch[k];
-  if ((pusch->active == true) && (frameP == pusch->frame) && (slotP == pusch->slot)) {
-    UL_tti_req->SFN = pusch->frame;
-    UL_tti_req->Slot = pusch->slot;
-    UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
-    UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
-    UL_tti_req->pdus_list[UL_tti_req->n_pdus].pusch_pdu = pusch->pusch_pdu;
-    UL_tti_req->n_pdus+=1;
-    memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pusch[k],
-           0, sizeof(NR_sched_pusch));
-  }
-}
-
 bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot) {
   return (bitmap >> slot) & 0x01;
 }
@@ -355,7 +305,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
 
   gNB_MAC_INST *gNB = RC.nrmac[module_idP];
   NR_UE_info_t *UE_info = &gNB->UE_info;
-  NR_UE_sched_ctrl_t *ue_sched_ctl = &UE_info->UE_sched_ctrl[UE_id];
   NR_COMMON_channels_t *cc = gNB->common_channels;
   NR_ServingCellConfigCommon_t        *scc     = cc->ServingCellConfigCommon;
   NR_TDD_UL_DL_Pattern_t *tdd_pattern = &scc->tdd_UL_DL_ConfigurationCommon->pattern1;
@@ -397,7 +346,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
       AssertFatal(1==0,"Undefined tdd period %ld\n", scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity);
   }
 
-  int num_slots_per_tdd = (slots_per_frame[*scc->ssbSubcarrierSpacing])/nb_periods_per_frame;
+  int num_slots_per_tdd = (nr_slots_per_frame[*scc->ssbSubcarrierSpacing])/nb_periods_per_frame;
 
   const int nr_ulmix_slots = tdd_pattern->nrofUplinkSlots + (tdd_pattern->nrofUplinkSymbols!=0);
 
@@ -425,7 +374,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
 
     // clear vrb_maps
     memset(cc[CC_id].vrb_map, 0, sizeof(uint16_t) * 275);
-    memset(cc[CC_id].vrb_map_UL, 0, sizeof(uint16_t) * 275);
+    // clear last scheduled slot's content (only)!
+    const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
+    const int last_slot = (slot + num_slots - 1) % num_slots;
+    uint16_t *vrb_map_UL = cc[CC_id].vrb_map_UL;
+    memset(&vrb_map_UL[last_slot * 275], 0, sizeof(uint16_t) * 275);
 
     clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame, slot);
   }
@@ -435,45 +388,43 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
 
 
   // This schedules MIB
-  schedule_nr_mib(module_idP, frame, slot, slots_per_frame[*scc->ssbSubcarrierSpacing]);
+  schedule_nr_mib(module_idP, frame, slot, nr_slots_per_frame[*scc->ssbSubcarrierSpacing]);
 
   // This schedule PRACH if we are not in phy_test mode
-  if (get_softmodem_params()->phy_test == 0)
-    schedule_nr_prach(module_idP, frame, slot);
+  if (get_softmodem_params()->phy_test == 0) {
+    /* we need to make sure that resources for PRACH are free. To avoid that
+       e.g. PUSCH has already been scheduled, make sure we schedule before
+       anything else: below, we simply assume an advance one frame (minus one
+       slot, because otherwise we would allocate the current slot in
+       UL_tti_req_ahead), but be aware that, e.g., K2 is allowed to be larger
+       (schedule_nr_prach will assert if resources are not free). */
+    const sub_frame_t n_slots_ahead = nr_slots_per_frame[*scc->ssbSubcarrierSpacing] - 1;
+    const frame_t f = (frame + (slot + n_slots_ahead) / nr_slots_per_frame[*scc->ssbSubcarrierSpacing]) % 1024;
+    const sub_frame_t s = (slot + n_slots_ahead) % nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
+    schedule_nr_prach(module_idP, f, s);
+  }
 
   // This schedule SR
   // TODO
 
   // This schedule CSI measurement reporting
   if (UE_info->active[UE_id])
-    nr_csi_meas_reporting(module_idP, UE_id, frame, slot, num_slots_per_tdd, nr_ulmix_slots, slots_per_frame[*scc->ssbSubcarrierSpacing]);
+    nr_csi_meas_reporting(module_idP, UE_id, frame, slot, num_slots_per_tdd, nr_ulmix_slots, nr_slots_per_frame[*scc->ssbSubcarrierSpacing]);
 
   // This schedule RA procedure if not in phy_test mode
   // Otherwise already consider 5G already connected
-  RC.nrmac[module_idP]->current_slot=slot;
   if (get_softmodem_params()->phy_test == 0) {
     nr_schedule_RA(module_idP, frame, slot);
-    nr_schedule_reception_msg3(module_idP, 0, frame, slot);
-
   }
 
   // This schedules the DCI for Uplink and subsequently PUSCH
-
-  // The decision about whether to schedule is done for each UE independently
-  // inside
-  if (UE_info->active[UE_id] && slot < 10) {
-
-    int tda = 1; // time domain assignment hardcoded for now
-    schedule_fapi_ul_pdu(module_idP, frame, slot, num_slots_per_tdd, nr_ulmix_slots, tda, ulsch_in_slot_bitmap);
-    nr_schedule_pusch(module_idP, UE_id, num_slots_per_tdd, nr_ulmix_slots, frame, slot);
+  if (slot < 10) {
+    nr_schedule_ulsch(module_idP, frame, slot, num_slots_per_tdd, nr_ulmix_slots, ulsch_in_slot_bitmap);
   }
 
-
-  if (UE_info->active[UE_id]
-      && (is_xlsch_in_slot(dlsch_in_slot_bitmap, slot % num_slots_per_tdd))
+  // This schedules the DCI for Downlink and PDSCH
+  if (is_xlsch_in_slot(dlsch_in_slot_bitmap, slot % num_slots_per_tdd)
       && slot < 10) {
-
-    ue_sched_ctl->current_harq_pid = slot % num_slots_per_tdd;
     nr_schedule_ue_spec(module_idP, frame, slot, num_slots_per_tdd);
   }
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
index 66dcfcff86ba5f2c0f3e470ec8b0f2478f2e1cc8..e15963f35502b9d493eb16d166645d4817f5725f 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
@@ -43,6 +43,7 @@
 
 extern RAN_CONTEXT_t RC;
 extern const uint8_t nr_slots_per_frame[5];
+extern uint16_t sl_ahead;
 
 uint8_t DELTA[4]= {2,3,4,6};
 
@@ -62,19 +63,19 @@ int16_t ssb_index_from_prach(module_id_t module_idP,
   nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0];
 
   uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex;
-	uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
+  uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
   
-	uint8_t total_RApreambles = 64;
-	if( scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles != NULL)
+  uint8_t total_RApreambles = 64;
+  if( scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles != NULL)
     total_RApreambles = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->totalNumberOfRA_Preambles;	
   
-	float  num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];	
+  float  num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];	
   uint16_t start_symbol_index = 0;
   uint8_t mu,N_dur=0,N_t_slot=0,start_symbol = 0, temp_start_symbol = 0, N_RA_slot=0;
   uint16_t format,RA_sfn_index = -1;
-	uint8_t config_period = 1;
+  uint8_t config_period = 1;
   uint16_t prach_occasion_id = -1;
-	uint8_t num_active_ssb = cc->num_active_ssb;
+  uint8_t num_active_ssb = cc->num_active_ssb;
 
   if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing)
     mu = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing;
@@ -95,45 +96,51 @@ int16_t ssb_index_from_prach(module_id_t module_idP,
 			       &N_RA_slot,
 			       &config_period);
   uint8_t index = 0,slot_index = 0;
-	for (slot_index = 0;slot_index < N_RA_slot; slot_index++) {
+  for (slot_index = 0;slot_index < N_RA_slot; slot_index++) {
     if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
        if((mu == 1) || (mu == 3))
          slot_index = 1;  //For scs = 30khz and 120khz
     }
     for (int i=0; i< N_t_slot; i++) {
       temp_start_symbol = (start_symbol + i * N_dur + 14 * slot_index) % 14;
-		  if(symbol == temp_start_symbol) {
-			  start_symbol_index = i;
-		    break;
-		  }
-	  }
-	}
+      if(symbol == temp_start_symbol) {
+        start_symbol_index = i;
+        break;
+      }
+    }
+  }
   if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
     if((mu == 1) || (mu == 3))
       slot_index = 0;  //For scs = 30khz and 120khz
   }
-  
-//  prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index; 
- prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period)*cc->total_prach_occasions_per_config_period) + (RA_sfn_index + slot_index) * N_t_slot * fdm + start_symbol_index * fdm + freq_index; 
-//one RO is shared by one or more SSB
- if(num_ssb_per_RO <= 1 )
-   index = (int) (prach_occasion_id / (int)(1/num_ssb_per_RO)) % num_active_ssb;
-//one SSB have more than one continuous RO
- else if ( num_ssb_per_RO > 1) {
-	 index = (prach_occasion_id * (int)num_ssb_per_RO)% num_active_ssb ;
-   for(int j = 0;j < num_ssb_per_RO;j++) {
-     if(preamble_index <  (((j+1) * total_RApreambles) / num_ssb_per_RO))
-      index = index + j;
-	  }		
-	}
-
-  LOG_D(MAC, "Frame %d, Slot %d: Prach Occasion id = %d ssb per RO = %f number of active SSB %u index = %d fdm %u symbol index %u freq_index %u total_RApreambles %u\n", frameP, slotP, prach_occasion_id, num_ssb_per_RO, num_active_ssb, index, fdm, start_symbol_index, freq_index, total_RApreambles);
+
+  //  prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index; 
+  prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period)*cc->total_prach_occasions_per_config_period) +
+                      (RA_sfn_index + slot_index) * N_t_slot * fdm + start_symbol_index * fdm + freq_index; 
+
+  //one RO is shared by one or more SSB
+  if(num_ssb_per_RO <= 1 )
+    index = (int) (prach_occasion_id / (int)(1/num_ssb_per_RO)) % num_active_ssb;
+  //one SSB have more than one continuous RO
+  else if ( num_ssb_per_RO > 1) {
+    index = (prach_occasion_id * (int)num_ssb_per_RO)% num_active_ssb ;
+    for(int j = 0;j < num_ssb_per_RO;j++) {
+      if(preamble_index <  (((j+1) * total_RApreambles) / num_ssb_per_RO))
+        index = index + j;
+    }
+  }
+
+  LOG_D(MAC, "Frame %d, Slot %d: Prach Occasion id = %d ssb per RO = %f number of active SSB %u index = %d fdm %u symbol index %u freq_index %u total_RApreambles %u\n", 
+        frameP, slotP, prach_occasion_id, num_ssb_per_RO, num_active_ssb, index, fdm, start_symbol_index, freq_index, total_RApreambles);
+
   return index;
 }
+
+
 //Compute Total active SSBs and RO available
 void find_SSB_and_RO_available(module_id_t module_idP) {
 
-	gNB_MAC_INST *gNB = RC.nrmac[module_idP];
+  gNB_MAC_INST *gNB = RC.nrmac[module_idP];
   NR_COMMON_channels_t *cc = &gNB->common_channels[0];
   NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
   nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0];
@@ -141,7 +148,7 @@ void find_SSB_and_RO_available(module_id_t module_idP) {
   uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex;
   uint8_t mu,N_dur=0,N_t_slot=0,start_symbol=0,N_RA_slot = 0;
   uint16_t format,N_RA_sfn = 0,unused_RA_occasion,repetition = 0;
-	uint8_t num_active_ssb = 0;
+  uint8_t num_active_ssb = 0;
   uint8_t max_association_period = 1;
 
   if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing)
@@ -151,190 +158,190 @@ void find_SSB_and_RO_available(module_id_t module_idP) {
 
   // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4
   get_nr_prach_occasion_info_from_index(config_index,
-                                    scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
-                                    mu,
-                                    cc->frame_type,
-                                    &format,
-                                    &start_symbol,
-                                    &N_t_slot,
-                                    &N_dur,
-                                    &N_RA_slot,
-	                                 &N_RA_sfn,
-                                   &max_association_period);
+                                        scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
+                                        mu,
+                                        cc->frame_type,
+                                        &format,
+                                        &start_symbol,
+                                        &N_t_slot,
+                                        &N_dur,
+                                        &N_RA_slot,
+                                        &N_RA_sfn,
+                                        &max_association_period);
 
   float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];	
-	uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
+  uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
   uint64_t L_ssb = (((uint64_t) cfg->ssb_table.ssb_mask_list[0].ssb_mask.value)<<32) | cfg->ssb_table.ssb_mask_list[1].ssb_mask.value ;
-	uint32_t total_RA_occasions = N_RA_sfn * N_t_slot * N_RA_slot * fdm;
+  uint32_t total_RA_occasions = N_RA_sfn * N_t_slot * N_RA_slot * fdm;
 
-	for(int i = 0;i < 64;i++) {
+  for(int i = 0;i < 64;i++) {
     if ((L_ssb >> (63-i)) & 0x01) { // only if the bit of L_ssb at current ssb index is 1
       cc->ssb_index[num_active_ssb] = i; 
-		  num_active_ssb++;
+      num_active_ssb++;
     }
-	}	
+  }
 
-	for(int i = 1; (1 << (i-1)) <= max_association_period;i++) {
+  for(int i = 1; (1 << (i-1)) <= max_association_period;i++) {
     if(total_RA_occasions >= (int) (num_active_ssb/num_ssb_per_RO)) {
-		  repetition = (uint16_t)((total_RA_occasions * num_ssb_per_RO )/num_active_ssb);
-		  break;
-		} 
-		else { 
-		  total_RA_occasions = total_RA_occasions * i;
-		  cc->max_association_period = i;
-		} 
-	}
+      repetition = (uint16_t)((total_RA_occasions * num_ssb_per_RO )/num_active_ssb);
+      break;
+    }
+    else {
+      total_RA_occasions = total_RA_occasions * i;
+      cc->max_association_period = i;
+    }
+  }
   if(cc->max_association_period == 0)
-			cc->max_association_period = 1;
-
- unused_RA_occasion = total_RA_occasions - (int)((num_active_ssb * repetition)/num_ssb_per_RO);
- cc->total_prach_occasions = total_RA_occasions - unused_RA_occasion;
- cc->num_active_ssb = num_active_ssb;
+    cc->max_association_period = 1;
 
-  LOG_I(MAC, "Total available RO %d, num of active SSB %d: unused RO = %d max_association_period %u N_RA_sfn %u \n", cc->total_prach_occasions, cc->num_active_ssb, unused_RA_occasion, max_association_period, N_RA_sfn);
+  unused_RA_occasion = total_RA_occasions - (int)((num_active_ssb * repetition)/num_ssb_per_RO);
+  cc->total_prach_occasions = total_RA_occasions - unused_RA_occasion;
+  cc->num_active_ssb = num_active_ssb;
 
+  LOG_I(MAC, "Total available RO %d, num of active SSB %d: unused RO = %d max_association_period %u N_RA_sfn %u \n",
+        cc->total_prach_occasions, cc->num_active_ssb, unused_RA_occasion, max_association_period, N_RA_sfn);
 }		
 		
-void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) {
-
+void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
+{
   gNB_MAC_INST *gNB = RC.nrmac[module_idP];
   NR_COMMON_channels_t *cc = gNB->common_channels;
   NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
-  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req[0];
+  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[0][slotP];
   nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0];
 
   if (is_nr_UL_slot(scc,slotP)) {
-  uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex;
-  uint8_t mu,N_dur,N_t_slot,start_symbol = 0,N_RA_slot;
-  uint16_t RA_sfn_index = -1;
-	uint8_t config_period = 1;
-  uint16_t format;
-  int slot_index = 0;
-  uint16_t prach_occasion_id = -1;
-
-  if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing)
-    mu = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing;
-  else
-    mu = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
-
-  uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
-  // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4
-  if ( get_nr_prach_info_from_index(config_index,
-                                    (int)frameP,
-                                    (int)slotP,
-                                    scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
-                                    mu,
-                                    cc->frame_type,
-                                    &format,
-                                    &start_symbol,
-                                    &N_t_slot,
-                                    &N_dur,
-                                    &RA_sfn_index,
-                                    &N_RA_slot,
-																		&config_period) ) {
-    uint16_t format0 = format&0xff;      // first column of format from table
-    uint16_t format1 = (format>>8)&0xff; // second column of format from table
-
-    if (N_RA_slot > 1) { //more than 1 PRACH slot in a subframe
-      if (slotP%2 == 1){
-	      slot_index = 1;
-      }	
-      else {
-	      slot_index = 0;
-			}	
-    }else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
-       slot_index = 0;
-    }
-
+    uint8_t config_index = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.prach_ConfigurationIndex;
+    uint8_t mu,N_dur,N_t_slot,start_symbol = 0,N_RA_slot;
+    uint16_t RA_sfn_index = -1;
+    uint8_t config_period = 1;
+    uint16_t format;
+    int slot_index = 0;
+    uint16_t prach_occasion_id = -1;
+
+    if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing)
+      mu = *scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing;
+    else
+      mu = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
+
+    uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
+    // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4
+    if ( get_nr_prach_info_from_index(config_index,
+                                      (int)frameP,
+                                      (int)slotP,
+                                      scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
+                                      mu,
+                                      cc->frame_type,
+                                      &format,
+                                      &start_symbol,
+                                      &N_t_slot,
+                                      &N_dur,
+                                      &RA_sfn_index,
+                                      &N_RA_slot,
+                                      &config_period) ) {
+
+      uint16_t format0 = format&0xff;      // first column of format from table
+      uint16_t format1 = (format>>8)&0xff; // second column of format from table
+
+      if (N_RA_slot > 1) { //more than 1 PRACH slot in a subframe
+        if (slotP%2 == 1)
+          slot_index = 1;
+        else
+          slot_index = 0;
+      }else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
+        slot_index = 0;
+      }
 
-    UL_tti_req->SFN = frameP;
-    UL_tti_req->Slot = slotP;
-    for (int fdm_index=0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion
-    for (int td_index=0; td_index<N_t_slot; td_index++) {
-
-      prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) + (RA_sfn_index + slot_index) * N_t_slot * fdm + td_index * fdm + fdm_index;
-			if((prach_occasion_id < cc->total_prach_occasions) && (td_index == 0)){  
-
-      UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE;
-      UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t);
-      nfapi_nr_prach_pdu_t  *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu;
-      memset(prach_pdu,0,sizeof(nfapi_nr_prach_pdu_t));
-      UL_tti_req->n_pdus+=1;
-
-      // filling the prach fapi structure
-      prach_pdu->phys_cell_id = *scc->physCellId;
-      prach_pdu->num_prach_ocas = N_t_slot;
-      prach_pdu->prach_start_symbol = start_symbol;
-      prach_pdu->num_ra = fdm_index;
-      prach_pdu->num_cs = get_NCS(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig,
-                                  format0,
-                                  scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig);
-      
-      LOG_D(MAC, "Frame %d, Slot %d: Prach Occasion id = %u  fdm index = %u start symbol = %u slot index = %u subframe index = %u \n",
-	    frameP, slotP,
-	    prach_occasion_id, prach_pdu->num_ra,
-	    prach_pdu->prach_start_symbol,
-	    slot_index, RA_sfn_index);
-      // SCF PRACH PDU format field does not consider A1/B1 etc. possibilities
-      // We added 9 = A1/B1 10 = A2/B2 11 A3/B3
-      if (format1!=0xff) {
-        switch(format0) {
-          case 0xa1:
-            prach_pdu->prach_format = 11;
-            break;
-          case 0xa2:
-            prach_pdu->prach_format = 12;
-            break;
-          case 0xa3:
-            prach_pdu->prach_format = 13;
-            break;
-        default:
-          AssertFatal(1==0,"Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
+      UL_tti_req->SFN = frameP;
+      UL_tti_req->Slot = slotP;
+      for (int fdm_index=0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion
+        for (int td_index=0; td_index<N_t_slot; td_index++) {
+
+          prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) +
+                              (RA_sfn_index + slot_index) * N_t_slot * fdm + td_index * fdm + fdm_index;
+
+          if((prach_occasion_id < cc->total_prach_occasions) && (td_index == 0)){
+
+            UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE;
+            UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t);
+            nfapi_nr_prach_pdu_t  *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu;
+            memset(prach_pdu,0,sizeof(nfapi_nr_prach_pdu_t));
+            UL_tti_req->n_pdus+=1;
+
+            // filling the prach fapi structure
+            prach_pdu->phys_cell_id = *scc->physCellId;
+            prach_pdu->num_prach_ocas = N_t_slot;
+            prach_pdu->prach_start_symbol = start_symbol;
+            prach_pdu->num_ra = fdm_index;
+            prach_pdu->num_cs = get_NCS(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig,
+                                        format0,
+                                        scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig);
+
+            LOG_D(MAC, "Frame %d, Slot %d: Prach Occasion id = %u  fdm index = %u start symbol = %u slot index = %u subframe index = %u \n",
+                  frameP, slotP,
+                  prach_occasion_id, prach_pdu->num_ra,
+                  prach_pdu->prach_start_symbol,
+                  slot_index, RA_sfn_index);
+            // SCF PRACH PDU format field does not consider A1/B1 etc. possibilities
+            // We added 9 = A1/B1 10 = A2/B2 11 A3/B3
+            if (format1!=0xff) {
+              switch(format0) {
+                case 0xa1:
+                  prach_pdu->prach_format = 11;
+                  break;
+                case 0xa2:
+                  prach_pdu->prach_format = 12;
+                  break;
+                case 0xa3:
+                  prach_pdu->prach_format = 13;
+                  break;
+              default:
+                AssertFatal(1==0,"Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
+              }
+            }
+            else{
+              switch(format0) {
+                case 0:
+                  prach_pdu->prach_format = 0;
+                  break;
+                case 1:
+                  prach_pdu->prach_format = 1;
+                  break;
+                case 2:
+                  prach_pdu->prach_format = 2;
+                  break;
+                case 3:
+                  prach_pdu->prach_format = 3;
+                  break;
+                case 0xa1:
+                  prach_pdu->prach_format = 4;
+                  break;
+                case 0xa2:
+                  prach_pdu->prach_format = 5;
+                  break;
+                case 0xa3:
+                  prach_pdu->prach_format = 6;
+                  break;
+                case 0xb1:
+                  prach_pdu->prach_format = 7;
+                  break;
+                case 0xb4:
+                  prach_pdu->prach_format = 8;
+                  break;
+                case 0xc0:
+                  prach_pdu->prach_format = 9;
+                  break;
+                case 0xc2:
+                  prach_pdu->prach_format = 10;
+                  break;
+              default:
+                AssertFatal(1==0,"Invalid PRACH format");
+              }
+            }
+          }
         }
       }
-      else{
-        switch(format0) {
-          case 0:
-            prach_pdu->prach_format = 0;
-            break;
-          case 1:
-            prach_pdu->prach_format = 1;
-            break;
-          case 2:
-            prach_pdu->prach_format = 2;
-            break;
-          case 3:
-            prach_pdu->prach_format = 3;
-            break;
-          case 0xa1:
-            prach_pdu->prach_format = 4;
-            break;
-          case 0xa2:
-            prach_pdu->prach_format = 5;
-            break;
-          case 0xa3:
-            prach_pdu->prach_format = 6;
-            break;
-          case 0xb1:
-            prach_pdu->prach_format = 7;
-            break;
-          case 0xb4:
-            prach_pdu->prach_format = 8;
-            break;
-          case 0xc0:
-            prach_pdu->prach_format = 9;
-            break;
-          case 0xc2:
-            prach_pdu->prach_format = 10;
-            break;
-        default:
-          AssertFatal(1==0,"Invalid PRACH format");
-        }
-      }		
-     }
     }
-   }
-  }
   }
 }
 
@@ -363,7 +370,14 @@ void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot,
   uint8_t start_next_period = (rach_slot-(rach_slot%tdd_period_slot)+tdd_period_slot)%nr_slots_per_frame[mu];
   *msg2_slot = start_next_period + last_dl_slot_period; // initializing scheduling of slot to next mixed (or last dl) slot
   *msg2_frame = (*msg2_slot>(rach_slot))? rach_frame : (rach_frame +1);
- 
+
+  // we can't schedule msg2 before sl_ahead since prach
+  int eff_slot = *msg2_slot+(*msg2_frame-rach_frame)*nr_slots_per_frame[mu];
+  if ((eff_slot-rach_slot)<=sl_ahead) {
+    *msg2_slot = (*msg2_slot+tdd_period_slot)%nr_slots_per_frame[mu];
+    *msg2_frame = (*msg2_slot>(rach_slot))? rach_frame : (rach_frame +1);
+  }
+
   switch(response_window){
     case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl1:
       slot_window = 1;
@@ -396,12 +410,11 @@ void nr_schedule_msg2(uint16_t rach_frame, uint16_t rach_slot,
 
   // slot and frame limit to transmit msg2 according to response window
   uint8_t slot_limit = (rach_slot + slot_window)%nr_slots_per_frame[mu];
-  //uint8_t frame_limit = (slot_limit>(rach_slot))? rach_frame : (rach_frame +1);
-
+  uint8_t frame_limit = (slot_limit>(rach_slot))? rach_frame : (rach_frame +1);
 
   // go to previous slot if the current scheduled slot is beyond the response window
   // and if the slot is not among the PDCCH monitored ones (38.213 10.1)
-  while ((*msg2_slot>slot_limit) || ((*msg2_frame*nr_slots_per_frame[mu]+*msg2_slot-monitoring_offset)%monitoring_slot_period !=0))  {
+  while (((*msg2_slot>slot_limit)&&(*msg2_frame>frame_limit)) || ((*msg2_frame*nr_slots_per_frame[mu]+*msg2_slot-monitoring_offset)%monitoring_slot_period !=0))  {
     if((*msg2_slot%tdd_period_slot) > 0)
       (*msg2_slot)--;
     else
@@ -562,7 +575,9 @@ void nr_schedule_RA(module_id_t module_idP, frame_t frameP, sub_frame_t slotP){
   stop_meas(&mac->schedule_ra);
 }
 
-void nr_get_Msg3alloc(NR_ServingCellConfigCommon_t *scc,
+void nr_get_Msg3alloc(module_id_t module_id,
+                      int CC_id,
+                      NR_ServingCellConfigCommon_t *scc,
                       NR_BWP_Uplink_t *ubwp,
                       sub_frame_t current_slot,
                       frame_t current_frame,
@@ -596,27 +611,25 @@ void nr_get_Msg3alloc(NR_ServingCellConfigCommon_t *scc,
     ra->Msg3_frame = current_frame + (temp_slot/nr_slots_per_frame[mu]);
 
   LOG_I(MAC, "[RAPROC] Msg3 slot %d: current slot %u Msg3 frame %u k2 %u Msg3_tda_id %u start symbol index %u\n", ra->Msg3_slot, current_slot, ra->Msg3_frame, k2,ra->Msg3_tda_id, StartSymbolIndex);
-  ra->msg3_nb_rb = 18;
-  ra->msg3_first_rb = 0;
-}
-
-
-void nr_schedule_reception_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t slotP){
-  gNB_MAC_INST                                *mac = RC.nrmac[module_idP];
-  nfapi_nr_ul_tti_request_t                   *ul_req = &mac->UL_tti_req[0];
-  NR_COMMON_channels_t                        *cc = &mac->common_channels[CC_id];
-  NR_RA_t                                     *ra = &cc->ra[0];
-
-  if (ra->state == WAIT_Msg3) {
-    if ((frameP == ra->Msg3_frame) && (slotP == ra->Msg3_slot) ){
-      ul_req->SFN = ra->Msg3_frame;
-      ul_req->Slot = ra->Msg3_slot;
-      ul_req->pdus_list[ul_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
-      ul_req->pdus_list[ul_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
-      ul_req->pdus_list[ul_req->n_pdus].pusch_pdu = ra->pusch_pdu;
-      ul_req->n_pdus+=1;
-    }
+  uint16_t *vrb_map_UL =
+      &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * 275];
+  const uint16_t bwpSize = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, 275);
+  /* search 18 free RBs */
+  int rbSize = 0;
+  int rbStart = 0;
+  while (rbSize < 18) {
+    rbStart += rbSize; /* last iteration rbSize was not enough, skip it */
+    rbSize = 0;
+    while (rbStart < bwpSize && vrb_map_UL[rbStart])
+      rbStart++;
+    AssertFatal(rbStart < bwpSize - 18, "no space to allocate Msg 3 for RA!\n");
+    while (rbStart + rbSize < bwpSize
+           && !vrb_map_UL[rbStart + rbSize]
+           && rbSize < 18)
+      rbSize++;
   }
+  ra->msg3_nb_rb = 18;
+  ra->msg3_first_rb = rbStart;
 }
 
 void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t slotP){
@@ -631,10 +644,32 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t
     return;
   }
 
+  uint16_t *vrb_map_UL =
+      &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[ra->Msg3_slot * 275];
+  for (int i = 0; i < ra->msg3_nb_rb; ++i) {
+    AssertFatal(!vrb_map_UL[i + ra->msg3_first_rb],
+                "RB %d in %4d.%2d is already taken, cannot allocate Msg3!\n",
+                i + ra->msg3_first_rb,
+                ra->Msg3_frame,
+                ra->Msg3_slot);
+    vrb_map_UL[i + ra->msg3_first_rb] = 1;
+  }
+
   LOG_I(MAC, "[gNB %d][RAPROC] Frame %d, Subframe %d : CC_id %d RA is active, Msg3 in (%d,%d)\n", module_idP, frameP, slotP, CC_id, ra->Msg3_frame, ra->Msg3_slot);
 
-  nfapi_nr_pusch_pdu_t  *pusch_pdu = &ra->pusch_pdu;
+  nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[CC_id][ra->Msg3_slot];
+  AssertFatal(future_ul_tti_req->SFN == ra->Msg3_frame
+              && future_ul_tti_req->Slot == ra->Msg3_slot,
+              "future UL_tti_req's frame.slot %d.%d does not match PUSCH %d.%d\n",
+              future_ul_tti_req->SFN,
+              future_ul_tti_req->Slot,
+              ra->Msg3_frame,
+              ra->Msg3_slot);
+  future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
+  future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
+  nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu;
   memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t));
+  future_ul_tti_req->n_pdus += 1;
 
   AssertFatal(ra->secondaryCellGroup,
               "no secondaryCellGroup for RNTI %04x\n",
@@ -913,7 +948,7 @@ void nr_generate_Msg2(module_id_t module_idP,
     dl_req->nPDUs+=2;
 
     // Program UL processing for Msg3
-    nr_get_Msg3alloc(scc, ubwp, slotP, frameP, ra);
+    nr_get_Msg3alloc(module_idP, CC_id, scc, ubwp, slotP, frameP, ra);
     LOG_I(MAC, "Frame %d, Subframe %d: Setting Msg3 reception for Frame %d Subframe %d\n", frameP, slotP, ra->Msg3_frame, ra->Msg3_slot);
     nr_add_msg3(module_idP, CC_id, frameP, slotP);
     ra->state = WAIT_Msg3;
@@ -990,7 +1025,7 @@ void nr_fill_rar(uint8_t Mod_idP,
                  uint8_t * dlsch_buffer,
                  nfapi_nr_pusch_pdu_t  *pusch_pdu){
 
-  LOG_I(MAC, "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u", ra->Msg2_frame, ra-> Msg2_slot, ra->preamble_index);
+  LOG_I(MAC, "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u\n", ra->Msg2_frame, ra-> Msg2_slot, ra->preamble_index);
   NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) dlsch_buffer;
   NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 1);
   unsigned char csi_req = 0, tpc_command;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
index b8aa4223be73a77833272eac686ed529812917bd..48b82dc7dc9ccbe12a7ff9fe32af649a41b9c6ed 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
@@ -38,7 +38,6 @@
 #include "NR_MAC_COMMON/nr_mac.h"
 #include "NR_MAC_gNB/nr_mac_gNB.h"
 #include "NR_MAC_COMMON/nr_mac_extern.h"
-#include "LAYER2/MAC/mac.h"
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
 
 /*NFAPI*/
@@ -394,7 +393,7 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id,
   /* Retrieve amount of data to send for this UE */
   sched_ctrl->num_total_bytes = 0;
   const int lcid = DL_SCH_LCID_DTCH;
-  const uint16_t rnti = UE_info->rnti[UE_id];
+  const rnti_t rnti = UE_info->rnti[UE_id];
   sched_ctrl->rlc_status[lcid] = mac_rlc_status_ind(module_id,
                                                     rnti,
                                                     module_id,
@@ -409,8 +408,9 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id,
   if (sched_ctrl->num_total_bytes == 0
       && !sched_ctrl->ta_apply) /* If TA should be applied, give at least one RB */
     return;
-  LOG_D(MAC,
-        "%d.%d, DTCH%d->DLSCH, RLC status %d bytes TA %d\n",
+
+  LOG_D(MAC, "[%s][%d.%d], DTCH%d->DLSCH, RLC status %d bytes TA %d\n",
+        __FUNCTION__,
         frame,
         slot,
         lcid,
@@ -454,7 +454,8 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id,
   AssertFatal(sched_ctrl->pucch_sched_idx >= 0, "no uplink slot for PUCCH found!\n");
 
   uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map;
-  const int current_harq_pid = sched_ctrl->current_harq_pid;
+  // for now HARQ PID is fixed and should be the same as in post-processor
+  const int current_harq_pid = slot % num_slots_per_tdd;
   NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid];
   NR_UE_ret_info_t *retInfo = &sched_ctrl->retInfo[current_harq_pid];
   const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, 275);
@@ -504,6 +505,9 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id,
         getN_PRB_DMRS(sched_ctrl->active_bwp, sched_ctrl->numDmrsCdmGrpsNoData);
     int nrOfSymbols = getNrOfSymbols(sched_ctrl->active_bwp,
                                      sched_ctrl->time_domain_allocation);
+    uint8_t N_DMRS_SLOT = get_num_dmrs_symbols(sched_ctrl->active_bwp->bwp_Dedicated->pdsch_Config->choice.setup,
+                                               RC.nrmac[module_id]->common_channels->ServingCellConfigCommon->dmrs_TypeA_Position ,
+                                               nrOfSymbols);
 
     int rbSize = 0;
     const int oh = 2 + (sched_ctrl->num_total_bytes >= 256)
@@ -515,8 +519,7 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id,
                            nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx),
                            rbSize,
                            nrOfSymbols,
-                           N_PRB_DMRS, // FIXME // This should be multiplied by the
-                                       // number of dmrs symbols
+                           N_PRB_DMRS * N_DMRS_SLOT,
                            0 /* N_PRB_oh, 0 for initialBWP */,
                            0 /* tb_scaling */,
                            1 /* nrOfLayers */)
@@ -551,8 +554,10 @@ void nr_schedule_ue_spec(module_id_t module_id,
      * Possible improvement: take the periodicity from input file.
      * If such UE is not scheduled now, it will be by the preprocessor later.
      * If we add the CE, ta_apply will be reset */
-    if (frame == (sched_ctrl->ta_frame + 10) % 1024)
+    if (frame == (sched_ctrl->ta_frame + 10) % 1024){
       sched_ctrl->ta_apply = true; /* the timer is reset once TA CE is scheduled */
+      LOG_D(MAC, "[UE %d][%d.%d] UL timing alignment procedures: setting flag for Timing Advance command\n", UE_id, frame, slot);
+    }
 
     if (sched_ctrl->rbSize <= 0)
       continue;
@@ -574,19 +579,22 @@ void nr_schedule_ue_spec(module_id_t module_id,
 
     uint8_t N_PRB_DMRS =
         getN_PRB_DMRS(sched_ctrl->active_bwp, sched_ctrl->numDmrsCdmGrpsNoData);
+
+    uint8_t N_DMRS_SLOT = get_num_dmrs_symbols(sched_ctrl->active_bwp->bwp_Dedicated->pdsch_Config->choice.setup,
+                                               RC.nrmac[module_id]->common_channels->ServingCellConfigCommon->dmrs_TypeA_Position ,
+                                               nrOfSymbols);
     const uint32_t TBS =
         nr_compute_tbs(nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx),
                        nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx),
                        sched_ctrl->rbSize,
                        nrOfSymbols,
-                       N_PRB_DMRS, // FIXME // This should be multiplied by the
-                                   // number of dmrs symbols
+                       N_PRB_DMRS * N_DMRS_SLOT,
                        0 /* N_PRB_oh, 0 for initialBWP */,
                        0 /* tb_scaling */,
                        1 /* nrOfLayers */)
         >> 3;
 
-    const int current_harq_pid = sched_ctrl->current_harq_pid;
+    const int current_harq_pid = slot % num_slots_per_tdd;
     NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid];
     NR_sched_pucch *pucch = &sched_ctrl->sched_pucch[sched_ctrl->pucch_sched_idx][sched_ctrl->pucch_occ_idx];
     harq->feedback_slot = pucch->ul_slot;
@@ -639,9 +647,18 @@ void nr_schedule_ue_spec(module_id_t module_id,
               retInfo->numDmrsCdmGrpsNoData);
       /* we do not have to do anything, since we do not require to get data
        * from RLC, encode MAC CEs, or copy data to FAPI structures */
-      LOG_W(MAC, "%d.%2d retransmission UE %d/RNTI %04x\n", frame, slot, UE_id, rnti);
+      LOG_W(MAC,
+            "%d.%2d DL retransmission UE %d/RNTI %04x HARQ PID %d round %d NDI %d\n",
+            frame,
+            slot,
+            UE_id,
+            rnti,
+            current_harq_pid,
+            harq->round,
+            harq->ndi);
     } else { /* initial transmission */
 
+      LOG_D(MAC, "[%s] Initial HARQ transmission in %d.%d\n", __FUNCTION__, frame, slot);
       /* reserve space for timing advance of UE if necessary,
        * nr_generate_dlsch_pdu() checks for ta_apply and add TA CE if necessary */
       const int ta_len = (sched_ctrl->ta_apply) ? 2 : 0;
@@ -695,7 +712,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
         header_length_total += header_length_last;
         num_sdus++;
       }
-      else if (get_softmodem_params()->phy_test) {
+      else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) {
         LOG_D(MAC, "Configuring DL_TX in %d.%d: random data\n", frame, slot);
         // fill dlsch_buffer with random data
         for (int i = 0; i < TBS; i++)
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
index eb41ae14e67b31f4fdf3660ac84586ec301db5ff..33a820ae02b2d25e1d3d1fa8b3da12d051d81695 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c
@@ -255,8 +255,8 @@ void nr_preprocessor_phytest(module_id_t module_id,
                              sub_frame_t slot,
                              int num_slots_per_tdd)
 {
-  if (slot != 1)
-    return; /* only schedule in slot 1 for now . DL in nFAPI mode is working when PDCCH and PDSCH are scheduled in even slots */
+  // if (slot != 1)
+  //   return; /* only schedule in slot 1 for now . DL in nFAPI mode is working when PDCCH and PDSCH are scheduled in even slots */
   NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info;
   const int UE_id = 0;
   const int CC_id = 0;
@@ -264,7 +264,6 @@ void nr_preprocessor_phytest(module_id_t module_id,
               "%s(): expected UE %d to be active\n",
               __func__,
               UE_id);
-
   NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
   /* find largest unallocated chunk */
   const int bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, 275);
@@ -314,7 +313,7 @@ void nr_preprocessor_phytest(module_id_t module_id,
   sched_ctrl->coreset = get_coreset(
       sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */);
   const int cid = sched_ctrl->coreset->controlResourceSetId;
-  const uint16_t Y = UE_info->Y[UE_id][cid][RC.nrmac[module_id]->current_slot];
+  const uint16_t Y = UE_info->Y[UE_id][cid][slot];
   const int m = UE_info->num_pdcch_cand[UE_id][cid];
   sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id],
                                   sched_ctrl->active_bwp,
@@ -340,7 +339,14 @@ void nr_preprocessor_phytest(module_id_t module_id,
   sched_ctrl->rbStart = rbStart;
   sched_ctrl->rbSize = rbSize;
   sched_ctrl->time_domain_allocation = 2;
-  sched_ctrl->mcsTableIdx = 0;
+  if (!UE_info->secondaryCellGroup[UE_id]->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->mcs_Table)
+    sched_ctrl->mcsTableIdx = 0;
+  else {
+    if (*UE_info->secondaryCellGroup[UE_id]->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->mcs_Table == 0)
+      sched_ctrl->mcsTableIdx = 1;
+    else
+      sched_ctrl->mcsTableIdx = 2;
+  }
   sched_ctrl->mcs = 9;
   sched_ctrl->numDmrsCdmGrpsNoData = 1;
 
@@ -349,458 +355,131 @@ void nr_preprocessor_phytest(module_id_t module_id,
     vrb_map[rb + sched_ctrl->rbStart] = 1;
 }
 
-void config_uldci(NR_BWP_Uplink_t *ubwp,
-                  nfapi_nr_pusch_pdu_t *pusch_pdu,
-                  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
-                  dci_pdu_rel15_t *dci_pdu_rel15,
-                  int *dci_formats, int *rnti_types,
-                  int time_domain_assignment, uint8_t tpc,
-                  int n_ubwp, int bwp_id) {
-
-  switch(dci_formats[(pdcch_pdu_rel15->numDlDci)-1]) {
-    case NR_UL_DCI_FORMAT_0_0:
-      dci_pdu_rel15->frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size,
-                                                                                         pusch_pdu->rb_start,
-	                                                                                 NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275));
-
-      dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
-      dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
-      dci_pdu_rel15->mcs = 9;
-
-      dci_pdu_rel15->format_indicator = 0;
-      dci_pdu_rel15->ndi = 1;
-      dci_pdu_rel15->rv = 0;
-      dci_pdu_rel15->harq_pid = 0;
-      dci_pdu_rel15->tpc = 1;
-      break;
-    case NR_UL_DCI_FORMAT_0_1:
-      dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator;
-      dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index;
-      dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id;
-      dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
-      dci_pdu_rel15->dai[0].val = 0; //TODO
-      // bwp indicator
-      if (n_ubwp < 4)
-        dci_pdu_rel15->bwp_indicator.val = bwp_id;
-      else
-        dci_pdu_rel15->bwp_indicator.val = bwp_id - 1; // as per table 7.3.1.1.2-1 in 38.212
-      // frequency domain assignment
-      if (ubwp->bwp_Dedicated->pusch_Config->choice.setup->resourceAllocation==NR_PUSCH_Config__resourceAllocation_resourceAllocationType1)
-        dci_pdu_rel15->frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size,
-                                                                                             pusch_pdu->rb_start,
-                                                                                             NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275));
-      else
-        AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n");
-      // time domain assignment
-      dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
-      // mcs
-      dci_pdu_rel15->mcs = pusch_pdu->mcs_index;
-      // tpc command for pusch
-      dci_pdu_rel15->tpc = tpc;
-      // SRS resource indicator
-      if (ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig != NULL) {
-        if (*ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig == NR_PUSCH_Config__txConfig_codebook)
-          dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS
-        else
-          AssertFatal(1==0,"Non Codebook configuration non supported\n");
-      }
-      // Antenna Ports
-      dci_pdu_rel15->antenna_ports.val = 0; // TODO for now it is hardcoded, it should depends on cdm group no data and rank
-      // DMRS sequence initialization
-      dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid;
-      break;
-    default :
-      AssertFatal(1==0,"Valid UL formats are 0_0 and 0_1 \n");
-  }
-
-  LOG_D(MAC, "[gNB scheduler phytest] ULDCI type 0 payload: PDCCH CCEIndex %d, freq_alloc %d, time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n",
-	pdcch_pdu_rel15->dci_pdu.CceIndex[pdcch_pdu_rel15->numDlDci],
-	dci_pdu_rel15->frequency_domain_assignment.val,
-	dci_pdu_rel15->time_domain_assignment.val,
-	dci_pdu_rel15->frequency_hopping_flag.val,
-	dci_pdu_rel15->mcs,
-	dci_pdu_rel15->tpc,
-	dci_pdu_rel15->ndi, 
-	dci_pdu_rel15->rv);
-
-}
-    
-int8_t select_ul_harq_pid(NR_UE_sched_ctrl_t *sched_ctrl) {
-
-  uint8_t hrq_id;
-  uint8_t max_ul_harq_pids = 3; // temp: for testing
-  // schedule active harq processes
-  NR_UE_ul_harq_t cur_harq;
-  for (hrq_id=0; hrq_id < max_ul_harq_pids; hrq_id++) {
-    cur_harq = sched_ctrl->ul_harq_processes[hrq_id];
-    if (cur_harq.state==ACTIVE_NOT_SCHED) {
-#ifdef UL_HARQ_PRINT
-      printf("[SCHED] Found ulharq id %d, scheduling it for retransmission\n",hrq_id);
-#endif
-      return hrq_id;
-    }
-  }
+void nr_ul_preprocessor_phytest(module_id_t module_id,
+                                frame_t frame,
+                                sub_frame_t slot,
+                                int num_slots_per_tdd,
+                                uint64_t ulsch_in_slot_bitmap) {
+  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
+  NR_COMMON_channels_t *cc = nr_mac->common_channels;
+  NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
+  const int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
+  NR_UE_info_t *UE_info = &nr_mac->UE_info;
+
+  AssertFatal(UE_info->num_UEs <= 1,
+              "%s() cannot handle more than one UE, but found %d\n",
+              __func__,
+              UE_info->num_UEs);
+  if (UE_info->num_UEs == 0)
+    return;
 
-  // schedule new harq processes
-  for (hrq_id=0; hrq_id < max_ul_harq_pids; hrq_id++) {
-    cur_harq = sched_ctrl->ul_harq_processes[hrq_id];
-    if (cur_harq.state==INACTIVE) {
-#ifdef UL_HARQ_PRINT
-      printf("[SCHED] Found new ulharq id %d, scheduling it\n",hrq_id);
-#endif
-      return hrq_id;
-    }
-  }
-  LOG_E(MAC,"All UL HARQ processes are busy. Cannot schedule ULSCH\n");
-  return -1;
-}
+  const int UE_id = 0;
+  const int CC_id = 0;
 
-long get_K2(NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu) {
-  DevAssert(ubwp);
-  const NR_PUSCH_TimeDomainResourceAllocation_t *tda_list = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment];
-  if (tda_list->k2)
-    return *tda_list->k2;
-  else if (mu < 2)
-    return 1;
-  else if (mu == 2)
-    return 2;
-  else
-    return 3;
-}
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
 
-void schedule_fapi_ul_pdu(int Mod_idP,
-                          frame_t frameP,
-                          sub_frame_t slotP,
-                          int num_slots_per_tdd,
-                          int ul_slots,
-                          int time_domain_assignment,
-                          uint64_t ulsch_in_slot_bitmap) {
-
-  gNB_MAC_INST                      *nr_mac    = RC.nrmac[Mod_idP];
-  NR_COMMON_channels_t                  *cc    = nr_mac->common_channels;
-  NR_ServingCellConfigCommon_t         *scc    = cc->ServingCellConfigCommon;
-
-  int bwp_id=1;
-  int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
-  int UE_id = 0;
-  NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info;
-  AssertFatal(UE_info->active[UE_id],"Cannot find UE_id %d is not active\n",UE_id);
-
-  NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id];
-  AssertFatal(secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
-	      "downlinkBWP_ToAddModList has %d BWP!\n",
-	      secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count);
-  NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
-  int n_ubwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count;
-  NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1];
-  NR_PUSCH_Config_t *pusch_Config = ubwp->bwp_Dedicated->pusch_Config->choice.setup;
-
-  AssertFatal(time_domain_assignment<ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count,
-              "time_domain_assignment %d>=%d\n",time_domain_assignment,ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.count);
-
-  int K2 = get_K2(ubwp, time_domain_assignment,mu);
-  /* check if slot is UL, and for phy test verify that it is in first TDD
-   * period, slot 8 (for K2=2, this is at slot 6 in the gNB; because of UE
+  const int tda = 1;
+  const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList =
+    sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
+  AssertFatal(tda < tdaList->list.count,
+              "time domain assignment %d >= %d\n",
+              tda,
+              tdaList->list.count);
+  int K2 = get_K2(sched_ctrl->active_ubwp, tda, mu);
+  const int sched_frame = frame + (slot + K2 >= num_slots_per_tdd);
+  const int sched_slot = (slot + K2) % num_slots_per_tdd;
+  /* check if slot is UL, and that slot is 8 (assuming K2=6 because of UE
    * limitations).  Note that if K2 or the TDD configuration is changed, below
    * conditions might exclude each other and never be true */
-  const int slot_idx = (slotP + K2) % num_slots_per_tdd;
-  if (is_xlsch_in_slot(ulsch_in_slot_bitmap, slot_idx)
-      && (!get_softmodem_params()->phy_test || slot_idx == 8)) {
-
-    nfapi_nr_ul_dci_request_t *UL_dci_req = &RC.nrmac[Mod_idP]->UL_dci_req[0];
-    UL_dci_req->SFN = frameP;
-    UL_dci_req->Slot = slotP;
-    nfapi_nr_ul_dci_request_pdus_t  *ul_dci_request_pdu;
-
-    AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList!=NULL,"searchPsacesToAddModList is null\n");
-    AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count>0,
-                "searchPsacesToAddModList is empty\n");
-
-    uint16_t rnti = UE_info->rnti[UE_id];
-
-    int first_ul_slot = num_slots_per_tdd - ul_slots;
-    NR_sched_pusch *pusch_sched = &UE_info->UE_sched_ctrl[UE_id].sched_pusch[slotP+K2-first_ul_slot];
-    pusch_sched->frame = frameP;
-    pusch_sched->slot = slotP + K2;
-    pusch_sched->active = true;
-    nfapi_nr_pusch_pdu_t  *pusch_pdu = &pusch_sched->pusch_pdu;
-    memset(pusch_pdu,0,sizeof(nfapi_nr_pusch_pdu_t));
-
-    LOG_D(MAC, "Scheduling UE specific PUSCH\n");
-    //UL_tti_req = &nr_mac->UL_tti_req[CC_id];
-
-    int dci_formats[2];
-    int rnti_types[2];
-
-    NR_SearchSpace_t *ss;
-    int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
-
-    AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList!=NULL,"searchPsacesToAddModList is null\n");
-    AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count>0,
-                "searchPsacesToAddModList is empty\n");
-
-    int found=0;
-
-    for (int i=0;i<bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count;i++) {
-      ss=bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i];
-      AssertFatal(ss->controlResourceSetId != NULL,"ss->controlResourceSetId is null\n");
-      AssertFatal(ss->searchSpaceType != NULL,"ss->searchSpaceType is null\n");
-      if (ss->searchSpaceType->present == target_ss) {
-        found=1;
-        break;
-      }
-    }
-    AssertFatal(found==1,"Couldn't find an adequate searchspace\n");
-
-    if (ss->searchSpaceType->choice.ue_Specific->dci_Formats)
-      dci_formats[0]  = NR_UL_DCI_FORMAT_0_1;
-    else
-      dci_formats[0]  = NR_UL_DCI_FORMAT_0_0;
-
-    rnti_types[0]   = NR_RNTI_C;
-
-    //Resource Allocation in time domain
-    int startSymbolAndLength=0;
-    int StartSymbolIndex,NrOfSymbols,mapping_type;
-
-    startSymbolAndLength = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->startSymbolAndLength;
-    SLIV2SL(startSymbolAndLength,&StartSymbolIndex,&NrOfSymbols);
-    pusch_pdu->start_symbol_index = StartSymbolIndex;
-    pusch_pdu->nr_of_symbols = NrOfSymbols;
-
-    mapping_type = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment]->mappingType;
-
-    pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA;
-    pusch_pdu->rnti = rnti;
-    pusch_pdu->handle = 0; //not yet used
-  
-    pusch_pdu->bwp_size  = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
-    pusch_pdu->bwp_start = NRRIV2PRBOFFSET(ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
-    pusch_pdu->subcarrier_spacing = ubwp->bwp_Common->genericParameters.subcarrierSpacing;
-    pusch_pdu->cyclic_prefix = 0;
-
-    if (pusch_Config->transformPrecoder == NULL) {
-      if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL)
-        pusch_pdu->transform_precoding = 1;
-      else
-        pusch_pdu->transform_precoding = 0;
-    }
-    else
-      pusch_pdu->transform_precoding = *pusch_Config->transformPrecoder;
-    if (pusch_Config->dataScramblingIdentityPUSCH != NULL)
-      pusch_pdu->data_scrambling_id = *pusch_Config->dataScramblingIdentityPUSCH;
-    else
-      pusch_pdu->data_scrambling_id = *scc->physCellId;
-
-    pusch_pdu->mcs_index = 9;
-    if (pusch_pdu->transform_precoding)
-      pusch_pdu->mcs_table = get_pusch_mcs_table(pusch_Config->mcs_Table, 0,
-                                                 dci_formats[0], rnti_types[0], target_ss, false);
-    else
-      pusch_pdu->mcs_table = get_pusch_mcs_table(pusch_Config->mcs_TableTransformPrecoder, 1,
-                                                 dci_formats[0], rnti_types[0], target_ss, false);
-
-    pusch_pdu->target_code_rate = nr_get_code_rate_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table);
-    pusch_pdu->qam_mod_order = nr_get_Qm_ul(pusch_pdu->mcs_index,pusch_pdu->mcs_table);
-    if (pusch_Config->tp_pi2BPSK!=NULL) {
-      if(((pusch_pdu->mcs_table==3)&&(pusch_pdu->mcs_index<2)) ||
-         ((pusch_pdu->mcs_table==4)&&(pusch_pdu->mcs_index<6))) {
-        pusch_pdu->target_code_rate = pusch_pdu->target_code_rate>>1;
-        pusch_pdu->qam_mod_order = pusch_pdu->qam_mod_order<<1;
-      }
-    }
-    pusch_pdu->nrOfLayers = 1;
-
-    //Pusch Allocation in frequency domain [TS38.214, sec 6.1.2.2]
-    if (pusch_Config->resourceAllocation==NR_PUSCH_Config__resourceAllocation_resourceAllocationType1) {
-      pusch_pdu->resource_alloc = 1; //type 1
-      pusch_pdu->rb_start = 0;
-      if (get_softmodem_params()->phy_test==1)
-        pusch_pdu->rb_size = min(pusch_pdu->bwp_size,50);
-      else
-        pusch_pdu->rb_size = pusch_pdu->bwp_size;
-    }
-    else
-      AssertFatal(1==0,"Only frequency resource allocation type 1 is currently supported\n");
-
-    pusch_pdu->vrb_to_prb_mapping = 0;
-
-    if (pusch_Config->frequencyHopping==NULL)
-      pusch_pdu->frequency_hopping = 0;
-    else
-      pusch_pdu->frequency_hopping = 1;
-
-    //pusch_pdu->tx_direct_current_location;//The uplink Tx Direct Current location for the carrier. Only values in the value range of this field between 0 and 3299, which indicate the subcarrier index within the carrier corresponding 1o the numerology of the corresponding uplink BWP and value 3300, which indicates "Outside the carrier" and value 3301, which indicates "Undetermined position within the carrier" are used. [TS38.331, UplinkTxDirectCurrentBWP IE]
-    //pusch_pdu->uplink_frequency_shift_7p5khz = 0;
-
-
-    // --------------------
-    // ------- DMRS -------
-    // --------------------
-    NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig;
-    if (mapping_type == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA)
-      NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup;
-    else
-      NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
-    if (NR_DMRS_UplinkConfig->dmrs_Type == NULL)
-      pusch_pdu->dmrs_config_type = 0;
-    else
-      pusch_pdu->dmrs_config_type = 1;
-    pusch_pdu->scid = 0;      // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]
-    if (pusch_pdu->transform_precoding) { // transform precoding disabled
-      long *scramblingid;
-      if (pusch_pdu->scid == 0)
-        scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0;
-      else
-        scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID1;
-      if (scramblingid == NULL)
-        pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
-      else
-        pusch_pdu->ul_dmrs_scrambling_id = *scramblingid;
-    }
-    else {
-      pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
-      if (NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
-        pusch_pdu->pusch_identity = *NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity;
-      else
-        pusch_pdu->pusch_identity = *scc->physCellId;
-    }
-    pusch_dmrs_AdditionalPosition_t additional_pos;
-    if (NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NULL)
-      additional_pos = 2;
-    else {
-      if (*NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos3)
-        additional_pos = 3;
-      else
-        additional_pos = *NR_DMRS_UplinkConfig->dmrs_AdditionalPosition;
-    }
-    pusch_maxLength_t pusch_maxLength;
-    if (NR_DMRS_UplinkConfig->maxLength == NULL)
-      pusch_maxLength = 1;
-    else
-      pusch_maxLength = 2;
-    uint16_t l_prime_mask = get_l_prime(pusch_pdu->nr_of_symbols, mapping_type, additional_pos, pusch_maxLength);
-    pusch_pdu->ul_dmrs_symb_pos = l_prime_mask << pusch_pdu->start_symbol_index;
-
-    pusch_pdu->num_dmrs_cdm_grps_no_data = 1;
-    pusch_pdu->dmrs_ports = 1;
-    // --------------------------------------------------------------------------------------------------------------------------------------------
-
-    // --------------------
-    // ------- PTRS -------
-    // --------------------
-    if (NR_DMRS_UplinkConfig->phaseTrackingRS != NULL) {
-      // TODO to be fixed from RRC config
-      uint8_t ptrs_mcs1 = 2;  // higher layer parameter in PTRS-UplinkConfig
-      uint8_t ptrs_mcs2 = 4;  // higher layer parameter in PTRS-UplinkConfig
-      uint8_t ptrs_mcs3 = 10; // higher layer parameter in PTRS-UplinkConfig
-      uint16_t n_rb0 = 25;    // higher layer parameter in PTRS-UplinkConfig
-      uint16_t n_rb1 = 75;    // higher layer parameter in PTRS-UplinkConfig
-      pusch_pdu->pusch_ptrs.ptrs_time_density = get_L_ptrs(ptrs_mcs1, ptrs_mcs2, ptrs_mcs3, pusch_pdu->mcs_index, pusch_pdu->mcs_table);
-      pusch_pdu->pusch_ptrs.ptrs_freq_density = get_K_ptrs(n_rb0, n_rb1, pusch_pdu->rb_size);
-      pusch_pdu->pusch_ptrs.ptrs_ports_list   = (nfapi_nr_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ptrs_ports_t));
-      pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0;
-
-      pusch_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS; // enable PUSCH PTRS
-    }
-    else{
-      pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
+  if (!(is_xlsch_in_slot(ulsch_in_slot_bitmap, sched_slot) && sched_slot == 8))
+    return;
+
+  const uint16_t rbStart = 0;
+  const uint16_t rbSize = 50; /* due to OAI UE limitations */
+  uint16_t *vrb_map_UL =
+      &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * 275];
+  for (int i = rbStart; i < rbStart + rbSize; ++i) {
+    if (vrb_map_UL[i]) {
+      LOG_E(MAC,
+            "%s(): %4d.%2d RB %d is already reserved, cannot schedule UE\n",
+            __func__,
+            frame,
+            slot,
+            i);
+      return;
     }
+  }
 
-    // --------------------------------------------------------------------------------------------------------------------------------------------
-
-    //Pusch Allocation in frequency domain [TS38.214, sec 6.1.2.2]
-    //Optional Data only included if indicated in pduBitmap
-    //int8_t harq_id=0;// Hard coding the harq id 
-    int8_t harq_id = select_ul_harq_pid(&UE_info->UE_sched_ctrl[UE_id]);
-    if (harq_id < 0) return;
-    NR_UE_ul_harq_t *cur_harq = &UE_info->UE_sched_ctrl[UE_id].ul_harq_processes[harq_id];
-    pusch_pdu->pusch_data.harq_process_id = harq_id;
-    pusch_pdu->pusch_data.new_data_indicator = cur_harq->ndi;
-    pusch_pdu->pusch_data.rv_index = nr_rv_round_map[cur_harq->round];
-
-    cur_harq->state = ACTIVE_SCHED;
-    cur_harq->last_tx_slot = pusch_sched->slot;
-
-    uint8_t num_dmrs_symb = 0;
-
-    for(int dmrs_counter = pusch_pdu->start_symbol_index; dmrs_counter < pusch_pdu->start_symbol_index + pusch_pdu->nr_of_symbols; dmrs_counter++)
-      num_dmrs_symb += ((pusch_pdu->ul_dmrs_symb_pos >> dmrs_counter) & 1);
+  sched_ctrl->sched_pusch.slot = sched_slot;
+  sched_ctrl->sched_pusch.frame = sched_frame;
 
-    uint8_t N_PRB_DMRS;
-    if (pusch_pdu->dmrs_config_type == 0) {
-      N_PRB_DMRS = pusch_pdu->num_dmrs_cdm_grps_no_data*6;
-    }
-    else {
-      N_PRB_DMRS = pusch_pdu->num_dmrs_cdm_grps_no_data*4;
-    }
-
-    pusch_pdu->pusch_data.tb_size = nr_compute_tbs(pusch_pdu->qam_mod_order,
-                                                   pusch_pdu->target_code_rate,
-                                                   pusch_pdu->rb_size,
-                                                   pusch_pdu->nr_of_symbols,
-                                                   N_PRB_DMRS * num_dmrs_symb,
-                                                   0, //nb_rb_oh
-                                                   0,
-                                                   pusch_pdu->nrOfLayers)>>3;
-
-    UE_info->mac_stats[UE_id].ulsch_rounds[cur_harq->round]++;
-    if (cur_harq->round == 0) UE_info->mac_stats[UE_id].ulsch_total_bytes_scheduled+=pusch_pdu->pusch_data.tb_size;
-
-    pusch_pdu->pusch_data.num_cb = 0; //CBG not supported
-    //pusch_pdu->pusch_data.cb_present_and_position;
-    //pusch_pdu->pusch_uci;
-    //pusch_pdu->pusch_ptrs;
-    //pusch_pdu->dfts_ofdm;
-    //beamforming
-    //pusch_pdu->beamforming; //not used for now
-
-
-    ul_dci_request_pdu = &UL_dci_req->ul_dci_pdu_list[UL_dci_req->numPdus];
-    memset((void*)ul_dci_request_pdu,0,sizeof(nfapi_nr_ul_dci_request_pdus_t));
-    ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE;
-    ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu));
-    nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15;
-    UL_dci_req->numPdus+=1;
-
-
-    LOG_D(MAC,"Configuring ULDCI/PDCCH in %d.%d\n", frameP,slotP);
-
-    uint8_t nr_of_candidates, aggregation_level;
-    find_aggregation_candidates(&aggregation_level, &nr_of_candidates, ss);
-    NR_ControlResourceSet_t *coreset = get_coreset(bwp, ss, 1 /* dedicated */);
-    const int cid = coreset->controlResourceSetId;
-    const uint16_t Y = UE_info->Y[UE_id][cid][nr_mac->current_slot];
-    const int m = UE_info->num_pdcch_cand[UE_id][cid];
-    int CCEIndex = allocate_nr_CCEs(nr_mac,
-                                    bwp,
-                                    coreset,
-                                    aggregation_level,
-                                    Y,
-                                    m,
-                                    nr_of_candidates);
-    if (CCEIndex < 0) {
-      LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__);
-      pusch_sched->active = false;
-      return;
-    }
-    else {
-      UE_info->num_pdcch_cand[UE_id][cid]++;
-      nr_configure_pdcch(nr_mac,
-                         pdcch_pdu_rel15,
-                         UE_info->rnti[UE_id],
-                         ss,
-                         coreset,
-                         scc,
-                         bwp,
-                         aggregation_level,
-                         CCEIndex);
-
-      dci_pdu_rel15_t *dci_pdu_rel15 = calloc(MAX_DCI_CORESET,sizeof(dci_pdu_rel15_t));
-      config_uldci(ubwp,pusch_pdu,pdcch_pdu_rel15,&dci_pdu_rel15[0],dci_formats,rnti_types,time_domain_assignment,UE_info->UE_sched_ctrl[UE_id].tpc0,n_ubwp,bwp_id);
-      fill_dci_pdu_rel15(scc,secondaryCellGroup,pdcch_pdu_rel15,dci_pdu_rel15,dci_formats,rnti_types,pusch_pdu->bwp_size,bwp_id);
-      free(dci_pdu_rel15);
-    }
+  const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+  sched_ctrl->search_space = get_searchspace(sched_ctrl->active_bwp, target_ss);
+  uint8_t nr_of_candidates;
+  find_aggregation_candidates(&sched_ctrl->aggregation_level,
+                              &nr_of_candidates,
+                              sched_ctrl->search_space);
+  sched_ctrl->coreset = get_coreset(
+      sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */);
+  const int cid = sched_ctrl->coreset->controlResourceSetId;
+  const uint16_t Y = UE_info->Y[UE_id][cid][slot];
+  const int m = UE_info->num_pdcch_cand[UE_id][cid];
+  sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id],
+                                           sched_ctrl->active_bwp,
+                                           sched_ctrl->coreset,
+                                           sched_ctrl->aggregation_level,
+                                           Y,
+                                           m,
+                                           nr_of_candidates);
+  if (sched_ctrl->cce_index < 0) {
+    LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__);
+    return;
   }
-}
+  UE_info->num_pdcch_cand[UE_id][cid]++;
+
+  sched_ctrl->sched_pusch.time_domain_allocation = tda;
+  const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats;
+  const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0;
+  const uint8_t num_dmrs_cdm_grps_no_data = 1;
+  /* we want to avoid a lengthy deduction of DMRS and other parameters in
+   * every TTI if we can save it, so check whether dci_format, TDA, or
+   * num_dmrs_cdm_grps_no_data has changed and only then recompute */
+  NR_sched_pusch_save_t *ps = &sched_ctrl->pusch_save;
+  if (ps->time_domain_allocation != tda
+      || ps->dci_format != dci_format
+      || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data)
+    nr_save_pusch_fields(scc,
+                         sched_ctrl->active_ubwp,
+                         dci_format,
+                         tda,
+                         num_dmrs_cdm_grps_no_data,
+                         ps);
+
+  const int mcs = 9;
+  NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
+  sched_pusch->mcs = mcs;
+  sched_pusch->rbStart = rbStart;
+  sched_pusch->rbSize = rbSize;
+
+  /* Calculate TBS from MCS */
+  sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table);
+  sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table);
+  if (ps->pusch_Config->tp_pi2BPSK
+      && ((ps->mcs_table == 3 && mcs < 2) || (ps->mcs_table == 4 && mcs < 6))) {
+    sched_pusch->R >>= 1;
+    sched_pusch->Qm <<= 1;
+  }
+  sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm,
+                                        sched_pusch->R,
+                                        sched_pusch->rbSize,
+                                        ps->nrOfSymbols,
+                                        ps->N_PRB_DMRS * ps->num_dmrs_symb,
+                                        0, // nb_rb_oh
+                                        0,
+                                        1 /* NrOfLayers */)
+                         >> 3;
 
+  /* mark the corresponding RBs as used */
+  for (int rb = rbStart; rb < rbStart + rbSize; rb++)
+    vrb_map_UL[rb] = 1;
+}
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index ae389cd23bc2d6b711d08e2783c28fe8e1ac75f1..f3260ea3cffbc07c2b73d84a89455ad2fa7e7867 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -32,7 +32,6 @@
 
 #include "assertions.h"
 
-#include "LAYER2/MAC/mac.h"
 #include "NR_MAC_gNB/nr_mac_gNB.h"
 #include "NR_MAC_COMMON/nr_mac_extern.h"
 
@@ -48,9 +47,6 @@
 #include "RRC/NR/nr_rrc_extern.h"
 #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
 
-//#include "LAYER2/MAC/pre_processor.c"
-#include "pdcp.h"
-
 #include "intertask_interface.h"
 
 #include "T.h"
@@ -213,6 +209,75 @@ int allocate_nr_CCEs(gNB_MAC_INST *nr_mac,
 
 }
 
+void nr_save_pusch_fields(const NR_ServingCellConfigCommon_t *scc,
+                          const NR_BWP_Uplink_t *ubwp,
+                          long dci_format,
+                          int tda,
+                          uint8_t num_dmrs_cdm_grps_no_data,
+                          NR_sched_pusch_save_t *ps)
+{
+  ps->dci_format = dci_format;
+  ps->time_domain_allocation = tda;
+  ps->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data;
+
+  const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList =
+      ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
+  const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength;
+  SLIV2SL(startSymbolAndLength,
+          &ps->startSymbolIndex,
+          &ps->nrOfSymbols);
+
+  ps->pusch_Config = ubwp->bwp_Dedicated->pusch_Config->choice.setup;
+  if (!ps->pusch_Config->transformPrecoder)
+    ps->transform_precoding = !scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder;
+  else
+    ps->transform_precoding = *ps->pusch_Config->transformPrecoder;
+  const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+  if (ps->transform_precoding)
+    ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config->mcs_Table,
+                                    0,
+                                    ps->dci_format,
+                                    NR_RNTI_C,
+                                    target_ss,
+                                    false);
+  else
+    ps->mcs_table = get_pusch_mcs_table(ps->pusch_Config->mcs_TableTransformPrecoder,
+                                    1,
+                                    ps->dci_format,
+                                    NR_RNTI_C,
+                                    target_ss,
+                                    false);
+
+  /* DMRS calculations */
+  ps->mapping_type = tdaList->list.array[tda]->mappingType;
+  ps->NR_DMRS_UplinkConfig =
+      ps->mapping_type == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA
+          ? ps->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup
+          : ps->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
+  ps->dmrs_config_type = ps->NR_DMRS_UplinkConfig->dmrs_Type == NULL ? 0 : 1;
+  const pusch_dmrs_AdditionalPosition_t additional_pos =
+      ps->NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NULL
+          ? 2
+          : (*ps->NR_DMRS_UplinkConfig->dmrs_AdditionalPosition ==
+                     NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos3
+                 ? 3
+                 : *ps->NR_DMRS_UplinkConfig->dmrs_AdditionalPosition);
+  const pusch_maxLength_t pusch_maxLength =
+      ps->NR_DMRS_UplinkConfig->maxLength == NULL ? 1 : 2;
+  const uint16_t l_prime_mask = get_l_prime(ps->nrOfSymbols,
+                                            ps->mapping_type,
+                                            additional_pos,
+                                            pusch_maxLength);
+  ps->ul_dmrs_symb_pos = l_prime_mask << ps->startSymbolIndex;
+  uint8_t num_dmrs_symb = 0;
+  for(int i = ps->startSymbolIndex; i < ps->startSymbolIndex + ps->nrOfSymbols; i++)
+    num_dmrs_symb += (ps->ul_dmrs_symb_pos >> i) & 1;
+  ps->num_dmrs_symb = num_dmrs_symb;
+  ps->N_PRB_DMRS = ps->dmrs_config_type == 0
+      ? num_dmrs_cdm_grps_no_data * 6
+      : num_dmrs_cdm_grps_no_data * 4;
+}
+
 void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu,
 				  nr_scs_e scs_common,
 				  nr_scs_e pdcch_scs,
@@ -453,6 +518,7 @@ void nr_fill_nfapi_dl_pdu(int Mod_idP,
   const int bwp_id = sched_ctrl->active_bwp->bwp_Id;
   const int nrOfLayers = 1;
   const int mcs = sched_ctrl->mcs;
+  const int mcs_table_index = sched_ctrl->mcsTableIdx;
   bool valid_ptrs_setup = false;
 
   AssertFatal(secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
@@ -492,10 +558,10 @@ void nr_fill_nfapi_dl_pdu(int Mod_idP,
     pdsch_pdu_rel15->CyclicPrefix = 0;
 
   pdsch_pdu_rel15->NrOfCodewords = 1;
-  pdsch_pdu_rel15->targetCodeRate[0] = nr_get_code_rate_dl(mcs,0);
+  pdsch_pdu_rel15->targetCodeRate[0] = nr_get_code_rate_dl(mcs, mcs_table_index);
   pdsch_pdu_rel15->qamModOrder[0] = 2;
   pdsch_pdu_rel15->mcsIndex[0] = mcs;
-  pdsch_pdu_rel15->mcsTable[0] = 0;
+  pdsch_pdu_rel15->mcsTable[0] = mcs_table_index;
   pdsch_pdu_rel15->rvIndex[0] = nr_rv_round_map[round];
   pdsch_pdu_rel15->dataScramblingId = *scc->physCellId;
   pdsch_pdu_rel15->nrOfLayers = nrOfLayers;
@@ -637,6 +703,81 @@ void nr_fill_nfapi_dl_pdu(int Mod_idP,
   dl_req->nPDUs += 2;
 }
 
+void config_uldci(NR_BWP_Uplink_t *ubwp,
+                  nfapi_nr_pusch_pdu_t *pusch_pdu,
+                  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
+                  dci_pdu_rel15_t *dci_pdu_rel15,
+                  int *dci_formats,
+                  int time_domain_assignment, uint8_t tpc,
+                  int n_ubwp, int bwp_id) {
+  const int bw = NRRIV2BW(ubwp->bwp_Common->genericParameters.locationAndBandwidth, 275);
+  switch (dci_formats[(pdcch_pdu_rel15->numDlDci) - 1]) {
+    case NR_UL_DCI_FORMAT_0_0:
+      dci_pdu_rel15->frequency_domain_assignment.val =
+          PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, bw);
+
+      dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
+      dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
+      dci_pdu_rel15->mcs = pusch_pdu->mcs_index;
+
+      dci_pdu_rel15->format_indicator = 0;
+      dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator;
+      dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index;
+      dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id;
+      dci_pdu_rel15->tpc = tpc;
+      break;
+    case NR_UL_DCI_FORMAT_0_1:
+      dci_pdu_rel15->ndi = pusch_pdu->pusch_data.new_data_indicator;
+      dci_pdu_rel15->rv = pusch_pdu->pusch_data.rv_index;
+      dci_pdu_rel15->harq_pid = pusch_pdu->pusch_data.harq_process_id;
+      dci_pdu_rel15->frequency_hopping_flag.val = pusch_pdu->frequency_hopping;
+      dci_pdu_rel15->dai[0].val = 0; //TODO
+      // bwp indicator
+      if (n_ubwp < 4)
+        dci_pdu_rel15->bwp_indicator.val = bwp_id;
+      else
+        dci_pdu_rel15->bwp_indicator.val = bwp_id - 1; // as per table 7.3.1.1.2-1 in 38.212
+      // frequency domain assignment
+      AssertFatal(ubwp->bwp_Dedicated->pusch_Config->choice.setup->resourceAllocation
+                      == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1,
+                  "Only frequency resource allocation type 1 is currently supported\n");
+      dci_pdu_rel15->frequency_domain_assignment.val =
+          PRBalloc_to_locationandbandwidth0(pusch_pdu->rb_size, pusch_pdu->rb_start, bw);
+      // time domain assignment
+      dci_pdu_rel15->time_domain_assignment.val = time_domain_assignment;
+      // mcs
+      dci_pdu_rel15->mcs = pusch_pdu->mcs_index;
+      // tpc command for pusch
+      dci_pdu_rel15->tpc = tpc;
+      // SRS resource indicator
+      if (ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig != NULL) {
+        AssertFatal(*ubwp->bwp_Dedicated->pusch_Config->choice.setup->txConfig == NR_PUSCH_Config__txConfig_codebook,
+                    "Non Codebook configuration non supported\n");
+        dci_pdu_rel15->srs_resource_indicator.val = 0; // taking resource 0 for SRS
+      }
+      // Antenna Ports
+      dci_pdu_rel15->antenna_ports.val = 0; // TODO for now it is hardcoded, it should depends on cdm group no data and rank
+      // DMRS sequence initialization
+      dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid;
+      break;
+    default :
+      AssertFatal(0, "Valid UL formats are 0_0 and 0_1\n");
+  }
+
+  LOG_D(MAC,
+        "%s() ULDCI type 0 payload: PDCCH CCEIndex %d, freq_alloc %d, "
+        "time_alloc %d, freq_hop_flag %d, mcs %d tpc %d ndi %d rv %d\n",
+        __func__,
+        pdcch_pdu_rel15->dci_pdu.CceIndex[pdcch_pdu_rel15->numDlDci],
+        dci_pdu_rel15->frequency_domain_assignment.val,
+        dci_pdu_rel15->time_domain_assignment.val,
+        dci_pdu_rel15->frequency_hopping_flag.val,
+        dci_pdu_rel15->mcs,
+        dci_pdu_rel15->tpc,
+        dci_pdu_rel15->ndi,
+        dci_pdu_rel15->rv);
+}
+
 void nr_configure_pdcch(gNB_MAC_INST *nr_mac,
                         nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu,
                         uint16_t rnti,
@@ -1721,20 +1862,17 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){
     UE_info->UE_sched_ctrl[UE_id].ta_update = 31;
     UE_info->UE_sched_ctrl[UE_id].ta_apply = false;
     UE_info->UE_sched_ctrl[UE_id].ul_rssi = 0;
+    /* set illegal time domain allocation to force recomputation of all fields */
+    UE_info->UE_sched_ctrl[UE_id].pusch_save.time_domain_allocation = -1;
     UE_info->UE_sched_ctrl[UE_id].sched_pucch = (NR_sched_pucch **)malloc(num_slots_ul*sizeof(NR_sched_pucch *));
     for (int s=0; s<num_slots_ul;s++)
       UE_info->UE_sched_ctrl[UE_id].sched_pucch[s] = (NR_sched_pucch *)malloc(2*sizeof(NR_sched_pucch));
-    UE_info->UE_sched_ctrl[UE_id].sched_pusch = (NR_sched_pusch *)malloc(num_slots_ul*sizeof(NR_sched_pusch));
 
     for (int k=0; k<num_slots_ul; k++) {
       for (int l=0; l<2; l++)
         memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l],
                0,
                sizeof(NR_sched_pucch));
-
-      memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pusch[k],
-             0,
-             sizeof(NR_sched_pusch));
     }
     LOG_I(MAC, "gNB %d] Add NR UE_id %d : rnti %x\n",
           mod_idP,
@@ -1776,7 +1914,6 @@ void mac_remove_nr_ue(module_id_t mod_id, rnti_t rnti)
     UE_info->rnti[UE_id] = 0;
     remove_nr_ue_list(&UE_info->list, UE_id);
     free(UE_info->UE_sched_ctrl[UE_id].sched_pucch);
-    free(UE_info->UE_sched_ctrl[UE_id].sched_pusch);
     memset((void *) &UE_info->UE_sched_ctrl[UE_id],
            0,
            sizeof(NR_UE_sched_ctrl_t));
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
index 909a3ea540bd21975699832ad702fe870498d49d..ec5195ec5beacf7c19ff9f40ed5f483da4f4e115 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
@@ -39,51 +39,59 @@ void nr_schedule_pucch(int Mod_idP,
                        int nr_ulmix_slots,
                        frame_t frameP,
                        sub_frame_t slotP) {
-
-  uint16_t O_csi, O_ack, O_uci;
-  uint8_t O_sr = 0; // no SR in PUCCH implemented for now
-  NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon;
   NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info;
   AssertFatal(UE_info->active[UE_id],"Cannot find UE_id %d is not active\n",UE_id);
 
-  NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id];
-  int bwp_id=1;
-  NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
-  nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
-
-  NR_sched_pucch *curr_pucch;
-
   for (int k=0; k<nr_ulmix_slots; k++) {
     for (int l=0; l<2; l++) {
-      curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l];
-      O_ack = curr_pucch->dai_c;
-      O_csi = curr_pucch->csi_bits;
-      O_uci = O_ack + O_csi + O_sr;
-      if ((O_uci>0) && (frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) {
-        UL_tti_req->SFN = curr_pucch->frame;
-        UL_tti_req->Slot = curr_pucch->ul_slot;
-        UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE;
-        UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t);
-        nfapi_nr_pucch_pdu_t  *pucch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pucch_pdu;
-        memset(pucch_pdu,0,sizeof(nfapi_nr_pucch_pdu_t));
-        UL_tti_req->n_pdus+=1;
-
-        LOG_D(MAC,"Scheduling pucch reception for frame %d slot %d with (%d, %d, %d) (SR ACK, CSI) bits\n",
-              frameP,slotP,O_sr,O_ack,curr_pucch->csi_bits);
-
-        nr_configure_pucch(pucch_pdu,
-                           scc,
-                           ubwp,
-                           UE_info->rnti[UE_id],
-                           curr_pucch->resource_indicator,
-                           O_csi,
-                           O_ack,
-                           O_sr);
-
-        memset((void *) &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l],
-               0,
-               sizeof(NR_sched_pucch));
-      }
+      NR_sched_pucch *curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l];
+      const uint16_t O_ack = curr_pucch->dai_c;
+      const uint16_t O_csi = curr_pucch->csi_bits;
+      const uint8_t O_sr = 0; // no SR in PUCCH implemented for now
+      if (O_ack + O_csi + O_sr == 0
+          || frameP != curr_pucch->frame
+          || slotP != curr_pucch->ul_slot)
+        continue;
+
+      nfapi_nr_ul_tti_request_t *future_ul_tti_req =
+          &RC.nrmac[Mod_idP]->UL_tti_req_ahead[0][curr_pucch->ul_slot];
+      AssertFatal(future_ul_tti_req->SFN == curr_pucch->frame
+                  && future_ul_tti_req->Slot == curr_pucch->ul_slot,
+                  "future UL_tti_req's frame.slot %d.%d does not match PUCCH %d.%d\n",
+                  future_ul_tti_req->SFN,
+                  future_ul_tti_req->Slot,
+                  curr_pucch->frame,
+                  curr_pucch->ul_slot);
+      future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE;
+      future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t);
+      nfapi_nr_pucch_pdu_t *pucch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pucch_pdu;
+      memset(pucch_pdu, 0, sizeof(nfapi_nr_pucch_pdu_t));
+      future_ul_tti_req->n_pdus += 1;
+
+      LOG_D(MAC,
+            "%4d.%2d Scheduling pucch reception in %4d.%2d: bits SR %d, ACK %d, CSI %d, k %d l %d\n",
+            frameP,
+            slotP,
+            curr_pucch->frame,
+            curr_pucch->ul_slot,
+            O_sr,
+            O_ack,
+            O_csi,
+            k, l);
+
+      NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon;
+      nr_configure_pucch(pucch_pdu,
+                         scc,
+                         UE_info->UE_sched_ctrl[UE_id].active_ubwp,
+                         UE_info->rnti[UE_id],
+                         curr_pucch->resource_indicator,
+                         O_csi,
+                         O_ack,
+                         O_sr);
+
+      memset(&UE_info->UE_sched_ctrl[UE_id].sched_pucch[k][l],
+             0,
+             sizeof(NR_sched_pucch));
     }
   }
 }
@@ -147,7 +155,7 @@ void compute_csi_bitlen (NR_CellGroupConfig_t *secondaryCellGroup, NR_UE_info_t
                 UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen =0;
               }
 
-              LOG_I (MAC, "UCI: CSI_bit len : ssbri %d, rsrp: %d, diff_rsrp: %d",
+              LOG_I (MAC, "UCI: CSI_bit len : ssbri %d, rsrp: %d, diff_rsrp: %d\n",
                      UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].cri_ssbri_bitlen,
                      UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].rsrp_bitlen,
                      UE_info->csi_report_template[UE_id][csi_report_id].CSI_report_bitlen[0].diff_rsrp_bitlen);
@@ -213,7 +221,7 @@ void nr_csi_meas_reporting(int Mod_idP,
     if ( (frame%(period/n_slots_frame)==(offset/n_slots_frame)) && (slot==((sched_slot/slots_per_tdd)*slots_per_tdd))) {
 
       // we are scheduling pucch for csi in the first pucch occasion (this comes before ack/nack)
-      curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[sched_slot-slots_per_tdd+ul_slots][0];
+      curr_pucch = &UE_info->UE_sched_ctrl[UE_id].sched_pucch[(sched_slot%slots_per_tdd)-slots_per_tdd+ul_slots][0];
 
       NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0];
 
@@ -266,15 +274,27 @@ void nr_csi_meas_reporting(int Mod_idP,
 }
 
 
-void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
-                   nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01,
-                   nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234,
-                   NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats) {
+void handle_nr_uci_pucch_0_1(module_id_t mod_id,
+                             frame_t frame,
+                             sub_frame_t slot,
+                             const nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01)
+{
+  int UE_id = find_nr_UE_id(mod_id, uci_01->rnti);
+  if (UE_id < 0) {
+    LOG_E(MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_01->rnti);
+    return;
+  }
+  NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info;
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
+
+  // tpc (power control)
+  sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10,
+                                uci_01->ul_cqi,
+                                30);
 
   // TODO
   int max_harq_rounds = 4; // TODO define macro
-
-  if (uci_01 != NULL) {
+  if (((uci_01->pduBitmap >> 1) & 0x01)) {
     // handle harq
     int harq_idx_s = 0;
 
@@ -283,7 +303,7 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
       // search for the right harq process
       for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES; harq_idx++) {
         // if the gNB received ack with a good confidence
-        if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
+        if ((slot - 1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
           sched_ctrl->harq_processes[harq_idx].feedback_slot = -1;
           if ((uci_01->harq->harq_list[harq_bit].harq_value == 1) &&
               (uci_01->harq->harq_confidence_level == 0)) {
@@ -299,13 +319,13 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
           if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) {
             sched_ctrl->harq_processes[harq_idx].ndi ^= 1;
             sched_ctrl->harq_processes[harq_idx].round = 0;
-            stats->dlsch_errors++;
+            UE_info->mac_stats[UE_id].dlsch_errors++;
           }
           break;
         }
         // if feedback slot processing is aborted
         else if (sched_ctrl->harq_processes[harq_idx].feedback_slot != -1
-                 && (UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot
+                 && (slot - 1) > sched_ctrl->harq_processes[harq_idx].feedback_slot
                  && sched_ctrl->harq_processes[harq_idx].is_waiting) {
           sched_ctrl->harq_processes[harq_idx].feedback_slot = -1;
           sched_ctrl->harq_processes[harq_idx].round++;
@@ -318,9 +338,29 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
       }
     }
   }
+}
+
+void handle_nr_uci_pucch_2_3_4(module_id_t mod_id,
+                               frame_t frame,
+                               sub_frame_t slot,
+                               const nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234)
+{
+  int UE_id = find_nr_UE_id(mod_id, uci_234->rnti);
+  if (UE_id < 0) {
+    LOG_E(MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_234->rnti);
+    return;
+  }
+  NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info;
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
 
+  // tpc (power control)
+  sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10,
+                                uci_234->ul_cqi,
+                                30);
 
-  if (uci_234 != NULL) {
+  // TODO
+  int max_harq_rounds = 4; // TODO define macro
+  if ((uci_234->pduBitmap >> 1) & 0x01) {
     int harq_idx_s = 0;
     int acknack;
 
@@ -329,7 +369,7 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
       acknack = ((uci_234->harq.harq_payload[harq_bit>>3])>>harq_bit)&0x01;
       for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES-1; harq_idx++) {
         // if the gNB received ack with a good confidence or if the max harq rounds was reached
-        if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
+        if ((slot - 1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
           // TODO add some confidence level for when there is no CRC
           sched_ctrl->harq_processes[harq_idx].feedback_slot = -1;
           if ((uci_234->harq.harq_crc != 1) && acknack) {
@@ -345,13 +385,13 @@ void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
           if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) {
             sched_ctrl->harq_processes[harq_idx].ndi ^= 1;
             sched_ctrl->harq_processes[harq_idx].round = 0;
-            stats->dlsch_errors++;
+            UE_info->mac_stats[UE_id].dlsch_errors++;
           }
           break;
         }
         // if feedback slot processing is aborted
         else if (sched_ctrl->harq_processes[harq_idx].feedback_slot != -1
-                 && (UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot
+                 && (slot - 1) > sched_ctrl->harq_processes[harq_idx].feedback_slot
                  && sched_ctrl->harq_processes[harq_idx].is_waiting) {
           sched_ctrl->harq_processes[harq_idx].feedback_slot = -1;
           sched_ctrl->harq_processes[harq_idx].round++;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
index a90b4c7a179552fd4bdce3fe74f8dc1fc38af167..2fa0de2f842d925c96ba5aa9787e15f7c40e271a 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
@@ -31,7 +31,7 @@
 
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
 #include "executables/softmodem-common.h"
-//#define ENABLE_MAC_PAYLOAD_DEBUG 1
+#include "common/utils/nr/nr_common.h"
 
 
 void nr_process_mac_pdu(
@@ -217,33 +217,18 @@ void nr_process_mac_pdu(
 		    log_dump(MAC, pdu_ptr + mac_subheader_len, 32, LOG_DUMP_CHAR, "\n");
 
                 #endif
-                if(IS_SOFTMODEM_NOS1){
-                  mac_rlc_data_ind(module_idP,
-                      0x1234,
-                      module_idP,
-                      frameP,
-                      ENB_FLAG_YES,
-                      MBMS_FLAG_NO,
-                      rx_lcid,
-                      (char *) (pdu_ptr + mac_subheader_len),
-                      mac_sdu_len,
-                      1,
-                      NULL);
-                }
-                else{
-                  mac_rlc_data_ind(module_idP,
-                      rnti,
-                      module_idP,
-                      frameP,
-                      ENB_FLAG_YES,
-                      MBMS_FLAG_NO,
-                      rx_lcid,
-                      (char *) (pdu_ptr + mac_subheader_len),
-                      mac_sdu_len,
-                      1,
-                      NULL);
-                }
 
+                mac_rlc_data_ind(module_idP,
+                                 rnti,
+                                 module_idP,
+                                 frameP,
+                                 ENB_FLAG_YES,
+                                 MBMS_FLAG_NO,
+                                 rx_lcid,
+                                 (char *) (pdu_ptr + mac_subheader_len),
+                                 mac_sdu_len,
+                                 1,
+                                 NULL);
 
 
             break;
@@ -262,37 +247,58 @@ void nr_process_mac_pdu(
     }
 }
 
-void handle_nr_ul_harq(uint16_t slot, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats, nfapi_nr_crc_t crc_pdu) {
+void handle_nr_ul_harq(module_id_t mod_id,
+                       frame_t frame,
+                       sub_frame_t slot,
+                       const nfapi_nr_crc_t *crc_pdu)
+{
+  int UE_id = find_nr_UE_id(mod_id, crc_pdu->rnti);
+  if (UE_id < 0) {
+    LOG_E(MAC, "%s(): unknown RNTI %04x in PUSCH\n", __func__, crc_pdu->rnti);
+    return;
+  }
+  NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info;
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
 
   int max_harq_rounds = 4; // TODO define macro
-  uint8_t hrq_id = crc_pdu.harq_id;
+  uint8_t hrq_id = crc_pdu->harq_id;
   NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id];
   if (cur_harq->state==ACTIVE_SCHED) {
-    if (!crc_pdu.tb_crc_status) {
+    if (!crc_pdu->tb_crc_status) {
       cur_harq->ndi ^= 1;
       cur_harq->round = 0;
       cur_harq->state = INACTIVE; // passed -> make inactive. can be used by scheduder for next grant
-#ifdef UL_HARQ_PRINT
-      printf("[HARQ HANDLER] Ulharq id %d crc passed, freeing it for scheduler\n",hrq_id);
-#endif
+      LOG_D(MAC,
+            "Ulharq id %d crc passed for RNTI %04x\n",
+            hrq_id,
+            crc_pdu->rnti);
     } else {
       cur_harq->round++;
       cur_harq->state = ACTIVE_NOT_SCHED;
-#ifdef UL_HARQ_PRINT
-      printf("[HARQ HANDLER] Ulharq id %d crc failed, requesting retransmission\n",hrq_id);
-#endif
+      LOG_D(MAC,
+            "Ulharq id %d crc failed for RNTI %04x\n",
+            hrq_id,
+            crc_pdu->rnti);
     }
 
     if (!(cur_harq->round<max_harq_rounds)) {
       cur_harq->ndi ^= 1;
       cur_harq->state = INACTIVE; // failed after 4 rounds -> make inactive
       cur_harq->round = 0;
-      LOG_D(MAC,"[HARQ HANDLER] RNTI %x: Ulharq id %d crc failed in all round, freeing it for scheduler\n",crc_pdu.rnti,hrq_id);
-      stats->ulsch_errors++;
+      LOG_D(MAC,
+            "RNTI %04x: Ulharq id %d crc failed in all rounds\n",
+            crc_pdu->rnti,
+            hrq_id);
+      UE_info->mac_stats[UE_id].ulsch_errors++;
     }
     return;
   } else
-    LOG_W(MAC,"Incorrect ULSCH HARQ process %d or invalid state %d (ignore this warning for RA)\n",hrq_id,cur_harq->state);
+    LOG_W(MAC,
+          "Incorrect ULSCH HARQ PID %d or invalid state %d for RNTI %04x "
+          "(ignore this warning for RA)\n",
+          hrq_id,
+          cur_harq->state,
+          crc_pdu->rnti);
 }
 
 /*
@@ -398,6 +404,11 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
                   bwpList->list.count);
       const int bwp_id = 1;
       UE_info->UE_sched_ctrl[UE_id].active_bwp = bwpList->list.array[bwp_id - 1];
+      struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList;
+      AssertFatal(ubwpList->list.count == 1,
+                  "uplinkBWP_ToAddModList has %d BWP!\n",
+                  ubwpList->list.count);
+      UE_info->UE_sched_ctrl[UE_id].active_ubwp = ubwpList->list.array[bwp_id - 1];
       LOG_I(MAC,
             "[gNB %d][RAPROC] PUSCH with TC_RNTI %x received correctly, "
             "adding UE MAC Context UE_id %d/RNTI %04x\n",
@@ -414,9 +425,390 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
             "reset RA state information for RA-RNTI %04x/index %d\n",
             ra->rnti,
             i);
+
       return;
     }
   }
+}
+
+long get_K2(NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu) {
+  DevAssert(ubwp);
+  const NR_PUSCH_TimeDomainResourceAllocation_t *tda_list = ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list.array[time_domain_assignment];
+  if (tda_list->k2)
+    return *tda_list->k2;
+  else if (mu < 2)
+    return 1;
+  else if (mu == 2)
+    return 2;
+  else
+    return 3;
+}
+
+int8_t select_ul_harq_pid(NR_UE_sched_ctrl_t *sched_ctrl) {
+  const uint8_t max_ul_harq_pids = 3; // temp: for testing
+  // schedule active harq processes
+  for (uint8_t hrq_id = 0; hrq_id < max_ul_harq_pids; hrq_id++) {
+    NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id];
+    if (cur_harq->state == ACTIVE_NOT_SCHED) {
+      LOG_D(MAC, "Found ulharq id %d, scheduling it for retransmission\n", hrq_id);
+      return hrq_id;
+    }
+  }
+
+  // schedule new harq processes
+  for (uint8_t hrq_id=0; hrq_id < max_ul_harq_pids; hrq_id++) {
+    NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id];
+    if (cur_harq->state == INACTIVE) {
+      LOG_D(MAC, "Found new ulharq id %d, scheduling it\n", hrq_id);
+      return hrq_id;
+    }
+  }
+  LOG_E(MAC, "All UL HARQ processes are busy. Cannot schedule ULSCH\n");
+  return -1;
+}
+
+void nr_simple_ulsch_preprocessor(module_id_t module_id,
+                                  frame_t frame,
+                                  sub_frame_t slot,
+                                  int num_slots_per_tdd,
+                                  uint64_t ulsch_in_slot_bitmap) {
+  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
+  NR_COMMON_channels_t *cc = nr_mac->common_channels;
+  NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
+  const int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
+  NR_UE_info_t *UE_info = &nr_mac->UE_info;
+
+  AssertFatal(UE_info->num_UEs <= 1,
+              "%s() cannot handle more than one UE, but found %d\n",
+              __func__,
+              UE_info->num_UEs);
+  if (UE_info->num_UEs == 0)
+    return;
+
+  const int UE_id = 0;
+  const int CC_id = 0;
+  NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
+
+  const int tda = 1;
+  const struct NR_PUSCH_TimeDomainResourceAllocationList *tdaList =
+    sched_ctrl->active_ubwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
+  AssertFatal(tda < tdaList->list.count,
+              "time domain assignment %d >= %d\n",
+              tda,
+              tdaList->list.count);
+  int K2 = get_K2(sched_ctrl->active_ubwp, tda, mu);
+  const int sched_frame = frame + (slot + K2 >= num_slots_per_tdd);
+  const int sched_slot = (slot + K2) % num_slots_per_tdd;
+  if (!is_xlsch_in_slot(ulsch_in_slot_bitmap, sched_slot))
+    return;
+
+  /* get first, largest unallocated region */
+  uint16_t *vrb_map_UL =
+      &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * 275];
+  uint16_t rbStart = 0;
+  while (vrb_map_UL[rbStart]) rbStart++;
+  const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+  uint16_t rbSize = 1;
+  while (rbStart + rbSize < bwpSize && !vrb_map_UL[rbStart+rbSize])
+    rbSize++;
+
+  sched_ctrl->sched_pusch.slot = sched_slot;
+  sched_ctrl->sched_pusch.frame = sched_frame;
+
+  const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
+  sched_ctrl->search_space = get_searchspace(sched_ctrl->active_bwp, target_ss);
+  uint8_t nr_of_candidates;
+  find_aggregation_candidates(&sched_ctrl->aggregation_level,
+                              &nr_of_candidates,
+                              sched_ctrl->search_space);
+  sched_ctrl->coreset = get_coreset(
+      sched_ctrl->active_bwp, sched_ctrl->search_space, 1 /* dedicated */);
+  const int cid = sched_ctrl->coreset->controlResourceSetId;
+  const uint16_t Y = UE_info->Y[UE_id][cid][slot];
+  const int m = UE_info->num_pdcch_cand[UE_id][cid];
+  sched_ctrl->cce_index = allocate_nr_CCEs(RC.nrmac[module_id],
+                                           sched_ctrl->active_bwp,
+                                           sched_ctrl->coreset,
+                                           sched_ctrl->aggregation_level,
+                                           Y,
+                                           m,
+                                           nr_of_candidates);
+  if (sched_ctrl->cce_index < 0) {
+    LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__);
+    return;
+  }
+  UE_info->num_pdcch_cand[UE_id][cid]++;
+
+  sched_ctrl->sched_pusch.time_domain_allocation = tda;
+  const long f = sched_ctrl->search_space->searchSpaceType->choice.ue_Specific->dci_Formats;
+  const int dci_format = f ? NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0;
+  const uint8_t num_dmrs_cdm_grps_no_data = 1;
+  /* we want to avoid a lengthy deduction of DMRS and other parameters in
+   * every TTI if we can save it, so check whether dci_format, TDA, or
+   * num_dmrs_cdm_grps_no_data has changed and only then recompute */
+  NR_sched_pusch_save_t *ps = &sched_ctrl->pusch_save;
+  if (ps->time_domain_allocation != tda
+      || ps->dci_format != dci_format
+      || ps->num_dmrs_cdm_grps_no_data != num_dmrs_cdm_grps_no_data)
+    nr_save_pusch_fields(scc,
+                         sched_ctrl->active_ubwp,
+                         dci_format,
+                         tda,
+                         num_dmrs_cdm_grps_no_data,
+                         ps);
+
+  const int mcs = 9;
+  NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
+  sched_pusch->mcs = mcs;
+  sched_pusch->rbStart = rbStart;
+  sched_pusch->rbSize = rbSize;
+
+  /* Calculate TBS from MCS */
+  sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table);
+  sched_pusch->Qm = nr_get_Qm_ul(mcs, ps->mcs_table);
+  if (ps->pusch_Config->tp_pi2BPSK
+      && ((ps->mcs_table == 3 && mcs < 2) || (ps->mcs_table == 4 && mcs < 6))) {
+    sched_pusch->R >>= 1;
+    sched_pusch->Qm <<= 1;
+  }
+  sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm,
+                                        sched_pusch->R,
+                                        sched_pusch->rbSize,
+                                        ps->nrOfSymbols,
+                                        ps->N_PRB_DMRS * ps->num_dmrs_symb,
+                                        0, // nb_rb_oh
+                                        0,
+                                        1 /* NrOfLayers */)
+                         >> 3;
+
+  /* mark the corresponding RBs as used */
+  for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++)
+    vrb_map_UL[rb + sched_ctrl->sched_pusch.rbStart] = 1;
+}
 
+void nr_schedule_ulsch(module_id_t module_id,
+                       frame_t frame,
+                       sub_frame_t slot,
+                       int num_slots_per_tdd,
+                       int ul_slots,
+                       uint64_t ulsch_in_slot_bitmap) {
+  RC.nrmac[module_id]->pre_processor_ul(
+      module_id, frame, slot, num_slots_per_tdd, ulsch_in_slot_bitmap);
+
+  NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon;
+  NR_UE_info_t *UE_info = &RC.nrmac[module_id]->UE_info;
+  const NR_UE_list_t *UE_list = &UE_info->list;
+  for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
+    NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
+    /* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in
+     * every TTI are pre-populated by the preprocessor and used below */
+    NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
+    if (sched_pusch->rbSize <= 0)
+      continue;
+
+    uint16_t rnti = UE_info->rnti[UE_id];
+
+    int8_t harq_id = select_ul_harq_pid(sched_ctrl);
+    if (harq_id < 0) return;
+    NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[harq_id];
+    cur_harq->state = ACTIVE_SCHED;
+    cur_harq->last_tx_slot = sched_pusch->slot;
+
+    int rnti_types[2] = { NR_RNTI_C, 0 };
+
+    /* pre-computed PUSCH values that only change if time domain allocation,
+     * DCI format, or DMRS parameters change. Updated in the preprocessor
+     * through nr_save_pusch_fields() */
+    NR_sched_pusch_save_t *ps = &sched_ctrl->pusch_save;
+
+    /* Statistics */
+    UE_info->mac_stats[UE_id].ulsch_rounds[cur_harq->round]++;
+    if (cur_harq->round == 0) {
+      UE_info->mac_stats[UE_id].ulsch_total_bytes_scheduled += sched_pusch->tb_size;
+    } else {
+      LOG_W(MAC,
+            "%d.%2d UL retransmission RNTI %04x sched %d.%2d HARQ PID %d round %d NDI %d\n",
+            frame,
+            slot,
+            rnti,
+            sched_pusch->frame,
+            sched_pusch->slot,
+            harq_id,
+            cur_harq->round,
+            cur_harq->ndi);
+    }
+
+    LOG_D(MAC,
+          "%4d.%2d RNTI %04x UL sched %4d.%2d start %d RBS %d MCS %d TBS %d HARQ PID %d round %d NDI %d\n",
+          frame,
+          slot,
+          rnti,
+          sched_pusch->frame,
+          sched_pusch->slot,
+          sched_pusch->rbStart,
+          sched_pusch->rbSize,
+          sched_pusch->mcs,
+          sched_pusch->tb_size,
+          harq_id,
+          cur_harq->round,
+          cur_harq->ndi);
+
+    /* PUSCH in a later slot, but corresponding DCI now! */
+    nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_id]->UL_tti_req_ahead[0][sched_pusch->slot];
+    AssertFatal(future_ul_tti_req->SFN == sched_pusch->frame
+                && future_ul_tti_req->Slot == sched_pusch->slot,
+                "%d.%d future UL_tti_req's frame.slot %d.%d does not match PUSCH %d.%d\n",
+                frame, slot,
+                future_ul_tti_req->SFN,
+                future_ul_tti_req->Slot,
+                sched_pusch->frame,
+                sched_pusch->slot);
+    future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
+    future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
+    nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu;
+    memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t));
+    future_ul_tti_req->n_pdus += 1;
+
+    LOG_D(MAC, "%4d.%2d Scheduling UE specific PUSCH\n", frame, slot);
+
+    pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA;
+    pusch_pdu->rnti = rnti;
+    pusch_pdu->handle = 0; //not yet used
+
+    /* FAPI: BWP */
+    pusch_pdu->bwp_size  = NRRIV2BW(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+    pusch_pdu->bwp_start = NRRIV2PRBOFFSET(sched_ctrl->active_ubwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+    pusch_pdu->subcarrier_spacing = sched_ctrl->active_ubwp->bwp_Common->genericParameters.subcarrierSpacing;
+    pusch_pdu->cyclic_prefix = 0;
+
+    /* FAPI: PUSCH information always included */
+    pusch_pdu->target_code_rate = sched_pusch->R;
+    pusch_pdu->qam_mod_order = sched_pusch->Qm;
+    pusch_pdu->mcs_index = sched_pusch->mcs;
+    pusch_pdu->mcs_table = ps->mcs_table;
+    pusch_pdu->transform_precoding = ps->transform_precoding;
+    if (ps->pusch_Config->dataScramblingIdentityPUSCH)
+      pusch_pdu->data_scrambling_id = *ps->pusch_Config->dataScramblingIdentityPUSCH;
+    else
+      pusch_pdu->data_scrambling_id = *scc->physCellId;
+    pusch_pdu->nrOfLayers = 1;
+
+    /* FAPI: DMRS */
+    pusch_pdu->ul_dmrs_symb_pos = ps->ul_dmrs_symb_pos;
+    pusch_pdu->dmrs_config_type = ps->dmrs_config_type;
+    if (pusch_pdu->transform_precoding) { // transform precoding disabled
+      long *scramblingid;
+      if (pusch_pdu->scid == 0)
+        scramblingid = ps->NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0;
+      else
+        scramblingid = ps->NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID1;
+      if (scramblingid == NULL)
+        pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
+      else
+        pusch_pdu->ul_dmrs_scrambling_id = *scramblingid;
+    }
+    else {
+      pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
+      if (ps->NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
+        pusch_pdu->pusch_identity = *ps->NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity;
+      else
+        pusch_pdu->pusch_identity = *scc->physCellId;
+    }
+    pusch_pdu->scid = 0;      // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]
+    pusch_pdu->num_dmrs_cdm_grps_no_data = ps->num_dmrs_cdm_grps_no_data;
+    pusch_pdu->dmrs_ports = 1;
+
+    /* FAPI: Pusch Allocation in frequency domain */
+    AssertFatal(ps->pusch_Config->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1,
+                "Only frequency resource allocation type 1 is currently supported\n");
+    pusch_pdu->resource_alloc = 1; //type 1
+    pusch_pdu->rb_start = sched_pusch->rbStart;
+    pusch_pdu->rb_size = sched_pusch->rbSize;
+    pusch_pdu->vrb_to_prb_mapping = 0;
+    if (ps->pusch_Config->frequencyHopping==NULL)
+      pusch_pdu->frequency_hopping = 0;
+    else
+      pusch_pdu->frequency_hopping = 1;
+
+    /* FAPI: Resource Allocation in time domain */
+    pusch_pdu->start_symbol_index = ps->startSymbolIndex;
+    pusch_pdu->nr_of_symbols = ps->nrOfSymbols;
+
+    /* PUSCH PDU */
+    pusch_pdu->pusch_data.rv_index = nr_rv_round_map[cur_harq->round];
+    pusch_pdu->pusch_data.harq_process_id = harq_id;
+    pusch_pdu->pusch_data.new_data_indicator = cur_harq->ndi;
+    pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size;
+    pusch_pdu->pusch_data.num_cb = 0; //CBG not supported
+
+    /* PUSCH PTRS */
+    if (ps->NR_DMRS_UplinkConfig->phaseTrackingRS != NULL) {
+      // TODO to be fixed from RRC config
+      uint8_t ptrs_mcs1 = 2;  // higher layer parameter in PTRS-UplinkConfig
+      uint8_t ptrs_mcs2 = 4;  // higher layer parameter in PTRS-UplinkConfig
+      uint8_t ptrs_mcs3 = 10; // higher layer parameter in PTRS-UplinkConfig
+      uint16_t n_rb0 = 25;    // higher layer parameter in PTRS-UplinkConfig
+      uint16_t n_rb1 = 75;    // higher layer parameter in PTRS-UplinkConfig
+      pusch_pdu->pusch_ptrs.ptrs_time_density = get_L_ptrs(ptrs_mcs1, ptrs_mcs2, ptrs_mcs3, pusch_pdu->mcs_index, pusch_pdu->mcs_table);
+      pusch_pdu->pusch_ptrs.ptrs_freq_density = get_K_ptrs(n_rb0, n_rb1, pusch_pdu->rb_size);
+      pusch_pdu->pusch_ptrs.ptrs_ports_list   = (nfapi_nr_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ptrs_ports_t));
+      pusch_pdu->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset = 0;
+
+      pusch_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS; // enable PUSCH PTRS
+    }
+    else{
+      pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
+    }
+
+    nfapi_nr_ul_dci_request_t *ul_dci_req = &RC.nrmac[module_id]->UL_dci_req[0];
+    ul_dci_req->SFN = frame;
+    ul_dci_req->Slot = slot;
+    nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu = &ul_dci_req->ul_dci_pdu_list[ul_dci_req->numPdus];
+    memset(ul_dci_request_pdu, 0, sizeof(nfapi_nr_ul_dci_request_pdus_t));
+    ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE;
+    ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu));
+    nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15;
+    ul_dci_req->numPdus += 1;
+
+    LOG_D(MAC,"Configuring ULDCI/PDCCH in %d.%d\n", frame,slot);
+
+    nr_configure_pdcch(RC.nrmac[0],
+                       pdcch_pdu_rel15,
+                       rnti,
+                       sched_ctrl->search_space,
+                       sched_ctrl->coreset,
+                       scc,
+                       sched_ctrl->active_bwp,
+                       sched_ctrl->aggregation_level,
+                       sched_ctrl->cce_index);
+
+    dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET];
+    memset(dci_pdu_rel15, 0, sizeof(dci_pdu_rel15));
+    NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id];
+    const int n_ubwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count;
+    // NOTE: below functions assume that dci_formats is an array corresponding
+    // to all UL DCIs in the PDCCH, but for us it is a simple int. So before
+    // having multiple UEs, the below need to be changed (IMO the functions
+    // should fill for one DCI only and not handle all of them).
+    config_uldci(sched_ctrl->active_ubwp,
+                 pusch_pdu,
+                 pdcch_pdu_rel15,
+                 &dci_pdu_rel15[0],
+                 &ps->dci_format,
+                 ps->time_domain_allocation,
+                 UE_info->UE_sched_ctrl[UE_id].tpc0,
+                 n_ubwp,
+                 sched_ctrl->active_bwp->bwp_Id);
+    fill_dci_pdu_rel15(scc,
+                       secondaryCellGroup,
+                       pdcch_pdu_rel15,
+                       dci_pdu_rel15,
+                       &ps->dci_format,
+                       rnti_types,
+                       pusch_pdu->bwp_size,
+                       sched_ctrl->active_bwp->bwp_Id);
+
+    memset(sched_pusch, 0, sizeof(*sched_pusch));
+  }
 }
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index 7bb08e4f046f2b714f7dbbc281d8db2987468889..c4b2f5503e9be850abfd17db70797a5306ca3073 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -88,6 +88,20 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id,
 
 void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP, uint8_t slots_per_frame);
 
+/// uplink scheduler
+void nr_schedule_ulsch(module_id_t module_id,
+                       frame_t frame,
+                       sub_frame_t slot,
+                       int num_slots_per_tdd,
+                       int ul_slots,
+                       uint64_t ulsch_in_slot_bitmap);
+
+void nr_simple_ulsch_preprocessor(module_id_t module_id,
+                                  frame_t frame,
+                                  sub_frame_t slot,
+                                  int num_slots_per_tdd,
+                                  uint64_t ulsch_in_slot_bitmap);
+
 /////// Random Access MAC-PHY interface functions and primitives ///////
 
 void nr_schedule_RA(module_id_t module_idP, frame_t frameP, sub_frame_t slotP);
@@ -107,7 +121,9 @@ void nr_clear_ra_proc(module_id_t module_idP, int CC_id, frame_t frameP);
 
 int nr_allocate_CCEs(int module_idP, int CC_idP, frame_t frameP, sub_frame_t slotP, int test_only);
 
-void nr_get_Msg3alloc(NR_ServingCellConfigCommon_t *scc,
+void nr_get_Msg3alloc(module_id_t module_id,
+                      int CC_id,
+                      NR_ServingCellConfigCommon_t *scc,
                       NR_BWP_Uplink_t *ubwp,
                       sub_frame_t current_subframe,
                       frame_t current_frame,
@@ -136,6 +152,13 @@ void nr_preprocessor_phytest(module_id_t module_id,
                              frame_t frame,
                              sub_frame_t slot,
                              int num_slots_per_tdd);
+/* \brief UL preprocessor for phytest: schedules UE_id 0 with fixed MCS on a
+ * fixed set of resources */
+void nr_ul_preprocessor_phytest(module_id_t module_id,
+                                frame_t frame,
+                                sub_frame_t slot,
+                                int num_slots_per_tdd,
+                                uint64_t ulsch_in_slot_bitmap);
 
 void nr_schedule_css_dlsch_phytest(module_id_t   module_idP,
                                    frame_t       frameP,
@@ -157,26 +180,24 @@ void nr_fill_nfapi_dl_pdu(int Mod_id,
                           int ndi,
                           int round);
 
-void nr_rx_acknack(nfapi_nr_uci_pusch_pdu_t *uci_pusch,
-                   nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01,
-                   nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234,
-                   NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats);
+void handle_nr_uci_pucch_0_1(module_id_t mod_id,
+                             frame_t frame,
+                             sub_frame_t slot,
+                             const nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_01);
+void handle_nr_uci_pucch_2_3_4(module_id_t mod_id,
+                               frame_t frame,
+                               sub_frame_t slot,
+                               const nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_234);
+
 
 void config_uldci(NR_BWP_Uplink_t *ubwp,
                   nfapi_nr_pusch_pdu_t *pusch_pdu,
                   nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
                   dci_pdu_rel15_t *dci_pdu_rel15,
-                  int *dci_formats, int *rnti_types,
+                  int *dci_formats,
                   int time_domain_assignment, uint8_t tpc,
                   int n_ubwp, int bwp_id);
 
-void nr_schedule_pusch(int Mod_idP,
-                       int UE_id,
-                       int num_slots_per_tdd,
-                       int ul_slots,
-                       frame_t       frameP,
-                       sub_frame_t   slotP);
-
 void nr_schedule_pucch(int Mod_idP,
                        int UE_id,
                        int nr_ulmix_slots,
@@ -279,6 +300,15 @@ void find_aggregation_candidates(uint8_t *aggregation_level,
                                  uint8_t *nr_of_candidates,
                                  NR_SearchSpace_t *ss);
 
+long get_K2(NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu);
+
+void nr_save_pusch_fields(const NR_ServingCellConfigCommon_t *scc,
+                          const NR_BWP_Uplink_t *ubwp,
+                          long dci_format,
+                          int tda,
+                          uint8_t num_dmrs_cdm_grps_no_data,
+                          NR_sched_pusch_save_t *ps);
+
 uint8_t nr_get_tpc(int target, uint8_t cqi, int incr);
 
 int get_spf(nfapi_nr_config_request_scf_t *cfg);
@@ -353,16 +383,6 @@ void nr_generate_Msg2(module_id_t module_idP,
                       frame_t frameP,
                       sub_frame_t slotP);
 
-void nr_schedule_reception_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t slotP);
-
-void schedule_fapi_ul_pdu(int Mod_idP,
-                          frame_t frameP,
-                          sub_frame_t slotP,
-                          int num_slots_per_tdd,
-                          int ul_slots,
-                          int time_domain_assignment,
-                          uint64_t ulsch_in_slot_bitmap);
-
 void nr_process_mac_pdu(
     module_id_t module_idP,
     rnti_t rnti,
@@ -398,7 +418,10 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
                const uint8_t ul_cqi,
                const uint16_t rssi);
 
-void handle_nr_ul_harq(uint16_t slot, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats, nfapi_nr_crc_t crc_pdu);
+void handle_nr_ul_harq(module_id_t mod_id,
+                       frame_t frame,
+                       sub_frame_t slot,
+                       const nfapi_nr_crc_t *crc_pdu);
 
 int16_t ssb_index_from_prach(module_id_t module_idP,
                              frame_t frameP,
@@ -409,5 +432,4 @@ int16_t ssb_index_from_prach(module_id_t module_idP,
 
 void find_SSB_and_RO_available(module_id_t module_idP);
 
-void handle_nr_uci(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats, int target_snrx10);
 #endif /*__LAYER2_NR_MAC_PROTO_H__*/
diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c
index b7db1f67aa59ebab45bed359646bb4a06ceeb7bd..78a0dbb649ddbd8af9646e644b9fd60836d53bf5 100644
--- a/openair2/LAYER2/NR_MAC_gNB/main.c
+++ b/openair2/LAYER2/NR_MAC_gNB/main.c
@@ -34,7 +34,6 @@
 #include "NR_MAC_COMMON/nr_mac_extern.h"
 #include "assertions.h"
 
-#include "LAYER2/PDCP_v10.1.0/pdcp.h"
 #include "LAYER2/nr_pdcp/nr_pdcp_entity.h"
 #include "RRC/NR/nr_rrc_defs.h"
 #include "common/utils/LOG/log.h"
@@ -82,10 +81,13 @@ void mac_top_init_gNB(void)
         
       RC.nrmac[i]->ul_handle = 0;
 
-      if (get_softmodem_params()->phy_test)
+      if (get_softmodem_params()->phy_test) {
         RC.nrmac[i]->pre_processor_dl = nr_preprocessor_phytest;
-      else
+        RC.nrmac[i]->pre_processor_ul = nr_ul_preprocessor_phytest;
+      } else {
         RC.nrmac[i]->pre_processor_dl = nr_simple_dlsch_preprocessor;
+        RC.nrmac[i]->pre_processor_ul = nr_simple_ulsch_preprocessor;
+      }
 
     }//END for (i = 0; i < RC.nb_nr_macrlc_inst; i++)
 
@@ -94,8 +96,8 @@ void mac_top_init_gNB(void)
     // These should be out of here later
     pdcp_layer_init();
 
-    if(IS_SOFTMODEM_NOS1)
-      nr_DRB_preconfiguration();
+    if(IS_SOFTMODEM_NOS1 && !get_softmodem_params()->do_ra)
+      nr_DRB_preconfiguration(0x1234);
 
     rrc_init_nr_global_param();
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 8e00bc090272354f192bc12a6c5d5d2c657c78d0..8b2e8fb0c79a44a4f9f61dcb3e385494ba9aecbf 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -62,8 +62,6 @@
 #include "NR_PHY_INTERFACE/NR_IF_Module.h"
 
 /* MAC */
-#include "LAYER2/MAC/mac.h"
-#include "LAYER2/MAC/mac_proto.h"
 #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
 #include "LAYER2/NR_MAC_COMMON/nr_mac_common.h"
 #include "NR_TAG.h"
@@ -142,8 +140,6 @@ typedef struct {
   uint8_t msg3_cqireq;
   /// Round of Msg3 HARQ
   uint8_t msg3_round;
-  /// Msg3 pusch pdu
-  nfapi_nr_pusch_pdu_t pusch_pdu;
   /// TBS used for Msg4
   int msg4_TBsize;
   /// MCS used for Msg4
@@ -192,8 +188,9 @@ typedef struct {
   NR_RA_t ra[NR_NB_RA_PROC_MAX];
   /// VRB map for common channels
   uint16_t vrb_map[275];
-  /// VRB map for common channels and retransmissions by PHICH
-  uint16_t vrb_map_UL[275];
+  /// VRB map for common channels and PUSCH, dynamically allocated because
+  /// length depends on number of slots and RBs
+  uint16_t *vrb_map_UL;
   /// number of subframe allocation pattern available for MBSFN sync area
   uint8_t num_sf_allocation_pattern;
   ///Number of active SSBs
@@ -285,12 +282,49 @@ typedef struct NR_sched_pucch {
   uint8_t resource_indicator;
 } NR_sched_pucch;
 
+/* this struct is a helper: as long as the TDA and DCI format remain the same
+ * over the same uBWP and search space, there is no need to recalculate all
+ * S/L, MCS table, or DMRS-related parameters over and over again. Hence, we
+ * store them in this struct for easy reference. */
+typedef struct NR_sched_pusch_save {
+  int dci_format;
+  int time_domain_allocation;
+  uint8_t num_dmrs_cdm_grps_no_data;
+
+  int startSymbolIndex;
+  int nrOfSymbols;
+
+  NR_PUSCH_Config_t *pusch_Config;
+  uint8_t transform_precoding;
+  uint8_t mcs_table;
+
+  long mapping_type;
+  NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig;
+  uint16_t dmrs_config_type;
+  uint16_t ul_dmrs_symb_pos;
+  uint8_t num_dmrs_symb;
+  uint8_t N_PRB_DMRS;
+} NR_sched_pusch_save_t;
+
 typedef struct NR_sched_pusch {
   int frame;
   int slot;
-  bool active;
-  nfapi_nr_pusch_pdu_t pusch_pdu;
-} NR_sched_pusch;
+
+  /// RB allocation within active uBWP
+  uint16_t rbSize;
+  uint16_t rbStart;
+
+  // time-domain allocation for scheduled RBs
+  int time_domain_allocation;
+
+  /// MCS
+  uint8_t mcs;
+
+  /// TBS-related info
+  uint16_t R;
+  uint8_t Qm;
+  uint32_t tb_size;
+} NR_sched_pusch_t;
 
 typedef struct NR_UE_harq {
   uint8_t is_waiting;
@@ -348,11 +382,15 @@ typedef struct {
 
   /// the currently active BWP in DL
   NR_BWP_Downlink_t *active_bwp;
+  /// the currently active BWP in UL
+  NR_BWP_Uplink_t *active_ubwp;
+
   NR_sched_pucch **sched_pucch;
   /// selected PUCCH index, if scheduled
   int pucch_sched_idx;
   int pucch_occ_idx;
-  NR_sched_pusch *sched_pusch;
+  NR_sched_pusch_save_t pusch_save;
+  NR_sched_pusch_t sched_pusch;
 
   /// CCE index and aggregation, should be coherent with cce_list
   NR_SearchSpace_t *search_space;
@@ -381,7 +419,6 @@ typedef struct {
   uint8_t tpc0;
   uint8_t tpc1;
   uint16_t ul_rssi;
-  uint8_t current_harq_pid;
   NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES];
   NR_UE_ul_harq_t ul_harq_processes[NR_MAX_NB_HARQ_PROCESSES];
   int dummy;
@@ -418,7 +455,6 @@ typedef struct {
 /*! \brief UE list used by gNB to order UEs/CC for scheduling*/
 #define MAX_CSI_REPORTCONFIG 48
 typedef struct {
-  DLSCH_PDU DLSCH_pdu[4][MAX_MOBILES_PER_GNB];
   /// scheduling control info
   nr_csi_report_t csi_report_template[MAX_MOBILES_PER_GNB][MAX_CSI_REPORTCONFIG];
   NR_UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB];
@@ -442,6 +478,11 @@ typedef void (*nr_pp_impl_dl)(module_id_t mod_id,
                               frame_t frame,
                               sub_frame_t slot,
                               int num_slots_per_tdd);
+typedef void (*nr_pp_impl_ul)(module_id_t mod_id,
+                              frame_t frame,
+                              sub_frame_t slot,
+                              int num_slots_per_tdd,
+                              uint64_t ulsch_in_slot_bitmap);
 
 /*! \brief top level eNB MAC structure */
 typedef struct gNB_MAC_INST_s {
@@ -468,8 +509,12 @@ typedef struct gNB_MAC_INST_s {
   nfapi_nr_config_request_scf_t     config[NFAPI_CC_MAX];
   /// NFAPI DL Config Request Structure
   nfapi_nr_dl_tti_request_t         DL_req[NFAPI_CC_MAX];
-  /// NFAPI UL TTI Request Structure (this is from the new SCF specs)
-  nfapi_nr_ul_tti_request_t         UL_tti_req[NFAPI_CC_MAX];
+  /// NFAPI UL TTI Request Structure, simple pointer into structure
+  /// UL_tti_req_ahead for current frame/slot
+  nfapi_nr_ul_tti_request_t        *UL_tti_req[NFAPI_CC_MAX];
+  /// NFAPI UL TTI Request Structure for future TTIs, dynamically allocated
+  /// because length depends on number of slots
+  nfapi_nr_ul_tti_request_t        *UL_tti_req_ahead[NFAPI_CC_MAX];
   /// NFAPI HI/DCI0 Config Request Structure
   nfapi_nr_ul_dci_request_t         UL_dci_req[NFAPI_CC_MAX];
   /// NFAPI DL PDU structure
@@ -503,11 +548,11 @@ typedef struct gNB_MAC_INST_s {
   time_stats_t schedule_pch;
   /// CCE lists
   int cce_list[MAX_NUM_BWP][MAX_NUM_CORESET][MAX_NUM_CCE];
-  /// current slot
-  int current_slot;
 
   /// DL preprocessor for differentiated scheduling
   nr_pp_impl_dl pre_processor_dl;
+  /// UL preprocessor for differentiated scheduling
+  nr_pp_impl_ul pre_processor_ul;
 } gNB_MAC_INST;
 
 #endif /*__LAYER2_NR_MAC_GNB_H__ */
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
index 22843bb956a9aaa33da1fff8725b144a088484b0..9308dd6f2eaba2bdfb8918a33aeb1e6a10934ab0 100644
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
@@ -358,16 +358,7 @@ boolean_t pdcp_data_req(
       LOG_D(PDCP, "pdcp data req on drb %ld, size %d, rnti %x, node_type %d \n",
             rb_idP, pdcp_pdu_size, ctxt_pP->rnti, RC.rrc ? RC.rrc[ctxt_pP->module_id]->node_type: -1);
 
-      // The check on nos1 is done only for the use case of LTE stack running over 5g-nr PHY. This should be changed
-      // before future merge of develop with develop-nr and instead of a check of IS_SOFTMODEM_NOS1, we should use a check
-      // with a new execution option capturing the nr-ip-over-LTE-stack use case.
-      ngran_node_t node_type;
-      if (IS_SOFTMODEM_NOS1)
-    	  node_type = ngran_gNB;
-      else
-    	  node_type = RC.rrc[ctxt_pP->module_id]->node_type;
-
-      if (ctxt_pP->enb_flag == ENB_FLAG_YES && NODE_IS_DU(node_type)) { //RC.rrc[ctxt_pP->module_id]->node_type
+      if (ctxt_pP->enb_flag == ENB_FLAG_YES && NODE_IS_DU(RC.rrc[ctxt_pP->module_id]->node_type)) {
         LOG_E(PDCP, "Can't be DU, bad node type %d \n", RC.rrc[ctxt_pP->module_id]->node_type);
         ret=FALSE;
       } else {
diff --git a/openair2/LAYER2/nr_pdcp/asn1_utils.c b/openair2/LAYER2/nr_pdcp/asn1_utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..264a2815bb201ec046024dd3720a5719746890f8
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/asn1_utils.c
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#include "pdcp.h"
+
+int decode_t_reordering(int v)
+{
+  static int tab[36] = {
+    0, 1, 2, 4, 5, 8, 10, 15, 20, 30, 40, 50, 60, 80, 100, 120, 140, 160, 180,
+    200, 220, 240, 260, 280, 300, 500, 750, 1000, 1250, 1500, 1750, 2000,
+    2250, 2500, 2750, 3000
+  };
+
+  if (v < 0 || v > 35) {
+    LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  return tab[v];
+}
+
+int decode_sn_size_ul(long s)
+{
+  if (s == 0) return 12;
+  if (s == 1) return 18;
+  LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+  exit(1);
+}
+
+int decode_sn_size_dl(long s)
+{
+  if (s == 0) return 12;
+  if (s == 1) return 18;
+  LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+  exit(1);
+}
+
+int decode_discard_timer(long v)
+{
+  static int tab[16] = {
+    10, 20, 30, 40, 50, 60, 75, 100, 150, 200, 250, 300, 500, 750, 1500, -1,
+  };
+
+  if (v < 0 || v > 15) {
+    LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+    exit(1);
+  }
+
+  return tab[v];
+}
diff --git a/openair2/LAYER2/nr_pdcp/asn1_utils.h b/openair2/LAYER2/nr_pdcp/asn1_utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..d525bce287110560d51c2c6e9765c8e00ea41147
--- /dev/null
+++ b/openair2/LAYER2/nr_pdcp/asn1_utils.h
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+#ifndef _OPENAIR2_LAYER2_NR_PDCP_ASN1_UTILS_H_
+#define _OPENAIR2_LAYER2_NR_PDCP_ASN1_UTILS_H_
+
+int decode_t_reordering(int v);
+int decode_sn_size_ul(long s);
+int decode_sn_size_dl(long s);
+int decode_discard_timer(long v);
+
+#endif /* _OPENAIR2_LAYER2_NR_PDCP_ASN1_UTILS_H_ */
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
index e25201c22c4b4d0ba71df92c9994fcee8bd9370c..f3d4b1613099765430c8825047d0686f7cdfde82 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
@@ -44,7 +44,10 @@ nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
     void *deliver_sdu_data,
     void (*deliver_pdu)(void *deliver_pdu_data, struct nr_pdcp_entity_t *entity,
                         char *buf, int size, int sdu_id),
-    void *deliver_pdu_data)
+    void *deliver_pdu_data,
+    int sn_size,
+    int t_reordering,
+    int discard_timer)
 {
   nr_pdcp_entity_drb_am_t *ret;
 
@@ -66,9 +69,12 @@ nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
   ret->common.deliver_pdu = deliver_pdu;
   ret->common.deliver_pdu_data = deliver_pdu_data;
 
-  ret->rb_id = rb_id;
+  ret->rb_id         = rb_id;
+  ret->sn_size       = sn_size;
+  ret->t_reordering  = t_reordering;
+  ret->discard_timer = discard_timer;
 
-  ret->common.maximum_nr_pdcp_sn = 4095;
+  ret->common.maximum_nr_pdcp_sn = (1 << sn_size) - 1;
 
   return (nr_pdcp_entity_t *)ret;
 }
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
index 45555ad6af9374dc2a8c5138bc09f10e12311a1a..ce5dd300e96c2dc28ba7a42f03d903a495a80720 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
@@ -19,6 +19,8 @@
  *      contact@openairinterface.org
  */
 
+#include <stdint.h>
+
 #ifndef _NR_PDCP_ENTITY_H_
 #define _NR_PDCP_ENTITY_H_
 
@@ -58,8 +60,11 @@ nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
     void *deliver_sdu_data,
     void (*deliver_pdu)(void *deliver_pdu_data, struct nr_pdcp_entity_t *entity,
                         char *buf, int size, int sdu_id),
-    void *deliver_pdu_data);
+    void *deliver_pdu_data,
+    int sn_size,
+    int t_reordering,
+    int discard_timer);
 
-void nr_DRB_preconfiguration(void);
+void nr_DRB_preconfiguration(uint16_t crnti);
 
 #endif /* _NR_PDCP_ENTITY_H_ */
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c
index 16d306f64c55fb596d3ef9b5c7000e50f00cc3ca..f2f849b9e36e301eafd17688381de37da4400259 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c
@@ -24,13 +24,17 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "common/utils/LOG/log.h"
 
 void nr_pdcp_entity_drb_am_recv_pdu(nr_pdcp_entity_t *_entity, char *buffer, int size)
 {
   nr_pdcp_entity_drb_am_t *entity = (nr_pdcp_entity_drb_am_t *)_entity;
 
   if (size < 3) abort();
-  if (!(buffer[0] & 0x80)) { printf("%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); exit(1); }
+
+  if (!(buffer[0] & 0x80))
+    LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
+
   entity->common.deliver_sdu(entity->common.deliver_sdu_data,
                              (nr_pdcp_entity_t *)entity, buffer+3, size-3);
 }
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h
index faa8226e93b64ad3b0333254f60de646494e16ed..d7c42e6a629281ddc36253894857e120d95f3e93 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h
@@ -27,6 +27,9 @@
 typedef struct {
   nr_pdcp_entity_t common;
   int rb_id;
+  int sn_size;               /* unit: bits */
+  int t_reordering;          /* unit: ms */
+  int discard_timer;         /* unit: ms, -1 means infinity */
 } nr_pdcp_entity_drb_am_t;
 
 void nr_pdcp_entity_drb_am_recv_pdu(nr_pdcp_entity_t *entity, char *buffer, int size);
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
index 2919c9debaf687d99b871a7e938f437e38e30c47..46a4d4c827b48dfdc67395621e88abcc194c4d5b 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
@@ -22,14 +22,17 @@
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
+#include "asn1_utils.h"
 #include "nr_pdcp_ue_manager.h"
 #include "NR_RadioBearerConfig.h"
 #include "NR_RLC-BearerConfig.h"
+#include "NR_RLC-Config.h"
 #include "NR_CellGroupConfig.h"
 #include "openair2/RRC/NR/nr_rrc_proto.h"
 
 /* from OAI */
 #include "pdcp.h"
+#include "LAYER2/nr_rlc/nr_rlc_oai_api.h"
 
 #define TODO do { \
     printf("%s:%d:%s: todo\n", __FILE__, __LINE__, __FUNCTION__); \
@@ -409,7 +412,6 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
     len = write(nas_sock_fd[0], buf, size);
     if (len != size) {
       LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
-      exit(1);
     }
   }
   else{
@@ -594,8 +596,17 @@ static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s)
   nr_pdcp_ue_t *ue;
 
   int drb_id = s->drb_Identity;
-
-printf("\n\n################# rnti %d add drb %d\n\n\n", rnti, drb_id);
+  int t_reordering = decode_t_reordering(*s->pdcp_Config->t_Reordering);
+  int sn_size_ul = decode_sn_size_ul(*s->pdcp_Config->drb->pdcp_SN_SizeUL);
+  int sn_size_dl = decode_sn_size_dl(*s->pdcp_Config->drb->pdcp_SN_SizeDL);
+  int discard_timer = decode_discard_timer(*s->pdcp_Config->drb->discardTimer);
+
+  /* TODO(?): accept different UL and DL SN sizes? */
+  if (sn_size_ul != sn_size_dl) {
+    LOG_E(PDCP, "%s:%d:%s: fatal, bad SN sizes, must be same. ul=%d, dl=%d\n",
+          __FILE__, __LINE__, __FUNCTION__, sn_size_ul, sn_size_dl);
+    exit(1);
+  }
 
   if (drb_id != 1) {
     LOG_E(PDCP, "%s:%d:%s: fatal, bad drb id %d\n",
@@ -609,11 +620,11 @@ printf("\n\n################# rnti %d add drb %d\n\n\n", rnti, drb_id);
     LOG_D(PDCP, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n",
           __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   } else {
-    pdcp_drb = new_nr_pdcp_entity_drb_am(drb_id, deliver_sdu_drb, ue, deliver_pdu_drb, ue);
+    pdcp_drb = new_nr_pdcp_entity_drb_am(drb_id, deliver_sdu_drb, ue, deliver_pdu_drb, ue,
+                                         sn_size_dl, t_reordering, discard_timer);
     nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb);
 
-    LOG_D(PDCP, "%s:%d:%s: added drb %d to ue %d\n",
-          __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
+    LOG_D(PDCP, "%s:%d:%s: added drb %d to ue rnti %x\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   }
   nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
 }
@@ -634,6 +645,7 @@ static void add_drb(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_Config_t *rlc_Co
           __FILE__, __LINE__, __FUNCTION__);
     exit(1);
   }
+  LOG_I(PDCP, "%s:%s:%d: added DRB for UE RNTI %x\n", __FILE__, __FUNCTION__, __LINE__, rnti);
 }
 
 boolean_t nr_rrc_pdcp_config_asn1_req(
@@ -680,7 +692,6 @@ boolean_t nr_rrc_pdcp_config_asn1_req(
 
   if (drb2add_list != NULL) {
     for (i = 0; i < drb2add_list->list.count; i++) {
-      LOG_I(PDCP, "Before calling add_drb \n");
       add_drb(rnti, drb2add_list->list.array[i], rlc_bearer2add_list->list.array[i]->rlc_Config);
     }
   }
@@ -715,7 +726,7 @@ boolean_t rrc_pdcp_config_asn1_req(
   return 0;
 }
 
-void nr_DRB_preconfiguration(void)
+void nr_DRB_preconfiguration(uint16_t crnti)
 {
 
   NR_RadioBearerConfig_t             *rbconfig = NULL;
@@ -767,67 +778,19 @@ void nr_DRB_preconfiguration(void)
 
   xer_fprint(stdout, &asn_DEF_NR_RadioBearerConfig, (const void*)rbconfig);
 
-
   NR_RLC_BearerConfig_t *RLC_BearerConfig = calloc(1,sizeof(*RLC_BearerConfig));
-
-  RLC_BearerConfig->logicalChannelIdentity = 4;
-  RLC_BearerConfig->servedRadioBearer = calloc(1,sizeof(*RLC_BearerConfig->servedRadioBearer));
-  RLC_BearerConfig->servedRadioBearer->present =    NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity;
-
-  RLC_BearerConfig->servedRadioBearer->choice.drb_Identity=1;
-  RLC_BearerConfig->reestablishRLC=calloc(1,sizeof(*RLC_BearerConfig->reestablishRLC));
-  *RLC_BearerConfig->reestablishRLC=NR_RLC_BearerConfig__reestablishRLC_true;
-  RLC_BearerConfig->rlc_Config=calloc(1,sizeof(*RLC_BearerConfig->rlc_Config));
-
-  // RLC UM Bi-directional Bearer configuration
-  RLC_BearerConfig->rlc_Config->present = NR_RLC_Config_PR_um_Bi_Directional;
-  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional));
-  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength));
-  *RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength   =    NR_SN_FieldLengthUM_size12;
-
-  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength));
-  *RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength   =    NR_SN_FieldLengthUM_size12;
-  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = NR_T_Reassembly_ms15;
-
-  // RLC AM Bearer configuration
-  /*RLC_BearerConfig->rlc_Config->present = NR_RLC_Config_PR_am;
-  RLC_BearerConfig->rlc_Config->choice.am = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am));
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength));
-  *RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength   =    NR_SN_FieldLengthAM_size18;
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45;
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.pollPDU          = NR_PollPDU_p64;
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.pollByte         = NR_PollByte_kB500;
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t32;
-
-  RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength));
-  *RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18;
-  RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.t_Reassembly   = NR_T_Reassembly_ms15;
-  RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15;*/
-
-  RLC_BearerConfig->mac_LogicalChannelConfig = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig));
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters));
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->priority            = 1;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->prioritisedBitRate  = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->bucketSizeDuration  = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->allowedServingCells = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->allowedSCS_List     = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->maxPUSCH_Duration   = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->configuredGrantType1Allowed = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup   = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup));
-  *RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup  = 1;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID   = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = false;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = false;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->bitRateQueryProhibitTimer   = NULL;
+  nr_rlc_bearer_init(RLC_BearerConfig);
+  nr_drb_config(RLC_BearerConfig->rlc_Config, NR_RLC_Config_PR_um_Bi_Directional);
+  nr_rlc_bearer_init_ul_spec(RLC_BearerConfig->mac_LogicalChannelConfig);
 
   Rlc_Bearer_ToAdd_list = calloc(1,sizeof(*Rlc_Bearer_ToAdd_list));
   ASN_SEQUENCE_ADD(&Rlc_Bearer_ToAdd_list->list, RLC_BearerConfig);
 
   if (ENB_NAS_USE_TUN){
-    PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_YES, 0x1234, 0, 0,0);
+    PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_YES, crnti, 0, 0, 0);
   }
   else{
-    PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_NO, 0x1234, 0, 0,0);
+    PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_NO, crnti, 0, 0,0);
   }
 
   nr_rrc_pdcp_config_asn1_req(
@@ -849,6 +812,9 @@ void nr_DRB_preconfiguration(void)
       rbconfig->drb_ToReleaseList,
       (LTE_PMCH_InfoList_r9_t *) NULL,
       Rlc_Bearer_ToAdd_list);
+
+  LOG_D(PDCP, "%s:%d: done RRC PDCP/RLC ASN1 request for UE rnti %x\n", __FUNCTION__, __LINE__, ctxt.rnti);
+
 }
 
 uint64_t get_pdcp_optmask(void)
diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c
index 2ed01b5b7806e1159ed85a95914222d6f0798c08..2f0d46afacba5e539bfe984b48a75f9e0c0f08c3 100644
--- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c
@@ -27,6 +27,7 @@
 #include "asn1_utils.h"
 #include "nr_rlc_ue_manager.h"
 #include "nr_rlc_entity.h"
+#include "nr_rlc_oai_api.h"
 #include "NR_RLC-BearerConfig.h"
 #include "NR_DRB-ToAddMod.h"
 #include "NR_DRB-ToAddModList.h"
@@ -44,6 +45,76 @@ static uint64_t nr_rlc_current_time;
 static int      nr_rlc_current_time_last_frame;
 static int      nr_rlc_current_time_last_subframe;
 
+void nr_rlc_bearer_init(NR_RLC_BearerConfig_t *RLC_BearerConfig){
+
+
+  RLC_BearerConfig->servedRadioBearer                      = calloc(1, sizeof(*RLC_BearerConfig->servedRadioBearer));
+  RLC_BearerConfig->reestablishRLC                         = calloc(1, sizeof(*RLC_BearerConfig->reestablishRLC));
+  RLC_BearerConfig->rlc_Config                             = calloc(1, sizeof(*RLC_BearerConfig->rlc_Config));
+  RLC_BearerConfig->mac_LogicalChannelConfig               = calloc(1, sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig));
+
+  RLC_BearerConfig->logicalChannelIdentity                 = 4;
+  RLC_BearerConfig->servedRadioBearer->present             = NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity;
+  RLC_BearerConfig->servedRadioBearer->choice.drb_Identity = 1;
+  *RLC_BearerConfig->reestablishRLC                        = NR_RLC_BearerConfig__reestablishRLC_true;
+
+}
+
+void nr_rlc_bearer_init_ul_spec(struct NR_LogicalChannelConfig *mac_LogicalChannelConfig){
+
+  mac_LogicalChannelConfig->ul_SpecificParameters                              = calloc(1, sizeof(*mac_LogicalChannelConfig->ul_SpecificParameters));
+  mac_LogicalChannelConfig->ul_SpecificParameters->priority                    = 1;
+  mac_LogicalChannelConfig->ul_SpecificParameters->prioritisedBitRate          = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
+  mac_LogicalChannelConfig->ul_SpecificParameters->bucketSizeDuration          = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
+  mac_LogicalChannelConfig->ul_SpecificParameters->allowedServingCells         = NULL;
+  mac_LogicalChannelConfig->ul_SpecificParameters->allowedSCS_List             = NULL;
+  mac_LogicalChannelConfig->ul_SpecificParameters->maxPUSCH_Duration           = NULL;
+  mac_LogicalChannelConfig->ul_SpecificParameters->configuredGrantType1Allowed = NULL;
+
+  mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup                = calloc(1,sizeof(*mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup));
+  *mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup               = 1;
+  mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID                = NULL;
+  mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask              = false;
+  mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = false;
+  mac_LogicalChannelConfig->ul_SpecificParameters->bitRateQueryProhibitTimer          = NULL;
+
+}
+
+void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc_config_pr){
+
+  switch (rlc_config_pr){
+    case NR_RLC_Config_PR_um_Bi_Directional:
+      // RLC UM Bi-directional Bearer configuration
+      rlc_Config->choice.um_Bi_Directional                            = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional));
+      rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength  = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength));
+      *rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12;
+      rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength  = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength));
+      *rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12;
+      rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly    = NR_T_Reassembly_ms15;
+      break;
+    case NR_RLC_Config_PR_am:
+      // RLC AM Bearer configuration
+      rlc_Config->choice.am                             = calloc(1, sizeof(*rlc_Config->choice.am));
+      rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength   = calloc(1, sizeof(*rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength));
+      *rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength  = NR_SN_FieldLengthAM_size18;
+      rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45;
+      rlc_Config->choice.am->ul_AM_RLC.pollPDU          = NR_PollPDU_p64;
+      rlc_Config->choice.am->ul_AM_RLC.pollByte         = NR_PollByte_kB500;
+      rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t32;
+      rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength   = calloc(1, sizeof(*rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength));
+      *rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength  = NR_SN_FieldLengthAM_size18;
+      rlc_Config->choice.am->dl_AM_RLC.t_Reassembly     = NR_T_Reassembly_ms15;
+      rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15;
+      break;
+    default:
+      LOG_E (RLC, "Error in %s: RLC config type %d is not handled\n", __FUNCTION__, rlc_config_pr);
+      break;
+    }
+
+  rlc_Config->present = rlc_config_pr;
+
+}
+
 void mac_rlc_data_ind     (
   const module_id_t         module_idP,
   const rnti_t              rntiP,
@@ -179,6 +250,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind(
                         + buf_stat.retx_size
                         + buf_stat.tx_size;
   } else {
+    LOG_W(RLC, "[%s] Radio Bearer (channel ID %d) is NULL for UE with rntiP %x\n", __FUNCTION__, channel_idP, rntiP);
     ret.bytes_in_buffer = 0;
   }
 
@@ -586,8 +658,7 @@ static void add_srb(int rnti, struct LTE_SRB_ToAddMod *s)
   nr_rlc_manager_lock(nr_rlc_ue_manager);
   ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, rnti);
   if (ue->srb[srb_id-1] != NULL) {
-    LOG_D(RLC, "%s:%d:%s: warning SRB %d already exist for ue %d, do nothing\n",
-          __FILE__, __LINE__, __FUNCTION__, srb_id, rnti);
+    LOG_W(RLC, "%s:%d:%s: SRB %d already exists for UE with RNTI %x, do nothing\n", __FILE__, __LINE__, __FUNCTION__, srb_id, rnti);
   } else {
     /* hack: hardcode values for NR */
     t_poll_retransmit = 45;
@@ -678,8 +749,7 @@ static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_
   nr_rlc_manager_lock(nr_rlc_ue_manager);
   ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, rnti);
   if (ue->drb[drb_id-1] != NULL) {
-    LOG_D(RLC, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n",
-          __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
+    LOG_W(RLC, "%s:%d:%s: DRB %d already exists for UE with RNTI %d, do nothing\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   } else {
     nr_rlc_am = new_nr_rlc_entity_am(100000,
                                      100000,
@@ -692,8 +762,7 @@ static void add_drb_am(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_
                                      sn_field_length);
     nr_rlc_ue_add_drb_rlc_entity(ue, drb_id, nr_rlc_am);
 
-    LOG_D(RLC, "%s:%d:%s: added drb %d to ue %d\n",
-          __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
+    LOG_D(RLC, "%s:%d:%s: added drb %d to UE with RNTI %x\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   }
   nr_rlc_manager_unlock(nr_rlc_ue_manager);
 }
@@ -752,8 +821,7 @@ static void add_drb_um(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_
   nr_rlc_manager_lock(nr_rlc_ue_manager);
   ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, rnti);
   if (ue->drb[drb_id-1] != NULL) {
-    LOG_D(RLC, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n",
-          __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
+    LOG_W(RLC, "DEBUG add_drb_um %s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   } else {
     nr_rlc_um = new_nr_rlc_entity_um(1000000,
                                      1000000,
@@ -762,8 +830,7 @@ static void add_drb_um(int rnti, struct NR_DRB_ToAddMod *s, NR_RLC_BearerConfig_
                                      sn_field_length);
     nr_rlc_ue_add_drb_rlc_entity(ue, drb_id, nr_rlc_um);
 
-    LOG_D(RLC, "%s:%d:%s: added drb %d to ue %d\n",
-          __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
+    LOG_D(RLC, "%s:%d:%s: added drb %d to UE with RNTI %x\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   }
   nr_rlc_manager_unlock(nr_rlc_ue_manager);
 }
@@ -782,6 +849,7 @@ static void add_drb(int rnti, struct NR_DRB_ToAddMod *s, struct NR_RLC_BearerCon
           __FILE__, __LINE__, __FUNCTION__);
     exit(1);
   }
+  LOG_I(RLC, "%s:%s:%d: added DRB to UE with RNTI %x\n", __FILE__, __FUNCTION__, __LINE__, rnti);
 }
 
 /* Dummy function due to dependency from LTE libraries */
@@ -869,7 +937,7 @@ rlc_op_status_t rrc_rlc_config_req   (
     exit(1);
   }
   nr_rlc_manager_lock(nr_rlc_ue_manager);
-  LOG_D(RLC, "%s:%d:%s: remove rb %ld (is_srb %d) for UE %d\n", __FILE__, __LINE__, __FUNCTION__, rb_idP, srb_flagP, ctxt_pP->rnti);
+  LOG_D(RLC, "%s:%d:%s: remove rb %ld (is_srb %d) for UE RNTI %x\n", __FILE__, __LINE__, __FUNCTION__, rb_idP, srb_flagP, ctxt_pP->rnti);
   ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, ctxt_pP->rnti);
   if (srb_flagP) {
     if (ue->srb[rb_idP-1] != NULL) {
diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h
new file mode 100644
index 0000000000000000000000000000000000000000..26dee0590b38ef030fae4251d74932178aa896cd
--- /dev/null
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+/*! \file       nr_rlc_oai_api.h
+ * \brief       Header file for nr_rlc_oai_api
+ * \author      Guido Casati
+ * \date        2020
+ * \email:      guido.casati@iis.fraunhofe.de
+ * \version     1.0
+ * @ingroup     _rlc
+
+ */
+
+#include "NR_RLC-BearerConfig.h"
+#include "NR_RLC-Config.h"
+#include "NR_LogicalChannelIdentity.h"
+#include "NR_RadioBearerConfig.h"
+#include "NR_CellGroupConfig.h"
+#include "openair2/RRC/NR/nr_rrc_proto.h"
+
+/* from OAI */
+#include "pdcp.h"
+
+struct NR_RLC_Config;
+struct NR_LogicalChannelConfig;
+
+void nr_rlc_bearer_init(NR_RLC_BearerConfig_t *RLC_BearerConfig);
+
+void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc_config_pr);
+
+void nr_rlc_bearer_init_ul_spec(struct NR_LogicalChannelConfig *mac_LogicalChannelConfig);
\ No newline at end of file
diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.c b/openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.c
index d4db8d8484283eaeb5189010f74676364f2afa99..8c46628333d45dfec2d64cf6b3010e4a511e623e 100644
--- a/openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.c
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.c
@@ -85,7 +85,7 @@ nr_rlc_ue_t *nr_rlc_manager_get_ue(nr_rlc_ue_manager_t *_m, int rnti)
     if (m->ue_list[i]->rnti == rnti)
       return m->ue_list[i];
 
-  LOG_D(RLC, "%s:%d:%s: new UE %d\n", __FILE__, __LINE__, __FUNCTION__, rnti);
+  LOG_D(RLC, "%s:%d:%s: new UE with RNTI %x\n", __FILE__, __LINE__, __FUNCTION__, rnti);
 
   m->ue_count++;
   m->ue_list = realloc(m->ue_list, sizeof(nr_rlc_ue_t *) * m->ue_count);
diff --git a/openair2/LAYER2/rlc_v2/rlc_oai_api.c b/openair2/LAYER2/rlc_v2/rlc_oai_api.c
index 5fede07c0154aec0e338b96338d3fff38ac0bcbc..b3aaff742f74ae3e0191818d7108edd0e6a7bbfe 100644
--- a/openair2/LAYER2/rlc_v2/rlc_oai_api.c
+++ b/openair2/LAYER2/rlc_v2/rlc_oai_api.c
@@ -642,8 +642,7 @@ static void add_srb(int rnti, int module_id, struct LTE_SRB_ToAddMod *s)
                                poll_pdu, poll_byte, max_retx_threshold);
     rlc_ue_add_srb_rlc_entity(ue, srb_id, rlc_am);
 
-    LOG_D(RLC, "%s:%d:%s: added srb %d to ue %d\n",
-          __FILE__, __LINE__, __FUNCTION__, srb_id, rnti);
+    LOG_D(RLC, "%s:%d:%s: added SRB %d to UE RNTI %x\n", __FILE__, __LINE__, __FUNCTION__, srb_id, rnti);
   }
   rlc_manager_unlock(rlc_ue_manager);
 }
@@ -720,8 +719,7 @@ static void add_drb_am(int rnti, int module_id, struct LTE_DRB_ToAddMod *s)
                                poll_pdu, poll_byte, max_retx_threshold);
     rlc_ue_add_drb_rlc_entity(ue, drb_id, rlc_am);
 
-    LOG_D(RLC, "%s:%d:%s: added drb %d to ue %d\n",
-          __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
+    LOG_D(RLC, "%s:%d:%s: added DRB %d to UE RNTI %x\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   }
   rlc_manager_unlock(rlc_ue_manager);
 }
@@ -791,8 +789,7 @@ static void add_drb_um(int rnti, int module_id, struct LTE_DRB_ToAddMod *s)
                                sn_field_length);
     rlc_ue_add_drb_rlc_entity(ue, drb_id, rlc_um);
 
-    LOG_D(RLC, "%s:%d:%s: added drb %d to ue %d\n",
-          __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
+    LOG_D(RLC, "%s:%d:%s: added DRB %d to UE RNTI %x\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti);
   }
   rlc_manager_unlock(rlc_ue_manager);
 }
@@ -909,8 +906,7 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t   * const ctxt_pP
                                     );
           rlc_ue_add_drb_rlc_entity(ue, drb_id, rlc_um);
 
-          LOG_D(RLC, "%s:%d:%s: added drb %d to ue %d\n",
-                __FILE__, __LINE__, __FUNCTION__, (int)drb_id, mbms_rnti);
+          LOG_D(RLC, "%s:%d:%s: added DRB %d to UE RNTI %x\n", __FILE__, __LINE__, __FUNCTION__, (int)drb_id, mbms_rnti);
         }
         rlc_manager_unlock(rlc_ue_manager);
 
diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
index 38142fb790bf14f7b9d0423543a2ea4b3ea52049..9513869fa5d6a6a17b776b86978edbb5a8e5ea59 100644
--- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
@@ -30,12 +30,9 @@
 * \warning
 */
 
-#include "openair1/PHY/defs_eNB.h"
-#include "openair1/PHY/phy_extern.h"
 #include "openair1/SCHED_NR/fapi_nr_l1.h"
 #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h"
 #include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
-#include "LAYER2/MAC/mac_proto.h"
 #include "LAYER2/NR_MAC_gNB/mac_proto.h"
 #include "common/ran_context.h"
 #include "executables/softmodem-common.h"
@@ -79,35 +76,28 @@ void handle_nr_rach(NR_UL_IND_t *UL_info) {
 }
 
 
-void handle_nr_uci(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats, int target_snrx10) {
-
+void handle_nr_uci(NR_UL_IND_t *UL_info)
+{
+  const module_id_t mod_id = UL_info->module_id;
+  const frame_t frame = UL_info->frame;
+  const sub_frame_t slot = UL_info->slot;
   int num_ucis = UL_info->uci_ind.num_ucis;
   nfapi_nr_uci_t *uci_list = UL_info->uci_ind.uci_list;
 
   for (int i = 0; i < num_ucis; i++) {
     switch (uci_list[i].pdu_type) {
-      case NFAPI_NR_UCI_PUSCH_PDU_TYPE: break;
+      case NFAPI_NR_UCI_PUSCH_PDU_TYPE:
+        LOG_E(MAC, "%s(): unhandled NFAPI_NR_UCI_PUSCH_PDU_TYPE\n", __func__);
+        break;
 
       case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: {
-        nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu = &uci_list[i].pucch_pdu_format_0_1;
-
-        // tpc (power control)
-        sched_ctrl->tpc1 = nr_get_tpc(target_snrx10,uci_pdu->ul_cqi,30);
-
-        if( (uci_pdu->pduBitmap>>1) & 0x01)
-          nr_rx_acknack(NULL,uci_pdu,NULL,UL_info,sched_ctrl,stats);
-
+        const nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu = &uci_list[i].pucch_pdu_format_0_1;
+        handle_nr_uci_pucch_0_1(mod_id, frame, slot, uci_pdu);
         break;
       }
       case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: {
-        nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu = &uci_list[i].pucch_pdu_format_2_3_4;
-
-        // tpc (power control)
-        sched_ctrl->tpc1 = nr_get_tpc(target_snrx10,uci_pdu->ul_cqi,30);
-
-        if( (uci_pdu->pduBitmap>>1) & 0x01)
-          nr_rx_acknack(NULL,NULL,uci_pdu,UL_info,sched_ctrl,stats);
-
+        const nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu = &uci_list[i].pucch_pdu_format_2_3_4;
+        handle_nr_uci_pucch_2_3_4(mod_id, frame, slot, uci_pdu);
         break;
       }
     }
@@ -115,77 +105,76 @@ void handle_nr_uci(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_
 
   UL_info->uci_ind.num_ucis = 0;
 }
-
-
-void handle_nr_ulsch(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl, NR_mac_stats_t *stats) {
-
-  if(nfapi_mode == NFAPI_MODE_PNF) {
-    if (UL_info->crc_ind.number_crcs>0) {
-      //LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.number_of_crcs:%d CRC_IND:SFN/SF:%d\n", UL_info->crc_ind.crc_indication_body.number_of_crcs, NFAPI_SFNSF2DEC(UL_info->crc_ind.sfn_sf));
-      //      oai_nfapi_crc_indication(&UL_info->crc_ind);
-
-      UL_info->crc_ind.number_crcs = 0;
-    }
-
-    if (UL_info->rx_ind.number_of_pdus>0) {
-      //LOG_D(PHY,"UL_info->rx_ind.number_of_pdus:%d RX_IND:SFN/SF:%d\n", UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf));
-      //      oai_nfapi_rx_ind(&UL_info->rx_ind);
-      UL_info->rx_ind.number_of_pdus = 0;
-    }
-  } else {
-
-    if (UL_info->rx_ind.number_of_pdus>0 && UL_info->crc_ind.number_crcs>0) {
-      for (int i=0; i<UL_info->rx_ind.number_of_pdus; i++) {
-        for (int j=0; j<UL_info->crc_ind.number_crcs; j++) {
-          // find crc_indication j corresponding rx_indication i
-          LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.crc_pdu_list[%d].rx_ue_information.rnti:%04x UL_info->rx_ind.rx_indication_body.rx_pdu_list[%d].rx_ue_information.rnti:%04x\n", j,
-                UL_info->crc_ind.crc_list[j].rnti, i, UL_info->rx_ind.pdu_list[i].rnti);
-
-          if (UL_info->crc_ind.crc_list[j].rnti ==
-              UL_info->rx_ind.pdu_list[i].rnti) {
-            LOG_D(PHY, "UL_info->crc_ind.crc_indication_body.crc_pdu_list[%d].crc_indication_rel8.crc_flag:%d\n", j, UL_info->crc_ind.crc_list[j].tb_crc_status);
-
-            handle_nr_ul_harq(UL_info->slot, sched_ctrl, stats, UL_info->crc_ind.crc_list[j]);
-
-            if (UL_info->crc_ind.crc_list[j].tb_crc_status == 1) { // CRC error indication
-              LOG_D(MAC,"Frame %d, Slot %d Calling rx_sdu (CRC error) \n",UL_info->frame,UL_info->slot);
-
-              nr_rx_sdu(UL_info->module_id,
-                        UL_info->CC_id,
-                        UL_info->rx_ind.sfn, //UL_info->frame,
-                        UL_info->rx_ind.slot, //UL_info->slot,
-                        UL_info->rx_ind.pdu_list[i].rnti,
-                        (uint8_t *)NULL,
-                        UL_info->rx_ind.pdu_list[i].pdu_length,
-                        UL_info->rx_ind.pdu_list[i].timing_advance,
-                        UL_info->rx_ind.pdu_list[i].ul_cqi,
-                        UL_info->rx_ind.pdu_list[i].rssi);
-            } else {
-              LOG_D(MAC,"Frame %d, Slot %d Calling rx_sdu (CRC ok) \n",UL_info->frame,UL_info->slot);
-              nr_rx_sdu(UL_info->module_id,
-                        UL_info->CC_id,
-                        UL_info->rx_ind.sfn, //UL_info->frame,
-                        UL_info->rx_ind.slot, //UL_info->slot,
-                        UL_info->rx_ind.pdu_list[i].rnti,
-                        UL_info->rx_ind.pdu_list[i].pdu,
-                        UL_info->rx_ind.pdu_list[i].pdu_length,
-                        UL_info->rx_ind.pdu_list[i].timing_advance,
-                        UL_info->rx_ind.pdu_list[i].ul_cqi,
-                        UL_info->rx_ind.pdu_list[i].rssi);
-            }
-            break;
-          }
-        } //    for (j=0;j<UL_info->crc_ind.number_crcs;j++)
-      } //   for (i=0;i<UL_info->rx_ind.number_of_pdus;i++)
-
-      UL_info->crc_ind.number_crcs=0;
-      UL_info->rx_ind.number_of_pdus = 0;
-    }
-    else if (UL_info->rx_ind.number_of_pdus!=0 || UL_info->crc_ind.number_crcs!=0) {
-      LOG_E(PHY,"hoping not to have mis-match between CRC ind and RX ind - hopefully the missing message is coming shortly rx_ind:%d(SFN/SL:%d/%d) crc_ind:%d(SFN/SL:%d/%d) \n",
-            UL_info->rx_ind.number_of_pdus, UL_info->rx_ind.sfn, UL_info->rx_ind.slot,
-            UL_info->crc_ind.number_crcs, UL_info->rx_ind.sfn, UL_info->rx_ind.slot);
-    }
+  // if(nfapi_mode == NFAPI_MODE_PNF) {
+  //   if (UL_info->crc_ind.number_crcs>0) {
+  //     //LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.number_of_crcs:%d CRC_IND:SFN/SF:%d\n", UL_info->crc_ind.crc_indication_body.number_of_crcs, NFAPI_SFNSF2DEC(UL_info->crc_ind.sfn_sf));
+  //     //      oai_nfapi_crc_indication(&UL_info->crc_ind);
+
+  //     UL_info->crc_ind.number_crcs = 0;
+  //   }
+
+  //   if (UL_info->rx_ind.number_of_pdus>0) {
+  //     //LOG_D(PHY,"UL_info->rx_ind.number_of_pdus:%d RX_IND:SFN/SF:%d\n", UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf));
+  //     //      oai_nfapi_rx_ind(&UL_info->rx_ind);
+  //     UL_info->rx_ind.number_of_pdus = 0;
+  //   }
+
+void handle_nr_ulsch(NR_UL_IND_t *UL_info)
+{
+  if (UL_info->rx_ind.number_of_pdus > 0 && UL_info->crc_ind.number_crcs > 0) {
+    for (int i = 0; i < UL_info->rx_ind.number_of_pdus; i++) {
+      for (int j = 0; j < UL_info->crc_ind.number_crcs; j++) {
+        // find crc_indication j corresponding rx_indication i
+        const nfapi_nr_rx_data_pdu_t *rx = &UL_info->rx_ind.pdu_list[i];
+        const nfapi_nr_crc_t *crc = &UL_info->crc_ind.crc_list[j];
+        LOG_D(PHY,
+              "UL_info->crc_ind.pdu_list[%d].rnti:%04x "
+              "UL_info->rx_ind.pdu_list[%d].rnti:%04x\n",
+              j,
+              crc->rnti,
+              i,
+              rx->rnti);
+
+        if (crc->rnti != rx->rnti)
+          continue;
+
+        LOG_D(MAC,
+              "%4d.%2d Calling rx_sdu (CRC %s/tb_crc_status %d)\n",
+              UL_info->frame,
+              UL_info->slot,
+              crc->tb_crc_status ? "error" : "ok",
+              crc->tb_crc_status);
+
+        /* if CRC passes, pass PDU, otherwise pass NULL as error indication */
+        nr_rx_sdu(UL_info->module_id,
+                  UL_info->CC_id,
+                  UL_info->rx_ind.sfn,
+                  UL_info->rx_ind.slot,
+                  rx->rnti,
+                  crc->tb_crc_status ? NULL : rx->pdu,
+                  rx->pdu_length,
+                  rx->timing_advance,
+                  rx->ul_cqi,
+                  rx->rssi);
+        handle_nr_ul_harq(UL_info->module_id, UL_info->frame, UL_info->slot, crc);
+        break;
+      } //    for (j=0;j<UL_info->crc_ind.number_crcs;j++)
+    } //   for (i=0;i<UL_info->rx_ind.number_of_pdus;i++)
+
+    UL_info->crc_ind.number_crcs = 0;
+    UL_info->rx_ind.number_of_pdus = 0;
+  } else if (UL_info->rx_ind.number_of_pdus != 0
+             || UL_info->crc_ind.number_crcs != 0) {
+    LOG_E(PHY,
+          "hoping not to have mis-match between CRC ind and RX ind - "
+          "hopefully the missing message is coming shortly "
+          "rx_ind:%d(SFN/SL:%d/%d) crc_ind:%d(SFN/SL:%d/%d) \n",
+          UL_info->rx_ind.number_of_pdus,
+          UL_info->rx_ind.sfn,
+          UL_info->rx_ind.slot,
+          UL_info->crc_ind.number_crcs,
+          UL_info->rx_ind.sfn,
+          UL_info->rx_ind.slot);
   }
 }
 
@@ -216,14 +205,12 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
     ifi->CC_mask |= (1<<CC_id);
   }
 
-  // clear DL/UL info for new scheduling round
-  clear_nr_nfapi_information(mac,CC_id,UL_info->frame,UL_info->slot);
   handle_nr_rach(UL_info);
   
-  handle_nr_uci(UL_info,&mac->UE_info.UE_sched_ctrl[0],&mac->UE_info.mac_stats[0],mac->pucch_target_snrx10);
+  handle_nr_uci(UL_info);
   // clear HI prior to handling ULSCH
   mac->UL_dci_req[CC_id].numPdus = 0;
-  handle_nr_ulsch(UL_info, &mac->UE_info.UE_sched_ctrl[0],&mac->UE_info.mac_stats[0]);
+  handle_nr_ulsch(UL_info);
 
   if (nfapi_mode != NFAPI_MODE_PNF) {
     if (ifi->CC_mask == ((1<<MAX_NUM_CCs)-1)) {
@@ -246,7 +233,7 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
       sched_info->DL_req      = &mac->DL_req[CC_id];
       sched_info->UL_dci_req  = &mac->UL_dci_req[CC_id];
 
-      sched_info->UL_tti_req  = &mac->UL_tti_req[CC_id];
+      sched_info->UL_tti_req  = mac->UL_tti_req[CC_id];
 
       sched_info->TX_req      = &mac->TX_req[CC_id];
 #ifdef DUMP_FAPI
diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c
index 71e0bd13ad41ff9d9afa3d5c018236b0f16b049e..9bc95b216b0348d3b2aea726d96c7af8d3096d47 100644
--- a/openair2/RRC/NR/rrc_gNB.c
+++ b/openair2/RRC/NR/rrc_gNB.c
@@ -75,7 +75,7 @@
 
 #include "rrc_eNB_GTPV1U.h"
 
-
+#include "nr_pdcp/nr_pdcp_entity.h"
 #include "pdcp.h"
 #include "gtpv1u_eNB_task.h"
 
diff --git a/openair2/RRC/NR/rrc_gNB_internode.c b/openair2/RRC/NR/rrc_gNB_internode.c
index 3c8d75edfac1913115fca20601af340fde926ab4..346b0ec800285d17ab83a8176cd5ebde99ccc48c 100644
--- a/openair2/RRC/NR/rrc_gNB_internode.c
+++ b/openair2/RRC/NR/rrc_gNB_internode.c
@@ -108,8 +108,8 @@ int generate_CG_Config(gNB_RRC_INST *rrc,
     fd = fopen("reconfig.raw","w");
     if (fd != NULL) {
       fwrite((void *)buffer,1,(size_t)((enc_rval.encoded+7)>>3),fd);
+      fclose(fd);
     }
-    fclose(fd);
   }
   
   enc_rval = uper_encode_to_buffer(&asn_DEF_NR_RadioBearerConfig, NULL, (void *)rbconfig, buffer, 1024);
@@ -134,8 +134,8 @@ int generate_CG_Config(gNB_RRC_INST *rrc,
     fd = fopen("rbconfig.raw","w");
     if (fd != NULL) {
       fwrite((void *)buffer,1,(size_t)((enc_rval.encoded+7)>>3),fd);
+      fclose(fd);
     }
-    fclose(fd);
   }
   
   total_size = total_size + ((enc_rval.encoded+7)>>3);
diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c
index 7b7647a7465ab75eeb4877474af42d28d3a2ce20..a0d32c1339d49898b2bd349b4a9360de9218621f 100644
--- a/openair2/RRC/NR/rrc_gNB_nsa.c
+++ b/openair2/RRC/NR/rrc_gNB_nsa.c
@@ -243,12 +243,9 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
       }
     } else
       LOG_W(RRC, "No E-RAB to be added received from SgNB Addition Request message \n");
-  }
 
-  if (m != NULL) {
     X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).MeNB_ue_x2_id = m->ue_x2_id;
     X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).SgNB_ue_x2_id = ue_context_p->ue_context.secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity;
-
     //X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = CG_Config_size; //Need to verify correct value for the buffer_size
     // Send to X2 entity to transport to MeNB
     asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CG_Config,
@@ -258,6 +255,8 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
                               1024);
     X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = (enc_rval.encoded+7)>>3;
     itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(0), msg); //Check right id instead of hardcoding
+  } else if (get_softmodem_params()->do_ra) {
+    PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, ue_context_p->ue_id_rnti, 0, 0,rrc->module_id);
   }
 
   rrc->Nb_ue++;
@@ -272,6 +271,15 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
                          ue_context_p->ue_id_rnti,
                          ue_context_p->ue_context.secondaryCellGroup);
 
+  if(m == NULL){
+    LOG_W(RRC, "Calling RRC PDCP/RLC ASN1 request functions for protocol context %p with module_id %d, rnti %x, frame %d, subframe %d eNB_index %d \n", &ctxt,
+                                                                                                                                                        ctxt.module_id,
+                                                                                                                                                        ctxt.rnti,
+                                                                                                                                                        ctxt.frame,
+                                                                                                                                                        ctxt.subframe,
+                                                                                                                                                        ctxt.eNB_index);
+  }
+
   nr_rrc_pdcp_config_asn1_req(
     &ctxt,
     (NR_SRB_ToAddModList_t *) NULL,
@@ -292,6 +300,8 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
       (LTE_PMCH_InfoList_r9_t *) NULL,
       ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList);
 
+  LOG_D(RRC, "%s:%d: done RRC PDCP/RLC ASN1 request for UE rnti %x\n", __FUNCTION__, __LINE__, ctxt.rnti);
+
 }
 
 void rrc_remove_nsa_user(gNB_RRC_INST *rrc, int rnti) {
diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c
index ca6e3e55bf378b3dbea8a9f329a83431fbb393be..7aa224c61401d15184c2a1ab28a90a8e46465edf 100644
--- a/openair2/RRC/NR/rrc_gNB_reconfig.c
+++ b/openair2/RRC/NR/rrc_gNB_reconfig.c
@@ -43,6 +43,7 @@
 #include "common/utils/nr/nr_common.h"
 #include "SIMULATION/TOOLS/sim.h"
 #include "executables/softmodem-common.h"
+#include "LAYER2/nr_rlc/nr_rlc_oai_api.h"
 
 #define false 0
 #define true 1
@@ -57,66 +58,33 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
   AssertFatal(servingcellconfigcommon!=NULL,"servingcellconfigcommon is null\n");
   AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n");
 
-  if(servingcellconfigcommon->ssb_PositionsInBurst->present !=2)
-    AssertFatal(1==0,"Currenrly implemented only for medium size SSB bitmap\n");
-  uint8_t bitmap = servingcellconfigcommon->ssb_PositionsInBurst->choice.mediumBitmap.buf[0];
+  uint64_t bitmap=0;
+  switch (servingcellconfigcommon->ssb_PositionsInBurst->present) {
+    case 1 :
+      bitmap = ((uint64_t) servingcellconfigcommon->ssb_PositionsInBurst->choice.shortBitmap.buf[0])<<56;
+      break;
+    case 2 :
+      bitmap = ((uint64_t) servingcellconfigcommon->ssb_PositionsInBurst->choice.mediumBitmap.buf[0])<<56;
+      break;
+    case 3 :
+      for (int i=0; i<8; i++) {
+        bitmap |= (((uint64_t) servingcellconfigcommon->ssb_PositionsInBurst->choice.longBitmap.buf[i])<<((7-i)*8));
+      }
+      break;
+    default:
+      AssertFatal(1==0,"SSB bitmap size value %d undefined (allowed values 1,2,3) \n", servingcellconfigcommon->ssb_PositionsInBurst->present);
+  }
 
   memset(secondaryCellGroup,0,sizeof(NR_CellGroupConfig_t));
   secondaryCellGroup->cellGroupId = scg_id;
   NR_RLC_BearerConfig_t *RLC_BearerConfig = calloc(1,sizeof(*RLC_BearerConfig));
-  RLC_BearerConfig->logicalChannelIdentity = 4;
-  RLC_BearerConfig->servedRadioBearer = calloc(1,sizeof(*RLC_BearerConfig->servedRadioBearer));
-  RLC_BearerConfig->servedRadioBearer->present =  NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity;
-  RLC_BearerConfig->servedRadioBearer->choice.drb_Identity=1;
-  RLC_BearerConfig->reestablishRLC=calloc(1,sizeof(*RLC_BearerConfig->reestablishRLC));
-  *RLC_BearerConfig->reestablishRLC=NR_RLC_BearerConfig__reestablishRLC_true;
-  RLC_BearerConfig->rlc_Config=calloc(1,sizeof(*RLC_BearerConfig->rlc_Config));
-
-#if 0
-
-  // RLC UM Bi-directional Bearer configuration 
-  RLC_BearerConfig->rlc_Config->present = NR_RLC_Config_PR_um_Bi_Directional;
-  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional));
-  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength));
-  *RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength   =    NR_SN_FieldLengthUM_size12;
-
-  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength));
-  *RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength   =    NR_SN_FieldLengthUM_size12;
-  RLC_BearerConfig->rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = NR_T_Reassembly_ms15;
-
-#else
-
-  // RLC AM Bearer configuration
-  RLC_BearerConfig->rlc_Config->present = NR_RLC_Config_PR_am;
-  RLC_BearerConfig->rlc_Config->choice.am = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am));
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength));
-  *RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength   =  NR_SN_FieldLengthAM_size18;
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45;
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.pollPDU          = NR_PollPDU_p64;
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.pollByte         = NR_PollByte_kB500;
-  RLC_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t32;
-  RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1,sizeof(*RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength));
-  *RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18;
-  RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.t_Reassembly   = NR_T_Reassembly_ms15;
-  RLC_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15;
-
-#endif
+  nr_rlc_bearer_init(RLC_BearerConfig);
+  if (get_softmodem_params()->do_ra)
+    nr_drb_config(RLC_BearerConfig->rlc_Config, NR_RLC_Config_PR_um_Bi_Directional);
+  else
+    nr_drb_config(RLC_BearerConfig->rlc_Config, NR_RLC_Config_PR_am);
+  nr_rlc_bearer_init_ul_spec(RLC_BearerConfig->mac_LogicalChannelConfig);
 
-  RLC_BearerConfig->mac_LogicalChannelConfig = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig));
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters));
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->priority            = 1;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->prioritisedBitRate  = NR_LogicalChannelConfig__ul_SpecificParameters__prioritisedBitRate_infinity;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->bucketSizeDuration  = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->allowedServingCells = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->allowedSCS_List     = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->maxPUSCH_Duration   = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->configuredGrantType1Allowed = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup   = calloc(1,sizeof(*RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup));
-  *RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelGroup  = 1;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID   = NULL;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask = false;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = false;
-  RLC_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->bitRateQueryProhibitTimer   = NULL;
   secondaryCellGroup->rlc_BearerToAddModList = calloc(1,sizeof(*secondaryCellGroup->rlc_BearerToAddModList));
   ASN_SEQUENCE_ADD(&secondaryCellGroup->rlc_BearerToAddModList->list, RLC_BearerConfig);
   secondaryCellGroup->mac_CellGroupConfig=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig));
@@ -250,9 +218,9 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList=calloc(1,sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->tci_StatesToAddModList));
 
  int n_ssb = 0;
- NR_TCI_State_t *tcic[8];
- for (int i=0;i<8;i++) {
-   if ((bitmap>>(7-i))&0x01){
+ NR_TCI_State_t *tcic[64];
+ for (int i=0;i<64;i++) {
+   if ((bitmap>>(63-i))&0x01){
      tcic[i]=calloc(1,sizeof(*tcic[i]));
      tcic[i]->tci_StateId=n_ssb;
      tcic[i]->qcl_Type1.cell=NULL;
@@ -361,7 +329,12 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->rateMatchPatternGroup1=NULL;
  secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->rateMatchPatternGroup2=NULL;
  secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->rbg_Size=NR_PDSCH_Config__rbg_Size_config1;
- secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->mcs_Table=NULL;
+ if (!get_softmodem_params()->use_256qam_table) {
+   secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->mcs_Table=NULL;
+ } else {
+   secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->mcs_Table = calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->mcs_Table));
+   *secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->mcs_Table = NR_PDSCH_Config__mcs_Table_qam256;
+ }
  secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI));
  *secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI = NR_PDSCH_Config__maxNrofCodeWordsScheduledByDCI_n1;
  secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling;
@@ -411,12 +384,21 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->controlResourceSetZero=NULL;
  bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet=calloc(1,sizeof(*bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet));
 
+ int curr_bwp = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,275);
+
  NR_ControlResourceSet_t *coreset = calloc(1,sizeof(*coreset));
  coreset->controlResourceSetId=1;
- // frequencyDomainResources '11111111 11111111 00000000 00000000 00000000 00000'B,
+ // frequency domain resources depends on BWP size
+ // options are 24, 48 or 96
  coreset->frequencyDomainResources.buf = calloc(1,6);
- coreset->frequencyDomainResources.buf[0] = 0xff;
- coreset->frequencyDomainResources.buf[1] = 0xff;
+ if (curr_bwp < 48)
+   coreset->frequencyDomainResources.buf[0] = 0xf0;
+ else
+   coreset->frequencyDomainResources.buf[0] = 0xff;
+ if (curr_bwp < 96)
+   coreset->frequencyDomainResources.buf[1] = 0;
+ else
+   coreset->frequencyDomainResources.buf[1] = 0xff;
  coreset->frequencyDomainResources.buf[2] = 0;
  coreset->frequencyDomainResources.buf[3] = 0;
  coreset->frequencyDomainResources.buf[4] = 0;
@@ -428,9 +410,9 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  coreset->precoderGranularity = NR_ControlResourceSet__precoderGranularity_sameAsREG_bundle;
 
  coreset->tci_StatesPDCCH_ToAddList=calloc(1,sizeof(*coreset->tci_StatesPDCCH_ToAddList));
- NR_TCI_StateId_t *tci[8];
- for (int i=0;i<8;i++) {
-   if ((bitmap>>(7-i))&0x01){
+ NR_TCI_StateId_t *tci[64];
+ for (int i=0;i<64;i++) {
+   if ((bitmap>>(63-i))&0x01){
      tci[i]=calloc(1,sizeof(*tci[i]));
      *tci[i] = i;
      ASN_SEQUENCE_ADD(&coreset->tci_StatesPDCCH_ToAddList->list,tci[i]);
@@ -530,7 +512,12 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  ss2->nrofCandidates=calloc(1,sizeof(*ss2->nrofCandidates));
  ss2->nrofCandidates->aggregationLevel1 = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0;
  ss2->nrofCandidates->aggregationLevel2 = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0;
- ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n4;
+ if (curr_bwp < 48)
+   ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1;
+ else if (curr_bwp < 96)
+   ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n2;
+ else
+   ss2->nrofCandidates->aggregationLevel4 = NR_SearchSpace__nrofCandidates__aggregationLevel4_n4;
  ss2->nrofCandidates->aggregationLevel8 = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0;
  ss2->nrofCandidates->aggregationLevel16 = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0;
  ss2->searchSpaceType=calloc(1,sizeof(*ss2->searchSpaceType));
@@ -652,9 +639,9 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
 
 
  n_ssb = 0;
- NR_TCI_State_t *tcid[8];
- for (int i=0;i<8;i++) {
-   if ((bitmap>>(7-i))&0x01){
+ NR_TCI_State_t *tcid[64];
+ for (int i=0;i<64;i++) {
+   if ((bitmap>>(63-i))&0x01){
      tcid[i]=calloc(1,sizeof(*tcid[i]));
      tcid[i]->tci_StateId=n_ssb;
      tcid[i]->qcl_Type1.cell=NULL;
@@ -679,7 +666,12 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->rateMatchPatternGroup1=NULL;
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->rateMatchPatternGroup2=NULL;
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->rbg_Size=NR_PDSCH_Config__rbg_Size_config1;
- bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table=NULL;
+ if (!get_softmodem_params()->use_256qam_table) {
+   bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table=NULL;
+ } else {
+   bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table));
+   *bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table = NR_PDSCH_Config__mcs_Table_qam256;
+ }
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI));
  *bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI = NR_PDSCH_Config__maxNrofCodeWordsScheduledByDCI_n1;
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling;
@@ -705,7 +697,12 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->rateMatchPatternGroup1=NULL;
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->rateMatchPatternGroup2=NULL;
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->rbg_Size=NR_PDSCH_Config__rbg_Size_config1;
- bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table=NULL;
+ if (!get_softmodem_params()->use_256qam_table) {
+   bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table=NULL;
+ } else {
+   bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table = calloc(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table));
+   *bwp->bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table = NR_PDSCH_Config__mcs_Table_qam256;
+ }
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI = calloc(1,sizeof(*bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI));
  *bwp->bwp_Dedicated->pdsch_Config->choice.setup->maxNrofCodeWordsScheduledByDCI = NR_PDSCH_Config__maxNrofCodeWordsScheduledByDCI_n1;
  bwp->bwp_Dedicated->pdsch_Config->choice.setup->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling;
@@ -914,7 +911,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  NR_PUCCH_Resource_t *pucchres2=calloc(1,sizeof(*pucchres2));
  NR_PUCCH_Resource_t *pucchres3=calloc(1,sizeof(*pucchres3));
  pucchres0->pucch_ResourceId=1;
- pucchres0->startingPRB=48;
+ pucchres0->startingPRB=8;
  pucchres0->intraSlotFrequencyHopping=NULL;
  pucchres0->secondHopPRB=NULL;
  pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0;
@@ -925,7 +922,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0);
 
  pucchres1->pucch_ResourceId=2;
- pucchres1->startingPRB=48;
+ pucchres1->startingPRB=8;
  pucchres1->intraSlotFrequencyHopping=NULL;
  pucchres1->secondHopPRB=NULL;
  pucchres1->format.present= NR_PUCCH_Resource__format_PR_format0;
@@ -936,23 +933,23 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres1);
 
  pucchres2->pucch_ResourceId=3;
- pucchres2->startingPRB=40;
+ pucchres2->startingPRB=0;
  pucchres2->intraSlotFrequencyHopping=NULL;
  pucchres2->secondHopPRB=NULL;
  pucchres2->format.present= NR_PUCCH_Resource__format_PR_format2;
  pucchres2->format.choice.format2=calloc(1,sizeof(*pucchres2->format.choice.format2));
- pucchres2->format.choice.format2->nrofPRBs=4;
+ pucchres2->format.choice.format2->nrofPRBs=8;
  pucchres2->format.choice.format2->nrofSymbols=1;
  pucchres2->format.choice.format2->startingSymbolIndex=13;
  ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres2);
 
  pucchres3->pucch_ResourceId=4;
- pucchres3->startingPRB=40;
+ pucchres3->startingPRB=0;
  pucchres3->intraSlotFrequencyHopping=NULL;
  pucchres3->secondHopPRB=NULL;
  pucchres3->format.present= NR_PUCCH_Resource__format_PR_format2;
  pucchres3->format.choice.format2=calloc(1,sizeof(*pucchres3->format.choice.format2));
- pucchres3->format.choice.format2->nrofPRBs=4;
+ pucchres3->format.choice.format2->nrofPRBs=8;
  pucchres3->format.choice.format2->nrofSymbols=1;
  pucchres3->format.choice.format2->startingSymbolIndex=12;
  ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres3);
@@ -1075,45 +1072,14 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
 
  NR_CSI_SSB_ResourceSet_t *ssbresset0 = calloc(1,sizeof(*ssbresset0));
  ssbresset0->csi_SSB_ResourceSetId=0;
- if ((bitmap>>7)&0x01){
-   NR_SSB_Index_t *ssbresset00=calloc(1,sizeof(*ssbresset00));
-   *ssbresset00=0;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset00);
- }
- if ((bitmap>>6)&0x01) {
-   NR_SSB_Index_t *ssbresset01=calloc(1,sizeof(*ssbresset01));
-   *ssbresset01=1;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset01);
- }
- if ((bitmap>>5)&0x01) {
-   NR_SSB_Index_t *ssbresset02=calloc(1,sizeof(*ssbresset02));
-   *ssbresset02=2;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset02);
- }
- if ((bitmap>>4)&0x01) {
-   NR_SSB_Index_t *ssbresset03=calloc(1,sizeof(*ssbresset03));
-   *ssbresset03=3;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset03);
- }
- if ((bitmap>>3)&0x01) {
-   NR_SSB_Index_t *ssbresset04=calloc(1,sizeof(*ssbresset04));
-   *ssbresset04=4;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset04);
- }
- if ((bitmap>>2)&0x01) {
-   NR_SSB_Index_t *ssbresset05=calloc(1,sizeof(*ssbresset05));
-   *ssbresset05=5;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset05);
- }
- if ((bitmap>>1)&0x01) {
-   NR_SSB_Index_t *ssbresset06=calloc(1,sizeof(*ssbresset06));
-   *ssbresset06=6;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset06);
- }
- if ((bitmap)&0x01) {
-   NR_SSB_Index_t *ssbresset07=calloc(1,sizeof(*ssbresset07));
-   *ssbresset07=7;
-   ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset07);
+
+ NR_SSB_Index_t *ssbresset[64];
+ for (int i=0;i<64;i++) {
+   if ((bitmap>>(63-i))&0x01){
+     ssbresset[i]=calloc(1,sizeof(*ssbresset[i]));
+     *ssbresset[i] = i;
+     ASN_SEQUENCE_ADD(&ssbresset0->csi_SSB_ResourceList.list,ssbresset[i]);
+   }
  }
  ASN_SEQUENCE_ADD(&csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list,ssbresset0);
 
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.c b/openair2/X2AP/x2ap_eNB_generate_messages.c
index e066535df931cb6b77b1df610d1b3ba46b7433fd..23973328f28d69f98cc5338ed0ebb62bd4664425 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.c
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.c
@@ -1439,7 +1439,7 @@ int x2ap_eNB_generate_ENDC_x2_setup_response(
           }
 
           if (instance_p->frame_type[i] == FDD) {
-                  servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_fDD;
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_fDD;
             servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i];
             servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i];
         	  switch (instance_p->N_RB_DL[i]) {
@@ -1473,12 +1473,98 @@ int x2ap_eNB_generate_ENDC_x2_setup_response(
             }
           }
           else {
-        	  AssertFatal(0,"X2Setupresponse not supported for TDD!");
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_tDD;
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.eARFCN = instance_p->fdd_earfcn_DL[i];
+
+            switch (instance_p->subframeAssignment[i]) {
+            case 0:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa0;
+              break;
+            case 1:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa1;
+              break;
+            case 2:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa2;
+              break;
+            case 3:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa3;
+              break;
+            case 4:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa4;
+              break;
+            case 5:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa5;
+              break;
+            case 6:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa6;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for subframeAssignment");
+              break;
+            }
+            switch (instance_p->specialSubframe[i]) {
+            case 0:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp0;
+              break;
+            case 1:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp1;
+              break;
+            case 2:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp2;
+              break;
+            case 3:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp3;
+              break;
+            case 4:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp4;
+              break;
+            case 5:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp5;
+              break;
+            case 6:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp6;
+              break;
+            case 7:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp7;
+              break;
+            case 8:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp8;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for subframeAssignment");
+              break;
+            }
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixDL=X2AP_CyclicPrefixDL_normal;
+            servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixUL=X2AP_CyclicPrefixUL_normal;
+
+            switch (instance_p->N_RB_DL[i]) {
+            case 6:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
+              break;
+            case 15:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
+              break;
+            case 25:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
+              break;
+            case 50:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
+              break;
+            case 75:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
+              break;
+            case 100:
+              servedCellMember->servedEUTRACellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL");
+              break;
+            }
           }
         }
-        ASN_SEQUENCE_ADD(&ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list, servedCellMember);
+      ASN_SEQUENCE_ADD(&ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list, servedCellMember);
       }
-    }
+  }
   ASN_SEQUENCE_ADD(&ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list, ie_ENB_ENDC);
 
 
diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c
index 972bef0a0745c9593b0a038a06d21cbeb8192659..ee006338c5a0e64532dd024b0f0b6488fc542412 100644
--- a/openair3/SCTP/sctp_eNB_task.c
+++ b/openair3/SCTP/sctp_eNB_task.c
@@ -413,10 +413,16 @@ sctp_handle_new_association_req(
     }
 
     /* Subscribe to all events */
-    memset((void *)&events, 1, sizeof(struct sctp_event_subscribe));
+    events.sctp_data_io_event = 1;
+    events.sctp_association_event = 1;
+    events.sctp_address_event = 1;
+    events.sctp_send_failure_event = 1;
+    events.sctp_peer_error_event = 1;
+    events.sctp_shutdown_event = 1;
+    events.sctp_partial_delivery_event = 1;
 
     if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &events,
-                   sizeof(struct sctp_event_subscribe)) < 0) {
+                   8) < 0) {
         SCTP_ERROR("Setsockopt IPPROTO_SCTP_EVENTS failed: %s\n",
                    strerror(errno));
         close(sd);
@@ -759,10 +765,16 @@ static int sctp_create_new_listener(
         }
     }
 
-    memset((void *)&event, 1, sizeof(struct sctp_event_subscribe));
+    event.sctp_data_io_event = 1;
+    event.sctp_association_event = 1;
+    event.sctp_address_event = 1;
+    event.sctp_send_failure_event = 1;
+    event.sctp_peer_error_event = 1;
+    event.sctp_shutdown_event = 1;
+    event.sctp_partial_delivery_event = 1;
 
     if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &event,
-                   sizeof(struct sctp_event_subscribe)) < 0) {
+                   8) < 0) {
         SCTP_ERROR("setsockopt: %s:%d\n", strerror(errno), errno);
         if (sd != -1) {
             close(sd);
diff --git a/openair3/SCTP/sctp_primitives_client.c b/openair3/SCTP/sctp_primitives_client.c
index bb71a854e168d6782935bde1f92df2bd84c58076..e19f20c957b55e0adbcf667720ed9ee210b104ee 100644
--- a/openair3/SCTP/sctp_primitives_client.c
+++ b/openair3/SCTP/sctp_primitives_client.c
@@ -241,10 +241,16 @@ int sctp_connect_to_remote_host(char *local_ip_addr[],
   }
 
   /* Subscribe to all events */
-  memset((void *)&events, 1, sizeof(struct sctp_event_subscribe));
+  events.sctp_data_io_event = 1;
+  events.sctp_association_event = 1;
+  events.sctp_address_event = 1;
+  events.sctp_send_failure_event = 1;
+  events.sctp_peer_error_event = 1;
+  events.sctp_shutdown_event = 1;
+  events.sctp_partial_delivery_event = 1;
 
   if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &events,
-                 sizeof(struct sctp_event_subscribe)) < 0) {
+                 8) < 0) {
     SCTP_ERROR("Setsockopt IPPROTO_SCTP_EVENTS failed: %s\n",
                strerror(errno));
     return -1;
diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c
index 3066f0906fd8a193dffc12e257a4a40424124ae9..3a69d4c991f1de68e057875691d718f1433e5d9f 100644
--- a/targets/ARCH/COMMON/common_lib.c
+++ b/targets/ARCH/COMMON/common_lib.c
@@ -112,6 +112,9 @@ int load_lib(openair0_device *device,
 	  else
           deflibname=OAI_RF_LIBNAME;
       shlib_fdesc[0].fname="device_init";
+  } else if (flag == RAU_REMOTE_THIRDPARTY_RADIO_HEAD) {
+    deflibname=OAI_THIRDPARTY_TP_LIBNAME;
+    shlib_fdesc[0].fname="transport_init";
   } else {
 	  deflibname=OAI_TP_LIBNAME;
 	  shlib_fdesc[0].fname="transport_init";
diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h
index 778c8165eb8b5b9198745834231c29fecc7c77af..85ee80ea7cdf443a01559cb27cdc265f09ababa2 100644
--- a/targets/ARCH/COMMON/common_lib.h
+++ b/targets/ARCH/COMMON/common_lib.h
@@ -41,6 +41,8 @@
 #define OAI_RF_LIBNAME        "oai_device"
 /* name of shared library implementing the transport */
 #define OAI_TP_LIBNAME        "oai_transpro"
+/* name of shared library implementing a third-party transport */
+#define OAI_THIRDPARTY_TP_LIBNAME        "thirdparty_transpro"
 /* name of shared library implementing the rf simulator */
 #define OAI_RFSIM_LIBNAME     "rfsimulator"
 /* name of shared library implementing the basic simulator */
@@ -51,10 +53,9 @@
 /* flags for BBU to determine whether the attached radio head is local or remote */
 #define RAU_LOCAL_RADIO_HEAD  0
 #define RAU_REMOTE_RADIO_HEAD 1
-
+#define RAU_REMOTE_THIRDPARTY_RADIO_HEAD 2
 #define MAX_WRITE_THREAD_PACKAGE     10
 #define MAX_WRITE_THREAD_BUFFER_SIZE 8
-
 #ifndef MAX_CARDS
   #define MAX_CARDS 8
 #endif
@@ -367,13 +368,23 @@ struct openair0_device_t {
   /*! \brief Called to send samples to the RF target
       @param device pointer to the device structure specific to the RF hardware target
       @param timestamp The timestamp at whicch the first sample MUST be sent
-      @param buff Buffer which holds the samples
+      @param buff Buffer which holds the samples (2 dimensional)
       @param nsamps number of samples to be sent
-      @param antenna_id index of the antenna if the device has multiple anteannas
+      @param number of antennas 
       @param flags flags must be set to TRUE if timestamp parameter needs to be applied
   */
   int (*trx_write_func)(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id, int flags);
 
+  /*! \brief Called to send samples to the RF target
+      @param device pointer to the device structure specific to the RF hardware target
+      @param timestamp The timestamp at whicch the first sample MUST be sent
+      @param buff Buffer which holds the samples (1 dimensional)
+      @param nsamps number of samples to be sent
+      @param antenna_id index of the antenna if the device has multiple anteannas
+      @param flags flags must be set to TRUE if timestamp parameter needs to be applied
+  */
+  int (*trx_write_func2)(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int antenna_id, int flags);
+
   /*! \brief Receive samples from hardware.
    * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
    * the first channel. *ptimestamp is the time at which the first sample
@@ -382,10 +393,24 @@ struct openair0_device_t {
    * \param[out] ptimestamp the time at which the first sample was received.
    * \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
    * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
-   * \param antenna_id Index of antenna for which to receive samples
+   * \param num_antennas number of antennas from which to receive samples
    * \returns the number of sample read
    */
-  int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int antenna_id);
+
+  int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int num_antennas);
+
+  /*! \brief Receive samples from hardware, this version provides a single antenna at a time and returns.
+   * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
+   * the first channel. *ptimestamp is the time at which the first sample
+   * was received.
+   * \param device the hardware to use
+   * \param[out] ptimestamp the time at which the first sample was received.
+   * \param[out] buff A pointers to a buffer for received samples. The buffer must be large enough to hold the number of samples \ref nsamps.
+   * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
+   * \param antenna_id Index of antenna from which samples were received
+   * \returns the number of sample read
+   */
+  int (*trx_read_func2)(openair0_device *device, openair0_timestamp *ptimestamp, void *buff, int nsamps,int *antenna_id);
 
   /*! \brief print the device statistics
    * \param device the hardware to use
@@ -431,6 +456,25 @@ struct openair0_device_t {
    */
   void (*configure_rru)(int idx, void *arg);
 
+/*! \brief Pointer to generic RRU private information
+   */
+
+  void *thirdparty_priv;
+
+  /*! \brief Callback for Third-party RRU Initialization routine
+     \param device the hardware configuration to use
+   */
+  int (*thirdparty_init)(openair0_device *device);
+  /*! \brief Callback for Third-party RRU Cleanup routine
+     \param device the hardware configuration to use
+   */
+  int (*thirdparty_cleanup)(openair0_device *device);
+
+  /*! \brief Callback for Third-party start streaming routine
+     \param device the hardware configuration to use
+   */
+  int (*thirdparty_startstreaming)(openair0_device *device);
+
   /*! \brief RRU Configuration callback
    * \param idx RU index
    * \param arg pointer to capabilities or configuration
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
index d893c66b526bf2602b80b21f86b556cb92095c4e..9c0a9e3f6530bdd0788d736291ea2bbee6e3786c 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
@@ -102,23 +102,15 @@ int eth_socket_init_raw(openair0_device *device) {
   eth->local_addrd_ll.sll_family   = AF_PACKET;
   eth->local_addrd_ll.sll_ifindex  = eth->if_index.ifr_ifindex;
   /* hear traffic from specific protocol*/
-  if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
-     eth->local_addrd_ll.sll_protocol = htons(0xbffe);
-  } else{ 
-     eth->local_addrc_ll.sll_protocol = htons((short)device->eth_params->my_portc);
-     eth->local_addrd_ll.sll_protocol = htons((short)device->eth_params->my_portd);
-  }
+  eth->local_addrc_ll.sll_protocol = htons((short)device->eth_params->my_portc);
+  eth->local_addrd_ll.sll_protocol = htons((short)device->eth_params->my_portd);
+  
   eth->local_addrc_ll.sll_halen    = ETH_ALEN;
   eth->local_addrc_ll.sll_pkttype  = PACKET_OTHERHOST;
   eth->local_addrd_ll.sll_halen    = ETH_ALEN;
   eth->local_addrd_ll.sll_pkttype  = PACKET_OTHERHOST;
   eth->addr_len = sizeof(struct sockaddr_ll);
   
-  if ((eth->flags != ETH_RAW_IF5_MOBIPASS ) && 
-      (bind(eth->sockfdc,(struct sockaddr *)&eth->local_addrc_ll,eth->addr_len)<0)) {
-    perror("ETHERNET: Cannot bind to socket (control)");
-    exit(0);
-  }
   if (bind(eth->sockfdd,(struct sockaddr *)&eth->local_addrd_ll,eth->addr_len)<0) {
     perror("ETHERNET: Cannot bind to socket (user)");
     exit(0);
@@ -127,12 +119,9 @@ int eth_socket_init_raw(openair0_device *device) {
  /* Construct the Ethernet header */ 
  ether_aton_r(local_mac, (struct ether_addr *)(&(eth->ehd.ether_shost)));
  ether_aton_r(remote_mac, (struct ether_addr *)(&(eth->ehd.ether_dhost)));
- if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
-   eth->ehd.ether_type = htons(0xbffe);
- } else {
-   eth->ehc.ether_type = htons((short)device->eth_params->my_portc);
-   eth->ehd.ether_type = htons((short)device->eth_params->my_portd);
- } 
+ eth->ehc.ether_type = htons((short)device->eth_params->my_portc);
+ eth->ehd.ether_type = htons((short)device->eth_params->my_portd);
+  
  printf("[%s] binding to hardware address %x:%x:%x:%x:%x:%x\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"),eth->ehd.ether_shost[0],eth->ehd.ether_shost[1],eth->ehd.ether_shost[2],eth->ehd.ether_shost[3],eth->ehd.ether_shost[4],eth->ehd.ether_shost[5]);
  
  return 0;
@@ -216,8 +205,6 @@ int trx_eth_write_raw_IF4p5(openair0_device *device, openair0_timestamp timestam
     packet_size = RAW_IF4p5_PULFFT_SIZE_BYTES(nblocks);    
   } else if (flags == IF4p5_PULTICK) {
     packet_size = RAW_IF4p5_PULTICK_SIZE_BYTES;    
-  } else if (flags == IF5_MOBIPASS) {
-    packet_size = RAW_IF5_MOBIPASS_SIZE_BYTES;
   } else {
     packet_size = RAW_IF4p5_PRACH_SIZE_BYTES;
   }
@@ -430,53 +417,6 @@ int trx_eth_read_raw_IF4p5(openair0_device *device, openair0_timestamp *timestam
 }
 
 
-int trx_eth_read_raw_IF5_mobipass(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
-  // Read nblocks info from packet itself
-  
-  int bytes_received=0;
-  eth_state_t *eth = (eth_state_t*)device->priv;
-  int ret;
-
-  ssize_t packet_size =  28; //MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t ;
-//   ssize_t packet_size =  MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + 640*sizeof(int16_t);
- 
-  bytes_received = recv(eth->sockfdd,
-                        buff[0],
-                        packet_size,
-                        MSG_PEEK);
-
-  if (bytes_received ==-1) {
-          eth->num_rx_errors++;
-          perror("[MOBIPASS]ETHERNET IF5 READ (header): ");
-          exit(-1);
-  }
-
-  IF5_mobipass_header_t *test_header = (IF5_mobipass_header_t*)((uint8_t *)buff[0] + MAC_HEADER_SIZE_BYTES);
-  *timestamp = test_header->time_stamp;
-  packet_size =  MAC_HEADER_SIZE_BYTES + sizeof_IF5_mobipass_header_t + 640*sizeof(int16_t);
-
-  while(bytes_received < packet_size) {
-    ret = recv(eth->sockfdd,
-	       buff[0],
-	       packet_size,
-	       0);
-    if (bytes_received ==-1) {
-      eth->num_rx_errors++;
-      perror("[MOBIPASS] ETHERNET IF5 READ (payload): ");
-      return(-1);
-    } else {
-      bytes_received+=ret;
-      eth->rx_actual_nsamps = bytes_received>>1;
-      eth->rx_count++;
-    }
-  }
- 
-  eth->rx_nsamps = nsamps;
-  return(bytes_received);
-
-
-}
-
 int eth_set_dev_conf_raw(openair0_device *device) {
 
   eth_state_t *eth = (eth_state_t*)device->priv;
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
index 473d129aafe5151cbcde95774f9c80e05809d5aa..2dfb4a7bf1321c253105a0e0971bd9cdfa60b6d3 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
@@ -47,7 +47,7 @@
 #include "ethernet_lib.h"
 #include "common/ran_context.h"
 
-#define DEBUG 0
+//#define DEBUG 1
 
 // These are for IF5 and must be put into the device structure if multiple RUs in the same RAU !!!!!!!!!!!!!!!!!
 uint16_t pck_seq_num = 1;
@@ -142,8 +142,8 @@ int eth_socket_init_udp(openair0_device *device) {
     perror("ETHERNET: Cannot set SO_REUSEADDR option on socket (control)");
     exit(0);
   }
-  if (setsockopt(eth->sockfdd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))) {
-    perror("ETHERNET: Cannot set SO_REUSEADDR option on socket (user)");
+  if (setsockopt(eth->sockfdd, SOL_SOCKET, SO_NO_CHECK, &enable, sizeof(int))) {
+    perror("ETHERNET: Cannot set SO_NO_CHECK option on socket (user)");
     exit(0);
   }
   
@@ -202,8 +202,9 @@ int trx_eth_read_udp_IF4p5(openair0_device *device, openair0_timestamp *timestam
           goto again;
         }
       } else {
-        perror("ETHERNET IF4p5 READ");
-        printf("(%s):\n", strerror(errno));
+	return(-1);
+        //perror("ETHERNET IF4p5 READ");
+        //printf("(%s):\n", strerror(errno));
       }
     } else {
       *timestamp = test_header->sub_type;
@@ -264,36 +265,82 @@ int trx_eth_write_udp_IF4p5(openair0_device *device, openair0_timestamp timestam
   return (bytes_sent);  	  
 }
 
-int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {	
+int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int cc, int flags) {	
   
   int bytes_sent=0;
   eth_state_t *eth = (eth_state_t*)device->priv;
   int sendto_flag =0;
-  int i=0;
+
   //sendto_flag|=flags;
   eth->tx_nsamps=nsamps;
 
  
 
-  for (i=0;i<cc;i++) {	
-    /* buff[i] points to the position in tx buffer where the payload to be sent is
-       buff2 points to the position in tx buffer where the packet header will be placed */
-    void *buff2 = (void*)(buff[i]- APP_HEADER_SIZE_BYTES); 
+
+  int nsamps2;  // aligned to upper 32 or 16 byte boundary
+  
+#if defined(__x86_64) || defined(__i386__)
+#ifdef __AVX2__
+  nsamps2 = (nsamps+7)>>3;
+  __m256i buff_tx[nsamps2+1];
+  __m256i *buff_tx2=buff_tx+1;
+#else
+  nsamps2 = (nsamps+3)>>2;
+  __m128i buff_tx[nsamps2+2];
+  __m128i *buff_tx2=buff_tx+2;
+#endif
+#elif defined(__arm__) || defined(__aarch64__)
+  nsamps2 = (nsamps+3)>>2;
+  int16x8_t buff_tx[nsamps2+2];
+  int16x8_t *buff_tx2=buff_tx+2;
+#else
+#error Unsupported CPU architecture, ethernet device cannot be built
+#endif
+
     
-    /* we don't want to ovewrite with the header info the previous tx buffer data so we store it*/
-    int32_t temp0 = *(int32_t *)buff2;
-    openair0_timestamp  temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
+    // bring TX data into 12 LSBs for softmodem RX
+  for (int j=0; j<nsamps2; j++) {
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+    buff_tx2[j] = _mm256_slli_epi16(((__m256i *)buff)[j],4);
+#else
+    buff_tx2[j] = _mm_slli_epi16(((__m128i *)buff)[j],4);
+#endif
+#elif defined(__arm__)
+    buff_tx2[j] = vshlq_n_s16(((int16x8_t *)buff)[j],4);
+#endif
+  }
+
+        /* buff[i] points to the position in tx buffer where the payload to be sent is
+       buff2 points to the position in tx buffer where the packet header will be placed */
+    void *buff2 = ((void*)buff_tx2)- APP_HEADER_SIZE_BYTES; 
     
+   
+ 
     bytes_sent = 0;
     
     /* constract application header */
-    // eth->pck_header.seq_num = pck_seq_num;
-    //eth->pck_header.antenna_id = 1+(i<<1);
-    //eth->pck_header.timestamp = timestamp;
-    *(uint16_t *)buff2 = eth->pck_seq_num;
-    *(uint16_t *)(buff2 + sizeof(uint16_t)) = 1+(i<<1);
-    *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = timestamp;
-    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_SEQ_NUM, eth->pck_seq_num);
+    // ECPRI Protocol revision + reserved bits (1 byte)
+    *(uint8_t *)buff2 = ECPRIREV;
+    // ECPRI Message type (1 byte)
+    *(uint8_t *)(buff2 + 1) = 64;
+    // ECPRI Payload Size (2 bytes)
+    AssertFatal(nsamps<16381,"nsamps > 16381\n");
+    *(uint8_t *)(buff2 + 2) = (nsamps<<2)>>8;
+    *(uint8_t *)(buff2 + 3) = (nsamps<<2)&0xff;
+    // ECPRI PC_ID (2 bytes)
+    *(uint16_t *)(buff2 + 4) = cc;
+    // OAI modified SEQ_ID (4 bytes)
+    *(uint64_t *)(buff2 + 6) = ((uint64_t )timestamp)*6;
+
+    /*
+    printf("ECPRI TX (REV %x, MessType %d, Payload size %d, PC_ID %d, TS %llu\n",
+	   *(uint8_t *)buff2,
+	   *(uint8_t *)(buff2+1),
+	   *(uint16_t *)(buff2+2),
+	   *(uint16_t *)(buff2+4),
+	   *(uint64_t *)(buff2+6));
+	   */	   	   
     
     int sent_byte;
     if (eth->compression == ALAW_COMPRESS) {
@@ -311,7 +358,7 @@ int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, voi
 	     bytes_sent);
 #endif
       /* Send packet */
-      bytes_sent += sendto(eth->sockfdd,
+      bytes_sent = sendto(eth->sockfdd,
 			   buff2, 
                            sent_byte,
 			   sendto_flag,
@@ -339,17 +386,13 @@ int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, voi
       }
     //}
                   
-      /* tx buffer values restored */  
-      *(int32_t *)buff2 = temp0;
-      *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
-  }
- 
   return (bytes_sent-APP_HEADER_SIZE_BYTES)>>2;
 }
       
 
+#define NOSHIFT 1
 
-int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
+int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void *buff, int nsamps, int *cc) {
   
   int bytes_received=0;
   eth_state_t *eth = (eth_state_t*)device->priv;
@@ -357,105 +400,98 @@ int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, voi
   int rcvfrom_flag =0;
   int block_cnt=0;
   int again_cnt=0;
-  int i=0;
-
+  static int packet_cnt=0;
+  int payload_size = UDP_PACKET_SIZE_BYTES(nsamps);
+
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+    int nsamps2 = (payload_size>>5)+1;
+  __m256i temp_rx[nsamps2];
+  char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;
+#else
+    int nsamps2 = (payload_size>>4)+1;
+  __m128i temp_rx[nsamps2];
+  char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;  
+#endif
+#elif defined(__arm__) || defined(__aarch64__)
+  int nsamps2 = (payload_size>>4)+1
+  int16x8_t temp_rx[nsamps2];
+  char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;  
+#else
+#error Unsupported CPU architecture device cannot be built
+  int nsamps2 = (payload_size>>2)+1;
+  int32_t temp_rx[payload_size>>2];
+  char* *temp_rx0 = ((char *)&temp_rx[1]) - APP_HEADER_SIZE_BYTES;  
+#endif
+  
   eth->rx_nsamps=nsamps;
 
-  for (i=0;i<cc;i++) {
-    /* buff[i] points to the position in rx buffer where the payload to be received will be placed
-       buff2 points to the position in rx buffer where the packet header will be placed */
-    void *buff2 = (void*)(buff[i]- APP_HEADER_SIZE_BYTES);
-    
-    /* we don't want to ovewrite with the header info the previous rx buffer data so we store it*/
-    int32_t temp0 = *(int32_t *)buff2;
-    openair0_timestamp temp1 = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
-    
-    bytes_received=0;
-    block_cnt=0;
-    int receive_bytes;
-    if (eth->compression == ALAW_COMPRESS) {
-      receive_bytes = UDP_PACKET_SIZE_BYTES_ALAW(nsamps);
-    } else {
-      receive_bytes = UDP_PACKET_SIZE_BYTES(nsamps);
-    }
-    
-    while(bytes_received < receive_bytes) {
-    again:
-#if DEBUG   
-	   printf("------- RX------: buff2 current position=%d remaining_bytes=%d  bytes_recv=%d \n",
-		  (void *)(buff2+bytes_received),
-		  receive_bytes - bytes_received,
-		  bytes_received);
-#endif
-      bytes_received +=recvfrom(eth->sockfdd,
-				buff2,
-	                        receive_bytes,
-				rcvfrom_flag,
-				(struct sockaddr *)&eth->dest_addrd,
-				(socklen_t *)&eth->addr_len);
-      
-      if (bytes_received ==-1) {
-	eth->num_rx_errors++;
-	if (errno == EAGAIN) {
-	  again_cnt++;
-	  usleep(10);
-	  if (again_cnt == 1000) {
+  bytes_received=0;
+  block_cnt=0;
+  AssertFatal(eth->compression == NO_COMPRESS, "IF5 compression not supported for now\n");
+  
+  while(bytes_received < payload_size) {
+  again:
+    bytes_received +=recvfrom(eth->sockfdd,
+			      temp_rx0,
+			      payload_size,
+			      rcvfrom_flag,
+			      (struct sockaddr *)&eth->dest_addrd,
+			      (socklen_t *)&eth->addr_len);
+    packet_cnt++;
+    if (bytes_received ==-1) {
+      eth->num_rx_errors++;
+      if (errno == EAGAIN) {
+	again_cnt++;
+	usleep(10);
+	if (again_cnt == 1000) {
 	  perror("ETHERNET READ: ");
 	  exit(-1);
-	  } else {
-	    printf("AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN \n");
-	    goto again;
-	  }	  
-	} else if (errno == EWOULDBLOCK) {
-	     block_cnt++;
-	     usleep(10);	  
-	     if (block_cnt == 1000) {
-      perror("ETHERNET READ: ");
-      exit(-1);
-    } else {
-	    printf("BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK \n");
-	    goto again;
-	  }
+	} else {
+	  bytes_received=0;
+	  goto again;
+	}	  
+      } else if (errno == EWOULDBLOCK) {
+	block_cnt++;
+	usleep(10);	  
+	if (block_cnt == 1000) {
+	  perror("ETHERNET READ: ");
+	  exit(-1);
+	} else {
+	  printf("BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK \n");
+	  goto again;
 	}
-      } else {
-#if DEBUG   
-	   printf("------- RX------: nu=%d an_id=%d ts%d bytes_recv=%d\n",
-		  *(int16_t *)buff2,
-		  *(int16_t *)(buff2 + sizeof(int16_t)),
-		  *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
-		  bytes_received);
-
-	   dump_packet((device->host_type == RAU_HOST)? "RAU":"RRU", buff2, UDP_PACKET_SIZE_BYTES(nsamps),RX_FLAG);	  
-#endif  
-	   
-	   /* store the timestamp value from packet's header */
-	   *timestamp =  *(openair0_timestamp *)(buff2 + sizeof(int32_t));
-	   /* store the sequence number of the previous packet received */    
-	   if (eth->pck_seq_num_cur == 0) {
-	     eth->pck_seq_num_prev = *(uint16_t *)buff2;
-	   } else {
-	     eth->pck_seq_num_prev = eth->pck_seq_num_cur;
-	   }
-	   /* get the packet sequence number from packet's header */
-	   eth->pck_seq_num_cur = *(uint16_t *)buff2;
-	   if ( ( eth->pck_seq_num_cur != (eth->pck_seq_num_prev + 1) ) && !((eth->pck_seq_num_prev==MAX_PACKET_SEQ_NUM(nsamps,device->openair0_cfg->samples_per_frame)) && (eth->pck_seq_num_cur==1 )) && !((eth->pck_seq_num_prev==1) && (eth->pck_seq_num_cur==1))) {	     
-	     //#if DEBUG
-	     printf("Out of order packet received: current_packet=%d previous_packet=%d timestamp=%"PRId64"\n",eth->pck_seq_num_cur,eth->pck_seq_num_prev,*timestamp);
-	     //#endif
-	   }
-	   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM,eth->pck_seq_num_cur);
-	   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM_PRV,eth->pck_seq_num_prev);
-						    eth->rx_actual_nsamps=bytes_received>>2;
-						    eth->rx_count++;
-      }	 
-	     
       }
-      /* tx buffer values restored */  
-      *(int32_t *)buff2 = temp0;
-      *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
-	  
-    }      
-  return (bytes_received-APP_HEADER_SIZE_BYTES)>>2;
+    } else {
+      /* store the timestamp value from packet's header */
+      *timestamp =  *(openair0_timestamp *)(temp_rx0 + ECPRICOMMON_BYTES+ECPRIPCID_BYTES);
+      // convert TS to samples, /3 for 30.72 Ms/s, /6 for 15.36 Ms/s, /12 for 7.68 Ms/s, etc.
+      *timestamp = *timestamp/6;
+      // handle 1.4,3,5,10,15 MHz cases
+      *cc        = *(uint16_t*)(temp_rx0 + ECPRICOMMON_BYTES);
+    }
+    eth->rx_actual_nsamps=payload_size>>2;
+    eth->rx_count++;
+  }	 
+
+#ifdef NOSHIFT
+  memcpy(buff,(void*)(temp_rx+1),payload_size); 
+#else
+  // populate receive buffer in lower 12-bits from 16-bit representation
+  for (int j=1; j<nsamps2; j++) {
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef __AVX2__
+       ((__m256i *)buff)[j-1] = _mm256_srai_epi16(temp_rx[j],2);
+#else
+       ((__m128i *)buff)[j-1] = _mm_srai_epi16(temp_rx[j],2);
+#endif
+#elif defined(__arm__)
+       ((int16x8_t *)buff)[j] = vshrq_n_s16(temp_rx[i][j],2);
+#endif
+  }
+#endif
+  
+  return (payload_size>>2);
 }
 
 
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
index 1d3c280f0e5d18a6485e5bd9f45cb9f3e0bae916..dce410de47e0fb1dcd49dc8258c7d5606e8b26d3 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
@@ -52,11 +52,20 @@ int num_devices_eth = 0;
 struct sockaddr_in dest_addr[MAX_INST];
 int dest_addr_len[MAX_INST];
 
+int load_lib(openair0_device *device,
+             openair0_config_t *openair0_cfg,
+             eth_params_t *cfg,
+             uint8_t flag);
 
 int trx_eth_start(openair0_device *device)
 {
     eth_state_t *eth = (eth_state_t*)device->priv;
 
+    if (eth->flags == ETH_UDP_IF5_ECPRI_MODE) {
+       AssertFatal(device->thirdparty_init != NULL, "device->thirdparty_init is null\n");
+       AssertFatal(device->thirdparty_init(device) == 0, "third-party init failed\n");
+       device->openair0_cfg->samples_per_packet = 256;
+    }
     /* initialize socket */
     if (eth->flags == ETH_RAW_MODE) {
         printf("Setting ETHERNET to ETH_RAW_IF5_MODE\n");
@@ -121,11 +130,6 @@ int trx_eth_start(openair0_device *device)
 
 
 
-    } else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
-        printf("Setting ETHERNET to RAW_IF5_MODE\n");
-        if (eth_socket_init_raw(device)!=0)   return -1;
-        if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0)  return -1;
-
     } else {
         printf("Setting ETHERNET to UDP_IF5_MODE\n");
         if (eth_socket_init_udp(device)!=0)   return -1;
@@ -137,8 +141,7 @@ int trx_eth_start(openair0_device *device)
           if(eth_get_dev_conf_udp(device)!=0)  return -1;
           }*/
 
-        /* adjust MTU wrt number of samples per packet */
-        if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0)  return -1;
+        //if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0)  return -1;
 
         if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0)  return -1;
     }
@@ -166,9 +169,15 @@ void trx_eth_end(openair0_device *device)
 }
 
 
-int trx_eth_stop(openair0_device *device)
-{
-    return(0);
+
+int trx_eth_stop(openair0_device *device) {
+  eth_state_t *eth = (eth_state_t*)device->priv;
+  
+  if (eth->flags == ETH_UDP_IF5_ECPRI_MODE) {
+    AssertFatal(device->thirdparty_cleanup != NULL, "device->thirdparty_cleanup is null\n");
+    AssertFatal(device->thirdparty_cleanup(device) == 0, "third-party cleanup failed\n");
+  }
+  return(0);
 }
 
 
@@ -387,20 +396,11 @@ int transport_init(openair0_device *device,
     eth_state_t *eth = (eth_state_t*)malloc(sizeof(eth_state_t));
     memset(eth, 0, sizeof(eth_state_t));
 
-    if (eth_params->transp_preference == 1) {
-        eth->flags = ETH_RAW_MODE;
-    } else if (eth_params->transp_preference == 0) {
-        eth->flags = ETH_UDP_MODE;
-    } else if (eth_params->transp_preference == 3) {
-        eth->flags = ETH_RAW_IF4p5_MODE;
-    } else if (eth_params->transp_preference == 2) {
-        eth->flags = ETH_UDP_IF4p5_MODE;
-    } else if (eth_params->transp_preference == 4) {
-        eth->flags = ETH_RAW_IF5_MOBIPASS;
-    } else {
-        printf("transport_init: Unknown transport preference %d - default to RAW", eth_params->transp_preference);
-        eth->flags = ETH_RAW_MODE;
-    }
+    eth->flags = eth_params->transp_preference;
+
+    // load third-party driver
+    if (eth->flags == ETH_UDP_IF5_ECPRI_MODE) load_lib(device,openair0_cfg,eth_params,RAU_REMOTE_THIRDPARTY_RADIO_HEAD);
+
 
     if (eth_params->if_compress == 0) {
         eth->compression = NO_COMPRESS;
@@ -423,12 +423,17 @@ int transport_init(openair0_device *device,
     device->trx_set_gains_func   = trx_eth_set_gains;
     device->trx_write_init       = trx_eth_write_init;
 
-    if (eth->flags == ETH_RAW_MODE) {
+    device->trx_read_func2 = NULL;
+    device->trx_read_func = NULL;
+    device->trx_write_func2 = NULL;
+    device->trx_write_func = NULL;
+
+    if  (eth->flags == ETH_RAW_MODE) {
         device->trx_write_func   = trx_eth_write_raw;
         device->trx_read_func    = trx_eth_read_raw;
-    } else if (eth->flags == ETH_UDP_MODE) {
-        device->trx_write_func   = trx_eth_write_udp;
-        device->trx_read_func    = trx_eth_read_udp;
+    } else if (eth->flags == ETH_UDP_MODE || eth->flags == ETH_UDP_IF5_ECPRI_MODE) {
+        device->trx_write_func2   = trx_eth_write_udp;
+        device->trx_read_func2    = trx_eth_read_udp;
         device->trx_ctlsend_func = trx_eth_ctlsend_udp;
         device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
     } else if (eth->flags == ETH_RAW_IF4p5_MODE) {
@@ -439,9 +444,6 @@ int transport_init(openair0_device *device,
         device->trx_read_func    = trx_eth_read_udp_IF4p5;
         device->trx_ctlsend_func = trx_eth_ctlsend_udp;
         device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
-    } else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
-        device->trx_write_func   = trx_eth_write_raw_IF4p5;
-        device->trx_read_func    = trx_eth_read_raw_IF5_mobipass;
     } else {
         //device->trx_write_func   = trx_eth_write_udp_IF4p5;
         //device->trx_read_func    = trx_eth_read_udp_IF4p5;
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h
index 65b2def60d549e4733c198673d95a5e5511f3e86..ad64ac1a8a3b91120540e391d2bd95e878206616 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h
@@ -49,7 +49,10 @@
 #define RX_FLAG 0
 
 #include "if_defs.h"
-#define APP_HEADER_SIZE_BYTES (sizeof(int32_t) + sizeof(openair0_timestamp))
+#define ECPRICOMMON_BYTES 4
+#define ECPRIPCID_BYTES 2
+#define APP_HEADER_SIZE_BYTES (ECPRICOMMON_BYTES + ECPRIPCID_BYTES + sizeof(openair0_timestamp))
+#define ECPRIREV 1 // ECPRI Version 1, C=0 - single ECPRI message per OAI TX packet
 
 /*!\brief opaque ethernet data structure */
 typedef struct {
@@ -234,8 +237,8 @@ int ethernet_tune(openair0_device *device, unsigned int option, int value);
 * @ingroup  _oai
 */
 int eth_socket_init_udp(openair0_device *device);
-int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags);
-int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc);
+int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int cc, int flags);
+int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void *buff, int nsamps, int *cc);
 
 
 int eth_socket_init_raw(openair0_device *device);
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h b/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h
index 0f2147847a6145230078b8e4f30f16d9c23eef12..47205cf8b8bdc72f6f985860eeafefc9b570f961 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/if_defs.h
@@ -36,15 +36,17 @@
 #include <netinet/ether.h>
 #include <stdint.h>
 
+#ifndef LITE_COMPILATION
 #include "PHY/LTE_TRANSPORT/if4_tools.h"
 #include "PHY/LTE_TRANSPORT/if5_tools.h"
+#endif
 
 // ETH transport preference modes
-#define ETH_UDP_MODE        0
-#define ETH_RAW_MODE        1
+#define ETH_UDP_MODE          0
+#define ETH_RAW_MODE          1
 #define ETH_UDP_IF4p5_MODE    2
 #define ETH_RAW_IF4p5_MODE    3
-#define ETH_RAW_IF5_MOBIPASS    4    
+#define ETH_UDP_IF5_ECPRI_MODE  4    
 
 // COMMOM HEADER LENGTHS
 
diff --git a/targets/ARCH/rfsimulator/README.md b/targets/ARCH/rfsimulator/README.md
index 9ec0ae50659ecf34f7d30a6ddccd1ab0397efa45..4a8d5ff79acb1092a590d0b0ca2bc49af105e3f2 100644
--- a/targets/ARCH/rfsimulator/README.md
+++ b/targets/ARCH/rfsimulator/README.md
@@ -59,6 +59,29 @@ The RF simulator is using the configuration module, and its parameters are defin
         
 Setting the env variable RFSIMULATOR can be used instead of using the serveraddr parameter; it is to preserve compatibility with previous version.
 
+## How to use the RF simulator options
+
+Add the following options to the command line to enable the channel model and the IQ samples saving for future replay:
+```bash
+--rfsimulator.options chanmod,saviq
+```
+or just:
+```bash
+--rfsimulator.options chanmod
+```
+to enable the channel model. 
+
+set the model with:
+```bash
+--rfsimulator.modelname AWGN
+```
+
+Example run:
+
+```bash
+sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD --rfsim --phy-test --rfsimulator.options chanmod --rfsimulator.modelname AWGN 
+```
+
 ## 4G case
 
 For the UE, it should be set to the IP address of the eNB. For example:
@@ -165,5 +188,50 @@ Only the input noise can be changed on command line with the `-s` parameter.
 
 With path loss = 0 set `-s 5` to see a little noise. `-s` is a shortcut to `channelmod.s`. It is expected to enhance the channel modelization flexibility by the addition of more parameters in the channelmod section.
 
+Example to add a very small noise:
+```bash
+-s 30
+```
+to add a lot of noise:
+```bash
+-s 5
+```
+
+Example run commands:
+```bash
+sudo RFSIMULATOR=server ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD --rfsim --phy-test --rfsimulator.options chanmod --rfsimulator.modelname AWGN 
+
+```
+# Real time control and monitoring
+
+Add the `--telnetsrv` option to the command line. Then in a new shell, connect to the telnet server, example:
+```bash
+telnet 127.0.0.1 9090
+```
+once connected it is possible to monitor the current status:
+```bash
+channelmod show current
+```
+
+see the available channel models:
+```bash
+channelmod show predef
+```
+
+or modify the channel model, for example setting a new model:
+```bash
+rfsimu setmodel AWGN
+```
+setting the pathloss, etc...:
+```bash
+channelmod modify <channelid> <param> <value>
+channelmod modify 0 ploss 15
+```
+where:
+```bash
+<param name> can be one of "riceanf", "aoa", "randaoa", "ploss", "offset", "forgetf"
+```
+
 # Caveats
 Still issues in power control: txgain, rxgain are not used.
+
diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c
index c4760d8aee46b190950bef6c2b56ec4e52f3a129..20fe6a782815ffecc50c5e346d325f019127cb40 100644
--- a/targets/ARCH/rfsimulator/simulator.c
+++ b/targets/ARCH/rfsimulator/simulator.c
@@ -555,7 +555,7 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi
 	    memset(b->circularBuf, 0, sampleToByte(CirSize,1));
 	  }
 
-          if (b->lastReceivedTS != 0 && b->th.timestamp-b->lastReceivedTS > 50 )
+          if (b->lastReceivedTS != 0 && b->th.timestamp-b->lastReceivedTS < 1000)
             LOG_W(HW,"UEsock: %d gap of: %ld in reception\n", fd, b->th.timestamp-b->lastReceivedTS );
 
           b->lastReceivedTS=b->th.timestamp;
@@ -628,7 +628,7 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo
       t->nextTimestamp+=nsamps;
 
       if ( ((t->nextTimestamp/nsamps)%100) == 0)
-        LOG_W(HW,"No UE, Generated void samples for Rx: %ld\n", t->nextTimestamp);
+        LOG_D(HW,"No UE, Generated void samples for Rx: %ld\n", t->nextTimestamp);
 
       *ptimestamp = t->nextTimestamp-nsamps;
       return nsamps;
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf
index ea38aba1b238bdc1c6e8b038491d5943f920e85a..19d9146f34b88ba720735066ddff997340e1a887 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf
@@ -71,6 +71,11 @@ gNBs =
              initialDLBWPmappingType_2           = 0;
              #this is SS=1,L=12 
              initialDLBWPstartSymbolAndLength_2  = 54;
+
+             initialDLBWPk0_3                    = 0;
+             initialDLBWPmappingType_3           = 0;
+             #this is SS=1,L=4 //5 (4 is for 43, 5 is for 57)
+             initialDLBWPstartSymbolAndLength_3  = 57; //43; //57;
   #uplinkConfigCommon 
      #frequencyInfoUL
       ul_frequencyBand                                                 = 257;
@@ -89,7 +94,7 @@ gNBs =
         initialULBWPsubcarrierSpacing                                           = 3;
       #rach-ConfigCommon
         #rach-ConfigGeneric
-          prach_ConfigurationIndex                                  = 98;
+          prach_ConfigurationIndex                                  = 52;
 #prach_msg1_FDM
 #0 = one, 1=two, 2=four, 3=eight
           prach_msg1_FDM                                            = 0;
@@ -103,12 +108,12 @@ gNBs =
         powerRampingStep                                            = 1;
 #ra_ReponseWindow
 #1,2,4,8,10,20,40,80
-        ra_ResponseWindow                                           = 4;
+        ra_ResponseWindow                                           = 7;
 #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
-#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
+#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen
         ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR                = 4;
 #oneHalf (0..15) 4,8,12,16,...60,64
-        ssb_perRACH_OccasionAndCB_PreamblesPerSSB                   = 15;
+        ssb_perRACH_OccasionAndCB_PreamblesPerSSB                   = 7;
 #ra_ContentionResolutionTimer
 #(0..7) 8,16,24,32,40,48,56,64
         ra_ContentionResolutionTimer                                = 7;
@@ -119,22 +124,26 @@ gNBs =
         prach_RootSequenceIndex                                     = 1;
         # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
         #  
-        msg1_SubcarrierSpacing                                      = 1,
+        msg1_SubcarrierSpacing                                      = 3,
 
 # restrictedSetConfig
 # 0=unrestricted, 1=restricted type A, 2=restricted type B
         restrictedSetConfig                                         = 0,
       # pusch-ConfigCommon (up to 16 elements)
-        initialULBWPk2_0                      = 2;
+        initialULBWPk2_0                      = 6;
         initialULBWPmappingType_0             = 1
         # this is SS=0 L=11
         initialULBWPstartSymbolAndLength_0    = 55;
- 	
-	initialULBWPk2_1                      = 2;
+
+        initialULBWPk2_1                      = 6;
         initialULBWPmappingType_1             = 1;
         # this is SS=0 L=12
         initialULBWPstartSymbolAndLength_1    = 69;
 
+        initialULBWPk2_2                      = 7;
+        initialULBWPmappingType_2             = 1;
+        # this is SS=10 L=4
+        initialULBWPstartSymbolAndLength_2    = 52;
 
         msg3_DeltaPreamble                                          = 1;
         p0_NominalWithGrant                                         =-90;
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf
index 82b941ea0eb672a91b2e422e1c905f48777e366b..6681a43a1de917e8fec72d44ad9d060a87e51db4 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf
@@ -47,7 +47,7 @@ gNBs =
         dl_carrierBandwidth                                            = 32;
      #initialDownlinkBWP
       #genericParameters
-        # this is RBstart=0,L=50 (275*(L-1))+RBstart
+        # this is RBstart=0,L=32 (275*(L-1))+RBstart
         initialDLBWPlocationAndBandwidth                                        = 8525;
 # subcarrierSpacing
 # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120  
@@ -121,8 +121,8 @@ gNBs =
         ra_ContentionResolutionTimer                                = 7;
         rsrp_ThresholdSSB                                           = 19;
 #prach-RootSequenceIndex_PR
-#0 = 839, 1 = 139
-        prach_RootSequenceIndex_PR                                  = 1;
+#1 = 839, 2 = 139
+        prach_RootSequenceIndex_PR                                  = 2;
         prach_RootSequenceIndex                                     = 1;
         # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
         #  
@@ -132,12 +132,12 @@ gNBs =
 # 0=unrestricted, 1=restricted type A, 2=restricted type B
         restrictedSetConfig                                         = 0,
       # pusch-ConfigCommon (up to 16 elements)
-        initialULBWPk2_0                      = 2;
+        initialULBWPk2_0                      = 6;
         initialULBWPmappingType_0             = 1
         # this is SS=0 L=11
         initialULBWPstartSymbolAndLength_0    = 55;
- 	
-	initialULBWPk2_1                      = 2;
+
+        initialULBWPk2_1                      = 6;
         initialULBWPmappingType_1             = 1;
         # this is SS=0 L=12
         initialULBWPstartSymbolAndLength_1    = 69;
@@ -211,7 +211,7 @@ gNBs =
                           );
 
     ///X2
-    enable_x2 = "yes";
+    enable_x2 = "no";
     t_reloc_prep      = 1000;      /* unit: millisecond */
     tx2_reloc_overall = 2000;      /* unit: millisecond */
     t_dc_prep         = 1000;      /* unit: millisecond */
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf
index 56078029af46a4bf216d185f3256621812aaa33b..1cd3b01b6c7aa6bfde7052ce0fb15b11a409f923 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf
@@ -1,6 +1,7 @@
 Active_gNBs = ( "gNB-Eurecom-5GNRBox");
 # Asn1_verbosity, choice in: none, info, annoying
 Asn1_verbosity = "none";
+Num_Threads_PUSCH = 8;
 
 gNBs =
 (
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc_b38_if5_ENDC.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc_b38_if5_ENDC.conf
new file mode 100644
index 0000000000000000000000000000000000000000..9b611b3f07816e9107d316d335b77fbb406671a1
--- /dev/null
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc_b38_if5_ENDC.conf
@@ -0,0 +1,243 @@
+Active_eNBs = ( "eNB_Eurecom_VCO_B38");
+# Asn1_verbosity, choice in: none, info, annoying
+Asn1_verbosity = "none";
+
+eNBs =
+(
+ {
+    # real_time choice in {hard, rt-preempt, no}
+    real_time       =  "no";
+
+    ////////// Identification parameters:
+    eNB_ID    =  0xe00;
+
+    cell_type =  "CELL_MACRO_ENB";
+
+    eNB_name  =  "eNB_Eurecom_VCO_B38";
+
+    // Tracking area code, 0x0000 and 0xfffe are reserved values
+    tracking_area_code = 1;
+
+    plmn_list = ( { mcc = 222; mnc = 01; mnc_length = 2; } );
+
+       ////////// Physical parameters:
+
+    component_carriers = (
+      {
+        node_function                                         = "NGFI_RCC_IF5";
+        node_timing                                           = "synch_to_ext_device";
+        node_synch_ref                                        = 0;
+        frame_type					      = "TDD";
+        tdd_config 					      = 1;
+        tdd_config_s            			      = 0;
+        prefix_type             			      = "NORMAL";
+        eutra_band              			      = 38;
+        downlink_frequency      			      = 2585000000L;
+        uplink_frequency_offset 			      = 0;
+        Nid_cell					      = 0;
+        N_RB_DL                 			      = 100;
+        Nid_cell_mbsfn          			      = 0;
+        nb_antenna_ports          			      = 1;
+        nb_antennas_tx          			      = 1;
+        nb_antennas_rx          			      = 1;
+        tx_gain                                            = 90;
+        rx_gain                                            = 125;
+        prach_root              			      = 0;
+        prach_config_index      			      = 0;
+        prach_high_speed        			      = "DISABLE";
+        prach_zero_correlation  			      = 5;
+        prach_freq_offset       			      = 2;
+        pucch_delta_shift       			      = 1;
+        pucch_nRB_CQI           			      = 1;
+        pucch_nCS_AN            			      = 0;
+        pucch_n1_AN             			      = 0;
+        pdsch_referenceSignalPower 			      = 10;
+        pdsch_p_b                  			      = 0;
+        pusch_n_SB                 			      = 1;
+        pusch_enable64QAM          			      = "DISABLE";
+        pusch_hoppingMode                                  = "interSubFrame";
+        pusch_hoppingOffset                                = 0;
+        pusch_groupHoppingEnabled  			      = "ENABLE";
+        pusch_groupAssignment      			      = 0;
+        pusch_sequenceHoppingEnabled		   	      = "DISABLE";
+        pusch_nDMRS1                                       = 1;
+        phich_duration                                     = "NORMAL";
+        phich_resource                                     = "ONESIXTH";
+        srs_enable                                         = "DISABLE";
+      /*  srs_BandwidthConfig                                =;
+        srs_SubframeConfig                                 =;
+        srs_ackNackST                                      =;
+        srs_MaxUpPts                                       =;*/
+
+        pusch_p0_Nominal                                   = -96;
+        pusch_alpha                                        = "AL1";
+        pucch_p0_Nominal                                   = -106;
+        msg3_delta_Preamble                                = 6;
+        pucch_deltaF_Format1                               = "deltaF2";
+        pucch_deltaF_Format1b                              = "deltaF3";
+        pucch_deltaF_Format2                               = "deltaF0";
+        pucch_deltaF_Format2a                              = "deltaF0";
+        pucch_deltaF_Format2b		    	      = "deltaF0";
+
+        rach_numberOfRA_Preambles                          = 64;
+        rach_preamblesGroupAConfig                         = "DISABLE";
+      /*
+        rach_sizeOfRA_PreamblesGroupA                      = ;
+        rach_messageSizeGroupA                             = ;
+        rach_messagePowerOffsetGroupB                      = ;
+      */
+        rach_powerRampingStep                              = 4;
+        rach_preambleInitialReceivedTargetPower            = -108;
+        rach_preambleTransMax                              = 10;
+        rach_raResponseWindowSize                          = 10;
+        rach_macContentionResolutionTimer                  = 48;
+        rach_maxHARQ_Msg3Tx                                = 4;
+
+        pcch_default_PagingCycle                           = 128;
+        pcch_nB                                            = "oneT";
+        bcch_modificationPeriodCoeff			      = 2;
+        ue_TimersAndConstants_t300			      = 1000;
+        ue_TimersAndConstants_t301			      = 1000;
+        ue_TimersAndConstants_t310			      = 1000;
+        ue_TimersAndConstants_t311			      = 10000;
+        ue_TimersAndConstants_n310			      = 20;
+        ue_TimersAndConstants_n311			      = 1;
+
+	ue_TransmissionMode				      = 1;
+      }
+    );
+
+
+    srb1_parameters :
+    {
+        # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
+        timer_poll_retransmit    = 80;
+
+        # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
+        timer_reordering         = 35;
+
+        # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
+        timer_status_prohibit    = 0;
+
+        # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
+        poll_pdu                 =  4;
+
+        # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
+        poll_byte                =  99999;
+
+        # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
+        max_retx_threshold       =  4;
+    }
+
+    # ------- SCTP definitions
+    SCTP :
+    {
+        # Number of streams to use in input/output
+        SCTP_INSTREAMS  = 2;
+        SCTP_OUTSTREAMS = 2;
+    };
+
+    ////////// MME parameters:
+    mme_ip_address      = ( { ipv4       = "192.168.18.150";
+                              ipv6       = "192:168:30::17";
+                              active     = "yes";
+                              preference = "ipv4";
+                            }
+                          );
+
+    enable_measurement_reports = "no";
+
+    ///X2
+    enable_x2 = "yes";
+    t_reloc_prep      = 1000;      /* unit: millisecond */
+    tx2_reloc_overall = 2000;      /* unit: millisecond */
+    t_dc_prep         = 1000;
+    t_dc_overall      = 2000;
+
+    NETWORK_INTERFACES :
+    {
+        ENB_INTERFACE_NAME_FOR_S1_MME            = "bond0";
+        ENB_IPV4_ADDRESS_FOR_S1_MME              = "192.168.18.203/24";
+        ENB_INTERFACE_NAME_FOR_S1U               = "bond0";
+        ENB_IPV4_ADDRESS_FOR_S1U                 = "192.168.18.203/24";
+        ENB_PORT_FOR_S1U                         = 2152; # Spec 2152
+        ENB_IPV4_ADDRESS_FOR_X2C                 = "192.168.18.203/24";
+        ENB_PORT_FOR_X2C                         = 36422; # Spec 36422
+    };
+
+    log_config :
+    {
+      global_log_level                      ="debug";
+      global_log_verbosity                  ="medium";
+      hw_log_level                          ="info";
+      hw_log_verbosity                      ="medium";
+      phy_log_level                         ="info";
+      phy_log_verbosity                     ="medium";
+      mac_log_level                         ="info";
+      mac_log_verbosity                     ="high";
+      rlc_log_level                         ="info";
+      rlc_log_verbosity                     ="medium";
+      pdcp_log_level                        ="info";
+      pdcp_log_verbosity                    ="medium";
+      rrc_log_level                         ="info";
+      rrc_log_verbosity                     ="medium";
+   };
+
+  }
+);
+MACRLCs = (
+	{
+        num_cc = 1;
+        tr_s_preference = "local_L1";
+        tr_n_preference = "local_RRC";
+        scheduler_mode = "fairRR";
+        puSch10xSnr     =  100;
+        puCch10xSnr     =  100;
+        }  
+);
+
+L1s = (
+    	{
+	num_cc = 1;
+	tr_n_preference = "local_mac";
+        prach_dtx_threshold = 150;
+        }  
+);
+
+RUs = (
+    {		  
+        local_if_name  = "bond0";
+        remote_address = "192.168.18.222";
+        local_address  = "192.168.18.203";
+        local_portc    = 50000;
+        remote_portc   = 55444;
+        local_portd    = 52001;
+        remote_portd   = 52183;
+        local_rf       = "no"
+        tr_preference  = "udp_ecpri_if5"
+        nb_tx          = 1
+        nb_rx          = 1
+        att_tx         = 5 
+        att_rx         = 0;
+        eNB_instances  = [0];
+    }
+);  
+
+THREAD_STRUCT = (
+  {
+    #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
+    parallel_config    = "PARALLEL_RU_L1_TRX_SPLIT";
+    #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
+    worker_config      = "WORKER_ENABLE";
+  }
+);
+
+NETWORK_CONTROLLER :
+{
+    FLEXRAN_ENABLED        = "no";
+    FLEXRAN_INTERFACE_NAME = "lo";
+    FLEXRAN_IPV4_ADDRESS   = "127.0.0.1";
+    FLEXRAN_PORT           = 2210;
+    FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
+    FLEXRAN_AWAIT_RECONF   = "no";
+};
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
index fd1b62fd3dc05e3ec56fb977c1a65ee9a45a60d0..e34b26150092b902660cdf8b9fb43ef7595e82ff 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
@@ -1,6 +1,7 @@
 Active_gNBs = ( "gNB-Eurecom-5GNRBox");
 # Asn1_verbosity, choice in: none, info, annoying
 Asn1_verbosity = "none";
+Num_Threads_PUSCH = 8;
 
 gNBs =
 (
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index 7d6cb9c429121b7329013982cca3b7b979c8ecfc..1347d75fb06939f6b3fbf5526f9f1fbc0c08c09a 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -461,10 +461,9 @@ void eNB_top(PHY_VARS_eNB *eNB,
     L1_proc->subframe_rx  = ru_proc->tti_rx;
     L1_proc->frame_tx     = (L1_proc->subframe_rx > (9-sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx;
     L1_proc->subframe_tx  = (L1_proc->subframe_rx + sf_ahead)%10;
-
+    
     if (rxtx(eNB,L1_proc,string) < 0)
-      LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id);
-
+      LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id);  
     ru_proc->timestamp_tx = L1_proc->timestamp_tx;
     ru_proc->tti_tx  = L1_proc->subframe_tx;
     ru_proc->frame_tx     = L1_proc->frame_tx;
@@ -1168,6 +1167,7 @@ void init_eNB_afterRU(void) {
 
       for (ru_id=0,aa=0; ru_id<eNB->num_RU; ru_id++) {
         eNB->frame_parms.nb_antennas_rx    += eNB->RU_list[ru_id]->nb_rx;
+
         AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL,
                     "RU %d : common.rxdataF is NULL\n",
                     eNB->RU_list[ru_id]->idx);
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
index 4e3a6612736a9ea4e8ed9cf468d55f7c8e8aa50e..56c2cb23dd43114975300a5c41b160c38c6a8551 100644
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -120,6 +120,8 @@ void configure_rru(int idx,
 void reset_proc(RU_t *ru);
 int connect_rau(RU_t *ru);
 
+void wait_eNBs(void);
+
 const char ru_states[6][9] = {"RU_IDLE","RU_CONFIG","RU_READY","RU_RUN","RU_ERROR","RU_SYNC"};
 
 extern uint16_t sf_ahead;
@@ -141,16 +143,12 @@ extern uint16_t sf_ahead;
 static inline void fh_if5_south_out(RU_t *ru,int frame, int subframe, uint64_t timestamp) {
   if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
 
+  ru->south_out_cnt++;
+
   send_IF5(ru, timestamp, subframe, &ru->seqno, IF5_RRH_GW_DL);
 }
 
 
-// southbound IF5 fronthaul for Mobipass packet format
-static inline void fh_if5_mobipass_south_out(RU_t *ru,int frame, int subframe, uint64_t timestamp) {
-  if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
-
-  send_IF5(ru, timestamp, subframe, &ru->seqno, IF5_MOBIPASS);
-}
 
 
 // southbound IF4p5 fronthaul
@@ -189,11 +187,12 @@ void fh_if5_south_in(RU_t *ru,
   recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL);
   proc->frame_rx    = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
   proc->tti_rx = (proc->timestamp_rx / fp->samples_per_tti)%10;
-
+  
   if (proc->first_rx == 0) {
     if (proc->tti_rx != *subframe) {
-      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*subframe);
-      exit_fun("Exiting");
+      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d), resynching\n",proc->tti_rx,*subframe);
+      *frame=proc->frame_rx;
+      *subframe=proc->tti_rx;
     }
 
     if (proc->frame_rx != *frame) {
@@ -324,48 +323,6 @@ void fh_slave_south_in(RU_t *ru,
 }
 
 
-// asynchronous inbound if5 fronthaul from south (Mobipass)
-void fh_if5_south_asynch_in_mobipass(RU_t *ru,
-                                     int *frame,
-                                     int *subframe) {
-  RU_proc_t *proc        = &ru->proc;
-  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
-  recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_MOBIPASS);
-  pthread_mutex_lock(&proc->mutex_asynch_rxtx);
-  int offset_mobipass = 40120;
-  pthread_mutex_lock(&proc->mutex_asynch_rxtx);
-  proc->tti_rx = ((proc->timestamp_rx-offset_mobipass)/fp->samples_per_tti)%10;
-  proc->frame_rx    = ((proc->timestamp_rx-offset_mobipass)/(fp->samples_per_tti*10))&1023;
-  proc->tti_rx = (proc->timestamp_rx/fp->samples_per_tti)%10;
-  proc->frame_rx    = (proc->timestamp_rx/(10*fp->samples_per_tti))&1023;
-
-  if (proc->first_rx == 1) {
-    proc->first_rx =2;
-    *subframe = proc->tti_rx;
-    *frame    = proc->frame_rx;
-    LOG_E(PHY,"[Mobipass]timestamp_rx:%llu, frame_rx %d, subframe: %d\n",(unsigned long long int)proc->timestamp_rx,proc->frame_rx,proc->tti_rx);
-  } else {
-    if (proc->tti_rx != *subframe) {
-      proc->first_rx++;
-      LOG_E(PHY,"[Mobipass]timestamp:%llu, tti_rx %d is not what we expect %d, first_rx:%d\n",(unsigned long long int)proc->timestamp_rx, proc->tti_rx,*subframe, proc->first_rx);
-      //exit_fun("Exiting");
-    }
-
-    if (proc->frame_rx != *frame) {
-      proc->first_rx++;
-      LOG_E(PHY,"[Mobipass]timestamp:%llu, frame_rx %d is not what we expect %d, first_rx:%d\n",(unsigned long long int)proc->timestamp_rx,proc->frame_rx,*frame, proc->first_rx);
-      // exit_fun("Exiting");
-    }
-
-    // temporary solution
-    *subframe = proc->tti_rx;
-    *frame    = proc->frame_rx;
-  }
-
-  pthread_mutex_unlock(&proc->mutex_asynch_rxtx);
-} // eNodeB_3GPP_BBU
-
-
 // asynchronous inbound if4p5 fronthaul from south
 void fh_if4p5_south_asynch_in(RU_t *ru,
                               int *frame,
@@ -456,7 +413,7 @@ void fh_if5_north_asynch_in(RU_t *ru,
   int tti_tx,frame_tx;
   openair0_timestamp timestamp_tx;
   recv_IF5(ru, &timestamp_tx, *subframe, IF5_RRH_GW_DL);
-  //      printf("Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx);
+  //      LOG_I(PHY,"Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx);
   tti_tx = (timestamp_tx/fp->samples_per_tti)%10;
   frame_tx    = (timestamp_tx/(fp->samples_per_tti*10))&1023;
   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
@@ -696,7 +653,7 @@ void rx_rf(RU_t *ru,
     ru->ts_offset = proc->timestamp_rx;
     proc->timestamp_rx = 0;
   } else if (resynch==0 && (proc->timestamp_rx - old_ts != fp->samples_per_tti)) {
-    LOG_I(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - fp->samples_per_tti,ru->ts_offset);
+    LOG_D(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - fp->samples_per_tti,ru->ts_offset);
     ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti);
     proc->timestamp_rx = ts-ru->ts_offset;
   }
@@ -761,7 +718,7 @@ void rx_rf(RU_t *ru,
     *subframe = proc->tti_rx;
   }
 
-  //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe);
+  //LOG_I(PHY,"timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe);
   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
 
   if (rxs != fp->samples_per_tti) {
@@ -929,12 +886,8 @@ static void *ru_thread_asynch_rxtx( void *param ) {
 
       LOG_D(PHY,"ru_thread_asynch_rxtx: Waiting on incoming fronthaul\n");
 
-      // asynchronous receive from south (Mobipass)
-      if (ru->fh_south_asynch_in) {
-        ru->fh_south_asynch_in(ru, &frame, &subframe);
-      }
       // asynchronous receive from north (RRU IF4/IF5)
-      else if (ru->fh_north_asynch_in) {
+      if (ru->fh_north_asynch_in) {
         if (subframe_select(ru->frame_parms,subframe)!=SF_UL)
           ru->fh_north_asynch_in(ru, &frame, &subframe);
       } else
@@ -1185,21 +1138,22 @@ void wakeup_L1s(RU_t *ru) {
   L1_proc_t *proc         = &eNB->proc;
   struct timespec t;
   LOG_D(PHY, "wakeup_L1s (num %d) for RU %d (%d.%d) ru->eNB_top:%p\n", ru->num_eNB, ru->idx, ru->proc.frame_rx, ru->proc.tti_rx, ru->eNB_top);
-  // call eNB function directly
   char string[20];
   sprintf(string, "Incoming RU %d", ru->idx);
+
+  // call eNB function directly
   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.frame_rx);
   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.tti_rx);
   AssertFatal(0==pthread_mutex_lock(&proc->mutex_RU),"");
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOCK_MUTEX_RU+ru->idx, 1);
-  //printf("wakeup_L1s: Frame %d, Subframe %d: RU %d done (wait_cnt %d),RU_mask[%d] %x\n",
-  //          ru->proc.frame_rx,ru->proc.subframe_rx,ru->idx,ru->wait_cnt,ru->proc.subframe_rx,proc->RU_mask[ru->proc.subframe_rx]);
+  //LOG_I(PHY,"wakeup_L1s: Frame %d, Subframe %d: RU %d done (wait_cnt %d),RU_mask[%d] %x\n",
+  //          ru->proc.frame_rx,ru->proc.tti_rx,ru->idx,ru->wait_cnt,ru->proc.tti_rx,proc->RU_mask[ru->proc.tti_rx]);
   //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.frame_rx);
-  //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.subframe_rx);
+  //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.tti_rx);
   clock_gettime(CLOCK_MONOTONIC, &ru->proc.t[ru->proc.tti_rx]);
 
   if (proc->RU_mask[ru->proc.tti_rx] == 0) {
-    //clock_gettime(CLOCK_MONOTONIC,&proc->t[ru->proc.subframe_rx]);
+    //clock_gettime(CLOCK_MONOTONIC,&proc->t[ru->proc.tti_rx]);
     proc->t[ru->proc.tti_rx] = ru->proc.t[ru->proc.tti_rx];
     //start_meas(&proc->ru_arrival_time);
     LOG_D(PHY,"RU %d starting timer for frame %d subframe %d\n", ru->idx, ru->proc.frame_rx, ru->proc.tti_rx);
@@ -1212,13 +1166,13 @@ void wakeup_L1s(RU_t *ru) {
           eNB->RU_list[i]->idx, eNB->RU_list[i]->proc.frame_rx, eNB->RU_list[i]->proc.tti_rx, ru_states[eNB->RU_list[i]->state]);
 
     if (ru == eNB->RU_list[i] && eNB->RU_list[i]->wait_cnt == 0) {
-      //AssertFatal((proc->RU_mask&(1<<i)) == 0, "eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", eNB->Mod_id,ru->proc.frame_rx,ru->proc.subframe_rx,ru->idx,eNB->num_RU,proc->RU_mask);
+      //AssertFatal((proc->RU_mask&(1<<i)) == 0, "eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", eNB->Mod_id,ru->proc.frame_rx,ru->proc.tti_rx,ru->idx,eNB->num_RU,proc->RU_mask);
       proc->RU_mask[ru->proc.tti_rx] |= (1<<i);
     } else if (/*eNB->RU_list[i]->state == RU_SYNC ||*/(eNB->RU_list[i]->is_slave==1 && eNB->RU_list[i]->wait_cnt>0 && ru!=eNB->RU_list[i] && ru->is_slave==0) ) {
       proc->RU_mask[ru->proc.tti_rx] |= (1<<i);
     }
 
-    //printf("RU %d, RU_mask[%d] %d, i %d, frame %d, slave %d, ru->cnt %d, i->cnt %d\n",ru->idx,ru->proc.subframe_rx,proc->RU_mask[ru->proc.subframe_rx],i,ru->proc.frame_rx,ru->is_slave,ru->wait_cnt,eNB->RU_list[i]->wait_cnt);
+    //LOG_I(PHY,"RU %d, RU_mask[%d] %d, i %d, frame %d, slave %d, ru->cnt %d, i->cnt %d\n",ru->idx,ru->proc.tti_rx,proc->RU_mask[ru->proc.tti_rx],i,ru->proc.frame_rx,ru->is_slave,ru->wait_cnt,eNB->RU_list[i]->wait_cnt);
     VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_MASK_RU, proc->RU_mask[ru->proc.tti_rx]);
 
     if (ru->is_slave == 0 && ( (proc->RU_mask[ru->proc.tti_rx]&(1<<i)) == 1 ) && eNB->RU_list[i]->state == RU_RUN) { //This is master & the RRU has already been received
@@ -1233,21 +1187,21 @@ void wakeup_L1s(RU_t *ru) {
   }
 
   //clock_gettime(CLOCK_MONOTONIC,&t);
-  //LOG_I(PHY,"RU mask is now %x, time is %lu\n",proc->RU_mask[ru->proc.subframe_rx], t.tv_nsec - proc->t[ru->proc.subframe_rx].tv_nsec);
+  //LOG_I(PHY,"RU mask is now %x, time is %lu\n",proc->RU_mask[ru->proc.tti_rx], t.tv_nsec - proc->t[ru->proc.tti_rx].tv_nsec);
 
   if (proc->RU_mask[ru->proc.tti_rx] == (1<<eNB->num_RU)-1) { // all RUs have provided their information so continue on and wakeup eNB top
     LOG_D(PHY,"ru_mask is %d \n ", proc->RU_mask[ru->proc.tti_rx]);
     LOG_D(PHY,"the number of RU is %d, the current ru is RU %d \n ", (1<<eNB->num_RU)-1, ru->idx);
-    LOG_D(PHY,"ru->proc.subframe_rx is %d \n", ru->proc.tti_rx);
+    LOG_D(PHY,"ru->proc.tti_rx is %d \n", ru->proc.tti_rx);
     LOG_D(PHY,"Resetting mask frame %d, subframe %d, this is RU %d\n", ru->proc.frame_rx, ru->proc.tti_rx, ru->idx);
     proc->RU_mask[ru->proc.tti_rx] = 0;
     VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_MASK_RU, proc->RU_mask[ru->proc.tti_rx]);
     clock_gettime(CLOCK_MONOTONIC,&t);
     //stop_meas(&proc->ru_arrival_time);
-    /*AssertFatal(t.tv_nsec < proc->t[ru->proc.subframe_rx].tv_nsec+5000000, "Time difference for subframe %d (Frame %d) => %lu > 5ms, this is RU %d\n",
-                  ru->proc.subframe_rx, ru->proc.frame_rx, t.tv_nsec - proc->t[ru->proc.subframe_rx].tv_nsec, ru->idx);*/
+    /*AssertFatal(t.tv_nsec < proc->t[ru->proc.tti_rx].tv_nsec+5000000, "Time difference for subframe %d (Frame %d) => %lu > 5ms, this is RU %d\n",
+                  ru->proc.tti_rx, ru->proc.frame_rx, t.tv_nsec - proc->t[ru->proc.tti_rx].tv_nsec, ru->idx);*/
     //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.frame_rx);
-    //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.subframe_rx);
+    //VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_L1S_RU+ru->idx, ru->proc.tti_rx);
     AssertFatal(0==pthread_mutex_unlock(&proc->mutex_RU),"");
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_LOCK_MUTEX_RU+ru->idx, 0 );
     // unlock RUs that are waiting for eNB processing to be completed
@@ -1280,8 +1234,8 @@ void wakeup_L1s(RU_t *ru) {
   }
 
   //      pthread_mutex_unlock(&proc->mutex_RU);
-  //      LOG_D(PHY,"wakeup eNB top for for subframe %d\n", ru->proc.subframe_rx);
-  //      ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string);
+  //      LOG_D(PHY,"wakeup eNB top for for subframe %d\n", ru->proc.tti_rx);
+  //      ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.tti_rx,string);
   ru->proc.emulate_rf_busy = 0;
 }
 
@@ -1350,7 +1304,7 @@ void fill_rf_config(RU_t *ru,
                     char *rf_config_file) {
   LTE_DL_FRAME_PARMS *fp   = ru->frame_parms;
   openair0_config_t *cfg   = &ru->openair0_cfg;
-  //printf("////////////////numerology in config = %d\n",numerology);
+  //LOG_I(PHY,"////////////////numerology in config = %d\n",numerology);
   int numerology = get_softmodem_params()->numerology;
 
   if(fp->N_RB_DL == 100) {
@@ -1377,7 +1331,7 @@ void fill_rf_config(RU_t *ru,
       cfg->tx_bw = 40e6;
       cfg->rx_bw = 40e6;
     } else {
-      printf("Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology);
+      LOG_I(PHY,"Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology);
       cfg->sample_rate=30.72e6;
       cfg->samples_per_frame = 307200;
       cfg->tx_bw = 10e6;
@@ -1416,7 +1370,7 @@ void fill_rf_config(RU_t *ru,
     cfg->tx_gain[i] = (double)ru->att_tx;
     cfg->rx_gain[i] = ru->max_rxgain-(double)ru->att_rx;
     cfg->configFilename = rf_config_file;
-    printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n",
+    LOG_I(PHY,"channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n",
            i, cfg->tx_gain[i],
            cfg->rx_gain[i],
            cfg->tx_freq[i],
@@ -1437,9 +1391,9 @@ int setup_RU_buffers(RU_t *ru) {
 
   if (ru) {
     frame_parms = ru->frame_parms;
-    printf("setup_RU_buffers: frame_parms = %p\n",frame_parms);
+    LOG_I(PHY,"setup_RU_buffers: frame_parms = %p\n",frame_parms);
   } else {
-    printf("RU not initialized (NULL pointer)\n");
+    LOG_I(PHY,"RU not initialized (NULL pointer)\n");
     return(-1);
   }
 
@@ -1462,7 +1416,7 @@ int setup_RU_buffers(RU_t *ru) {
       ru->sf_extension       /= 4;
       ru->end_of_burst_delay /= 4;
     } else {
-      printf("not handled, todo\n");
+      LOG_I(PHY,"not handled, todo\n");
       exit(1);
     }
   } else {
@@ -1476,13 +1430,13 @@ int setup_RU_buffers(RU_t *ru) {
     for (i=0; i<ru->nb_rx; i++) {
       card = i/4;
       ant = i%4;
-      printf("Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
+      LOG_I(PHY,"Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
       free(ru->common.rxdata[i]);
       ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant];
-      printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]);
+      LOG_I(PHY,"rxdata[%d] @ %p\n",i,ru->common.rxdata[i]);
 
       for (j=0; j<16; j++) {
-        printf("rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]);
+        LOG_I(PHY,"rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]);
         ru->common.rxdata[i][j] = 16-j;
       }
     }
@@ -1490,13 +1444,13 @@ int setup_RU_buffers(RU_t *ru) {
     for (i=0; i<ru->nb_tx; i++) {
       card = i/4;
       ant = i%4;
-      printf("Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
+      LOG_I(PHY,"Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
       free(ru->common.txdata[i]);
       ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant];
-      printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]);
+      LOG_I(PHY,"txdata[%d] @ %p\n",i,ru->common.txdata[i]);
 
       for (j=0; j<16; j++) {
-        printf("txbuffer %d: %x\n",j,ru->common.txdata[i][j]);
+        LOG_I(PHY,"txbuffer %d: %x\n",j,ru->common.txdata[i][j]);
         ru->common.txdata[i][j] = 16-j;
       }
     }
@@ -1623,7 +1577,7 @@ static void *ru_thread_tx( void *param ) {
       }
 
       if (eNB_proc->RU_mask_tx != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
-        //printf("Not all RUs have provided their info (mask = %d), RU %d, num_RUs %d\n", eNB_proc->RU_mask_tx,ru->idx,eNB->num_RU);
+        //LOG_I(PHY,"Not all RUs have provided their info (mask = %d), RU %d, num_RUs %d\n", eNB_proc->RU_mask_tx,ru->idx,eNB->num_RU);
         AssertFatal((ret=pthread_mutex_unlock(&eNB_proc->mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret);
       } else { // all RUs TX are finished so send the ready signal to eNB processing
         eNB_proc->RU_mask_tx = 0;
@@ -1644,7 +1598,7 @@ static void *ru_thread_tx( void *param ) {
       }
     }
 
-    //printf("ru_thread_tx: Frame %d, Subframe %d: RU %d done (wait_cnt %d),RU_mask_tx %d\n",
+    //LOG_I(PHY,"ru_thread_tx: Frame %d, Subframe %d: RU %d done (wait_cnt %d),RU_mask_tx %d\n",
     //eNB_proc->frame_rx,eNB_proc->subframe_rx,ru->idx,ru->wait_cnt,eNB_proc->RU_mask_tx);
   }
 
@@ -1676,12 +1630,10 @@ static void *ru_thread( void *param ) {
   LOG_I(PHY,"Starting RU %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]);
 
   if(get_softmodem_params()->emulate_rf) {
-    fill_rf_config(ru,ru->rf_config_file);
-    init_frame_parms(ru->frame_parms,1);
     phy_init_RU(ru);
 
     if (setup_RU_buffers(ru)!=0) {
-      printf("Exiting, cannot initialize RU Buffers\n");
+      LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n");
       exit(-1);
     }
 
@@ -1693,24 +1645,20 @@ static void *ru_thread( void *param ) {
     ru->state = RU_RUN;
   } else if (ru->has_ctrl_prt == 0) {
     // There is no control port: start everything here
-    LOG_I(PHY, "RU %d has not ctrl port\n",ru->idx);
+    LOG_I(PHY, "RU %d has no OAI ctrl port\n",ru->idx);
 
-    if (ru->if_south == LOCAL_RF) {
-      fill_rf_config(ru,ru->rf_config_file);
-      init_frame_parms(ru->frame_parms,1);
-      ru->frame_parms->nb_antennas_rx = ru->nb_rx;
-      phy_init_RU(ru);
-      openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
+    fill_rf_config(ru,ru->rf_config_file);
+    init_frame_parms(ru->frame_parms,1);
+    ru->frame_parms->nb_antennas_rx = ru->nb_rx;
 
-      if (setup_RU_buffers(ru)!=0) {
-        printf("Exiting, cannot initialize RU Buffers\n");
-        exit(-1);
-      }
+    if (ru->if_south == LOCAL_RF)       openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
 
-      AssertFatal((ret=pthread_mutex_lock(&RC.ru_mutex))==0,"mutex_lock returns %d\n",ret);
-      RC.ru_mask &= ~(1<<ru->idx);
-      pthread_cond_signal(&RC.ru_cond);
-      AssertFatal((ret=pthread_mutex_unlock(&RC.ru_mutex))==0,"mutex_unlock returns %d\n",ret);
+    phy_init_RU(ru);
+      
+      
+    if (setup_RU_buffers(ru)!=0) {
+        LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n");
+	      exit(-1);
     }
 
     AssertFatal((ret=pthread_mutex_lock(&RC.ru_mutex))==0,"mutex_lock returns %d\n",ret);
@@ -1745,9 +1693,9 @@ static void *ru_thread( void *param ) {
 
       // Start RF device if any
       if (ru->start_rf) {
-        if (ru->start_rf(ru) != 0)
-          LOG_E(HW,"Could not start the RF device\n");
-        else LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
+	if (ru->start_rf(ru) != 0)
+	  AssertFatal(1==0,"Could not start the RF device\n");
+	else LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
       } else LOG_D(PHY,"RU %d no rf device\n",ru->idx);
     }
 
@@ -1781,7 +1729,6 @@ static void *ru_thread( void *param ) {
       // synchronization on input FH interface, acquire signals/data and block
       if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&subframe);
       else AssertFatal(1==0, "No fronthaul interface at south port");
-
 #ifdef PHY_TX_THREAD
 
       if(first_phy_tx == 0) {
@@ -1945,7 +1892,7 @@ static void *ru_thread( void *param ) {
     } // ru->state = RU_RUN
   } // while !oai_exit
 
-  printf( "Exiting ru_thread \n");
+  LOG_I(PHY, "Exiting ru_thread \n");
 
   if (!(get_softmodem_params()->emulate_rf)) {
     if (ru->stop_rf != NULL) {
@@ -2190,6 +2137,12 @@ static void *rf_tx( void *param ) {
 #endif
 
 
+
+int start_streaming(RU_t *ru) {
+  LOG_I(PHY,"Starting streaming on third-party RRU\n");
+  return(ru->ifdevice.thirdparty_startstreaming(&ru->ifdevice));
+}
+
 int start_if(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB) {
   return(ru->ifdevice.trx_start_func(&ru->ifdevice));
 }
@@ -2235,7 +2188,7 @@ void reset_proc(RU_t *ru) {
 
 
 void init_RU_proc(RU_t *ru) {
-  int i=0, ret;
+  int i=0;
   RU_proc_t *proc;
   pthread_attr_t *attr_FH=NULL, *attr_FH1=NULL, *attr_prach=NULL, *attr_asynch=NULL, *attr_synch=NULL, *attr_emulateRF=NULL, *attr_ctrl=NULL, *attr_prach_br=NULL;
   //pthread_attr_t *attr_fep=NULL;
@@ -2304,7 +2257,17 @@ void init_RU_proc(RU_t *ru) {
   attr_prach_br  = &proc->attr_prach_br;
 #endif
 
-  if (ru->function!=eNodeB_3GPP) pthread_create( &proc->pthread_ctrl, attr_ctrl, ru_thread_control, (void *)ru );
+  if (ru->has_ctrl_prt == 1) pthread_create( &proc->pthread_ctrl, attr_ctrl, ru_thread_control, (void*)ru );
+  else {
+    if (ru->start_if) {
+      LOG_I(PHY,"Starting IF interface for RU %d\n",ru->idx);
+      AssertFatal(
+                  ru->start_if(ru,NULL)   == 0, "Could not start the IF device\n");
+
+      if (ru->if_south != LOCAL_RF) wait_eNBs();
+    }
+  }
+
 
   pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void *)ru );
 #if defined(PRE_SCD_THREAD)
@@ -2343,23 +2306,6 @@ void init_RU_proc(RU_t *ru) {
     LOG_I(PHY,"%s() DJP - added creation of pthread_prach\n", __FUNCTION__);
     pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void *)ru );
     ru->state=RU_RUN;
-    if(!get_softmodem_params()->emulate_rf)
-    {
-      fill_rf_config(ru,ru->rf_config_file);
-      init_frame_parms(ru->frame_parms,1);
-      ru->frame_parms->nb_antennas_rx = ru->nb_rx;
-      phy_init_RU(ru);
-      ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
-      if (ret < 0) {
-         LOG_I(PHY,"Exiting, cannot load device. Make sure that your SDR board is connected!\n");
-         exit(1);
-      }
-
-      if (setup_RU_buffers(ru)!=0) {
-        LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n");
-        exit(1);
-      }
-    }
   }
 
   if (get_thread_worker_conf() == WORKER_ENABLE) {
@@ -2368,7 +2314,7 @@ void init_RU_proc(RU_t *ru) {
   }
 
   if (opp_enabled == 1) pthread_create(&ru->ru_stats_thread,NULL,ru_stats_thread,(void *)ru);
-
+/*
   if (ru->function == eNodeB_3GPP) {
     usleep(10000);
     LOG_I(PHY, "Signaling main thread that RU %d (is_slave %d,send_dmrs %d) is ready in state %s\n",ru->idx,ru->is_slave,ru->generate_dmrs_sync,ru_states[ru->state]);
@@ -2377,6 +2323,7 @@ void init_RU_proc(RU_t *ru) {
     pthread_cond_signal(&RC.ru_cond);
     AssertFatal((ret=pthread_mutex_unlock(&RC.ru_mutex))==0,"mutex_unlock returns %d\n",ret);
   }
+  */
 }
 
 
@@ -2539,6 +2486,7 @@ void init_precoding_weights(PHY_VARS_eNB *eNB) {
 void set_function_spec_param(RU_t *ru) {
   int ret;
 
+
   switch (ru->if_south) {
     case LOCAL_RF:   // this is an RU with integrated RF (RRU, eNB)
       if (ru->function ==  NGFI_RRU_IF5) {                 // IF5 RRU
@@ -2559,10 +2507,10 @@ void set_function_spec_param(RU_t *ru) {
         reset_meas(&ru->compression);
         reset_meas(&ru->transport);
         ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
-        printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
+        LOG_I(PHY,"NGFI_RRU_IF5: openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
 
         if (ret<0) {
-          printf("Exiting, cannot initialize transport protocol\n");
+          LOG_I(PHY,"Exiting, cannot initialize transport protocol\n");
           exit(-1);
         }
       } else if (ru->function == NGFI_RRU_IF4p5) {
@@ -2583,10 +2531,10 @@ void set_function_spec_param(RU_t *ru) {
         reset_meas(&ru->compression);
         reset_meas(&ru->transport);
         ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
-        printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
+        LOG_I(PHY,"NGFI_RRU_if4p5 : openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
 
         if (ret<0) {
-          printf("Exiting, cannot initialize transport protocol\n");
+          LOG_I(PHY,"Exiting, cannot initialize transport protocol\n");
           exit(-1);
         }
 
@@ -2606,7 +2554,7 @@ void set_function_spec_param(RU_t *ru) {
       ru->fh_south_out           = tx_rf;                               // local synchronous RF TX
       ru->start_rf               = start_rf;                            // need to start the local RF interface
       ru->stop_rf                = stop_rf;
-      printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf);
+      LOG_I(PHY,"NFGI_RRU_IF4p5: configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf);
       /*
         if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise
         fill_rf_config(ru,rf_config_file);
@@ -2616,7 +2564,7 @@ void set_function_spec_param(RU_t *ru) {
 
         ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
         if (setup_RU_buffers(ru)!=0) {
-        printf("Exiting, cannot initialize RU Buffers\n");
+        LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n");
         exit(-1);
         }*/
       break;
@@ -2629,25 +2577,22 @@ void set_function_spec_param(RU_t *ru) {
 
       if (ru->if_timing == synch_to_other) {
         ru->fh_south_in          = fh_slave_south_in;                  // synchronize to master
-        ru->fh_south_out         = fh_if5_mobipass_south_out;          // use send_IF5 for mobipass
-        ru->fh_south_asynch_in   = fh_if5_south_asynch_in_mobipass;    // UL is asynchronous
       } else {
         ru->fh_south_in          = fh_if5_south_in;     // synchronous IF5 reception
         ru->fh_south_out         = fh_if5_south_out;    // synchronous IF5 transmission
         ru->fh_south_asynch_in   = NULL;                // no asynchronous UL
       }
-
-      ru->start_rf               = NULL;                 // no local RF
+      ru->start_rf               = ru->eth_params.transp_preference == ETH_UDP_IF5_ECPRI_MODE ? start_streaming : NULL;
       ru->stop_rf                = NULL;
       ru->start_if               = start_if;             // need to start if interface for IF5
       ru->ifdevice.host_type     = RAU_HOST;
       ru->ifdevice.eth_params    = &ru->eth_params;
       ru->ifdevice.configure_rru = configure_ru;
       ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
-      printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
+      LOG_I(PHY,"REMOTE_IF5: openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
 
       if (ret<0) {
-        printf("Exiting, cannot initialize transport protocol\n");
+        LOG_I(PHY,"Exiting, cannot initialize transport protocol\n");
         exit(-1);
       }
 
@@ -2670,10 +2615,10 @@ void set_function_spec_param(RU_t *ru) {
       ru->ifdevice.eth_params    = &ru->eth_params;
       ru->ifdevice.configure_rru = configure_ru;
       ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
-      printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
+      LOG_I(PHY,"REMOTE IF4p5: openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
 
       if (ret<0) {
-        printf("Exiting, cannot initialize transport protocol\n");
+        LOG_I(PHY,"Exiting, cannot initialize transport protocol\n");
         exit(-1);
       }
 
@@ -2687,12 +2632,14 @@ void set_function_spec_param(RU_t *ru) {
       }
 
       malloc_IF4p5_buffer(ru);
+
       break;
 
     default:
       LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south);
       break;
   } // switch on interface type
+
 }
 
 //extern void RCconfig_RU(void);
@@ -2782,6 +2729,11 @@ void init_RU(char *rf_config_file, int send_dmrssync) {
 
     LOG_I(PHY, "Initializing RRU descriptor %d : (%s,%s,%d)\n", ru_id, ru_if_types[ru->if_south], NB_timing[ru->if_timing], ru->function);
     set_function_spec_param(ru);
+    if (ru->function != NGFI_RRU_IF4p5 && ru->function != NGFI_RRU_IF5) {
+       fill_rf_config(ru,ru->rf_config_file);
+       init_frame_parms(ru->frame_parms,1);
+    }
+
     LOG_I(PHY, "Starting ru_thread %d, is_slave %d, send_dmrs %d\n", ru_id, ru->is_slave, ru->generate_dmrs_sync);
     init_RU_proc(ru);
   } // for ru_id
@@ -2795,7 +2747,7 @@ void stop_ru(RU_t *ru) {
 #if defined(PRE_SCD_THREAD) || defined(PHY_TX_THREAD)
   int *status;
 #endif
-  printf("Stopping RU %p processing threads\n",(void *)ru);
+  LOG_I(PHY,"Stopping RU %p processing threads\n",(void *)ru);
 #if defined(PRE_SCD_THREAD)
 
   if(ru) {
@@ -2849,7 +2801,7 @@ void init_ru_vnf(void) {
   pthread_mutex_init(&RC.ru_mutex,NULL);
   pthread_cond_init(&RC.ru_cond,NULL);
   // read in configuration file)
-  printf("configuring RU from file\n");
+  LOG_I(PHY,"configuring RU from file\n");
   RCconfig_RU();
   LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs());
 
@@ -2939,7 +2891,7 @@ void RCconfig_RU(void) {
       RC.ru[j]                                    = (RU_t *)malloc(sizeof(RU_t));
       memset((void *)RC.ru[j],0,sizeof(RU_t));
       RC.ru[j]->idx                                 = j;
-      printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]);
+      LOG_I(PHY,"Creating RC.ru[%d]:%p\n", j, RC.ru[j]);
       RC.ru[j]->if_timing                           = synch_to_ext_device;
 
       if (RC.nb_L1_inst >0)
@@ -2949,7 +2901,7 @@ void RCconfig_RU(void) {
 
       for (i=0; i<RC.ru[j]->num_eNB; i++) RC.ru[j]->eNB_list[i] = RC.eNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0];
 
-      RC.ru[j]->has_ctrl_prt                        = 1;
+      RC.ru[j]->has_ctrl_prt                        = 0;
 
       if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) {
         RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr));
@@ -2996,7 +2948,7 @@ void RCconfig_RU(void) {
           RC.ru[j]->if_south                        = LOCAL_RF;
           RC.ru[j]->function                        = eNodeB_3GPP;
           RC.ru[j]->state                           = RU_RUN;
-          printf("Setting function for RU %d to eNodeB_3GPP\n",j);
+          LOG_I(PHY,"Setting function for RU %d to eNodeB_3GPP\n",j);
         } else {
           RC.ru[j]->eth_params.local_if_name            = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));
           RC.ru[j]->eth_params.my_addr                  = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr));
@@ -3006,42 +2958,43 @@ void RCconfig_RU(void) {
 
           // Check if control port set
           if  (!(config_isparamset(RUParamList.paramarray[j],RU_REMOTE_PORTC_IDX)) ) {
-            printf("Removing control port for RU %d\n",j);
+            LOG_I(PHY,"Removing control port for RU %d\n",j);
             RC.ru[j]->has_ctrl_prt            = 0;
           } else {
             RC.ru[j]->eth_params.my_portc                 = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr);
             RC.ru[j]->eth_params.remote_portc             = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
-            printf(" Control port %u \n",RC.ru[j]->eth_params.my_portc);
+            LOG_I(PHY," Control port %u \n",RC.ru[j]->eth_params.my_portc);
           }
 
           if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) {
             RC.ru[j]->if_south                        = LOCAL_RF;
             RC.ru[j]->function                        = NGFI_RRU_IF5;
             RC.ru[j]->eth_params.transp_preference    = ETH_UDP_MODE;
-            printf("Setting function for RU %d to NGFI_RRU_IF5 (udp)\n",j);
+            LOG_I(PHY,"Setting function for RU %d to NGFI_RRU_IF5 (udp)\n",j);
           } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) {
             RC.ru[j]->if_south                        = LOCAL_RF;
             RC.ru[j]->function                        = NGFI_RRU_IF5;
             RC.ru[j]->eth_params.transp_preference    = ETH_RAW_MODE;
-            printf("Setting function for RU %d to NGFI_RRU_IF5 (raw)\n",j);
+            LOG_I(PHY,"Setting function for RU %d to NGFI_RRU_IF5 (raw)\n",j);
           } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) {
             RC.ru[j]->if_south                        = LOCAL_RF;
             RC.ru[j]->function                        = NGFI_RRU_IF4p5;
             RC.ru[j]->eth_params.transp_preference    = ETH_UDP_IF4p5_MODE;
-            printf("Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n",j);
+            RC.ru[j]->has_ctrl_prt                   =1;
+            LOG_I(PHY,"Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n",j);
           } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) {
             RC.ru[j]->if_south                        = LOCAL_RF;
             RC.ru[j]->function                        = NGFI_RRU_IF4p5;
             RC.ru[j]->eth_params.transp_preference    = ETH_RAW_IF4p5_MODE;
-            printf("Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j);
+            LOG_I(PHY,"Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j);
           }
 
-          printf("RU %d is_slave=%s\n",j,*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr));
+          LOG_I(PHY,"RU %d is_slave=%s\n",j,*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr));
 
           if (strcmp(*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr), "yes") == 0) RC.ru[j]->is_slave=1;
           else RC.ru[j]->is_slave=0;
 
-          printf("RU %d ota_sync_enabled=%s\n",j,*(RUParamList.paramarray[j][RU_OTA_SYNC_ENABLE_IDX].strptr));
+          LOG_I(PHY,"RU %d ota_sync_enabled=%s\n",j,*(RUParamList.paramarray[j][RU_OTA_SYNC_ENABLE_IDX].strptr));
 
           if (strcmp(*(RUParamList.paramarray[j][RU_OTA_SYNC_ENABLE_IDX].strptr), "yes") == 0) RC.ru[j]->ota_sync_enable=1;
           else RC.ru[j]->ota_sync_enable=0;
@@ -3055,8 +3008,8 @@ void RCconfig_RU(void) {
 
         for (i=0; i<RC.ru[j]->num_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i];
       } //strcmp(local_rf, "yes") == 0
-      else {
-        printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr));
+else {
+        LOG_I(PHY,"RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr));
         RC.ru[j]->eth_params.local_if_name      = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));
         RC.ru[j]->eth_params.my_addr            = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr));
         RC.ru[j]->eth_params.remote_addr        = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr));
@@ -3064,34 +3017,34 @@ void RCconfig_RU(void) {
         RC.ru[j]->eth_params.remote_portc       = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
         RC.ru[j]->eth_params.my_portd           = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr);
         RC.ru[j]->eth_params.remote_portd       = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr);
-
+      
         if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) {
-          RC.ru[j]->if_south                     = REMOTE_IF5;
-          RC.ru[j]->function                     = NGFI_RAU_IF5;
-          RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE;
+	  RC.ru[j]->if_south                     = REMOTE_IF5;
+	  RC.ru[j]->function                     = NGFI_RAU_IF5;
+	  RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE;
+        } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_ecpri_if5") == 0) {
+	  RC.ru[j]->if_south                     = REMOTE_IF5;
+	  RC.ru[j]->function                     = NGFI_RAU_IF5;
+	  RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF5_ECPRI_MODE;
         } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) {
-          RC.ru[j]->if_south                     = REMOTE_IF5;
-          RC.ru[j]->function                     = NGFI_RAU_IF5;
-          RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE;
+	  RC.ru[j]->if_south                     = REMOTE_IF5;
+	  RC.ru[j]->function                     = NGFI_RAU_IF5;
+	  RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE;
         } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) {
-          RC.ru[j]->if_south                     = REMOTE_IF4p5;
-          RC.ru[j]->function                     = NGFI_RAU_IF4p5;
-          RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
+	  RC.ru[j]->if_south                     = REMOTE_IF4p5;
+	  RC.ru[j]->function                     = NGFI_RAU_IF4p5;
+  	  RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
+	  RC.ru[j]->has_ctrl_prt                 = 1;
         } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) {
-          RC.ru[j]->if_south                     = REMOTE_IF4p5;
-          RC.ru[j]->function                     = NGFI_RAU_IF4p5;
-          RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
-        } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if5_mobipass") == 0) {
-          RC.ru[j]->if_south                     = REMOTE_IF5;
-          RC.ru[j]->function                     = NGFI_RAU_IF5;
-          RC.ru[j]->if_timing                    = synch_to_other;
-          RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF5_MOBIPASS;
+	  RC.ru[j]->if_south                     = REMOTE_IF4p5;
+	  RC.ru[j]->function                     = NGFI_RAU_IF4p5;
+	  RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
+	
+          if (strcmp(*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr), "yes") == 0) RC.ru[j]->is_slave=1;
+          else RC.ru[j]->is_slave=0;
         }
-
-        if (strcmp(*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr), "yes") == 0) RC.ru[j]->is_slave=1;
-        else RC.ru[j]->is_slave=0;
       }  /* strcmp(local_rf, "yes") != 0 */
-
+      
       RC.ru[j]->nb_tx                             = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr);
       RC.ru[j]->nb_rx                             = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr);
       RC.ru[j]->att_tx                            = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr);
diff --git a/targets/RT/USER/rcc_if5.gtkw b/targets/RT/USER/rcc_if5.gtkw
index d64a9ca0fb2e0352c5f9f7a584ad2225cd140249..34c6bab5d13b26fb44e8ff1b0a0173ae88577d33 100644
--- a/targets/RT/USER/rcc_if5.gtkw
+++ b/targets/RT/USER/rcc_if5.gtkw
@@ -1,41 +1,67 @@
 [*]
-[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI
-[*] Sun Jul 31 13:30:42 2016
+[*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI
+[*] Tue Sep 24 06:59:08 2019
 [*]
 [dumpfile] "/tmp/openair_dump_eNB.vcd"
-[dumpfile_mtime] "Sun Jul 31 13:21:59 2016"
-[dumpfile_size] 18273240
-[savefile] "/home/fourmi/openairinterface5g/targets/RT/USER/rcc_if5.gtkw"
-[timestart] 24070893000
-[size] 1301 716
-[pos] 309 0
-*-19.793451 29026062100 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-[sst_width] 284
-[signals_width] 262
+[dumpfile_mtime] "Mon Sep 23 20:04:56 2019"
+[dumpfile_size] 1625759
+[savefile] "/home/orange/aw2s/openairinterface5g/targets/RT/USER/rcc_if5.gtkw"
+[timestart] 12600104000
+[size] 1215 1000
+[pos] 0 22
+*-19.506693 12600920638 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[sst_width] 386
+[signals_width] 344
 [sst_expanded] 1
-[sst_vpaned_height] 294
+[sst_vpaned_height] 303
+@29
+functions.send_if5
+@28
+functions.recv_if5
 @24
 variables.trx_ts[63:0]
 variables.trx_tst[63:0]
 @28
-functions.send_if5
-functions.recv_if5
 functions.eNB_thread_rxtx0
 @24
+variables.frame_number_RX0_RU[63:0]
+variables.subframe_number_RX0_RU[63:0]
+variables.frame_number_TX0_RU[63:0]
+variables.subframe_number_TX0_RU[63:0]
+@28
+functions.mac_schedule_dlsch
+functions.macxface_eNB_dlsch_ulsch_scheduler
+functions.macxface_ue_scheduler
+functions.phy_eNB_ofdm_mod_l
+@24
 variables.frame_number_RX0_eNB[63:0]
 variables.subframe_number_RX0_eNB[63:0]
 variables.frame_number_TX0_eNB[63:0]
 variables.subframe_number_TX0_eNB[63:0]
-@28
-functions.eNB_thread_rxtx1
-@24
 variables.frame_number_RX1_eNB[63:0]
 variables.subframe_number_RX1_eNB[63:0]
 variables.frame_number_TX1_eNB[63:0]
 variables.subframe_number_TX1_eNB[63:0]
 @28
+functions.phy_eNB_dlsch_modulation
+functions.phy_eNB_dlsch_encoding
+functions.phy_eNB_dlsch_scrambling
+functions.phy_eNB_beam_precoding
+functions.phy_enb_pdcch_tx
+functions.phy_enb_prach_rx
+functions.phy_procedures_ru_feprx0
+functions.phy_procedures_eNb_rx_uespec0
+functions.phy_procedures_eNb_rx_uespec1
+functions.phy_enb_sfgen
+functions.phy_procedures_eNb_tx0
+functions.phy_procedures_eNb_tx1
+functions.phy_procedures_ru_feprx1
+functions.phy_procedures_ru_feptx_ofdm0
+functions.phy_procedures_ru_feptx_ofdm1
+functions.phy_procedures_ru_feptx_prec0
+functions.phy_procedures_ru_feptx_prec1
+functions.eNB_thread_rxtx1
 functions.phy_enb_sfgen
-functions.phy_eNB_slot_fep
 functions.phy_enb_prach_rx
 @24
 variables.dci_info[63:0]
diff --git a/targets/RT/USER/ru_control.c b/targets/RT/USER/ru_control.c
index 6daf0f4dfac678a831fcfa0d08c7e7545eab5720..7ac6a8913ef3be0d7eea86a16993aa0126a55617 100644
--- a/targets/RT/USER/ru_control.c
+++ b/targets/RT/USER/ru_control.c
@@ -524,7 +524,7 @@ void* ru_thread_control( void* param )
   }
 
   
-  ru->state = (ru->function==eNodeB_3GPP)? RU_RUN : RU_IDLE;
+  ru->state = (ru->function==eNodeB_3GPP || ru->if_south == REMOTE_IF5)? RU_RUN : RU_IDLE;
   LOG_I(PHY,"Control channel ON for RU %d\n", ru->idx);
 
   while (!oai_exit) // Change the cond