diff --git a/charts/physims/Chart.yaml b/charts/physims/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..bef28aac2759f35d9e8a1963fb93450f4c4c2d61
--- /dev/null
+++ b/charts/physims/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-physim
+description: A Helm chart for physical simulators network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulators
+  - RAN
+  - 4G
+  - 5G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/dlsim/Chart.yaml b/charts/physims/charts/dlsim/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..de7f5958b2f967d70adeeca94e171a50775a31b8
--- /dev/null
+++ b/charts/physims/charts/dlsim/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-dlsim
+description: A Helm subchart for dlsim network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - dlsim
+  - RAN
+  - 4G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/dlsim/templates/NOTES.txt b/charts/physims/charts/dlsim/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..75b79e3dd4d4a30be484fb6ff6b980eef9f56f22
--- /dev/null
+++ b/charts/physims/charts/dlsim/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-dlsim.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-dlsim.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-dlsim.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-dlsim.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/dlsim/templates/_helpers.tpl b/charts/physims/charts/dlsim/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..7ae142b6719dca78536d59d81d459dcf8c353a1c
--- /dev/null
+++ b/charts/physims/charts/dlsim/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-dlsim.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-dlsim.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-dlsim.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-dlsim.labels" -}}
+helm.sh/chart: {{ include "oai-dlsim.chart" . }}
+{{ include "oai-dlsim.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-dlsim.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-dlsim.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-dlsim.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-dlsim.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/dlsim/templates/deployment.yaml b/charts/physims/charts/dlsim/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9cbdd383b35dcc1f19e7a0c02ccd6db658dda2ea
--- /dev/null
+++ b/charts/physims/charts/dlsim/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-dlsim.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-dlsim.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-dlsim.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-dlsim
+        # volumeMounts:
+        # - mountPath: /opt/oai-dlsim/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015100" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/dlsim/templates/service.yaml b/charts/physims/charts/dlsim/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6aeb0dbf530981d9c209cdb7f766d00f1267cd23
--- /dev/null
+++ b/charts/physims/charts/dlsim/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-dlsim.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-dlsim
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-dlsim.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/dlsim/values.yaml b/charts/physims/charts/dlsim/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c0142b50ae1704d9a0717c47891fb9f090549991
--- /dev/null
+++ b/charts/physims/charts/dlsim/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-dlsim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-dlsim-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/ldpctest/Chart.yaml b/charts/physims/charts/ldpctest/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..667bd3d8aa196ea9af9938a77e3f399c43016898
--- /dev/null
+++ b/charts/physims/charts/ldpctest/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-ldpctest
+description: A Helm subchart for ldpctest network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - ldpctest
+  - RAN
+  - 5G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/ldpctest/templates/NOTES.txt b/charts/physims/charts/ldpctest/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bda83c2f9e732b8affd1131d0f33724ed3f0cd87
--- /dev/null
+++ b/charts/physims/charts/ldpctest/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-ldpctest.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-ldpctest.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-ldpctest.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-ldpctest.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/ldpctest/templates/_helpers.tpl b/charts/physims/charts/ldpctest/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..018eaa5af5d6cd42c95f2d88fe2680b2f054b2c3
--- /dev/null
+++ b/charts/physims/charts/ldpctest/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-ldpctest.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-ldpctest.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-ldpctest.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-ldpctest.labels" -}}
+helm.sh/chart: {{ include "oai-ldpctest.chart" . }}
+{{ include "oai-ldpctest.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-ldpctest.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-ldpctest.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-ldpctest.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-ldpctest.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/ldpctest/templates/deployment.yaml b/charts/physims/charts/ldpctest/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ef30d9c08ad335dc4611d5798ae3edac560dbac6
--- /dev/null
+++ b/charts/physims/charts/ldpctest/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-ldpctest.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-ldpctest.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-ldpctest.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-ldpctest
+        # volumeMounts:
+        # - mountPath: /opt/oai-ldpctest/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015102" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/ldpctest/templates/service.yaml b/charts/physims/charts/ldpctest/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..eb0db8ce00678d5d2610d8c765aa7231c74434eb
--- /dev/null
+++ b/charts/physims/charts/ldpctest/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-ldpctest.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-ldpctest
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-ldpctest.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/ldpctest/values.yaml b/charts/physims/charts/ldpctest/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..91eab91af5418bd248a169d9e8d677a2852f866b
--- /dev/null
+++ b/charts/physims/charts/ldpctest/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-ldpctest.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-ldpctest-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/nr-dlschsim/Chart.yaml b/charts/physims/charts/nr-dlschsim/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3837f0cd2ba60ccccfcfaeaa4764250d85dea995
--- /dev/null
+++ b/charts/physims/charts/nr-dlschsim/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-nr-dlschsim
+description: A Helm subchart for nr-dlschsim network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - nr-dlschsim
+  - RAN
+  - 5G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/nr-dlschsim/templates/NOTES.txt b/charts/physims/charts/nr-dlschsim/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1f88d6497664fd9d3d18ad1504526673fce16077
--- /dev/null
+++ b/charts/physims/charts/nr-dlschsim/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-nr-dlschsim.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-nr-dlschsim.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-nr-dlschsim.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-nr-dlschsim.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/nr-dlschsim/templates/_helpers.tpl b/charts/physims/charts/nr-dlschsim/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..6b6a5181e9da5557644dad51cc22303922457235
--- /dev/null
+++ b/charts/physims/charts/nr-dlschsim/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-nr-dlschsim.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-nr-dlschsim.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-nr-dlschsim.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-nr-dlschsim.labels" -}}
+helm.sh/chart: {{ include "oai-nr-dlschsim.chart" . }}
+{{ include "oai-nr-dlschsim.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-nr-dlschsim.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-nr-dlschsim.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-nr-dlschsim.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-nr-dlschsim.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/nr-dlschsim/templates/deployment.yaml b/charts/physims/charts/nr-dlschsim/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..06f01a0f0baeaa38a61bc85a0d6878302becb578
--- /dev/null
+++ b/charts/physims/charts/nr-dlschsim/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-dlschsim.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-nr-dlschsim.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-nr-dlschsim.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-nr-dlschsim
+        # volumeMounts:
+        # - mountPath: /opt/oai-nr-dlschsim/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015106" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/nr-dlschsim/templates/service.yaml b/charts/physims/charts/nr-dlschsim/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0dd065c9e0a3d24cf5d499f3f0cc3f28b95f0391
--- /dev/null
+++ b/charts/physims/charts/nr-dlschsim/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-dlschsim.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-nr-dlschsim
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-nr-dlschsim.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/nr-dlschsim/values.yaml b/charts/physims/charts/nr-dlschsim/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e96541102c4f30792350ec3a8aeacc9808bfe6e1
--- /dev/null
+++ b/charts/physims/charts/nr-dlschsim/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-nr-dlschsim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-nr-dlschsim-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/nr-dlsim/Chart.yaml b/charts/physims/charts/nr-dlsim/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2ec4b7eabdfbb97e2dbc71428c500f7ee42cc4e4
--- /dev/null
+++ b/charts/physims/charts/nr-dlsim/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-nr-dlsim
+description: A Helm subchart for nr-dlsim network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - nr-dlsim
+  - RAN
+  - 5G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/nr-dlsim/templates/NOTES.txt b/charts/physims/charts/nr-dlsim/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..79027454cfbd9411a7cc6722e4e2fbe05beb039a
--- /dev/null
+++ b/charts/physims/charts/nr-dlsim/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-nr-dlsim.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-nr-dlsim.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-nr-dlsim.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-nr-dlsim.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/nr-dlsim/templates/_helpers.tpl b/charts/physims/charts/nr-dlsim/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..1dd7fbd3fd5a7addca9d7969c9589a1b9d7e6302
--- /dev/null
+++ b/charts/physims/charts/nr-dlsim/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-nr-dlsim.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-nr-dlsim.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-nr-dlsim.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-nr-dlsim.labels" -}}
+helm.sh/chart: {{ include "oai-nr-dlsim.chart" . }}
+{{ include "oai-nr-dlsim.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-nr-dlsim.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-nr-dlsim.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-nr-dlsim.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-nr-dlsim.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/nr-dlsim/templates/deployment.yaml b/charts/physims/charts/nr-dlsim/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4c38664e61b14c8a473f1193b5686725a93089bc
--- /dev/null
+++ b/charts/physims/charts/nr-dlsim/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-dlsim.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-nr-dlsim.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-nr-dlsim.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-nr-dlsim
+        # volumeMounts:
+        # - mountPath: /opt/oai-nr-dlsim/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015105" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/nr-dlsim/templates/service.yaml b/charts/physims/charts/nr-dlsim/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c58433f3b26f6a0a0b3c35620de392426c07381e
--- /dev/null
+++ b/charts/physims/charts/nr-dlsim/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-dlsim.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-nr-dlsim
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-nr-dlsim.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/nr-dlsim/values.yaml b/charts/physims/charts/nr-dlsim/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c86fc96cff29c8b9b3cf83594aaa58711c4f0650
--- /dev/null
+++ b/charts/physims/charts/nr-dlsim/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-nr-dlsim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-nr-dlsim-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/nr-pbchsim/Chart.yaml b/charts/physims/charts/nr-pbchsim/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6d8359598d5f7ed1d155793817d8b7c408a9fa6a
--- /dev/null
+++ b/charts/physims/charts/nr-pbchsim/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-nr-pbchsim
+description: A Helm subchart for nr-pbchsim network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - nr-pbchsim
+  - RAN
+  - 5G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/nr-pbchsim/templates/NOTES.txt b/charts/physims/charts/nr-pbchsim/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cee233d4f36c3380af3a4cb42af3b3b500243619
--- /dev/null
+++ b/charts/physims/charts/nr-pbchsim/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-nr-pbchsim.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-nr-pbchsim.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-nr-pbchsim.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-nr-pbchsim.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/nr-pbchsim/templates/_helpers.tpl b/charts/physims/charts/nr-pbchsim/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..0e3103334384493a08e2c883f1cd9964fa1f400a
--- /dev/null
+++ b/charts/physims/charts/nr-pbchsim/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-nr-pbchsim.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-nr-pbchsim.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-nr-pbchsim.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-nr-pbchsim.labels" -}}
+helm.sh/chart: {{ include "oai-nr-pbchsim.chart" . }}
+{{ include "oai-nr-pbchsim.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-nr-pbchsim.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-nr-pbchsim.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-nr-pbchsim.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-nr-pbchsim.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/nr-pbchsim/templates/deployment.yaml b/charts/physims/charts/nr-pbchsim/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..551785abc0ddf08998599cef769a34ccc09f93f4
--- /dev/null
+++ b/charts/physims/charts/nr-pbchsim/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-pbchsim.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-nr-pbchsim.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-nr-pbchsim.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-nr-pbchsim
+        # volumeMounts:
+        # - mountPath: /opt/oai-nr-pbchsim/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015104" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/nr-pbchsim/templates/service.yaml b/charts/physims/charts/nr-pbchsim/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..35faf3c33dae49955f814387c99a9c31c46871d2
--- /dev/null
+++ b/charts/physims/charts/nr-pbchsim/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-pbchsim.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-nr-pbchsim
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-nr-pbchsim.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/nr-pbchsim/values.yaml b/charts/physims/charts/nr-pbchsim/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..62d89f9632c286708ff45fbc99ae387e66f753b3
--- /dev/null
+++ b/charts/physims/charts/nr-pbchsim/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-nr-pbchsim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-nr-pbchsim-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/nr-prachsim/Chart.yaml b/charts/physims/charts/nr-prachsim/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8c88587a7fd999914a6a4be755e56bf6e9136cde
--- /dev/null
+++ b/charts/physims/charts/nr-prachsim/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-nr-prachsim
+description: A Helm subchart for nr-prachsim network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - nr-prachsim
+  - RAN
+  - 5G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/nr-prachsim/templates/NOTES.txt b/charts/physims/charts/nr-prachsim/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..376694e7e464ee2fe5996d0982e993485947ac55
--- /dev/null
+++ b/charts/physims/charts/nr-prachsim/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-nr-prachsim.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-nr-prachsim.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-nr-prachsim.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-nr-prachsim.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/nr-prachsim/templates/_helpers.tpl b/charts/physims/charts/nr-prachsim/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..6362c72b2a6e89a79257a0d8f2b91caa84970ac9
--- /dev/null
+++ b/charts/physims/charts/nr-prachsim/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-nr-prachsim.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-nr-prachsim.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-nr-prachsim.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-nr-prachsim.labels" -}}
+helm.sh/chart: {{ include "oai-nr-prachsim.chart" . }}
+{{ include "oai-nr-prachsim.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-nr-prachsim.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-nr-prachsim.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-nr-prachsim.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-nr-prachsim.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/nr-prachsim/templates/deployment.yaml b/charts/physims/charts/nr-prachsim/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..52bc030c4591ba8ed74d424021cd91406087c5de
--- /dev/null
+++ b/charts/physims/charts/nr-prachsim/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-prachsim.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-nr-prachsim.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-nr-prachsim.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-nr-prachsim
+        # volumeMounts:
+        # - mountPath: /opt/oai-nr-prachsim/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015112" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/nr-prachsim/templates/service.yaml b/charts/physims/charts/nr-prachsim/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..71bfe7b9feb524cf1ba1542b13d28ec93fa915c4
--- /dev/null
+++ b/charts/physims/charts/nr-prachsim/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-prachsim.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-nr-prachsim
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-nr-prachsim.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/nr-prachsim/values.yaml b/charts/physims/charts/nr-prachsim/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3ea9787f7ab5cf660cfd98e7e61adddb1aa9b47e
--- /dev/null
+++ b/charts/physims/charts/nr-prachsim/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-nr-prachsim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-nr-prachsim-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/nr-pucchsim/Chart.yaml b/charts/physims/charts/nr-pucchsim/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..bb0033175f43bd73dd46f8474f19acd12e1b895d
--- /dev/null
+++ b/charts/physims/charts/nr-pucchsim/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-nr-pucchsim
+description: A Helm subchart for nr-pucchsim network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - nr-pucchsim
+  - RAN
+  - 5G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/nr-pucchsim/templates/NOTES.txt b/charts/physims/charts/nr-pucchsim/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7c2cfa9155eff91c08bfeec4eb14b36c7f49cde4
--- /dev/null
+++ b/charts/physims/charts/nr-pucchsim/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-nr-pucchsim.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-nr-pucchsim.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-nr-pucchsim.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-nr-pucchsim.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/nr-pucchsim/templates/_helpers.tpl b/charts/physims/charts/nr-pucchsim/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..210ba26db2f3e7e6aa07b36563c26792de3d5082
--- /dev/null
+++ b/charts/physims/charts/nr-pucchsim/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-nr-pucchsim.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-nr-pucchsim.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-nr-pucchsim.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-nr-pucchsim.labels" -}}
+helm.sh/chart: {{ include "oai-nr-pucchsim.chart" . }}
+{{ include "oai-nr-pucchsim.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-nr-pucchsim.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-nr-pucchsim.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-nr-pucchsim.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-nr-pucchsim.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/nr-pucchsim/templates/deployment.yaml b/charts/physims/charts/nr-pucchsim/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d783991e0b4a3f572b82ca2665c8443cd4465dde
--- /dev/null
+++ b/charts/physims/charts/nr-pucchsim/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-pucchsim.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-nr-pucchsim.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-nr-pucchsim.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-nr-pucchsim
+        # volumeMounts:
+        # - mountPath: /opt/oai-nr-pucchsim/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015109" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/nr-pucchsim/templates/service.yaml b/charts/physims/charts/nr-pucchsim/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9e8760e76b68834a00451cd1d3e71ec72e2cd719
--- /dev/null
+++ b/charts/physims/charts/nr-pucchsim/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-pucchsim.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-nr-pucchsim
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-nr-pucchsim.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/nr-pucchsim/values.yaml b/charts/physims/charts/nr-pucchsim/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cf50c0bd3cf8a82feaef6911203e6422b39858ad
--- /dev/null
+++ b/charts/physims/charts/nr-pucchsim/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-nr-pucchsim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-nr-pucchsim-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/nr-ulschsim/Chart.yaml b/charts/physims/charts/nr-ulschsim/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e2525f0032b35ab32188cae55d43b49664da5804
--- /dev/null
+++ b/charts/physims/charts/nr-ulschsim/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-nr-ulschsim
+description: A Helm subchart for nr-ulschsim network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - nr-ulschsim
+  - RAN
+  - 5G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/nr-ulschsim/templates/NOTES.txt b/charts/physims/charts/nr-ulschsim/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..65566932cd7c96f2951ac2f9a445492e852d0e21
--- /dev/null
+++ b/charts/physims/charts/nr-ulschsim/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-nr-ulschsim.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-nr-ulschsim.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-nr-ulschsim.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-nr-ulschsim.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/nr-ulschsim/templates/_helpers.tpl b/charts/physims/charts/nr-ulschsim/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..9aa13a81f062e3d0a610fc2434e850d77baf634f
--- /dev/null
+++ b/charts/physims/charts/nr-ulschsim/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-nr-ulschsim.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-nr-ulschsim.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-nr-ulschsim.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-nr-ulschsim.labels" -}}
+helm.sh/chart: {{ include "oai-nr-ulschsim.chart" . }}
+{{ include "oai-nr-ulschsim.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-nr-ulschsim.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-nr-ulschsim.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-nr-ulschsim.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-nr-ulschsim.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/nr-ulschsim/templates/deployment.yaml b/charts/physims/charts/nr-ulschsim/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..56fb0de5b878954ca95179d0c49a60d10a0af102
--- /dev/null
+++ b/charts/physims/charts/nr-ulschsim/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-ulschsim.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-nr-ulschsim.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-nr-ulschsim.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-nr-ulschsim
+        # volumeMounts:
+        # - mountPath: /opt/oai-nr-ulschsim/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015108" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/nr-ulschsim/templates/service.yaml b/charts/physims/charts/nr-ulschsim/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d34882700e1b84e8bef58187701c2eb89276011c
--- /dev/null
+++ b/charts/physims/charts/nr-ulschsim/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-ulschsim.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-nr-ulschsim
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-nr-ulschsim.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/nr-ulschsim/values.yaml b/charts/physims/charts/nr-ulschsim/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..420b15459655986e89640e20ca2a23b747816528
--- /dev/null
+++ b/charts/physims/charts/nr-ulschsim/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-nr-ulschsim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-nr-ulschsim-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/nr-ulsim/Chart.yaml b/charts/physims/charts/nr-ulsim/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ede87ea7e487e3e1ccbec9e04fb77e1d168143bc
--- /dev/null
+++ b/charts/physims/charts/nr-ulsim/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-nr-ulsim
+description: A Helm subchart for nr-ulsim network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - nr-ulsim
+  - RAN
+  - 5G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/nr-ulsim/templates/NOTES.txt b/charts/physims/charts/nr-ulsim/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6865eeaedf096ad070079aec1d024a9bf2358145
--- /dev/null
+++ b/charts/physims/charts/nr-ulsim/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-nr-ulsim.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-nr-ulsim.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-nr-ulsim.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-nr-ulsim.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/nr-ulsim/templates/_helpers.tpl b/charts/physims/charts/nr-ulsim/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..90f0bd0e363db238d832517cc87b56011ddb3986
--- /dev/null
+++ b/charts/physims/charts/nr-ulsim/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-nr-ulsim.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-nr-ulsim.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-nr-ulsim.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-nr-ulsim.labels" -}}
+helm.sh/chart: {{ include "oai-nr-ulsim.chart" . }}
+{{ include "oai-nr-ulsim.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-nr-ulsim.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-nr-ulsim.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-nr-ulsim.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-nr-ulsim.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/nr-ulsim/templates/deployment.yaml b/charts/physims/charts/nr-ulsim/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c0fa5ceb3b1b28c578c4cf6b1be3623574b15a68
--- /dev/null
+++ b/charts/physims/charts/nr-ulsim/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-ulsim.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-nr-ulsim.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-nr-ulsim.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-nr-ulsim
+        # volumeMounts:
+        # - mountPath: /opt/oai-nr-ulsim/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015111" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/nr-ulsim/templates/service.yaml b/charts/physims/charts/nr-ulsim/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..95f198d1b123ca859866da0a76c050905e0202cd
--- /dev/null
+++ b/charts/physims/charts/nr-ulsim/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-nr-ulsim.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-nr-ulsim
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-nr-ulsim.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/nr-ulsim/values.yaml b/charts/physims/charts/nr-ulsim/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7eb8e33fcbcab2c83442fe5b024034bfe2753970
--- /dev/null
+++ b/charts/physims/charts/nr-ulsim/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-nr-ulsim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-nr-ulsim-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/polartest/Chart.yaml b/charts/physims/charts/polartest/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ae5f5ca2631bbb94472c14d0f91672ceb2f970b9
--- /dev/null
+++ b/charts/physims/charts/polartest/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-polartest
+description: A Helm subchart for polartest network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - polartest
+  - RAN
+  - 4G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/polartest/templates/NOTES.txt b/charts/physims/charts/polartest/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9c2c978de0ddf27df5f59b0a04345ee455abeb21
--- /dev/null
+++ b/charts/physims/charts/polartest/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-polartest.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-polartest.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-polartest.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-polartest.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/polartest/templates/_helpers.tpl b/charts/physims/charts/polartest/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..ce81dbe525587d8abf510f6de73bde4bfb5484bd
--- /dev/null
+++ b/charts/physims/charts/polartest/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-polartest.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-polartest.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-polartest.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-polartest.labels" -}}
+helm.sh/chart: {{ include "oai-polartest.chart" . }}
+{{ include "oai-polartest.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-polartest.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-polartest.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-polartest.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-polartest.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/polartest/templates/deployment.yaml b/charts/physims/charts/polartest/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..01a6efc815b7cba88f777b4fc0c495960845f582
--- /dev/null
+++ b/charts/physims/charts/polartest/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-polartest.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-polartest.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-polartest.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-polartest
+        # volumeMounts:
+        # - mountPath: /opt/oai-polartest/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015103" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/polartest/templates/service.yaml b/charts/physims/charts/polartest/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..40abb6769eb3128366b2658326c13a5e8069d7e0
--- /dev/null
+++ b/charts/physims/charts/polartest/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-polartest.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-polartest
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-polartest.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/polartest/values.yaml b/charts/physims/charts/polartest/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..496dc8afba245c7c8204618cd01dc4509bf27897
--- /dev/null
+++ b/charts/physims/charts/polartest/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-polartest.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-polartest-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/smallblocktest/Chart.yaml b/charts/physims/charts/smallblocktest/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..74092783aec9c3f36cf0d286368b709b843736b2
--- /dev/null
+++ b/charts/physims/charts/smallblocktest/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-smallblocktest
+description: A Helm subchart for smallblocktest network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - smallblocktest
+  - RAN
+  - 4G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/smallblocktest/templates/NOTES.txt b/charts/physims/charts/smallblocktest/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c593dbfe223177cfe73ae6b911aeff0cdb3ac54d
--- /dev/null
+++ b/charts/physims/charts/smallblocktest/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-smallblocktest.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-smallblocktest.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-smallblocktest.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-smallblocktest.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/smallblocktest/templates/_helpers.tpl b/charts/physims/charts/smallblocktest/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..a3c264b33ebf817d52f0319a03512403d342713e
--- /dev/null
+++ b/charts/physims/charts/smallblocktest/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-smallblocktest.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-smallblocktest.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-smallblocktest.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-smallblocktest.labels" -}}
+helm.sh/chart: {{ include "oai-smallblocktest.chart" . }}
+{{ include "oai-smallblocktest.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-smallblocktest.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-smallblocktest.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-smallblocktest.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-smallblocktest.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/smallblocktest/templates/deployment.yaml b/charts/physims/charts/smallblocktest/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3439c2597ed787be2d53102c8ce4c719314fddeb
--- /dev/null
+++ b/charts/physims/charts/smallblocktest/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-smallblocktest.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-smallblocktest.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-smallblocktest.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-smallblock
+        # volumeMounts:
+        # - mountPath: /opt/oai-smallblocktest/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015107" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/smallblocktest/templates/service.yaml b/charts/physims/charts/smallblocktest/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d51bf21ce4c1dcc45031c00fb18894dbf0218f84
--- /dev/null
+++ b/charts/physims/charts/smallblocktest/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-smallblocktest.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-smallblocktest
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-smallblocktest.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/smallblocktest/values.yaml b/charts/physims/charts/smallblocktest/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9dd791265f2416098e2a2406286337a10ca88a46
--- /dev/null
+++ b/charts/physims/charts/smallblocktest/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-smallblocktest.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-smallblocktest-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/charts/ulsim/Chart.yaml b/charts/physims/charts/ulsim/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2311d729b4c3aad7ae49641baf5f62778efd5d0b
--- /dev/null
+++ b/charts/physims/charts/ulsim/Chart.yaml
@@ -0,0 +1,36 @@
+apiVersion: v1
+name: oai-ulsim
+description: A Helm subchart for ulsim network function
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+version: 0.1.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: v1
+
+keywords:
+  - Physical Simulator
+  - ulsim
+  - RAN
+  - 4G
+
+sources:
+  - https://gitlab.eurecom.fr/oai/openairinterface5g
+
+maintainers:
+  - name:  OPENAIRINTERFACE
+    email: contact@openairinterface.org
diff --git a/charts/physims/charts/ulsim/templates/NOTES.txt b/charts/physims/charts/ulsim/templates/NOTES.txt
new file mode 100644
index 0000000000000000000000000000000000000000..91ab3ce0b7a523af4cdb8d9829cd982362ee8651
--- /dev/null
+++ b/charts/physims/charts/ulsim/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{- if contains "NodePort" .Values.service.type }}
+  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "oai-ulsim.fullname" . }})
+  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+  echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "oai-ulsim.fullname" . }}'
+  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "oai-ulsim.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+  echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oai-ulsim.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+  echo "Visit http://127.0.0.1:8080 to use your application"
+  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80
+{{- end }}
diff --git a/charts/physims/charts/ulsim/templates/_helpers.tpl b/charts/physims/charts/ulsim/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..67b65004791cfa3231dffacac4232b4f9dbd4a6d
--- /dev/null
+++ b/charts/physims/charts/ulsim/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oai-ulsim.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oai-ulsim.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oai-ulsim.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "oai-ulsim.labels" -}}
+helm.sh/chart: {{ include "oai-ulsim.chart" . }}
+{{ include "oai-ulsim.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oai-ulsim.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oai-ulsim.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oai-ulsim.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "oai-ulsim.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/physims/charts/ulsim/templates/deployment.yaml b/charts/physims/charts/ulsim/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e8c90dabc1857c673d8a6a51d8c1da40d799ea2d
--- /dev/null
+++ b/charts/physims/charts/ulsim/templates/deployment.yaml
@@ -0,0 +1,49 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-ulsim.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oai-ulsim.selectorLabels" . | nindent 6 }}
+  strategy:
+    type: Recreate
+  template:
+    metadata:
+      labels:
+        {{- include "oai-ulsim.selectorLabels" . | nindent 8 }}
+    spec:
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+    {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+    {{- end }}
+      containers:
+      - name: physim
+        image: "{{ .Values.global.image.repository }}:{{ .Values.global.image.version }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        securityContext:
+          {{- toYaml .Values.securityContext | nindent 12 }}
+        ports:
+        - containerPort: 80
+          name: oai-ulsim
+        # volumeMounts:
+        # - mountPath: /opt/oai-ulsim/certs
+        #   name: certs
+        command: ["/bin/sh", "-c"]
+        args:
+        - >  
+          export OPENAIR_DIR=/opt/oai-physim &&
+          cd cmake_targets/autotests &&
+          ./run_exec_autotests.bash -g "015101" -q -np -b &&
+          echo "FINISHED" &&
+          sleep infinity
+      dnsPolicy: ClusterFirst
+      restartPolicy: Always
+      schedulerName: default-scheduler
+      serviceAccountName: {{ .Values.global.serviceAccountName }}
+      terminationGracePeriodSeconds: 30
diff --git a/charts/physims/charts/ulsim/templates/service.yaml b/charts/physims/charts/ulsim/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..dcc37d6299461562d9ecfc7776cbb1b0f7fd10c8
--- /dev/null
+++ b/charts/physims/charts/ulsim/templates/service.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}
+  labels:
+    {{- include "oai-ulsim.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+{{- if  contains "ClusterIP" .Values.service.type }}
+  clusterIP: None
+{{- end }}
+  ports:
+    - name: oai-ulsim
+      # Port accessible outside cluster
+      port: {{ .Values.service.port }}
+      # Port to forward to inside the pod
+      targetPort: {{ .Values.service.Port }}
+      protocol: TCP
+  selector:
+    {{- include "oai-ulsim.selectorLabels" . | nindent 4 }}
diff --git a/charts/physims/charts/ulsim/values.yaml b/charts/physims/charts/ulsim/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f5110989d86bb5db489151e88202256f0e57c54e
--- /dev/null
+++ b/charts/physims/charts/ulsim/values.yaml
@@ -0,0 +1,63 @@
+# Default values for oai-ulsim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+namespace: "oaicicd-ran-tmp"
+
+image:
+  registry: local
+  repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+  version: temp
+  # pullPolicy: IfNotPresent or Never or Always
+  pullPolicy: Always
+
+imagePullSecrets: []
+
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+  # Specifies whether a service account should be created
+  create: true
+  # Annotations to add to the service account
+  annotations: {}
+  # The name of the service account to use.
+  # If not set and create is true, a name is generated using the fullname template
+  name: "oai-ulsim-sa"
+
+podSecurityContext:
+  runAsUser: 0
+  runAsGroup: 0
+
+securityContext:
+  privileged: true
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/charts/physims/templates/rbac.yaml b/charts/physims/templates/rbac.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..35f956a203beaf004b75369e524147dc0afabf1b
--- /dev/null
+++ b/charts/physims/templates/rbac.yaml
@@ -0,0 +1,12 @@
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRoleBinding
+metadata:
+  name: {{ .Chart.Name }}-{{ .Values.global.namespace }}-rbac
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: cluster-admin
+subjects:
+- kind: ServiceAccount
+  name: {{ .Values.global.serviceAccountName }}
+  namespace: {{ .Values.global.namespace }}
diff --git a/charts/physims/templates/serviceaccount.yaml b/charts/physims/templates/serviceaccount.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..21d094ad38b154cfba02982fad63b7ab3cb61936
--- /dev/null
+++ b/charts/physims/templates/serviceaccount.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ .Values.global.serviceAccountName }}
diff --git a/charts/physims/values.yaml b/charts/physims/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b348e822bb0e2e64ed7ae2f2c1c6e737f0afd5ec
--- /dev/null
+++ b/charts/physims/values.yaml
@@ -0,0 +1,84 @@
+# Default values for oai-physim.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+global:
+  serviceAccountName: oai-physim-sa
+  namespace: "oaicicd-ran-tmp"
+  image:
+    repository: image-registry.openshift-image-registry.svc:5000/oaicicd-ran-tmp/oai-physim
+    version: TAG
+
+## Declaring values specific to coressponding physim to overwrite
+
+dlsim:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+ulsim:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+ldpctest:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+polartest:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+nr-pbchsim:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+nr-dlsim:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+nr-dlschsim:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+smallblocktest:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+nr-ulschsim:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+nr-pucchsim:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+nr-ulsim:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
+
+nr-prachsim:
+  replicaCount: 1
+  service:
+    type: ClusterIP
+    port: 80
diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container
index dd9dba2e6675656f73c6f8ef0d99141ad2332819..a4d7a4bf92869514876c72e470ef93420ed18cfc 100644
--- a/ci-scripts/Jenkinsfile-GitLab-Container
+++ b/ci-scripts/Jenkinsfile-GitLab-Container
@@ -176,6 +176,30 @@ pipeline {
         }
       }
     }
+    stage ("Image Test Processes") {
+      parallel {
+        stage ("Physical Simulators") {
+          when { expression {doMandatoryTests} }
+          steps {
+            script {
+              triggerSlaveJob ('RAN-PhySim-Cluster', 'Test-Physim-Cluster')
+            }
+          }
+          post {
+            always {
+              script {
+                finalizeSlaveJob('RAN-PhySim-Cluster')
+              }
+            }
+            failure {
+              script {
+                currentBuild.result = 'FAILURE'
+              }
+            }
+          }
+        }
+      }
+    }
   }
   post {
     always {
diff --git a/ci-scripts/Jenkinsfile-gitlab b/ci-scripts/Jenkinsfile-gitlab
index bb78a21ca0d8f0f79326868105c78825d7803160..d5c526acb385586c4d2777a05d21f89b55a6839c 100644
--- a/ci-scripts/Jenkinsfile-gitlab
+++ b/ci-scripts/Jenkinsfile-gitlab
@@ -196,16 +196,6 @@ pipeline {
             }
         }
 
-        stage ("Start VM -- phy-sim") {
-            steps {
-              lock (vmResource) {
-                timeout (time: 5, unit: 'MINUTES') {
-                    sh "./ci-scripts/oai-ci-vm-tool build --workspace $WORKSPACE --variant phy-sim --job-name ${JOB_NAME} --build-id ${BUILD_ID} --daemon"
-                }
-              }
-            }
-        }
-        
         stage ("Start VM -- enb-ethernet") {
             steps {
               lock (vmResource) {
@@ -255,15 +245,6 @@ pipeline {
                         }
                     }
                 }
-                stage ("Build physical simulators") {
-                    steps {
-                        gitlabCommitStatus(name: "Build phy-sim") {
-                            timeout (time: 45, unit: 'MINUTES') {
-                               sh "./ci-scripts/oai-ci-vm-tool wait --workspace $WORKSPACE --variant phy-sim --job-name ${JOB_NAME} --build-id ${BUILD_ID} --keep-vm-alive"
-                            }
-                        }
-                    }
-                }
                 stage ("Build eNB-ethernet") {
                     steps {
                         gitlabCommitStatus(name: "Build eNB-ethernet") {
@@ -296,9 +277,9 @@ pipeline {
                     script {
                         dir ('archives') {
                             if (fileExists('red_hat')) {
-                                sh "zip -r -qq vm_build_logs.zip basic_sim phy_sim enb_eth ue_eth gnb_usrp nr_ue_usrp red_hat"
+                                sh "zip -r -qq vm_build_logs.zip basic_sim enb_eth ue_eth gnb_usrp nr_ue_usrp red_hat"
                             } else {
-                                sh "zip -r -qq vm_build_logs.zip basic_sim phy_sim enb_eth ue_eth gnb_usrp nr_ue_usrp"
+                                sh "zip -r -qq vm_build_logs.zip basic_sim enb_eth ue_eth gnb_usrp nr_ue_usrp"
                             }
                         }
                         if(fileExists('archives/vm_build_logs.zip')) {
@@ -332,26 +313,6 @@ pipeline {
             parallel {
                 stage ("VM-based tests") {
                     stages {
-                        stage ("Test physical simulators") {
-                            when {
-                                expression {doMandatoryTests}
-                            }
-                            steps {
-                              lock (vmResource) {
-                                script {
-                                    timeout (time: 90, unit: 'MINUTES') {
-                                        try {
-                                            gitlabCommitStatus(name: "Test phy-sim") {
-                                                sh "./ci-scripts/oai-ci-vm-tool test --workspace $WORKSPACE --variant phy-sim --job-name ${JOB_NAME} --build-id ${BUILD_ID}"
-                                            }
-                                        } catch (Exception e) {
-                                          currentBuild.result = 'FAILURE'
-                                        }
-                                    }
-                                }
-                              }
-                            }
-                        }
                         stage ("Build Flexran Controller") {
                             when {
                                 expression {doFlexranCtrlTest && doMandatoryTests}
@@ -716,7 +677,7 @@ pipeline {
                     script {
                       if (doMandatoryTests) {
                         dir ('archives') {
-                            sh "if [ -d basic_sim/test ] || [ -d phy_sim/test ] || [ -d l2_sim/test ]; then zip -r -qq vm_tests_logs.zip */test ; fi"
+                            sh "if [ -d basic_sim/test ] || [ -d rf_sim/test ] || [ -d l2_sim/test ]; then zip -r -qq vm_tests_logs.zip */test ; fi"
                         }
                         if(fileExists('archives/vm_tests_logs.zip')) {
                             archiveArtifacts artifacts: 'archives/vm_tests_logs.zip'
diff --git a/ci-scripts/Jenkinsfile-physim-deploy b/ci-scripts/Jenkinsfile-physim-deploy
new file mode 100644
index 0000000000000000000000000000000000000000..2d2cf054b5e589f26bbcaba1a61641747338ef72
--- /dev/null
+++ b/ci-scripts/Jenkinsfile-physim-deploy
@@ -0,0 +1,233 @@
+#!/bin/groovy
+/*
+ * 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
+ */
+
+// Location of the executor node
+def pythonExecutor = params.pythonExecutor
+
+// Location of the test XML file to be run
+def testXMLFile = params.pythonTestXmlFile
+def mainPythonAllXmlFiles = ""
+def buildStageStatus = true
+
+// Name of the test stage
+def testStageName = params.pipelineTestStageName
+
+// Name of the resource
+def ciEpcResource = params.epcResource
+
+// Global Parameters. Normally they should be populated when the master job
+// triggers the slave job with parameters
+def eNB_Repository
+def eNB_Branch
+def eNB_CommitID
+def eNB_AllowMergeRequestProcess = false
+def eNB_TargetBranch
+
+// Flags
+def scmEvent = false
+def upstreamEvent = false
+
+//-------------------------------------------------------------------------------
+// Pipeline start
+pipeline {
+  agent {
+    label pythonExecutor
+  }
+  options {
+    disableConcurrentBuilds()
+    timestamps()
+    ansiColor('xterm')
+    lock(ciEpcResource)
+  }
+
+  stages {
+    stage ('Verify Parameters') {
+      steps {
+        script {
+          echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
+
+          JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"'
+          JOB_TIMESTAMP = JOB_TIMESTAMP.trim()
+
+          def allParametersPresent = true
+
+          // It is already to late to check it
+          if (params.pythonExecutor != null) {
+            echo "eNB CI executor node  :   ${pythonExecutor}"
+          }
+          // If not present picking a default Stage Name
+          if (params.pipelineTestStageName == null) {
+            // picking default
+            testStageName = 'Template Test Stage'
+          }
+
+          if (params.smartphonesResource == null) {
+            allParametersPresent = false
+          }
+          if (params.eNB_IPAddress == null) {
+            allParametersPresent = false
+          }
+          if (params.eNB_SourceCodePath == null) {
+            allParametersPresent = false
+          }
+          if (params.eNB_Credentials == null) {
+            allParametersPresent = false
+          }
+          // the following 4 parameters should be pushed by the master trigger
+          // if not present, take the job GIT variables (used for developing)
+          if (params.eNB_Repository == null) {
+            eNB_Repository = env.GIT_URL
+          } else {
+            eNB_Repository = params.eNB_Repository
+          }
+          echo "eNB_Repository        :   ${eNB_Repository}"
+          if (params.eNB_Branch == null) {
+            eNB_Branch = env.GIT_BRANCH
+          } else {
+            eNB_Branch = params.eNB_Branch
+          }
+          echo "eNB_Branch            :   ${eNB_Branch}"
+          if (params.eNB_CommitID == null) {
+            eNB_CommitID = env.GIT_COMMIT
+          } else {
+            eNB_CommitID = params.eNB_CommitID
+          }
+          echo "eNB_CommitID          :   ${eNB_CommitID}"
+          if (params.eNB_mergeRequest != null) {
+            eNB_AllowMergeRequestProcess = params.eNB_mergeRequest
+            if (eNB_AllowMergeRequestProcess) {
+              if (params.eNB_TargetBranch != null) {
+                eNB_TargetBranch = params.eNB_TargetBranch
+              } else {
+                eNB_TargetBranch = 'develop'
+              }
+              echo "eNB_TargetBranch      :   ${eNB_TargetBranch}"
+            }
+          }
+
+          if (params.EPC_IPAddress == null) {
+            allParametersPresent = false
+          }
+          if (params.EPC_Type == null) {
+            allParametersPresent = false
+          }
+          if (params.EPC_SourceCodePath == null) {
+            allParametersPresent = false
+          }
+          if (params.EPC_Credentials == null) {
+            allParametersPresent = false
+          }
+
+          if (params.ADB_IPAddress == null) {
+            allParametersPresent = false
+          }
+          if (params.ADB_Credentials == null) {
+            allParametersPresent = false
+          }
+          if (params.OC_Credentials == null) {
+            allParametersPresent = false
+          }
+          if (params.OC_ProjectName == null) {
+            allParametersPresent = false
+          }
+          if (allParametersPresent) {
+            echo "All parameters are present"
+            if (eNB_AllowMergeRequestProcess) {
+              sh "git fetch"
+              sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest"
+            } else {
+              sh "git fetch"
+              sh "git checkout -f ${eNB_CommitID}"
+            }
+          } else {
+            echo "Some parameters are missing"
+            sh "./ci-scripts/fail.sh"
+          }
+        }
+      }
+    }
+
+    stage ("Deploy and Test") {
+      steps {
+        script {
+          dir ('ci-scripts') {
+            echo "\u2705 \u001B[32m${testStageName}\u001B[0m"
+            // If not present picking a default XML file
+            if (params.pythonTestXmlFile == null) {
+              // picking default
+              testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.xml'
+              echo "Test XML file(default):   ${testXMLFile}"
+              mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " "
+            } else {
+              String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
+              for (xmlFile in myXmlTestSuite) {
+                if (fileExists(xmlFile)) {
+                  mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " "
+                  echo "Test XML file         :   ${xmlFile}"
+                }
+              }
+            }
+            withCredentials([
+              [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'],
+              [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.EPC_Credentials}", usernameVariable: 'EPC_Username', passwordVariable: 'EPC_Password'],
+              [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.ADB_Credentials}", usernameVariable: 'ADB_Username', passwordVariable: 'ADB_Password'],
+              [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password']
+            ]) {
+              sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} ${mainPythonAllXmlFiles}"
+              String[] myXmlTestSuite = testXMLFile.split("\\r?\\n")
+              for (xmlFile in myXmlTestSuite) {
+                if (fileExists(xmlFile)) {
+                  try {
+                    sh "python3 main.py --mode=TesteNB --eNBIPAddress=${params.eNB_IPAddress} --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --EPCIPAddress=${params.EPC_IPAddress} --EPCType=${params.EPC_Type} --EPCUserName=${EPC_Username} --EPCPassword=${EPC_Password} --EPCSourceCodePath=${params.EPC_SourceCodePath} --ADBIPAddress=${params.ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}"
+                  } catch (Exception e) {
+                    currentBuild.result = 'FAILURE'
+                    buildStageStatus = false
+                  }
+                }
+              }
+              sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}"
+            }
+          }
+        } 
+      }
+    }
+    stage ("Log Collection") {
+      steps {
+        script {
+          dir ('ci-scripts') {
+            // Zipping all archived log files
+            sh "zip -r -qq physim_deploytest_logs_${env.BUILD_ID}.zip physim_test_logs_*/*"
+            sh "rm -rf physim_test_logs_*/"
+            if (fileExists("physim_deploytest_logs_${env.BUILD_ID}.zip")) {
+              archiveArtifacts artifacts: "physim_deploytest_logs_${env.BUILD_ID}.zip"
+            }
+            if (fileExists("test_results.html")) {
+              sh "mv test_results.html test_results_${env.JOB_NAME}.html"
+              sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results_${JOB_NAME}.html"
+              archiveArtifacts artifacts: "test_results_${env.JOB_NAME}.html"
+            }
+          }
+        }
+      }
+    }
+  }  
+}  
diff --git a/ci-scripts/args_parse.py b/ci-scripts/args_parse.py
index 288e0b4885aeccab95de87ba0f3eec896e2fa767..0ed12bfc08a2a1bc23ae6a01ee1192599a576e4f 100644
--- a/ci-scripts/args_parse.py
+++ b/ci-scripts/args_parse.py
@@ -41,7 +41,7 @@ import constants as CONST
 #-----------------------------------------------------------
 
 
-def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
+def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA,PHYSIM):
 
 
     py_param_file_present = False
@@ -81,6 +81,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
             ldpc.ranRepository=matchReg.group(1)
             CONTAINERS.ranRepository=matchReg.group(1)
             SCA.ranRepository=matchReg.group(1)
+            PHYSIM.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)
@@ -94,6 +95,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
                 HTML.ranAllowMerge=True
                 CONTAINERS.ranAllowMerge=True
                 SCA.ranAllowMerge=True
+                PHYSIM.ranAllowMerge=True
         elif re.match('^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE):
             if re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE)
@@ -105,6 +107,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
             ldpc.ranBranch=matchReg.group(1)
             CONTAINERS.ranBranch=matchReg.group(1)
             SCA.ranBranch=matchReg.group(1)
+            PHYSIM.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)
@@ -116,6 +119,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
             ldpc.ranCommitID=matchReg.group(1)
             CONTAINERS.ranCommitID=matchReg.group(1)
             SCA.ranCommitID=matchReg.group(1)
+            PHYSIM.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)
@@ -127,6 +131,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
             ldpc.ranTargetBranch=matchReg.group(1)
             CONTAINERS.ranTargetBranch=matchReg.group(1)
             SCA.ranTargetBranch=matchReg.group(1)
+            PHYSIM.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)
@@ -134,6 +139,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
                 ldpc.eNBIpAddr=matchReg.group(1)
                 CONTAINERS.eNBIPAddress=matchReg.group(1)
                 SCA.eNBIPAddress=matchReg.group(1)
+                PHYSIM.eNBIPAddress=matchReg.group(1)
             elif re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1IPAddress=matchReg.group(1)
@@ -149,6 +155,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
                 ldpc.eNBUserName=matchReg.group(1)
                 CONTAINERS.eNBUserName=matchReg.group(1)
                 SCA.eNBUserName=matchReg.group(1)
+                PHYSIM.eNBUserName=matchReg.group(1)
             elif re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1UserName=matchReg.group(1)
@@ -164,6 +171,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
                 ldpc.eNBPassWord=matchReg.group(1)
                 CONTAINERS.eNBPassword=matchReg.group(1)
                 SCA.eNBPassword=matchReg.group(1)
+                PHYSIM.eNBPassword=matchReg.group(1)
             elif re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1Password=matchReg.group(1)
@@ -179,6 +187,7 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
                 ldpc.eNBSourceCodePath=matchReg.group(1)
                 CONTAINERS.eNBSourceCodePath=matchReg.group(1)
                 SCA.eNBSourceCodePath=matchReg.group(1)
+                PHYSIM.eNBSourceCodePath=matchReg.group(1)
             elif re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE):
                 matchReg = re.match('^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE)
                 RAN.eNB1SourceCodePath=matchReg.group(1)
@@ -248,6 +257,15 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA):
             finalStatus = matchReg.group(1)
             if ((finalStatus == 'true') or (finalStatus == 'True')):
                 CiTestObj.finalStatus = True
+        elif re.match('^\-\-OCUserName=(.+)$', myArgv, re.IGNORECASE):
+            matchReg = re.match('^\-\-OCUserName=(.+)$', myArgv, re.IGNORECASE)
+            PHYSIM.OCUserName = matchReg.group(1)
+        elif re.match('^\-\-OCPassword=(.+)$', myArgv, re.IGNORECASE):
+            matchReg = re.match('^\-\-OCPassword=(.+)$', myArgv, re.IGNORECASE)
+            PHYSIM.OCPassword = matchReg.group(1)
+        elif re.match('^\-\-OCProjectName=(.+)$', myArgv, re.IGNORECASE):
+            matchReg = re.match('^\-\-OCProjectName=(.+)$', myArgv, re.IGNORECASE)
+            PHYSIM.OCProjectName = matchReg.group(1)
         else:
             HELP.GenericHelp(CONST.Version)
             sys.exit('Invalid Parameter: ' + myArgv)
diff --git a/ci-scripts/auto_start_gnb.sh b/ci-scripts/auto_start_gnb.sh
new file mode 100644
index 0000000000000000000000000000000000000000..86ffc66d184269ad34937d6bab02161fd6261208
--- /dev/null
+++ b/ci-scripts/auto_start_gnb.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+while true
+do
+  echo "gNB will be started automatically..."
+  sleep 1
+  sudo .././cmake_targets/ran_build/build/nr-softmodem -E -O ../targets/PROJECTS/GENERIC-LTE-EPC/CONF/testing_gnb.conf
+done
diff --git a/ci-scripts/buildOnVM.sh b/ci-scripts/buildOnVM.sh
index 31e9653769cdc019745ce3864eed45aea34e9f4b..f4cf3931dd327827dc36731ce8d45855059f3c00 100755
--- a/ci-scripts/buildOnVM.sh
+++ b/ci-scripts/buildOnVM.sh
@@ -62,7 +62,7 @@ function build_on_vm {
     echo "ARCHIVES_LOC        = $ARCHIVES_LOC"
     echo "BUILD_OPTIONS       = $BUILD_OPTIONS"
 
-    if [[ "$VM_NAME" == *"-enb-usrp"* ]] || [[ "$VM_NAME" == *"-cppcheck"* ]]
+    if [[ "$VM_NAME" == *"-enb-usrp"* ]] || [[ "$VM_NAME" == *"-cppcheck"* ]] || [[ "$VM_NAME" == *"-phy-sim"* ]]
     then
         echo "This VM type is no longer supported in the pipeline framework"
         return
diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py
index e5011dcd46413ae051b4c4ed2899459baa3acd62..6c8a2deb77ae8ffdf25d8221283efb95040b4a6b 100644
--- a/ci-scripts/cls_containerize.py
+++ b/ci-scripts/cls_containerize.py
@@ -88,6 +88,7 @@ class Containerize():
 		self.host = ''
 		self.allImagesSize = {}
 		self.collectInfo = {}
+
 #-----------------------------------------------------------
 # Container management functions
 #-----------------------------------------------------------
@@ -335,6 +336,31 @@ class Containerize():
 					errorandwarnings['warnings'] = warningsNo
 					errorandwarnings['status'] = status
 				files[fil] = errorandwarnings
+			# Let analyze the target image creation part
+			if os.path.isfile('build_log_{}/{}.log'.format(self.testCase_id,image)):
+				errorandwarnings = {}
+				with open('build_log_{}/{}.log'.format(self.testCase_id,image), mode='r') as inputfile:
+					startOfTargetImageCreation = False
+					buildStatus = False
+					for line in inputfile:
+						result = re.search('FROM .* as ' + image + '$', str(line))
+						if result is not None:
+							startOfTargetImageCreation = True
+						if startOfTargetImageCreation:
+							result = re.search('Successfully tagged ' + image + ':', str(line))
+							if result is not None:
+								buildStatus = True
+							result = re.search('COMMIT ' + image + ':', str(line))
+							if result is not None:
+								buildStatus = True
+					inputfile.close()
+					if buildStatus:
+						errorandwarnings['errors'] = 0
+					else:
+						errorandwarnings['errors'] = 1
+					errorandwarnings['warnings'] = 0
+					errorandwarnings['status'] = buildStatus
+					files['Target Image Creation'] = errorandwarnings
 			self.collectInfo[image] = files
 		
 		if status:
diff --git a/ci-scripts/cls_physim1.py b/ci-scripts/cls_physim1.py
new file mode 100644
index 0000000000000000000000000000000000000000..41beb1e0966b4b27d03eeb30d228c1fd7f6673de
--- /dev/null
+++ b/ci-scripts/cls_physim1.py
@@ -0,0 +1,292 @@
+#/*
+# * 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 logging
+import sshconnection as SSH
+import html
+import os
+import re
+import time
+import sys
+import constants as CONST
+import helpreadme as HELP
+
+class PhySim:
+	def __init__(self):
+		self.eNBIpAddr = ""
+		self.eNBUserName = ""
+		self.eNBPassword = ""
+		self.OCUserName = ""
+		self.OCPassword = ""
+		self.OCProjectName = ""
+		self.eNBSourceCodePath = ""
+		self.ranRepository = ""
+		self.ranBranch = ""
+		self.ranCommitID= ""
+		self.ranAllowMerge= False
+		self.ranTargetBranch= ""
+		self.testResult = {}
+		self.testCount = [0,0,0]
+		self.testSummary = {}
+		self.testStatus = False
+
+#-----------------$
+#PUBLIC Methods$
+#-----------------$
+
+	def Deploy_PhySim(self, HTML):
+		if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		lIpAddr = self.eNBIPAddress
+		lUserName = self.eNBUserName
+		lPassWord = self.eNBPassword
+		lSourcePath = self.eNBSourceCodePath
+		ocUserName = self.OCUserName
+		ocPassword = self.OCPassword
+		ocProjectName = self.OCProjectName
+
+		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '' or ocUserName == '' or ocPassword == '' or ocProjectName == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		logging.debug('Building on server: ' + lIpAddr)
+		mySSH = SSH.SSHConnection()
+		mySSH.open(lIpAddr, lUserName, lPassWord)
+
+		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 self.ranAllowMerge:
+			imageTag = "ci-temp"
+		else:
+			imageTag = "develop"
+		# Check if image is exist on the Red Hat server, before pushing it to OC cluster
+		mySSH.command("sudo podman image inspect --format='Size = {{.Size}} bytes' oai-physim:" + imageTag, '\$', 60)
+		if mySSH.getBefore().count('no such image') != 0:
+			logging.error('\u001B[1m No such image oai-physim\u001B[0m')
+			mySSH.close()
+			sys.exit(-1)
+		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   oai-physim size is ' + ('%.0f' % imageSize) + ' kbytes\u001B[0m')
+				else:
+					imageSize = imageSize / 1000
+					if imageSize < 1000:
+						logging.debug('\u001B[1m   oai-physim size is ' + ('%.0f' % imageSize) + ' Mbytes\u001B[0m')
+					else:
+						imageSize = imageSize / 1000
+						logging.debug('\u001B[1m   oai-physim is ' + ('%.3f' % imageSize) + ' Gbytes\u001B[0m')
+			else:
+				logging.debug('oai-physim size is unknown')
+
+		# logging to OC Cluster and then switch to corresponding project
+		mySSH.command(f'oc login -u {ocUserName} -p {ocPassword}', '\$', 6)
+		if mySSH.getBefore().count('Login successful.') == 0:
+			logging.error('\u001B[1m OC Cluster Login Failed\u001B[0m')
+			mySSH.close()
+			sys.exit(-1)
+		else:
+			logging.debug('\u001B[1m   Login to OC Cluster Successfully\u001B[0m')
+		mySSH.command(f'oc project {ocProjectName}', '\$', 6)
+		if mySSH.getBefore().count(f'Already on project "{ocProjectName}"') == 0 and mySSH.getBefore().count(f'Now using project "{self.OCProjectName}"') == 0:
+			logging.error(f'\u001B[1m Unable to access OC project {ocProjectName}\u001B[0m')
+			mySSH.close()
+			sys.exit(-1)
+		else:
+			logging.debug(f'\u001B[1m   Now using project {ocProjectName}\u001B[0m')
+
+		# Tag the image and push to the OC cluster
+		mySSH.command('oc whoami -t | sudo podman login -u ' + ocUserName + ' --password-stdin https://default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/ --tls-verify=false', '\$', 6)
+		if mySSH.getBefore().count('Login Succeeded!') == 0:
+			logging.error('\u001B[1m Podman Login to OC Cluster Registry Failed\u001B[0m')
+			mySSH.close()
+			sys.exit(-1)
+		else:
+			logging.debug('\u001B[1m Podman Login to OC Cluster Registry Successfully\u001B[0m')
+		mySSH.command('oc create -f openshift/oai-physim-image-stream.yml', '\$', 6)
+		if mySSH.getBefore().count('(AlreadyExists):') == 0 and mySSH.getBefore().count('created') == 0:
+			logging.error(f'\u001B[1m Image Stream "oai-physim" Creation Failed on OC Cluster {ocProjectName}\u001B[0m')
+			mySSH.close()
+			sys.exit(-1)
+		else:
+			logging.debug(f'\u001B[1m   Image Stream "oai-physim" created on OC project {ocProjectName}\u001B[0m')
+		mySSH.command(f'sudo podman tag oai-physim:{imageTag} default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6)
+		mySSH.command(f'sudo podman push default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag} --tls-verify=false', '\$', 30)
+		if mySSH.getBefore().count('Storing signatures') == 0:
+			logging.error('\u001B[1m Image "oai-physim" push to OC Cluster Registry Failed\u001B[0m')
+			mySSH.close()
+			sys.exit(-1)
+		else:
+			logging.debug('\u001B[1m Image "oai-physim" push to OC Cluster Registry Successfully\u001B[0m')
+
+		# Using helm charts deployment
+		mySSH.command(f'sed -i -e "s#TAG#{imageTag}#g" ./charts/physims/values.yaml', '\$', 6)
+		mySSH.command('helm install physim ./charts/physims/ | tee -a cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 6)
+		if mySSH.getBefore().count('STATUS: deployed') == 0:
+			logging.error('\u001B[1m Deploying PhySim Failed using helm chart on OC Cluster\u001B[0m')
+			mySSH.command('helm uninstall physim >> cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 6)
+			mySSH.close()
+			self.AnalyzeLogFile_phySim(HTML)
+			sys.exit(-1)
+		else:
+			logging.debug('\u001B[1m   Deployed PhySim Successfully using helm chart\u001B[0m')
+		isRunning = False
+		count = 0
+		while(count < 2 and isRunning == False):
+			time.sleep(60)
+			mySSH.command('oc get pods -o wide -l app.kubernetes.io/instance=physim | tee -a cmake_targets/log/physim_pods_summary.txt', '\$', 6, resync=True)
+			if mySSH.getBefore().count('Running') == 12:
+				logging.debug('\u001B[1m Running the physim test Scenarios\u001B[0m')
+				isRunning = True
+				podNames = re.findall('oai-[\S\d\w]+', mySSH.getBefore())
+			count +=1
+		if isRunning == False:
+			logging.error('\u001B[1m Some PODS Running FAILED \u001B[0m')
+			mySSH.command('oc get pods -l app.kubernetes.io/instance=physim 2>&1 | tee -a cmake_targets/log/physim_pods_summary.txt', '\$', 6)
+			mySSH.command('helm uninstall physim >> cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 6)
+			self.AnalyzeLogFile_phySim(HTML)
+			sys.exit(-1)
+		# Waiting to complete the running test
+		count = 0
+		isFinished = False
+		# doing a deep copy!
+		tmpPodNames = podNames.copy()
+		while(count < 28 and isFinished == False):
+			time.sleep(58)
+			for podName in tmpPodNames:
+				mySSH.command(f'oc logs --tail=1 {podName} 2>&1', '\$', 6, silent=True, resync=True)
+				time.sleep(2)
+				if mySSH.getBefore().count('FINISHED') != 0:
+					logging.debug(podName + ' is finished')
+					tmpPodNames.remove(podName)
+			if not tmpPodNames:
+				isFinished = True
+			count += 1
+		if isFinished:
+			logging.debug('\u001B[1m PhySim test is Complete\u001B[0m')
+
+		# Getting the logs of each executables running in individual pods
+		for podName in podNames:
+			mySSH.command(f'oc logs {podName} >> cmake_targets/log/physim_test.txt 2>&1', '\$', 15, resync=True)
+		time.sleep(30)
+
+		# UnDeploy the physical simulator pods
+		mySSH.command('helm uninstall physim | tee -a cmake_targets/log/physim_helm_summary.txt 2>&1', '\$', 6)
+		isFinished1 = False
+		while(isFinished1 == False):
+			time.sleep(20)
+			mySSH.command('oc get pods -l app.kubernetes.io/instance=physim', '\$', 6, resync=True)
+			if re.search('No resources found', mySSH.getBefore()):
+				isFinished1 = True
+		if isFinished1 == True:
+			logging.debug('\u001B[1m UnDeployed PhySim Successfully on OC Cluster\u001B[0m')
+		mySSH.command(f'sudo podman rmi default-route-openshift-image-registry.apps.5glab.nsa.eurecom.fr/{self.OCProjectName}/oai-physim:{imageTag}', '\$', 6)
+		mySSH.command('oc delete is oai-physim', '\$', 6)
+		logging.debug('\u001B[1m Deleted the Image and ImageStream\u001B[0m')
+		mySSH.command('oc logout', '\$', 6)
+		mySSH.close()
+		self.AnalyzeLogFile_phySim(HTML)
+		if self.testStatus == False:
+			sys.exit(-1)
+
+	def AnalyzeLogFile_phySim(self, HTML):
+		lIpAddr = self.eNBIPAddress
+		lUserName = self.eNBUserName
+		lPassWord = self.eNBPassword
+		lSourcePath = self.eNBSourceCodePath
+		mySSH = SSH.SSHConnection()
+		mySSH.open(lIpAddr, lUserName, lPassWord)
+		mySSH.command('cd ' + lSourcePath, '\$', 5)
+		mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5)
+		mySSH.command('mkdir -p physim_test_log_' + self.testCase_id, '\$', 5)
+		mySSH.command('cp log/physim_* ' + 'physim_test_log_' + self.testCase_id, '\$', 5)
+		if not os.path.exists(f'./physim_test_logs_{self.testCase_id}'):
+			os.mkdir(f'./physim_test_logs_{self.testCase_id}')
+		mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/physim_test_log_' + self.testCase_id + '/*', './physim_test_logs_' + self.testCase_id)
+		mySSH.command('rm -rf ./physim_test_log_'+ self.testCase_id, '\$', 5)
+		mySSH.command('oc logout', '\$', 6)
+		mySSH.close()
+		# physim test log analysis
+		nextt = 0
+		if (os.path.isfile(f'./physim_test_logs_{self.testCase_id}/physim_test.txt')):
+			with open(f'./physim_test_logs_{self.testCase_id}/physim_test.txt', 'r') as logfile:
+				for line in logfile:
+					if re.search('execution 015', str(line)) or re.search('Bypassing compilation', str(line)):
+						nextt = 1
+					elif nextt == 1:
+						if not re.search('Test Results', str(line)):
+							nextt = 0
+							ret2 = re.search('T[^\n]*', str(line))
+							if ret2 is not None:
+								ret3 = ret2.group()
+								ret3 = ret3.replace("", "")
+					if re.search('execution 015', str(line)):
+						self.testCount[0] += 1
+						testName = line.split()
+						ret1 = re.search('Result = PASS', str(line))
+						if ret1 is not None:
+							self.testResult[testName[1]] = [ret3, 'PASS']
+							self.testCount[1] += 1
+						else:
+							self.testResult[testName[1]] = [ret3, 'FAIL']
+							self.testCount[2] += 1
+		self.testSummary['Nbtests'] = self.testCount[0]
+		self.testSummary['Nbpass'] =  self.testCount[1]
+		self.testSummary['Nbfail'] =  self.testCount[2]
+		if self.testSummary['Nbfail'] == 0:
+			self.testStatus = True
+		HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
+		HTML.CreateHtmlTestRowPhySimTestResult(self.testSummary,self.testResult)
+		logging.info('\u001B[1m Physical Simulator Pass\u001B[0m')
+		return 0
diff --git a/ci-scripts/conf_files/benetel-5g.conf b/ci-scripts/conf_files/benetel-5g.conf
index 5788cd9b365f4632b3abf8b410639e1d688cd8d0..9adead3a68e260fe9e57cd5457edb373eb127432 100644
--- a/ci-scripts/conf_files/benetel-5g.conf
+++ b/ci-scripts/conf_files/benetel-5g.conf
@@ -66,17 +66,7 @@ gNBs =
 
         initialDLBWPk0_1                    = 0;  #for mixed slot
         initialDLBWPmappingType_1           = 0;
-        initialDLBWPstartSymbolAndLength_1  = 53; #this is SS=1,L=5
-
-             initialDLBWPk0_2                    = 0;
-             initialDLBWPmappingType_2           = 0;
-             #this is SS=1,L=12 
-             initialDLBWPstartSymbolAndLength_2  = 54;
-
-             initialDLBWPk0_3                    = 0;
-             initialDLBWPmappingType_3           = 0;
-             #this is SS=1,L=4 //5 (4 is for 43, 5 is for 57)
-             initialDLBWPstartSymbolAndLength_3  = 57; //43; //57;
+        initialDLBWPstartSymbolAndLength_1  = 57; #this is SS=1,L=5
 
   #uplinkConfigCommon 
      #frequencyInfoUL
@@ -102,6 +92,8 @@ gNBs =
           prach_msg1_FDM                                            = 0;
           prach_msg1_FrequencyStart                                 = 74;
           zeroCorrelationZoneConfig                                 = 13;
+          #preambleReceivedTargetPower                               = -118;
+          #preambleReceivedTargetPower                               = -104;
           preambleReceivedTargetPower                               = -108;
 #preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
           preambleTransMax                                          = 6;
diff --git a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf
index f0c1caef7e373102d4666858e6c8e2fcb9ae2e23..8fbbc8a7cd600ff40f38e40b61a0134cedabe63f 100644
--- a/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf
+++ b/ci-scripts/conf_files/gnb.band261.tm1.32PRB.usrpn300.conf
@@ -230,6 +230,7 @@ MACRLCs = (
 	num_cc = 1;
 	tr_s_preference = "local_L1";
 	tr_n_preference = "local_RRC";
+	ulsch_max_slots_inactivity = 1;
         }  
 );
 
diff --git a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf
index f125dcd3b2e245e9833229bb86a960df48fece29..4afbfdcda078bba959b302339fbb5c2126fa803d 100644
--- a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf
+++ b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf
@@ -211,6 +211,7 @@ MACRLCs = (
 	num_cc = 1;
 	tr_s_preference = "local_L1";
 	tr_n_preference = "local_RRC";
+	ulsch_max_slots_inactivity = 1;
 	}
 );
 
@@ -231,7 +232,7 @@ RUs = (
          att_rx         = 0;
          bands          = [7];
          max_pdschReferenceSignalPower = -27;
-         max_rxgain                    = 75;
+         max_rxgain                    = 50;
          eNB_instances  = [0];
          ## beamforming 1x2 matrix: 1 layer x 2 antennas
          bf_weights = [0x00007fff, 0x0000];
diff --git a/ci-scripts/createVM.sh b/ci-scripts/createVM.sh
index ab859c10d761fb27d2fc7e1f4d5503361453eaed..f3f8ddaca28641ddf5b465001661170c11739b58 100755
--- a/ci-scripts/createVM.sh
+++ b/ci-scripts/createVM.sh
@@ -87,7 +87,7 @@ function create_vm {
     echo "VM_CPU              = $VM_CPU"
     echo "VM_DISK             = $VM_DISK GBytes"
 
-    if [[ "$VM_NAME" == *"-enb-usrp"* ]] || [[ "$VM_NAME" == *"-cppcheck"* ]]
+    if [[ "$VM_NAME" == *"-enb-usrp"* ]] || [[ "$VM_NAME" == *"-cppcheck"* ]] || [[ "$VM_NAME" == *"-phy-sim"* ]]
     then
         echo "This VM type is no longer supported in the pipeline framework"
         return
diff --git a/ci-scripts/datalog_rt_stats.yaml b/ci-scripts/datalog_rt_stats.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3680d2a19bdb7f484ab061dfd33db0a65d0a48b5
--- /dev/null
+++ b/ci-scripts/datalog_rt_stats.yaml
@@ -0,0 +1,33 @@
+#this is a configuration file
+#used to build real time processing statistics 
+#for 5G NR phy test (gNB terminate)
+Title : Processing Time (us)
+ColNames :
+  - Metric
+  - Average
+  - Max
+  - Average vs Reference Deviation (Reference Value ; Acceptability Threshold)
+Ref : 
+  feprx : 60.0
+  feptx_prec : 8.0
+  feptx_ofdm : 85.0
+  feptx_total : 75.0
+  L1 Tx processing : 300.0
+  DLSCH encoding : 230.0
+  L1 Rx processing : 175.0
+  PUSCH inner-receiver : 100.0
+  PUSCH decoding : 140.0 
+  DL & UL scheduling timing stats : 15.0
+  UL Indication : 20.0
+Threshold :
+  feprx : 1.25
+  feptx_prec : 1.25
+  feptx_ofdm : 1.25
+  feptx_total : 1.25
+  L1 Tx processing : 1.25
+  DLSCH encoding : 1.25
+  L1 Rx processing : 1.25
+  PUSCH inner-receiver : 1.25
+  PUSCH decoding : 1.25
+  DL & UL scheduling timing stats : 1.25
+  UL Indication : 1.25
diff --git a/ci-scripts/html.py b/ci-scripts/html.py
index a0ac6385730104e5b965fc772f81b18a7da56733..de4e049adb9059c860bc62918e2ec9b4034da1b0 100644
--- a/ci-scripts/html.py
+++ b/ci-scripts/html.py
@@ -47,7 +47,7 @@ import constants as CONST
 class HTMLManagement():
 
 	def __init__(self):
-	
+
 		self.htmlFile = ''
 		self.htmlHeaderCreated = False
 		self.htmlFooterCreated = False
@@ -86,13 +86,13 @@ class HTMLManagement():
 #-----------------------------------------------------------
 # Setters and Getters
 #-----------------------------------------------------------
-	
+
 	def SethtmlUEConnected(self, nbUEs):
 		if nbUEs > 0:
 			self.htmlUEConnected = nbUEs
 		else:
 			self.htmlUEConnected = 1
-	
+
 
 
 #-----------------------------------------------------------
@@ -412,7 +412,12 @@ class HTMLManagement():
 			for image in collectInfo:
 				files = collectInfo[image]
         		# TabHeader for image logs on built shared and target images
-				self.htmlFile.write('      <tr bgcolor = "#F0F0F0" >\n')
+				if allImagesSize[image].count('unknown') > 0:
+					self.htmlFile.write('      <tr bgcolor = "orange" >\n')
+				elif allImagesSize[image].count('Build Failed') > 0:
+					self.htmlFile.write('      <tr bgcolor = "red" >\n')
+				else:
+					self.htmlFile.write('      <tr bgcolor = "#F0F0F0" >\n')
 				self.htmlFile.write('        <td colspan=' + str(5+self.htmlUEConnected) + '><b> ---- ' + image  + ' IMAGE STATUS ----> Size ' + allImagesSize[image] + ' </b></td>\n')
 				self.htmlFile.write('      </tr>\n')
 				self.htmlFile.write('      <tr bgcolor = "#33CCFF" >\n')
@@ -431,21 +436,54 @@ class HTMLManagement():
 						self.htmlFile.write('        <td bgcolor = "green" >' + str(parameters['errors'])  + '</td>\n')
 					else:
 						self.htmlFile.write('        <td bgcolor = "red" >' + str(parameters['errors'])  + '</td>\n')
-					if (parameters['warnings'] == 0):
+					if (parameters['errors'] > 0):
+						self.htmlFile.write('        <td bgcolor = "red" >' + str(parameters['warnings'])  + '</td>\n')
+					elif (parameters['warnings'] == 0):
 						self.htmlFile.write('        <td bgcolor = "green" >' + str(parameters['warnings'])  + '</td>\n')
 					elif ((parameters['warnings'] > 0) and (parameters['warnings'] <= 20)):
 						self.htmlFile.write('        <td bgcolor = "orange" >' + str(parameters['warnings'])  + '</td>\n')
 					else:
-						self.htmlFile.write('        <td bgcolor = "red" >' + str(parameters['warnings'])  + '</td>\n')	
+						self.htmlFile.write('        <td bgcolor = "red" >' + str(parameters['warnings'])  + '</td>\n')
 					if (parameters['errors'] == 0) and (parameters['warnings'] == 0):
 						self.htmlFile.write('        <th colspan=' + str(1+self.htmlUEConnected) + ' bgcolor = "green" ><font color="white">OK </font></th>\n')
 					elif (parameters['errors'] == 0) and ((parameters['warnings'] > 0) and (parameters['warnings'] <= 20)):
 						self.htmlFile.write('        <th colspan=' + str(1+self.htmlUEConnected) + ' bgcolor = "orange" ><font color="white">OK </font></th>\n')
 					else:
-						self.htmlFile.write('        <th colspan=' + str(1+self.htmlUEConnected) + ' bgcolor = "red" > NOT OK  </th>\n')	
+						self.htmlFile.write('        <th colspan=' + str(1+self.htmlUEConnected) + ' bgcolor = "red" > NOT OK  </th>\n')
 					self.htmlFile.write('      </tr>\n')
 		self.htmlFile.close()
 
+	#for the moment it is limited to 4 columns, to be made generic later
+	def CreateHtmlDataLogTable(self, DataLog):
+		if (self.htmlFooterCreated or (not self.htmlHeaderCreated)):
+			return
+		self.htmlFile = open('test_results.html', 'a')
+		
+        # TabHeader 
+		self.htmlFile.write('      <tr bgcolor = "#F0F0F0" >\n')
+		self.htmlFile.write('        <td colspan=' + str(5+self.htmlUEConnected) + '><b> ---- ' + DataLog['Title'] + ' ---- </b></td>\n')
+		self.htmlFile.write('      </tr>\n')
+		self.htmlFile.write('      <tr bgcolor = "#33CCFF" >\n')
+		self.htmlFile.write('        <th colspan="3">'+ DataLog['ColNames'][0] +'</th>\n')
+		self.htmlFile.write('        <th>' + DataLog['ColNames'][1] + '</th>\n')
+		self.htmlFile.write('        <th>' + DataLog['ColNames'][2] + '</th>\n')
+		self.htmlFile.write('        <th colspan=' + str(1+self.htmlUEConnected) + '>'+ DataLog['ColNames'][3] +'</th>\n')
+		self.htmlFile.write('      </tr>\n')
+
+		for k in DataLog['Data']:
+			# TestRow 
+			self.htmlFile.write('      <tr>\n')
+			self.htmlFile.write('        <td colspan="3" bgcolor = "lightcyan" >' + k  + ' </td>\n')				
+			self.htmlFile.write('        <td bgcolor = "lightcyan" >' + DataLog['Data'][k][0]  + ' </td>\n')
+			self.htmlFile.write('        <td bgcolor = "lightcyan" >' + DataLog['Data'][k][1]  + ' </td>\n')
+			if float(DataLog['Data'][k][2])> DataLog['Threshold'][k]:
+				self.htmlFile.write('        <th bgcolor = "red" >' + DataLog['Data'][k][2]  + ' (Ref = ' + str(DataLog['Ref'][k]) + ' ; Thres = '   +str(DataLog['Threshold'][k])+') ' + '</th>\n')
+			else:
+				self.htmlFile.write('        <th bgcolor = "green" ><font color="white">' + DataLog['Data'][k][2]  + ' (Ref = ' + str(DataLog['Ref'][k]) + ' ; Thres = '   +str(DataLog['Threshold'][k])+') ' + '</th>\n')					
+			self.htmlFile.write('      </tr>\n')
+		self.htmlFile.close()
+
+
 	def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue):
 		if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)):
 			self.htmlFile = open('test_results.html', 'a')
@@ -562,5 +600,57 @@ class HTMLManagement():
 			self.htmlFile.write('        <td colspan=' + str(2+self.htmlUEConnected) + '>' + str(CCR.nbWrongScanfArg[vId]) + '</td>\n')
 			self.htmlFile.write('      </tr>\n')
 			vId += 1
-            
+
+	def CreateHtmlTestRowPhySimTestResult(self, testSummary, testResult):
+		if (self.htmlFooterCreated or (not self.htmlHeaderCreated)):
+			return
+		self.htmlFile = open('test_results.html', 'a')
+		if bool(testResult) == False and bool(testSummary) == False:
+			self.htmlFile.write('      <tr bgcolor = "red" >\n')
+			self.htmlFile.write('        <td colspan=' + str(5+self.htmlUEConnected) + '><b> ----PHYSIM TESTING FAILED - Unable to recover the test logs ---- </b></td>\n')
+			self.htmlFile.write('      </tr>\n')
+		else:
+		# Tab header
+			self.htmlFile.write('      <tr bgcolor = "#F0F0F0" >\n')
+			self.htmlFile.write('        <td colspan=' + str(5+self.htmlUEConnected) + '><b> ---- PHYSIM TEST SUMMARY---- </b></td>\n')
+			self.htmlFile.write('      </tr>\n')
+			self.htmlFile.write('      <tr bgcolor = "#33CCFF" >\n')
+			self.htmlFile.write('        <th colspan="2">LogFile Name</th>\n')
+			self.htmlFile.write('        <th colspan="2">Nb Tests</th>\n')
+			self.htmlFile.write('        <th>Nb Failure</th>\n')
+			self.htmlFile.write('        <th>Nb Pass</th>\n')
+			self.htmlFile.write('      </tr>\n')
+			self.htmlFile.write('      <tr>\n')
+			self.htmlFile.write('        <td colspan="2" bgcolor = "lightcyan" > physim_test.txt  </td>\n')
+			self.htmlFile.write('        <td colspan="2" bgcolor = "lightcyan" >' + str(testSummary['Nbtests']) + ' </td>\n')
+			if testSummary['Nbfail'] == 0:
+				self.htmlFile.write('        <td bgcolor = "lightcyan" >' + str(testSummary['Nbfail']) + ' </td>\n')
+			else:
+				self.htmlFile.write('        <td bgcolor = "red" >' + str(testSummary['Nbfail']) + ' </td>\n')
+			self.htmlFile.write('        <td gcolor = "lightcyan" >' + str(testSummary['Nbpass']) + ' </td>\n')
+			self.htmlFile.write('      </tr>\n')
+			self.htmlFile.write('      <tr bgcolor = "#F0F0F0" >\n')
+			self.htmlFile.write('        <td colspan=' + str(5+self.htmlUEConnected) + '><b> ---- PHYSIM TEST DETAIL INFO---- </b></td>\n')
+			self.htmlFile.write('      </tr>\n')
+			self.htmlFile.write('      <tr bgcolor = "#33CCFF" >\n')
+			self.htmlFile.write('        <th colspan="2">Test Name</th>\n')
+			self.htmlFile.write('        <th colspan="2">Test Description</th>\n')
+			self.htmlFile.write('        <th colspan=' + str(1+self.htmlUEConnected) + '>Result</th>\n')
+			self.htmlFile.write('      </tr>\n')
+			y = ''
+			for key, value in testResult.items():
+				x = key.split(".")
+				if x[0] != y:
+					self.htmlFile.write('      <tr bgcolor = "lightgreen" >\n')
+					self.htmlFile.write('        <td style="text-align: center;" colspan=' + str(5+self.htmlUEConnected) + '><b>"' + x[0] + '" series </b></td>\n')
+					self.htmlFile.write('      </tr>\n')
+					y = x[0]
+				self.htmlFile.write('      <tr>\n')
+				self.htmlFile.write('        <td colspan="2" bgcolor = "lightcyan" >' + key  + ' </td>\n')
+				self.htmlFile.write('        <td colspan="2" bgcolor = "lightcyan" >' + value[0]  + '</td>\n')
+				if 'PASS' in value:
+					self.htmlFile.write('        <td colspan=' + str(1+self.htmlUEConnected) + ' bgcolor = "green" >' + value[1]  + '</td>\n')
+				else:
+					self.htmlFile.write('        <td colspan=' + str(1+self.htmlUEConnected) + ' bgcolor = "red" >' + value[1]  + '</td>\n')
+
 		self.htmlFile.close()
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index f13df9beb5bb4ea2942563c8a05ddd5fb7bf4c71..961bb16975f7503b2ce18d59b22e30caa535f5cd 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -43,7 +43,7 @@ import cls_physim               #class PhySim for physical simulators build and
 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 cls_static_code_analysis #class for static code analysis
-
+import cls_physim1          #class PhySim for physical simulators deploy and run
 
 import sshconnection 
 import epc
@@ -380,6 +380,7 @@ RAN = ran.RANManagement()
 HTML = html.HTMLManagement()
 CONTAINERS = cls_containerize.Containerize()
 SCA = cls_static_code_analysis.StaticCodeAnalysis()
+PHYSIM = cls_physim1.PhySim()
 
 ldpc=cls_physim.PhySim()    #create an instance for LDPC test using GPU or CPU build
 
@@ -390,7 +391,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,CONTAINERS,HELP,SCA)
+py_param_file_present, py_params, mode = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,EPC,ldpc,CONTAINERS,HELP,SCA,PHYSIM)
 
 
 
@@ -745,6 +746,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 					CONTAINERS.UndeployObject(HTML, RAN)
 				elif action == 'Cppcheck_Analysis':
 					SCA.CppCheckAnalysis(HTML)
+				elif action == 'Deploy_Run_PhySim':
+					PHYSIM.Deploy_PhySim(HTML)
 				else:
 					sys.exit('Invalid class (action) from xml')
 				if not RAN.prematureExit:
diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py
index f1f79a24358f7bc4cc4bfda987ec90047e9d2fd3..f5f53c20b7e9ecd501e704c84affe583e3fb2502 100644
--- a/ci-scripts/ran.py
+++ b/ci-scripts/ran.py
@@ -37,6 +37,8 @@ import logging
 import os
 import time
 from multiprocessing import Process, Lock, SimpleQueue
+import yaml
+
 
 #-----------------------------------------------------------
 # OAI Testing modules
@@ -90,6 +92,7 @@ class RANManagement():
 		self.testCase_id = ''
 		self.epcPcapFile = ''
 		self.runtime_stats= ''
+		self.datalog_rt_stats={}
 
 
 
@@ -633,6 +636,8 @@ class RANManagement():
 					HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
 			else:
 				HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+		if len(self.datalog_rt_stats)!=0:
+			HTML.CreateHtmlDataLogTable(self.datalog_rt_stats)
 		self.eNBmbmsEnables[int(self.eNB_instance)] = False
 		self.eNBstatuses[int(self.eNB_instance)] = -1
 
@@ -699,6 +704,21 @@ class RANManagement():
 		#count "problem receiving samples" msg
 		pb_receiving_samples_cnt = 0
 	
+		#the datalog config file has to be loaded
+		datalog_rt_stats_file='datalog_rt_stats.yaml'
+		if (os.path.isfile(datalog_rt_stats_file)):
+			yaml_file=datalog_rt_stats_file
+		elif (os.path.isfile('ci-scripts/'+datalog_rt_stats_file)):
+			yaml_file='ci-scripts/'+datalog_rt_stats_file
+		else:
+			logging.error("Datalog RT stats yaml file cannot be found")
+			sys.exit("Datalog RT stats yaml file cannot be found")
+
+		with open(yaml_file,'r') as f:
+			datalog_rt_stats = yaml.load(f,Loader=yaml.FullLoader)
+		rt_keys = datalog_rt_stats['Ref'] #we use the keys from the Ref field  
+
+
 		for line in enb_log_file.readlines():
 			# Runtime statistics
 			result = re.search('Run time:' ,str(line))
@@ -857,21 +877,21 @@ class RANManagement():
 			#keys below are the markers we are loooking for, loop over this keys list
 			#everytime these markers are found in the log file, the previous ones are overwritten in the dict
 			#eventually we record and print only the last occurence 
-			keys = {'UE ID','dlsch_rounds','dlsch_total_bytes','ulsch_rounds','ulsch_total_bytes_scheduled', 'scheduling timing stats'}
+			keys = {'UE ID','dlsch_rounds','dlsch_total_bytes','ulsch_rounds','ulsch_total_bytes_scheduled'}
 			for k in keys:
 				result = re.search(k, line)
 				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())
-			#real time statistics
-			#same method as above
-			keys = {'feprx','feptx_prec','feptx_ofdm','feptx_total','L1 Tx processing','DLSCH encoding','L1 Rx processing','PUSCH inner-receiver','PUSCH decoding'}   
-			for k in keys:
+			#real time statistics for gNB
+			for k in rt_keys:
 				result = re.search(k, line)     
 				if result is not None:
 					#remove 1- all useless char before relevant info  2- trailing char
+					line=line.replace('[0m','')
 					tmp=re.match(rf'^.*?(\b{k}\b.*)',line.rstrip()) #from python 3.6 we can use literal string interpolation for the variable k, using rf' in the regex 
 					real_time_stats[k]=tmp.group(1)
+
 			#count "problem receiving samples" msg
 			result = re.search('\[PHY\]\s+problem receiving samples', str(line))
 			if result is not None:
@@ -920,13 +940,23 @@ class RANManagement():
 					logging.debug(dlsch_ulsch_stats[key])
 				htmleNBFailureMsg += statMsg
 
-			#real time statistics statistics
+			#real time statistics
+			datalog_rt_stats['Data']={}
 			if len(real_time_stats)!=0: #check if dictionary is not empty
-				statMsg=''
-				for key in real_time_stats: #for each dictionary key
-					statMsg += real_time_stats[key] + '\n' 
-					logging.debug(real_time_stats[key])
-				htmleNBFailureMsg += statMsg
+				for k in real_time_stats:
+					tmp=re.match(r'^(?P<metric>.*):\s+(?P<avg>\d+\.\d+) us;\s+\d+;\s+(?P<max>\d+\.\d+) us;',real_time_stats[k])
+					if tmp is not None:
+						metric=tmp.group('metric')
+						avg=float(tmp.group('avg'))
+						max=float(tmp.group('max'))
+						datalog_rt_stats['Data'][metric]=["{:.0f}".format(avg),"{:.0f}".format(max),"{:.2f}".format(avg/datalog_rt_stats['Ref'][metric])]
+				#once all metrics are collected, store the data as a class attribute to build a dedicated HTML table afterward
+				self.datalog_rt_stats=datalog_rt_stats
+				#check if there is a fail => will render the test as failed
+				for k in datalog_rt_stats['Data']:
+					if float(datalog_rt_stats['Data'][k][2])> datalog_rt_stats['Threshold'][k]: #condition for fail : avg/ref is greater than the fixed threshold
+						#setting prematureExit is ok although not the best option
+						self.prematureExit=True
 			else:
 				statMsg = 'No real time stats found in the log file\n'
 				logging.debug('No real time stats found in the log file')
diff --git a/ci-scripts/reportBuildLocally.sh b/ci-scripts/reportBuildLocally.sh
index b46ade903f2d36ce49e5d39e5b813863f710af70..eab005c7408cb3ad4a6c28020d1d65e29b62abd4 100755
--- a/ci-scripts/reportBuildLocally.sh
+++ b/ci-scripts/reportBuildLocally.sh
@@ -568,33 +568,6 @@ function report_build {
 
     echo "   <h2>Ubuntu 16.04 LTS -- Summary</h2>" >> ./build_results.html
 
-    if [ -f ./archives/cppcheck/cppcheck.xml ]
-    then
-        sca_summary_table_header ./archives/cppcheck/cppcheck.xml "OAI Static Code Analysis with CPPCHECK"
-        sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Uninitialized variable" uninitvar
-        sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Uninitialized struct member" uninitStructMember
-        sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Memory leak" memleak
-        sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Memory is freed twice" doubleFree
-        sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Resource leak" resourceLeak
-        sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Possible null pointer dereference" nullPointer
-        sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Array access  out of bounds" arrayIndexOutOfBounds
-        sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Buffer is accessed out of bounds" bufferAccessOutOfBounds
-        sca_summary_table_row ./archives/cppcheck/cppcheck.xml "Expression depends on order of evaluation of side effects" unknownEvaluationOrder
-        sca_summary_table_footer ./archives/cppcheck/cppcheck.xml
-    fi
-
-#    summary_table_header "OAI Build: 4G LTE eNB -- USRP option" ./archives/enb_usrp
-#    summary_table_row "LTE SoftModem - Release 15" ./archives/enb_usrp/lte-softmodem.Rel15.txt "Built target lte-softmodem" ./enb_usrp_row1.html
-#    summary_table_row "Coding - Release 15" ./archives/enb_usrp/coding.Rel15.txt "Built target coding" ./enb_usrp_row2.html
-#    summary_table_row "OAI USRP device if - Release 15" ./archives/enb_usrp/oai_usrpdevif.Rel15.txt "Built target oai_usrpdevif" ./enb_usrp_row3.html
-#    summary_table_row "OAI ETHERNET transport - Release 15" ./archives/enb_usrp/oai_eth_transpro.Rel15.txt "Built target oai_eth_transpro" ./enb_usrp_row4.html
-#    summary_table_row "Parameters Lib Config - Release 15" ./archives/enb_usrp/params_libconfig.Rel15.txt "Built target params_libconfig" ./enb_usrp_row5.html
-#    summary_table_row "NASMESH - Release 15" ./archives/enb_usrp/nasmesh.Rel15.txt "Built target nasmesh" ./enb_usrp_row6.html
-#    summary_table_row "RB Tool - Release 15" ./archives/enb_usrp/rb_tool.Rel15.txt "Built target rb_tool" ./enb_usrp_row7.html
-#    summary_table_row "RF Simulator - Release 15" ./archives/enb_usrp/rfsimulator.Rel15.txt "Built target rfsimulator" ./enb_usrp_row8.html
-#    summary_table_row "TCP Bridge - Release 15" ./archives/enb_usrp/tcp_bridge_oai.Rel15.txt "Built target tcp_bridge_oai" ./enb_usrp_row9.html
-#    summary_table_footer
-#
     summary_table_header "OAI Build: 4G LTE eNB -- USRP option" ./archives/enb_eth
     summary_table_row "LTE SoftModem - Release 15" ./archives/enb_eth/lte-softmodem.Rel15.txt "Built target lte-softmodem" ./enb_eth_row1.html
     summary_table_row "Coding - Release 15" ./archives/enb_eth/coding.Rel15.txt "Built target coding" ./enb_eth_row2.html
@@ -637,48 +610,6 @@ function report_build {
     summary_table_row "NVRAM - Release 15" ./archives/basic_sim/nvram.Rel15.txt "Built target nvram" ./basic_sim_row13.html
     summary_table_footer
 
-    summary_table_header "OAI Build: 4G LTE / 5G NR Physical simulators option" ./archives/phy_sim
-    summary_table_row "LTE DL Simulator - Release 15" ./archives/phy_sim/dlsim.Rel15.txt "Built target dlsim" ./phy_sim_row1.html
-    summary_table_row "LTE UL Simulator - Release 15" ./archives/phy_sim/ulsim.Rel15.txt "Built target ulsim" ./phy_sim_row2.html
-    summary_table_row "Coding - Release 15" ./archives/phy_sim/coding.Rel15.txt "Built target coding" ./phy_sim_row3.html
-    if [ -f ./archives/phy_sim/ldpctest.Rel15.txt ]
-    then
-        summary_table_row "NR LDPC Test - Release 15" ./archives/phy_sim/ldpctest.Rel15.txt "Built target ldpctest" ./phy_sim_row4.html
-    fi
-    if [ -f ./archives/phy_sim/polartest.Rel15.txt ]
-    then
-        summary_table_row "NR Polar Test - Release 15" ./archives/phy_sim/polartest.Rel15.txt "Built target polartest" ./phy_sim_row5.html
-    fi
-    if [ -f ./archives/phy_sim/nr_pbchsim.Rel15.txt ]
-    then
-        summary_table_row "NR PBCH Test - Release 15" ./archives/phy_sim/nr_pbchsim.Rel15.txt "Built target nr_pbchsim" ./phy_sim_row6.html
-    fi
-    if [ -f ./archives/phy_sim/nr_dlschsim.Rel15.txt ]
-    then
-        summary_table_row "NR DLSCH Test - Release 15" ./archives/phy_sim/nr_dlschsim.Rel15.txt "Built target nr_dlschsim" ./phy_sim_row7.html
-    fi
-    if [ -f ./archives/phy_sim/nr_pucchsim.Rel15.txt ]
-    then
-        summary_table_row "NR PUCCH Test - Release 15" ./archives/phy_sim/nr_pucchsim.Rel15.txt "Built target nr_pucchsim" ./phy_sim_row8.html
-    fi
-    if [ -f ./archives/phy_sim/smallblocktest.Rel15.txt ]
-    then
-        summary_table_row "NR Small Block Test - Release 15" ./archives/phy_sim/smallblocktest.Rel15.txt "Built target smallblocktest" ./phy_sim_row9.html
-    fi
-    if [ -f ./archives/phy_sim/nr_dlsim.Rel15.txt ]
-    then
-        summary_table_row "NR DL Sim Test - Release 15" ./archives/phy_sim/nr_dlsim.Rel15.txt "Built target nr_dlsim" ./phy_sim_row10.html
-    fi
-    if [ -f ./archives/phy_sim/nr_ulschsim.Rel15.txt ]
-    then
-        summary_table_row "NR ULSCH Test - Release 15" ./archives/phy_sim/nr_ulschsim.Rel15.txt "Built target nr_ulschsim" ./phy_sim_row11.html
-    fi
-    if [ -f ./archives/phy_sim/nr_ulsim.Rel15.txt ]
-    then
-        summary_table_row "NR UL Sim Test - Release 15" ./archives/phy_sim/nr_ulsim.Rel15.txt "Built target nr_ulsim" ./phy_sim_row12.html
-    fi
-    summary_table_footer
-
     if [ -f archives/gnb_usrp/nr-softmodem.Rel15.txt ]
     then
         summary_table_header "OAI Build: 5G NR gNB -- USRP option" ./archives/gnb_usrp
@@ -721,13 +652,6 @@ function report_build {
     echo "   <button data-toggle=\"collapse\" data-target=\"#oai-compilation-details\">Details for Compilation Errors and Warnings </button>" >> ./build_results.html
     echo "   <div id=\"oai-compilation-details\" class=\"collapse\">" >> ./build_results.html
 
-#    if [ -f ./enb_usrp_row1.html ] || [ -f ./enb_usrp_row2.html ] || [ -f ./enb_usrp_row3.html ] || [ -f ./enb_usrp_row4.html ]
-#    then
-#        for DETAILS_TABLE in `ls ./enb_usrp_row*.html`
-#        do
-#            cat $DETAILS_TABLE >> ./build_results.html
-#        done
-#    fi
     if [ -f ./enb_eth_row1.html ] || [ -f ./enb_eth_row2.html ] || [ -f ./enb_eth_row3.html ] || [ -f ./enb_eth_row4.html ] || [ -f ./enb_eth_row5.html ] || [ -f ./enb_eth_row6.html ] || [ -f ./enb_eth_row7.html ] || [ -f ./enb_eth_row8.html ] || [ -f ./enb_eth_row9.html ]
     then
         for DETAILS_TABLE in `ls ./enb_eth_row*.html`
@@ -749,13 +673,6 @@ function report_build {
             cat $DETAILS_TABLE >> ./build_results.html
         done
     fi
-    if [ -f ./phy_sim_row1.html ] || [ -f ./phy_sim_row2.html ] || [ -f ./phy_sim_row3.html ] || [ -f ./phy_sim_row4.html ] || [ -f ./phy_sim_row5.html ] || [ -f ./phy_sim_row6.html ] || [ -f ./phy_sim_row7.html ] || [ -f ./phy_sim_row8.html ]
-    then
-        for DETAILS_TABLE in `ls ./phy_sim_row*.html`
-        do
-            cat $DETAILS_TABLE >> ./build_results.html
-        done
-    fi
     if [ -f ./gnb_usrp_row1.html ] || [ -f ./gnb_usrp_row2.html ] || [ -f ./gnb_usrp_row3.html ] || [ -f ./gnb_usrp_row4.html ]
     then 
         for DETAILS_TABLE in `ls ./gnb_usrp_row*.html`
@@ -770,13 +687,6 @@ function report_build {
             cat $DETAILS_TABLE >> ./build_results.html
         done
     fi
-    if [ -f ./enb_usrp_rh_row1.html ] || [ -f ./enb_usrp_rh_row2.html ] || [ -f ./enb_usrp_rh_row3.html ] || [ -f ./enb_usrp_rh_row4.html ]
-    then
-        for DETAILS_TABLE in `ls ./enb_usrp_rh_row*.html`
-        do
-            cat $DETAILS_TABLE >> ./build_results.html
-        done
-    fi
     rm -f ./*_row*.html
 
     echo "   </div>" >> ./build_results.html
diff --git a/ci-scripts/runTestOnVM.sh b/ci-scripts/runTestOnVM.sh
index 6725d2f62bb94a60cb99cc6e9b3a4da7833b89da..cb751c3830f6b9aa78a9febc10acd96fda7dd35c 100755
--- a/ci-scripts/runTestOnVM.sh
+++ b/ci-scripts/runTestOnVM.sh
@@ -1478,13 +1478,13 @@ function run_test_on_vm {
         echo "$VM_NAME has for IP addr = $VM_IP_ADDR"
     fi
 
-    if [ "$RUN_OPTIONS" == "none" ]
+    if [ "$RUN_OPTIONS" == "none" ] || [[ $RUN_OPTIONS =~ .*run_exec_autotests.* ]]
     then
         echo "No run on VM testing for this variant currently"
         return
     fi
 
-    if [[ $RUN_OPTIONS =~ .*run_exec_autotests.* ]]
+    if [[ $RUN_OPTIONS =~ .*run_XXXX_autotests.* ]]
     then
         echo "############################################################"
         echo "Running test script on VM ($VM_NAME)"
diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py
index 5bfe5da70f94b3abf104957514158eaa482ec369..4a0992436b2844b40500877ebb93d9833cdb3bfb 100644
--- a/ci-scripts/sshconnection.py
+++ b/ci-scripts/sshconnection.py
@@ -111,11 +111,20 @@ class SSHConnection():
 		self.sshresponse = self.ssh.expect(expected)
 		return self.sshresponse
 
-	def command(self, commandline, expectedline, timeout):
-		logging.debug(commandline)
+	def command(self, commandline, expectedline, timeout, silent=False, resync=False):
+		if not silent:
+			logging.debug(commandline)
 		self.ssh.timeout = timeout
-		self.ssh.sendline(commandline)
-		self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT])
+		# Nasty patch when pexpect output is out of sync.
+		# Much pronounced when running back-to-back-back oc commands
+		if resync:
+			self.ssh.send(commandline)
+			self.ssh.expect([commandline, pexpect.TIMEOUT])
+			self.ssh.send('\r\n')
+			self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT])
+		else:
+			self.ssh.sendline(commandline)
+			self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT])
 		if self.sshresponse == 0:
 			return 0
 		elif self.sshresponse == 1:
diff --git a/ci-scripts/waitBuildOnVM.sh b/ci-scripts/waitBuildOnVM.sh
index f7e300edf452bbc93203168073e30d8b01ab1799..4a604a1fe94d8d1c466608a76fc6a174e0f18583 100755
--- a/ci-scripts/waitBuildOnVM.sh
+++ b/ci-scripts/waitBuildOnVM.sh
@@ -47,7 +47,7 @@ function wait_on_vm_build {
     echo "ARCHIVES_LOC        = $ARCHIVES_LOC"
     echo "BUILD_OPTIONS       = $BUILD_OPTIONS"
 
-    if [[ "$VM_NAME" == *"-enb-usrp"* ]] || [[ "$VM_NAME" == *"-cppcheck"* ]]
+    if [[ "$VM_NAME" == *"-enb-usrp"* ]] || [[ "$VM_NAME" == *"-cppcheck"* ]] || [[ "$VM_NAME" == *"-phy-sim"* ]]
     then
         echo "This VM type is no longer supported in the pipeline framework"
         return
@@ -93,7 +93,7 @@ function wait_on_vm_build {
 }
 
 function check_on_vm_build {
-    if [[ "$VM_NAME" == *"-enb-usrp"* ]] || [[ "$VM_NAME" == *"-cppcheck"* ]]
+    if [[ "$VM_NAME" == *"-enb-usrp"* ]] || [[ "$VM_NAME" == *"-cppcheck"* ]] || [[ "$VM_NAME" == *"-phy-sim"* ]]
     then
         echo "This VM type is no longer supported in the pipeline framework"
         return
diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml
index de16116124c8f3999e58a8b47f1e7a7bd0419ccd..2282e101e58467d6c0d09a720d2e31a8ef3a4542 100755
--- a/ci-scripts/xml_class_list.yml
+++ b/ci-scripts/xml_class_list.yml
@@ -38,3 +38,4 @@
   - Deploy_Object
   - Undeploy_Object
   - Cppcheck_Analysis
+  - Deploy_Run_PhySim
\ No newline at end of file
diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run.xml
index 00610d430eb223e17516d0e4f643537bd8a5570d..9e798afdc488ca4d13b4c88d7cd4d1976fbbdfb7 100644
--- a/ci-scripts/xml_files/gnb_phytest_usrp_run.xml
+++ b/ci-scripts/xml_files/gnb_phytest_usrp_run.xml
@@ -24,7 +24,7 @@
         <htmlTabRef>gNB-PHY-Test</htmlTabRef>
         <htmlTabName>Run-gNB-PHY-Test</htmlTabName>
         <htmlTabIcon>tasks</htmlTabIcon>	
-	<repeatCount>2</repeatCount>
+	<repeatCount>3</repeatCount>
 	<TestCaseRequestedList>
 090101 000001 090109
 	</TestCaseRequestedList>
@@ -40,7 +40,7 @@
 	<testCase id="000001">
 		<class>IdleSleep</class>
 		<desc>Sleep</desc>
-		<idle_sleep_time_in_sec>180</idle_sleep_time_in_sec>
+		<idle_sleep_time_in_sec>300</idle_sleep_time_in_sec>
 	</testCase>
 
 
diff --git a/ci-scripts/xml_files/physim_deploy_run.xml b/ci-scripts/xml_files/physim_deploy_run.xml
new file mode 100644
index 0000000000000000000000000000000000000000..63152c1fb55808c2169b62b09bf4a0162d2b91ca
--- /dev/null
+++ b/ci-scripts/xml_files/physim_deploy_run.xml
@@ -0,0 +1,37 @@
+<!--
+
+ 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>Physical Simulators Check</htmlTabName>
+	<htmlTabIcon>wrench</htmlTabIcon>
+	<TestCaseRequestedList>
+ 010201
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="010201">
+		<class>Deploy_Run_PhySim</class>
+		<desc>Deploy and run physical simulator on openshift</desc>
+	</testCase>
+
+</testCaseList>
diff --git a/docker/Dockerfile.eNB.rhel8.2 b/docker/Dockerfile.eNB.rhel8.2
index aa8b9aa228962ed012e39d2bb21a02e0a62d2b8f..cf012502e07feba1c0bd8d07a04413325c94ea56 100644
--- a/docker/Dockerfile.eNB.rhel8.2
+++ b/docker/Dockerfile.eNB.rhel8.2
@@ -25,7 +25,7 @@
 #
 #---------------------------------------------------------------------
 
-FROM localhost/ran-build:latest AS enb-build 
+FROM ran-build:latest AS enb-build
 
 RUN rm -Rf /oai-ran
 WORKDIR /oai-ran
@@ -37,10 +37,9 @@ RUN /bin/sh oaienv && \
     mkdir -p log && \
     ./build_oai --eNB --ninja -w USRP --verbose-ci
 
-# debug
-#RUN ldconfig -v && ldd /oai-ran/targets/bin/lte-softmodem.Rel15
-#RUN ls -ls /oai-ran/targets/bin
-#RUN ls -ls /oai-ran/cmake_targets/ran_build/build/*.so
+RUN yum install -y python3-pip && \
+    pip3 install --ignore-installed pyyaml && \
+    python3 ./docker/scripts/generateTemplate.py ./docker/scripts/enb_parameters.yaml
 
 #start from scratch for target executable
 FROM registry.access.redhat.com/ubi8/ubi:latest as oai-enb
@@ -59,6 +58,7 @@ RUN yum update -y && \
 
 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 .
@@ -93,34 +93,16 @@ COPY --from=enb-build /usr/local/lib64/libuhd.so.4.0.0 /usr/local/lib64
 
 RUN ldconfig
 
-#debug
-#RUN ldd /usr/local/lib/liboai_eth_transpro.so.Rel15
-#RUN ldd /usr/local/lib/libtcp_bridge_oai.so.Rel15
-#RUN ldd /usr/local/lib/librfsimulator.so.Rel15
-#RUN ldd /usr/local/lib/liboai_usrpdevif.so.Rel15
-#RUN ldd /usr/local/lib/libcoding.so
-#RUN ldd /usr/local/lib/libparams_libconfig.so
-#RUN ldd /usr/local/lib/libdfts.so
-#RUN ldd /usr/local/lib/liboai_iqplayer.so
-#RUN ldd /opt/oai-enb/bin/lte-softmodem.Rel15
-
 # 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
-#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)
+# 2152 --> S1U, GTP/UDP
+# 36412 --> S1C, SCTP/UDP
+# 36422 --> X2C, SCTP/UDP
+EXPOSE 2152/udp 36412/udp 36422/udp
 
-#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.eNB.ubuntu18 b/docker/Dockerfile.eNB.ubuntu18
index 95d7194c317e6c38fceefbfebfd93fc64e649ca0..1f276094d5d9e5284d38ea38fcd342632fd9e554 100644
--- a/docker/Dockerfile.eNB.ubuntu18
+++ b/docker/Dockerfile.eNB.ubuntu18
@@ -41,11 +41,6 @@ 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
-#RUN ls -ls /oai-ran/cmake_targets/ran_build/build/*.so
-
 #start from scratch for target executable
 FROM ubuntu:bionic as oai-enb
 ENV DEBIAN_FRONTEND=noninteractive
@@ -98,17 +93,6 @@ COPY --from=enb-build /usr/local/lib/libprotobuf-c.so.1 .
 
 RUN ldconfig
 
-#debug
-#RUN ldd /usr/local/lib/liboai_eth_transpro.so.Rel15
-#RUN ldd /usr/local/lib/libtcp_bridge_oai.so.Rel15
-#RUN ldd /usr/local/lib/librfsimulator.so.Rel15
-#RUN ldd /usr/local/lib/liboai_usrpdevif.so.Rel15
-#RUN ldd /usr/local/lib/libcoding.so
-#RUN ldd /usr/local/lib/libparams_libconfig.so
-#RUN ldd /usr/local/lib/libdfts.so
-#RUN ldd /usr/local/lib/liboai_iqplayer.so
-#RUN ldd /opt/oai-enb/bin/lte-softmodem.Rel15
-
 # Copy the relevant configuration files for eNB
 WORKDIR /opt/oai-enb/etc
 COPY --from=enb-build /oai-ran/docker/etc .
diff --git a/docker/Dockerfile.lteUE.rhel8.2 b/docker/Dockerfile.lteUE.rhel8.2
index e22343d63cec65d90e23051c44abb3da778094b3..731abed1a834e78159c34f765bc50925c73dee6a 100644
--- a/docker/Dockerfile.lteUE.rhel8.2
+++ b/docker/Dockerfile.lteUE.rhel8.2
@@ -25,7 +25,7 @@
 #
 #---------------------------------------------------------------------
 
-FROM localhost/ran-build:latest AS lte-ue-build 
+FROM ran-build:latest AS lte-ue-build
 
 RUN rm -Rf /oai-ran
 WORKDIR /oai-ran
@@ -37,10 +37,10 @@ RUN /bin/sh oaienv && \
     mkdir -p log && \
     ./build_oai --UE --ninja -w USRP --verbose-ci
 
-# debug
-#RUN ldconfig -v && ldd /oai-ran/targets/bin/lte-uesoftmodem.Rel15
-#RUN ls -lst /oai-ran/targets/bin
-#RUN ls -lst /oai-ran/cmake_targets/ran_build/build/*.so
+RUN yum install -y python3-pip && \
+    pip3 install --ignore-installed pyyaml && \
+    python3 ./docker/scripts/generateTemplate.py ./docker/scripts/lte_ue_parameters.yaml && \
+    python3 ./docker/scripts/generateTemplate.py ./docker/scripts/lte_ue_sim_parameters.yaml
 
 #start from scratch for target executable
 FROM registry.access.redhat.com/ubi8/ubi:latest as oai-lte-ue
@@ -59,12 +59,10 @@ RUN yum update -y && \
 
 WORKDIR /opt/oai-lte-ue/bin
 COPY --from=lte-ue-build /oai-ran/targets/bin/lte-uesoftmodem.Rel15 .
+COPY --from=lte-ue-build /oai-ran/docker/scripts/lte_ue_entrypoint.sh entrypoint.sh
 COPY --from=lte-ue-build /oai-ran/targets/bin/conf2uedata .
 COPY --from=lte-ue-build /oai-ran/targets/bin/nvram .
 COPY --from=lte-ue-build /oai-ran/targets/bin/usim .
-COPY --from=lte-ue-build /oai-ran/targets/bin/.ue_emm.nvram0 .
-COPY --from=lte-ue-build /oai-ran/targets/bin/.ue.nvram0 .
-COPY --from=lte-ue-build /oai-ran/targets/bin/.usim.nvram0 .
 
 WORKDIR /usr/local/lib/
 COPY --from=lte-ue-build /oai-ran/targets/bin/liboai_eth_transpro.so.Rel15 .
@@ -99,26 +97,10 @@ COPY --from=lte-ue-build /usr/local/lib64/libuhd.so.4.0.0 /usr/local/lib64
 
 RUN ldconfig
 
-#debug
-#RUN ldd /opt/oai-lte-ue/bin/lte-uesoftmodem.Rel15
-#RUN ldd /opt/oai-lte-ue/bin/conf2uedata
-#RUN ldd /opt/oai-lte-ue/bin/nvram
-#RUN ldd /opt/oai-lte-ue/bin/usim
-#RUN ldd /usr/local/lib/liboai_eth_transpro.so.Rel15
-#RUN ldd /usr/local/lib/libtcp_bridge_oai.so.Rel15
-#RUN ldd /usr/local/lib/librfsimulator.so.Rel15
-#RUN ldd /usr/local/lib/liboai_usrpdevif.so.Rel15
-#RUN ldd /usr/local/lib/libcoding.so
-#RUN ldd /usr/local/lib/libparams_libconfig.so
-#RUN ldd /usr/local/lib/libSIMU.so
-#RUN ldd /usr/local/lib/libdfts.so
-
-# Copy the relevant configuration files for eNB
+# Copy the relevant configuration files for UE
 WORKDIR /opt/oai-lte-ue/etc
-COPY --from=lte-ue-build /oai-ran/ci-scripts/conf_files/ue.* .
-COPY --from=lte-ue-build /oai-ran/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf ./ue_usim.conf
+COPY --from=lte-ue-build /oai-ran/docker/etc .
 
 WORKDIR /opt/oai-lte-ue
-#CMD ["/opt/oai-lte-ue/bin/lte-uesoftmodem", "-O", "/opt/oai-lte-ue/etc/enb.conf"]
-#ENTRYPOINT ["/opt/oai-lte-ue/bin/entrypoint.sh"]
-CMD ["sleep", "infinity"]
+CMD ["/opt/oai-lte-ue/bin/lte-uesoftmodem.Rel15"]
+ENTRYPOINT ["/opt/oai-lte-ue/bin/entrypoint.sh"]
diff --git a/docker/Dockerfile.lteUE.ubuntu18 b/docker/Dockerfile.lteUE.ubuntu18
index 6af2e619918e776d0b46ec4b466d4677dacd627a..6575a81899babd752bf42a90a16f55078bf207b8 100644
--- a/docker/Dockerfile.lteUE.ubuntu18
+++ b/docker/Dockerfile.lteUE.ubuntu18
@@ -37,11 +37,10 @@ RUN /bin/sh oaienv && \
     mkdir -p log && \
     ./build_oai --UE --ninja -w USRP --verbose-ci
 
-# debug
-#RUN ldconfig -v
-#RUN ldd /oai-ran/targets/bin/lte-uesoftmodem.Rel15
-#RUN ls -lst /oai-ran/targets/bin
-#RUN ls -lst /oai-ran/cmake_targets/ran_build/build/*.so
+RUN apt-get install -y python3-pip && \
+    pip3 install --ignore-installed pyyaml && \
+    python3 ./docker/scripts/generateTemplate.py ./docker/scripts/lte_ue_parameters.yaml && \
+    python3 ./docker/scripts/generateTemplate.py ./docker/scripts/lte_ue_sim_parameters.yaml
 
 #start from scratch for target executable
 FROM ubuntu:bionic as oai-lte-ue
@@ -76,12 +75,10 @@ RUN apt-get update && \
 
 WORKDIR /opt/oai-lte-ue/bin
 COPY --from=lte-ue-build /oai-ran/targets/bin/lte-uesoftmodem.Rel15 .
+COPY --from=lte-ue-build /oai-ran/docker/scripts/lte_ue_entrypoint.sh entrypoint.sh
 COPY --from=lte-ue-build /oai-ran/targets/bin/conf2uedata .
 COPY --from=lte-ue-build /oai-ran/targets/bin/nvram .
 COPY --from=lte-ue-build /oai-ran/targets/bin/usim .
-COPY --from=lte-ue-build /oai-ran/targets/bin/.ue_emm.nvram0 .
-COPY --from=lte-ue-build /oai-ran/targets/bin/.ue.nvram0 .
-COPY --from=lte-ue-build /oai-ran/targets/bin/.usim.nvram0 .
 
 WORKDIR /usr/local/lib/
 COPY --from=lte-ue-build /oai-ran/targets/bin/liboai_eth_transpro.so.Rel15 .
@@ -100,26 +97,10 @@ COPY --from=lte-ue-build /usr/local/lib/libprotobuf-c.so.1 .
 
 RUN ldconfig
 
-#debug
-#RUN ldd /opt/oai-lte-ue/bin/lte-uesoftmodem.Rel15
-#RUN ldd /opt/oai-lte-ue/bin/conf2uedata
-#RUN ldd /opt/oai-lte-ue/bin/nvram
-#RUN ldd /opt/oai-lte-ue/bin/usim
-#RUN ldd /usr/local/lib/liboai_eth_transpro.so.Rel15
-#RUN ldd /usr/local/lib/libtcp_bridge_oai.so.Rel15
-#RUN ldd /usr/local/lib/librfsimulator.so.Rel15
-#RUN ldd /usr/local/lib/liboai_usrpdevif.so.Rel15
-#RUN ldd /usr/local/lib/libcoding.so
-#RUN ldd /usr/local/lib/libparams_libconfig.so
-#RUN ldd /usr/local/lib/libSIMU.so
-#RUN ldd /usr/local/lib/libdfts.so
-
-# Copy the relevant configuration files for eNB
+# Copy the relevant configuration files for UE
 WORKDIR /opt/oai-lte-ue/etc
-COPY --from=lte-ue-build /oai-ran/ci-scripts/conf_files/ue.* ./
-COPY --from=lte-ue-build /oai-ran/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf ./ue_usim.conf
+COPY --from=lte-ue-build /oai-ran/docker/etc .
 
 WORKDIR /opt/oai-lte-ue
-#CMD ["/opt/oai-lte-ue/bin/lte-uesoftmodem", "-O", "/opt/oai-lte-ue/etc/enb.conf"]
-#ENTRYPOINT ["/opt/oai-lte-ue/bin/entrypoint.sh"]
-CMD ["sleep", "infinity"]
+CMD ["/opt/oai-lte-ue/bin/lte-uesoftmodem.Rel15"]
+ENTRYPOINT ["/opt/oai-lte-ue/bin/entrypoint.sh"]
diff --git a/docker/scripts/enb_entrypoint.sh b/docker/scripts/enb_entrypoint.sh
index 31d99b2a676e2393ee16d4107fbd902943d145b2..dbe97360f67a689a200aa3e51e38d565a34190b1 100755
--- a/docker/scripts/enb_entrypoint.sh
+++ b/docker/scripts/enb_entrypoint.sh
@@ -2,17 +2,20 @@
 
 set -euo pipefail
 
+PREFIX=/opt/oai-enb
+RRC_INACTIVITY_THRESHOLD=${RRC_INACTIVITY_THRESHOLD:-0}
+
 # 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
+if [[ -v USE_FDD_CU ]]; then ln -s $PREFIX/etc/cu.fdd.conf $PREFIX/etc/enb.conf; fi
+if [[ -v USE_FDD_DU ]]; then ln -s $PREFIX/etc/du.fdd.conf $PREFIX/etc/enb.conf; fi
+if [[ -v USE_FDD_MONO ]]; then ln -s $PREFIX/etc/enb.fdd.conf $PREFIX/etc/enb.conf; fi
+if [[ -v USE_TDD_MONO ]]; then ln -s $PREFIX/etc/enb.tdd.conf $PREFIX/etc/enb.conf; fi
+if [[ -v USE_FDD_FAPI_RCC ]]; then ln -s $PREFIX/etc/rcc.nfapi.fdd.conf $PREFIX/etc/enb.conf; fi
+if [[ -v USE_FDD_RRU ]]; then ln -s $PREFIX/etc/rru.fdd.conf $PREFIX/etc/enb.conf; fi
+if [[ -v USE_TDD_RRU ]]; then ln -s $PREFIX/etc/rru.tdd.conf $PREFIX/etc/enb.conf; fi
 
 # Only this template will be manipulated
-CONFIG_FILES=`ls /opt/oai-enb/etc/enb.conf`
+CONFIG_FILES=`ls $PREFIX/etc/enb.conf || true`
 
 for c in ${CONFIG_FILES}; do
     # grep variable names (format: ${VAR}) from template to be rendered
diff --git a/docker/scripts/enb_parameters.yaml b/docker/scripts/enb_parameters.yaml
index a60fc20e29434725379d3fbe8172dd33c22e2f3f..d115d177ab863df37f232aca8421f060e1e4914c 100644
--- a/docker/scripts/enb_parameters.yaml
+++ b/docker/scripts/enb_parameters.yaml
@@ -159,6 +159,8 @@
       env: "@ENB_S1U_IP_ADDRESS@"
     - key: ENB_IPV4_ADDRESS_FOR_X2C
       env: "@ENB_X2_IP_ADDRESS@"
+    - key: rrc_inactivity_threshold
+      env: "@RRC_INACTIVITY_THRESHOLD@"
     - key: FLEXRAN_ENABLED
       env: "@FLEXRAN_ENABLED@"
     - key: FLEXRAN_INTERFACE_NAME
@@ -204,7 +206,7 @@
       env: "@F1_CU_IP_ADDRESS@"
       
   - filePrefix: "rcc.band7.tm1.nfapi"
-    outputfilename: "rcc.if4p5.enb.fdd.conf"
+    outputfilename: "rcc.nfapi.fdd.conf"
     config:
     - key: Active_eNBs
       env: "@ENB_NAME@"
diff --git a/docker/scripts/generateTemplate.py b/docker/scripts/generateTemplate.py
index 4949e9cf21531849fd3fa72d4adb18d8fa0c950a..418476d3959161898f35fec9550777b8f295acc6 100644
--- a/docker/scripts/generateTemplate.py
+++ b/docker/scripts/generateTemplate.py
@@ -35,11 +35,12 @@ def main():
   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"]
+    print('filePrefix = ' + filePrefix)
+    print('outputfilename = ' + outputfilename)
     for inputfile in dir:
       if inputfile.find(filePrefix) >=0:
         prefix_outputfile = {"cu": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}', 
@@ -48,7 +49,9 @@ def main():
                              "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}'
+                             "rcc.band7.tm1.nfapi": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "ue.nfapi": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}',
+                             "ue_sim_ci": f'{data[0]["paths"]["dest_dir"]}/{outputfilename}'
                              }
         if filePrefix in prefix_outputfile:
           outputfile1 = prefix_outputfile[filePrefix]  
@@ -61,6 +64,9 @@ def main():
              open(outputfile1, mode='w') as outputfile:
           for line in inputfile:
             count = 0
+            if re.search(r'EHPLMN_LIST', line):
+              outputfile.write(line)
+              continue
             for key in config["config"]:
               if line.find(key["key"]) >= 0:
                 count += 1
diff --git a/docker/scripts/lte_ue_entrypoint.sh b/docker/scripts/lte_ue_entrypoint.sh
new file mode 100755
index 0000000000000000000000000000000000000000..235128f73855aea4452d89940ea64d640e844e6d
--- /dev/null
+++ b/docker/scripts/lte_ue_entrypoint.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+set -euo pipefail
+
+PREFIX=/opt/oai-lte-ue
+
+# Based another env var, pick one template to use
+if [[ -v USE_NFAPI ]]; then ln -s $PREFIX/etc/ue.nfapi.conf $PREFIX/etc/ue.conf; fi
+
+# Only this template will be manipulated and the USIM one!
+CONFIG_FILES=`ls $PREFIX/etc/ue.conf $PREFIX/etc/ue_usim.conf || true`
+
+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
+
+#now generate USIM files
+# At this point all operations will be run from $PREFIX!
+cd $PREFIX
+$PREFIX/bin/conf2uedata -c $PREFIX/etc/ue_usim.conf -o $PREFIX
+
+# 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
+
+# in case we have conf file, append
+new_args=()
+while [[ $# -gt 0 ]]; do
+  new_args+=("$1")
+  shift
+done
+if [[ -v USE_NFAPI ]]; then
+  new_args+=("-O")
+  new_args+=("$PREFIX/etc/ue.conf")
+fi
+
+echo "=================================="
+echo "== Starting LTE UE soft modem"
+if [[ -v USE_ADDITIONAL_OPTIONS ]]; then
+    echo "Additional option(s): ${USE_ADDITIONAL_OPTIONS}"
+    for word in ${USE_ADDITIONAL_OPTIONS}; do
+        new_args+=("$word")
+    done
+    echo "${new_args[@]}"
+    exec "${new_args[@]}"
+else
+    echo "${new_args[@]}"
+    exec "${new_args[@]}"
+fi
diff --git a/docker/scripts/lte_ue_parameters.yaml b/docker/scripts/lte_ue_parameters.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..977659bb54c280d53c86179c5f674673069b31b8
--- /dev/null
+++ b/docker/scripts/lte_ue_parameters.yaml
@@ -0,0 +1,37 @@
+#/*
+# * 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: ue.nfapi
+    outputfilename: "ue.nfapi.conf"
+    config:
+    - key: remote_n_address
+      env: "@ENB_IP_ADDRESS@"
+    - key: local_n_address
+      env: "@LTE_UE_IP_ADDRESS@"
+    - key: local_n_if_name
+      env: "@UE_NFAPI_IF_NAME@"
+
diff --git a/docker/scripts/lte_ue_sim_parameters.yaml b/docker/scripts/lte_ue_sim_parameters.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a339ed7504ea16d105f342d46700f5e852e540e9
--- /dev/null
+++ b/docker/scripts/lte_ue_sim_parameters.yaml
@@ -0,0 +1,47 @@
+#/*
+# * 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: "openair3/NAS/TOOLS/"
+    dest_dir: docker/etc
+    
+- configurations:
+  - filePrefix: ue_sim_ci
+    outputfilename: "ue_usim.conf"
+    config:
+    - key: MNC
+      env: "@MNC@"
+    - key: MCC
+      env: "@MCC@"
+    - key: MSIN
+      env: "@SHORT_IMSI@"
+    - key: USIM_API_K
+      env: "@LTE_KEY@"
+    - key: OPC
+      env: "@OPC@"
+    - key: MSISDN
+      env: "@MSISDN@"
+    - key: HPLMN
+      env: "@HPLMN@"
+    - key: OPLMN_LIST
+      env: "@HPLMN@"
+
diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c
index 4047ff1386ca94ae4e99811c2c1b900e400d0fae..8b3d6fc64e3dd788781a19930263c4fd67980cb2 100644
--- a/executables/nr-gnb.c
+++ b/executables/nr-gnb.c
@@ -355,7 +355,9 @@ void init_gNB_Tpool(int inst) {
   // ULSCH decoding threadpool
   gNB->threadPool = (tpool_t*)malloc(sizeof(tpool_t));
   int numCPU = sysconf(_SC_NPROCESSORS_ONLN);
+  LOG_I(PHY,"Number of threads requested in config file: %d, Number of threads available on this machine: %d\n",gNB->pusch_proc_threads,numCPU);
   int threadCnt = min(numCPU, gNB->pusch_proc_threads);
+  if (threadCnt < 2) LOG_E(PHY,"Number of threads for gNB should be more than 1. Allocated only %d\n",threadCnt);
   char ul_pool[80];
   sprintf(ul_pool,"-1");
   int s_offset = 0;
diff --git a/executables/nr-ue.c b/executables/nr-ue.c
index 2adf37319627f8fec1609ad469002c097d7b44cf..a35a11a0332b4a3d301549f82d94ee872e7a2546 100644
--- a/executables/nr-ue.c
+++ b/executables/nr-ue.c
@@ -27,6 +27,8 @@
 #include "SCHED_NR_UE/phy_frame_config_nr.h"
 #include "SCHED_NR_UE/defs.h"
 #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
+#include "executables/softmodem-common.h"
+#include "SCHED_NR_UE/pucch_uci_ue_nr.h"
 
 /*
  *  NR SLOT PROCESSING SEQUENCE
@@ -85,6 +87,14 @@
  *
  */
 
+#ifndef NO_RAT_NR
+  #define DURATION_RX_TO_TX           (NR_UE_CAPABILITY_SLOT_RX_TO_TX)  /* for NR this will certainly depends to such UE capability which is not yet defined */
+#else
+  #define DURATION_RX_TO_TX           (6)   /* For LTE, this duration is fixed to 4 and it is linked to LTE standard for both modes FDD/TDD */
+#endif
+#define RX_JOB_ID 0x1010
+#define TX_JOB_ID 100
+
 typedef enum {
   pss = 0,
   pbch = 1,
@@ -101,6 +111,7 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue,
   ue->Mod_id      = UE_id;
   ue->mac_enabled = 1;
   ue->if_inst     = nr_ue_if_module_init(0);
+  ue->dci_thres   = 0;
 
   // Setting UE mode to NOT_SYNCHED by default
   for (gNB_id = 0; gNB_id < nb_connected_gNB; gNB_id++){
@@ -123,10 +134,7 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue,
  * \param arg is a pointer to a \ref PHY_VARS_NR_UE structure.
  */
 
-typedef struct syncData_s {
-  UE_nr_rxtx_proc_t proc;
-  PHY_VARS_NR_UE *UE;
-} syncData_t;
+typedef nr_rxtx_thread_data_t syncData_t;
 
 static void UE_synch(void *arg) {
   syncData_t *syncD=(syncData_t *) arg;
@@ -273,7 +281,11 @@ static void UE_synch(void *arg) {
   }
 }
 
-void processSlotTX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
+void processSlotTX(void *arg) {
+
+  nr_rxtx_thread_data_t *rxtxD = (nr_rxtx_thread_data_t *) arg;
+  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
+  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
   fapi_nr_config_request_t *cfg = &UE->nrUE_config;
   int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx);
   uint8_t gNB_id = 0;
@@ -304,10 +316,14 @@ void processSlotTX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
   }
 }
 
-void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
+void processSlotRX(void *arg) {
 
+  nr_rxtx_thread_data_t *rxtxD = (nr_rxtx_thread_data_t *) arg;
+  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
+  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
   fapi_nr_config_request_t *cfg = &UE->nrUE_config;
   int rx_slot_type = nr_ue_slot_select(cfg, proc->frame_rx, proc->nr_slot_rx);
+  int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx);
   uint8_t gNB_id = 0;
 
   if (rx_slot_type == NR_DOWNLINK_SLOT || rx_slot_type == NR_MIXED_SLOT){
@@ -323,7 +339,7 @@ void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
     phy_procedures_slot_parallelization_nrUE_RX( UE, proc, 0, 0, 1, no_relay, NULL );
 #else
     uint64_t a=rdtsc();
-    phy_procedures_nrUE_RX(UE, proc, gNB_id, get_nrUE_params()->nr_dlsch_parallel);
+    phy_procedures_nrUE_RX(UE, proc, gNB_id, get_nrUE_params()->nr_dlsch_parallel, &rxtxD->txFifo);
     LOG_D(PHY, "In %s: slot %d, time %lu\n", __FUNCTION__, proc->nr_slot_rx, (rdtsc()-a)/3500);
 #endif
 
@@ -341,34 +357,38 @@ void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
         nr_pdcp_tick(proc->frame_rx, proc->nr_slot_rx / UE->frame_parms.slots_per_subframe);
       }
     }
-  }
 
-}
+    // Wait for PUSCH processing to finish
+    notifiedFIFO_elt_t *res;
+    res = pullTpool(&rxtxD->txFifo,&(get_nrUE_params()->Tpool));
+    delNotifiedFIFO_elt(res);
 
-/*!
- * \brief This is the UE thread for RX subframe n and TX subframe n+4.
- * This thread performs the phy_procedures_UE_RX() on every received slot.
- * then, if TX is enabled it performs TX for n+4.
- * \param arg is a pointer to a \ref PHY_VARS_NR_UE structure.
- * \returns a pointer to an int. The storage is not on the heap and must not be freed.
- */
+  } else {
+    processSlotTX(rxtxD);
+  }
 
-typedef struct processingData_s {
-  UE_nr_rxtx_proc_t proc;
-  PHY_VARS_NR_UE    *UE;
-}  processingData_t;
+  if (tx_slot_type == NR_UPLINK_SLOT || tx_slot_type == NR_MIXED_SLOT){
+    if (UE->UE_mode[gNB_id] <= PUSCH) {
+      if (get_softmodem_params()->usim_test==0) {
+        pucch_procedures_ue_nr(UE,
+                               gNB_id,
+                               proc,
+                               FALSE);
+      }
 
-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;
+      LOG_D(PHY, "Sending Uplink data \n");
+      nr_ue_pusch_common_procedures(UE,
+                                    proc->nr_slot_tx,
+                                    &UE->frame_parms,1);
+    }
 
-  processSlotRX(UE, proc);
-  processSlotTX(UE, proc);
-  ue_ta_procedures(UE, slot_tx, frame_tx);
+    if (UE->UE_mode[gNB_id] > NOT_SYNCHED && UE->UE_mode[gNB_id] < PUSCH) {
+      nr_ue_prach_procedures(UE, proc, gNB_id);
+    }
+    LOG_D(PHY,"****** end TX-Chain for AbsSubframe %d.%d ******\n", proc->frame_tx, proc->nr_slot_tx);
+  }
 
+  ue_ta_procedures(UE, proc->nr_slot_tx, proc->frame_tx);
 }
 
 void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
@@ -485,25 +505,44 @@ void *UE_thread(void *arg) {
   int start_rx_stream = 0;
   AssertFatal(0== openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), "");
   UE->rfdevice.host_type = RAU_HOST;
+  UE->lost_sync = 0;
+  UE->is_synchronized = 0;
   AssertFatal(UE->rfdevice.trx_start_func(&UE->rfdevice) == 0, "Could not start the device\n");
+
   notifiedFIFO_t nf;
   initNotifiedFIFO(&nf);
-  int nbSlotProcessing=0;
-  int thread_idx=0;
+
   notifiedFIFO_t freeBlocks;
   initNotifiedFIFO_nothreadSafe(&freeBlocks);
+
+  int nbSlotProcessing=0;
+  int thread_idx=0;
   NR_UE_MAC_INST_t *mac = get_mac_inst(0);
   int timing_advance = UE->timing_advance;
 
-  for (int i=0; i<RX_NB_TH+1; i++)  // RX_NB_TH working + 1 we are making to be pushed
-    pushNotifiedFIFO_nothreadSafe(&freeBlocks,
-                                  newNotifiedFIFO_elt(sizeof(processingData_t), 0,&nf,UE_processing));
-
   bool syncRunning=false;
   const int nb_slot_frame = UE->frame_parms.slots_per_frame;
   int absolute_slot=0, decoded_frame_rx=INT_MAX, trashed_frames=0;
 
+  for (int i=0; i<NR_RX_NB_TH+1; i++) {// NR_RX_NB_TH working + 1 we are making to be pushed
+    notifiedFIFO_elt_t *newElt = newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), RX_JOB_ID,&nf,processSlotRX);
+    nr_rxtx_thread_data_t *curMsg=(nr_rxtx_thread_data_t *)NotifiedFifoData(newElt);
+    initNotifiedFIFO(&curMsg->txFifo);
+    pushNotifiedFIFO_nothreadSafe(&freeBlocks, newElt);
+  }
+
   while (!oai_exit) {
+    if (UE->lost_sync) {
+      int nb = abortTpool(&(get_nrUE_params()->Tpool),RX_JOB_ID);
+      nb += abortNotifiedFIFO(&nf, RX_JOB_ID);
+      LOG_I(PHY,"Number of aborted slots %d\n",nb);
+      for (int i=0; i<nb; i++)
+        pushNotifiedFIFO_nothreadSafe(&freeBlocks, newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), RX_JOB_ID,&nf,processSlotRX));
+      nbSlotProcessing = 0;
+      UE->is_synchronized = 0;
+      UE->lost_sync = 0;
+    }
+
     if (syncRunning) {
       notifiedFIFO_elt_t *res=tryPullTpool(&nf,&(get_nrUE_params()->Tpool));
 
@@ -513,9 +552,10 @@ void *UE_thread(void *arg) {
         if (UE->is_synchronized) {
           decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
           // shift the frame index with all the frames we trashed meanwhile we perform the synch search
-          decoded_frame_rx=(decoded_frame_rx + (!UE->init_sync_frame) + trashed_frames) % MAX_FRAME_NUMBER;
+          decoded_frame_rx=(decoded_frame_rx + UE->init_sync_frame + trashed_frames) % MAX_FRAME_NUMBER;
         }
         delNotifiedFIFO_elt(res);
+        start_rx_stream=0;
       } else {
         readFrame(UE, &timestamp, true);
         trashed_frames+=2;
@@ -562,13 +602,13 @@ void *UE_thread(void *arg) {
 
     // whatever means thread_idx
     // Fix me: will be wrong when slot 1 is slow, as slot 2 finishes
-    // Slot 3 will overlap if RX_NB_TH is 2
+    // Slot 3 will overlap if NR_RX_NB_TH is 2
     // this is general failure in UE !!!
-    thread_idx = absolute_slot % RX_NB_TH;
+    thread_idx = absolute_slot % NR_RX_NB_TH;
     int slot_nr = absolute_slot % nb_slot_frame;
     notifiedFIFO_elt_t *msgToPush;
-    AssertFatal((msgToPush=pullNotifiedFIFO_nothreadSafe(&freeBlocks)) != NULL,"chained list failure");
-    processingData_t *curMsg=(processingData_t *)NotifiedFifoData(msgToPush);
+    AssertFatal((msgToPush=pullTpool(&freeBlocks,&(get_nrUE_params()->Tpool))) != NULL,"chained list failure");
+    nr_rxtx_thread_data_t *curMsg=(nr_rxtx_thread_data_t *)NotifiedFifoData(msgToPush);
     curMsg->UE=UE;
     // update thread index for received subframe
     curMsg->proc.thread_id   = thread_idx;
@@ -596,18 +636,18 @@ void *UE_thread(void *arg) {
 
     for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
       txp[i] = (void *)&UE->common_vars.txdata[i][UE->frame_parms.get_samples_slot_timestamp(
-               ((slot_nr + DURATION_RX_TO_TX - RX_NB_TH)%nb_slot_frame),&UE->frame_parms,0)];
+               ((slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH)%nb_slot_frame),&UE->frame_parms,0)];
 
     int readBlockSize, writeBlockSize;
 
     if (slot_nr<(nb_slot_frame - 1)) {
       readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms);
-      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms);
+      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH) % nb_slot_frame, &UE->frame_parms);
     } else {
       UE->rx_offset_diff = computeSamplesShift(UE);
       readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) -
                     UE->rx_offset_diff;
-      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms)- UE->rx_offset_diff;
+      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH) % nb_slot_frame, &UE->frame_parms)- UE->rx_offset_diff;
     }
 
     AssertFatal(readBlockSize ==
@@ -639,27 +679,27 @@ void *UE_thread(void *arg) {
 
     notifiedFIFO_elt_t *res;
 
-    while (nbSlotProcessing >= RX_NB_TH) {
+    while (nbSlotProcessing >= NR_RX_NB_TH) {
       res=pullTpool(&nf, &(get_nrUE_params()->Tpool));
       nbSlotProcessing--;
-      processingData_t *tmp=(processingData_t *)res->msgData;
+      nr_rxtx_thread_data_t *tmp=(nr_rxtx_thread_data_t *)res->msgData;
 
       if (tmp->proc.decoded_frame_rx != -1)
         decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
-      else 
+      else
          decoded_frame_rx=-1;
 
       pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
     }
 
-    if (  decoded_frame_rx>0 && decoded_frame_rx != curMsg->proc.frame_rx)
+    if (decoded_frame_rx>0 && decoded_frame_rx != curMsg->proc.frame_rx)
       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  );
+            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 -
+      - NR_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
@@ -669,7 +709,7 @@ void *UE_thread(void *arg) {
     }
 
     int flags = 0;
-    int slot_tx_usrp = slot_nr + DURATION_RX_TO_TX - RX_NB_TH;
+    int slot_tx_usrp = slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH;
 
     if (openair0_cfg[0].duplex_mode == duplex_mode_TDD) {
 
@@ -701,26 +741,9 @@ void *UE_thread(void *arg) {
       memset(txp[i], 0, writeBlockSize);
 
     nbSlotProcessing++;
-    msgToPush->key=slot_nr;
+    LOG_D(PHY,"Number of slots being processed at the moment: %d\n",nbSlotProcessing);
     pushTpool(&(get_nrUE_params()->Tpool), msgToPush);
 
-    if (IS_SOFTMODEM_RFSIM) {  //getenv("RFSIMULATOR")
-      // FixMe: Wait previous thread is done, because race conditions seems too bad
-      // in case of actual RF board, the overlap between threads mitigate the issue
-      // We must receive one message, that proves the slot processing is done
-      res=pullTpool(&nf, &(get_nrUE_params()->Tpool));
-      nbSlotProcessing--;
-      processingData_t *tmp=(processingData_t *)res->msgData;
-
-      if (tmp->proc.decoded_frame_rx != -1)
-        decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
-      else 
-        decoded_frame_rx=-1;
-        //decoded_frame_rx=tmp->proc.decoded_frame_rx;
-
-      pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
-    }
-
   } // while !oai_exit
 
   return NULL;
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
index 174d5409bd843b5f645b0156bc51c2d3a2945431..13a191a18a5e718f4fef82cf74117c201402ba5d 100644
--- a/executables/nr-uesoftmodem.c
+++ b/executables/nr-uesoftmodem.c
@@ -232,9 +232,16 @@ nrUE_params_t *get_nrUE_params(void) {
 }
 /* initialie thread pools used for NRUE processing paralleliation */ 
 void init_tpools(uint8_t nun_dlsch_threads) {
-  char *params=calloc(1,(RX_NB_TH*3)+1);
-  for (int i=0; i<RX_NB_TH; i++) {
-    memcpy(params+(i*3),"-1,",3);
+  char *params = NULL;
+  if (IS_SOFTMODEM_RFSIM) {
+    params = calloc(1,2);
+    memcpy(params,"N",1);
+  }
+  else {
+    params = calloc(1,(NR_RX_NB_TH*NR_NB_TH_SLOT*3)+1);
+    for (int i=0; i<NR_RX_NB_TH*NR_NB_TH_SLOT; i++) {
+      memcpy(params+(i*3),"-1,",3);
+    }
   }
   initTpool(params, &(nrUE_params.Tpool), false);
   free(params);
@@ -258,7 +265,6 @@ static void get_options(void) {
     printf("%s\n",uecap_xer);
     uecap_xer_in=1;
   } /* UE with config file  */
-    init_tpools(nrUE_params.nr_dlsch_parallel);
 }
 
 // set PHY vars from command line
@@ -415,6 +421,7 @@ int main( int argc, char **argv ) {
   get_options (); //Command-line options specific for NRUE
 
   get_common_options(SOFTMODEM_5GUE_BIT );
+  init_tpools(nrUE_params.nr_dlsch_parallel);
   CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP);
 #if T_TRACER
   T_Config_Init();
diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h
index e4275a48bb31db737965843054a62d21d2036884..9fa96462fd254d1594b29bebefa43e306d5257a7 100644
--- a/executables/softmodem-common.h
+++ b/executables/softmodem-common.h
@@ -73,6 +73,7 @@ extern "C"
 #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_NONSTOP       "Go back to frame sync mode after 100 consecutive PBCH failures\n"
 //#define CONFIG_HLP_NUMUES        "Set the number of UEs for the emulation"
 #define CONFIG_HLP_MSLOTS        "Skip the missed slots/subframes \n"
 #define CONFIG_HLP_ULMCS         "Set the maximum uplink MCS\n"
@@ -115,6 +116,7 @@ extern "C"
 #define USIM_TEST           softmodem_params.usim_test
 #define USE_256QAM_TABLE    softmodem_params.use_256qam_table
 #define NFAPI               softmodem_params.nfapi
+#define NON_STOP            softmodem_params.non_stop
 
 #define DEFAULT_RFCONFIG_FILE    "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat";
 
@@ -148,6 +150,7 @@ extern int usrp_tx_thread;
     {"use-256qam-table",     CONFIG_HLP_256QAM,       PARAMFLAG_BOOL, iptr:&USE_256QAM_TABLE,             defintval:0,           TYPE_INT,    0},                     \
     {"usrp-tx-thread-config", CONFIG_HLP_USRP_THREAD, 0,              iptr:&usrp_tx_thread,               defstrval:0,           TYPE_INT,    0},        \
     {"nfapi",                CONFIG_HLP_NFAPI,        0,              u8ptr:&nfapi_mode,                       defintval:0,           TYPE_UINT8,  0},                     \
+    {"non-stop",            CONFIG_HLP_NONSTOP,      PARAMFLAG_BOOL, iptr:&NON_STOP,                       defintval:0,           TYPE_INT,  0},                     \
   }
 
   
@@ -238,6 +241,7 @@ typedef struct {
   uint32_t       send_dmrs_sync;
   int            use_256qam_table;
   uint8_t        nfapi;
+  int            non_stop;
 } softmodem_params_t;
 
 extern uint64_t get_softmodem_optmask(void);
diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
index 8c2118cd3d4d05d0908dc57572aa874798d24e2a..0436f92a8d493ed2904ac073527a29df7ff283f6 100644
--- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
+++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
@@ -1058,12 +1058,6 @@ typedef struct {
   fapi_nr_tdd_table_t tdd_table;
   fapi_nr_prach_config_t prach_config;
 
-  fapi_nr_dl_bwp_common_config_t     dl_bwp_common;
-  fapi_nr_dl_bwp_dedicated_config_t  dl_bwp_dedicated;
-
-  fapi_nr_ul_bwp_common_config_t     ul_bwp_common;
-  fapi_nr_ul_bwp_dedicated_config_t  ul_bwp_dedicated;
-
 } fapi_nr_config_request_t;
 
 #endif
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c
index b7de182ab711242dfc84b5d19dacf9a313c7f1a1..3f6eb00bcb45e886a159e57e6c82ecc0ec7e5f14 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dci.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c
@@ -97,7 +97,7 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
     cset_start_symb = pdcch_pdu_rel15->StartSymbolIndex;
     cset_nsymb = pdcch_pdu_rel15->DurationSymbols;
     dci_idx = 0;
-    LOG_D(PHY, "Coreset rb_offset %d, nb_rb %d\n",rb_offset,n_rb);
+    LOG_D(PHY, "Coreset rb_offset %d, nb_rb %d BWP Start %d\n",rb_offset,n_rb,pdcch_pdu_rel15->BWPStart);
     LOG_D(PHY, "Coreset starting subcarrier %d on symbol %d (%d symbols)\n", cset_start_sc, cset_start_symb, cset_nsymb);
     // DMRS length is per OFDM symbol
     uint32_t dmrs_length = n_rb*6; //2(QPSK)*3(per RB)*6(REG per CCE)
@@ -196,9 +196,9 @@ void nr_generate_dci(PHY_VARS_gNB *gNB,
 
         // dmrs index depends on reference point for k according to 38.211 7.4.1.3.2
         if (pdcch_pdu_rel15->CoreSetType == NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG)
-          dmrs_idx =gNB->cce_list[d][cce_idx].reg_list[reg_in_cce_idx].reg_idx * 3;
+          dmrs_idx =(gNB->cce_list[d][cce_idx].reg_list[reg_in_cce_idx].reg_idx / pdcch_pdu_rel15->DurationSymbols) * 3;
         else
-          dmrs_idx = (gNB->cce_list[d][cce_idx].reg_list[reg_in_cce_idx].reg_idx + rb_offset) * 3;
+          dmrs_idx = (gNB->cce_list[d][cce_idx].reg_list[reg_in_cce_idx].reg_idx / pdcch_pdu_rel15->DurationSymbols + rb_offset) * 3;
 
         k_prime = 0;
 
diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
index 8176514eb4195b8879bf0a1cfcc9ff5e7109363f..c1cebc64a8e9ac6ed9770509b19e03d4c1451af7 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c
@@ -874,6 +874,33 @@ void nr_pdcch_unscrambling(int16_t *z,
 
 
 #ifdef NR_PDCCH_DCI_RUN
+/* This function compares the received DCI bits with
+ * re-encoded DCI bits and returns the number of mismatched bits
+ */
+uint16_t nr_dci_false_detection(uint64_t *dci,
+                            int16_t *soft_in,
+                            const t_nrPolar_params *polar_param,
+                            int encoded_length,
+                            int rnti) {
+
+  uint32_t encoder_output[NR_MAX_DCI_SIZE_DWORD];
+  polar_encoder_fast(dci, (void*)encoder_output, rnti, 1, polar_param);
+  uint8_t *enout_p = (uint8_t*)encoder_output;
+  uint16_t x = 0;
+
+  for (int i=0; i<encoded_length/8; i++) {
+    x += ( enout_p[i] & 1 ) ^ ( ( soft_in[i*8] >> 15 ) & 1);
+    x += ( ( enout_p[i] >> 1 ) & 1 ) ^ ( ( soft_in[i*8+1] >> 15 ) & 1 );
+    x += ( ( enout_p[i] >> 2 ) & 1 ) ^ ( ( soft_in[i*8+2] >> 15 ) & 1 );
+    x += ( ( enout_p[i] >> 3 ) & 1 ) ^ ( ( soft_in[i*8+3] >> 15 ) & 1 );
+    x += ( ( enout_p[i] >> 4 ) & 1 ) ^ ( ( soft_in[i*8+4] >> 15 ) & 1 );
+    x += ( ( enout_p[i] >> 5 ) & 1 ) ^ ( ( soft_in[i*8+5] >> 15 ) & 1 );
+    x += ( ( enout_p[i] >> 6 ) & 1 ) ^ ( ( soft_in[i*8+6] >> 15 ) & 1 );
+    x += ( ( enout_p[i] >> 7 ) & 1 ) ^ ( ( soft_in[i*8+7] >> 15 ) & 1 );
+  }
+  return x;
+}
+
 uint8_t nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue,
                                   UE_nr_rxtx_proc_t *proc,
                                   fapi_nr_dci_indication_t *dci_ind) {
@@ -920,15 +947,23 @@ uint8_t nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue,
         if (crc == n_rnti) {
           LOG_D(PHY, "(%i.%i) Received dci indication (rnti %x,dci format %d,n_CCE %d,payloadSize %d,payload %llx)\n",
                 proc->frame_rx, proc->nr_slot_rx,n_rnti,rel15->dci_format_options[k],CCEind,dci_length,*(unsigned long long*)dci_estimation);
-          dci_ind->SFN = proc->frame_rx;
-          dci_ind->slot = proc->nr_slot_rx;
-          dci_ind->dci_list[dci_ind->number_of_dcis].rnti        = n_rnti;
-          dci_ind->dci_list[dci_ind->number_of_dcis].n_CCE       = CCEind;
-          dci_ind->dci_list[dci_ind->number_of_dcis].dci_format  = rel15->dci_format_options[k];
-          dci_ind->dci_list[dci_ind->number_of_dcis].payloadSize = dci_length;
-          memcpy((void*)dci_ind->dci_list[dci_ind->number_of_dcis].payloadBits,(void*)dci_estimation,8);
-          dci_ind->number_of_dcis++;
-          break;    // If DCI is found, no need to check for remaining DCI lengths
+          uint16_t mb = nr_dci_false_detection(dci_estimation,tmp_e,currentPtrDCI,L*108,n_rnti);
+          ue->dci_thres = (ue->dci_thres + mb) / 2;
+          if (mb > (ue->dci_thres+20)) {
+            LOG_W(PHY,"DCI false positive. Dropping DCI index %d. Mismatched bits: %d/%d. Current DCI threshold: %d\n",j,mb,L*108,ue->dci_thres);
+            continue;
+          }
+          else {
+            dci_ind->SFN = proc->frame_rx;
+            dci_ind->slot = proc->nr_slot_rx;
+            dci_ind->dci_list[dci_ind->number_of_dcis].rnti        = n_rnti;
+            dci_ind->dci_list[dci_ind->number_of_dcis].n_CCE       = CCEind;
+            dci_ind->dci_list[dci_ind->number_of_dcis].dci_format  = rel15->dci_format_options[k];
+            dci_ind->dci_list[dci_ind->number_of_dcis].payloadSize = dci_length;
+            memcpy((void*)dci_ind->dci_list[dci_ind->number_of_dcis].payloadBits,(void*)dci_estimation,8);
+            dci_ind->number_of_dcis++;
+            break;    // If DCI is found, no need to check for remaining DCI lengths
+          }
         } else {
           LOG_D(PHY,"(%i.%i) Decoded crc %x does not match rnti %x for DCI format %d\n", proc->frame_rx, proc->nr_slot_rx, crc, n_rnti, rel15->dci_format_options[k]);
         }
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
index bfef89ea850eba7a19e4e97c6dfd6811742fd23d..df35f148692302c17ba25ecd5be60f2ee2d6b888 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
@@ -308,12 +308,15 @@ int nr_initial_sync(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, int n_frames)
         // 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)
+        // for a correct computation of frame number to sync with the one decoded at MIB we need to take into account in which of the n_frames we got sync
+        ue->init_sync_frame = n_frames - 1 - is;
+        // we also need to take into account the shift by samples_per_frame in case the if is true
+        if (ue->ssb_offset < sync_pos_frame){
           ue->rx_offset = fp->samples_per_frame - sync_pos_frame + ue->ssb_offset;
+          ue->init_sync_frame += 1;
+        }
         else
           ue->rx_offset = ue->ssb_offset - sync_pos_frame;
-
-        ue->init_sync_frame = is;
       }   
 
     /*
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
index ef884512fdea450a52bc8c14f8ee7179ee61881c..66c3de97eaffa726dbd842e62f8299eef2aed13b 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c
@@ -589,7 +589,7 @@ int nr_rx_pbch( PHY_VARS_NR_UE *ue,
       frame_parms->ssb_index += (((nr_ue_pbch_vars->xtra_byte>>(7-i))&0x01)<<(3+i));
   }
 
-  ue->symbol_offset = nr_get_ssb_start_symbol(frame_parms,i_ssb);
+  ue->symbol_offset = nr_get_ssb_start_symbol(frame_parms,frame_parms->ssb_index);
   if (frame_parms->half_frame_bit)
     ue->symbol_offset += (frame_parms->slots_per_frame>>1)*frame_parms->symbols_per_slot;
 
diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h
index bf0a7bc9e5474dd7cfac255341e3bf51b7923e8a..e3c0737838005c222b833a0d4b6e8d8aa3f56633 100644
--- a/openair1/PHY/defs_nr_UE.h
+++ b/openair1/PHY/defs_nr_UE.h
@@ -763,6 +763,8 @@ typedef struct {
   int is_synchronized;
   /// \brief Indicates on which frame is synchronized in a two frame synchronization
   int is_synchronized_on_frame;
+  /// \brief Indicator that UE lost frame synchronization
+  int lost_sync;
   /// Data structure for UE process scheduling
   UE_nr_proc_t proc;
   /// Flag to indicate the UE shouldn't do timing correction at all
@@ -789,6 +791,8 @@ typedef struct {
   uint8_t ho_initiated;
   /// \brief indicator that Handover procedure has been triggered
   uint8_t ho_triggered;
+  /// threshold for false dci detection
+  int dci_thres;
   /// \brief Measurement variables.
   PHY_NR_MEASUREMENTS measurements;
   NR_DL_FRAME_PARMS  frame_parms;
@@ -1080,6 +1084,7 @@ typedef struct {
 typedef struct nr_rxtx_thread_data_s {
   UE_nr_rxtx_proc_t proc;
   PHY_VARS_NR_UE    *UE;
+  notifiedFIFO_t txFifo;
 }  nr_rxtx_thread_data_t;
 
 #include "SIMULATION/ETH_TRANSPORT/defs.h"
diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h
index 398252c37b9dbfb03e6f56cef77b0127102e6336..d1d69ecabe8c9682c4fd453af587a4ebcfe40b4c 100644
--- a/openair1/PHY/defs_nr_common.h
+++ b/openair1/PHY/defs_nr_common.h
@@ -109,6 +109,8 @@
 
 #define MAX_NUM_NR_CHANNEL_BITS (14*273*12*8)  // 14 symbols, 273 RB
 #define MAX_NUM_NR_RE (14*273*12)
+#define NR_RX_NB_TH 1
+#define NR_NB_TH_SLOT 2
 
 extern const uint8_t nr_rv_round_map[4]; 
 extern const uint8_t nr_rv_round_map_ue[4]; 
diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
index f59f57b957b64d3010fd8d039c6acd6ffff4a2b9..d6450f19cf47c6d5c5ae4ef09953fbb01f4ea3da 100644
--- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c
+++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
@@ -564,6 +564,10 @@ void phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
           gNB->uci_pdu_list[num_ucis].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t);
           nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &gNB->uci_pdu_list[num_ucis].pucch_pdu_format_0_1;
 
+          offset = pucch_pdu->start_symbol_index*gNB->frame_parms.ofdm_symbol_size + (gNB->frame_parms.first_carrier_offset+pucch_pdu->prb_start*12);
+          power_rxF = signal_energy_nodc(&gNB->common_vars.rxdataF[0][offset],12);
+          LOG_D(PHY,"frame %d, slot %d: PUCCH signal energy %d\n",frame_rx,slot_rx,power_rxF);
+
           nr_decode_pucch0(gNB,
 	                   slot_rx,
                            uci_pdu_format0,
diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h
index f7f44a520d31d34fc6246a436214edb634d890ee..2675e46a04be92c5b7b449ebe007215cbbc7f9ad 100644
--- a/openair1/SCHED_NR_UE/defs.h
+++ b/openair1/SCHED_NR_UE/defs.h
@@ -115,14 +115,17 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t
   @param proc           Pointer to proc information
   @param gNB_id         Local id of eNB on which to act
   @param dlsch_parallel use multithreaded dlsch processing
+  @param txFifo         Result fifo if PDSCH is run in parallel
 */
 int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
                            UE_nr_rxtx_proc_t *proc,
                            uint8_t gNB_id,
-                           uint8_t dlsch_parallel);
+                           uint8_t dlsch_parallel,
+                           notifiedFIFO_t *txFifo);
 
 int phy_procedures_slot_parallelization_nrUE_RX(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, uint8_t eNB_id, uint8_t abstraction_flag, uint8_t do_pdcch_flag, relaying_type_t r_type);
 
+void processSlotTX(void *arg);
 
 #ifdef UE_SLOT_PARALLELISATION
   void *UE_thread_slot1_dl_processing(void *arg);
diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
index 54464446a50c3ded331d0d3d7eefc86405ce5ec5..c8ac871bbf28820a6c646fa0b59475170242ec76 100644
--- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
+++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
@@ -127,6 +127,8 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){
               // dlsch0_harq->status not ACTIVE may be due to false retransmission. Reset the 
               // following flag to skip PDSCH procedures in that case.
               dlsch0->active = 0;
+              dlsch0_harq->harq_ack.ack = 1;
+              dlsch0_harq->harq_ack.send_harq_status = 1;
             }
             dlsch0_harq->harq_ack.vDAI_DL = dlsch_config_pdu->dai;
             /* PTRS */
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index 60fe897456f2fe367bea70899a27787edff0cf8a..ba81d9b205a1a6e28fa83303b0b0799b3273b484 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -142,7 +142,7 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
     case FAPI_NR_RX_PDU_TYPE_MIB:
       rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.pdu = ue->pbch_vars[gNB_id]->decoded_output;
       rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.additional_bits = ue->pbch_vars[gNB_id]->xtra_byte;
-      rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.ssb_index = frame_parms->ssb_index;
+      rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.ssb_index = (frame_parms->ssb_index)&0x7;
       rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.ssb_length = frame_parms->Lmax;
       rx_ind->rx_indication_body[n_pdus - 1].mib_pdu.cell_id = frame_parms->Nid_cell;
     break;
@@ -275,25 +275,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue,
         nr_ue_ulsch_procedures(ue, harq_pid, frame_tx, slot_tx, proc->thread_id, gNB_id);
     }
 
-    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,
-                                  slot_tx,
-                                  &ue->frame_parms,1);
-
-  }
-
-  if (ue->UE_mode[gNB_id] > NOT_SYNCHED && ue->UE_mode[gNB_id] < PUSCH) {
-    nr_ue_prach_procedures(ue, proc, gNB_id);
   }
-  LOG_D(PHY,"****** end TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX, VCD_FUNCTION_OUT);
 #if UE_TIMING_TRACE
@@ -368,7 +350,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_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);
+  LOG_D(PHY,"[UE  %d] Frame %d Slot %d, Trying PBCH (NidCell %d, gNB_id %d)\n",ue->Mod_id,frame_rx,nr_slot_rx,ue->frame_parms.Nid_cell,gNB_id);
 
   ret = nr_rx_pbch(ue, proc,
 		   ue->pbch_vars[gNB_id],
@@ -435,8 +417,13 @@ void nr_ue_pbch_procedures(uint8_t gNB_id,
     ue->pbch_vars[gNB_id]->pdu_errors++;
 
     if (ue->pbch_vars[gNB_id]->pdu_errors_conseq>=100) {
-      LOG_E(PHY,"More that 100 consecutive PBCH errors! Exiting!\n");
-      exit_fun("More that 100 consecutive PBCH errors! Exiting!\n");
+      if (get_softmodem_params()->non_stop) {
+        LOG_E(PHY,"More that 100 consecutive PBCH errors! Going back to Sync mode!\n");
+        ue->lost_sync = 1;
+      } else {
+        LOG_E(PHY,"More that 100 consecutive PBCH errors! Exiting!\n");
+        exit_fun("More that 100 consecutive PBCH errors! Exiting!\n");
+      }
     }
   }
 
@@ -1615,7 +1602,8 @@ int is_pbch_in_slot(fapi_nr_config_request_t *config, int frame, int slot, NR_DL
 int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
                            UE_nr_rxtx_proc_t *proc,
                            uint8_t gNB_id,
-                           uint8_t dlsch_parallel
+                           uint8_t dlsch_parallel,
+                           notifiedFIFO_t *txFifo
                            )
 {                                         
   int frame_rx = proc->frame_rx;
@@ -1772,6 +1760,13 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
   }
 
 #endif //NR_PDCCH_SCHED
+  
+  // Start PUSCH processing here. It runs in parallel with PDSCH processing
+  notifiedFIFO_elt_t *newElt = newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), proc->nr_slot_tx,txFifo,processSlotTX);
+  nr_rxtx_thread_data_t *curMsg=(nr_rxtx_thread_data_t *)NotifiedFifoData(newElt);
+  curMsg->proc = *proc;
+  curMsg->UE = ue;
+  pushTpool(&(get_nrUE_params()->Tpool), newElt);
 
 #if UE_TIMING_TRACE
   start_meas(&ue->generic_stat);
@@ -1904,6 +1899,7 @@ int phy_procedures_nrUE_RX(PHY_VARS_NR_UE *ue,
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT);
 
  }
+ 
 #if UE_TIMING_TRACE
 start_meas(&ue->generic_stat);
 #endif
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index a9912222a3269bfa746c29132a62dc8808e4600a..95920d2ea11c590740a9d37f828ec7d791dd827b 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -202,6 +202,8 @@ int is_x2ap_enabled(void)
   return 0;
 }
 
+void processSlotTX(void *arg) {}
+
 //nFAPI P7 dummy functions
 
 int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) { return(0);  }
@@ -286,6 +288,20 @@ void nr_dlsim_preprocessor(module_id_t module_id,
   AssertFatal(ps->mcsTableIdx >= 0 && ps->mcsTableIdx <= 2, "invalid mcsTableIdx %d\n", ps->mcsTableIdx);
 }
 
+typedef struct {
+  uint64_t       optmask;   //mask to store boolean config options
+  uint8_t        nr_dlsch_parallel; // number of threads for dlsch decoding, 0 means no parallelization
+  tpool_t        Tpool;             // thread pool 
+} nrUE_params_t;
+
+nrUE_params_t nrUE_params;
+
+nrUE_params_t *get_nrUE_params(void) {
+  return &nrUE_params;
+}
+
+void do_nothing(void *args) {
+}
 
 int main(int argc, char **argv)
 {
@@ -717,13 +733,7 @@ int main(int argc, char **argv)
 
   prepare_scd(scd);
 
-  fill_default_secondaryCellGroup(scc,
-                                  scd,
-                                  secondaryCellGroup,
-                                  0,
-                                  1,
-                                  n_tx,
-                                  0);
+  fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0);
 
   /* RRC parameter validation for secondaryCellGroup */
   fix_scd(scd);
@@ -885,6 +895,7 @@ int main(int argc, char **argv)
   unsigned int errors_bit    = 0;
   uint32_t errors_scrambling = 0;
 
+  initTpool("N", &(nrUE_params.Tpool), false);
 
   test_input_bit       = (unsigned char *) malloc16(sizeof(unsigned char) * 16 * 68 * 384);
   estimated_output_bit = (unsigned char *) malloc16(sizeof(unsigned char) * 16 * 68 * 384);
@@ -1135,7 +1146,8 @@ int main(int argc, char **argv)
         phy_procedures_nrUE_RX(UE,
                                &UE_proc,
                                0,
-                               dlsch_threads);
+                               dlsch_threads,
+                               NULL);
         
         //printf("dlsim round %d ends\n",round);
         round++;
diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c
index 26c151818873dbe3485d89aee0a965c4b77f0749..54ec6ab9da6a62ded8ac281c42122c7195b6a082 100644
--- a/openair1/SIMULATION/NR_PHY/prachsim.c
+++ b/openair1/SIMULATION/NR_PHY/prachsim.c
@@ -174,6 +174,20 @@ int nr_derive_key(int alg_type, uint8_t alg_id,
   return 0;
 }
 
+typedef struct {
+  uint64_t       optmask;   //mask to store boolean config options
+  uint8_t        nr_dlsch_parallel; // number of threads for dlsch decoding, 0 means no parallelization
+  tpool_t        Tpool;             // thread pool 
+} nrUE_params_t;
+
+nrUE_params_t nrUE_params;
+
+nrUE_params_t *get_nrUE_params(void) {
+  return &nrUE_params;
+}
+
+void processSlotTX(void *arg) {}
+
 int main(int argc, char **argv){
 
   char c;
diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c
index d348df27cf6c58a4d263954c2cde28e4a0da1a3f..1fa98e1a0ea202e953c47c32a2c470cff5c0e224 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -198,6 +198,19 @@ int nr_derive_key(int alg_type, uint8_t alg_id,
   return 0;
 }
 
+typedef struct {
+  uint64_t       optmask;   //mask to store boolean config options
+  uint8_t        nr_dlsch_parallel; // number of threads for dlsch decoding, 0 means no parallelization
+  tpool_t        Tpool;             // thread pool 
+} nrUE_params_t;
+
+void processSlotTX(void *arg) {}
+
+nrUE_params_t nrUE_params;
+
+nrUE_params_t *get_nrUE_params(void) {
+  return &nrUE_params;
+}
 // needed for some functions
 uint16_t n_rnti = 0x1234;
 openair0_config_t openair0_cfg[MAX_CARDS];
@@ -663,13 +676,7 @@ int main(int argc, char **argv)
 
   prepare_scd(scd);
 
-  fill_default_secondaryCellGroup(scc,
-                                  scd,
-				  secondaryCellGroup,
-				  0,
-				  1,
-				  n_tx,
-				  0);
+  fill_default_secondaryCellGroup(scc, scd, secondaryCellGroup, 0, 1, n_tx, 0, 0);
 
   // xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup);
 
diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h
index 308af2eeb916b760f5643f19c0e84b4874d5dc7d..60b40cb349b3143dcd05b248ea9f37b41f4cf8f0 100644
--- a/openair2/GNB_APP/MACRLC_nr_paramdef.h
+++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h
@@ -55,7 +55,7 @@
 #define CONFIG_STRING_MACRLC_REMOTE_S_PORTC                "remote_s_portc"
 #define CONFIG_STRING_MACRLC_LOCAL_S_PORTD                 "local_s_portd"
 #define CONFIG_STRING_MACRLC_REMOTE_S_PORTD                "remote_s_portd"
-
+#define CONFIG_STRING_MACRLC_ULSCH_MAX_SLOTS_INACTIVITY    "ulsch_max_slots_inactivity"
 
 /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
 /*                                            MacRLC  configuration parameters                                                                           */
@@ -79,6 +79,7 @@
 {CONFIG_STRING_MACRLC_REMOTE_S_PORTC,                    NULL,     0,          uptr:NULL,           defintval:50020,           TYPE_UINT,     0},        \
 {CONFIG_STRING_MACRLC_LOCAL_S_PORTD,                     NULL,     0,          uptr:NULL,           defintval:50021,           TYPE_UINT,     0},        \
 {CONFIG_STRING_MACRLC_REMOTE_S_PORTD,                    NULL,     0,          uptr:NULL,           defintval:50021,           TYPE_UINT,     0},        \
+{CONFIG_STRING_MACRLC_ULSCH_MAX_SLOTS_INACTIVITY,        "Maximum number of slots before a UE is scheduled ULSCH due to inactivity", 0, uptr:NULL, defintval:200, TYPE_UINT, 0}, \
 }
 #define MACRLC_CC_IDX                                          0
 #define MACRLC_TRANSPORT_N_PREFERENCE_IDX                      1
@@ -97,5 +98,6 @@
 #define MACRLC_REMOTE_S_PORTC_IDX                              14
 #define MACRLC_LOCAL_S_PORTD_IDX                               15
 #define MACRLC_REMOTE_S_PORTD_IDX                              16
+#define MACRLC_ULSCH_MAX_SLOTS_INACTIVITY                      17
 /*---------------------------------------------------------------------------------------------------------------------------------------------------------*/
 #endif
diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c
index d3dd769807981953157190d5e717ff0c2d73323f..b9bf141fce69d43738d3b7d049c066bbb18af01e 100644
--- a/openair2/GNB_APP/gnb_config.c
+++ b/openair2/GNB_APP/gnb_config.c
@@ -53,7 +53,7 @@
 
 //#include "L1_paramdef.h"
 #include "L1_nr_paramdef.h"
-#include "MACRLC_paramdef.h"
+#include "MACRLC_nr_paramdef.h"
 #include "common/config/config_userapi.h"
 //#include "RRC_config_tools.h"
 #include "gnb_paramdef.h"
@@ -698,6 +698,7 @@ void RCconfig_nr_macrlc() {
       }else { // other midhaul
         AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr));
       } 
+      RC.nrmac[j]->ulsch_max_slots_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_SLOTS_INACTIVITY].uptr);
     }//  for (j=0;j<RC.nb_nr_macrlc_inst;j++)
   }else {// MacRLC_ParamList.numelt > 0
     AssertFatal (0,"No " CONFIG_STRING_MACRLC_LIST " configuration found");     
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index d3e8ed01df6db164534b5f79a2cafb2bda7657fb..adbf7a5774bc6fd382fac3675670c7a55df3366b 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -837,7 +837,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
              using tables 7.3.1.2.2-1, 7.3.1.2.2-2, 7.3.1.2.2-3, 7.3.1.2.2-4 of 3GPP TS 38.212 */
     dlsch_config_pdu_1_1->n_dmrs_cdm_groups = 1;
     /* VRB_TO_PRB_MAPPING */
-    if (mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.resource_allocation != 0)
+    if ((pdsch_config->resourceAllocation == 1) && (pdsch_config->vrb_ToPRB_Interleaver != NULL))
       dlsch_config_pdu_1_1->vrb_to_prb_mapping = (dci->vrb_to_prb_mapping.val == 0) ? vrb_to_prb_mapping_non_interleaved:vrb_to_prb_mapping_interleaved;
     /* PRB_BUNDLING_SIZE_IND */
     dlsch_config_pdu_1_1->prb_bundling_size_ind = dci->prb_bundling_size_indicator.val;
@@ -896,11 +896,22 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
     /* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */
     // according to TS 38.213 Table 9.2.3-1
     NR_BWP_Id_t ul_bwp_id = mac->UL_BWP_Id;
-    dlsch_config_pdu_1_1->pdsch_to_harq_feedback_time_ind = mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0];
+    dlsch_config_pdu_1_1->pdsch_to_harq_feedback_time_ind =
+      mac->ULbwp[ul_bwp_id-1]->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0];
+
     /* ANTENNA_PORTS */
     uint8_t n_codewords = 1; // FIXME!!!
-    if ((mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.dmrs_type == 1) &&
-	(mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.max_length == 1)){
+    long *max_length = NULL;
+    long *dmrs_type = NULL;
+    if (pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA) {
+      max_length = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->maxLength;
+      dmrs_type = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type;
+    }
+    if (pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB) {
+      max_length = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->maxLength;
+      dmrs_type = pdsch_config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type;
+    }
+    if ((dmrs_type == NULL) && (max_length == NULL)){
       // Table 7.3.1.2.2-1: Antenna port(s) (1000 + DMRS port), dmrs-Type=1, maxLength=1
       dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_1[dci->antenna_ports.val][0];
       dlsch_config_pdu_1_1->dmrs_ports[0]     = table_7_3_2_3_3_1[dci->antenna_ports.val][1];
@@ -908,8 +919,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
       dlsch_config_pdu_1_1->dmrs_ports[2]     = table_7_3_2_3_3_1[dci->antenna_ports.val][3];
       dlsch_config_pdu_1_1->dmrs_ports[3]     = table_7_3_2_3_3_1[dci->antenna_ports.val][4];
     }
-    if ((mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.dmrs_type == 1) &&
-	(mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.max_length == 2)){
+    if ((dmrs_type == NULL) && (max_length != NULL)){
       // Table 7.3.1.2.2-2: Antenna port(s) (1000 + DMRS port), dmrs-Type=1, maxLength=2
       if (n_codewords == 1) {
 	dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_2_oneCodeword[dci->antenna_ports.val][0];
@@ -932,8 +942,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
 	dlsch_config_pdu_1_1->n_front_load_symb = table_7_3_2_3_3_2_twoCodeword[dci->antenna_ports.val][9];
       }
     }
-    if ((mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.dmrs_type == 2) &&
-	(mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.max_length == 1)){
+    if ((dmrs_type != NULL) && (max_length == NULL)){
       // Table 7.3.1.2.2-3: Antenna port(s) (1000 + DMRS port), dmrs-Type=2, maxLength=1
       if (n_codewords == 1) {
 	dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_3_oneCodeword[dci->antenna_ports.val][0];
@@ -952,8 +961,7 @@ int8_t nr_ue_process_dci(module_id_t module_id, int cc_id, uint8_t gNB_index, fr
 	dlsch_config_pdu_1_1->dmrs_ports[5]     = table_7_3_2_3_3_3_twoCodeword[dci->antenna_ports.val][6];
       }
     }
-    if ((mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.dmrs_type == 2) &&
-	(mac->phy_config.config_req.dl_bwp_dedicated.pdsch_config_dedicated.dmrs_dl_for_pdsch_mapping_type_a.max_length == 2)){
+    if ((dmrs_type != NULL) && (max_length != NULL)){
       // Table 7.3.1.2.2-4: Antenna port(s) (1000 + DMRS port), dmrs-Type=2, maxLength=2
       if (n_codewords == 1) {
 	dlsch_config_pdu_1_1->n_dmrs_cdm_groups = table_7_3_2_3_3_4_oneCodeword[dci->antenna_ports.val][0];
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
index 750a19112d0cd061cffa472a6a0c671e9715c1d8..3bd10ab4a7a3e32c09b22e492f433cca65bd1c0e 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
@@ -149,14 +149,25 @@ fapi_nr_ul_config_request_t *get_ul_config_request(NR_UE_MAC_INST_t *mac, int sl
 
 void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, dci_pdu_rel15_t *dci) {
 
-  fapi_nr_pusch_config_dedicated_t *pusch_config_dedicated = &mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated;
+  NR_ServingCellConfigCommon_t *scc = mac->scc;
   NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup;
 
+  long	transformPrecoder;
+  if (pusch_Config->transformPrecoder)
+    transformPrecoder = *pusch_Config->transformPrecoder;
+  else {
+    if(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder)
+      transformPrecoder = NR_PUSCH_Config__transformPrecoder_enabled;
+    else
+      transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled;
+  }
+
+
   /* PRECOD_NBR_LAYERS */
-  if ((pusch_config_dedicated->tx_config == tx_config_nonCodebook));
+  if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook));
   // 0 bits if the higher layer parameter txConfig = nonCodeBook
 
-  if ((pusch_config_dedicated->tx_config == tx_config_codebook)){
+  if ((*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)){
 
     uint8_t n_antenna_port = 0; //FIXME!!!
 
@@ -165,43 +176,43 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con
     if (n_antenna_port == 4){ // 4 antenna port and the higher layer parameter txConfig = codebook
 
       // Table 7.3.1.1.2-2: transformPrecoder=disabled and maxRank = 2 or 3 or 4
-      if ((pusch_config_dedicated->transform_precoder == transform_precoder_disabled)
-        && ((pusch_config_dedicated->max_rank == 2) ||
-        (pusch_config_dedicated->max_rank == 3) ||
-        (pusch_config_dedicated->max_rank == 4))){
+      if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)
+        && ((*pusch_Config->maxRank == 2) ||
+        (*pusch_Config->maxRank == 3) ||
+        (*pusch_Config->maxRank == 4))){
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_fullyAndPartialAndNonCoherent) {
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][0];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1];
         }
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_partialAndNonCoherent){
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][2];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3];
         }
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_nonCoherent){
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][4];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5];
         }
       }
 
       // Table 7.3.1.1.2-3: transformPrecoder= enabled, or transformPrecoder=disabled and maxRank = 1
-      if (((pusch_config_dedicated->transform_precoder == transform_precoder_enabled)
-        || (pusch_config_dedicated->transform_precoder == transform_precoder_disabled))
-        && (pusch_config_dedicated->max_rank == 1)){
+      if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)
+        || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
+        && (*pusch_Config->maxRank == 1)){
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_fullyAndPartialAndNonCoherent) {
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][6];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7];
         }
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_partialAndNonCoherent){
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][8];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9];
         }
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_nonCoherent){
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][10];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11];
         }
@@ -210,14 +221,14 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con
 
     if (n_antenna_port == 4){ // 2 antenna port and the higher layer parameter txConfig = codebook
       // Table 7.3.1.1.2-4: transformPrecoder=disabled and maxRank = 2
-      if ((pusch_config_dedicated->transform_precoder == transform_precoder_disabled) && (pusch_config_dedicated->max_rank == 2)){
+      if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)){
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_fullyAndPartialAndNonCoherent) {
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][12];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13];
         }
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_nonCoherent){
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][14];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15];
         }
@@ -225,16 +236,16 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con
       }
 
       // Table 7.3.1.1.2-5: transformPrecoder= enabled, or transformPrecoder= disabled and maxRank = 1
-      if (((pusch_config_dedicated->transform_precoder == transform_precoder_enabled)
-        || (pusch_config_dedicated->transform_precoder == transform_precoder_disabled))
-        && (pusch_config_dedicated->max_rank == 1)){
+      if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)
+        || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
+        && (*pusch_Config->maxRank == 1)){
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_fullyAndPartialAndNonCoherent) {
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][16];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17];
         }
 
-        if (pusch_config_dedicated->codebook_subset == codebook_subset_nonCoherent){
+        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][18];
           pusch_config_pdu->transform_precoding = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19];
         }
@@ -245,7 +256,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con
 
   /*-------------------- Changed to enable Transform precoding in RF SIM------------------------------------------------*/
 
-  if (pusch_config_pdu->transform_precoding == transform_precoder_enabled) {
+ /*if (pusch_config_pdu->transform_precoding == transform_precoder_enabled) {
 
     pusch_config_dedicated->transform_precoder = transform_precoder_enabled;
 
@@ -269,15 +280,7 @@ void ul_layers_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_con
 
     }
   } else
-    pusch_config_dedicated->transform_precoder = transform_precoder_disabled;
-
-  // mapping type b configured from RRC. TBD: Mapping type b is not handled in this function.
-  if ((pusch_config_dedicated->transform_precoder == transform_precoder_enabled) &&
-      (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_b.dmrs_type == 1) &&
-      (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_b.max_length == 1)) { // tables 7.3.1.1.2-6
-    pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
-    pusch_config_pdu->dmrs_ports = dci->antenna_ports.val;
-  }
+    pusch_config_dedicated->transform_precoder = transform_precoder_disabled;*/
 }
 
 // todo: this function shall be reviewed completely because of the many comments left by the author
@@ -285,27 +288,47 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf
 
   /* ANTENNA_PORTS */
   uint8_t rank = 0; // We need to initialize rank FIXME!!!
-  fapi_nr_pusch_config_dedicated_t *pusch_config_dedicated = &mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated;
 
-  if ((pusch_config_dedicated->transform_precoder == transform_precoder_enabled) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.max_length == 1)) { // tables 7.3.1.1.2-6
+  NR_ServingCellConfigCommon_t *scc = mac->scc;
+  NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup;
+
+  long	transformPrecoder;
+  if (pusch_Config->transformPrecoder)
+    transformPrecoder = *pusch_Config->transformPrecoder;
+  else {
+    if(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder)
+      transformPrecoder = NR_PUSCH_Config__transformPrecoder_enabled;
+    else
+      transformPrecoder = NR_PUSCH_Config__transformPrecoder_disabled;
+  }
+  long *max_length = NULL;
+  long *dmrs_type = NULL;
+  if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA) {
+    max_length = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->maxLength;
+    dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->dmrs_Type;
+  }
+  else {
+    max_length = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->maxLength;
+    dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->dmrs_Type;
+  }
+
+
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) &&
+    (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC
       pusch_config_pdu->dmrs_ports = dci->antenna_ports.val; //TBC
   }
 
-  if ((pusch_config_dedicated->transform_precoder == transform_precoder_enabled) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.max_length == 2)) { // tables 7.3.1.1.2-7
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) &&
+    (dmrs_type == NULL) && (max_length != NULL)) { // tables 7.3.1.1.2-7
 
     pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC
     pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 3)?(dci->antenna_ports.val-4):(dci->antenna_ports.val); //TBC
     //pusch_config_pdu->n_front_load_symb = (dci->antenna_ports > 3)?2:1; //FIXME
   }
 
-  if ((pusch_config_dedicated->transform_precoder == transform_precoder_disabled) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.max_length == 1)) { // tables 7.3.1.1.2-8/9/10/11
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) &&
+    (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-8/9/10/11
 
     if (rank == 1) {
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC
@@ -337,9 +360,8 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf
     }
   }
 
-  if ((pusch_config_dedicated->transform_precoder == transform_precoder_disabled) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 1) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.max_length == 2)) { // tables 7.3.1.1.2-12/13/14/15
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) &&
+    (dmrs_type == NULL) && (max_length != NULL)) { // tables 7.3.1.1.2-12/13/14/15
 
     if (rank == 1){
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC
@@ -375,9 +397,9 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf
     }
   }
 
-  if ((pusch_config_dedicated->transform_precoder == transform_precoder_disabled) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 2) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.max_length == 1)) { // tables 7.3.1.1.2-16/17/18/19
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) &&
+    (dmrs_type != NULL) &&
+    (max_length == NULL)) { // tables 7.3.1.1.2-16/17/18/19
 
     if (rank == 1){
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?((dci->antenna_ports.val > 5)?3:2):1; //TBC
@@ -409,9 +431,8 @@ void ul_ports_config(NR_UE_MAC_INST_t * mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf
     }
   }
 
-  if ((pusch_config_dedicated->transform_precoder == transform_precoder_disabled) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.dmrs_type == 2) &&
-    (pusch_config_dedicated->dmrs_ul_for_pusch_mapping_type_a.max_length == 2)) { // tables 7.3.1.1.2-20/21/22/23
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) &&
+    (dmrs_type != NULL) && (max_length != NULL)) { // tables 7.3.1.1.2-20/21/22/23
 
     if (rank == 1){
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_20[dci->antenna_ports.val][0]; //TBC
@@ -577,7 +598,6 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
     int target_ss;
     bool valid_ptrs_setup = 0;
     uint16_t n_RB_ULBWP = NRRIV2BW(mac->ULbwp[0]->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
-    fapi_nr_pusch_config_dedicated_t *pusch_config_dedicated = &mac->phy_config.config_req.ul_bwp_dedicated.pusch_config_dedicated;
     NR_PUSCH_Config_t *pusch_Config = mac->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup;
 
     // Basic sanity check for MCS value to check for a false or erroneous DCI
@@ -668,7 +688,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
     }
 
     /* FREQ_HOPPING_FLAG */
-    if ((pusch_config_dedicated->resource_allocation != 0) && (pusch_config_dedicated->frequency_hopping !=0)){
+    if ((pusch_Config->frequencyHopping!=NULL) && (pusch_Config->resourceAllocation != NR_PUSCH_Config__resourceAllocation_resourceAllocationType0)){
       pusch_config_pdu->frequency_hopping = dci->frequency_hopping_flag.val;
     }
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c
index 528edc64aa5e098322849a0f99d471857d6ec97a..98e9ce4351b80ef4cfa488c68e93c1254269c489 100644
--- a/openair2/LAYER2/NR_MAC_gNB/config.c
+++ b/openair2/LAYER2/NR_MAC_gNB/config.c
@@ -372,14 +372,6 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
     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");
 
-    for (int i = 0; i < MAX_NUM_BWP; ++i) {
-      RC.nrmac[Mod_idP]->pucch_index_used[i] =
-        calloc(n, sizeof(*RC.nrmac[Mod_idP]->pucch_index_used));
-      AssertFatal(RC.nrmac[Mod_idP]->pucch_index_used[i],
-                  "could not allocate memory for RC.nrmac[]->pucch_index_used[%d]\n",
-                  i);
-    }
-
     LOG_I(MAC,"Configuring common parameters from NR ServingCellConfig\n");
 
     config_common(Mod_idP,
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
index 7175a129ba98a047947a2e1aff4bbe4c9645f243..36f687b5cd2bed4d2896107e8469d368fdac164c 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
@@ -402,7 +402,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
   }
 
   // This schedule SR
-  // TODO
+  nr_sr_reporting(module_idP, frame, slot);
 
   // Schedule CSI measurement reporting: check in slot 0 for the whole frame
   if (slot == 0)
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c
index cc61df0be76d834a9db3afc39a54717e7dbb1cd7..f93ad92a1391940116b5f8e92fe41fca0ed96e68 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c
@@ -253,8 +253,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
         case 3:
           // long bitmap FR2 max 64 SSBs
           num_ssb = 0;
-          for (int i_ssb=0; i_ssb<63; i_ssb++) {
-            if ((longBitmap->buf[i_ssb/8]>>(7-i_ssb))&0x01) {
+          for (int i_ssb=0; i_ssb<64; i_ssb++) {
+            if ((longBitmap->buf[i_ssb/8]>>(7-(i_ssb%8)))&0x01) {
               ssb_start_symbol = get_ssb_start_symbol(band,scs,i_ssb);
               // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters
               if ((ssb_start_symbol/14) == rel_slot){
@@ -433,8 +433,8 @@ void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP,
                      bwp);
 
   // TODO: This assignment should be done in function nr_configure_pdcch()
-  pdcch_pdu_rel15->BWPSize = gNB_mac->type0_PDCCH_CSS_config->num_rbs;
-  pdcch_pdu_rel15->BWPStart = gNB_mac->type0_PDCCH_CSS_config->cset_start_rb;
+  pdcch_pdu_rel15->BWPSize = type0_PDCCH_CSS_config->num_rbs;
+  pdcch_pdu_rel15->BWPStart = type0_PDCCH_CSS_config->cset_start_rb;
 
   nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs];
   memset((void*)dl_tti_pdsch_pdu,0,sizeof(nfapi_nr_dl_tti_request_pdu_t));
@@ -593,7 +593,8 @@ void schedule_nr_sib1(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
       uint8_t sib1_sdu_length = mac_rrc_nr_data_req(module_idP, CC_id, frameP, BCCH, SI_RNTI, 1, sib1_payload);
       LOG_D(NR_MAC,"sib1_sdu_length = %i\n", sib1_sdu_length);
       LOG_D(NR_MAC,"SIB1: \n");
-      for (int k=0;k<sib1_sdu_length;k++) LOG_D(NR_MAC,"byte %d : %x\n",k,((uint8_t*)sib1_payload)[k]);
+      for (int k=0;k<sib1_sdu_length;k++)
+        LOG_D(NR_MAC,"byte %d : %x\n",k,((uint8_t*)sib1_payload)[k]);
 
       // Configure sched_ctrlCommon for SIB1
       schedule_control_sib1(module_idP, CC_id, type0_PDCCH_CSS_config, time_domain_allocation, mcsTableIdx, mcs, candidate_idx, sib1_sdu_length);
@@ -609,7 +610,7 @@ void schedule_nr_sib1(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
       }
 
       // TODO: There are exceptions to this in table 5.1.2.1.1-4,5 (Default time domain allocation tables B, C)
-      int mappingtype = (startSymbolIndex <= 3) ? typeA : typeB ;
+      int mappingtype = (startSymbolIndex <= 3) ? typeA : typeB;
 
       // Calculate number of PRB_DMRS
       uint8_t N_PRB_DMRS = gNB_mac->sched_ctrlCommon->pdsch_semi_static.numDmrsCdmGrpsNoData * 6;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
index d36f274f47e97407a1603856ba9b3a7cd7204545..800c23a9a0b318afa2fcb2fc6e34648bd8e66de9 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
@@ -118,8 +118,13 @@ int diff_rsrp_ssb_csi_meas_10_1_6_1_2[16] = {
 
 void nr_schedule_pucch(int Mod_idP,
                        frame_t frameP,
-                       sub_frame_t slotP) {
-  NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info;
+                       sub_frame_t slotP)
+{
+  gNB_MAC_INST *nrmac = RC.nrmac[Mod_idP];
+  if (!is_xlsch_in_slot(nrmac->ulsch_slot_bitmap[slotP / 64], slotP))
+    return;
+
+  NR_UE_info_t *UE_info = &nrmac->UE_info;
   const NR_list_t *UE_list = &UE_info->list;
 
   for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
@@ -504,11 +509,11 @@ void nr_csi_meas_reporting(int Mod_idP,
 
       // find free PUCCH that is in order with possibly existing PUCCH
       // schedulings (other CSI, SR)
-      NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[2];
+      NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[1];
       AssertFatal(curr_pucch->csi_bits == 0
                   && !curr_pucch->sr_flag
                   && curr_pucch->dai_c == 0,
-                  "PUCCH not free at index 2 for UE %04x\n",
+                  "PUCCH not free at index 1 for UE %04x\n",
                   UE_info->rnti[UE_id]);
       curr_pucch->frame = frame;
       curr_pucch->ul_slot = sched_slot;
@@ -1007,12 +1012,6 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id,
   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);
-  sched_ctrl->pucch_snrx10 = uci_01->ul_cqi * 5 - 640;
-
   if (((uci_01->pduBitmap >> 1) & 0x01)) {
     // iterate over received harq bits
     for (int harq_bit = 0; harq_bit < uci_01->harq->num_harq; harq_bit++) {
@@ -1027,6 +1026,20 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id,
       handle_dl_harq(mod_id, UE_id, pid, harq_value == 1 && harq_confidence == 0);
     }
   }
+
+  // check scheduling request result, confidence_level == 0 is good
+  if (uci_01->pduBitmap & 0x1 && uci_01->sr->sr_indication && uci_01->sr->sr_confidence_level == 0 && uci_01->ul_cqi >= 148) {
+    // SR detected with SNR >= 10dB
+    sched_ctrl->SR |= true;
+    LOG_D(MAC, "SR UE %04x ul_cqi %d\n", uci_01->rnti, uci_01->ul_cqi);
+  }
+
+  // tpc (power control) only if we received AckNack or positive SR. For a
+  // negative SR, the UE won't have sent anything, and the SNR is not valid
+  if (((uci_01->pduBitmap >> 1) & 0x1) || sched_ctrl->SR) {
+    sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10, uci_01->ul_cqi, 30);
+    sched_ctrl->pucch_snrx10 = uci_01->ul_cqi * 5 - 640;
+  }
 }
 
 void handle_nr_uci_pucch_2_3_4(module_id_t mod_id,
@@ -1100,10 +1113,7 @@ bool nr_acknack_scheduling(int mod_id,
    * * we do not multiplex with CSI, which is always in pucch_sched[2]
    * * SR uses format 0 and is allocated in the first UL (mixed) slot (and not
    *   later)
-   * * that the PUCCH resource set 0 (for up to 2 bits) points to the first N
-   *   PUCCH resources, where N is the number of resources in the PUCCH
-   *   resource set. This is used in pucch_index_used, which counts the used
-   *   resources by index, and not by their ID! */
+   * * each UE has dedicated PUCCH Format 0 resources, and we use index 0! */
   NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[mod_id]->UE_info.UE_sched_ctrl[UE_id];
   NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0];
   AssertFatal(pucch->csi_bits == 0,
@@ -1111,12 +1121,8 @@ bool nr_acknack_scheduling(int mod_id,
               __func__,
               pucch->csi_bits);
 
-  const int max_acknacks = 2;
-  AssertFatal(pucch->dai_c + pucch->sr_flag <= max_acknacks,
-              "illegal number of bits in PUCCH of UE %d\n",
-              UE_id);
   /* if the currently allocated PUCCH of this UE is full, allocate it */
-  if (pucch->sr_flag + pucch->dai_c == max_acknacks) {
+  if (pucch->dai_c == 2) {
     /* advance the UL slot information in PUCCH by one so we won't schedule in
      * the same slot again */
     const int f = pucch->frame;
@@ -1126,7 +1132,7 @@ bool nr_acknack_scheduling(int mod_id,
     pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f;
     pucch->ul_slot = (s + 1) % n_slots_frame;
     // we assume that only two indices over the array sched_pucch exist
-    const NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[2];
+    NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[1];
     // skip the CSI PUCCH if it is present and if in the next frame/slot
     if (csi_pucch->csi_bits > 0
         && csi_pucch->frame == pucch->frame
@@ -1138,6 +1144,7 @@ bool nr_acknack_scheduling(int mod_id,
                   pucch->ul_slot,
                   UE_id);
       nr_fill_nfapi_pucch(mod_id, frame, slot, csi_pucch, UE_id);
+      memset(csi_pucch, 0, sizeof(*csi_pucch));
       pucch->frame = s >= n_slots_frame - 2 ?  (f + 1) % 1024 : f;
       pucch->ul_slot = (s + 2) % n_slots_frame;
     }
@@ -1156,9 +1163,8 @@ bool nr_acknack_scheduling(int mod_id,
   uint8_t pdsch_to_harq_feedback[8];
   get_pdsch_to_harq_feedback(mod_id, UE_id, ss_type, pdsch_to_harq_feedback);
 
-  /* there is a scheduled SR or HARQ. Check whether we can use it for this
-   * ACKNACK */
-  if (pucch->sr_flag + pucch->dai_c > 0) {
+  /* there is a HARQ. Check whether we can use it for this ACKNACK */
+  if (pucch->dai_c > 0) {
     /* this UE already has a PUCCH occasion */
     DevAssert(pucch->frame == frame);
 
@@ -1189,18 +1195,14 @@ bool nr_acknack_scheduling(int mod_id,
 
   /* we need to find a new PUCCH occasion */
 
-  NR_PUCCH_Config_t *pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup;
-  DevAssert(pucch_Config->resourceToAddModList->list.count > 0);
-  DevAssert(pucch_Config->resourceSetToAddModList->list.count > 0);
-  const int n_res = pucch_Config->resourceSetToAddModList->list.array[0]->resourceList.list.count;
-  int *pucch_index_used = RC.nrmac[mod_id]->pucch_index_used[sched_ctrl->active_ubwp->bwp_Id];
-
   /* if time information is outdated (e.g., last PUCCH occasion in last frame),
    * set to first possible UL occasion in this frame. Note that if such UE is
    * scheduled a lot and used all AckNacks, pucch->frame might have been
    * wrapped around to next frame */
   if (frame != pucch->frame || pucch->ul_slot < first_ul_slot_tdd) {
-    DevAssert(pucch->sr_flag + pucch->dai_c == 0);
+    AssertFatal(pucch->sr_flag + pucch->dai_c == 0,
+                "expected no SR/AckNack for UE %d in %4d.%2d, but has %d/%d for %4d.%2d\n",
+                UE_id, frame, slot, pucch->sr_flag, pucch->dai_c, pucch->frame, pucch->ul_slot);
     AssertFatal(frame + 1 != pucch->frame,
                 "frame wrap around not handled in %s() yet\n",
                 __func__);
@@ -1208,27 +1210,11 @@ bool nr_acknack_scheduling(int mod_id,
     pucch->ul_slot = first_ul_slot_tdd;
   }
 
-  // increase to first slot in which PUCCH resources are available
-  while (pucch_index_used[pucch->ul_slot] >= n_res) {
-    pucch->ul_slot++;
-    /* if there is no free resource anymore, abort search */
-    if ((pucch->frame == frame
-         && pucch->ul_slot >= first_ul_slot_tdd + nr_ulmix_slots)
-        || (pucch->frame == frame + 1)) {
-      LOG_E(MAC,
-            "%4d.%2d no free PUCCH resources anymore while searching for UE %d\n",
-            frame,
-            slot,
-            UE_id);
-      return false;
-    }
-  }
-
   // advance ul_slot if it is not reachable by UE
   pucch->ul_slot = max(pucch->ul_slot, slot + pdsch_to_harq_feedback[0]);
 
   // is there already CSI in this slot?
-  const NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[2];
+  NR_sched_pucch_t *csi_pucch = &sched_ctrl->sched_pucch[1];
   // skip the CSI PUCCH if it is present and if in the next frame/slot
   if (csi_pucch->csi_bits > 0
       && csi_pucch->frame == pucch->frame
@@ -1240,6 +1226,7 @@ bool nr_acknack_scheduling(int mod_id,
                 pucch->ul_slot,
                 UE_id);
     nr_fill_nfapi_pucch(mod_id, frame, slot, csi_pucch, UE_id);
+    memset(csi_pucch, 0, sizeof(*csi_pucch));
     /* advance the UL slot information in PUCCH by one so we won't schedule in
      * the same slot again */
     const int f = pucch->frame;
@@ -1270,29 +1257,19 @@ bool nr_acknack_scheduling(int mod_id,
   pucch->timing_indicator = i; // index in the list of timing indicators
 
   pucch->dai_c++;
-  const int pucch_res = pucch_index_used[pucch->ul_slot];
-  pucch->resource_indicator = pucch_res;
-  pucch_index_used[pucch->ul_slot] += 1;
-  AssertFatal(pucch_index_used[pucch->ul_slot] <= n_res,
-              "UE %d in %4d.%2d: pucch_index_used is %d (%d available)\n",
-              UE_id,
-              pucch->frame,
-              pucch->ul_slot,
-              pucch_index_used[pucch->ul_slot],
-              n_res);
+  pucch->resource_indicator = 0; // each UE has dedicated PUCCH resources
 
   /* verify that at that slot and symbol, resources are free. We only do this
    * for initialCyclicShift 0 (we assume it always has that one), so other
    * initialCyclicShifts can overlap with ICS 0!*/
-  const NR_PUCCH_Resource_t *resource =
-      pucch_Config->resourceToAddModList->list.array[pucch_res];
+  const NR_PUCCH_Config_t *pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup;
+  const NR_PUCCH_Resource_t *resource = pucch_Config->resourceToAddModList->list.array[pucch->resource_indicator];
   DevAssert(resource->format.present == NR_PUCCH_Resource__format_PR_format0);
   if (resource->format.choice.format0->initialCyclicShift == 0) {
     uint16_t *vrb_map_UL = &RC.nrmac[mod_id]->common_channels[CC_id].vrb_map_UL[pucch->ul_slot * MAX_BWP_SIZE];
     const uint16_t symb = 1 << resource->format.choice.format0->startingSymbolIndex;
-    AssertFatal((vrb_map_UL[resource->startingPRB] & symb) == 0,
-                "symbol %x is not free for PUCCH alloc in vrb_map_UL at RB %ld and slot %d\n",
-                symb, resource->startingPRB, pucch->ul_slot);
+    if ((vrb_map_UL[resource->startingPRB] & symb) != 0)
+      LOG_W(MAC, "symbol 0x%x is not free for PUCCH alloc in vrb_map_UL at RB %ld and slot %d.%d\n", symb, resource->startingPRB, pucch->frame, pucch->ul_slot);
     vrb_map_UL[resource->startingPRB] |= symb;
   }
   return true;
@@ -1425,3 +1402,154 @@ uint16_t compute_pucch_prb_size(uint8_t format,
     AssertFatal(1==0,"Not yet implemented");
   }
 }
+
+void nr_sr_reporting(int Mod_idP, frame_t SFN, sub_frame_t slot)
+{
+  gNB_MAC_INST *nrmac = RC.nrmac[Mod_idP];
+  if (!is_xlsch_in_slot(nrmac->ulsch_slot_bitmap[slot / 64], slot))
+    return;
+  NR_ServingCellConfigCommon_t *scc = nrmac->common_channels->ServingCellConfigCommon;
+  const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
+  NR_UE_info_t *UE_info = &nrmac->UE_info;
+  NR_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];
+    NR_PUCCH_Config_t *pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup;
+    AssertFatal(pucch_Config->schedulingRequestResourceToAddModList->list.count>0,"NO SR configuration available");
+
+    for (int SR_resource_id =0; SR_resource_id < pucch_Config->schedulingRequestResourceToAddModList->list.count;SR_resource_id++) {
+      NR_SchedulingRequestResourceConfig_t *SchedulingRequestResourceConfig = pucch_Config->schedulingRequestResourceToAddModList->list.array[SR_resource_id];
+
+      int SR_period; int SR_offset;
+
+      periodicity__SRR(SchedulingRequestResourceConfig,&SR_period,&SR_offset);
+      // convert to int to avoid underflow of uint
+      int sfn_sf = SFN * n_slots_frame + slot;
+      if ((sfn_sf - SR_offset) % SR_period != 0)
+        continue;
+      LOG_D(MAC, "%4d.%2d Scheduling Request identified\n", SFN, slot);
+      NR_PUCCH_ResourceId_t *PucchResourceId = SchedulingRequestResourceConfig->resource;
+
+      int found = -1;
+      NR_PUCCH_ResourceSet_t *pucchresset = pucch_Config->resourceSetToAddModList->list.array[0]; // set with formats 0,1
+      int n_list = pucchresset->resourceList.list.count;
+       for (int i=0; i<n_list; i++) {
+        if (*pucchresset->resourceList.list.array[i] == *PucchResourceId )
+          found = i;
+      }
+      AssertFatal(found>-1,"SR resource not found among PUCCH resources");
+
+      /* loop through nFAPI PUCCH messages: if the UEs is in there in this slot
+       * with the resource_indicator, it means we already allocated that PUCCH
+       * resource for AckNack (e.g., the UE has been scheduled often), and we
+       * just need to add the SR_flag. Otherwise, just allocate in the internal
+       * PUCCH resource, and nr_schedule_pucch() will handle the rest */
+      NR_PUCCH_Resource_t *pucch_res = pucch_Config->resourceToAddModList->list.array[found];
+      /* for the moment, can only handle SR on PUCCH Format 0 */
+      DevAssert(pucch_res->format.present == NR_PUCCH_Resource__format_PR_format0);
+      nfapi_nr_ul_tti_request_t *ul_tti_req = &nrmac->UL_tti_req_ahead[0][slot];
+      bool nfapi_allocated = false;
+      for (int i = 0; i < ul_tti_req->n_pdus; ++i) {
+        if (ul_tti_req->pdus_list[i].pdu_type != NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE)
+          continue;
+        nfapi_nr_pucch_pdu_t *pdu = &ul_tti_req->pdus_list[i].pucch_pdu;
+        /* check that it is our PUCCH F0. Assuming there can be only one */
+        if (pdu->rnti == UE_info->rnti[UE_id]
+            && pdu->format_type == 0 // does not use NR_PUCCH_Resource__format_PR_format0
+            && pdu->initial_cyclic_shift == pucch_res->format.choice.format0->initialCyclicShift
+            && pdu->nr_of_symbols == pucch_res->format.choice.format0->nrofSymbols
+            && pdu->start_symbol_index == pucch_res->format.choice.format0->startingSymbolIndex) {
+          LOG_D(MAC,"%4d.%2d adding SR_flag 1 to PUCCH nFAPI SR for RNTI %04x\n", SFN, slot, pdu->rnti);
+          pdu->sr_flag = 1;
+          nfapi_allocated = true;
+          break;
+        }
+      }
+
+      if (nfapi_allocated)  // break scheduling resource loop, continue next UE
+        break;
+
+      /* we did not find it: check if current PUCCH is for the current slot, in
+       * which case we add the SR to it; otherwise, allocate SR separately */
+      NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[0];
+      if (curr_pucch->frame == SFN && curr_pucch->ul_slot == slot) {
+        if (curr_pucch->resource_indicator != found) {
+          LOG_W(MAC, "%4d.%2d expected PUCCH in this slot to have resource indicator of SR (%d), skipping SR\n", SFN, slot, found);
+          continue;
+        }
+        curr_pucch->sr_flag = true;
+      } else {
+        NR_sched_pucch_t sched_sr;
+        memset(&sched_sr, 0, sizeof(sched_sr));
+        sched_sr.frame = SFN;
+        sched_sr.ul_slot = slot;
+        sched_sr.resource_indicator = found;
+        sched_sr.sr_flag = true;
+        nr_fill_nfapi_pucch(Mod_idP, SFN, slot, &sched_sr, UE_id);
+      }
+    }
+  }
+}
+
+
+void periodicity__SRR (NR_SchedulingRequestResourceConfig_t *SchedulingReqRec, int *period, int *offset)
+{
+  NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR P_O = SchedulingReqRec->periodicityAndOffset->present;
+  switch (P_O){
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl1:
+      *period = 1;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl1;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl2:
+      *period = 2;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl2;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl4:
+      *period = 4;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl4;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl5:
+      *period = 5;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl5;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl8:
+      *period = 8;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl8;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl10:
+      *period = 10;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl10;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl16:
+      *period = 16;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl16;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl20:
+      *period = 20;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl20;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl40:
+      *period = 40;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl40;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl80:
+      *period = 80;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl80;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl160:
+      *period = 160;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl160;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl320:
+      *period = 320;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl320;
+      break;
+    case NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl640:
+      *period = 640;
+      *offset = SchedulingReqRec->periodicityAndOffset->choice.sl640;
+      break;
+    default:
+      AssertFatal(1==0,"No periodicityAndOffset resources found in schedulingrequestresourceconfig");
+  }
+}
+
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
index a2e066d8c5b470733678f06f4e9364498453ee46..323baa48a7b7b8a7fa60487398fc07efc6561929 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
@@ -745,6 +745,34 @@ long get_K2(const NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu) {
     return 3;
 }
 
+bool nr_UE_is_to_be_scheduled(module_id_t mod_id, int CC_id, int UE_id, frame_t frame, sub_frame_t slot)
+{
+  const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon;
+  const uint8_t slots_per_frame[5] = {10, 20, 40, 80, 160};
+  const int n = slots_per_frame[*scc->ssbSubcarrierSpacing];
+  const int now = frame * n + slot;
+
+  const struct gNB_MAC_INST_s *nrmac = RC.nrmac[mod_id];
+  const NR_UE_sched_ctrl_t *sched_ctrl = &nrmac->UE_info.UE_sched_ctrl[UE_id];
+  const int last_ul_sched = sched_ctrl->last_ul_frame * n + sched_ctrl->last_ul_slot;
+
+  const int diff = (now - last_ul_sched + 1024 * n) % (1024 * n);
+  /* UE is to be scheduled if
+   * (1) we think the UE has more bytes awaiting than what we scheduled
+   * (2) there is a scheduling request
+   * (3) or we did not schedule it in more than 10 frames */
+  const bool has_data = sched_ctrl->estimated_ul_buffer > sched_ctrl->sched_ul_bytes;
+  const bool high_inactivity = diff >= nrmac->ulsch_max_slots_inactivity;
+  LOG_D(MAC,
+        "%4d.%2d UL inactivity %d slots has_data %d SR %d\n",
+        frame,
+        slot,
+        diff,
+        has_data,
+        sched_ctrl->SR);
+  return has_data || sched_ctrl->SR || high_inactivity;
+}
+
 int next_list_entry_looped(NR_list_t *list, int UE_id)
 {
   if (UE_id < 0)
@@ -874,7 +902,6 @@ void update_ul_ue_R_Qm(NR_sched_pusch_t *sched_pusch, const NR_pusch_semi_static
 
 float ul_thr_ue[MAX_MOBILES_PER_GNB];
 uint32_t ul_pf_tbs[3][28]; // pre-computed, approximate TBS values for PF coefficient
-int bsr0ue = -1;
 void pf_ul(module_id_t module_id,
            frame_t frame,
            sub_frame_t slot,
@@ -894,12 +921,6 @@ void pf_ul(module_id_t module_id,
   int ue_array[MAX_MOBILES_PER_GNB];
   NR_list_t UE_sched = { .head = -1, .next = ue_array, .tail = -1, .len = MAX_MOBILES_PER_GNB };
 
-  /* Hack: currently, we do not have SR, and need to schedule UEs continuously.
-   * To keep the wasted resources low, we switch UEs to be scheduled in a
-   * round-robin fashion below, and only schedule a UE with BSR=0 if it is the
-   * selected one */
-  bsr0ue = next_list_entry_looped(UE_list, bsr0ue);
-
   /* Loop UE_list to calculate throughput and coeff */
   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];
@@ -931,11 +952,16 @@ void pf_ul(module_id_t module_id,
       continue;
     }
 
-    /* Check BSR and schedule UE if it is zero to avoid starvation, since we do
-     * not have SR (yet) */
-    if (sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes <= 0) {
-      if (UE_id != bsr0ue)
-        continue;
+    const int B = max(0, sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes);
+    /* preprocessor computed sched_frame/sched_slot */
+    const bool do_sched = nr_UE_is_to_be_scheduled(module_id, 0, UE_id, sched_pusch->frame, sched_pusch->slot);
+
+    if (B == 0 && !do_sched)
+      continue;
+
+    /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled
+     * based on data to transmit) */
+    if (B == 0 && do_sched) {
       /* if no data, pre-allocate 5RB */
       bool freeCCE = find_free_CCE(module_id, slot, UE_id);
       if (!freeCCE) {
@@ -1106,7 +1132,7 @@ bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t
   int K2 = get_K2(sched_ctrl->active_ubwp, tda, mu);
   const int sched_frame = frame + (slot + K2 >= nr_slots_per_frame[mu]);
   const int sched_slot = (slot + K2) % nr_slots_per_frame[mu];
-  if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[slot / 64], sched_slot))
+  if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot))
     return false;
 
   sched_ctrl->sched_pusch.slot = sched_slot;
@@ -1218,6 +1244,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot)
   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];
     UE_info->mac_stats[UE_id].ulsch_current_bytes = 0;
+
     /* 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;
@@ -1225,6 +1252,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot)
       continue;
 
     uint16_t rnti = UE_info->rnti[UE_id];
+    sched_ctrl->SR = false;
 
     int8_t harq_id = sched_pusch->ul_harq_pid;
     if (harq_id < 0) {
@@ -1281,6 +1309,8 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot)
             cur_harq->ndi);
     }
     UE_info->mac_stats[UE_id].ulsch_current_bytes = sched_pusch->tb_size;
+    sched_ctrl->last_ul_frame = sched_pusch->frame;
+    sched_ctrl->last_ul_slot = sched_pusch->slot;
 
     LOG_D(MAC,
           "%4d.%2d RNTI %04x UL sched %4d.%2d start %2d RBS %3d startSymbol %2d nb_symbol %2d MCS %2d TBS %4d HARQ PID %2d round %d NDI %d est %6d sched %6d est BSR %6d\n",
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index 42560971741e0aa42ae5d5798d7534ac047f1a49..4bf82dd002821e27795d499fc7aced3635809594 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -414,4 +414,10 @@ bool nr_find_nb_rb(uint16_t Qm,
                    uint32_t *tbs,
                    uint16_t *nb_rb);
 
+void nr_sr_reporting(int Mod_idP, frame_t frameP, sub_frame_t slotP);
+
+void periodicity__SRR (NR_SchedulingRequestResourceConfig_t *SchedulingReqRecconf,
+                       int *period,
+                       int *offset);
+
 #endif /*__LAYER2_NR_MAC_PROTO_H__*/
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index c8ea892ca52ca9988a57ee0fae789235c961900f..52255b8f3226dc3d78bb9d1f0790111656815be3 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -522,11 +522,9 @@ typedef struct {
   int cce_index;
   uint8_t aggregation_level;
 
-  /// PUCCH scheduling information. Array of three, we assume for the moment:
-  /// HARQ in the first field, SR in second, CSI in third (as fixed by RRC
-  /// conf., i.e. if actually present).  The order is important for
-  /// nr_acknack_scheduling()!
-  NR_sched_pucch_t sched_pucch[3];
+  /// PUCCH scheduling information. Array of two: HARQ+SR in the first field,
+  /// CSI in second.  This order is important for nr_acknack_scheduling()!
+  NR_sched_pucch_t sched_pucch[2];
 
   /// PUSCH semi-static configuration: is not cleared across TTIs
   NR_pusch_semi_static_t pusch_semi_static;
@@ -547,6 +545,9 @@ typedef struct {
   NR_pdsch_semi_static_t pdsch_semi_static;
   /// Sched PDSCH: scheduling decisions, copied into HARQ and cleared every TTI
   NR_sched_pdsch_t sched_pdsch;
+  /// For UL synchronization: store last UL scheduling grant
+  frame_t last_ul_frame;
+  sub_frame_t last_ul_slot;
 
   /// total amount of data awaiting for this UE
   uint32_t num_total_bytes;
@@ -563,6 +564,8 @@ typedef struct {
   int pucch_snrx10;
 
   struct CSI_Report CSI_report[MAX_CSI_REPORTS];
+  bool SR;
+
   /// information about every HARQ process
   NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES];
   /// HARQ processes that are free
@@ -705,10 +708,6 @@ typedef struct gNB_MAC_INST_s {
   int cce_list[MAX_NUM_BWP][MAX_NUM_CORESET][MAX_NUM_CCE];
   /// list of allocated beams per period
   int16_t *tdd_beam_association;
-  /// PUCCH: keep track of the resources has already been used by saving the
-  /// highest index not yet been used in a given slot. Dynamically allocated
-  /// so we can have it for every slot as a function of the numerology
-  int *pucch_index_used[MAX_NUM_BWP];
 
   /// bitmap of DLSCH slots, can hold up to 160 slots
   uint64_t dlsch_slot_bitmap[3];
@@ -722,6 +721,9 @@ typedef struct gNB_MAC_INST_s {
   /// points to the right UL slot
   int *preferred_ul_tda[MAX_NUM_BWP];
 
+  /// maximum number of slots before a UE will be scheduled ULSCH automatically
+  uint32_t ulsch_max_slots_inactivity;
+
   /// DL preprocessor for differentiated scheduling
   nr_pp_impl_dl pre_processor_dl;
   /// UL preprocessor for differentiated scheduling
diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c
index 88333272cb6b518675aa4a21cd7070311f428c92..66553e813ba3650f249630eb6a25f7e9947b976d 100644
--- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c
+++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c
@@ -73,7 +73,8 @@ void nr_rlc_bearer_init_ul_spec(struct NR_LogicalChannelConfig *mac_LogicalChann
 
   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->schedulingRequestID                = calloc(1,sizeof(*mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID));
+  *mac_LogicalChannelConfig->ul_SpecificParameters->schedulingRequestID               = 0;
   mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_Mask              = false;
   mac_LogicalChannelConfig->ul_SpecificParameters->logicalChannelSR_DelayTimerApplied = false;
   mac_LogicalChannelConfig->ul_SpecificParameters->bitRateQueryProhibitTimer          = NULL;
diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
index e42d19167d7922a2ccaf899824afd91789c443a0..a789f0c34e9ed5ab904de1bfb729bdefc071180f 100644
--- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
@@ -105,10 +105,6 @@ void handle_nr_uci(NR_UL_IND_t *UL_info)
   }
 
   UL_info->uci_ind.num_ucis = 0;
-
-  // mark corresponding PUCCH resources as free
-  // NOTE: we just assume it is BWP ID 1, to be revised for multiple BWPs
-  RC.nrmac[mod_id]->pucch_index_used[1][slot] = 0;
 }
 
 
diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c
index a26a4ac5b1512c380a5580a137f38037b09c3da4..39222f814dc8d1210fe712fdd745bb7f8e144f2a 100644
--- a/openair2/RRC/NR/MESSAGES/asn1_msg.c
+++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c
@@ -1287,7 +1287,8 @@ uint16_t do_RRCReconfiguration(
     //                                  1,
     //                                  1,
     //                                  carrier->pdsch_AntennaPorts,
-    //                                  carrier->initial_csi_index[gnb_rrc_inst->Nb_ue]);
+    //                                  carrier->initial_csi_index[ue_context_p->local_uid + 1],
+    //                                  ue_context_pP->local_uid);
 
     /******************** Meas Config ********************/
     // measConfig
diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h
index ea7b853c0347ad431940845e2580fbfa4de26318..7923cf6e05b1a50eb6df2b06773ed6f2fcea0c53 100644
--- a/openair2/RRC/NR/nr_rrc_proto.h
+++ b/openair2/RRC/NR/nr_rrc_proto.h
@@ -85,14 +85,16 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
                                      int scg_id,
                                      int servCellIndex,
                                      int n_physical_antenna_ports,
-                                     int initial_csi_index);
+                                     int initial_csi_index,
+                                     int uid);
 
 void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon,
                            NR_ServingCellConfig_t *servingcellconfigdedicated,
                            NR_RRCReconfiguration_IEs_t *reconfig,
                            NR_CellGroupConfig_t *secondaryCellGroup,
                            int n_physical_antenna_ports,
-                           int initial_csi_index);
+                           int initial_csi_index,
+                           int uid);
 
 void fill_default_rbconfig(NR_RadioBearerConfig_t *rbconfig,
                            int eps_bearer_id, int rb_id,
diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c
index 2336c758fc523c59be8ef046b3be784037dadc8a..7861f2166c479b5e638bcd32ea19b56a7a34979f 100644
--- a/openair2/RRC/NR/rrc_gNB_nsa.c
+++ b/openair2/RRC/NR/rrc_gNB_nsa.c
@@ -152,7 +152,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
   ue_context_p->ue_context.reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration;
   NR_RRCReconfiguration_IEs_t *reconfig_ies=calloc(1,sizeof(NR_RRCReconfiguration_IEs_t));
   ue_context_p->ue_context.reconfig->criticalExtensions.choice.rrcReconfiguration = reconfig_ies;
-  carrier->initial_csi_index[rrc->Nb_ue] = 0;
+  carrier->initial_csi_index[ue_context_p->local_uid + 1] = 0;
   ue_context_p->ue_context.rb_config = calloc(1,sizeof(NR_RRCReconfiguration_t));
   if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1 || get_softmodem_params()->sa == 1){
     fill_default_rbconfig(ue_context_p->ue_context.rb_config,
@@ -245,14 +245,16 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc,struct rrc_gNB_ue_context_s *ue_context_
                         reconfig_ies,
                         ue_context_p->ue_context.secondaryCellGroup,
                         carrier->pdsch_AntennaPorts,
-                        carrier->initial_csi_index[rrc->Nb_ue]);
+                        carrier->initial_csi_index[ue_context_p->local_uid + 1],
+                        ue_context_p->local_uid);
   } else {
     fill_default_reconfig(carrier->servingcellconfigcommon,
                         NULL,
                         reconfig_ies,
                         ue_context_p->ue_context.secondaryCellGroup,
                         carrier->pdsch_AntennaPorts,
-                        carrier->initial_csi_index[rrc->Nb_ue]);
+                        carrier->initial_csi_index[ue_context_p->local_uid + 1],
+                        ue_context_p->local_uid);
   }
   ue_context_p->ue_id_rnti = ue_context_p->ue_context.secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity;
   NR_CG_Config_t *CG_Config = calloc(1,sizeof(*CG_Config));
diff --git a/openair2/RRC/NR/rrc_gNB_reconfig.c b/openair2/RRC/NR/rrc_gNB_reconfig.c
index cd5ded97148b43979aa783ecf24bc952c29f5c93..e7e60aa312860285c03d0416a99d0b74d7ef89f2 100644
--- a/openair2/RRC/NR/rrc_gNB_reconfig.c
+++ b/openair2/RRC/NR/rrc_gNB_reconfig.c
@@ -149,7 +149,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
                                      int scg_id,
                                      int servCellIndex,
                                      int n_physical_antenna_ports,
-                                     int initial_csi_index) {
+                                     int initial_csi_index,
+                                     int uid) {
   AssertFatal(servingcellconfigcommon!=NULL,"servingcellconfigcommon is null\n");
   AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n");
 
@@ -184,7 +185,17 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
   ASN_SEQUENCE_ADD(&secondaryCellGroup->rlc_BearerToAddModList->list, RLC_BearerConfig);
   secondaryCellGroup->mac_CellGroupConfig=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig));
   secondaryCellGroup->mac_CellGroupConfig->drx_Config = NULL;
-  secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig = NULL;
+
+  secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig));
+  secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList = calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList));
+  NR_SchedulingRequestToAddMod_t *SchedulingRequestConf = calloc(1,sizeof(*SchedulingRequestConf));
+  SchedulingRequestConf->schedulingRequestId = 0;  //Could be changed
+  SchedulingRequestConf->sr_ProhibitTimer = calloc(1,sizeof(*SchedulingRequestConf->sr_ProhibitTimer));
+  *SchedulingRequestConf->sr_ProhibitTimer = NR_SchedulingRequestToAddMod__sr_ProhibitTimer_ms16;
+  SchedulingRequestConf->sr_TransMax = NR_SchedulingRequestToAddMod__sr_TransMax_n32;
+  ASN_SEQUENCE_ADD(&secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToAddModList->list,SchedulingRequestConf);
+  secondaryCellGroup->mac_CellGroupConfig->schedulingRequestConfig->schedulingRequestToReleaseList = NULL;
+
   secondaryCellGroup->mac_CellGroupConfig->bsr_Config=calloc(1,sizeof(*secondaryCellGroup->mac_CellGroupConfig->bsr_Config));
   secondaryCellGroup->mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10;
   secondaryCellGroup->mac_CellGroupConfig->bsr_Config->retxBSR_Timer     = NR_BSR_Config__retxBSR_Timer_sf160;
@@ -251,7 +262,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
       if ((bitmap>>(63-i))&0x01){
         ssbElem[n_ssb] = calloc(1,sizeof(struct NR_CFRA_SSB_Resource));
         ssbElem[n_ssb]->ssb = i;
-        ssbElem[n_ssb]->ra_PreambleIndex = 63;
+        ssbElem[n_ssb]->ra_PreambleIndex = 63 - (uid % 64);
         ASN_SEQUENCE_ADD(&secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ssb_ResourceList.list,ssbElem[n_ssb]);
         n_ssb++;
       }
@@ -263,8 +274,8 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
   secondaryCellGroup->spCellConfig->rlf_TimersAndConstants = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants));
   secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->present = NR_SetupRelease_RLF_TimersAndConstants_PR_setup;
   secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup=calloc(1,sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup));
-  secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->t310 = NR_RLF_TimersAndConstants__t310_ms2000;
-  secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->n310 = NR_RLF_TimersAndConstants__n310_n10;
+  secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->t310 = NR_RLF_TimersAndConstants__t310_ms4000;
+  secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->n310 = NR_RLF_TimersAndConstants__n310_n20;
   secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->n311 = NR_RLF_TimersAndConstants__n311_n1;
   secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->ext1 = calloc(1,sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->ext1));
   secondaryCellGroup->spCellConfig->rlf_TimersAndConstants->choice.setup->ext1->t311 = NR_RLF_TimersAndConstants__ext1__t311_ms30000;
@@ -975,7 +986,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=8;
+ pucchres0->startingPRB= (8 + uid) % curr_bwp;
  pucchres0->intraSlotFrequencyHopping=NULL;
  pucchres0->secondHopPRB=NULL;
  pucchres0->format.present= NR_PUCCH_Resource__format_PR_format0;
@@ -986,7 +997,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  ASN_SEQUENCE_ADD(&pucch_Config->resourceToAddModList->list,pucchres0);
 
  pucchres1->pucch_ResourceId=2;
- pucchres1->startingPRB=8;
+ pucchres1->startingPRB= (8 + uid) % curr_bwp;
  pucchres1->intraSlotFrequencyHopping=NULL;
  pucchres1->secondHopPRB=NULL;
  pucchres1->format.present= NR_PUCCH_Resource__format_PR_format0;
@@ -1029,7 +1040,19 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  pucchfmt2->nrofSlots=NULL;
  pucchfmt2->pi2BPSK=NULL;
  pucchfmt2->simultaneousHARQ_ACK_CSI=NULL;
- pucch_Config->schedulingRequestResourceToAddModList=NULL;
+
+ // for scheduling requestresource
+ pucch_Config->schedulingRequestResourceToAddModList = calloc(1,sizeof(*pucch_Config->schedulingRequestResourceToAddModList));
+ NR_SchedulingRequestResourceConfig_t *schedulingRequestResourceConfig = calloc(1,sizeof(*schedulingRequestResourceConfig));
+ schedulingRequestResourceConfig->schedulingRequestResourceId = 1;
+ schedulingRequestResourceConfig->schedulingRequestID = 0;
+ schedulingRequestResourceConfig->periodicityAndOffset = calloc(1,sizeof(*schedulingRequestResourceConfig->periodicityAndOffset));
+ schedulingRequestResourceConfig->periodicityAndOffset->present = NR_SchedulingRequestResourceConfig__periodicityAndOffset_PR_sl10;
+ schedulingRequestResourceConfig->periodicityAndOffset->choice.sl10 = 7;
+ schedulingRequestResourceConfig->resource = calloc(1,sizeof(*schedulingRequestResourceConfig->resource));
+ *schedulingRequestResourceConfig->resource = 1;
+ ASN_SEQUENCE_ADD(&pucch_Config->schedulingRequestResourceToAddModList->list,schedulingRequestResourceConfig);
+
  pucch_Config->schedulingRequestResourceToReleaseList=NULL;
  pucch_Config->multi_CSI_PUCCH_ResourceList=NULL;
  pucch_Config->dl_DataToUL_ACK = calloc(1,sizeof(*pucch_Config->dl_DataToUL_ACK));
@@ -1177,7 +1200,7 @@ void fill_default_secondaryCellGroup(NR_ServingCellConfigCommon_t *servingcellco
  csirep1->reportConfigType.present = NR_CSI_ReportConfig__reportConfigType_PR_periodic;
  csirep1->reportConfigType.choice.periodic = calloc(1,sizeof(*csirep1->reportConfigType.choice.periodic));
  csirep1->reportConfigType.choice.periodic->reportSlotConfig.present=NR_CSI_ReportPeriodicityAndOffset_PR_slots320;
- csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = 49;
+ csirep1->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320 = 9 + (10 * uid) % 320;
  NR_PUCCH_CSI_Resource_t *pucchcsires1 = calloc(1,sizeof(*pucchcsires1));
  pucchcsires1->uplinkBandwidthPartId=1;
  pucchcsires1->pucch_Resource=3;
@@ -1241,14 +1264,22 @@ void fill_default_reconfig(NR_ServingCellConfigCommon_t *servingcellconfigcommon
                            NR_RRCReconfiguration_IEs_t *reconfig,
                            NR_CellGroupConfig_t *secondaryCellGroup,
                            int n_physical_antenna_ports,
-                           int initial_csi_index) {
+                           int initial_csi_index,
+                           int uid) {
   AssertFatal(servingcellconfigcommon!=NULL,"servingcellconfigcommon is null\n");
   AssertFatal(reconfig!=NULL,"reconfig is null\n");
   AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n");
   // radioBearerConfig
   reconfig->radioBearerConfig=NULL;
   // secondaryCellGroup
-  fill_default_secondaryCellGroup(servingcellconfigcommon,servingcellconfigdedicated,secondaryCellGroup,1,1,n_physical_antenna_ports,initial_csi_index);
+  fill_default_secondaryCellGroup(servingcellconfigcommon,
+                                  servingcellconfigdedicated,
+                                  secondaryCellGroup,
+                                  1,
+                                  1,
+                                  n_physical_antenna_ports,
+                                  initial_csi_index,
+                                  uid);
   xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup);
 
   char scg_buffer[1024];
diff --git a/openair2/X2AP/x2ap_eNB.c b/openair2/X2AP/x2ap_eNB.c
index 321190015d7c8a37be529a8c67a263acddf0f9af..0474d417df4af2890ae4fcde23678b53d5efdc20 100644
--- a/openair2/X2AP/x2ap_eNB.c
+++ b/openair2/X2AP/x2ap_eNB.c
@@ -130,6 +130,18 @@ void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_associa
   DevAssert(x2ap_enb_data_p != NULL);
   dump_trees();
 
+  /* gNB: exit if connection to eNB failed - to be modified if needed.
+   * We may want to try to connect over and over again until we succeed
+   * but the modifications to the code to get this behavior are complex.
+   * Exit on error is a simple solution that can be caught by a script
+   * for example.
+   */
+  if (instance_p->cell_type == CELL_MACRO_GNB
+      && sctp_new_association_resp->sctp_state == SCTP_STATE_UNREACHABLE) {
+    X2AP_ERROR("association with eNB failed, is it running? If no, run it first. If yes, check IP addresses in your configuration file.\n");
+    exit(1);
+  }
+
   if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
     X2AP_WARN("Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u\n",
               sctp_new_association_resp->sctp_state,
diff --git a/openair3/NAS/TOOLS/ue_sim_ci.conf b/openair3/NAS/TOOLS/ue_sim_ci.conf
new file mode 100644
index 0000000000000000000000000000000000000000..5d95c9ba3f182497836948f5c872071f678b4228
--- /dev/null
+++ b/openair3/NAS/TOOLS/ue_sim_ci.conf
@@ -0,0 +1,45 @@
+# List of known PLMNS
+PLMN: {
+    PLMN0: {
+           FULLNAME="OpenAirInterface";
+           SHORTNAME="OAICN";
+           MNC="96";
+           MCC="208";
+    };
+};
+
+UE0:
+{
+    USER: {
+        IMEI="356113022094149";
+        MANUFACTURER="OAI";
+        MODEL="LTE SoftModem";
+        PIN="0000";
+    };
+
+    SIM: {
+        MSIN="0100001111";
+        USIM_API_K="8baf473f2f8fd09487cccbd7097c6862";
+        OPC="e734f8734007d6c5ce7a0508809e7e9c";
+        MSISDN="33611123456";
+    };
+
+    # Home PLMN Selector with Access Technology
+    HPLMN= "20896";
+
+    # User controlled PLMN Selector with Access Technology
+    UCPLMN_LIST = ();
+
+    # Operator PLMN List
+    OPLMN_LIST = ("20896");
+
+    # Operator controlled PLMN Selector with Access Technology
+    OCPLMN_LIST = ();
+
+    # Forbidden plmns
+    FPLMN_LIST = ();
+
+    # Equivalent home plmns
+    EHPLMN_LIST = ();
+
+};
diff --git a/openshift/oai-physim-image-stream.yml b/openshift/oai-physim-image-stream.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9ef338f139a347f434badb8fc137e55bb497b4d5
--- /dev/null
+++ b/openshift/oai-physim-image-stream.yml
@@ -0,0 +1,29 @@
+#/*
+# * 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
+# */
+#---------------------------------------------------------------------
+#
+apiVersion: image.openshift.io/v1
+kind: ImageStream
+metadata:
+  name: oai-physim
+spec:
+  lookupPolicy:
+    local: true
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf
index c72ec515dcd2d12591bd2d69ee9863f0782a198b..4147ec6ae2e041bca8c697149bf682bf382e33b8 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf
@@ -67,17 +67,7 @@ gNBs =
 
         initialDLBWPk0_1                    = 0;  #for mixed slot
         initialDLBWPmappingType_1           = 0;
-        initialDLBWPstartSymbolAndLength_1  = 53; #this is SS=1,L=5
-
-             initialDLBWPk0_2                    = 0;
-             initialDLBWPmappingType_2           = 0;
-             #this is SS=1,L=12 
-             initialDLBWPstartSymbolAndLength_2  = 54;
-
-             initialDLBWPk0_3                    = 0;
-             initialDLBWPmappingType_3           = 0;
-             #this is SS=1,L=4 //5 (4 is for 43, 5 is for 57)
-             initialDLBWPstartSymbolAndLength_3  = 57; //43; //57;
+        initialDLBWPstartSymbolAndLength_1  = 57; #this is SS=1,L=5
 
   #uplinkConfigCommon 
      #frequencyInfoUL
@@ -103,6 +93,8 @@ gNBs =
           prach_msg1_FDM                                            = 0;
           prach_msg1_FrequencyStart                                 = 74;
           zeroCorrelationZoneConfig                                 = 13;
+          #preambleReceivedTargetPower                               = -118;
+          #preambleReceivedTargetPower                               = -104;
           preambleReceivedTargetPower                               = -108;
 #preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
           preambleTransMax                                          = 6;
@@ -285,6 +277,7 @@ RUs = (
 THREAD_STRUCT = (
   {
     #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
+    //parallel_config    = "PARALLEL_RU_L1_TRX_SPLIT";
     parallel_config    = "PARALLEL_SINGLE_THREAD";
     #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
     worker_config      = "WORKER_DISABLE";