\n')
self.htmlFile.write(' | ' + self.testCase_id + ' | \n')
@@ -2213,15 +2879,17 @@ class SSHConnection():
if (processesStatus == 0):
self.htmlFile.write(' ' + str(status) + ' | \n')
elif (processesStatus == ENB_PROCESS_FAILED):
- self.htmlFile.write(' KO - eNB process not found | \n')
+ self.htmlFile.write(' KO - ' + machine + ' process not found | \n')
elif (processesStatus == ENB_PROCESS_SEG_FAULT):
- self.htmlFile.write(' KO - eNB process ended in Segmentation Fault | \n')
- elif (processesStatus == ENB_PROCESS_ASSERTION):
- self.htmlFile.write(' KO - eNB process ended in Assertion | \n')
+ self.htmlFile.write(' KO - ' + machine + ' process ended in Segmentation Fault | \n')
+ elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == UE_PROCESS_ASSERTION):
+ self.htmlFile.write(' KO - ' + machine + ' process ended in Assertion | \n')
elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE):
- self.htmlFile.write(' KO - eNB process faced Real Time issue(s) | \n')
- elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE):
- self.htmlFile.write(' OK | \n')
+ self.htmlFile.write(' KO - ' + machine + ' process faced Real Time issue(s) | \n')
+ elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == UE_PROCESS_NOLOGFILE_TO_ANALYZE):
+ self.htmlFile.write(' OK? | \n')
+ elif (processesStatus == UE_PROCESS_COULD_NOT_SYNC):
+ self.htmlFile.write(' KO - UE could not sync | \n')
elif (processesStatus == HSS_PROCESS_FAILED):
self.htmlFile.write(' KO - HSS process not found | \n')
elif (processesStatus == MME_PROCESS_FAILED):
@@ -2325,8 +2993,11 @@ def Usage():
print(' --XMLTestFile=[XML Test File to be run]')
print('------------------------------------------------------------')
+#def GetModeFromXML():
+# SSH.mode = test.findtext('mode')
+
def CheckClassValidity(action,id):
- if action != 'Build_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'IdleSleep':
+ if action != 'Build_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'Initialize_OAI_eNB' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep':
logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action)
return False
return True
@@ -2340,11 +3011,21 @@ def GetParametersFromXML(action):
SSH.eNB_instance = test.findtext('eNB_instance')
if (SSH.eNB_instance is None):
SSH.eNB_instance = '0'
-
+ SSH.air_interface = test.findtext('air_interface')
+ if (SSH.air_interface is None):
+ SSH.air_interface = 'lte'
+ else:
+ SSH.air_interface = SSH.air_interface.lower()
+
if action == 'Terminate_eNB':
SSH.eNB_instance = test.findtext('eNB_instance')
if (SSH.eNB_instance is None):
SSH.eNB_instance = '0'
+ SSH.air_interface = test.findtext('air_interface')
+ if (SSH.air_interface is None):
+ SSH.air_interface = 'lte'
+ else:
+ SSH.air_interface = SSH.air_interface.lower()
if action == 'Attach_UE':
nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach')
@@ -2353,7 +3034,42 @@ def GetParametersFromXML(action):
else:
SSH.nbMaxUEtoAttach = int(nbMaxUEtoAttach)
- if action == 'Ping':
+ if action == 'Build_OAI_UE':
+ SSH.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args')
+ SSH.clean_repository = test.findtext('clean_repository')
+ if (SSH.clean_repository == 'false'):
+ SSH.clean_repository = False
+ else:
+ SSH.clean_repository = True
+
+ if action == 'Initialize_OAI_UE':
+ SSH.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args')
+ SSH.UE_instance = test.findtext('UE_instance')
+ if (SSH.UE_instance is None):
+ SSH.UE_instance = '0'
+ SSH.air_interface = test.findtext('air_interface')
+ if (SSH.air_interface is None):
+ SSH.air_interface = 'lte'
+ else:
+ SSH.air_interface = SSH.air_interface.lower()
+
+ if action == 'Initialize_OAI_eNB':
+ SSH.Initialize_OAI_eNB_args = test.findtext('Initialize_OAI_eNB_args')
+ SSH.UE_instance = test.findtext('eNB_instance')
+ if (SSH.eNB_instance is None):
+ SSH.eNB_instance = '0'
+ SSH.air_interface = test.findtext('air_interface')
+ if (SSH.air_interface is None):
+ SSH.air_interface = 'lte'
+ else:
+ SSH.air_interface = SSH.air_interface.lower()
+
+ if action == 'Terminate_OAI_UE':
+ SSH.eNB_instance = test.findtext('UE_instance')
+ if (SSH.UE_instance is None):
+ SSH.UE_instance = '0'
+
+ if action == 'Ping' or action == 'Ping_CatM_module':
SSH.ping_args = test.findtext('ping_args')
SSH.ping_packetloss_threshold = test.findtext('ping_packetloss_threshold')
@@ -2395,6 +3111,7 @@ SSH = SSHConnection()
argvs = sys.argv
argc = len(argvs)
+cwd = os.getcwd()
while len(argvs) > 1:
myArgv = argvs.pop(1) # 0th is this file's name
@@ -2403,6 +3120,9 @@ while len(argvs) > 1:
sys.exit(0)
elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE)
+ #if matchReg and mode is not None:
+ #print('Warning: the mode is defined in both xml file and command line')
+ #print('ignoring the mode defined in the xml file')
mode = matchReg.group(1)
elif re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE)
@@ -2467,6 +3187,18 @@ while len(argvs) > 1:
matchReg = re.match('^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE)
SSH.testXMLfiles.append(matchReg.group(1))
SSH.nbTestXMLfiles += 1
+ elif re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE):
+ matchReg = re.match('^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE)
+ SSH.UEIPAddress = matchReg.group(1)
+ elif re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE):
+ matchReg = re.match('^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE)
+ SSH.UEUserName = matchReg.group(1)
+ elif re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE):
+ matchReg = re.match('^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE)
+ SSH.UEPassword = matchReg.group(1)
+ elif re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE):
+ matchReg = re.match('^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE)
+ SSH.UESourceCodePath = matchReg.group(1)
elif re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE):
matchReg = re.match('^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE)
finalStatus = matchReg.group(1)
@@ -2482,11 +3214,17 @@ if re.match('^TerminateeNB$', mode, re.IGNORECASE):
sys.exit('Insufficient Parameter')
SSH.TerminateeNB()
elif re.match('^TerminateUE$', mode, re.IGNORECASE):
- if SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '':
+ if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''):
Usage()
sys.exit('Insufficient Parameter')
signal.signal(signal.SIGUSR1, receive_signal)
SSH.TerminateUE()
+elif re.match('^TerminateOAIUE$', mode, re.IGNORECASE):
+ if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '':
+ Usage()
+ sys.exit('Insufficient Parameter')
+ signal.signal(signal.SIGUSR1, receive_signal)
+ SSH.TerminateOAIUE()
elif re.match('^TerminateHSS$', mode, re.IGNORECASE):
if SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '':
Usage()
@@ -2503,7 +3241,7 @@ elif re.match('^TerminateSPGW$', mode, re.IGNORECASE):
sys.exit('Insufficient Parameter')
SSH.TerminateSPGW()
elif re.match('^LogCollectBuild$', mode, re.IGNORECASE):
- if SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '':
+ if (SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '') and (SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == ''):
Usage()
sys.exit('Insufficient Parameter')
SSH.LogCollectBuild()
@@ -2537,36 +3275,62 @@ elif re.match('^LogCollectIperf$', mode, re.IGNORECASE):
Usage()
sys.exit('Insufficient Parameter')
SSH.LogCollectIperf()
+elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE):
+ if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '':
+ Usage()
+ sys.exit('Insufficient Parameter')
+ SSH.LogCollectOAIUE()
elif re.match('^InitiateHtml$', mode, re.IGNORECASE):
- if SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '':
+ if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''):
Usage()
sys.exit('Insufficient Parameter')
count = 0
+ foundCount = 0
while (count < SSH.nbTestXMLfiles):
- xml_test_file = sys.path[0] + "/" + SSH.testXMLfiles[count]
- xmlTree = ET.parse(xml_test_file)
- xmlRoot = xmlTree.getroot()
- SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count)))
- SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count)))
- SSH.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign'))
+ xml_test_file = cwd + "/" + SSH.testXMLfiles[count]
+ if (os.path.isfile(xml_test_file)):
+ try:
+ xmlTree = ET.parse(xml_test_file)
+ except:
+ print("Error while parsing file: " + xml_test_file)
+ xmlRoot = xmlTree.getroot()
+ SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count)))
+ SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count)))
+ SSH.htmlTabIcons.append(xmlRoot.findtext('htmlTabIcon',default='info-sign'))
+ foundCount += 1
count += 1
+ if foundCount != SSH.nbTestXMLfiles:
+ SSH.nbTestXMLfiles = foundCount
SSH.CreateHtmlHeader()
elif re.match('^FinalizeHtml$', mode, re.IGNORECASE):
SSH.CreateHtmlFooter(SSH.finalStatus)
-elif re.match('^TesteNB$', mode, re.IGNORECASE):
- if SSH.eNBIPAddress == '' or SSH.eNBRepository == '' or SSH.eNBBranch == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '' or SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '' or SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '':
- Usage()
- sys.exit('Insufficient Parameter')
+elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE):
+ if re.match('^TesteNB$', mode, re.IGNORECASE):
+ if (SSH.eNBRepository == '' or SSH.eNBBranch == '' or SSH.eNBSourceCodePath == ''):
+ Usage()
+ sys.exit('Insufficient Parameter')
+ if (SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '') and (SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == ''):
+ Usage()
+ sys.exit('Insufficient Parameter')
+ elif SSH.ADBIPAddress == 'none' and SSH.EPCIPAddress == 'none':
+ pass
+ elif SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '' or SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '':
+ Usage()
+ sys.exit('Insufficient Parameter')
+ if (SSH.EPCIPAddress != ''):
+ SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp")
+ SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp")
+ else:
+ if SSH.UEIPAddress == '' or SSH.eNBRepository == '' or SSH.eNBBranch == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '':
+ Usage()
+ sys.exit('UE: Insufficient Parameter')
- if (SSH.EPCIPAddress != 'none'):
- SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, sys.path[0] + "/tcp_iperf_stats.awk", "/tmp")
- SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, sys.path[0] + "/active_net_interfaces.awk", "/tmp")
#read test_case_list.xml file
# if no parameters for XML file, use default value
if (SSH.nbTestXMLfiles != 1):
- xml_test_file = sys.path[0] + "/test_case_list.xml"
+ xml_test_file = cwd + "/test_case_list.xml"
else:
- xml_test_file = sys.path[0] + "/" + SSH.testXMLfiles[0]
+ xml_test_file = cwd + "/" + SSH.testXMLfiles[0]
xmlTree = ET.parse(xml_test_file)
xmlRoot = xmlTree.getroot()
@@ -2622,6 +3386,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE):
SSH.testCase_id = id
SSH.desc = test.findtext('desc')
action = test.findtext('class')
+ mode = test.findtext('mode')
if (CheckClassValidity(action, id) == False):
continue
SSH.ShowTestID()
@@ -2643,6 +3408,14 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE):
SSH.AttachUE()
elif action == 'Detach_UE':
SSH.DetachUE()
+ elif action == 'Build_OAI_UE':
+ SSH.BuildOAIUE()
+ elif action == 'Initialize_OAI_UE':
+ SSH.InitializeOAIUE()
+ elif action == 'Terminate_OAI_UE':
+ SSH.TerminateOAIUE()
+ elif action == 'Initialize_OAI_eNB':
+ SSH.InitializeOAIeNB()
elif action == 'Initialize_CatM_module':
SSH.InitializeCatM()
elif action == 'Terminate_CatM_module':
@@ -2651,6 +3424,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE):
SSH.AttachCatM()
elif action == 'Detach_CatM_module':
SSH.TerminateCatM()
+ elif action == 'Ping_CatM_module':
+ SSH.PingCatM()
elif action == 'Ping':
SSH.Ping()
elif action == 'Iperf':
diff --git a/ci-scripts/oai-ci-vm-tool b/ci-scripts/oai-ci-vm-tool
index 940bcd2852..3d9fb87cba 100755
--- a/ci-scripts/oai-ci-vm-tool
+++ b/ci-scripts/oai-ci-vm-tool
@@ -39,7 +39,7 @@ function variant_usage {
echo " --variant phy-sim OR -v3"
echo " --variant cppcheck OR -v4"
echo " --variant gnb-usrp OR -v5"
- echo " --variant nu-ue-usrp OR -v6"
+ echo " --variant nr-ue-usrp OR -v6"
echo " --variant enb-ethernet OR -v7"
echo " --variant ue-ethernet OR -v8"
}
@@ -252,9 +252,9 @@ case $key in
VM_NAME=ci-phy-sim
ARCHIVES_LOC=phy_sim
LOG_PATTERN=.Rel15.txt
- NB_PATTERN_FILES=8
+ NB_PATTERN_FILES=10
BUILD_OPTIONS="--phy_simulators"
- VM_MEMORY=4096
+ VM_MEMORY=8192
RUN_OPTIONS="./run_exec_autotests.bash -g \"01510*\" -q -np -b"
NBARGS=$[$NBARGS+256]
shift
@@ -331,9 +331,9 @@ case $key in
VM_NAME=ci-phy-sim
ARCHIVES_LOC=phy_sim
LOG_PATTERN=.Rel15.txt
- NB_PATTERN_FILES=8
+ NB_PATTERN_FILES=10
BUILD_OPTIONS="--phy_simulators"
- VM_MEMORY=4096
+ VM_MEMORY=8192
RUN_OPTIONS="./run_exec_autotests.bash -g \"01510*\" -q -np -b"
NBARGS=$[$NBARGS+256]
;;
@@ -354,7 +354,7 @@ case $key in
BUILD_OPTIONS="--gNB -w USRP"
NBARGS=$[$NBARGS+256]
;;
- nu-ue-usrp)
+ nr-ue-usrp)
VM_NAME=ci-ue-nr-usrp
ARCHIVES_LOC=nrue_usrp
LOG_PATTERN=.Rel15.txt
diff --git a/ci-scripts/xml_files/enb_usrp210_band40_test_20mhz_tm1.xml b/ci-scripts/xml_files/enb_usrp210_band40_test_20mhz_tm1_not_run.xml
similarity index 100%
rename from ci-scripts/xml_files/enb_usrp210_band40_test_20mhz_tm1.xml
rename to ci-scripts/xml_files/enb_usrp210_band40_test_20mhz_tm1_not_run.xml
diff --git a/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml
new file mode 100644
index 0000000000..f9d068c5b2
--- /dev/null
+++ b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml
@@ -0,0 +1,64 @@
+
+
+ run-OAI-gNB-NR-UE-USRP
+ run OAI gNB and OAI NR UE USRP
+ tasks
+
+090101 000001 090102 000001 090108 090109
+
+
+
+
+ Initialize_OAI_eNB
+ Initialize gNB USRP
+ -O ../../../ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf
+ NR
+
+
+
+ IdleSleep
+ Sleep
+ 5
+
+
+
+ Initialize_OAI_UE
+ Initialize NR UE USRP
+ -C 3510000000 --numerology 1 -r 106 --phy-test --usrp-args "addr=192.168.30.2,clock_source=external,time_source=external" --threadoffset 16
+ NR
+
+
+
+ Terminate_OAI_UE
+ Terminate NR UE
+ NR
+
+
+
+ Terminate_eNB
+ Terminate gNB
+ NR
+
+
+
diff --git a/ci-scripts/xml_files/gnb_usrp_build.xml b/ci-scripts/xml_files/gnb_usrp_build.xml
new file mode 100644
index 0000000000..1b57c077ba
--- /dev/null
+++ b/ci-scripts/xml_files/gnb_usrp_build.xml
@@ -0,0 +1,39 @@
+
+
+ gnb-build-tab
+ Build-gNB
+ wrench
+
+010101
+
+
+
+
+ TesteNB
+ Build_eNB
+ Build gNB (USRP)
+ --gNB -w USRP
+
+
+
diff --git a/ci-scripts/xml_files/if4p5_usrp210_band40_test_20mhz.xml b/ci-scripts/xml_files/if4p5_usrp210_band40_test_20mhz_not_run.xml
similarity index 100%
rename from ci-scripts/xml_files/if4p5_usrp210_band40_test_20mhz.xml
rename to ci-scripts/xml_files/if4p5_usrp210_band40_test_20mhz_not_run.xml
diff --git a/ci-scripts/xml_files/nr_ue_usrp_build.xml b/ci-scripts/xml_files/nr_ue_usrp_build.xml
new file mode 100644
index 0000000000..7d8d97d2c5
--- /dev/null
+++ b/ci-scripts/xml_files/nr_ue_usrp_build.xml
@@ -0,0 +1,40 @@
+
+
+ nr-ue-build-tab
+ Build-NR-UE
+ wrench
+
+010102
+
+
+
+
+ TestUE
+ Build_OAI_UE
+ Build NR UE (USRP)
+ --nrUE -w USRP
+ false
+
+
+
diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index c05f89be9e..4e05552c1a 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -167,7 +167,7 @@ endif()
#
set(CMAKE_C_FLAGS
- "${CMAKE_C_FLAGS} ${C_FLAGS_PROCESSOR} -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat -fPIC ")
+ "${CMAKE_C_FLAGS} ${C_FLAGS_PROCESSOR} -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat -fPIC")
# add autotools definitions that were maybe used!
set(MKVER "'MAKE_VERSION(a,b,c)=((a)*256+(b)*16+c)'")
set(CMAKE_C_FLAGS
@@ -671,7 +671,7 @@ add_boolean_option(EXMIMO_IOT True "????")
add_boolean_option(LOCALIZATION False "???")
add_integer_option(MAX_NUM_CCs 1 "????")
add_boolean_option(MU_RECEIVER False "????")
-add_boolean_option(PHYSIM True "for L1 simulators (dlsim, ulsim, ...)")
+add_boolean_option(PHYSIM False "for L1 simulators (dlsim, ulsim, ...)")
add_boolean_option(PHY_CONTEXT True "not clear: must remain False for dlsim")
add_boolean_option(PHY_EMUL False "not clear: must remain False for dlsim")
add_boolean_option(SMBV False "Rohde&Schwarz SMBV100A vector signal generator")
@@ -754,6 +754,7 @@ include_directories("${OPENAIR_BIN_DIR}")
# Legacy exact order
+include_directories("${OPENAIR_DIR}/executables")
include_directories("${OPENAIR2_DIR}/COMMON")
include_directories("${OPENAIR2_DIR}/UTIL")
include_directories("${OPENAIR2_DIR}/UTIL/LOG")
@@ -1118,15 +1119,19 @@ set(PHY_POLARSRC
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_procedures.c
${OPENAIR1_DIR}/PHY/CODING/nrPolar_tools/nr_polar_sequence_pattern.c
)
+set(PHY_SMALLBLOCKSRC
+ ${OPENAIR1_DIR}/PHY/CODING/nrSmallBlock/encodeSmallBlock.c
+ ${OPENAIR1_DIR}/PHY/CODING/nrSmallBlock/decodeSmallBlock.c
+)
set(PHY_TURBOIF
${OPENAIR1_DIR}/PHY/CODING/coding_load.c
- )
+)
set(PHY_LDPCSRC
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_encoder2.c
${OPENAIR1_DIR}/PHY/CODING/nrLDPC_encoder/ldpc_generate_coefficient.c
- )
+)
add_library(coding MODULE ${PHY_TURBOSRC} )
set(PHY_SRC_COMMON
@@ -1275,6 +1280,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_tools.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_dlsch_coding.c
+ ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_tbs_tools.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_sch_dmrs.c
${OPENAIR1_DIR}/PHY/NR_REFSIG/nr_gold.c
@@ -1291,6 +1297,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/TOOLS/time_meas.c
${OPENAIR1_DIR}/PHY/TOOLS/lut.c
${PHY_POLARSRC}
+ ${PHY_SMALLBLOCKSRC}
${PHY_LDPCSRC}
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/pucch_rx.c # added by prasanth
)
@@ -1305,6 +1312,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
+ ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_tbs_tools.c
@@ -1335,6 +1343,7 @@ set(PHY_SRC_UE
${OPENAIR1_DIR}/PHY/INIT/nr_init_ue.c
# ${OPENAIR1_DIR}/SIMULATION/NR_UE_PHY/unit_tests/src/pucch_uci_test.c
${PHY_POLARSRC}
+ ${PHY_SMALLBLOCKSRC}
${PHY_LDPCSRC}
)
@@ -1576,6 +1585,7 @@ add_library(L2
${ENB_APP_SRC}
)
add_dependencies(L2 rrc_flag s1ap_flag x2_flag)
+
add_library(MAC_NR
${MAC_NR_SRC}
)
@@ -1594,7 +1604,6 @@ add_dependencies(S1AP_LIB nr_rrc_flag s1ap_flag)
add_library(L2_UE
${L2_SRC_UE}
${MAC_SRC_UE}
- #${MAC_NR_SRC_UE}
)
if (NOT ${NOS1})
target_compile_definitions(L2_UE PUBLIC -DPDCP_USE_NETLINK)
@@ -1603,44 +1612,13 @@ endif()
add_dependencies(L2_UE rrc_flag s1ap_flag x2_flag)
add_library( NR_L2_UE
- #${L2_SRC_UE}
${NR_L2_SRC_UE}
${MAC_NR_SRC_UE}
- #${MAC_SRC_UE}
-)
-
-set ( NR_LTE_UE_REUSE_SRC
- ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_timefreq.c
- ${OPENAIR1_DIR}/SCHED/phy_procedures_lte_common.c
- #${OPENAIR1_DIR}/SCHED_UE/phy_procedures_lte_ue.c
- ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c
- #${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pmch_common.c
-
- #${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_cell_spec.c
- #${OPENAIR1_DIR}/PHY/CODING/lte_segmentation.c
- #${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/prach_common.c
-# ${OPENAIR1_DIR}/PHY/INIT/lte_init_ue.c
- ${OPENAIR1_DIR}/PHY/CODING/crc_byte.c
- ${OPENAIR1_DIR}/PHY/CODING/viterbi_lte.c
- ${OPENAIR1_DIR}/PHY/CODING/viterbi.c
- #${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/phich_common.c
- ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c
-
-# ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c
-# ${OPENAIR1_DIR}/PHY/CODING/lte_rate_matching.c
- ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte_lte.c
- ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte.c
- ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_gold.c
- ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_est_freq_offset.c
- ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c
- ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ue_measurements.c
- #${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c
- #${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation_avx2.c
-)
-
-add_library( NR_LTE_UE_REUSE_LIB
- ${NR_LTE_UE_REUSE_SRC}
-)
+ )
+
+add_library( MAC_NR_COMMON
+ ${OPENAIR2_DIR}/LAYER2/NR_MAC_gNB/nr_mac_common.c
+ )
include_directories("${OPENAIR2_DIR}/NR_UE_PHY_INTERFACE")
include_directories("${OPENAIR2_DIR}/LAYER2/NR_MAC_UE")
@@ -2137,11 +2115,18 @@ if (${XFORMS})
${OPENAIR1_DIR}/PHY/TOOLS/nr_phy_scope.c
)
set(XFORMS_SOURCE_SOFTMODEM
- ${OPENAIR_TARGETS}/RT/USER/stats.c
+ ${OPENAIR_DIR}/targets/RT/USER/stats.c
)
set(XFORMS_LIBRARIES "forms")
endif (${XFORMS})
+include_directories ("/usr/include/X11")
+
+add_library(gnbScope MODULE
+ ${OPENAIR1_DIR}/PHY/TOOLS/nr_phy_scope.c
+ )
+target_link_libraries(gnbScope forms)
+
set(CMAKE_MODULE_PATH "${OPENAIR_DIR}/cmake_targets/tools/MODULES" "${CMAKE_MODULE_PATH}")
#include T directory even if the T is off because T macros are in the code
@@ -2185,6 +2170,24 @@ add_definitions(-DASN1_MINIMUM_VERSION=924)
#################################
# add executables for operation
#################################
+add_library(minimal_lib
+ ${OPENAIR_DIR}/common/utils/backtrace.c
+ ${OPENAIR_DIR}/common/utils/LOG/log.c
+ ${OPENAIR_DIR}/common/config/config_userapi.c
+ ${OPENAIR_DIR}/common/config/config_load_configmodule.c
+ ${OPENAIR_DIR}/common/config/config_cmdline.c
+ ${OPENAIR_DIR}/common/utils/minimal_stub.c
+ )
+target_link_libraries(minimal_lib pthread dl)
+
+add_executable(replay_node
+ ${OPENAIR_TARGETS}/ARCH/rfsimulator/stored_node.c
+ )
+target_link_libraries (replay_node minimal_lib)
+
+add_executable(measurement_display
+ ${OPENAIR_DIR}/common/utils/threadPool/measurement_display.c)
+target_link_libraries (measurement_display minimal_lib)
# lte-softmodem is both eNB and UE implementation
###################################################
@@ -2347,19 +2350,16 @@ add_executable(nr-softmodem
${nr_rrc_h}
${s1ap_h}
# ${OPENAIR_BIN_DIR}/messages_xml.h
- ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
- ${OPENAIR_TARGETS}/RT/USER/nr-gnb.c
- ${OPENAIR_TARGETS}/RT/USER/nr-ru.c
- ${OPENAIR_TARGETS}/RT/USER/nr-softmodem.c
+ ${OPENAIR_DIR}/executables/nr-gnb.c
+ ${OPENAIR_DIR}/executables/nr-ru.c
+ ${OPENAIR_DIR}/executables/nr-softmodem.c
${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
- ${OPENAIR_TARGETS}/COMMON/create_nr_tasks.c
${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
${OPENAIR_DIR}/common/utils/utils.c
${OPENAIR_DIR}/common/utils/system.c
${GTPU_need_ITTI}
- ${XFORMS_SOURCE}
- ${XFORMS_SOURCE_SOFTMODEM}
+ ${XFORMS_SOURCE_NR}
${T_SOURCE}
${CONFIG_SOURCES}
${SHLIB_LOADER_SOURCES}
@@ -2369,7 +2369,7 @@ target_link_libraries (nr-softmodem
-Wl,--start-group
UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_RU LFDS GTPV1U SECU_CN SECU_OSA
${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB}
- RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB L2 L2_NR
+ RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB L2 L2_NR MAC_NR_COMMON
NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
-Wl,--end-group z dl)
@@ -2385,13 +2385,10 @@ add_executable(nr-softmodem-nos1
${rrc_h}
${s1ap_h}
# ${OPENAIR_BIN_DIR}/messages_xml.h
- ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
- ${OPENAIR_TARGETS}/RT/USER/nr-gnb.c
- ${OPENAIR_TARGETS}/RT/USER/nr-ru.c
- ${OPENAIR_TARGETS}/RT/USER/nr-softmodem.c
+ ${OPENAIR_DIR}/executables/nr-gnb.c
+ ${OPENAIR_DIR}/executables/nr-ru.c
+ ${OPENAIR_DIR}/executables/nr-softmodem.c
${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
- ${OPENAIR_TARGETS}/COMMON/create_tasks.c
- ${OPENAIR_TARGETS}/COMMON/create_nr_tasks.c
${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
${OPENAIR2_DIR}/RRC/NAS/nas_config.c
${OPENAIR2_DIR}/RRC/NAS/rb_config.c
@@ -2399,8 +2396,7 @@ add_executable(nr-softmodem-nos1
${OPENAIR_DIR}/common/utils/utils.c
${OPENAIR_DIR}/common/utils/system.c
${GTPU_need_ITTI}
- ${XFORMS_SOURCE}
- ${XFORMS_SOURCE_SOFTMODEM}
+ ${XFORMS_SOURCE_NR}
${T_SOURCE}
${CONFIG_SOURCES}
${SHLIB_LOADER_SOURCES}
@@ -2410,7 +2406,7 @@ target_link_libraries (nr-softmodem-nos1
-Wl,--start-group
UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_RU LFDS GTPV1U SECU_CN SECU_OSA
${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} LFDS7 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${MIH_LIB}
- RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB L2 L2_NR
+ RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB L2 L2_NR MAC_NR_COMMON
NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB
-Wl,--end-group z dl)
@@ -2426,18 +2422,16 @@ add_executable(nr-uesoftmodem
${rrc_h}
${s1ap_h}
# ${OPENAIR_BIN_DIR}/messages_xml.h
- ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
- ${OPENAIR_TARGETS}/RT/USER/nr-ue.c
- ${OPENAIR_TARGETS}/RT/USER/nr-uesoftmodem.c
+ ${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c
+ ${OPENAIR_DIR}/executables/nr-uesoftmodem.c
+ ${OPENAIR_DIR}/executables/nr-ue.c
${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
-# ${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c
${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c
${OPENAIR_DIR}/common/utils/utils.c
${OPENAIR_DIR}/common/utils/system.c
${XFORMS_SOURCE_NR}
- ${XFORMS_SOURCE_SOFTMODEM}
${T_SOURCE}
${CONFIG_SOURCES}
${SHLIB_LOADER_SOURCES}
@@ -2445,7 +2439,7 @@ add_executable(nr-uesoftmodem
target_link_libraries (nr-uesoftmodem
-Wl,--start-group
- RRC_LIB NR_RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB PHY_COMMON PHY_NR_UE PHY_RU LFDS NR_L2_UE #NR_LTE_UE_REUSE_LIB
+ RRC_LIB NR_RRC_LIB SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB PHY_COMMON PHY_NR_UE PHY_RU LFDS NR_L2_UE MAC_NR_COMMON
${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 ${ATLAS_LIBRARIES}
-Wl,--end-group z dl)
@@ -2461,17 +2455,14 @@ add_executable(nr-uesoftmodem-nos1
${rrc_h}
${s1ap_h}
# ${OPENAIR_BIN_DIR}/messages_xml.h
- ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
- ${OPENAIR_TARGETS}/RT/USER/nr-ue.c
- ${OPENAIR_TARGETS}/RT/USER/nr-uesoftmodem.c
+ ${OPENAIR_DIR}/executables/nr-ue.c
+ ${OPENAIR_DIR}/executables/nr-uesoftmodem.c
${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c
- #${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c
${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
${OPENAIR_DIR}/common/utils/utils.c
${OPENAIR_DIR}/common/utils/system.c
${XFORMS_SOURCE_NR}
- ${XFORMS_SOURCE_SOFTMODEM}
${T_SOURCE}
${CONFIG_SOURCES}
${SHLIB_LOADER_SOURCES}
@@ -2479,7 +2470,7 @@ add_executable(nr-uesoftmodem-nos1
target_link_libraries (nr-uesoftmodem-nos1
-Wl,--start-group
- RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB PHY_COMMON PHY_NR_UE PHY_UE PHY_RU LFDS NR_L2_UE
+ RRC_LIB NR_RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB PHY_COMMON PHY_NR_UE PHY_UE PHY_RU LFDS NR_L2_UE MAC_NR_COMMON
${MSC_LIB} ${RAL_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} LFDS7 ${ATLAS_LIBRARIES}
-Wl,--end-group z dl)
@@ -2523,6 +2514,7 @@ target_link_libraries (nr-uesoftmodem-nos1 ${T_LIB})
add_executable(dlsim_tm4
${OPENAIR1_DIR}/SIMULATION/LTE_PHY/dlsim_tm4.c
${OPENAIR1_DIR}/PHY/TOOLS/lte_phy_scope_tm4.c
+ ${OPENAIR_DIR}/common/utils/system.c
${T_SOURCE}
)
target_link_libraries (dlsim_tm4
@@ -2535,6 +2527,12 @@ add_executable(polartest
${OPENAIR_DIR}/common/utils/backtrace.c)
target_link_libraries(polartest SIMU PHY PHY_NR PHY_COMMON m ${ATLAS_LIBRARIES})
+
+add_executable(smallblocktest
+ ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/smallblocktest.c
+ ${OPENAIR_DIR}/common/utils/backtrace.c)
+target_link_libraries(smallblocktest SIMU PHY PHY_NR PHY_COMMON m ${ATLAS_LIBRARIES})
+
add_executable(ldpctest
${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c
${OPENAIR_DIR}/common/utils/backtrace.c)
@@ -2543,12 +2541,14 @@ target_link_libraries(ldpctest SIMU PHY PHY_NR m ${ATLAS_LIBRARIES})
add_executable(nr_dlschsim
${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlschsim.c
${OPENAIR_DIR}/common/utils/backtrace.c
+ ${OPENAIR_DIR}/common/utils/system.c
${T_SOURCE})
target_link_libraries(nr_dlschsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} dl)
add_executable(nr_pbchsim
${OPENAIR1_DIR}/SIMULATION/NR_PHY/pbchsim.c
${OPENAIR_DIR}/common/utils/backtrace.c
+ ${OPENAIR_DIR}/common/utils/system.c
${T_SOURCE})
target_link_libraries(nr_pbchsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} dl)
@@ -2563,8 +2563,15 @@ target_link_libraries(nr_pucchsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR
add_executable(nr_dlsim
${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlsim.c
${OPENAIR_DIR}/common/utils/backtrace.c
+ ${OPENAIR_DIR}/common/utils/system.c
${T_SOURCE})
-target_link_libraries(nr_dlsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_NR MAC_UE_NR RRC_LIB NR_RRC_LIB CONFIG_LIB L2_NR -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} dl)
+target_link_libraries(nr_dlsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_NR MAC_UE_NR MAC_NR_COMMON RRC_LIB NR_RRC_LIB CONFIG_LIB L2_NR -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} dl)
+
+add_executable(nr_ulschsim
+ ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulschsim.c
+ ${OPENAIR_DIR}/common/utils/backtrace.c
+ ${T_SOURCE})
+target_link_libraries(nr_ulschsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} dl)
foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim)
@@ -2572,6 +2579,7 @@ foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim pr
add_executable(${myExe}
${OPENAIR1_DIR}/SIMULATION/LTE_PHY/${myExe}.c
${OPENAIR_DIR}/common/utils/backtrace.c
+ ${OPENAIR_DIR}/common/utils/system.c
${XFORMS_SOURCE}
${T_SOURCE}
${CONFIG_SOURCES}
@@ -2697,7 +2705,9 @@ L2
L2_NR
L2_UE
NR_L2_UE
-NR_LTE_UE_REUSE_LIB
+MAC_NR_COMMON
+MAC_NR
+MAC_UE_NR
CN_UTILS
GTPV1U
SCTP_CLIENT
diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml
index 2c47513c34..792e46cec6 100644
--- a/cmake_targets/autotests/test_case_list.xml
+++ b/cmake_targets/autotests/test_case_list.xml
@@ -1116,7 +1116,50 @@
segmentation fault|assertion|exiting|fatal
3
+
+
+ execution
+ shortblocktest Test cases. (Test1: 3 bits),
+ (Test2: 6 bits),
+ (Test3: 7 bits),
+ (Test4: 11 bits)
+
+ $OPENAIR_DIR/cmake_targets/build_oai
+ --phy_simulators -c
+ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash
+
+ $OPENAIR_DIR/targets/bin/smallblocktest.Rel15
+ -l 3 -s -4 -d 1 -i 10000
+ -l 6 -s -4 -d 1 -i 10000
+ -l 7 -s -4 -d 1 -i 10000
+ -l 11 -s -4 -d 1 -i 10000
+ smallblocktest.test1 smallblocktest.test2 smallblocktest.test3 smallblocktest.test4
+ BLER= 0.000000
+ segmentation fault|assertion|exiting|fatal
+ 3
+
+
+
+ execution
+ nr_ulschsim Test cases. (Test1: 106 PRB),
+ (Test2: 217 PRB),
+ (Test3: 273 PRB)
+
+ $OPENAIR_DIR/cmake_targets/build_oai
+ --phy_simulators -c
+ $OPENAIR_DIR/cmake_targets/autotests/tools/free_mem.bash
+
+ $OPENAIR_DIR/targets/bin/nr_ulschsim.Rel15
+ -R 106 -m9 -s13 -n100
+ -R 217 -m15 -s15 -n100
+ -R 273 -m19 -s20 -n100
+ nr_ulschsim.test1 nr_ulschsim.test2 nr_ulschsim.test3
+ PUSCH test OK
+ segmentation fault|assertion|exiting|fatal
+ 3
+
+
execution
dlsim_tm4 test cases (Test 1: 10 MHz, R2.FDD (MCS 5), EVA5, -1dB),
diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai
index 4ac63a376f..ecd53cc87c 100755
--- a/cmake_targets/build_oai
+++ b/cmake_targets/build_oai
@@ -80,8 +80,6 @@ function print_help() {
This program installs OpenAirInterface Software
You should have ubuntu 16.xx or 18.04 updated
Options
--h
- This help
-c | --clean
Erase all files to make a rebuild from start
-C | --clean-all
@@ -422,11 +420,6 @@ function main() {
CMAKE_CMD="$CMAKE_CMD .."
echo_info "CMAKE_CMD=$CMAKE_CMD"
- if [ "$eNB" = "1" -o "$gNB" = "1" ] && [ "$UE" = "1" -o "$nrUE" = "1" ]; then
- echo_error "Cannot build UE/nrUE and eNB/gNB on one build_oai execution"
- echo_error "use 2 build_oai invocations"
- exit
- fi
#########################################################
# check validity of HW and TP parameters for eNB / gNB
@@ -691,7 +684,7 @@ function main() {
echo_info "Compiling unitary tests simulators"
# TODO: fix: dlsim_tm4 pucchsim prachsim pdcchsim pbchsim mbmssim
#simlist="dlsim_tm4 dlsim ulsim pucchsim prachsim pdcchsim pbchsim mbmssim"
- simlist="nr_pucchsim dlsim ulsim polartest ldpctest nr_pbchsim nr_dlschsim nr_dlsim"
+ simlist="nr_pucchsim dlsim ulsim polartest ldpctest smallblocktest nr_pbchsim nr_dlschsim nr_dlsim nr_ulschsim"
for f in $simlist ; do
compilations \
phy_simulators $f \
diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper
index 8c5d33975c..1c4b291069 100755
--- a/cmake_targets/tools/build_helper
+++ b/cmake_targets/tools/build_helper
@@ -683,7 +683,7 @@ install_asn1c_from_source(){
# better to use a given commit than a branch in case the branch
# is updated and requires modifications in the source of OAI
#git checkout velichkov_s1ap_plus_option_group
- git checkout d3aed06bb2bec7df1b5c6d0333f8c7dfc5993372
+ git checkout f12568d617dbf48497588f8e227d70388fa217c9
autoreconf -iv
./configure
make -j`nproc`
diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c
index a92bdf11e4..1124a26b72 100644
--- a/common/utils/LOG/log.c
+++ b/common/utils/LOG/log.c
@@ -40,7 +40,7 @@
#include "assertions.h"
#if defined(ENABLE_ITTI)
-# include "intertask_interface.h"
+ #include "intertask_interface.h"
#endif
# include
@@ -75,16 +75,14 @@ char *log_level_highlight_start[] = {LOG_RED, LOG_ORANGE, "", LOG_BLUE, LOG_CYBL
char *log_level_highlight_end[] = {LOG_RESET,LOG_RESET,LOG_RESET, LOG_RESET,LOG_RESET}; /*!< \brief Optional end-format strings for highlighting */
-int write_file_matlab(const char *fname,const char *vname,void *data,int length,int dec,char format)
-{
-
+int write_file_matlab(const char *fname,const char *vname,void *data,int length,int dec,char format) {
FILE *fp=NULL;
int i;
if (data == NULL)
- return -1;
- //printf("Writing %d elements of type %d to %s\n",length,format,fname);
+ return -1;
+ //printf("Writing %d elements of type %d to %s\n",length,format,fname);
if (format == 10 || format ==11 || format == 12 || format == 13 || format == 14) {
fp = fopen(fname,"a+");
@@ -92,8 +90,6 @@ int write_file_matlab(const char *fname,const char *vname,void *data,int length,
fp = fopen(fname,"w+");
}
-
-
if (fp== NULL) {
printf("[OPENAIR][FILE OUTPUT] Cannot open file %s\n",fname);
return(-1);
@@ -102,121 +98,108 @@ int write_file_matlab(const char *fname,const char *vname,void *data,int length,
if (format != 10 && format !=11 && format != 12 && format != 13 && format != 14)
fprintf(fp,"%s = [",vname);
-
switch (format) {
- case 0: // real 16-bit
+ case 0: // real 16-bit
+ for (i=0; i 0))
+ fprintf(fp,"%d + j*(%d),",((short *)data)[i],((short *)data)[i+1]);
+ else if (i == 2*(length-1))
+ fprintf(fp,"%d + j*(%d);",((short *)data)[i],((short *)data)[i+1]);
+ else if (i == 0)
+ fprintf(fp,"\n%d + j*(%d),",((short *)data)[i],((short *)data)[i+1]);
+ }
- break;
+ break;
- case 9: // real unsigned 8-bit
- for (i=0; i 0))
+ fprintf(fp,"%d,",((short *)data)[i]);
+ else if (i == (length-1))
+ fprintf(fp,"%d;",((short *)data)[i]);
+ else if (i == 0)
+ fprintf(fp,"\n%d,",((short *)data)[i]);
+ }
- break;
-
-
- case 10 : // case eren 16 bit complex :
-
- for (i=0; i 0))
- fprintf(fp,"%d + j*(%d),",((short *)data)[i],((short *)data)[i+1]);
- else if (i == 2*(length-1))
- fprintf(fp,"%d + j*(%d);",((short *)data)[i],((short *)data)[i+1]);
- else if (i == 0)
- fprintf(fp,"\n%d + j*(%d),",((short *)data)[i],((short *)data)[i+1]);
-
-
-
- }
-
- break;
-
- case 11 : //case eren 16 bit real for channel magnitudes:
- for (i=0; i 0))
- fprintf(fp,"%d,",((short *)data)[i]);
- else if (i == (length-1))
- fprintf(fp,"%d;",((short *)data)[i]);
- else if (i == 0)
- fprintf(fp,"\n%d,",((short *)data)[i]);
- }
-
- printf("\n eren: length :%d",length);
- break;
-
- case 12 : // case eren for log2_maxh real unsigned 8 bit
- fprintf(fp,"%d \n",((unsigned char *)&data)[0]);
- break;
+ printf("\n eren: length :%d",length);
+ break;
+ case 12 : // case eren for log2_maxh real unsigned 8 bit
+ fprintf(fp,"%d \n",((unsigned char *)&data)[0]);
+ break;
}
if (format != 10 && format !=11 && format !=12 && format != 13 && format != 15) {
@@ -235,131 +218,141 @@ int write_file_matlab(const char *fname,const char *vname,void *data,int length,
void log_getconfig(log_t *g_log) {
char *gloglevel = NULL;
int consolelog ;
-
-
paramdef_t logparams_defaults[] = LOG_GLOBALPARAMS_DESC;
paramdef_t logparams_level[MAX_LOG_PREDEF_COMPONENTS];
paramdef_t logparams_logfile[MAX_LOG_PREDEF_COMPONENTS];
paramdef_t logparams_debug[sizeof(log_maskmap)/sizeof(mapping)];
paramdef_t logparams_dump[sizeof(log_maskmap)/sizeof(mapping)];
-
int ret = config_get( logparams_defaults,sizeof(logparams_defaults)/sizeof(paramdef_t),CONFIG_STRING_LOG_PREFIX);
- if (ret <0) {
- fprintf(stderr,"[LOG] init aborted, configuration couldn't be performed");
- return;
- }
-/* set LOG display options (enable/disable color, thread name, level ) */
+ if (ret <0) {
+ fprintf(stderr,"[LOG] init aborted, configuration couldn't be performed");
+ return;
+ }
+
+ /* set LOG display options (enable/disable color, thread name, level ) */
for(int i=0; iflag = g_log->flag | log_options[j].value;
- break;
- } else if (log_options[j+1].name == NULL){
- fprintf(stderr,"Unknown log option: %s\n",logparams_defaults[LOG_OPTIONS_IDX].strlistptr[i]);
- exit(-1);
- }
- }
- }
-
-/* build the parameter array for setting per component log level and infile options */
+ for(int j=0; log_options[j].name != NULL ; j++) {
+ if (strcmp(logparams_defaults[LOG_OPTIONS_IDX].strlistptr[i],log_options[j].name) == 0) {
+ g_log->flag = g_log->flag | log_options[j].value;
+ break;
+ } else if (log_options[j+1].name == NULL) {
+ fprintf(stderr,"Unknown log option: %s\n",logparams_defaults[LOG_OPTIONS_IDX].strlistptr[i]);
+ exit(-1);
+ }
+ }
+ }
+
+ /* build the parameter array for setting per component log level and infile options */
memset(logparams_level, 0, sizeof(paramdef_t)*MAX_LOG_PREDEF_COMPONENTS);
memset(logparams_logfile, 0, sizeof(paramdef_t)*MAX_LOG_PREDEF_COMPONENTS);
+
for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_PREDEF_COMPONENTS; i++) {
if(g_log->log_component[i].name == NULL) {
- g_log->log_component[i].name = malloc(16);
- sprintf((char *)g_log->log_component[i].name,"comp%i?",i);
- logparams_logfile[i].paramflags = PARAMFLAG_DONOTREAD;
- logparams_level[i].paramflags = PARAMFLAG_DONOTREAD;
+ g_log->log_component[i].name = malloc(16);
+ sprintf((char *)g_log->log_component[i].name,"comp%i?",i);
+ logparams_logfile[i].paramflags = PARAMFLAG_DONOTREAD;
+ logparams_level[i].paramflags = PARAMFLAG_DONOTREAD;
}
+
sprintf(logparams_level[i].optname, LOG_CONFIG_LEVEL_FORMAT, g_log->log_component[i].name);
sprintf(logparams_logfile[i].optname, LOG_CONFIG_LOGFILE_FORMAT, g_log->log_component[i].name);
-/* workaround: all log options in existing configuration files use lower case component names
- where component names include uppercase char in log.h.... */
- for (int j=0 ; jlog_component[i].level = map_str_to_int(log_level_names, *(logparams_level[i].strptr));
set_log(i, g_log->log_component[i].level);
+
if (*(logparams_logfile[i].uptr) == 1)
- set_component_filelog(i);
+ set_component_filelog(i);
}
-/* build then read the debug and dump parameter array */
- for (int i=0;log_maskmap[i].name != NULL ; i++) {
- sprintf(logparams_debug[i].optname, LOG_CONFIG_DEBUG_FORMAT, log_maskmap[i].name);
- sprintf(logparams_dump[i].optname, LOG_CONFIG_DUMP_FORMAT, log_maskmap[i].name);
- logparams_debug[i].defuintval = 0;
- logparams_debug[i].type = TYPE_UINT;
- logparams_debug[i].paramflags = PARAMFLAG_BOOL;
- logparams_debug[i].uptr = NULL;
- logparams_debug[i].chkPptr = NULL;
- logparams_debug[i].numelt = 0;
- logparams_dump[i].defuintval = 0;
- logparams_dump[i].type = TYPE_UINT;
- logparams_dump[i].paramflags = PARAMFLAG_BOOL;
- logparams_dump[i].uptr = NULL;
- logparams_dump[i].chkPptr = NULL;
- logparams_dump[i].numelt = 0;
+ /* build then read the debug and dump parameter array */
+ for (int i=0; log_maskmap[i].name != NULL ; i++) {
+ sprintf(logparams_debug[i].optname, LOG_CONFIG_DEBUG_FORMAT, log_maskmap[i].name);
+ sprintf(logparams_dump[i].optname, LOG_CONFIG_DUMP_FORMAT, log_maskmap[i].name);
+ logparams_debug[i].defuintval = 0;
+ logparams_debug[i].type = TYPE_UINT;
+ logparams_debug[i].paramflags = PARAMFLAG_BOOL;
+ logparams_debug[i].uptr = NULL;
+ logparams_debug[i].chkPptr = NULL;
+ logparams_debug[i].numelt = 0;
+ logparams_dump[i].defuintval = 0;
+ logparams_dump[i].type = TYPE_UINT;
+ logparams_dump[i].paramflags = PARAMFLAG_BOOL;
+ logparams_dump[i].uptr = NULL;
+ logparams_dump[i].chkPptr = NULL;
+ logparams_dump[i].numelt = 0;
}
- config_get( logparams_debug,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
- config_get( logparams_dump,(sizeof(log_maskmap)/sizeof(mapping)) - 1 ,CONFIG_STRING_LOG_PREFIX);
-/* set the debug mask according to the debug parameters values */
+
+ config_get( logparams_debug,(sizeof(log_maskmap)/sizeof(mapping)) - 1,CONFIG_STRING_LOG_PREFIX);
+ config_get( logparams_dump,(sizeof(log_maskmap)/sizeof(mapping)) - 1,CONFIG_STRING_LOG_PREFIX);
+
+ /* set the debug mask according to the debug parameters values */
for (int i=0; log_maskmap[i].name != NULL ; i++) {
if (*(logparams_debug[i].uptr) )
- g_log->debug_mask = g_log->debug_mask | log_maskmap[i].value;
+ g_log->debug_mask = g_log->debug_mask | log_maskmap[i].value;
+
if (*(logparams_dump[i].uptr) )
- g_log->dump_mask = g_log->dump_mask | log_maskmap[i].value;
- }
-/* log globally enabled/disabled */
+ g_log->dump_mask = g_log->dump_mask | log_maskmap[i].value;
+ }
+
+ /* log globally enabled/disabled */
set_glog_onlinelog(consolelog);
}
-int register_log_component(char *name, char *fext, int compidx)
-{
-int computed_compidx=compidx;
+int register_log_component(char *name, char *fext, int compidx) {
+ int computed_compidx=compidx;
if (strlen(fext) > 3) {
- fext[3]=0; /* limit log file extension to 3 chars */
+ fext[3]=0; /* limit log file extension to 3 chars */
}
+
if (compidx < 0) { /* this is not a pre-defined component */
- for (int i = MAX_LOG_PREDEF_COMPONENTS; i< MAX_LOG_COMPONENTS; i++) {
- if (g_log->log_component[i].name == NULL) {
- computed_compidx=i;
- break;
- }
+ for (int i = MAX_LOG_PREDEF_COMPONENTS; i< MAX_LOG_COMPONENTS; i++) {
+ if (g_log->log_component[i].name == NULL) {
+ computed_compidx=i;
+ break;
}
+ }
}
+
if (computed_compidx >= 0 && computed_compidx log_component[computed_compidx].name = strdup(name);
- g_log->log_component[computed_compidx].stream = stdout;
- g_log->log_component[computed_compidx].filelog = 0;
- g_log->log_component[computed_compidx].filelog_name = malloc(strlen(name)+16);/* /tmp/.%s */
- sprintf(g_log->log_component[computed_compidx].filelog_name,"/tmp/%s.%s",name,fext);
+ g_log->log_component[computed_compidx].name = strdup(name);
+ g_log->log_component[computed_compidx].stream = stdout;
+ g_log->log_component[computed_compidx].filelog = 0;
+ g_log->log_component[computed_compidx].filelog_name = malloc(strlen(name)+16);/* /tmp/.%s */
+ sprintf(g_log->log_component[computed_compidx].filelog_name,"/tmp/%s.%s",name,fext);
} else {
- fprintf(stderr,"{LOG} %s %d Couldn't register componemt %s\n",__FILE__,__LINE__,name);
+ fprintf(stderr,"{LOG} %s %d Couldn't register componemt %s\n",__FILE__,__LINE__,name);
}
-return computed_compidx;
+
+ return computed_compidx;
}
-int logInit (void)
-{
+int logInit (void) {
int i;
g_log = calloc(1, sizeof(log_t));
@@ -367,10 +360,8 @@ int logInit (void)
perror ("cannot allocated memory for log generation module \n");
exit(EXIT_FAILURE);
}
+
memset(g_log,0,sizeof(log_t));
-
-
-
register_log_component("PHY","log",PHY);
register_log_component("MAC","log",MAC);
register_log_component("OPT","log",OPT);
@@ -386,143 +377,121 @@ int logInit (void)
register_log_component("OTG_JITTER","dat",OTG_JITTER);
register_log_component("OCG","",OCG);
register_log_component("PERF","",PERF);
- register_log_component("OIP","",OIP);
- register_log_component("CLI","",CLI);
- register_log_component("MSC","log",MSC);
- register_log_component("OCM","log",OCM);
- register_log_component("HW","",HW);
- register_log_component("OSA","",OSA);
- register_log_component("eRAL","",RAL_ENB);
- register_log_component("mRAL","",RAL_UE);
- register_log_component("ENB_APP","log",ENB_APP);
- register_log_component("FLEXRAN_AGENT","log",FLEXRAN_AGENT);
- register_log_component("TMR","",TMR);
- register_log_component("USIM","txt",USIM);
- register_log_component("SIM","txt",SIM);
-
+ register_log_component("OIP","",OIP);
+ register_log_component("CLI","",CLI);
+ register_log_component("MSC","log",MSC);
+ register_log_component("OCM","log",OCM);
+ register_log_component("HW","",HW);
+ register_log_component("OSA","",OSA);
+ register_log_component("eRAL","",RAL_ENB);
+ register_log_component("mRAL","",RAL_UE);
+ register_log_component("ENB_APP","log",ENB_APP);
+ register_log_component("FLEXRAN_AGENT","log",FLEXRAN_AGENT);
+ register_log_component("TMR","",TMR);
+ register_log_component("USIM","txt",USIM);
+ register_log_component("SIM","txt",SIM);
/* following log component are used for the localization*/
register_log_component("LOCALIZE","log",LOCALIZE);
register_log_component("NAS","log",NAS);
register_log_component("UDP","",UDP_);
-
-
register_log_component("GTPV1U","",GTPU);
-
-
register_log_component("S1AP","",S1AP);
register_log_component("X2AP","",X2AP);
-
-
register_log_component("SCTP","",SCTP);
register_log_component("X2AP","",X2AP);
register_log_component("LOADER","log",LOADER);
register_log_component("ASN","log",ASN);
-
-
for (int i=0 ; log_level_names[i].name != NULL ; i++)
- g_log->level2string[i] = toupper(log_level_names[i].name[0]); // uppercased first letter of level name
-
-
-
-
+ g_log->level2string[i] = toupper(log_level_names[i].name[0]); // uppercased first letter of level name
g_log->filelog_name = "/tmp/openair.log";
-
log_getconfig(g_log);
-
-
// set all unused component items to 0, they are for non predefined components
for (i=MAX_LOG_PREDEF_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
- memset(&(g_log->log_component[i]),0,sizeof(log_component_t));
+ memset(&(g_log->log_component[i]),0,sizeof(log_component_t));
}
- printf("log init done\n");
+ printf("log init done\n");
return 0;
}
char *log_getthreadname(char *threadname, int bufsize) {
+ int rt = pthread_getname_np(pthread_self(), threadname,bufsize) ;
-int rt = pthread_getname_np(pthread_self(), threadname,bufsize) ;
- if (rt == 0)
- {
- return threadname;
- } else {
- return "thread?";
- }
+ if (rt == 0) {
+ return threadname;
+ } else {
+ return "thread?";
+ }
}
static int log_header(char *log_buffer, int buffsize, int comp, int level,const char *format) {
char threadname[PR_SET_NAME];
-return snprintf(log_buffer, buffsize , "%s%s[%s]%c %s %s%s",
- log_level_highlight_end[level],
- ( (g_log->flag & FLAG_NOCOLOR)?"":log_level_highlight_start[level]),
- g_log->log_component[comp].name,
- ( (g_log->flag & FLAG_LEVEL)?g_log->level2string[level]:' '),
- ( (g_log->flag & FLAG_THREAD)?log_getthreadname(threadname,PR_SET_NAME+1):""),
- format,
- log_level_highlight_end[level]);
+ return snprintf(log_buffer, buffsize, "%s%s[%s]%c %s %s%s",
+ log_level_highlight_end[level],
+ ( (g_log->flag & FLAG_NOCOLOR)?"":log_level_highlight_start[level]),
+ g_log->log_component[comp].name,
+ ( (g_log->flag & FLAG_LEVEL)?g_log->level2string[level]:' '),
+ ( (g_log->flag & FLAG_THREAD)?log_getthreadname(threadname,PR_SET_NAME+1):""),
+ format,
+ log_level_highlight_end[level]);
}
-void logRecord_mt(const char *file, const char *func, int line, int comp, int level, const char* format, ... )
- {
- char log_buffer[MAX_LOG_TOTAL]={0};
+void logRecord_mt(const char *file, const char *func, int line, int comp, int level, const char *format, ... ) {
+ char log_buffer[MAX_LOG_TOTAL]= {0};
va_list args;
-
va_start(args, format);
-
-
-
-
- log_header(log_buffer,MAX_LOG_TOTAL ,comp, level,format);
+ log_header(log_buffer,MAX_LOG_TOTAL,comp, level,format);
g_log->log_component[comp].vprint(g_log->log_component[comp].stream,log_buffer, args);
+ fflush(g_log->log_component[comp].stream);
va_end(args);
-
-
}
-void log_dump(int component, void *buffer, int buffsize,int datatype, const char* format, ... ) {
-va_list args;
-char *wbuf;
+void log_dump(int component, void *buffer, int buffsize,int datatype, const char *format, ... ) {
+ va_list args;
+ char *wbuf;
+ switch(datatype) {
+ case LOG_DUMP_DOUBLE:
+ wbuf=malloc((buffsize * 10) + 64 + MAX_LOG_TOTAL);
+ break;
- switch(datatype) {
- case LOG_DUMP_DOUBLE:
- wbuf=malloc((buffsize * 10) + 64 + MAX_LOG_TOTAL);
- break;
- case LOG_DUMP_CHAR:
- default:
- wbuf=malloc((buffsize * 3 ) + 64 + MAX_LOG_TOTAL);
- break;
+ case LOG_DUMP_CHAR:
+ default:
+ wbuf=malloc((buffsize * 3 ) + 64 + MAX_LOG_TOTAL);
+ break;
+ }
+
+ if (wbuf != NULL) {
+ va_start(args, format);
+ int pos=log_header(wbuf,MAX_LOG_TOTAL,component, OAILOG_INFO,"");
+ int pos2=vsprintf(wbuf+pos,format, args);
+ pos=pos+pos2;
+ va_end(args);
+
+ for (int i=0; ilog_component[component].print(g_log->log_component[component].stream,wbuf);
free(wbuf);
- }
+ }
}
-int set_log(int component, int level)
-{
+int set_log(int component, int level) {
/* Checking parameters */
DevCheck((component >= MIN_LOG_COMPONENTS) && (component < MAX_LOG_COMPONENTS),
component, MIN_LOG_COMPONENTS, MAX_LOG_COMPONENTS);
@@ -530,38 +499,34 @@ int set_log(int component, int level)
OAILOG_ERR);
if ( g_log->log_component[component].level != OAILOG_DISABLE )
- g_log->log_component[component].savedlevel = g_log->log_component[component].level;
- g_log->log_component[component].level = level;
+ g_log->log_component[component].savedlevel = g_log->log_component[component].level;
+ g_log->log_component[component].level = level;
return 0;
}
-void set_glog(int level)
-{
+void set_glog(int level) {
for (int c=0; c< MAX_LOG_COMPONENTS; c++ ) {
- set_log(c, level);
+ set_log(c, level);
}
-
}
-void set_glog_onlinelog(int enable)
-{
+void set_glog_onlinelog(int enable) {
for (int c=0; c< MAX_LOG_COMPONENTS; c++ ) {
- if ( enable ) {
- g_log->log_component[c].level = g_log->log_component[c].savedlevel;
- g_log->log_component[c].vprint = vfprintf;
- g_log->log_component[c].print = fprintf;
- g_log->log_component[c].stream = stdout;
- } else {
- g_log->log_component[c].level = OAILOG_DISABLE;
- }
- }
+ if ( enable ) {
+ g_log->log_component[c].level = g_log->log_component[c].savedlevel;
+ g_log->log_component[c].vprint = vfprintf;
+ g_log->log_component[c].print = fprintf;
+ g_log->log_component[c].stream = stdout;
+ } else {
+ g_log->log_component[c].level = OAILOG_DISABLE;
+ }
+ }
}
-void set_glog_filelog(int enable)
-{
-static FILE *fptr;
+void set_glog_filelog(int enable) {
+ static FILE *fptr;
if ( enable ) {
fptr = fopen(g_log->filelog_name,"w");
@@ -574,33 +539,35 @@ static FILE *fptr;
} else {
for (int c=0; c< MAX_LOG_COMPONENTS; c++ ) {
g_log->log_component[c].filelog = 0;
+
if (fptr != NULL) {
fclose(fptr);
}
+
g_log->log_component[c].stream = stdout;
- }
- }
+ }
+ }
}
-void set_component_filelog(int comp)
-{
- if (g_log->log_component[comp].stream == NULL || g_log->log_component[comp].stream == stdout) {
- g_log->log_component[comp].stream = fopen(g_log->log_component[comp].filelog_name,"w");
- }
- g_log->log_component[comp].vprint = vfprintf;
- g_log->log_component[comp].print = fprintf;
- g_log->log_component[comp].filelog = 1;
+void set_component_filelog(int comp) {
+ if (g_log->log_component[comp].stream == NULL || g_log->log_component[comp].stream == stdout) {
+ g_log->log_component[comp].stream = fopen(g_log->log_component[comp].filelog_name,"w");
+ }
+
+ g_log->log_component[comp].vprint = vfprintf;
+ g_log->log_component[comp].print = fprintf;
+ g_log->log_component[comp].filelog = 1;
}
-void close_component_filelog(int comp)
-{
- g_log->log_component[comp].filelog = 0;
- if (g_log->log_component[comp].stream != NULL && g_log->log_component[comp].stream != stdout ) {
- fclose(g_log->log_component[comp].stream);
- g_log->log_component[comp].stream = stdout;
- }
- g_log->log_component[comp].vprint = vfprintf;
- g_log->log_component[comp].print = fprintf;
-
+void close_component_filelog(int comp) {
+ g_log->log_component[comp].filelog = 0;
+
+ if (g_log->log_component[comp].stream != NULL && g_log->log_component[comp].stream != stdout ) {
+ fclose(g_log->log_component[comp].stream);
+ g_log->log_component[comp].stream = stdout;
+ }
+
+ g_log->log_component[comp].vprint = vfprintf;
+ g_log->log_component[comp].print = fprintf;
}
/*
@@ -608,8 +575,7 @@ void close_component_filelog(int comp)
* with string value NULL
*/
/* map a string to an int. Takes a mapping array and a string as arg */
-int map_str_to_int(mapping *map, const char *str)
-{
+int map_str_to_int(mapping *map, const char *str) {
while (1) {
if (map->name == NULL) {
return(-1);
@@ -624,8 +590,7 @@ int map_str_to_int(mapping *map, const char *str)
}
/* map an int to a string. Takes a mapping array and a value */
-char *map_int_to_str(mapping *map, int val)
-{
+char *map_int_to_str(mapping *map, int val) {
while (1) {
if (map->name == NULL) {
return NULL;
@@ -639,8 +604,7 @@ char *map_int_to_str(mapping *map, int val)
}
}
-int is_newline( char *str, int size)
-{
+int is_newline( char *str, int size) {
int i;
for ( i = 0; i < size; i++ ) {
@@ -653,85 +617,62 @@ int is_newline( char *str, int size)
return 0;
}
-void logClean (void)
-{
+void logClean (void) {
int i;
LOG_UI(PHY,"\n");
-
-
-
for (i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
- close_component_filelog(i);
+ close_component_filelog(i);
}
}
-
+
#ifdef LOG_TEST
-int main(int argc, char *argv[])
-{
-
+int main(int argc, char *argv[]) {
logInit();
-
-
test_log();
-
return 1;
}
-int test_log(void)
-{
+int test_log(void) {
LOG_ENTER(MAC); // because the default level is DEBUG
LOG_I(EMU, "1 Starting OAI logs version %s Build date: %s on %s\n",
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
LOG_D(MAC, "1 debug MAC \n");
LOG_W(MAC, "1 warning MAC \n");
-
set_log(EMU, OAILOG_INFO);
set_log(MAC, OAILOG_WARNING);
-
LOG_I(EMU, "2 Starting OAI logs version %s Build date: %s on %s\n",
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
LOG_E(MAC, "2 error MAC\n");
LOG_D(MAC, "2 debug MAC \n");
LOG_W(MAC, "2 warning MAC \n");
LOG_I(MAC, "2 info MAC \n");
-
-
set_log(MAC, OAILOG_NOTICE);
-
LOG_ENTER(MAC);
LOG_I(EMU, "3 Starting OAI logs version %s Build date: %s on %s\n",
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
LOG_D(MAC, "3 debug MAC \n");
LOG_W(MAC, "3 warning MAC \n");
LOG_I(MAC, "3 info MAC \n");
-
set_log(MAC, LOG_DEBUG);
set_log(EMU, LOG_DEBUG);
-
LOG_ENTER(MAC);
LOG_I(EMU, "4 Starting OAI logs version %s Build date: %s on %s\n",
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
LOG_D(MAC, "4 debug MAC \n");
LOG_W(MAC, "4 warning MAC \n");
LOG_I(MAC, "4 info MAC \n");
-
-
set_log(MAC, LOG_DEBUG);
set_log(EMU, LOG_DEBUG);
-
LOG_I(LOG, "5 Starting OAI logs version %s Build date: %s on %s\n",
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
LOG_D(MAC, "5 debug MAC \n");
LOG_W(MAC, "5 warning MAC \n");
LOG_I(MAC, "5 info MAC \n");
-
-
set_log(MAC, LOG_TRACE);
set_log(EMU, LOG_TRACE);
-
LOG_ENTER(MAC);
LOG_I(LOG, "6 Starting OAI logs version %s Build date: %s on %s\n",
BUILD_VERSION, BUILD_DATE, BUILD_HOST);
@@ -739,7 +680,6 @@ int test_log(void)
LOG_W(MAC, "6 warning MAC \n");
LOG_I(MAC, "6 info MAC \n");
LOG_EXIT(MAC);
-
return 0;
}
#endif
diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h
index db73bd7f5b..b8a72ece7b 100644
--- a/common/utils/LOG/log.h
+++ b/common/utils/LOG/log.h
@@ -45,14 +45,15 @@
#include
#include
#ifndef __STDC_FORMAT_MACROS
-#define __STDC_FORMAT_MACROS
+ #define __STDC_FORMAT_MACROS
#endif
#include
#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
+ #define _GNU_SOURCE
#endif
#include
#include "T.h"
+#include
/*----------------------------------------------------------------------------*/
#ifdef __cplusplus
@@ -82,11 +83,11 @@ extern "C" {
* @brief LOG defines 9 levels of messages for users. Importance of these levels decrease gradually from 0 to 8
* @{*/
# define OAILOG_DISABLE -1 /*!< \brief disable all LOG messages, cannot be used in LOG macros, use only in LOG module */
-# define OAILOG_ERR 0 /*!< \brief critical error conditions, impact on "must have" fuctinalities */
+# define OAILOG_ERR 0 /*!< \brief critical error conditions, impact on "must have" functionalities */
# define OAILOG_WARNING 1 /*!< \brief warning conditions, shouldn't happen but doesn't impact "must have" functionalities */
# define OAILOG_INFO 2 /*!< \brief informational messages most people don't need, shouldn't impact real-time behavior */
-# define OAILOG_DEBUG 3 /*!< \brief first level debug-level messages, for developers , may impact real-time behavior */
-# define OAILOG_TRACE 4 /*!< \brief second level debug-level messages, for developers ,likely impact real-time behavior*/
+# define OAILOG_DEBUG 3 /*!< \brief first level debug-level messages, for developers, may impact real-time behavior */
+# define OAILOG_TRACE 4 /*!< \brief second level debug-level messages, for developers, likely impact real-time behavior*/
#define NUM_LOG_LEVEL 5 /*!< \brief the number of message levels users have with LOG (OAILOG_DISABLE is not available to user as a level, so it is not included)*/
/* @}*/
@@ -127,11 +128,11 @@ extern "C" {
/** @defgroup macros to identify a debug entity
* @ingroup each macro is a bit mask where the unique bit set identifies an entity to be debugged
- * it allows to dynamically activate or not blocks of code. The LOG_MASKMAP_INIT macro
+ * it allows to dynamically activate or not blocks of code. The LOG_MASKMAP_INIT macro
* is used to map a character string name to each debug bit, it allows to set or clear
* the corresponding bit via the defined name, from the configuration or from the telnet
* server.
- * @brief
+ * @brief
* @{*/
#define DEBUG_PRACH (1<<0)
#define DEBUG_RU (1<<1)
@@ -150,22 +151,22 @@ extern "C" {
#define LOG_MASKMAP_INIT {\
- {"PRACH", DEBUG_PRACH},\
- {"RU", DEBUG_RU},\
- {"UE_PHYPROC", DEBUG_UE_PHYPROC},\
- {"LTEESTIM", DEBUG_LTEESTIM},\
- {"DLCELLSPEC", DEBUG_DLCELLSPEC},\
- {"ULSCH", DEBUG_ULSCH},\
- {"RRC", DEBUG_RRC},\
- {"PDCP", DEBUG_PDCP},\
- {"DFT", DEBUG_DFT},\
- {"ASN1", DEBUG_ASN1},\
- {"CTRLSOCKET", DEBUG_CTRLSOCKET},\
- {"SECURITY", DEBUG_SECURITY},\
- {"NAS", DEBUG_NAS},\
- {"UE_TIMING", UE_TIMING},\
- {NULL,-1}\
-}
+ {"PRACH", DEBUG_PRACH},\
+ {"RU", DEBUG_RU},\
+ {"UE_PHYPROC", DEBUG_UE_PHYPROC},\
+ {"LTEESTIM", DEBUG_LTEESTIM},\
+ {"DLCELLSPEC", DEBUG_DLCELLSPEC},\
+ {"ULSCH", DEBUG_ULSCH},\
+ {"RRC", DEBUG_RRC},\
+ {"PDCP", DEBUG_PDCP},\
+ {"DFT", DEBUG_DFT},\
+ {"ASN1", DEBUG_ASN1},\
+ {"CTRLSOCKET", DEBUG_CTRLSOCKET},\
+ {"SECURITY", DEBUG_SECURITY},\
+ {"NAS", DEBUG_NAS},\
+ {"UE_TIMING", UE_TIMING},\
+ {NULL,-1}\
+ }
@@ -178,51 +179,51 @@ extern "C" {
typedef enum {
- MIN_LOG_COMPONENTS = 0,
- PHY = MIN_LOG_COMPONENTS,
- MAC,
- EMU,
- SIM,
- OCG,
- OMG,
- OPT,
- OTG,
- OTG_LATENCY,
- OTG_LATENCY_BG,
- OTG_GP,
- OTG_GP_BG,
- OTG_JITTER,
- RLC,
- PDCP,
- RRC,
- NAS,
- PERF,
- OIP,
- CLI,
- MSC,
- OCM,
- UDP_,
- GTPU,
- SPGW,
- S1AP,
- SCTP,
- HW,
- OSA,
- RAL_ENB,
- RAL_UE,
- ENB_APP,
- FLEXRAN_AGENT,
- TMR,
- USIM,
- LOCALIZE,
- X2AP,
- GNB_APP,
- NR_RRC,
- NR_MAC,
- NR_PHY,
- LOADER,
- ASN,
- MAX_LOG_PREDEF_COMPONENTS,
+ MIN_LOG_COMPONENTS = 0,
+ PHY = MIN_LOG_COMPONENTS,
+ MAC,
+ EMU,
+ SIM,
+ OCG,
+ OMG,
+ OPT,
+ OTG,
+ OTG_LATENCY,
+ OTG_LATENCY_BG,
+ OTG_GP,
+ OTG_GP_BG,
+ OTG_JITTER,
+ RLC,
+ PDCP,
+ RRC,
+ NAS,
+ PERF,
+ OIP,
+ CLI,
+ MSC,
+ OCM,
+ UDP_,
+ GTPU,
+ SPGW,
+ S1AP,
+ SCTP,
+ HW,
+ OSA,
+ RAL_ENB,
+ RAL_UE,
+ ENB_APP,
+ FLEXRAN_AGENT,
+ TMR,
+ USIM,
+ LOCALIZE,
+ X2AP,
+ GNB_APP,
+ NR_RRC,
+ NR_MAC,
+ NR_PHY,
+ LOADER,
+ ASN,
+ MAX_LOG_PREDEF_COMPONENTS,
}
comp_name_t;
@@ -231,42 +232,42 @@ comp_name_t;
typedef struct {
- char *name; /*!< \brief string name of item */
- int value; /*!< \brief integer value of mapping */
+ char *name; /*!< \brief string name of item */
+ int value; /*!< \brief integer value of mapping */
} mapping;
typedef int(*log_vprint_func_t)(FILE *stream, const char *format, va_list ap );
typedef int(*log_print_func_t)(FILE *stream, const char *format, ... );
typedef struct {
- const char *name;
- int level;
- int savedlevel;
- int flag;
- int filelog;
- char *filelog_name;
- FILE *stream;
- log_vprint_func_t vprint;
- log_print_func_t print;
- /* SR: make the log buffer component relative */
- char log_buffer[MAX_LOG_TOTAL];
+ const char *name;
+ int level;
+ int savedlevel;
+ int flag;
+ int filelog;
+ char *filelog_name;
+ FILE *stream;
+ log_vprint_func_t vprint;
+ log_print_func_t print;
+ /* SR: make the log buffer component relative */
+ char log_buffer[MAX_LOG_TOTAL];
} log_component_t;
typedef struct {
- log_component_t log_component[MAX_LOG_COMPONENTS];
- char level2string[NUM_LOG_LEVEL];
- int flag;
- char* filelog_name;
- uint64_t debug_mask;
- uint64_t dump_mask;
+ log_component_t log_component[MAX_LOG_COMPONENTS];
+ char level2string[NUM_LOG_LEVEL];
+ int flag;
+ char *filelog_name;
+ uint64_t debug_mask;
+ uint64_t dump_mask;
} log_t;
#if defined(ENABLE_ITTI)
typedef enum log_instance_type_e {
- LOG_INSTANCE_UNKNOWN,
- LOG_INSTANCE_ENB,
- LOG_INSTANCE_UE,
+ LOG_INSTANCE_UNKNOWN,
+ LOG_INSTANCE_ENB,
+ LOG_INSTANCE_UE,
} log_instance_type_t;
void log_set_instance_type (log_instance_type_t instance);
@@ -277,9 +278,9 @@ void log_set_instance_type (log_instance_type_t instance);
log_t *g_log;
#else
#ifdef __cplusplus
- extern "C" {
+extern "C" {
#endif
-extern log_t *g_log;
+ extern log_t *g_log;
#ifdef __cplusplus
}
#endif
@@ -289,7 +290,7 @@ extern log_t *g_log;
/*----------------------------------------------------------------------------*/
int logInit (void);
void logRecord_mt(const char *file, const char *func, int line,int comp, int level, const char *format, ...) __attribute__ ((format (printf, 6, 7)));
-void log_dump(int component, void *buffer, int buffsize,int datatype, const char* format, ... );
+void log_dump(int component, void *buffer, int buffsize,int datatype, const char *format, ... );
int set_log(int component, int level);
void set_glog(int level);
@@ -332,22 +333,22 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int
#define LOG_CONFIG_DUMP_FORMAT "%s_dump"
#define LOG_CONFIG_HELP_OPTIONS " list of comma separated options to enable log module behavior. Available options: \n"\
- " nocolor: disable color usage in log messages\n"\
- " level: add log level indication in log messages\n"\
- " thread: add threads names in log messages\n"
-
+ " nocolor: disable color usage in log messages\n"\
+ " level: add log level indication in log messages\n"\
+ " thread: add threads names in log messages\n"
+
+
-
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
-/* LOG globalconfiguration parameters */
-/* optname help paramflags XXXptr defXXXval type numelt */
+/* LOG globalconfiguration parameters */
+/* optname help paramflags XXXptr defXXXval type numelt */
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define LOG_GLOBALPARAMS_DESC { \
-{LOG_CONFIG_STRING_GLOBAL_LOG_LEVEL, "Default log level for all componemts\n", 0, strptr:(char **)&gloglevel, defstrval:log_level_names[2].name, TYPE_STRING, 0}, \
-{LOG_CONFIG_STRING_GLOBAL_LOG_ONLINE, "Default console output option, for all components\n", 0, iptr:&(consolelog), defintval:1, TYPE_INT, 0}, \
-{LOG_CONFIG_STRING_GLOBAL_LOG_OPTIONS, LOG_CONFIG_HELP_OPTIONS, 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST,0} \
-}
+ {LOG_CONFIG_STRING_GLOBAL_LOG_LEVEL, "Default log level for all componemts\n", 0, strptr:(char **)&gloglevel, defstrval:log_level_names[2].name, TYPE_STRING, 0}, \
+ {LOG_CONFIG_STRING_GLOBAL_LOG_ONLINE, "Default console output option, for all components\n", 0, iptr:&(consolelog), defintval:1, TYPE_INT, 0}, \
+ {LOG_CONFIG_STRING_GLOBAL_LOG_OPTIONS, LOG_CONFIG_HELP_OPTIONS, 0, strlistptr:NULL, defstrlistval:NULL, TYPE_STRINGLIST,0} \
+ }
#define LOG_OPTIONS_IDX 2
/*----------------------------------------------------------------------------------*/
@@ -359,23 +360,23 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int
#define LOG_DUMP_DOUBLE 1
// debugging macros
#define LOG_F LOG_I /* because LOG_F was originaly to dump a message or buffer but is also used as a regular level...., to dump use LOG_DUMPMSG */
-# if T_TRACER
- /* per component, level dependant macros */
-# define LOG_E(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_ERR ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_ERR, x) ;} else { T(T_LEGACY_ ## c ## _ERROR, T_PRINTF(x)) ;}} while (0)
-# define LOG_W(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_WARNING) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_WARNING, x) ;} else { T(T_LEGACY_ ## c ## _WARNING, T_PRINTF(x)) ;}} while (0)
-# define LOG_I(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_INFO ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ;} else { T(T_LEGACY_ ## c ## _INFO, T_PRINTF(x)) ;}} while (0)
-# define LOG_D(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_DEBUG ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_DEBUG, x) ;} else { T(T_LEGACY_ ## c ## _DEBUG, T_PRINTF(x)) ;}} while (0)
-# define LOG_T(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_TRACE ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_TRACE, x) ;} else { T(T_LEGACY_ ## c ## _TRACE, T_PRINTF(x)) ;}} while (0)
- /* macro used to dump a buffer or a message as in openair2/RRC/LTE/RRC_eNB.c, replaces LOG_F macro */
+# if T_TRACER
+/* per component, level dependant macros */
+# define LOG_E(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_ERR ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_ERR, x) ;} else { T(T_LEGACY_ ## c ## _ERROR, T_PRINTF(x)) ;}} while (0)
+# define LOG_W(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_WARNING) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_WARNING, x) ;} else { T(T_LEGACY_ ## c ## _WARNING, T_PRINTF(x)) ;}} while (0)
+# define LOG_I(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_INFO ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ;} else { T(T_LEGACY_ ## c ## _INFO, T_PRINTF(x)) ;}} while (0)
+# define LOG_D(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_DEBUG ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_DEBUG, x) ;} else { T(T_LEGACY_ ## c ## _DEBUG, T_PRINTF(x)) ;}} while (0)
+# define LOG_T(c, x...) do { if (T_stdout) { if( g_log->log_component[c].level >= OAILOG_TRACE ) logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_TRACE, x) ;} else { T(T_LEGACY_ ## c ## _TRACE, T_PRINTF(x)) ;}} while (0)
+/* macro used to dump a buffer or a message as in openair2/RRC/LTE/RRC_eNB.c, replaces LOG_F macro */
# define LOG_DUMPMSG(c, f, b, s, x...) do { if(g_log->dump_mask & f) log_dump(c, b, s, LOG_DUMP_CHAR, x) ;} while (0) /* */
# define nfapi_log(FILE, FNC, LN, COMP, LVL, F...) do { if (T_stdout) { logRecord_mt(__FILE__, __FUNCTION__, __LINE__,COMP, LVL, F) ;}} while (0) /* */
- /* bitmask dependant macros, to isolate debugging code */
+/* bitmask dependant macros, to isolate debugging code */
# define LOG_DEBUGFLAG(D) (g_log->debug_mask & D)
- /* bitmask dependant macros, to generate debug file such as matlab file or message dump */
+/* bitmask dependant macros, to generate debug file such as matlab file or message dump */
# define LOG_DUMPFLAG(D) (g_log->dump_mask & D)
# define LOG_M(file, vector, data, len, dec, format) do { write_file_matlab(file, vector, data, len, dec, format);} while(0)/* */
- /* define variable only used in LOG macro's */
+/* define variable only used in LOG macro's */
# define LOG_VAR(A,B) A B
# else /* T_TRACER: remove all debugging and tracing messages, except errors */
# define LOG_I(c, x...) do {logRecord_mt(__FILE__, __FUNCTION__, __LINE__,c, OAILOG_INFO, x) ; } while(0)/* */
@@ -385,15 +386,15 @@ int32_t write_file_matlab(const char *fname, const char *vname, void *data, int
# define LOG_T(c, x...) /* */
# define LOG_DUMPMSG(c, b, s, x...) /* */
-# define nfapi_log(FILE, FNC, LN, COMP, LVL, FMT...)
+# define nfapi_log(FILE, FNC, LN, COMP, LVL, FMT...)
# define LOG_DEBUGFLAG(D) ( 0 )
-# define LOG_DUMPFLAG(D) ( 0 )
+# define LOG_DUMPFLAG(D) ( 0 )
# define LOG_M(file, vector, data, len, dec, format) do { write_file_matlab(file, vector, data, len, dec, format);} while(0)
# define LOG_VAR(A,B)
# endif /* T_TRACER */
/* avoid warnings for variables only used in LOG macro's but set outside debug section */
-#define GCC_NOTUSED __attribute__((unused))
-#define LOG_USEDINLOG_VAR(A,B) GCC_NOTUSED A B
+#define GCC_NOTUSED __attribute__((unused))
+#define LOG_USEDINLOG_VAR(A,B) GCC_NOTUSED A B
/* unfiltered macros, usefull for simulators or messages at init time, before log is configured */
#define LOG_UM(file, vector, data, len, dec, format) do { write_file_matlab(file, vector, data, len, dec, format);} while(0)
@@ -425,78 +426,82 @@ static __inline__ uint64_t rdtsc(void) {
extern double cpuf;
-static inline uint64_t checkTCPU(int timeout, char * file, int line) {
- static __thread uint64_t lastCPUTime=0;
- static __thread uint64_t last=0;
- uint64_t cur=rdtsc();
- struct timespec CPUt;
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &CPUt);
- uint64_t CPUTime=CPUt.tv_sec*1000*1000+CPUt.tv_nsec/1000;
- double microCycles=(double)(cpuf*1000);
- int duration=(int)((cur-last)/microCycles);
- if ( last!=0 && duration > timeout ) {
- //struct timespec ts;
- //clock_gettime(CLOCK_MONOTONIC, &ts);
- printf("%s:%d lte-ue delay %d (exceed %d), CPU for this period: %lld\n", file, line,
- duration, timeout, (long long)CPUTime-lastCPUTime );
- }
- last=cur;
- lastCPUTime=CPUTime;
- return cur;
+static inline uint64_t checkTCPU(int timeout, char *file, int line) {
+ static __thread uint64_t lastCPUTime=0;
+ static __thread uint64_t last=0;
+ uint64_t cur=rdtsc();
+ struct timespec CPUt;
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &CPUt);
+ uint64_t CPUTime=CPUt.tv_sec*1000*1000+CPUt.tv_nsec/1000;
+ double microCycles=(double)(cpuf*1000);
+ int duration=(int)((cur-last)/microCycles);
+
+ if ( last!=0 && duration > timeout ) {
+ //struct timespec ts;
+ //clock_gettime(CLOCK_MONOTONIC, &ts);
+ printf("%s:%d lte-ue delay %d (exceed %d), CPU for this period: %lld\n", file, line,
+ duration, timeout, (long long)CPUTime-lastCPUTime );
+ }
+
+ last=cur;
+ lastCPUTime=CPUTime;
+ return cur;
}
-static inline unsigned long long checkT(int timeout, char * file, int line) {
- static __thread unsigned long long last=0;
- unsigned long long cur=rdtsc();
- int microCycles=(int)(cpuf*1000);
- int duration=(int)((cur-last)/microCycles);
- if ( last!=0 && duration > timeout )
- printf("%s:%d lte-ue delay %d (exceed %d)\n", file, line,
- duration, timeout);
- last=cur;
- return cur;
+static inline unsigned long long checkT(int timeout, char *file, int line) {
+ static __thread unsigned long long last=0;
+ unsigned long long cur=rdtsc();
+ int microCycles=(int)(cpuf*1000);
+ int duration=(int)((cur-last)/microCycles);
+
+ if ( last!=0 && duration > timeout )
+ printf("%s:%d lte-ue delay %d (exceed %d)\n", file, line,
+ duration, timeout);
+
+ last=cur;
+ return cur;
}
typedef struct m {
- uint64_t iterations;
- uint64_t sum;
- uint64_t maxArray[11];
+ uint64_t iterations;
+ uint64_t sum;
+ uint64_t maxArray[11];
} Meas;
-static inline void printMeas(char * txt, Meas *M, int period) {
- if (M->iterations%period == 0 ) {
- char txt2[512];
- sprintf(txt2,"%s avg=%" PRIu64 " iterations=%" PRIu64 " max=%"
- PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 "\n",
- txt,
- M->sum/M->iterations,
- M->iterations,
- M->maxArray[1],M->maxArray[2], M->maxArray[3],M->maxArray[4], M->maxArray[5],
- M->maxArray[6],M->maxArray[7], M->maxArray[8],M->maxArray[9],M->maxArray[10]);
+static inline void printMeas(char *txt, Meas *M, int period) {
+ if (M->iterations%period == 0 ) {
+ char txt2[512];
+ sprintf(txt2,"%s avg=%" PRIu64 " iterations=%" PRIu64 " max=%"
+ PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 "\n",
+ txt,
+ M->sum/M->iterations,
+ M->iterations,
+ M->maxArray[1],M->maxArray[2], M->maxArray[3],M->maxArray[4], M->maxArray[5],
+ M->maxArray[6],M->maxArray[7], M->maxArray[8],M->maxArray[9],M->maxArray[10]);
#if DISABLE_LOG_X
- printf("%s",txt2);
+ printf("%s",txt2);
#else
- LOG_W(PHY, "%s",txt2);
+ LOG_W(PHY, "%s",txt2);
#endif
- }
+ }
}
-static inline int cmpint(const void* a, const void* b) {
- uint64_t* aa=(uint64_t*)a;
- uint64_t* bb=(uint64_t*)b;
- return (int)(*aa-*bb);
+static inline int cmpint(const void *a, const void *b) {
+ uint64_t *aa=(uint64_t *)a;
+ uint64_t *bb=(uint64_t *)b;
+ return (int)(*aa-*bb);
}
-static inline void updateTimes(uint64_t start, Meas *M, int period, char * txt) {
- if (start!=0) {
- uint64_t end=rdtsc();
- long long diff=(end-start)/(cpuf*1000);
- M->maxArray[0]=diff;
- M->sum+=diff;
- M->iterations++;
- qsort(M->maxArray, 11, sizeof(uint64_t), cmpint);
- printMeas(txt,M,period);
- }
+static inline void updateTimes(uint64_t start, Meas *M, int period, char *txt) {
+ if (start!=0) {
+ uint64_t end=rdtsc();
+ long long diff=(end-start)/(cpuf*1000);
+ M->maxArray[0]=diff;
+ M->sum+=diff;
+ M->iterations++;
+ qsort(M->maxArray, 11, sizeof(uint64_t), cmpint);
+ printMeas(txt,M,period);
+ }
}
#define check(a) do { checkT(a,__FILE__,__LINE__); } while (0)
diff --git a/common/utils/minimal_stub.c b/common/utils/minimal_stub.c
new file mode 100644
index 0000000000..86454fe53f
--- /dev/null
+++ b/common/utils/minimal_stub.c
@@ -0,0 +1,4 @@
+int T_stdout;
+
+void exit_function(const char *file, const char *function, const int line, const char *s) {
+}
diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp
index 5b8d1a430e..3a1fff6e93 100644
--- a/common/utils/ocp_itti/intertask_interface.cpp
+++ b/common/utils/ocp_itti/intertask_interface.cpp
@@ -8,6 +8,7 @@
#include
+#include
typedef struct timer_elm_s {
timer_type_t type; ///< Timer type
@@ -280,22 +281,8 @@ extern "C" {
int itti_create_task(task_id_t task_id, void *(*start_routine)(void *), void *args_p) {
task_list_t *t=&tasks[task_id];
- AssertFatal ( pthread_create (&t->thread, NULL, start_routine, args_p) ==0,
- "Thread creation for task %d failed!\n", task_id);
- pthread_setname_np( t->thread, itti_get_task_name(task_id) );
+ threadCreate (&t->thread, start_routine, args_p, (char*)itti_get_task_name(task_id),-1,OAI_PRIORITY_RT);
LOG_I(TMR,"Created Posix thread %s\n", itti_get_task_name(task_id) );
-#if 1 // BMC test RT prio
- {
- int policy;
- struct sched_param sparam;
- memset(&sparam, 0, sizeof(sparam));
- sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-10;
- policy = SCHED_FIFO ;
- if (pthread_setschedparam(t->thread, policy, &sparam) != 0) {
- LOG_E(TMR,"task %s : Failed to set pthread priority\n", itti_get_task_name(task_id) );
- }
- }
-#endif
return 0;
}
diff --git a/common/utils/simple_executable.h b/common/utils/simple_executable.h
new file mode 100644
index 0000000000..98b75012df
--- /dev/null
+++ b/common/utils/simple_executable.h
@@ -0,0 +1,37 @@
+#ifndef __SIMPLE_EXE_H__
+#define __SIMPLE_EXE_H__
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "common_lib.h"
+
+#ifdef T
+ #undef T
+ #define T(...)
+#endif
+
+#endif
diff --git a/common/utils/system.c b/common/utils/system.c
index dcec681e2d..31c1035129 100644
--- a/common/utils/system.c
+++ b/common/utils/system.c
@@ -28,13 +28,23 @@
* separate process solves this problem.
*/
+#define _GNU_SOURCE
#include "system.h"
#include
#include
#include
#include
#include
-
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#define MAX_COMMAND 4096
static int command_pipe_read;
@@ -50,37 +60,37 @@ static int module_initialized = 0;
/* util functions */
/********************************************************************/
-static void lock_system(void)
-{
+static void lock_system(void) {
if (pthread_mutex_lock(&lock) != 0) {
printf("pthread_mutex_lock fails\n");
abort();
}
}
-static void unlock_system(void)
-{
+static void unlock_system(void) {
if (pthread_mutex_unlock(&lock) != 0) {
printf("pthread_mutex_unlock fails\n");
abort();
}
}
-static void write_pipe(int p, char *b, int size)
-{
+static void write_pipe(int p, char *b, int size) {
while (size) {
int ret = write(p, b, size);
+
if (ret <= 0) exit(0);
+
b += ret;
size -= ret;
}
}
-static void read_pipe(int p, char *b, int size)
-{
+static void read_pipe(int p, char *b, int size) {
while (size) {
int ret = read(p, b, size);
+
if (ret <= 0) exit(0);
+
b += ret;
size -= ret;
}
@@ -95,14 +105,13 @@ static void read_pipe(int p, char *b, int size)
* when the main process exits, because then a "read" on the pipe
* will return 0, in which case "read_pipe" exits.
*/
-static void background_system_process(void)
-{
+static void background_system_process(void) {
int len;
int ret;
char command[MAX_COMMAND+1];
while (1) {
- read_pipe(command_pipe_read, (char*)&len, sizeof(int));
+ read_pipe(command_pipe_read, (char *)&len, sizeof(int));
read_pipe(command_pipe_read, command, len);
ret = system(command);
write_pipe(result_pipe_write, (char *)&ret, sizeof(int));
@@ -114,8 +123,7 @@ static void background_system_process(void)
/* return -1 on error, 0 on success */
/********************************************************************/
-int background_system(char *command)
-{
+int background_system(char *command) {
int res;
int len;
@@ -125,18 +133,22 @@ int background_system(char *command)
}
len = strlen(command)+1;
+
if (len > MAX_COMMAND) {
printf("FATAL: command too long. Increase MAX_COMMAND (%d).\n", MAX_COMMAND);
printf("command was: '%s'\n", command);
abort();
}
+
/* only one command can run at a time, so let's lock/unlock */
lock_system();
- write_pipe(command_pipe_write, (char*)&len, sizeof(int));
+ write_pipe(command_pipe_write, (char *)&len, sizeof(int));
write_pipe(command_pipe_write, command, len);
- read_pipe(result_pipe_read, (char*)&res, sizeof(int));
+ read_pipe(result_pipe_read, (char *)&res, sizeof(int));
unlock_system();
+
if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) return -1;
+
return 0;
}
@@ -146,17 +158,16 @@ int background_system(char *command)
/* to be called very early by the main processing */
/********************************************************************/
-void start_background_system(void)
-{
+void start_background_system(void) {
int p[2];
pid_t son;
-
module_initialized = 1;
if (pipe(p) == -1) {
perror("pipe");
exit(1);
}
+
command_pipe_read = p[0];
command_pipe_write = p[1];
@@ -164,10 +175,11 @@ void start_background_system(void)
perror("pipe");
exit(1);
}
+
result_pipe_read = p[0];
result_pipe_write = p[1];
-
son = fork();
+
if (son == -1) {
perror("fork");
exit(1);
@@ -181,6 +193,56 @@ void start_background_system(void)
close(result_pipe_read);
close(command_pipe_write);
-
background_system_process();
}
+
+
+void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name, int affinity, int priority){
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+ struct sched_param sparam={0};
+ sparam.sched_priority = priority;
+ pthread_attr_setschedparam(&attr, &sparam);
+
+ pthread_create(t, &attr, func, param);
+
+ pthread_setname_np(*t, name);
+ if (affinity != -1 ) {
+ cpu_set_t cpuset;
+ CPU_ZERO(&cpuset);
+ CPU_SET(affinity, &cpuset);
+ AssertFatal( pthread_setaffinity_np(*t, sizeof(cpu_set_t), &cpuset) == 0, "Error setting processor affinity");
+ }
+
+ pthread_attr_destroy(&attr);
+}
+
+// Block CPU C-states deep sleep
+void configure_linux(void) {
+ int ret;
+ static int latency_target_fd=-1;
+ uint32_t latency_target_value=10; // in microseconds
+ if (latency_target_fd == -1) {
+ if ( (latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR)) != -1 ) {
+ ret = write(latency_target_fd, &latency_target_value, sizeof(latency_target_value));
+ if (ret == 0) {
+ printf("# error setting cpu_dma_latency to %d!: %s\n", latency_target_value, strerror(errno));
+ close(latency_target_fd);
+ latency_target_fd=-1;
+ return;
+ }
+ }
+ }
+ if (latency_target_fd != -1)
+ LOG_I(HW,"# /dev/cpu_dma_latency set to %dus\n", latency_target_value);
+ else
+ LOG_E(HW,"Can't set /dev/cpu_dma_latency to %dus\n", latency_target_value);
+
+ // Set CPU frequency to it's maximum
+ if ( 0 != system("for d in /sys/devices/system/cpu/cpu[0-9]*; do cat $d/cpufreq/cpuinfo_max_freq > $d/cpufreq/scaling_min_freq; done"))
+ LOG_W(HW,"Can't set cpu frequency\n");
+
+}
diff --git a/common/utils/system.h b/common/utils/system.h
index 658c17adc1..a89a6c5b17 100644
--- a/common/utils/system.h
+++ b/common/utils/system.h
@@ -21,6 +21,12 @@
#ifndef _SYSTEM_H_OAI_
#define _SYSTEM_H_OAI_
+#include
+#include
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/****************************************************
* send a command to the background process
@@ -36,4 +42,23 @@ int background_system(char *command);
void start_background_system(void);
+void set_latency_target(void);
+void configure_linux(void);
+
+void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name, int affinity, int priority);
+#define OAI_PRIORITY_RT_LOW sched_get_priority_min(SCHED_FIFO)
+#define OAI_PRIORITY_RT sched_get_priority_max(SCHED_FIFO)-10
+#define OAI_PRIORITY_RT_MAX sched_get_priority_max(SCHED_FIFO)
+
+void thread_top_init(char *thread_name,
+ int affinity,
+ uint64_t runtime,
+ uint64_t deadline,
+ uint64_t period);
+
+#ifdef __cplusplus
+}
+#endif
+
+
#endif /* _SYSTEM_H_OAI_ */
diff --git a/common/utils/threadPool/Makefile b/common/utils/threadPool/Makefile
new file mode 100644
index 0000000000..af0b44996c
--- /dev/null
+++ b/common/utils/threadPool/Makefile
@@ -0,0 +1,8 @@
+all: measurement_display thread-pool-test
+
+measurement_display: measurement_display.c thread-pool.h
+ gcc measurement_display.c -I ${OPENAIR_DIR}/ -I ${OPENAIR_DIR}/common/utils/ -I. ${OPENAIR_DIR}/common/utils/backtrace.c -lpthread -D TEST_THREAD_POOL -I../LOG -I../../utils/T -o measurement_display
+
+thread-pool-test: thread-pool.c thread-pool.h
+ gcc -g thread-pool.c -I ${OPENAIR_DIR}/ -I ${OPENAIR_DIR}/common/utils/ -I. ${OPENAIR_DIR}/common/utils/backtrace.c -I ${OPENAIR_DIR}/openair2/COMMON ${OPENAIR_DIR}/common/utils/LOG/log.c ${OPENAIR_DIR}/common/config/config_userapi.c ${OPENAIR_DIR}/common/config/config_load_configmodule.c ${OPENAIR_DIR}/common/config/config_cmdline.c -lpthread -ldl -D TEST_THREAD_POOL -I../LOG -I../../utils/T -o thread-pool-test
+
diff --git a/common/utils/threadPool/measurement_display.c b/common/utils/threadPool/measurement_display.c
new file mode 100644
index 0000000000..8f6e2c239a
--- /dev/null
+++ b/common/utils/threadPool/measurement_display.c
@@ -0,0 +1,47 @@
+/*
+ Author: Laurent THOMAS, Open Cells
+ copyleft: OpenAirInterface Software Alliance and it's licence
+*/
+#include
+
+#include "thread-pool.h"
+
+#define SEP "\t"
+
+uint64_t cpuCyclesMicroSec;
+
+int main(int argc, char *argv[]) {
+ if(argc != 2) {
+ printf("Need one parameter: the trace Linux pipe (fifo)");
+ exit(1);
+ }
+
+ mkfifo(argv[1],0666);
+ int fd=open(argv[1], O_RDONLY);
+
+ if ( fd == -1 ) {
+ perror("open read mode trace file:");
+ exit(1);
+ }
+
+ uint64_t deb=rdtsc();
+ usleep(100000);
+ cpuCyclesMicroSec=(rdtsc()-deb)/100000;
+ printf("Cycles per µs: %lu\n",cpuCyclesMicroSec);
+ printf("Key" SEP "delay to process" SEP "processing time" SEP "delay to be read answer\n");
+ notifiedFIFO_elt_t doneRequest;
+
+ while ( 1 ) {
+ if ( read(fd,&doneRequest, sizeof(doneRequest)) == sizeof(doneRequest)) {
+ printf("%lu" SEP "%lu" SEP "%lu" SEP "%lu" "\n",
+ doneRequest.key,
+ (doneRequest.startProcessingTime-doneRequest.creationTime)/cpuCyclesMicroSec,
+ (doneRequest.endProcessingTime-doneRequest.startProcessingTime)/cpuCyclesMicroSec,
+ (doneRequest.returnTime-doneRequest.endProcessingTime)/cpuCyclesMicroSec
+ );
+ } else {
+ printf("no measurements\n");
+ sleep(1);
+ }
+ }
+}
diff --git a/common/utils/threadPool/thread-pool.c b/common/utils/threadPool/thread-pool.c
new file mode 100644
index 0000000000..b45a8fa722
--- /dev/null
+++ b/common/utils/threadPool/thread-pool.c
@@ -0,0 +1,216 @@
+/*
+ Author: Laurent THOMAS, Open Cells
+ copyleft: OpenAirInterface Software Alliance and it's licence
+*/
+
+#define _GNU_SOURCE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+void displayList(notifiedFIFO_t *nf) {
+ int n=0;
+ notifiedFIFO_elt_t *ptr=nf->outF;
+
+ while(ptr) {
+ printf("element: %d, key: %lu\n",++n,ptr->key);
+ ptr=ptr->next;
+ }
+
+ printf("End of list: %d elements\n",n);
+}
+
+static inline notifiedFIFO_elt_t *pullNotifiedFifoRemember( notifiedFIFO_t *nf, struct one_thread *thr) {
+ mutexlock(nf->lockF);
+
+ while(!nf->outF)
+ condwait(nf->notifF, nf->lockF);
+
+ notifiedFIFO_elt_t *ret=nf->outF;
+ nf->outF=nf->outF->next;
+
+ if (nf->outF==NULL)
+ nf->inF=NULL;
+
+ // For abort feature
+ thr->runningOnKey=ret->key;
+ thr->abortFlag=false;
+ mutexunlock(nf->lockF);
+ return ret;
+}
+
+void *one_thread(void *arg) {
+ struct one_thread *myThread=(struct one_thread *) arg;
+ struct thread_pool *tp=myThread->pool;
+
+ // Infinite loop to process requests
+ do {
+ notifiedFIFO_elt_t *elt=pullNotifiedFifoRemember(&tp->incomingFifo, myThread);
+
+ if (tp->measurePerf) elt->startProcessingTime=rdtsc();
+
+ elt->processingFunc(NotifiedFifoData(elt));
+
+ if (tp->measurePerf) elt->endProcessingTime=rdtsc();
+
+ if (elt->reponseFifo) {
+ // Check if the job is still alive, else it has been aborted
+ mutexlock(tp->incomingFifo.lockF);
+
+ if (myThread->abortFlag)
+ delNotifiedFIFO_elt(elt);
+ else
+ pushNotifiedFIFO(elt->reponseFifo, elt);
+
+ mutexunlock(tp->incomingFifo.lockF);
+ }
+ } while (true);
+}
+
+void initTpool(char *params,tpool_t *pool, bool performanceMeas) {
+ memset(pool,0,sizeof(*pool));
+ char *measr=getenv("threadPoolMeasurements");
+ pool->measurePerf=performanceMeas;
+ // force measurement if the output is defined
+ pool->measurePerf=measr!=NULL;
+
+ if (measr) {
+ mkfifo(measr,0666);
+ AssertFatal(-1 != (pool->dummyTraceFd=
+ open(measr, O_RDONLY| O_NONBLOCK)),"");
+ AssertFatal(-1 != (pool->traceFd=
+ open(measr, O_WRONLY|O_APPEND|O_NOATIME|O_NONBLOCK)),"");
+ } else
+ pool->traceFd=-1;
+
+ pool->activated=true;
+ initNotifiedFIFO(&pool->incomingFifo);
+ char *saveptr, * curptr;
+ pool->nbThreads=0;
+ pool->restrictRNTI=false;
+ curptr=strtok_r(params,",",&saveptr);
+
+ while ( curptr!=NULL ) {
+ int c=toupper(curptr[0]);
+
+ switch (c) {
+ case 'U':
+ pool->restrictRNTI=true;
+ break;
+
+ case 'N':
+ pool->activated=false;
+ break;
+
+ default:
+ pool->allthreads=(struct one_thread *)malloc(sizeof(struct one_thread));
+ pool->allthreads->next=pool->allthreads;
+ printf("create a thread for core %d\n", atoi(curptr));
+ pool->allthreads->coreID=atoi(curptr);
+ pool->allthreads->id=pool->nbThreads;
+ pool->allthreads->pool=pool;
+ //Configure the thread scheduler policy for Linux
+ // set the thread name for debugging
+ sprintf(pool->allthreads->name,"Tpool_%d",pool->allthreads->coreID);
+ threadCreate(&pool->allthreads->threadID, one_thread, (void *)pool->allthreads,
+ pool->allthreads->name, pool->allthreads->coreID, OAI_PRIORITY_RT);
+ pool->nbThreads++;
+ }
+
+ curptr=strtok_r(NULL,",",&saveptr);
+ }
+
+ if (pool->activated && pool->nbThreads==0) {
+ printf("No servers created in the thread pool, exit\n");
+ exit(1);
+ }
+}
+
+#ifdef TEST_THREAD_POOL
+
+void exit_function(const char *file, const char *function, const int line, const char *s) {
+}
+
+struct testData {
+ int id;
+ char txt[30];
+};
+
+void processing(void *arg) {
+ struct testData *in=(struct testData *)arg;
+ printf("doing: %d, %s, in thr %ld\n",in->id, in->txt,pthread_self() );
+ sprintf(in->txt,"Done by %ld, job %d", pthread_self(), in->id);
+ usleep(rand()%100);
+ printf("done: %d, %s, in thr %ld\n",in->id, in->txt,pthread_self() );
+}
+
+int main() {
+ notifiedFIFO_t myFifo;
+ initNotifiedFIFO(&myFifo);
+ pushNotifiedFIFO(&myFifo,newNotifiedFIFO_elt(sizeof(struct testData), 1234,NULL,NULL));
+
+ for(int i=10; i>1; i--) {
+ pushNotifiedFIFO(&myFifo,newNotifiedFIFO_elt(sizeof(struct testData), 1000+i,NULL,NULL));
+ }
+
+ displayList(&myFifo);
+ notifiedFIFO_elt_t *tmp=pullNotifiedFIFO(&myFifo);
+ printf("pulled: %lu\n", tmp->key);
+ displayList(&myFifo);
+ tmp=pullNotifiedFIFO(&myFifo);
+ printf("pulled: %lu\n", tmp->key);
+ displayList(&myFifo);
+ abortNotifiedFIFO(&myFifo,1005);
+ printf("aborted 1005\n");
+ displayList(&myFifo);
+ pushNotifiedFIFO(&myFifo,newNotifiedFIFO_elt(sizeof(struct testData), 12345678, NULL, NULL));
+ displayList(&myFifo);
+ abortNotifiedFIFO(&myFifo,12345678);
+ printf("aborted 12345678\n");
+ displayList(&myFifo);
+
+ do {
+ tmp=pollNotifiedFIFO(&myFifo);
+
+ if (tmp) {
+ printf("pulled: %lu\n", tmp->key);
+ displayList(&myFifo);
+ } else
+ printf("Empty list \n");
+ } while(tmp);
+
+ tpool_t pool;
+ char params[]="1,2,3,u";
+ initTpool(params,&pool, true);
+ notifiedFIFO_t worker_back;
+ initNotifiedFIFO(&worker_back);
+
+ for (int i=0; i <1000 ; i++) {
+ notifiedFIFO_elt_t *work=newNotifiedFIFO_elt(sizeof(struct testData), i, &worker_back, processing);
+ struct testData *x=(struct testData *)NotifiedFifoData(work);
+ x->id=i;
+ pushTpool(&pool, work);
+ }
+
+ do {
+ tmp=pullTpool(&worker_back,&pool);
+
+ if (tmp) {
+ struct testData *dd=NotifiedFifoData(tmp);
+ printf("Result: %s\n",dd->txt);
+ delNotifiedFIFO_elt(tmp);
+ } else
+ printf("Empty list \n");
+
+ abortTpool(&pool,510);
+ } while(tmp);
+
+ return 0;
+}
+#endif
diff --git a/common/utils/threadPool/thread-pool.h b/common/utils/threadPool/thread-pool.h
new file mode 100644
index 0000000000..d6dc332c5a
--- /dev/null
+++ b/common/utils/threadPool/thread-pool.h
@@ -0,0 +1,257 @@
+/*
+ Author: Laurent THOMAS, Open Cells
+ copyleft: OpenAirInterface Software Alliance and it's licence
+*/
+
+#ifndef THREAD_POOL_H
+#define THREAD_POOL_H
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef DEBUG
+ #define THREADINIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+#else
+ #define THREADINIT PTHREAD_MUTEX_INITIALIZER
+#endif
+#define mutexinit(mutex) AssertFatal(pthread_mutex_init(&mutex,NULL)==0,"");
+#define condinit(signal) AssertFatal(pthread_cond_init(&signal,NULL)==0,"");
+#define mutexlock(mutex) AssertFatal(pthread_mutex_lock(&mutex)==0,"");
+#define mutextrylock(mutex) pthread_mutex_trylock(&mutex)
+#define mutexunlock(mutex) AssertFatal(pthread_mutex_unlock(&mutex)==0,"");
+#define condwait(condition, mutex) AssertFatal(pthread_cond_wait(&condition, &mutex)==0,"");
+#define condbroadcast(signal) AssertFatal(pthread_cond_broadcast(&signal)==0,"");
+#define condsignal(signal) AssertFatal(pthread_cond_broadcast(&signal)==0,"");
+
+typedef struct notifiedFIFO_elt_s {
+ struct notifiedFIFO_elt_s *next;
+ uint64_t key; //To filter out elements
+ struct notifiedFIFO_s *reponseFifo;
+ void (*processingFunc)(void *);
+ bool malloced;
+ uint64_t creationTime;
+ uint64_t startProcessingTime;
+ uint64_t endProcessingTime;
+ uint64_t returnTime;
+ void *msgData;
+} notifiedFIFO_elt_t;
+
+typedef struct notifiedFIFO_s {
+ notifiedFIFO_elt_t *outF;
+ notifiedFIFO_elt_t *inF;
+ pthread_mutex_t lockF;
+ pthread_cond_t notifF;
+} notifiedFIFO_t;
+
+// You can use this allocator or use any piece of memory
+static inline notifiedFIFO_elt_t *newNotifiedFIFO_elt(int size,
+ uint64_t key,
+ notifiedFIFO_t *reponseFifo,
+ void (*processingFunc)(void *)) {
+ notifiedFIFO_elt_t *ret;
+ AssertFatal( NULL != (ret=(notifiedFIFO_elt_t *) malloc(sizeof(notifiedFIFO_elt_t)+size+32)), "");
+ ret->next=NULL;
+ ret->key=key;
+ ret->reponseFifo=reponseFifo;
+ ret->processingFunc=processingFunc;
+ // We set user data piece aligend 32 bytes to be able to process it with SIMD
+ ret->msgData=(void *)ret+(sizeof(notifiedFIFO_elt_t)/32+1)*32;
+ ret->malloced=true;
+ return ret;
+}
+
+static inline void *NotifiedFifoData(notifiedFIFO_elt_t *elt) {
+ return elt->msgData;
+}
+
+static inline void delNotifiedFIFO_elt(notifiedFIFO_elt_t *elt) {
+ if (elt->malloced) {
+ elt->malloced=false;
+ free(elt);
+ } else
+ printf("delNotifiedFIFO on something not allocated by newNotifiedFIFO\n");
+
+ //LOG_W(UTIL,"delNotifiedFIFO on something not allocated by newNotifiedFIFO\n");
+}
+
+static inline void initNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf) {
+ nf->inF=NULL;
+ nf->outF=NULL;
+}
+static inline void initNotifiedFIFO(notifiedFIFO_t *nf) {
+ mutexinit(nf->lockF);
+ condinit (nf->notifF);
+ initNotifiedFIFO_nothreadSafe(nf);
+ // No delete function: the creator has only to free the memory
+}
+
+static inline void pushNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) {
+ msg->next=NULL;
+
+ if (nf->outF == NULL)
+ nf->outF = msg;
+
+ if (nf->inF != NULL)
+ nf->inF->next = msg;
+
+ nf->inF = msg;
+}
+
+static inline void pushNotifiedFIFO(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) {
+ mutexlock(nf->lockF);
+ pushNotifiedFIFO_nothreadSafe(nf,msg);
+ condbroadcast(nf->notifF);
+ mutexunlock(nf->lockF);
+}
+
+static inline notifiedFIFO_elt_t *pullNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf) {
+ if (nf->outF == NULL)
+ return NULL;
+
+ notifiedFIFO_elt_t *ret=nf->outF;
+
+ if (nf->outF==nf->outF->next)
+ LOG_E(TMR,"Circular list in thread pool: push several times the same buffer is forbidden\n");
+
+ nf->outF=nf->outF->next;
+
+ if (nf->outF==NULL)
+ nf->inF=NULL;
+
+ return ret;
+}
+
+static inline notifiedFIFO_elt_t *pullNotifiedFIFO(notifiedFIFO_t *nf) {
+ mutexlock(nf->lockF);
+ notifiedFIFO_elt_t *ret;
+
+ while((ret=pullNotifiedFIFO_nothreadSafe(nf)) == NULL)
+ condwait(nf->notifF, nf->lockF);
+
+ mutexunlock(nf->lockF);
+ return ret;
+}
+
+static inline notifiedFIFO_elt_t *pollNotifiedFIFO(notifiedFIFO_t *nf) {
+ int tmp=mutextrylock(nf->lockF);
+
+ if (tmp != 0 )
+ return NULL;
+
+ notifiedFIFO_elt_t *ret=pullNotifiedFIFO_nothreadSafe(nf);
+ mutexunlock(nf->lockF);
+ return ret;
+}
+
+// This function aborts all messages matching the key
+// If the queue is used in thread pools, it doesn't cancels already running processing
+// because the message has already been picked
+static inline void abortNotifiedFIFO(notifiedFIFO_t *nf, uint64_t key) {
+ mutexlock(nf->lockF);
+ notifiedFIFO_elt_t **start=&nf->outF;
+
+ while(*start!=NULL) {
+ if ( (*start)->key == key ) {
+ notifiedFIFO_elt_t *request=*start;
+ *start=(*start)->next;
+ delNotifiedFIFO_elt(request);
+ }
+
+ if (*start != NULL)
+ start=&(*start)->next;
+ }
+
+ mutexunlock(nf->lockF);
+}
+
+struct one_thread {
+ pthread_t threadID;
+ int id;
+ int coreID;
+ char name[256];
+ uint64_t runningOnKey;
+ bool abortFlag;
+ struct thread_pool *pool;
+ struct one_thread *next;
+};
+
+typedef struct thread_pool {
+ int activated;
+ bool measurePerf;
+ int traceFd;
+ int dummyTraceFd;
+ uint64_t cpuCyclesMicroSec;
+ uint64_t startProcessingUE;
+ int nbThreads;
+ bool restrictRNTI;
+ notifiedFIFO_t incomingFifo;
+ struct one_thread *allthreads;
+} tpool_t;
+
+static inline void pushTpool(tpool_t *t, notifiedFIFO_elt_t *msg) {
+ if (t->measurePerf) msg->creationTime=rdtsc();
+
+ pushNotifiedFIFO(&t->incomingFifo, msg);
+}
+
+static inline notifiedFIFO_elt_t *pullTpool(notifiedFIFO_t *responseFifo, tpool_t *t) {
+ notifiedFIFO_elt_t *msg= pullNotifiedFIFO(responseFifo);
+
+ if (t->measurePerf)
+ msg->returnTime=rdtsc();
+
+ if (t->traceFd >= 0)
+ if(write(t->traceFd, msg, sizeof(*msg)));
+
+ return msg;
+}
+
+static inline notifiedFIFO_elt_t *tryPullTpool(notifiedFIFO_t *responseFifo, tpool_t *t) {
+ notifiedFIFO_elt_t *msg= pollNotifiedFIFO(responseFifo);
+
+ if (msg == NULL)
+ return NULL;
+
+ if (t->measurePerf)
+ msg->returnTime=rdtsc();
+
+ if (t->traceFd)
+ if(write(t->traceFd, msg, sizeof(*msg)));
+
+ return msg;
+}
+
+static inline void abortTpool(tpool_t *t, uint64_t key) {
+ notifiedFIFO_t *nf=&t->incomingFifo;
+ mutexlock(nf->lockF);
+ notifiedFIFO_elt_t **start=&nf->outF;
+
+ while(*start!=NULL) {
+ if ( (*start)->key == key ) {
+ notifiedFIFO_elt_t *request=*start;
+ *start=(*start)->next;
+ delNotifiedFIFO_elt(request);
+ }
+
+ if (*start != NULL)
+ start=&(*start)->next;
+ }
+
+ struct one_thread *ptr=t->allthreads;
+
+ while(ptr!=NULL) {
+ if (ptr->runningOnKey==key)
+ ptr->abortFlag=true;
+
+ ptr=ptr->next;
+ }
+
+ mutexunlock(nf->lockF);
+}
+void initTpool(char *params,tpool_t *pool, bool performanceMeas);
+
+#endif
diff --git a/common/utils/threadPool/thread-pool.md b/common/utils/threadPool/thread-pool.md
new file mode 100644
index 0000000000..2b6336fb60
--- /dev/null
+++ b/common/utils/threadPool/thread-pool.md
@@ -0,0 +1,71 @@
+# Thread pool
+
+The thread pool is a working server, made of a set of worker threads that can be mapped on CPU cores.
+
+Each worker loop on pick from the same input queue jobs to do.
+When a job is done, the worker sends a return if a return is defined.
+
+A selective abort allows to cancel parallel jobs (usage: a client pushed jobs, but from a response of one job, the other linked jobs becomes useless).
+
+All the thread pool functions are thread safe, nevertheless the working functions are implemented by the thread pool client, so the client has to tackle the parallel execution of his functions called "processingFunc" hereafter.
+
+## license
+Author: Laurent Thomas, Open cells project
+The owner share this piece code to Openairsoftware alliance as per OSA license terms
+
+# jobs
+
+A job is a message (notifiedFIFO_elt_t):
+next: internal FIFO chain, do not set it
+key: a long int that the client can use to identify a message or a group of messages
+responseFifo: if the client defines a response FIFO, the message will be posted back after processing
+processingFunc: any funtion (type void processingFunc(void *)) that the worker will launch
+msgData: the data passed to processingFunc. It can be added automatically, or you can set it to a buffer you are managing
+malloced: a boolean that enable internal free in these cases: no return Fifo or Abort feature
+
+The job messages can be created with newNotifiedFIFO_elt() and delNotifiedFIFO_elt() or managed by the client.
+
+# Queues of jobs
+
+Queues are type of: notifiedFIFO_t that must be initialized by init_notifiedFIFO()
+No delete function is required, the creator has only to free the data of type notifiedFIFO_t
+
+push_notifiedFIFO() add a job in the queue
+pull_notifiedFIFO() is blocking, poll_notifiedFIFO() is non blocking
+
+abort_notifiedFIFO() allows the customer to delete all waiting jobs that match with the key (see key in jobs definition)
+
+# Thread pools
+
+## initialization
+The clients can create one or more thread pools with init_tpool()
+the params string structure: describes a list of cores, separated by "," that run a worker thread
+
+If the core exists on the CPU, the thread pool initialization sets the affinity between this thread and the related code (use negative values is allowed, so the thread will never be mapped on a specific core).
+
+The threads are all Linux real time scheduler, their name is set automatically is "Tpool_"
+
+## adding jobs
+The client create their jobs messages as a notifiedFIFO_elt_t, then they push it with pushTpool() (that internally calls push_notifiedFIFO())
+
+If they need a return, they have to create response queues with init_notifiedFIFO() and set this FIFO pointer in the notifiedFIFO_elt_t before pushing the job.
+
+## abort
+
+A abort service abortTpool() allows to abort all jobs that match a key (see jobs "key"). When the abort returns, it garanties no job (matching the key) response will be posted on response queues.
+
+Nevertheless, jobs already performed before the return of abortTpool() are pushed in the response Fifo queue.
+
+## Performance measurements
+
+A performance measurement is integrated: the pool will automacillay fill timestamps:
+
+* creationTime: time the request is push to the pool;
+* startProcessingTime: time a worker start to run on the job
+* endProcessingTime: time the worker finished the job
+* returnTime: time the client reads the result
+
+if you set the environement variable: thread-pool-measurements to a valid file name
+These measurements will be wrote to this Linux pipe.
+
+A tool to read the linux fifo and display it in ascii is provided: see the local directory Makefile for this tool and to compile the thread pool unitary tests.
diff --git a/common/utils/utils.h b/common/utils/utils.h
index cfe3df34b9..11db07056e 100644
--- a/common/utils/utils.h
+++ b/common/utils/utils.h
@@ -3,6 +3,9 @@
#include
#include
+#ifdef __cplusplus
+extern "C" {
+#endif
void *calloc_or_fail(size_t size);
void *malloc_or_fail(size_t size);
@@ -14,4 +17,17 @@ int hex_string_to_hex_value (uint8_t *hex_value, const char *hex_string, int siz
char *itoa(int i);
+#define findInList(keY, result, list, element_type) {\
+ int i;\
+ for (i=0; i
+
+#include "time_utils.h"
+
+#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "assertions.h"
+#include
+#include
+
+#include "PHY/types.h"
+
+#include "PHY/INIT/phy_init.h"
+
+#include "PHY/defs_gNB.h"
+#include "SCHED/sched_eNB.h"
+#include "SCHED_NR/sched_nr.h"
+#include "SCHED_NR/fapi_nr_l1.h"
+#include "PHY/LTE_TRANSPORT/transport_proto.h"
+
+#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
+//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "../../ARCH/COMMON/common_lib.h"
+
+//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "PHY/LTE_TRANSPORT/if4_tools.h"
+#include "PHY/LTE_TRANSPORT/if5_tools.h"
+
+#include "PHY/phy_extern.h"
+
+
+#include "LAYER2/MAC/mac.h"
+#include "LAYER2/MAC/mac_extern.h"
+#include "LAYER2/MAC/mac_proto.h"
+#include "RRC/LTE/rrc_extern.h"
+#include "PHY_INTERFACE/phy_interface.h"
+#include "common/utils/LOG/log_extern.h"
+#include "UTIL/OTG/otg_tx.h"
+#include "UTIL/OTG/otg_externs.h"
+#include "UTIL/MATH/oml.h"
+#include "common/utils/LOG/vcd_signal_dumper.h"
+#include "UTIL/OPT/opt.h"
+#include "enb_config.h"
+
+
+#ifndef OPENAIR2
+ #include "UTIL/OTG/otg_extern.h"
+#endif
+
+#if defined(ENABLE_ITTI)
+ #if defined(ENABLE_USE_MME)
+ #include "s1ap_eNB.h"
+ #ifdef PDCP_USE_NETLINK
+ #include "SIMULATION/ETH_TRANSPORT/proto.h"
+ #endif
+ #endif
+#endif
+
+#include "T.h"
+
+//#define DEBUG_THREADS 1
+
+//#define USRP_DEBUG 1
+// Fix per CC openair rf/if device update
+// extern openair0_device openair0;
+
+
+#if defined(ENABLE_ITTI)
+ extern volatile int start_gNB;
+ extern volatile int start_UE;
+#endif
+extern volatile int oai_exit;
+
+extern openair0_config_t openair0_cfg[MAX_CARDS];
+
+extern int transmission_mode;
+
+uint16_t sl_ahead=4;
+uint16_t sf_ahead=4;
+//pthread_t main_gNB_thread;
+
+time_stats_t softmodem_stats_mt; // main thread
+time_stats_t softmodem_stats_hw; // hw acquisition
+time_stats_t softmodem_stats_rxtx_sf; // total tx time
+time_stats_t nfapi_meas; // total tx time
+time_stats_t softmodem_stats_rx_sf; // total rx time
+
+/* mutex, cond and variable to serialize phy proc TX calls
+ * (this mechanism may be relaxed in the future for better
+ * performances)
+ */
+static struct {
+ pthread_mutex_t mutex_phy_proc_tx;
+ pthread_cond_t cond_phy_proc_tx;
+ volatile uint8_t phy_proc_CC_id;
+} sync_phy_proc;
+
+extern double cpuf;
+
+void init_gNB(int,int);
+void stop_gNB(int nb_inst);
+
+int wakeup_txfh(gNB_L1_rxtx_proc_t *proc,PHY_VARS_gNB *gNB);
+int wakeup_tx(PHY_VARS_gNB *gNB);
+extern PARALLEL_CONF_t get_thread_parallel_conf(void);
+extern WORKER_CONF_t get_thread_worker_conf(void);
+
+
+void wakeup_prach_gNB(PHY_VARS_gNB *gNB,RU_t *ru,int frame,int subframe);
+
+extern uint8_t nfapi_mode;
+extern void oai_subframe_ind(uint16_t sfn, uint16_t sf);
+extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset);
+
+//#define TICK_TO_US(ts) (ts.diff)
+#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials)
+
+
+static inline int rxtx(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc, char *thread_name) {
+ start_meas(&softmodem_stats_rxtx_sf);
+
+ // *******************************************************************
+
+ if (nfapi_mode == 1) {
+ // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick
+ uint16_t frame = proc->frame_rx;
+ uint16_t slot = proc->slot_rx;
+ //add_subframe(&frame, &subframe, 4);
+ //oai_subframe_ind(proc->frame_tx, proc->subframe_tx);
+ //LOG_D(PHY, "oai_subframe_ind(frame:%u, subframe:%d) - NOT CALLED ********\n", frame, subframe);
+ start_meas(&nfapi_meas);
+ oai_subframe_ind(frame, slot);
+ stop_meas(&nfapi_meas);
+
+ if (gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus||
+ gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs ||
+ gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs ||
+ gNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles ||
+ gNB->UL_INFO.cqi_ind.number_of_cqis
+ ) {
+ LOG_D(PHY, "UL_info[rx_ind:%05d:%d harqs:%05d:%d crcs:%05d:%d preambles:%05d:%d cqis:%d] RX:%04d%d TX:%04d%d \n",
+ NFAPI_SFNSF2DEC(gNB->UL_INFO.rx_ind.sfn_sf), gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus,
+ NFAPI_SFNSF2DEC(gNB->UL_INFO.harq_ind.sfn_sf), gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs,
+ NFAPI_SFNSF2DEC(gNB->UL_INFO.crc_ind.sfn_sf), gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs,
+ NFAPI_SFNSF2DEC(gNB->UL_INFO.rach_ind.sfn_sf), gNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles,
+ gNB->UL_INFO.cqi_ind.number_of_cqis,
+ proc->frame_rx, proc->slot_rx,
+ proc->frame_tx, proc->slot_tx);
+ }
+ }
+
+ /// NR disabling
+ // ****************************************
+ // Common RX procedures subframe n
+ T(T_GNB_PHY_DL_TICK, T_INT(gNB->Mod_id), T_INT(proc->frame_tx), T_INT(proc->slot_tx));
+ /*
+ // if this is IF5 or 3GPP_gNB
+ if (gNB && gNB->RU_list && gNB->RU_list[0] && gNB->RU_list[0]->function < NGFI_RAU_IF4p5) {
+ wakeup_prach_gNB(gNB,NULL,proc->frame_rx,proc->slot_rx);
+ }
+
+ // UE-specific RX processing for subframe n
+ if (nfapi_mode == 0 || nfapi_mode == 1) {
+ phy_procedures_gNB_uespec_RX(gNB, proc, no_relay );
+ }
+ */
+ pthread_mutex_lock(&gNB->UL_INFO_mutex);
+ gNB->UL_INFO.frame = proc->frame_rx;
+ gNB->UL_INFO.slot = proc->slot_rx;
+ gNB->UL_INFO.module_id = gNB->Mod_id;
+ gNB->UL_INFO.CC_id = gNB->CC_id;
+ gNB->if_inst->NR_UL_indication(&gNB->UL_INFO);
+ pthread_mutex_unlock(&gNB->UL_INFO_mutex);
+
+ /// end
+ // *****************************************
+ // TX processing for subframe n+sl_ahead
+ // run PHY TX procedures the one after the other for all CCs to avoid race conditions
+ // (may be relaxed in the future for performance reasons)
+ // *****************************************
+ //if (wait_CCs(proc)<0) return(-1);
+
+ if (oai_exit) return(-1);
+
+ if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) {
+ phy_procedures_gNB_TX(gNB, proc, 1);
+ }
+
+ stop_meas( &softmodem_stats_rxtx_sf );
+ LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, proc->frame_rx, proc->slot_rx, proc->frame_tx, proc->slot_tx);
+#if 0
+ LOG_D(PHY, "rxtx:%lld nfapi:%lld phy:%lld tx:%lld rx:%lld prach:%lld ofdm:%lld ",
+ softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now,
+ TICK_TO_US(gNB->phy_proc),
+ TICK_TO_US(gNB->phy_proc_tx),
+ TICK_TO_US(gNB->phy_proc_rx),
+ TICK_TO_US(gNB->rx_prach),
+ TICK_TO_US(gNB->ofdm_mod_stats),
+ softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now);
+ LOG_D(PHY,
+ "dlsch[enc:%lld mod:%lld scr:%lld rm:%lld t:%lld i:%lld] rx_dft:%lld ",
+ TICK_TO_US(gNB->dlsch_encoding_stats),
+ TICK_TO_US(gNB->dlsch_modulation_stats),
+ TICK_TO_US(gNB->dlsch_scrambling_stats),
+ TICK_TO_US(gNB->dlsch_rate_matching_stats),
+ TICK_TO_US(gNB->dlsch_turbo_encoding_stats),
+ TICK_TO_US(gNB->dlsch_interleaving_stats),
+ TICK_TO_US(gNB->rx_dft_stats));
+ LOG_D(PHY," ulsch[ch:%lld freq:%lld dec:%lld demod:%lld ru:%lld ",
+ TICK_TO_US(gNB->ulsch_channel_estimation_stats),
+ TICK_TO_US(gNB->ulsch_freq_offset_estimation_stats),
+ TICK_TO_US(gNB->ulsch_decoding_stats),
+ TICK_TO_US(gNB->ulsch_demodulation_stats),
+ TICK_TO_US(gNB->ulsch_rate_unmatching_stats));
+ LOG_D(PHY, "td:%lld dei:%lld dem:%lld llr:%lld tci:%lld ",
+ TICK_TO_US(gNB->ulsch_turbo_decoding_stats),
+ TICK_TO_US(gNB->ulsch_deinterleaving_stats),
+ TICK_TO_US(gNB->ulsch_demultiplexing_stats),
+ TICK_TO_US(gNB->ulsch_llr_stats),
+ TICK_TO_US(gNB->ulsch_tc_init_stats));
+ LOG_D(PHY, "tca:%lld tcb:%lld tcg:%lld tce:%lld l1:%lld l2:%lld]\n\n",
+ TICK_TO_US(gNB->ulsch_tc_alpha_stats),
+ TICK_TO_US(gNB->ulsch_tc_beta_stats),
+ TICK_TO_US(gNB->ulsch_tc_gamma_stats),
+ TICK_TO_US(gNB->ulsch_tc_ext_stats),
+ TICK_TO_US(gNB->ulsch_tc_intl1_stats),
+ TICK_TO_US(gNB->ulsch_tc_intl2_stats)
+ );
+#endif
+ return(0);
+}
+
+static void *gNB_L1_thread_tx(void *param) {
+ PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param;
+ gNB_L1_proc_t *gNB_proc = &gNB->proc;
+ gNB_L1_rxtx_proc_t *proc = &gNB_proc->L1_proc_tx;
+ //PHY_VARS_gNB *gNB = RC.gNB[0][proc->CC_id];
+ char thread_name[100];
+ sprintf(thread_name,"TXnp4_%d\n",&gNB->proc.L1_proc == proc ? 0 : 1);
+
+ //wait_sync("tx_thread");
+
+ while (!oai_exit) {
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX1, 0 );
+
+ if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break;
+
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX1, 1 );
+
+ if (oai_exit) break;
+
+ // *****************************************
+ // TX processing for subframe n+4
+ // run PHY TX procedures the one after the other for all CCs to avoid race conditions
+ // (may be relaxed in the future for performance reasons)
+ // *****************************************
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_TX1_GNB,proc->slot_tx);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_RX1_GNB,proc->slot_rx);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_GNB,proc->frame_tx);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_GNB,proc->frame_rx);
+ phy_procedures_gNB_TX(gNB, proc, 1);
+ pthread_mutex_lock( &proc->mutex );
+ proc->instance_cnt = -1;
+
+ // the thread can now be woken up
+ if (pthread_cond_signal(&proc->cond) != 0) {
+ LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB TXnp4 thread\n");
+ exit_fun( "ERROR pthread_cond_signal" );
+ }
+
+ pthread_mutex_unlock( &proc->mutex );
+ wakeup_txfh(proc,gNB);
+ }
+
+ return 0;
+}
+
+/*!
+ * \brief The RX UE-specific and TX thread of gNB.
+ * \param param is a \ref gNB_L1_proc_t structure which contains the info what to process.
+ * \returns a pointer to an int. The storage is not on the heap and must not be freed.
+ */
+
+static void *gNB_L1_thread( void *param ) {
+ static int gNB_thread_rxtx_status;
+ PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param;
+ gNB_L1_proc_t *gNB_proc = &gNB->proc;
+ gNB_L1_rxtx_proc_t *proc = &gNB_proc->L1_proc;
+ //PHY_VARS_gNB *gNB = RC.gNB[0][proc->CC_id];
+ char thread_name[100];
+ // set default return value
+ gNB_thread_rxtx_status = 0;
+ sprintf(thread_name,"RXn_TXnp4_%d",&gNB->proc.L1_proc == proc ? 0 : 1);
+
+ while (!oai_exit) {
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX0, 0 );
+
+ if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break;
+
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX0, 1 );
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_TX0_GNB,proc->slot_tx);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_RX0_GNB,proc->slot_rx);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_GNB,proc->frame_tx);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_GNB,proc->frame_rx);
+
+ if (oai_exit) break;
+
+ if (gNB->CC_id==0) {
+ if (rxtx(gNB,proc,thread_name) < 0) break;
+ }
+
+ if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) {
+ phy_procedures_gNB_TX(gNB, proc, 1);
+ }
+
+ if (release_thread(&proc->mutex,&proc->instance_cnt,thread_name)<0) break;
+
+ if(get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) {
+ wakeup_tx(gNB);
+ } else if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) {
+ wakeup_txfh(proc,gNB);
+ }
+ } // while !oai_exit
+
+ LOG_D(PHY, " *** Exiting gNB thread RXn_TXnp4\n");
+ gNB_thread_rxtx_status = 0;
+ return &gNB_thread_rxtx_status;
+}
+
+
+#if 0 //defined(ENABLE_ITTI) && defined(ENABLE_USE_MME)
+// Wait for gNB application initialization to be complete (gNB registration to MME)
+static void wait_system_ready (char *message, volatile int *start_flag) {
+ static char *indicator[] = {". ", ".. ", "... ", ".... ", ".....",
+ " ....", " ...", " ..", " .", " "
+ };
+ int i = 0;
+
+ while ((!oai_exit) && (*start_flag == 0)) {
+ LOG_N(EMU, message, indicator[i]);
+ fflush(stdout);
+ i = (i + 1) % (sizeof(indicator) / sizeof(indicator[0]));
+ usleep(200000);
+ }
+
+ LOG_D(EMU,"\n");
+}
+#endif
+
+
+
+
+
+void gNB_top(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, char *string, struct RU_t_s *ru) {
+ gNB_L1_proc_t *proc = &gNB->proc;
+ gNB_L1_rxtx_proc_t *L1_proc = &proc->L1_proc;
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ RU_proc_t *ru_proc=&ru->proc;
+ proc->frame_rx = frame_rx;
+ proc->slot_rx = slot_rx;
+
+ if (!oai_exit) {
+ T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->slot_rx));
+ L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sl_ahead*fp->samples_per_slot);
+ L1_proc->frame_rx = ru_proc->frame_rx;
+ L1_proc->slot_rx = ru_proc->tti_rx;
+ L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx;
+ L1_proc->slot_tx = (L1_proc->slot_rx + sl_ahead)%fp->slots_per_frame;
+
+ if (rxtx(gNB,L1_proc,string) < 0) LOG_E(PHY,"gNB %d CC_id %d failed during execution\n",gNB->Mod_id,gNB->CC_id);
+
+ ru_proc->timestamp_tx = L1_proc->timestamp_tx;
+ ru_proc->tti_tx = L1_proc->slot_tx;
+ ru_proc->frame_tx = L1_proc->frame_tx;
+ }
+}
+
+int wakeup_txfh(gNB_L1_rxtx_proc_t *proc,PHY_VARS_gNB *gNB) {
+ RU_t *ru;
+ RU_proc_t *ru_proc;
+ struct timespec wait;
+ wait.tv_sec=0;
+ wait.tv_nsec=5000000L;
+ //printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~inside wakeup_txfh %d.%d IC_RU = %d\n", proc->frame_tx, proc->slot_tx, proc->instance_cnt_RUs);
+
+ if(wait_on_condition(&proc->mutex_RUs,&proc->cond_RUs,&proc->instance_cnt_RUs,"wakeup_txfh")<0) {
+ LOG_E(PHY,"Frame %d, subframe %d: TX FH not ready\n", proc->frame_tx, proc->slot_tx);
+ return(-1);
+ }
+
+ pthread_mutex_lock(&gNB->proc.mutex_RU_tx);
+ gNB->proc.RU_mask_tx = 0;
+ pthread_mutex_unlock(&gNB->proc.mutex_RU_tx);
+
+ if (release_thread(&proc->mutex_RUs,&proc->instance_cnt_RUs,"wakeup_txfh")<0) return(-1);
+
+ for(int i=0; inum_RU; i++) {
+ ru = gNB->RU_list[i];
+ ru_proc = &ru->proc;
+
+ if (ru_proc->instance_cnt_gNBs == 0) {
+ LOG_E(PHY,"Frame %d, subframe %d: TX FH thread busy, dropping Frame %d, subframe %d\n", ru_proc->frame_tx, ru_proc->tti_tx, proc->frame_rx, proc->slot_rx);
+ return(-1);
+ }
+
+ if (pthread_mutex_timedlock(&ru_proc->mutex_gNBs,&wait) != 0) {
+ LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB TX1 thread %d (IC %d)\n", ru_proc->tti_rx&1,ru_proc->instance_cnt_gNBs );
+ exit_fun( "error locking mutex_gNB" );
+ return(-1);
+ }
+
+ ru_proc->instance_cnt_gNBs = 0;
+ ru_proc->timestamp_tx = proc->timestamp_tx;
+ ru_proc->tti_tx = proc->slot_tx;
+ ru_proc->frame_tx = proc->frame_tx;
+ LOG_I(PHY,"Signaling tx_thread_fh for %d.%d\n",ru_proc->frame_tx,ru_proc->tti_tx);
+
+ // the thread can now be woken up
+ if (pthread_cond_signal(&ru_proc->cond_gNBs) != 0) {
+ LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB TXnp4 thread\n");
+ exit_fun( "ERROR pthread_cond_signal" );
+ return(-1);
+ }
+
+ pthread_mutex_unlock( &ru_proc->mutex_gNBs );
+ }
+
+ return(0);
+}
+
+int wakeup_tx(PHY_VARS_gNB *gNB) {
+ gNB_L1_proc_t *proc=&gNB->proc;
+ gNB_L1_rxtx_proc_t *L1_proc_tx = &proc->L1_proc_tx;
+ gNB_L1_rxtx_proc_t *L1_proc = &proc->L1_proc;
+ struct timespec wait;
+ wait.tv_sec=0;
+ wait.tv_nsec=5000000L;
+
+ if (pthread_mutex_timedlock(&L1_proc_tx->mutex,&wait) != 0) {
+ LOG_E(PHY, "[SCHED][eNB] ERROR locking mutex for eNB L1_thread_tx\n");
+ exit_fun("ERROR pthread_lock");
+ return(-1);
+ }
+
+ while(L1_proc_tx->instance_cnt == 0) {
+ pthread_cond_wait(&L1_proc_tx->cond,&L1_proc_tx->mutex);
+ }
+
+ L1_proc_tx->instance_cnt = 0;
+ L1_proc_tx->slot_rx = L1_proc->slot_rx;
+ L1_proc_tx->frame_rx = L1_proc->frame_rx;
+ L1_proc_tx->slot_tx = L1_proc->slot_tx;
+ L1_proc_tx->frame_tx = L1_proc->frame_tx;
+ L1_proc_tx->timestamp_tx = L1_proc->timestamp_tx;
+
+ // the thread can now be woken up
+ if (pthread_cond_signal(&L1_proc_tx->cond) != 0) {
+ LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n");
+ exit_fun( "ERROR pthread_cond_signal" );
+ return(-1);
+ }
+
+ pthread_mutex_unlock( &L1_proc_tx->mutex);
+ return(0);
+}
+
+int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) {
+ gNB_L1_proc_t *proc=&gNB->proc;
+ gNB_L1_rxtx_proc_t *L1_proc=&proc->L1_proc;
+ NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
+ RU_proc_t *ru_proc=&ru->proc;
+ int i;
+ struct timespec wait;
+ pthread_mutex_lock(&proc->mutex_RU);
+
+ for (i=0; inum_RU; i++) {
+ if (ru == gNB->RU_list[i]) {
+ if ((proc->RU_mask&(1< 0)
+ LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n",
+ gNB->Mod_id,proc->frame_rx,proc->slot_rx,ru->idx,gNB->num_RU,proc->RU_mask);
+
+ proc->RU_mask |= (1<RU_mask != (1<num_RU)-1) { // not all RUs have provided their information so return
+ LOG_E(PHY,"Not all RUs have provided their info\n");
+ pthread_mutex_unlock(&proc->mutex_RU);
+ return(0);
+ } else { // all RUs have provided their information so continue on and wakeup gNB processing
+ proc->RU_mask = 0;
+ pthread_mutex_unlock(&proc->mutex_RU);
+ }
+
+ wait.tv_sec=0;
+ wait.tv_nsec=5000000L;
+
+ /* accept some delay in processing - up to 5ms */
+ for (i = 0; i < fp->slots_per_frame && L1_proc->instance_cnt == 0; i++) {
+ LOG_W( PHY,"[gNB] SFN.SL %d.%d, gNB RXn-TXnp4 thread busy!! (i %d, cnt %i)\n", L1_proc->frame_tx, L1_proc->slot_tx, i,L1_proc->instance_cnt);
+ usleep(100);
+ }
+
+ if (L1_proc->instance_cnt == 0) {
+ exit_fun( "TX thread busy" );
+ return(-1);
+ }
+
+ // wake up TX for subframe n+sl_ahead
+ // lock the TX mutex and make sure the thread is ready
+ if (pthread_mutex_timedlock(&L1_proc->mutex,&wait) != 0) {
+ LOG_E( PHY, "[gNB] ERROR pthread_mutex_lock for gNB RXTX thread %d (IC %d)\n", L1_proc->slot_rx&1,L1_proc->instance_cnt );
+ exit_fun( "error locking mutex" );
+ return(-1);
+ }
+
+ ++L1_proc->instance_cnt;
+ // We have just received and processed the common part of a subframe, say n.
+ // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired
+ // transmitted timestamp of the next TX slot (first).
+ // The last (TS_rx mod samples_per_frame) was n*samples_per_tti,
+ // we want to generate subframe (n+sl_ahead), so TS_tx = TX_rx+sl_ahead*samples_per_tti,
+ // and proc->slot_tx = proc->slot_rx+sl_ahead
+ L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sl_ahead*fp->samples_per_slot);
+ L1_proc->frame_rx = ru_proc->frame_rx;
+ L1_proc->slot_rx = ru_proc->tti_rx;
+ L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx;
+ L1_proc->slot_tx = (L1_proc->slot_rx + sl_ahead)%fp->slots_per_frame;
+ LOG_I(PHY,"wakeupL1: passing parameter IC = %d, RX: %d.%d, TX: %d.%d to L1 sl_ahead = %d\n", L1_proc->instance_cnt, L1_proc->frame_rx, L1_proc->slot_rx, L1_proc->frame_tx, L1_proc->slot_tx, sl_ahead);
+
+ // the thread can now be woken up
+ if (pthread_cond_signal(&L1_proc->cond) != 0) {
+ LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB RXn-TXnp4 thread\n");
+ exit_fun( "ERROR pthread_cond_signal" );
+ return(-1);
+ }
+
+ pthread_mutex_unlock( &L1_proc->mutex );
+ return(0);
+}
+/*
+void wakeup_prach_gNB(PHY_VARS_gNB *gNB,RU_t *ru,int frame,int subframe) {
+
+ gNB_L1_proc_t *proc = &gNB->proc;
+ LTE_DL_FRAME_PARMS *fp=&gNB->frame_parms;
+ int i;
+
+ if (ru!=NULL) {
+ pthread_mutex_lock(&proc->mutex_RU_PRACH);
+ for (i=0;inum_RU;i++) {
+ if (ru == gNB->RU_list[i]) {
+ LOG_D(PHY,"frame %d, subframe %d: RU %d for gNB %d signals PRACH (mask %x, num_RU %d)\n",frame,subframe,i,gNB->Mod_id,proc->RU_mask_prach,gNB->num_RU);
+ if ((proc->RU_mask_prach&(1< 0)
+ LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information (PRACH) from RU %d (num_RU %d, mask %x) has not been served yet!\n",
+ gNB->Mod_id,frame,subframe,ru->idx,gNB->num_RU,proc->RU_mask_prach);
+ proc->RU_mask_prach |= (1<RU_mask_prach != (1<num_RU)-1) { // not all RUs have provided their information so return
+ pthread_mutex_unlock(&proc->mutex_RU_PRACH);
+ return;
+ }
+ else { // all RUs have provided their information so continue on and wakeup gNB processing
+ proc->RU_mask_prach = 0;
+ pthread_mutex_unlock(&proc->mutex_RU_PRACH);
+ }
+ }
+
+ // check if we have to detect PRACH first
+ if (is_prach_subframe(fp,frame,subframe)>0) {
+ LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe);
+ if (proc->instance_cnt_prach == 0) {
+ LOG_W(PHY,"[gNB] Frame %d Subframe %d, dropping PRACH\n", frame,subframe);
+ return;
+ }
+
+ // wake up thread for PRACH RX
+ if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
+ LOG_E( PHY, "[gNB] ERROR pthread_mutex_lock for gNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach);
+ exit_fun( "error locking mutex_prach" );
+ return;
+ }
+
+ ++proc->instance_cnt_prach;
+ // set timing for prach thread
+ proc->frame_prach = frame;
+ proc->subframe_prach = subframe;
+
+ // the thread can now be woken up
+ if (pthread_cond_signal(&proc->cond_prach) != 0) {
+ LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB PRACH thread %d\n", proc->thread_index);
+ exit_fun( "ERROR pthread_cond_signal" );
+ return;
+ }
+
+ pthread_mutex_unlock( &proc->mutex_prach );
+ }
+
+}*/
+
+/*!
+ * \brief The prach receive thread of gNB.
+ * \param param is a \ref gNB_L1_proc_t structure which contains the info what to process.
+ * \returns a pointer to an int. The storage is not on the heap and must not be freed.
+ */
+/*
+static void* gNB_thread_prach( void* param ) {
+ static int gNB_thread_prach_status;
+
+
+ PHY_VARS_gNB *gNB= (PHY_VARS_gNB *)param;
+ gNB_L1_proc_t *proc = &gNB->proc;
+
+ // set default return value
+ gNB_thread_prach_status = 0;
+
+
+
+ while (!oai_exit) {
+
+ if (oai_exit) break;
+
+
+ if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"gNB_prach_thread") < 0) break;
+
+ LOG_D(PHY,"Running gNB prach procedures\n");
+ prach_procedures(gNB
+#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+ ,0
+#endif
+ );
+
+ if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"gNB_prach_thread") < 0) break;
+ }
+
+ LOG_I(PHY, "Exiting gNB thread PRACH\n");
+
+ gNB_thread_prach_status = 0;
+ return &gNB_thread_prach_status;
+}
+*/
+
+extern void init_td_thread(PHY_VARS_gNB *);
+extern void init_te_thread(PHY_VARS_gNB *);
+
+void init_gNB_proc(int inst) {
+ int i=0;
+ int CC_id;
+ PHY_VARS_gNB *gNB;
+ gNB_L1_proc_t *proc;
+ gNB_L1_rxtx_proc_t *L1_proc,*L1_proc_tx;
+ LOG_I(PHY,"%s(inst:%d) RC.nb_nr_CC[inst]:%d \n",__FUNCTION__,inst,RC.nb_nr_CC[inst]);
+
+ for (CC_id=0; CC_idproc;
+ L1_proc = &proc->L1_proc;
+ L1_proc_tx = &proc->L1_proc_tx;
+ L1_proc->instance_cnt = -1;
+ L1_proc_tx->instance_cnt = -1;
+ L1_proc->instance_cnt_RUs = 0;
+ L1_proc_tx->instance_cnt_RUs = 0;
+ proc->instance_cnt_prach = -1;
+ proc->instance_cnt_asynch_rxtx = -1;
+ proc->CC_id = CC_id;
+ proc->first_rx =1;
+ proc->first_tx =1;
+ proc->RU_mask =0;
+ proc->RU_mask_tx = (1<num_RU)-1;
+ proc->RU_mask_prach =0;
+ pthread_mutex_init( &gNB->UL_INFO_mutex, NULL);
+ pthread_mutex_init( &L1_proc->mutex, NULL);
+ pthread_mutex_init( &L1_proc_tx->mutex, NULL);
+ pthread_cond_init( &L1_proc->cond, NULL);
+ pthread_cond_init( &L1_proc_tx->cond, NULL);
+ pthread_mutex_init( &proc->mutex_prach, NULL);
+ pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL);
+ pthread_mutex_init( &proc->mutex_RU,NULL);
+ pthread_mutex_init( &proc->mutex_RU_tx,NULL);
+ pthread_mutex_init( &proc->mutex_RU_PRACH,NULL);
+ pthread_cond_init( &proc->cond_prach, NULL);
+ pthread_cond_init( &proc->cond_asynch_rxtx, NULL);
+ LOG_I(PHY,"gNB->single_thread_flag:%d\n", gNB->single_thread_flag);
+
+ if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) {
+ threadCreate( &L1_proc->pthread, gNB_L1_thread, gNB, "L1_proc", -1, OAI_PRIORITY_RT );
+ threadCreate( &L1_proc_tx->pthread, gNB_L1_thread_tx, gNB,"L1_proc_tx", -1, OAI_PRIORITY_RT);
+ }
+
+ //pthread_create( &proc->pthread_prach, attr_prach, gNB_thread_prach, gNB );
+ char name[16];
+
+ if (gNB->single_thread_flag==0) {
+ snprintf( name, sizeof(name), "L1 %d", i );
+ pthread_setname_np( L1_proc->pthread, name );
+ snprintf( name, sizeof(name), "L1TX %d", i );
+ pthread_setname_np( L1_proc_tx->pthread, name );
+ }
+
+ AssertFatal(proc->instance_cnt_prach == -1,"instance_cnt_prach = %d\n",proc->instance_cnt_prach);
+ }
+
+ /* setup PHY proc TX sync mechanism */
+ pthread_mutex_init(&sync_phy_proc.mutex_phy_proc_tx, NULL);
+ pthread_cond_init(&sync_phy_proc.cond_phy_proc_tx, NULL);
+ sync_phy_proc.phy_proc_CC_id = 0;
+}
+
+
+
+/*!
+ * \brief Terminate gNB TX and RX threads.
+ */
+void kill_gNB_proc(int inst) {
+ int *status;
+ PHY_VARS_gNB *gNB;
+ gNB_L1_proc_t *proc;
+ gNB_L1_rxtx_proc_t *L1_proc, *L1_proc_tx;
+
+ for (int CC_id=0; CC_idproc;
+ L1_proc = &proc->L1_proc;
+ L1_proc_tx = &proc->L1_proc_tx;
+ LOG_I(PHY, "Killing TX CC_id %d inst %d\n", CC_id, inst );
+
+ if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) {
+ pthread_mutex_lock(&L1_proc->mutex);
+ L1_proc->instance_cnt = 0;
+ pthread_cond_signal(&L1_proc->cond);
+ pthread_mutex_unlock(&L1_proc->mutex);
+ pthread_mutex_lock(&L1_proc_tx->mutex);
+ L1_proc_tx->instance_cnt = 0;
+ pthread_cond_signal(&L1_proc_tx->cond);
+ pthread_mutex_unlock(&L1_proc_tx->mutex);
+ }
+
+ proc->instance_cnt_prach = 0;
+ pthread_cond_signal( &proc->cond_prach );
+ pthread_cond_signal( &proc->cond_asynch_rxtx );
+ pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx);
+ // LOG_D(PHY, "joining pthread_prach\n");
+ // pthread_join( proc->pthread_prach, (void**)&status );
+ LOG_I(PHY, "Destroying prach mutex/cond\n");
+ pthread_mutex_destroy( &proc->mutex_prach );
+ pthread_cond_destroy( &proc->cond_prach );
+ LOG_I(PHY, "Destroying UL_INFO mutex\n");
+ pthread_mutex_destroy(&gNB->UL_INFO_mutex);
+
+ if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) {
+ LOG_I(PHY, "Joining L1_proc mutex/cond\n");
+ pthread_join( L1_proc->pthread, (void **)&status );
+ LOG_I(PHY, "Joining L1_proc_tx mutex/cond\n");
+ pthread_join( L1_proc_tx->pthread, (void **)&status );
+ }
+
+ LOG_I(PHY, "Destroying L1_proc mutex/cond\n");
+ pthread_mutex_destroy( &L1_proc->mutex );
+ pthread_cond_destroy( &L1_proc->cond );
+ LOG_I(PHY, "Destroying L1_proc_tx mutex/cond\n");
+ pthread_mutex_destroy( &L1_proc_tx->mutex );
+ pthread_cond_destroy( &L1_proc_tx->cond );
+ pthread_mutex_destroy( &proc->mutex_RU );
+ pthread_mutex_destroy( &proc->mutex_RU_tx );
+ }
+}
+
+
+
+
+void reset_opp_meas(void) {
+ int sfn;
+ reset_meas(&softmodem_stats_mt);
+ reset_meas(&softmodem_stats_hw);
+
+ for (sfn=0; sfn < 10; sfn++) {
+ reset_meas(&softmodem_stats_rxtx_sf);
+ reset_meas(&softmodem_stats_rx_sf);
+ }
+}
+
+
+void print_opp_meas(void) {
+ int sfn=0;
+ print_meas(&softmodem_stats_mt, "Main gNB Thread", NULL, NULL);
+ print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL);
+
+ for (sfn=0; sfn < 10; sfn++) {
+ print_meas(&softmodem_stats_rxtx_sf,"[gNB][total_phy_proc_rxtx]",NULL, NULL);
+ print_meas(&softmodem_stats_rx_sf,"[gNB][total_phy_proc_rx]",NULL,NULL);
+ }
+}
+
+
+/// eNB kept in function name for nffapi calls, TO FIX
+void init_eNB_afterRU(void) {
+ int inst,CC_id,ru_id,i,aa;
+ PHY_VARS_gNB *gNB;
+ LOG_I(PHY,"%s() RC.nb_nr_inst:%d\n", __FUNCTION__, RC.nb_nr_inst);
+
+ for (inst=0; instnum_RU>0,"Number of RU attached to gNB %d is zero\n",gNB->Mod_id);
+
+ LOG_I(PHY,"Mapping RX ports from %d RUs to gNB %d\n",gNB->num_RU,gNB->Mod_id);
+ //LOG_I(PHY,"Overwriting gNB->prach_vars.rxsigF[0]:%p\n", gNB->prach_vars.rxsigF[0]);
+ gNB->prach_vars.rxsigF[0] = (int16_t **)malloc16(64*sizeof(int16_t *));
+ LOG_I(PHY,"gNB->num_RU:%d\n", gNB->num_RU);
+
+ for (ru_id=0,aa=0; ru_idnum_RU; ru_id++) {
+ AssertFatal(gNB->RU_list[ru_id]->common.rxdataF!=NULL,
+ "RU %d : common.rxdataF is NULL\n",
+ gNB->RU_list[ru_id]->idx);
+ AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF!=NULL,
+ "RU %d : prach_rxsigF is NULL\n",
+ gNB->RU_list[ru_id]->idx);
+
+ for (i=0; iRU_list[ru_id]->nb_rx; aa++,i++) {
+ LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n",gNB->RU_list[ru_id]->idx,i,aa);
+ gNB->prach_vars.rxsigF[0][aa] = gNB->RU_list[ru_id]->prach_rxsigF[i];
+ gNB->common_vars.rxdataF[aa] = gNB->RU_list[ru_id]->common.rxdataF[i];
+ }
+ }
+
+ /* TODO: review this code, there is something wrong.
+ * In monolithic mode, we come here with nb_antennas_rx == 0
+ * (not tested in other modes).
+ */
+ //init_precoding_weights(RC.gNB[inst][CC_id]);
+ }
+
+ init_gNB_proc(inst);
+ }
+
+ for (ru_id=0; ru_idnr_wakeup_rxtx = wakeup_rxtx;
+ // RC.ru[ru_id]->wakeup_prach_eNB = wakeup_prach_gNB;
+ RC.ru[ru_id]->gNB_top = gNB_top;
+ }
+}
+
+void init_gNB(int single_thread_flag,int wait_for_sync) {
+ int CC_id;
+ int inst;
+ PHY_VARS_gNB *gNB;
+ LOG_I(PHY,"[nr-softmodem.c] gNB structure about to allocated RC.nb_nr_L1_inst:%d RC.nb_nr_L1_CC[0]:%d\n",RC.nb_nr_L1_inst,RC.nb_nr_L1_CC[0]);
+
+ if (RC.gNB == NULL) RC.gNB = (PHY_VARS_gNB ***) malloc(RC.nb_nr_L1_inst*sizeof(PHY_VARS_gNB **));
+
+ LOG_I(PHY,"[lte-softmodem.c] gNB structure RC.gNB allocated\n");
+
+ for (inst=0; instabstraction_flag = 0;
+ gNB->single_thread_flag = single_thread_flag;
+ /*nr_polar_init(&gNB->nrPolar_params,
+ NR_POLAR_PBCH_MESSAGE_TYPE,
+ NR_POLAR_PBCH_PAYLOAD_BITS,
+ NR_POLAR_PBCH_AGGREGATION_LEVEL);*/
+ LOG_I(PHY,"Initializing gNB %d CC_id %d single_thread_flag:%d\n",inst,CC_id,single_thread_flag);
+#ifndef OCP_FRAMEWORK
+ LOG_I(PHY,"Initializing gNB %d CC_id %d\n",inst,CC_id);
+#endif
+ LOG_I(PHY,"Registering with MAC interface module\n");
+ AssertFatal((gNB->if_inst = NR_IF_Module_init(inst))!=NULL,"Cannot register interface");
+ gNB->if_inst->NR_Schedule_response = nr_schedule_response;
+ gNB->if_inst->NR_PHY_config_req = nr_phy_config_request;
+ memset((void *)&gNB->UL_INFO,0,sizeof(gNB->UL_INFO));
+ memset((void *)&gNB->Sched_INFO,0,sizeof(gNB->Sched_INFO));
+ LOG_I(PHY,"Setting indication lists\n");
+ gNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = gNB->rx_pdu_list;
+ gNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = gNB->crc_pdu_list;
+ gNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = gNB->sr_pdu_list;
+ gNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = gNB->harq_pdu_list;
+ gNB->UL_INFO.cqi_ind.cqi_pdu_list = gNB->cqi_pdu_list;
+ gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list;
+ gNB->prach_energy_counter = 0;
+ }
+ }
+
+ LOG_I(PHY,"[nr-softmodem.c] gNB structure allocated\n");
+}
+
+
+void stop_gNB(int nb_inst) {
+ for (int inst=0; inst.
+
+ Contact Information
+ OpenAirInterface Admin: openair_admin@eurecom.fr
+ OpenAirInterface Tech : openair_tech@eurecom.fr
+ OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
+
+ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+*******************************************************************************/
+
+/*! \file lte-enb.c
+ * \brief Top-level threads for eNodeB
+ * \author R. Knopp, F. Kaltenberger, Navid Nikaein
+ * \date 2012
+ * \version 0.1
+ * \company Eurecom
+ * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr
+ * \note
+ * \warning
+ */
+#define _GNU_SOURCE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "common/utils/assertions.h"
+#include "common/utils/system.h"
+#include "msc.h"
+
+#include "../../ARCH/COMMON/common_lib.h"
+#include "../../ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h"
+
+#include "PHY/LTE_TRANSPORT/if4_tools.h"
+#include "PHY/LTE_TRANSPORT/if5_tools.h"
+
+#include "PHY/types.h"
+#include "PHY/defs_nr_common.h"
+#include "PHY/phy_extern.h"
+#include "PHY/LTE_TRANSPORT/transport_proto.h"
+#include "PHY/INIT/phy_init.h"
+#include "SCHED/sched_eNB.h"
+#include "SCHED_NR/sched_nr.h"
+
+#include "LAYER2/MAC/mac.h"
+#include "LAYER2/MAC/mac_extern.h"
+#include "LAYER2/MAC/mac_proto.h"
+#include "RRC/LTE/rrc_extern.h"
+#include "PHY_INTERFACE/phy_interface.h"
+
+#include "common/utils/LOG/log.h"
+#include "common/utils/LOG/vcd_signal_dumper.h"
+
+#include "enb_config.h"
+
+#ifdef SMBV
+#include "PHY/TOOLS/smbv.h"
+unsigned short config_frames[4] = {2,9,11,13};
+#endif
+
+/* these variables have to be defined before including ENB_APP/enb_paramdef.h */
+static int DEFBANDS[] = {7};
+static int DEFENBS[] = {0};
+
+#include "ENB_APP/enb_paramdef.h"
+#include "common/config/config_userapi.h"
+
+#ifndef OPENAIR2
+ #include "UTIL/OTG/otg_extern.h"
+#endif
+
+#if defined(ENABLE_ITTI)
+ #if defined(ENABLE_USE_MME)
+ #include "s1ap_eNB.h"
+ #ifdef PDCP_USE_NETLINK
+ #include "SIMULATION/ETH_TRANSPORT/proto.h"
+ #endif
+ #endif
+#endif
+
+#include "T.h"
+#include "nfapi_interface.h"
+
+extern volatile int oai_exit;
+
+
+extern void nr_phy_free_RU(RU_t *);
+extern void nr_phy_config_request(NR_PHY_Config_t *gNB);
+
+extern PARALLEL_CONF_t get_thread_parallel_conf(void);
+extern WORKER_CONF_t get_thread_worker_conf(void);
+
+void init_RU(char *);
+void stop_RU(int nb_ru);
+void do_ru_sync(RU_t *ru);
+
+void configure_ru(int idx,
+ void *arg);
+
+void configure_rru(int idx,
+ void *arg);
+
+int attach_rru(RU_t *ru);
+
+int connect_rau(RU_t *ru);
+
+extern uint16_t sl_ahead;
+
+extern int emulate_rf;
+extern int numerology;
+
+/*************************************************************/
+/* Functions to attach and configure RRU */
+
+extern void wait_gNBs(void);
+
+int attach_rru(RU_t *ru) {
+ ssize_t msg_len,len;
+ RRU_CONFIG_msg_t rru_config_msg;
+ int received_capabilities=0;
+ wait_gNBs();
+
+ // Wait for capabilities
+ while (received_capabilities==0) {
+ memset((void *)&rru_config_msg,0,sizeof(rru_config_msg));
+ rru_config_msg.type = RAU_tick;
+ rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE;
+ LOG_I(PHY,"Sending RAU tick to RRU %d\n",ru->idx);
+ AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
+ "RU %d cannot access remote radio\n",ru->idx);
+ msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
+
+ // wait for answer with timeout
+ if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
+ &rru_config_msg,
+ msg_len))<0) {
+ LOG_I(PHY,"Waiting for RRU %d\n",ru->idx);
+ } else if (rru_config_msg.type == RRU_capabilities) {
+ AssertFatal(rru_config_msg.len==msg_len,"Received capabilities with incorrect length (%d!=%d)\n",(int)rru_config_msg.len,(int)msg_len);
+ LOG_I(PHY,"Received capabilities from RRU %d (len %d/%d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",ru->idx,
+ (int)rru_config_msg.len,(int)msg_len,
+ ((RRU_capabilities_t *)&rru_config_msg.msg[0])->num_bands,
+ ((RRU_capabilities_t *)&rru_config_msg.msg[0])->max_pdschReferenceSignalPower[0],
+ ((RRU_capabilities_t *)&rru_config_msg.msg[0])->max_rxgain[0],
+ ((RRU_capabilities_t *)&rru_config_msg.msg[0])->nb_tx[0],
+ ((RRU_capabilities_t *)&rru_config_msg.msg[0])->nb_rx[0]);
+ received_capabilities=1;
+ } else {
+ LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx);
+ }
+ }
+
+ configure_ru(ru->idx,
+ (RRU_capabilities_t *)&rru_config_msg.msg[0]);
+ rru_config_msg.type = RRU_config;
+ rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t);
+ LOG_I(PHY,"Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",ru->idx,
+ ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands,
+ ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]);
+ AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
+ "RU %d failed send configuration to remote radio\n",ru->idx);
+ return 0;
+}
+
+int connect_rau(RU_t *ru) {
+ RRU_CONFIG_msg_t rru_config_msg;
+ ssize_t msg_len;
+ int tick_received = 0;
+ int configuration_received = 0;
+ RRU_capabilities_t *cap;
+ int i;
+ int len;
+
+ // wait for RAU_tick
+ while (tick_received == 0) {
+ msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE;
+
+ if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
+ &rru_config_msg,
+ msg_len))<0) {
+ LOG_I(PHY,"Waiting for RAU\n");
+ } else {
+ if (rru_config_msg.type == RAU_tick) {
+ LOG_I(PHY,"Tick received from RAU\n");
+ tick_received = 1;
+ } else LOG_E(PHY,"Received erroneous message (%d)from RAU, expected RAU_tick\n",rru_config_msg.type);
+ }
+ }
+
+ // send capabilities
+ rru_config_msg.type = RRU_capabilities;
+ rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
+ cap = (RRU_capabilities_t *)&rru_config_msg.msg[0];
+ LOG_I(PHY,"Sending Capabilities (len %d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",
+ (int)rru_config_msg.len,ru->num_bands,ru->max_pdschReferenceSignalPower,ru->max_rxgain,ru->nb_tx,ru->nb_rx);
+
+ switch (ru->function) {
+ case NGFI_RRU_IF4p5:
+ cap->FH_fmt = OAI_IF4p5_only;
+ break;
+
+ case NGFI_RRU_IF5:
+ cap->FH_fmt = OAI_IF5_only;
+ break;
+
+ case MBP_RRU_IF5:
+ cap->FH_fmt = MBP_IF5;
+ break;
+
+ default:
+ AssertFatal(1==0,"RU_function is unknown %d\n",RC.ru[0]->function);
+ break;
+ }
+
+ cap->num_bands = ru->num_bands;
+
+ for (i=0; inum_bands; i++) {
+ LOG_I(PHY,"Band %d: nb_rx %d nb_tx %d pdschReferenceSignalPower %d rxgain %d\n",
+ ru->band[i],ru->nb_rx,ru->nb_tx,ru->max_pdschReferenceSignalPower,ru->max_rxgain);
+ cap->band_list[i] = ru->band[i];
+ cap->nb_rx[i] = ru->nb_rx;
+ cap->nb_tx[i] = ru->nb_tx;
+ cap->max_pdschReferenceSignalPower[i] = ru->max_pdschReferenceSignalPower;
+ cap->max_rxgain[i] = ru->max_rxgain;
+ }
+
+ AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
+ "RU %d failed send capabilities to RAU\n",ru->idx);
+ // wait for configuration
+ rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t);
+
+ while (configuration_received == 0) {
+ if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
+ &rru_config_msg,
+ rru_config_msg.len))<0) {
+ LOG_I(PHY,"Waiting for configuration from RAU\n");
+ } else {
+ LOG_I(PHY,"Configuration received from RAU (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",
+ ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands,
+ ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0],
+ ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]);
+ configure_rru(ru->idx,
+ (void *)&rru_config_msg.msg[0]);
+ configuration_received = 1;
+ }
+ }
+
+ return 0;
+}
+/*************************************************************/
+/* Southbound Fronthaul functions, RCC/RAU */
+
+// southbound IF5 fronthaul for 16-bit OAI format
+static inline void fh_if5_south_out(RU_t *ru) {
+ if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
+
+ send_IF5(ru, ru->proc.timestamp_tx, ru->proc.tti_tx, &ru->seqno, IF5_RRH_GW_DL);
+}
+
+// southbound IF5 fronthaul for Mobipass packet format
+static inline void fh_if5_mobipass_south_out(RU_t *ru) {
+ if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
+
+ send_IF5(ru, ru->proc.timestamp_tx, ru->proc.tti_tx, &ru->seqno, IF5_MOBIPASS);
+}
+
+// southbound IF4p5 fronthaul
+static inline void fh_if4p5_south_out(RU_t *ru) {
+ if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
+
+ LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.tti_tx);
+
+ if (nr_slot_select(&ru->gNB_list[0]->gNB_config,ru->proc.tti_tx)!=SF_UL)
+ send_IF4p5(ru,ru->proc.frame_tx, ru->proc.tti_tx, IF4p5_PDLFFT);
+}
+
+/*************************************************************/
+/* Input Fronthaul from south RCC/RAU */
+
+// Synchronous if5 from south
+void fh_if5_south_in(RU_t *ru,int *frame, int *tti) {
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ RU_proc_t *proc = &ru->proc;
+ recv_IF5(ru, &proc->timestamp_rx, *tti, IF5_RRH_GW_UL);
+ proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_slot*20))&1023;
+ proc->tti_rx = (proc->timestamp_rx / fp->samples_per_slot)%20;
+
+ if (proc->first_rx == 0) {
+ if (proc->tti_rx != *tti) {
+ LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*tti);
+ exit_fun("Exiting");
+ }
+
+ if (proc->frame_rx != *frame) {
+ LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame);
+ exit_fun("Exiting");
+ }
+ } else {
+ proc->first_rx = 0;
+ *frame = proc->frame_rx;
+ *tti = proc->tti_rx;
+ }
+
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
+}
+
+// Synchronous if4p5 from south
+void fh_if4p5_south_in(RU_t *ru,int *frame,int *slot) {
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ RU_proc_t *proc = &ru->proc;
+ int f,sl;
+ uint16_t packet_type;
+ uint32_t symbol_number=0;
+ uint32_t symbol_mask_full=0;
+
+ /*
+ if ((fp->frame_type == TDD) && (subframe_select(fp,*slot)==SF_S))
+ symbol_mask_full = (1<ul_symbols_in_S_subframe)-1;
+ else
+ symbol_mask_full = (1<symbols_per_slot)-1;
+
+ AssertFatal(proc->symbol_mask[*slot]==0,"rx_fh_if4p5: proc->symbol_mask[%d] = %x\n",*slot,proc->symbol_mask[*slot]);*/
+ do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
+ recv_IF4p5(ru, &f, &sl, &packet_type, &symbol_number);
+
+ if (packet_type == IF4p5_PULFFT) proc->symbol_mask[sl] = proc->symbol_mask[sl] | (1<first_rx==0) && (f!=*frame)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received frame %d != expected %d\n",f,*frame);
+
+ if ((proc->first_rx==0) && (sl!=*slot)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n",sl,*slot,proc->first_rx);
+
+ break;
+ } else if (packet_type == IF4p5_PRACH) {
+ // nothing in RU for RAU
+ }
+
+ LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*slot,proc->symbol_mask[sl]);
+ } while(proc->symbol_mask[sl] != symbol_mask_full);
+
+ //caculate timestamp_rx, timestamp_tx based on frame and subframe
+ proc->tti_rx = sl;
+ proc->frame_rx = f;
+ proc->timestamp_rx = ((proc->frame_rx * fp->slots_per_frame) + proc->tti_rx ) * fp->samples_per_slot ;
+ // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe);
+ proc->tti_tx = (sl+sl_ahead)%fp->slots_per_frame;
+ proc->frame_tx = (sl>(fp->slots_per_frame-sl_ahead)) ? (f+1)&1023 : f;
+
+ if (proc->first_rx == 0) {
+ if (proc->tti_rx != *slot) {
+ LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*slot);
+ exit_fun("Exiting");
+ }
+
+ if (proc->frame_rx != *frame) {
+ LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame);
+ exit_fun("Exiting");
+ }
+ } else {
+ proc->first_rx = 0;
+ *frame = proc->frame_rx;
+ *slot = proc->tti_rx;
+ }
+
+ if (ru == RC.ru[0]) {
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, f );
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, sl);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, proc->tti_tx );
+ }
+
+ proc->symbol_mask[proc->tti_rx] = 0;
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
+ LOG_D(PHY,"RU %d: fh_if4p5_south_in sleeping ...\n",ru->idx);
+}
+
+// asynchronous inbound if4p5 fronthaul from south
+void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *slot) {
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ RU_proc_t *proc = &ru->proc;
+ uint16_t packet_type;
+ uint32_t symbol_number,symbol_mask,prach_rx;
+ // uint32_t got_prach_info=0;
+ symbol_number = 0;
+ symbol_mask = (1<<(fp->symbols_per_slot))-1;
+ prach_rx = 0;
+
+ do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
+ recv_IF4p5(ru, &proc->frame_rx, &proc->tti_rx, &packet_type, &symbol_number);
+
+ // grab first prach information for this new subframe
+ /*if (got_prach_info==0) {
+ prach_rx = is_prach_subframe(fp, proc->frame_rx, proc->tti_rx);
+ got_prach_info = 1;
+ }*/
+ if (proc->first_rx != 0) {
+ *frame = proc->frame_rx;
+ *slot = proc->tti_rx;
+ proc->first_rx = 0;
+ } else {
+ if (proc->frame_rx != *frame) {
+ LOG_E(PHY,"frame_rx %d is not what we expect %d\n",proc->frame_rx,*frame);
+ exit_fun("Exiting");
+ }
+
+ if (proc->tti_rx != *slot) {
+ LOG_E(PHY,"tti_rx %d is not what we expect %d\n",proc->tti_rx,*slot);
+ exit_fun("Exiting");
+ }
+ }
+
+ if (packet_type == IF4p5_PULFFT) symbol_mask &= (~(1< 0) || (prach_rx >0)); // haven't received all PUSCH symbols and PRACH information
+}
+
+
+
+
+
+/*************************************************************/
+/* Input Fronthaul from North RRU */
+
+// RRU IF4p5 TX fronthaul receiver. Assumes an if_device on input and if or rf device on output
+// receives one subframe's worth of IF4p5 OFDM symbols and OFDM modulates
+void fh_if4p5_north_in(RU_t *ru,int *frame,int *slot) {
+ uint32_t symbol_number=0;
+ uint32_t symbol_mask, symbol_mask_full;
+ uint16_t packet_type;
+ /// **** incoming IF4p5 from remote RCC/RAU **** ///
+ symbol_number = 0;
+ symbol_mask = 0;
+ symbol_mask_full = (1<<(ru->nr_frame_parms->symbols_per_slot))-1;
+
+ do {
+ recv_IF4p5(ru, frame, slot, &packet_type, &symbol_number);
+ symbol_mask = symbol_mask | (1<nr_frame_parms;
+ RU_proc_t *proc = &ru->proc;
+ int tti_tx,frame_tx;
+ openair0_timestamp timestamp_tx;
+ recv_IF5(ru, ×tamp_tx, *slot, IF5_RRH_GW_DL);
+ // printf("Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx);
+ tti_tx = (timestamp_tx/fp->samples_per_slot)%fp->slots_per_frame;
+ frame_tx = (timestamp_tx/(fp->samples_per_slot*fp->slots_per_frame))&1023;
+
+ if (proc->first_tx != 0) {
+ *slot = tti_tx;
+ *frame = frame_tx;
+ proc->first_tx = 0;
+ } else {
+ AssertFatal(tti_tx == *slot,
+ "tti_tx %d is not what we expect %d\n",tti_tx,*slot);
+ AssertFatal(frame_tx == *frame,
+ "frame_tx %d is not what we expect %d\n",frame_tx,*frame);
+ }
+}
+
+void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ nfapi_nr_config_request_t *cfg = &ru->gNB_list[0]->gNB_config;
+ RU_proc_t *proc = &ru->proc;
+ uint16_t packet_type;
+ uint32_t symbol_number,symbol_mask,symbol_mask_full=0;
+ int slot_tx,frame_tx;
+ LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru);
+ symbol_number = 0;
+ symbol_mask = 0;
+
+ // symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_slot))-1;
+ do {
+ recv_IF4p5(ru, &frame_tx, &slot_tx, &packet_type, &symbol_number);
+
+ if ((nr_slot_select(cfg,slot_tx) == SF_DL) && (symbol_number == 0)) start_meas(&ru->rx_fhaul);
+
+ LOG_D(PHY,"subframe %d (%d): frame %d, subframe %d, symbol %d\n",
+ *slot,nr_slot_select(cfg,*slot),frame_tx,slot_tx,symbol_number);
+
+ if (proc->first_tx != 0) {
+ *frame = frame_tx;
+ *slot = slot_tx;
+ proc->first_tx = 0;
+ //symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_slot))-1;
+ } else {
+ AssertFatal(frame_tx == *frame,
+ "frame_tx %d is not what we expect %d\n",frame_tx,*frame);
+ AssertFatal(slot_tx == *slot,
+ "slot_tx %d is not what we expect %d\n",slot_tx,*slot);
+ }
+
+ if (packet_type == IF4p5_PDLFFT) {
+ symbol_mask = symbol_mask | (1<rx_fhaul);
+
+ proc->tti_tx = slot_tx;
+ proc->frame_tx = frame_tx;
+
+ if ((frame_tx == 0)&&(slot_tx == 0)) proc->frame_tx_unwrap += 1024;
+
+ proc->timestamp_tx = ((((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * fp->slots_per_frame) + (uint64_t)slot_tx) * (uint64_t)fp->samples_per_slot;
+ LOG_D(PHY,"RU %d/%d TST %llu, frame %d, subframe %d\n",ru->idx,0,(long long unsigned int)proc->timestamp_tx,frame_tx,slot_tx);
+
+ // dump VCD output for first RU in list
+ if (ru == RC.ru[0]) {
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame_tx );
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot_tx );
+ }
+
+ if (ru->feptx_ofdm) ru->feptx_ofdm(ru);
+
+ if (ru->fh_south_out) ru->fh_south_out(ru);
+}
+
+void fh_if5_north_out(RU_t *ru) {
+ RU_proc_t *proc=&ru->proc;
+ uint8_t seqno=0;
+ /// **** send_IF5 of rxdata to BBU **** ///
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 );
+ send_IF5(ru, proc->timestamp_rx, proc->tti_rx, &seqno, IF5_RRH_GW_UL);
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 );
+}
+
+// RRU IF4p5 northbound interface (RX)
+void fh_if4p5_north_out(RU_t *ru) {
+ RU_proc_t *proc=&ru->proc;
+
+ //NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ //const int subframe = proc->tti_rx;
+ if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx );
+
+ /*
+ if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) {
+ /// **** in TDD during DL send_IF4 of ULTICK to RCC **** ///
+ send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULTICK);
+ return;
+ }*/
+ start_meas(&ru->tx_fhaul);
+ send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULFFT);
+ stop_meas(&ru->tx_fhaul);
+}
+
+static void *emulatedRF_thread(void *param) {
+ RU_proc_t *proc = (RU_proc_t *) param;
+ int microsec = 500; // length of time to sleep, in miliseconds
+ struct timespec req = {0};
+ req.tv_sec = 0;
+ req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2;
+ wait_sync("emulatedRF_thread");
+
+ while(!oai_exit) {
+ nanosleep(&req, (struct timespec *)NULL);
+ pthread_mutex_lock(&proc->mutex_emulateRF);
+ ++proc->instance_cnt_emulateRF;
+ pthread_mutex_unlock(&proc->mutex_emulateRF);
+ pthread_cond_signal(&proc->cond_emulateRF);
+ }
+
+ return 0;
+}
+
+void rx_rf(RU_t *ru,int *frame,int *slot) {
+ RU_proc_t *proc = &ru->proc;
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ void *rxp[ru->nb_rx];
+ unsigned int rxs;
+ int i;
+ openair0_timestamp ts,old_ts;
+ AssertFatal(*slotslots_per_frame && *slot>=0, "slot %d is illegal (%d)\n",*slot,fp->slots_per_frame);
+
+ for (i=0; inb_rx; i++)
+ rxp[i] = (void *)&ru->common.rxdata[i][*slot*fp->samples_per_slot];
+
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
+ old_ts = proc->timestamp_rx;
+ LOG_D(PHY,"Reading %d samples for slot %d (%p)\n",fp->samples_per_slot,*slot,rxp[0]);
+
+ if(emulate_rf) {
+ wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
+ release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
+ rxs = fp->samples_per_slot;
+ ts = old_ts + rxs;
+ } else {
+ rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
+ &ts,
+ rxp,
+ fp->samples_per_slot,
+ ru->nb_rx);
+ }
+
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
+ proc->timestamp_rx = ts-ru->ts_offset;
+
+ //AssertFatal(rxs == fp->samples_per_subframe,
+ //"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_subframe,rxs);
+ if (rxs != fp->samples_per_slot) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_slot,rxs);
+
+ if (proc->first_rx == 1) {
+ ru->ts_offset = proc->timestamp_rx;
+ proc->timestamp_rx = 0;
+ } else {
+ if (proc->timestamp_rx - old_ts != fp->samples_per_slot) {
+ LOG_I(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - fp->samples_per_slot,ru->ts_offset);
+ ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_slot);
+ proc->timestamp_rx = ts-ru->ts_offset;
+ }
+ }
+
+ proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_slot*fp->slots_per_frame))&1023;
+ proc->tti_rx = (proc->timestamp_rx / fp->samples_per_slot)%fp->slots_per_frame;
+ // synchronize first reception to frame 0 subframe 0
+ proc->timestamp_tx = proc->timestamp_rx+(sl_ahead*fp->samples_per_slot);
+ proc->tti_tx = (proc->tti_rx+sl_ahead)%fp->slots_per_frame;
+ proc->frame_tx = (proc->tti_rx>(fp->slots_per_frame-1-sl_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
+ LOG_I(PHY,"RU %d/%d TS %llu (off %d), frame %d, slot %d.%d / %d\n",
+ ru->idx,
+ 0,
+ (unsigned long long int)proc->timestamp_rx,
+ (int)ru->ts_offset,proc->frame_rx,proc->tti_rx,proc->tti_tx,fp->slots_per_frame);
+
+ // dump VCD output for first RU in list
+ if (ru == RC.ru[0]) {
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, proc->frame_rx );
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx );
+ }
+
+ if (proc->first_rx == 0) {
+ if (proc->tti_rx != *slot) {
+ LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",(long long unsigned int)proc->timestamp_rx,proc->tti_rx,*slot);
+ exit_fun("Exiting");
+ }
+
+ if (proc->frame_rx != *frame) {
+ LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",(long long unsigned int)proc->timestamp_rx,proc->frame_rx,*frame);
+ exit_fun("Exiting");
+ }
+ } else {
+ proc->first_rx = 0;
+ *frame = proc->frame_rx;
+ *slot = proc->tti_rx;
+ }
+
+ //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
+
+ if (rxs != fp->samples_per_slot) {
+ //exit_fun( "problem receiving samples" );
+ LOG_E(PHY, "problem receiving samples\n");
+ }
+}
+
+
+void tx_rf(RU_t *ru) {
+ RU_proc_t *proc = &ru->proc;
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ nfapi_nr_config_request_t *cfg = &ru->gNB_list[0]->gNB_config;
+ void *txp[ru->nb_tx];
+ unsigned int txs;
+ int i;
+ T(T_ENB_PHY_OUTPUT_SIGNAL, T_INT(0), T_INT(0), T_INT(proc->frame_tx), T_INT(proc->tti_tx),
+ T_INT(0), T_BUFFER(&ru->common.txdata[0][proc->tti_tx * fp->samples_per_slot], fp->samples_per_slot * 4));
+ nr_subframe_t SF_type = nr_slot_select(cfg,proc->tti_tx%fp->slots_per_frame);
+ int sf_extension = 0;
+
+ if ((SF_type == SF_DL) ||
+ (SF_type == SF_S)) {
+ int siglen=fp->samples_per_slot,flags=1;
+ /*
+ if (SF_type == SF_S) {
+ siglen = fp->dl_symbols_in_S_subframe*(fp->ofdm_symbol_size+fp->nb_prefix_samples0);
+ flags=3; // end of burst
+ }
+ if ((fp->frame_type == TDD) &&
+ (SF_type == SF_DL)&&
+ (prevSF_type == SF_UL) &&
+ (nextSF_type == SF_DL)) {
+ flags = 2; // start of burst
+ sf_extension = ru->N_TA_offset<<1;
+ }
+
+ if ((cfg->subframe_config.duplex_mode == TDD) &&
+ (SF_type == SF_DL)&&
+ (prevSF_type == SF_UL) &&
+ (nextSF_type == SF_UL)) {
+ flags = 4; // start of burst and end of burst (only one DL SF between two UL)
+ sf_extension = ru->N_TA_offset<<1;
+ } */
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, proc->tti_tx );
+
+ for (i=0; inb_tx; i++)
+ txp[i] = (void *)&ru->common.txdata[i][(proc->tti_tx*fp->samples_per_slot)-sf_extension];
+
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (proc->timestamp_tx-ru->openair0_cfg.tx_sample_advance)&0xffffffff );
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
+ // prepare tx buffer pointers
+ txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
+ proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension,
+ txp,
+ siglen+sf_extension,
+ ru->nb_tx,
+ flags);
+ LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx,
+ (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->tti_tx);
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
+ AssertFatal(txs == siglen+sf_extension,"TX : Timeout (sent %d/%d)\n",txs, siglen);
+ }
+}
+
+
+/*!
+ * \brief The Asynchronous RX/TX FH thread of RAU/RCC/gNB/RRU.
+ * This handles the RX FH for an asynchronous RRU/UE
+ * \param param is a \ref gNB_L1_proc_t structure which contains the info what to process.
+ * \returns a pointer to an int. The storage is not on the heap and must not be freed.
+ */
+static void *ru_thread_asynch_rxtx( void *param ) {
+ static int ru_thread_asynch_rxtx_status;
+ RU_t *ru = (RU_t *)param;
+ RU_proc_t *proc = &ru->proc;
+ int subframe=0, frame=0;
+ // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe
+ wait_sync("ru_thread_asynch_rxtx");
+ // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe
+ printf( "waiting for devices (ru_thread_asynch_rx)\n");
+ wait_on_condition(&proc->mutex_asynch_rxtx,&proc->cond_asynch_rxtx,&proc->instance_cnt_asynch_rxtx,"thread_asynch");
+ printf( "devices ok (ru_thread_asynch_rx)\n");
+
+ while (!oai_exit) {
+ if (oai_exit) break;
+
+ if (subframe==9) {
+ subframe=0;
+ frame++;
+ frame&=1023;
+ } else {
+ subframe++;
+ }
+
+ LOG_D(PHY,"ru_thread_asynch_rxtx: Waiting on incoming fronthaul\n");
+
+ // asynchronous receive from south (Mobipass)
+ if (ru->fh_south_asynch_in) ru->fh_south_asynch_in(ru,&frame,&subframe);
+ // asynchronous receive from north (RRU IF4/IF5)
+ else if (ru->fh_north_asynch_in) {
+ if (nr_slot_select(&ru->gNB_list[0]->gNB_config,subframe)!=SF_UL)
+ ru->fh_north_asynch_in(ru,&frame,&subframe);
+ } else AssertFatal(1==0,"Unknown function in ru_thread_asynch_rxtx\n");
+ }
+
+ ru_thread_asynch_rxtx_status=0;
+ return(&ru_thread_asynch_rxtx_status);
+}
+
+
+
+
+/*!
+ * \brief The prach receive thread of RU.
+ * \param param is a \ref RU_proc_t structure which contains the info what to process.
+ * \returns a pointer to an int. The storage is not on the heap and must not be freed.
+ */
+static void *ru_thread_prach( void *param ) {
+ static int ru_thread_prach_status;
+ RU_t *ru = (RU_t *)param;
+ RU_proc_t *proc = (RU_proc_t *)&ru->proc;
+ // set default return value
+ ru_thread_prach_status = 0;
+
+ while (RC.ru_mask>0) {
+ usleep(1e6);
+ LOG_I(PHY,"%s() RACH waiting for RU to be configured\n", __FUNCTION__);
+ }
+
+ LOG_I(PHY,"%s() RU configured - RACH processing thread running\n", __FUNCTION__);
+
+ while (!oai_exit) {
+ if (oai_exit) break;
+
+ if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
+
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );
+
+ /*if (ru->gNB_list[0]){
+ prach_procedures(
+ ru->gNB_list[0]
+ #if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+ ,0
+ #endif
+ );
+ }
+ else {
+ rx_prach(NULL,
+ ru,
+ NULL,
+ NULL,
+ NULL,
+ proc->frame_prach,
+ 0
+ #if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+ ,0
+ #endif
+ );
+ }
+ VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 ); */
+ if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
+ }
+
+ LOG_I(PHY, "Exiting RU thread PRACH\n");
+ ru_thread_prach_status = 0;
+ return &ru_thread_prach_status;
+}
+
+
+int wakeup_synch(RU_t *ru) {
+ struct timespec wait;
+ wait.tv_sec=0;
+ wait.tv_nsec=5000000L;
+
+ // wake up synch thread
+ // lock the synch mutex and make sure the thread is ready
+ if (pthread_mutex_timedlock(&ru->proc.mutex_synch,&wait) != 0) {
+ LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU synch thread (IC %d)\n", ru->proc.instance_cnt_synch );
+ exit_fun( "error locking mutex_synch" );
+ return(-1);
+ }
+
+ ++ru->proc.instance_cnt_synch;
+
+ // the thread can now be woken up
+ if (pthread_cond_signal(&ru->proc.cond_synch) != 0) {
+ LOG_E( PHY, "[RU] ERROR pthread_cond_signal for RU synch thread\n");
+ exit_fun( "ERROR pthread_cond_signal" );
+ return(-1);
+ }
+
+ pthread_mutex_unlock( &ru->proc.mutex_synch );
+ return(0);
+}
+
+void do_ru_synch(RU_t *ru) {
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ RU_proc_t *proc = &ru->proc;
+ int i;
+ void *rxp[2],*rxp2[2];
+ int32_t dummy_rx[ru->nb_rx][fp->samples_per_subframe] __attribute__((aligned(32)));
+ int rxs;
+ int ic;
+
+ // initialize the synchronization buffer to the common_vars.rxdata
+ for (int i=0; inb_rx; i++)
+ rxp[i] = &ru->common.rxdata[i][0];
+
+ double temp_freq1 = ru->rfdevice.openair0_cfg->rx_freq[0];
+ double temp_freq2 = ru->rfdevice.openair0_cfg->tx_freq[0];
+
+ for (i=0; i<4; i++) {
+ ru->rfdevice.openair0_cfg->rx_freq[i] = ru->rfdevice.openair0_cfg->tx_freq[i];
+ ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq1;
+ }
+
+ ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0);
+
+ while ((ru->in_synch ==0)&&(!oai_exit)) {
+ // read in frame
+ rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
+ &(proc->timestamp_rx),
+ rxp,
+ fp->samples_per_subframe*10,
+ ru->nb_rx);
+
+ if (rxs != fp->samples_per_subframe*10) LOG_E(PHY,"requested %d samples, got %d\n",fp->samples_per_subframe*10,rxs);
+
+ // wakeup synchronization processing thread
+ wakeup_synch(ru);
+ ic=0;
+
+ while ((ic>=0)&&(!oai_exit)) {
+ // continuously read in frames, 1ms at a time,
+ // until we are done with the synchronization procedure
+ for (i=0; inb_rx; i++)
+ rxp2[i] = (void *)&dummy_rx[i][0];
+
+ for (i=0; i<10; i++)
+ rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
+ &(proc->timestamp_rx),
+ rxp2,
+ fp->samples_per_subframe,
+ ru->nb_rx);
+
+ pthread_mutex_lock(&ru->proc.mutex_synch);
+ ic = ru->proc.instance_cnt_synch;
+ pthread_mutex_unlock(&ru->proc.mutex_synch);
+ } // ic>=0
+ } // in_synch==0
+
+ // read in rx_offset samples
+ LOG_I(PHY,"Resynchronizing by %d samples\n",ru->rx_offset);
+ rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
+ &(proc->timestamp_rx),
+ rxp,
+ ru->rx_offset,
+ ru->nb_rx);
+
+ for (i=0; i<4; i++) {
+ ru->rfdevice.openair0_cfg->rx_freq[i] = temp_freq1;
+ ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq2;
+ }
+
+ ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0);
+}
+
+
+
+void wakeup_gNB_L1s(RU_t *ru) {
+ int i;
+ PHY_VARS_gNB **gNB_list = ru->gNB_list;
+ LOG_D(PHY,"wakeup_gNB_L1s (num %d) for RU %d ru->gNB_top:%p\n",ru->num_gNB,ru->idx, ru->gNB_top);
+
+ if (ru->num_gNB==1 && ru->gNB_top!=0 && get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) {
+ // call gNB function directly
+ char string[20];
+ sprintf(string,"Incoming RU %d",ru->idx);
+ LOG_D(PHY,"RU %d Call gNB_top\n",ru->idx);
+ ru->gNB_top(gNB_list[0],ru->proc.frame_rx,ru->proc.tti_rx,string,ru);
+ } else {
+ LOG_D(PHY,"ru->num_gNB:%d\n", ru->num_gNB);
+
+ for (i=0; inum_gNB; i++) {
+ LOG_D(PHY,"ru->wakeup_rxtx:%p\n", ru->nr_wakeup_rxtx);
+
+ if (ru->nr_wakeup_rxtx!=0 && ru->nr_wakeup_rxtx(gNB_list[i],ru) < 0) {
+ LOG_E(PHY,"could not wakeup gNB rxtx process for subframe %d\n", ru->proc.tti_rx);
+ }
+ }
+ }
+}
+
+static inline int wakeup_prach_ru(RU_t *ru) {
+ struct timespec wait;
+ wait.tv_sec=0;
+ wait.tv_nsec=5000000L;
+
+ if (pthread_mutex_timedlock(&ru->proc.mutex_prach,&wait) !=0) {
+ LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread (IC %d)\n", ru->proc.instance_cnt_prach);
+ exit_fun( "error locking mutex_rxtx" );
+ return(-1);
+ }
+
+ if (ru->proc.instance_cnt_prach==-1) {
+ ++ru->proc.instance_cnt_prach;
+ ru->proc.frame_prach = ru->proc.frame_rx;
+ ru->proc.subframe_prach = ru->proc.tti_rx;
+
+ // DJP - think prach_procedures() is looking at gNB frame_prach
+ if (ru->gNB_list[0]) {
+ ru->gNB_list[0]->proc.frame_prach = ru->proc.frame_rx;
+ ru->gNB_list[0]->proc.slot_prach = ru->proc.tti_rx;
+ }
+
+ LOG_I(PHY,"RU %d: waking up PRACH thread\n",ru->idx);
+ // the thread can now be woken up
+ AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n");
+ } else LOG_W(PHY,"RU prach thread busy, skipping\n");
+
+ pthread_mutex_unlock( &ru->proc.mutex_prach );
+ return(0);
+}
+
+// this is for RU with local RF unit
+void fill_rf_config(RU_t *ru, char *rf_config_file) {
+ int i;
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ nfapi_nr_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config; //tmp index
+ openair0_config_t *cfg = &ru->openair0_cfg;
+ int N_RB = gNB_config->rf_config.dl_carrier_bandwidth.value;
+ int mu = gNB_config->subframe_config.numerology_index_mu.value;
+
+ if (mu == NR_MU_0) { //or if LTE
+ if(N_RB == 100) {
+ if (fp->threequarter_fs) {
+ cfg->sample_rate=23.04e6;
+ cfg->samples_per_frame = 230400;
+ cfg->tx_bw = 10e6;
+ cfg->rx_bw = 10e6;
+ } else {
+ cfg->sample_rate=30.72e6;
+ cfg->samples_per_frame = 307200;
+ cfg->tx_bw = 10e6;
+ cfg->rx_bw = 10e6;
+ }
+ } else if(N_RB == 50) {
+ cfg->sample_rate=15.36e6;
+ cfg->samples_per_frame = 153600;
+ cfg->tx_bw = 5e6;
+ cfg->rx_bw = 5e6;
+ } else if (N_RB == 25) {
+ cfg->sample_rate=7.68e6;
+ cfg->samples_per_frame = 76800;
+ cfg->tx_bw = 2.5e6;
+ cfg->rx_bw = 2.5e6;
+ } else if (N_RB == 6) {
+ cfg->sample_rate=1.92e6;
+ cfg->samples_per_frame = 19200;
+ cfg->tx_bw = 1.5e6;
+ cfg->rx_bw = 1.5e6;
+ } else AssertFatal(1==0,"Unknown N_RB %d\n",N_RB);
+ } else if (mu == NR_MU_1) {
+ if(N_RB == 217) {
+ if (fp->threequarter_fs) {
+ cfg->sample_rate=92.16e6;
+ cfg->samples_per_frame = 921600;
+ cfg->tx_bw = 40e6;
+ cfg->rx_bw = 40e6;
+ } else {
+ cfg->sample_rate=122.88e6;
+ cfg->samples_per_frame = 1228800;
+ cfg->tx_bw = 40e6;
+ cfg->rx_bw = 40e6;
+ }
+ } else if(N_RB == 106) {
+ cfg->sample_rate=61.44e6;
+ cfg->samples_per_frame = 614400;
+ cfg->tx_bw = 20e6;
+ cfg->rx_bw = 20e6;
+ } else {
+ AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",N_RB,mu);
+ }
+ } else {
+ AssertFatal(0 == 1,"Numerology %d not supported for the moment\n",mu);
+ }
+
+ if (gNB_config->subframe_config.duplex_mode.value==TDD)
+ cfg->duplex_mode = duplex_mode_TDD;
+ else //FDD
+ cfg->duplex_mode = duplex_mode_FDD;
+
+ cfg->Mod_id = 0;
+ cfg->num_rb_dl=N_RB;
+ cfg->tx_num_channels=ru->nb_tx;
+ cfg->rx_num_channels=ru->nb_rx;
+
+ for (i=0; inb_tx; i++) {
+ cfg->tx_freq[i] = (double)fp->dl_CarrierFreq;
+ cfg->rx_freq[i] = (double)fp->ul_CarrierFreq;
+ cfg->tx_gain[i] = ru->att_tx;
+ cfg->rx_gain[i] = ru->max_rxgain-ru->att_rx;
+ cfg->configFilename = rf_config_file;
+ printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n",
+ i, cfg->tx_gain[i],
+ cfg->rx_gain[i],
+ cfg->tx_freq[i],
+ cfg->rx_freq[i]);
+ }
+}
+
+/* this function maps the RU tx and rx buffers to the available rf chains.
+ Each rf chain is is addressed by the card number and the chain on the card. The
+ rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple
+ antennas are mapped to successive RF chains on the same card. */
+int setup_RU_buffers(RU_t *ru) {
+ int i,j;
+ int card,ant;
+ //uint16_t N_TA_offset = 0;
+ NR_DL_FRAME_PARMS *frame_parms;
+ //nfapi_nr_config_request_t *gNB_config = ru->gNB_list[0]->gNB_config; //tmp index
+
+ if (ru) {
+ frame_parms = ru->nr_frame_parms;
+ printf("setup_RU_buffers: frame_parms = %p\n",frame_parms);
+ } else {
+ printf("RU[%d] not initialized\n", ru->idx);
+ return(-1);
+ }
+
+ /* if (frame_parms->frame_type == TDD) {
+ if (frame_parms->N_RB_DL == 100) ru->N_TA_offset = 624;
+ else if (frame_parms->N_RB_DL == 50) ru->N_TA_offset = 624/2;
+ else if (frame_parms->N_RB_DL == 25) ru->N_TA_offset = 624/4;
+ } */
+ if (ru->openair0_cfg.mmapped_dma == 1) {
+ // replace RX signal buffers with mmaped HW versions
+ for (i=0; inb_rx; i++) {
+ card = i/4;
+ ant = i%4;
+ printf("Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
+ free(ru->common.rxdata[i]);
+ ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant];
+ printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]);
+
+ for (j=0; j<16; j++) {
+ printf("rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]);
+ ru->common.rxdata[i][j] = 16-j;
+ }
+ }
+
+ for (i=0; inb_tx; i++) {
+ card = i/4;
+ ant = i%4;
+ printf("Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
+ free(ru->common.txdata[i]);
+ ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant];
+ printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]);
+
+ for (j=0; j<16; j++) {
+ printf("txbuffer %d: %x\n",j,ru->common.txdata[i][j]);
+ ru->common.txdata[i][j] = 16-j;
+ }
+ }
+ } else { // not memory-mapped DMA
+ //nothing to do, everything already allocated in lte_init
+ }
+
+ return(0);
+}
+
+static void *ru_stats_thread(void *param) {
+ RU_t *ru = (RU_t *)param;
+ wait_sync("ru_stats_thread");
+
+ while (!oai_exit) {
+ sleep(1);
+
+ if (opp_enabled == 1) {
+ if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx",NULL,NULL);
+
+ if (ru->feptx_ofdm) print_meas(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL);
+
+ if (ru->fh_north_asynch_in) print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL);
+
+ if (ru->fh_north_out) {
+ print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL);
+ print_meas(&ru->compression,"compression",NULL,NULL);
+ print_meas(&ru->transport,"transport",NULL,NULL);
+ }
+ }
+ }
+
+ return(NULL);
+}
+
+static void *ru_thread_tx( void *param ) {
+ RU_t *ru = (RU_t *)param;
+ RU_proc_t *proc = &ru->proc;
+ PHY_VARS_gNB *gNB;
+ gNB_L1_proc_t *gNB_proc;
+ gNB_L1_rxtx_proc_t *L1_proc;
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ char filename[40];
+ int print_frame = 8;
+ int i = 0;
+ cpu_set_t cpuset;
+ CPU_ZERO(&cpuset);
+ //CPU_SET(5, &cpuset);
+ //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
+ //wait_sync("ru_thread_tx");
+ wait_on_condition(&proc->mutex_FH1,&proc->cond_FH1,&proc->instance_cnt_FH1,"ru_thread_tx");
+ printf( "ru_thread_tx ready\n");
+
+ while (!oai_exit) {
+ if (oai_exit) break;
+
+ LOG_I(PHY,"ru_thread_tx: Waiting for TX processing\n");
+ // wait until eNBs are finished subframe RX n and TX n+4
+ wait_on_condition(&proc->mutex_gNBs,&proc->cond_gNBs,&proc->instance_cnt_gNBs,"ru_thread_tx");
+
+ if (oai_exit) break;
+
+ //printf("~~~~~~~~~~~~~~~~start process for ru_thread_tx %d.%d\n", proc->frame_tx, proc->tti_tx);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, proc->tti_tx );
+
+ // do TX front-end processing if needed (precoding and/or IDFTs)
+ if (ru->feptx_prec) ru->feptx_prec(ru);
+
+ // do OFDM if needed
+ if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
+
+ if(!emulate_rf) {
+ // do outgoing fronthaul (south) if needed
+ if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
+
+ if (ru->fh_north_out) ru->fh_north_out(ru);
+ } else {
+ if(proc->frame_tx == print_frame) {
+ for (i=0; inb_tx; i++) {
+ sprintf(filename,"tx%ddataF_frame%d_sl%d.m", i, print_frame, proc->tti_tx);
+ LOG_M(filename,"txdataF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_subframe_wCP, 1, 1);
+
+ if(proc->tti_tx == 9) {
+ sprintf(filename,"tx%ddata_frame%d.m", i, print_frame);
+ LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1);
+ sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame);
+ FILE *output_fd = fopen(filename,"w");
+
+ if (output_fd) {
+ fwrite(&ru->common.txdata[i][0],
+ sizeof(int32_t),
+ fp->samples_per_frame,
+ output_fd);
+ fclose(output_fd);
+ } else {
+ LOG_E(PHY,"Cannot write to file %s\n",filename);
+ }
+ }//if(proc->tti_tx == 9)
+ }//for (i=0; inb_tx; i++)
+ }//if(proc->frame_tx == print_frame)
+ }//else emulate_rf
+
+ release_thread(&proc->mutex_gNBs,&proc->instance_cnt_gNBs,"ru_thread_tx");
+
+ for(i = 0; inum_gNB; i++) {
+ gNB = ru->gNB_list[i];
+ gNB_proc = &gNB->proc;
+ L1_proc = (get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)? &gNB_proc->L1_proc_tx : &gNB_proc->L1_proc;
+ pthread_mutex_lock(&gNB_proc->mutex_RU_tx);
+
+ for (int j=0; jnum_RU; j++) {
+ if (ru == gNB->RU_list[j]) {
+ if ((gNB_proc->RU_mask_tx&(1< 0)
+ LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU tx %d (num_RU %d,mask %x) has not been served yet!\n",
+ gNB->Mod_id,gNB_proc->frame_rx,gNB_proc->slot_rx,ru->idx,gNB->num_RU,gNB_proc->RU_mask_tx);
+
+ gNB_proc->RU_mask_tx |= (1<RU_mask_tx != (1<num_RU)-1) { // not all RUs have provided their information so return
+ pthread_mutex_unlock(&gNB_proc->mutex_RU_tx);
+ } else { // all RUs TX are finished so send the ready signal to eNB processing
+ gNB_proc->RU_mask_tx = 0;
+ pthread_mutex_unlock(&gNB_proc->mutex_RU_tx);
+ pthread_mutex_lock( &L1_proc->mutex_RUs);
+ L1_proc->instance_cnt_RUs = 0;
+
+ // the thread can now be woken up
+ if (pthread_cond_signal(&L1_proc->cond_RUs) != 0) {
+ LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n");
+ exit_fun( "ERROR pthread_cond_signal" );
+ }
+
+ pthread_mutex_unlock( &L1_proc->mutex_RUs );
+ }
+ }
+ }
+
+ release_thread(&proc->mutex_FH1,&proc->instance_cnt_FH1,"ru_thread_tx");
+ return 0;
+}
+
+static void *ru_thread( void *param ) {
+ static int ru_thread_status;
+ RU_t *ru = (RU_t *)param;
+ RU_proc_t *proc = &ru->proc;
+ NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
+ int ret;
+ int slot = fp->slots_per_frame-1;
+ int frame =1023;
+ char filename[40],threadname[40];
+ int print_frame = 8;
+ int i = 0;
+ // set default return value
+ ru_thread_status = 0;
+ // set default return value
+ sprintf(threadname,"ru_thread %d",ru->idx);
+ LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]);
+
+ if(emulate_rf) {
+ fill_rf_config(ru,ru->rf_config_file);
+ nr_init_frame_parms(&ru->gNB_list[0]->gNB_config, fp);
+ nr_dump_frame_parms(fp);
+ nr_phy_init_RU(ru);
+
+ if (setup_RU_buffers(ru)!=0) {
+ printf("Exiting, cannot initialize RU Buffers\n");
+ exit(-1);
+ }
+ } else {
+ // Start IF device if any
+ if (ru->start_if) {
+ LOG_I(PHY,"Starting IF interface for RU %d\n",ru->idx);
+ AssertFatal(ru->start_if(ru,NULL) == 0, "Could not start the IF device\n");
+
+ if (ru->if_south == LOCAL_RF) ret = connect_rau(ru);
+ else ret = attach_rru(ru);
+
+ AssertFatal(ret==0,"Cannot connect to remote radio\n");
+ }
+
+ if (ru->if_south == LOCAL_RF) { // configure RF parameters only
+ fill_rf_config(ru,ru->rf_config_file);
+ nr_init_frame_parms(&ru->gNB_list[0]->gNB_config, fp);
+ nr_dump_frame_parms(fp);
+ nr_phy_init_RU(ru);
+ ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
+ AssertFatal(ret==0,"Cannot connect to local radio\n");
+ }
+
+ if (setup_RU_buffers(ru)!=0) {
+ printf("Exiting, cannot initialize RU Buffers\n");
+ exit(-1);
+ }
+ }
+
+ LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx);
+ pthread_mutex_lock(&RC.ru_mutex);
+ RC.ru_mask &= ~(1<idx);
+ pthread_cond_signal(&RC.ru_cond);
+ pthread_mutex_unlock(&RC.ru_mutex);
+ wait_sync("ru_thread");
+
+ if(!emulate_rf) {
+ // Start RF device if any
+ if (ru->start_rf) {
+ if (ru->start_rf(ru) != 0)
+ LOG_E(HW,"Could not start the RF device\n");
+ else LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
+ } else LOG_I(PHY,"RU %d no rf device\n",ru->idx);
+
+ // if an asnych_rxtx thread exists
+ // wakeup the thread because the devices are ready at this point
+
+ if ((ru->fh_south_asynch_in)||(ru->fh_north_asynch_in)) {
+ pthread_mutex_lock(&proc->mutex_asynch_rxtx);
+ proc->instance_cnt_asynch_rxtx=0;
+ pthread_mutex_unlock(&proc->mutex_asynch_rxtx);
+ pthread_cond_signal(&proc->cond_asynch_rxtx);
+ } else LOG_I(PHY,"RU %d no asynch_south interface\n",ru->idx);
+
+ // if this is a slave RRU, try to synchronize on the DL frequency
+ if ((ru->is_slave) && (ru->if_south == LOCAL_RF)) do_ru_synch(ru);
+ }
+
+ pthread_mutex_lock(&proc->mutex_FH1);
+ proc->instance_cnt_FH1 = 0;
+ pthread_mutex_unlock(&proc->mutex_FH1);
+ pthread_cond_signal(&proc->cond_FH1);
+
+ // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
+ while (!oai_exit) {
+ // these are local subframe/frame counters to check that we are in synch with the fronthaul timing.
+ // They are set on the first rx/tx in the underly FH routines.
+ if (slot==(fp->slots_per_frame-1)) {
+ slot=0;
+ frame++;
+ frame&=1023;
+ } else {
+ slot++;
+ }
+
+ // synchronization on input FH interface, acquire signals/data and block
+ if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&slot);
+ else AssertFatal(1==0, "No fronthaul interface at south port");
+
+ LOG_D(PHY,"AFTER fh_south_in - SFN/SL:%d%d RU->proc[RX:%d.%d TX:%d.%d] RC.gNB[0][0]:[RX:%d%d TX(SFN):%d]\n",
+ frame,slot,
+ proc->frame_rx,proc->tti_rx,
+ proc->frame_tx,proc->tti_tx,
+ RC.gNB[0][0]->proc.frame_rx,RC.gNB[0][0]->proc.slot_rx,
+ RC.gNB[0][0]->proc.frame_tx);
+ /*
+ LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n",
+ ru->do_prach,
+ is_prach_subframe(fp, proc->frame_rx, proc->tti_rx),
+ proc->frame_rx,proc->tti_rx);
+
+ if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->tti_rx)==1)) {
+ wakeup_prach_ru(ru);
+ }*/
+
+ // adjust for timing offset between RU
+ //printf("~~~~~~~~~~~~~~~~~~~~~~~~~~%d.%d in ru_thread is in process\n", proc->frame_rx, proc->tti_rx);
+ if (ru->idx!=0) proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023;
+
+ // do RX front-end processing (frequency-shift, dft) if needed
+ if (ru->feprx) ru->feprx(ru);
+
+ // At this point, all information for subframe has been received on FH interface
+
+ // wakeup all gNB processes waiting for this RU
+ if (ru->num_gNB>0) wakeup_gNB_L1s(ru);
+
+ if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD && ru->num_eNB==0) {
+ // do TX front-end processing if needed (precoding and/or IDFTs)
+ if (ru->feptx_prec) ru->feptx_prec(ru);
+
+ // do OFDM if needed
+ if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
+
+ if(!emulate_rf) {
+ // do outgoing fronthaul (south) if needed
+ if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
+
+ if (ru->fh_north_out) ru->fh_north_out(ru);
+ } else {
+ if(proc->frame_tx == print_frame) {
+ for (i=0; inb_tx; i++) {
+ sprintf(filename,"tx%ddataF_frame%d_sl%d.m", i, print_frame, proc->tti_tx);
+ LOG_M(filename,"txdataF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_slot_wCP, 1, 1);
+
+ if(proc->tti_tx == 9) {
+ sprintf(filename,"tx%ddata_frame%d.m", i, print_frame);
+ LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1);
+ sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame);
+ FILE *output_fd = fopen(filename,"w");
+
+ if (output_fd) {
+ fwrite(&ru->common.txdata[i][0],
+ sizeof(int32_t),
+ fp->samples_per_frame,
+ output_fd);
+ fclose(output_fd);
+ } else {
+ LOG_E(PHY,"Cannot write to file %s\n",filename);
+ }
+ }//if(proc->tti_tx == 9)
+ }//for (i=0; inb_tx; i++)
+ }//if(proc->frame_tx == print_frame)
+ }//else emulate_rf
+
+ proc->emulate_rf_busy = 0;
+ }//if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD)
+ }
+
+ printf( "Exiting ru_thread \n");
+
+ if (ru->stop_rf != NULL) {
+ if (ru->stop_rf(ru) != 0)
+ LOG_E(HW,"Could not stop the RF device\n");
+ else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx);
+ }
+
+ ru_thread_status = 0;
+ return &ru_thread_status;
+}
+/*
+// This thread run the initial synchronization like a UE
+void *ru_thread_synch(void *arg) {
+
+ RU_t *ru = (RU_t*)arg;
+ NR_DL_FRAME_PARMS *fp=ru->nr_frame_parms;
+ int32_t sync_pos,sync_pos2;
+ uint32_t peak_val;
+ uint32_t sync_corr[307200] __attribute__((aligned(32)));
+ static int ru_thread_synch_status;
+
+
+
+ wait_sync("ru_thread_synch");
+
+ // initialize variables for PSS detection
+ lte_sync_time_init(ru->nr_frame_parms);
+
+ while (!oai_exit) {
+
+ // wait to be woken up
+ if (wait_on_condition(&ru->proc.mutex_synch,&ru->proc.cond_synch,&ru->proc.instance_cnt_synch,"ru_thread_synch")<0) break;
+
+ // if we're not in synch, then run initial synch
+ if (ru->in_synch == 0) {
+ // run intial synch like UE
+ LOG_I(PHY,"Running initial synchronization\n");
+
+ sync_pos = lte_sync_time_gNB(ru->common.rxdata,
+ fp,
+ fp->samples_per_subframe*5,
+ &peak_val,
+ sync_corr);
+ LOG_I(PHY,"RU synch: %d, val %d\n",sync_pos,peak_val);
+
+ if (sync_pos >= 0) {
+ if (sync_pos >= fp->nb_prefix_samples)
+ sync_pos2 = sync_pos - fp->nb_prefix_samples;
+ else
+ sync_pos2 = sync_pos + (fp->samples_per_subframe*10) - fp->nb_prefix_samples;
+
+ if (fp->frame_type == FDD) {
+
+ // PSS is hypothesized in last symbol of first slot in Frame
+ int sync_pos_slot = (fp->samples_per_subframe>>1) - fp->ofdm_symbol_size - fp->nb_prefix_samples;
+
+ if (sync_pos2 >= sync_pos_slot)
+ ru->rx_offset = sync_pos2 - sync_pos_slot;
+ else
+ ru->rx_offset = (fp->samples_per_subframe*10) + sync_pos2 - sync_pos_slot;
+ }
+ else {
+
+ }
+
+ LOG_I(PHY,"Estimated sync_pos %d, peak_val %d => timing offset %d\n",sync_pos,peak_val,ru->rx_offset);
+
+ if ((peak_val > 300000) && (sync_pos > 0)) {
+ // if (sync_pos++ > 3) {
+ write_output("ru_sync.m","sync",(void*)&sync_corr[0],fp->samples_per_subframe*5,1,2);
+ write_output("ru_rx.m","rxs",(void*)ru->ru_time.rxdata[0][0],fp->samples_per_subframe*10,1,1);
+ exit(-1);
+ }
+
+ ru->in_synch=1;
+ }
+ }
+
+ if (release_thread(&ru->proc.mutex_synch,&ru->proc.instance_cnt_synch,"ru_synch_thread") < 0) break;
+ } // oai_exit
+
+ ru_thread_synch_status = 0;
+ return &ru_thread_synch_status;
+
+}
+*/
+
+int start_if(struct RU_t_s *ru,struct PHY_VARS_gNB_s *gNB) {
+ return(ru->ifdevice.trx_start_func(&ru->ifdevice));
+}
+
+int start_rf(RU_t *ru) {
+ return(ru->rfdevice.trx_start_func(&ru->rfdevice));
+}
+
+int stop_rf(RU_t *ru) {
+ ru->rfdevice.trx_end_func(&ru->rfdevice);
+ return 0;
+}
+
+extern void fep_full(RU_t *ru);
+extern void ru_fep_full_2thread(RU_t *ru);
+extern void nr_feptx_ofdm(RU_t *ru);
+extern void nr_feptx_ofdm_2thread(RU_t *ru);
+extern void feptx_prec(RU_t *ru);
+extern void init_fep_thread(RU_t *ru);
+extern void init_nr_feptx_thread(RU_t *ru);
+
+void init_RU_proc(RU_t *ru) {
+ int i=0;
+ RU_proc_t *proc;
+ char name[100];
+#ifndef OCP_FRAMEWORK
+ LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]);
+#endif
+ proc = &ru->proc;
+ memset((void *)proc,0,sizeof(RU_proc_t));
+ proc->ru = ru;
+ proc->instance_cnt_prach = -1;
+ proc->instance_cnt_synch = -1; ;
+ proc->instance_cnt_FH = -1;
+ proc->instance_cnt_FH1 = -1;
+ proc->instance_cnt_gNBs = -1;
+ proc->instance_cnt_asynch_rxtx = -1;
+ proc->instance_cnt_emulateRF = -1;
+ proc->first_rx = 1;
+ proc->first_tx = 1;
+ proc->frame_offset = 0;
+ proc->num_slaves = 0;
+ proc->frame_tx_unwrap = 0;
+
+ for (i=0; i<10; i++) proc->symbol_mask[i]=0;
+
+ pthread_mutex_init( &proc->mutex_prach, NULL);
+ pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL);
+ pthread_mutex_init( &proc->mutex_synch,NULL);
+ pthread_mutex_init( &proc->mutex_FH,NULL);
+ pthread_mutex_init( &proc->mutex_FH1,NULL);
+ pthread_mutex_init( &proc->mutex_emulateRF,NULL);
+ pthread_mutex_init( &proc->mutex_gNBs, NULL);
+ pthread_cond_init( &proc->cond_prach, NULL);
+ pthread_cond_init( &proc->cond_FH, NULL);
+ pthread_cond_init( &proc->cond_FH1, NULL);
+ pthread_cond_init( &proc->cond_emulateRF, NULL);
+ pthread_cond_init( &proc->cond_asynch_rxtx, NULL);
+ pthread_cond_init( &proc->cond_synch,NULL);
+ pthread_cond_init( &proc->cond_gNBs, NULL);
+ threadCreate( &proc->pthread_FH, ru_thread, (void *)ru, "thread_FH", -1, OAI_PRIORITY_RT_MAX );
+
+ if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)
+ threadCreate( &proc->pthread_FH1, ru_thread_tx, (void *)ru, "thread_FH1", -1, OAI_PRIORITY_RT );
+
+ if(emulate_rf)
+ threadCreate( &proc->pthread_emulateRF, emulatedRF_thread, (void *)proc, "emulateRF", -1, OAI_PRIORITY_RT );
+
+ if (ru->function == NGFI_RRU_IF4p5) {
+ threadCreate( &proc->pthread_prach, ru_thread_prach, (void *)ru, "RACH", -1, OAI_PRIORITY_RT );
+ ///tmp deactivation of synch thread
+ // if (ru->is_slave == 1) pthread_create( &proc->pthread_synch, attr_synch, ru_thread_synch, (void*)ru);
+
+ if ((ru->if_timing == synch_to_other) ||
+ (ru->function == NGFI_RRU_IF5) ||
+ (ru->function == NGFI_RRU_IF4p5)) threadCreate( &proc->pthread_asynch_rxtx, ru_thread_asynch_rxtx, (void *)ru, "asynch_rxtx", -1, OAI_PRIORITY_RT );
+
+ snprintf( name, sizeof(name), "ru_thread_FH %d", ru->idx );
+ pthread_setname_np( proc->pthread_FH, name );
+ } else if (ru->function == gNodeB_3GPP && ru->if_south == LOCAL_RF) { // DJP - need something else to distinguish between monolithic and PNF
+ LOG_I(PHY,"%s() DJP - added creation of pthread_prach\n", __FUNCTION__);
+ threadCreate( &proc->pthread_prach, ru_thread_prach, (void *)ru,"RACH", -1, OAI_PRIORITY_RT );
+ }
+
+ if (get_nprocs()>=2) {
+ if (ru->feprx) init_fep_thread(ru);
+
+ if (ru->feptx_ofdm) nr_init_feptx_thread(ru);
+ }
+
+ if (opp_enabled == 1) threadCreate(&ru->ru_stats_thread,ru_stats_thread,(void *)ru, "emulateRF", -1, OAI_PRIORITY_RT_LOW);
+}
+
+void kill_RU_proc(int inst) {
+ RU_t *ru = RC.ru[inst];
+ RU_proc_t *proc = &ru->proc;
+ pthread_mutex_lock(&proc->mutex_FH);
+ proc->instance_cnt_FH = 0;
+ pthread_mutex_unlock(&proc->mutex_FH);
+ pthread_cond_signal(&proc->cond_FH);
+ pthread_mutex_lock(&proc->mutex_prach);
+ proc->instance_cnt_prach = 0;
+ pthread_mutex_unlock(&proc->mutex_prach);
+ pthread_cond_signal(&proc->cond_prach);
+ pthread_mutex_lock(&proc->mutex_synch);
+ proc->instance_cnt_synch = 0;
+ pthread_mutex_unlock(&proc->mutex_synch);
+ pthread_cond_signal(&proc->cond_synch);
+ pthread_mutex_lock(&proc->mutex_gNBs);
+ proc->instance_cnt_gNBs = 0;
+ pthread_mutex_unlock(&proc->mutex_gNBs);
+ pthread_cond_signal(&proc->cond_gNBs);
+ pthread_mutex_lock(&proc->mutex_asynch_rxtx);
+ proc->instance_cnt_asynch_rxtx = 0;
+ pthread_mutex_unlock(&proc->mutex_asynch_rxtx);
+ pthread_cond_signal(&proc->cond_asynch_rxtx);
+ LOG_D(PHY, "Joining pthread_FH\n");
+ pthread_join(proc->pthread_FH, NULL);
+
+ if (ru->function == NGFI_RRU_IF4p5) {
+ LOG_D(PHY, "Joining pthread_prach\n");
+ pthread_join(proc->pthread_prach, NULL);
+
+ if (ru->is_slave) {
+ LOG_D(PHY, "Joining pthread_\n");
+ pthread_join(proc->pthread_synch, NULL);
+ }
+
+ if ((ru->if_timing == synch_to_other) ||
+ (ru->function == NGFI_RRU_IF5) ||
+ (ru->function == NGFI_RRU_IF4p5)) {
+ LOG_D(PHY, "Joining pthread_asynch_rxtx\n");
+ pthread_join(proc->pthread_asynch_rxtx, NULL);
+ }
+ }
+
+ if (get_nprocs() >= 2) {
+ if (ru->feprx) {
+ pthread_mutex_lock(&proc->mutex_fep);
+ proc->instance_cnt_fep = 0;
+ pthread_mutex_unlock(&proc->mutex_fep);
+ pthread_cond_signal(&proc->cond_fep);
+ LOG_D(PHY, "Joining pthread_fep\n");
+ pthread_join(proc->pthread_fep, NULL);
+ pthread_mutex_destroy(&proc->mutex_fep);
+ pthread_cond_destroy(&proc->cond_fep);
+ }
+
+ if (ru->feptx_ofdm) {
+ pthread_mutex_lock(&proc->mutex_feptx);
+ proc->instance_cnt_feptx = 0;
+ pthread_mutex_unlock(&proc->mutex_feptx);
+ pthread_cond_signal(&proc->cond_feptx);
+ LOG_D(PHY, "Joining pthread_feptx\n");
+ pthread_join(proc->pthread_feptx, NULL);
+ pthread_mutex_destroy(&proc->mutex_feptx);
+ pthread_cond_destroy(&proc->cond_feptx);
+ }
+ }
+
+ if (opp_enabled) {
+ LOG_D(PHY, "Joining ru_stats_thread\n");
+ pthread_join(ru->ru_stats_thread, NULL);
+ }
+
+ pthread_mutex_destroy(&proc->mutex_prach);
+ pthread_mutex_destroy(&proc->mutex_asynch_rxtx);
+ pthread_mutex_destroy(&proc->mutex_synch);
+ pthread_mutex_destroy(&proc->mutex_FH);
+ pthread_mutex_destroy(&proc->mutex_gNBs);
+ pthread_cond_destroy(&proc->cond_prach);
+ pthread_cond_destroy(&proc->cond_FH);
+ pthread_cond_destroy(&proc->cond_asynch_rxtx);
+ pthread_cond_destroy(&proc->cond_synch);
+ pthread_cond_destroy(&proc->cond_gNBs);
+}
+
+int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) {
+ FH_fmt_options_t fmt = cap->FH_fmt;
+ int i;
+ int found_band=0;
+ LOG_I(PHY,"RRU %d, num_bands %d, looking for band %d\n",ru->idx,cap->num_bands,ru->nr_frame_parms->eutra_band);
+
+ for (i=0; inum_bands; i++) {
+ LOG_I(PHY,"band %d on RRU %d\n",cap->band_list[i],ru->idx);
+
+ if (ru->nr_frame_parms->eutra_band == cap->band_list[i]) {
+ found_band=1;
+ break;
+ }
+ }
+
+ if (found_band == 0) {
+ LOG_I(PHY,"Couldn't find target EUTRA band %d on RRU %d\n",ru->nr_frame_parms->eutra_band,ru->idx);
+ return(-1);
+ }
+
+ switch (ru->if_south) {
+ case LOCAL_RF:
+ AssertFatal(1==0, "This RU should not have a local RF, exiting\n");
+ return(0);
+ break;
+
+ case REMOTE_IF5:
+ if (fmt == OAI_IF5_only || fmt == OAI_IF5_and_IF4p5) return(0);
+
+ break;
+
+ case REMOTE_IF4p5:
+ if (fmt == OAI_IF4p5_only || fmt == OAI_IF5_and_IF4p5) return(0);
+
+ break;
+
+ case REMOTE_MBP_IF5:
+ if (fmt == MBP_IF5) return(0);
+
+ break;
+
+ default:
+ LOG_I(PHY,"No compatible Fronthaul interface found for RRU %d\n", ru->idx);
+ return(-1);
+ }
+
+ return(-1);
+}
+
+
+char rru_format_options[4][20] = {"OAI_IF5_only","OAI_IF4p5_only","OAI_IF5_and_IF4p5","MBP_IF5"};
+
+char rru_formats[3][20] = {"OAI_IF5","MBP_IF5","OAI_IF4p5"};
+char ru_if_formats[4][20] = {"LOCAL_RF","REMOTE_OAI_IF5","REMOTE_MBP_IF5","REMOTE_OAI_IF4p5"};
+
+void configure_ru(int idx,
+ void *arg) {
+ RU_t *ru = RC.ru[idx];
+ RRU_config_t *config = (RRU_config_t *)arg;
+ RRU_capabilities_t *capabilities = (RRU_capabilities_t *)arg;
+ nfapi_nr_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config;
+ int ret;
+ LOG_I(PHY, "Received capabilities from RRU %d\n",idx);
+
+ if (capabilities->FH_fmt < MAX_FH_FMTs) LOG_I(PHY, "RU FH options %s\n",rru_format_options[capabilities->FH_fmt]);
+
+ AssertFatal((ret=check_capabilities(ru,capabilities)) == 0,
+ "Cannot configure RRU %d, check_capabilities returned %d\n", idx,ret);
+ // take antenna capabilities of RRU
+ ru->nb_tx = capabilities->nb_tx[0];
+ ru->nb_rx = capabilities->nb_rx[0];
+ // Pass configuration to RRU
+ LOG_I(PHY, "Using %s fronthaul (%d), band %d \n",ru_if_formats[ru->if_south],ru->if_south,ru->nr_frame_parms->eutra_band);
+ // wait for configuration
+ config->FH_fmt = ru->if_south;
+ config->num_bands = 1;
+ config->band_list[0] = ru->nr_frame_parms->eutra_band;
+ config->tx_freq[0] = ru->nr_frame_parms->dl_CarrierFreq;
+ config->rx_freq[0] = ru->nr_frame_parms->ul_CarrierFreq;
+ //config->tdd_config[0] = ru->nr_frame_parms->tdd_config;
+ //config->tdd_config_S[0] = ru->nr_frame_parms->tdd_config_S;
+ config->att_tx[0] = ru->att_tx;
+ config->att_rx[0] = ru->att_rx;
+ config->N_RB_DL[0] = gNB_config->rf_config.dl_carrier_bandwidth.value;
+ config->N_RB_UL[0] = gNB_config->rf_config.ul_carrier_bandwidth.value;
+ config->threequarter_fs[0] = ru->nr_frame_parms->threequarter_fs;
+ /* if (ru->if_south==REMOTE_IF4p5) {
+ config->prach_FreqOffset[0] = ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset;
+ config->prach_ConfigIndex[0] = ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
+ LOG_I(PHY,"REMOTE_IF4p5: prach_FrequOffset %d, prach_ConfigIndex %d\n",
+ config->prach_FreqOffset[0],config->prach_ConfigIndex[0]);*/
+ nr_init_frame_parms(&ru->gNB_list[0]->gNB_config, ru->nr_frame_parms);
+ nr_phy_init_RU(ru);
+}
+
+void configure_rru(int idx,
+ void *arg) {
+ RRU_config_t *config = (RRU_config_t *)arg;
+ RU_t *ru = RC.ru[idx];
+ nfapi_nr_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config;
+ ru->nr_frame_parms->eutra_band = config->band_list[0];
+ ru->nr_frame_parms->dl_CarrierFreq = config->tx_freq[0];
+ ru->nr_frame_parms->ul_CarrierFreq = config->rx_freq[0];
+
+ if (ru->nr_frame_parms->dl_CarrierFreq == ru->nr_frame_parms->ul_CarrierFreq) {
+ gNB_config->subframe_config.duplex_mode.value = TDD;
+ //ru->nr_frame_parms->tdd_config = config->tdd_config[0];
+ //ru->nr_frame_parms->tdd_config_S = config->tdd_config_S[0];
+ } else
+ gNB_config->subframe_config.duplex_mode.value = FDD;
+
+ ru->att_tx = config->att_tx[0];
+ ru->att_rx = config->att_rx[0];
+ gNB_config->rf_config.dl_carrier_bandwidth.value = config->N_RB_DL[0];
+ gNB_config->rf_config.ul_carrier_bandwidth.value = config->N_RB_UL[0];
+ ru->nr_frame_parms->threequarter_fs = config->threequarter_fs[0];
+
+ //ru->nr_frame_parms->pdsch_config_common.referenceSignalPower = ru->max_pdschReferenceSignalPower-config->att_tx[0];
+ if (ru->function==NGFI_RRU_IF4p5) {
+ ru->nr_frame_parms->att_rx = ru->att_rx;
+ ru->nr_frame_parms->att_tx = ru->att_tx;
+ /*
+ LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d, att (%d,%d)\n",
+ config->prach_FreqOffset[0],config->prach_ConfigIndex[0],ru->att_tx,ru->att_rx);
+ ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset = config->prach_FreqOffset[0];
+ ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex = config->prach_ConfigIndex[0]; */
+ }
+
+ fill_rf_config(ru,ru->rf_config_file);
+ nr_init_frame_parms(&ru->gNB_list[0]->gNB_config, ru->nr_frame_parms);
+ nr_phy_init_RU(ru);
+}
+
+/*
+void init_precoding_weights(PHY_VARS_gNB *gNB) {
+
+ int layer,ru_id,aa,re,ue,tb;
+ LTE_DL_FRAME_PARMS *fp=&gNB->frame_parms;
+ RU_t *ru;
+ LTE_gNB_DLSCH_t *dlsch;
+
+ // init precoding weigths
+ for (ue=0;uedlsch[ue][tb];
+ for (layer=0; layer<4; layer++) {
+ int nb_tx=0;
+ for (ru_id=0;ru_idnb_tx;
+ }
+ dlsch->ue_spec_bf_weights[layer] = (int32_t**)malloc16(nb_tx*sizeof(int32_t*));
+
+ for (aa=0; aaue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t));
+ for (re=0;reofdm_symbol_size; re++) {
+ dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff;
+ }
+ }
+ }
+ }
+ }
+}*/
+
+void set_function_spec_param(RU_t *ru) {
+ int ret;
+
+ switch (ru->if_south) {
+ case LOCAL_RF: // this is an RU with integrated RF (RRU, gNB)
+ if (ru->function == NGFI_RRU_IF5) { // IF5 RRU
+ ru->do_prach = 0; // no prach processing in RU
+ ru->fh_north_in = NULL; // no shynchronous incoming fronthaul from north
+ ru->fh_north_out = fh_if5_north_out; // need only to do send_IF5 reception
+ ru->fh_south_out = tx_rf; // send output to RF
+ ru->fh_north_asynch_in = fh_if5_north_asynch_in; // TX packets come asynchronously
+ ru->feprx = NULL; // nothing (this is a time-domain signal)
+ ru->feptx_ofdm = NULL; // nothing (this is a time-domain signal)
+ ru->feptx_prec = NULL; // nothing (this is a time-domain signal)
+ ru->start_if = start_if; // need to start the if interface for if5
+ ru->ifdevice.host_type = RRU_HOST;
+ ru->rfdevice.host_type = RRU_HOST;
+ ru->ifdevice.eth_params = &ru->eth_params;
+ reset_meas(&ru->rx_fhaul);
+ reset_meas(&ru->tx_fhaul);
+ reset_meas(&ru->compression);
+ reset_meas(&ru->transport);
+ ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
+ printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
+
+ if (ret<0) {
+ printf("Exiting, cannot initialize transport protocol\n");
+ exit(-1);
+ }
+ } else if (ru->function == NGFI_RRU_IF4p5) {
+ ru->do_prach = 1; // do part of prach processing in RU
+ ru->fh_north_in = NULL; // no synchronous incoming fronthaul from north
+ ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception
+ ru->fh_south_out = tx_rf; // send output to RF
+ ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously
+ ru->feprx = (get_nprocs()<=2) ? fep_full :ru_fep_full_2thread; // RX DFTs
+ ru->feptx_ofdm = (get_nprocs()<=2) ? nr_feptx_ofdm : nr_feptx_ofdm_2thread; // this is fep with idft only (no precoding in RRU)
+ ru->feptx_prec = NULL;
+ ru->start_if = start_if; // need to start the if interface for if4p5
+ ru->ifdevice.host_type = RRU_HOST;
+ ru->rfdevice.host_type = RRU_HOST;
+ ru->ifdevice.eth_params = &ru->eth_params;
+ reset_meas(&ru->rx_fhaul);
+ reset_meas(&ru->tx_fhaul);
+ reset_meas(&ru->compression);
+ reset_meas(&ru->transport);
+ ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
+ printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
+
+ if (ret<0) {
+ printf("Exiting, cannot initialize transport protocol\n");
+ exit(-1);
+ }
+
+ malloc_IF4p5_buffer(ru);
+ } else if (ru->function == gNodeB_3GPP) {
+ ru->do_prach = 0; // no prach processing in RU
+ ru->feprx = (get_nprocs()<=2) ? fep_full : ru_fep_full_2thread; // RX DFTs
+ ru->feptx_ofdm = (get_nprocs()<=2) ? nr_feptx_ofdm : nr_feptx_ofdm_2thread; // this is fep with idft and precoding
+ ru->feptx_prec = feptx_prec; // this is fep with idft and precoding
+ ru->fh_north_in = NULL; // no incoming fronthaul from north
+ ru->fh_north_out = NULL; // no outgoing fronthaul to north
+ ru->start_if = NULL; // no if interface
+ ru->rfdevice.host_type = RAU_HOST;
+ }
+
+ ru->fh_south_in = rx_rf; // local synchronous RF RX
+ ru->fh_south_out = tx_rf; // local synchronous RF TX
+ ru->start_rf = start_rf; // need to start the local RF interface
+ ru->stop_rf = stop_rf;
+ printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf);
+ /*
+ if (ru->function == gNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise
+ fill_rf_config(ru,rf_config_file);
+ init_frame_parms(&ru->frame_parms,1);
+ nr_phy_init_RU(ru);
+ }
+
+ ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
+ if (setup_RU_buffers(ru)!=0) {
+ printf("Exiting, cannot initialize RU Buffers\n");
+ exit(-1);
+ }*/
+ break;
+
+ case REMOTE_IF5: // the remote unit is IF5 RRU
+ ru->do_prach = 0;
+ ru->feprx = (get_nprocs()<=2) ? fep_full : fep_full; // this is frequency-shift + DFTs
+ ru->feptx_prec = feptx_prec; // need to do transmit Precoding + IDFTs
+ ru->feptx_ofdm = (get_nprocs()<=2) ? nr_feptx_ofdm : nr_feptx_ofdm_2thread; // need to do transmit Precoding + IDFTs
+ ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception
+ ru->fh_south_out = fh_if5_south_out; // synchronous IF5 transmission
+ ru->fh_south_asynch_in = NULL; // no asynchronous UL
+ ru->start_rf = NULL; // no local RF
+ ru->stop_rf = NULL;
+ ru->start_if = start_if; // need to start if interface for IF5
+ ru->ifdevice.host_type = RAU_HOST;
+ ru->ifdevice.eth_params = &ru->eth_params;
+ ru->ifdevice.configure_rru = configure_ru;
+ ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
+ printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
+
+ if (ret<0) {
+ printf("Exiting, cannot initialize transport protocol\n");
+ exit(-1);
+ }
+
+ break;
+
+ case REMOTE_IF4p5:
+ ru->do_prach = 0;
+ ru->feprx = NULL; // DFTs
+ ru->feptx_prec = feptx_prec; // Precoding operation
+ ru->feptx_ofdm = NULL; // no OFDM mod
+ ru->fh_south_in = fh_if4p5_south_in; // synchronous IF4p5 reception
+ ru->fh_south_out = fh_if4p5_south_out; // synchronous IF4p5 transmission
+ ru->fh_south_asynch_in = (ru->if_timing == synch_to_other) ? fh_if4p5_south_in : NULL; // asynchronous UL if synch_to_other
+ ru->fh_north_out = NULL;
+ ru->fh_north_asynch_in = NULL;
+ ru->start_rf = NULL; // no local RF
+ ru->stop_rf = NULL;
+ ru->start_if = start_if; // need to start if interface for IF4p5
+ ru->ifdevice.host_type = RAU_HOST;
+ ru->ifdevice.eth_params = &ru->eth_params;
+ ru->ifdevice.configure_rru = configure_ru;
+ ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
+ printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
+
+ if (ret<0) {
+ printf("Exiting, cannot initialize transport protocol\n");
+ exit(-1);
+ }
+
+ malloc_IF4p5_buffer(ru);
+ break;
+
+ default:
+ LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south);
+ break;
+ } // switch on interface type
+}
+
+extern void RCconfig_RU(void);
+
+void init_RU(char *rf_config_file) {
+ int ru_id;
+ RU_t *ru;
+ PHY_VARS_gNB *gNB0= (PHY_VARS_gNB *)NULL;
+ NR_DL_FRAME_PARMS *fp = (NR_DL_FRAME_PARMS *)NULL;
+ int i;
+ int CC_id;
+ // create status mask
+ RC.ru_mask = 0;
+ pthread_mutex_init(&RC.ru_mutex,NULL);
+ pthread_cond_init(&RC.ru_cond,NULL);
+ // read in configuration file)
+ printf("configuring RU from file\n");
+ RCconfig_RU();
+ LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_nr_L1_inst,RC.nb_RU,get_nprocs());
+
+ if (RC.nb_nr_CC != 0)
+ for (i=0; inum_RU=0;
+
+ LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU);
+
+ for (ru_id=0; ru_idrf_config_file = rf_config_file;
+ ru->idx = ru_id;
+ ru->ts_offset = 0;
+ // use gNB_list[0] as a reference for RU frame parameters
+ // NOTE: multiple CC_id are not handled here yet!
+
+ if (ru->num_gNB > 0) {
+ LOG_D(PHY, "%s() RC.ru[%d].num_gNB:%d ru->gNB_list[0]:%p RC.gNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_gNB, ru->gNB_list[0], RC.gNB[0][0], ru->rf_config_file);
+
+ if (ru->gNB_list[0] == 0) {
+ LOG_E(PHY,"%s() DJP - ru->gNB_list ru->num_gNB are not initialized - so do it manually\n", __FUNCTION__);
+ ru->gNB_list[0] = RC.gNB[0][0];
+ ru->num_gNB=1;
+ //
+ // DJP - feptx_prec() / feptx_ofdm() parses the gNB_list (based on num_gNB) and copies the txdata_F to txdata in RU
+ //
+ } else {
+ LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__);
+ }
+ }
+
+ gNB0 = ru->gNB_list[0];
+ fp = ru->nr_frame_parms;
+ LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
+
+ if (gNB0) {
+ if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5))
+ AssertFatal(gNB0!=NULL,"gNB0 is null!\n");
+
+ if (gNB0) {
+ LOG_I(PHY,"Copying frame parms from gNB %d to ru %d\n",gNB0->Mod_id,ru->idx);
+ memcpy((void *)fp,(void *)&gNB0->frame_parms,sizeof(NR_DL_FRAME_PARMS));
+ memset((void *)ru->frame_parms, 0, sizeof(LTE_DL_FRAME_PARMS));
+ // attach all RU to all gNBs in its list/
+ LOG_D(PHY,"ru->num_gNB:%d gNB0->num_RU:%d\n", ru->num_gNB, gNB0->num_RU);
+
+ for (i=0; inum_gNB; i++) {
+ gNB0 = ru->gNB_list[i];
+ gNB0->RU_list[gNB0->num_RU++] = ru;
+ }
+ }
+ }
+
+ // LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],gNB_timing[ru->if_timing],ru->function);
+ set_function_spec_param(ru);
+ LOG_I(PHY,"Starting ru_thread %d\n",ru_id);
+ init_RU_proc(ru);
+ } // for ru_id
+
+ // sleep(1);
+ LOG_D(HW,"[nr-softmodem.c] RU threads created\n");
+}
+
+
+
+
+void stop_RU(int nb_ru) {
+ for (int inst = 0; inst < nb_ru; inst++) {
+ LOG_I(PHY, "Stopping RU %d processing threads\n", inst);
+ kill_RU_proc(inst);
+ }
+}
+
+
+/* --------------------------------------------------------*/
+/* from here function to use configuration module */
+void RCconfig_RU(void) {
+ int j = 0;
+ int i = 0;
+ paramdef_t RUParams[] = RUPARAMS_DESC;
+ paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0};
+ config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL);
+
+ if ( RUParamList.numelt > 0) {
+ RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *));
+ RC.ru_mask=(1<idx = j;
+ RC.ru[j]->nr_frame_parms = (NR_DL_FRAME_PARMS *)malloc(sizeof(NR_DL_FRAME_PARMS));
+ RC.ru[j]->frame_parms = (LTE_DL_FRAME_PARMS *)malloc(sizeof(LTE_DL_FRAME_PARMS));
+ printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]);
+ RC.ru[j]->if_timing = synch_to_ext_device;
+
+ if (RC.nb_nr_L1_inst >0)
+ RC.ru[j]->num_gNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt;
+ else
+ RC.ru[j]->num_gNB = 0;
+
+ for (i=0; inum_gNB; i++) RC.ru[j]->gNB_list[i] = RC.gNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0];
+
+ if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) {
+ RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr));
+ }
+
+ if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) {
+ if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) {
+ RC.ru[j]->openair0_cfg.clock_source = internal;
+ LOG_D(PHY, "RU clock source set as internal\n");
+ } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) {
+ RC.ru[j]->openair0_cfg.clock_source = external;
+ LOG_D(PHY, "RU clock source set as external\n");
+ } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) {
+ RC.ru[j]->openair0_cfg.clock_source = gpsdo;
+ LOG_D(PHY, "RU clock source set as gpsdo\n");
+ } else {
+ LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr));
+ }
+ }
+
+ if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) {
+ if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) {
+ RC.ru[j]->if_south = LOCAL_RF;
+ RC.ru[j]->function = gNodeB_3GPP;
+ printf("Setting function for RU %d to gNodeB_3GPP\n",j);
+ } else {
+ RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));
+ RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr));
+ RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr));
+ RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr);
+ RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
+ RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr);
+ RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr);
+
+ if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) {
+ RC.ru[j]->if_south = LOCAL_RF;
+ RC.ru[j]->function = NGFI_RRU_IF5;
+ RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE;
+ printf("Setting function for RU %d to NGFI_RRU_IF5 (udp)\n",j);
+ } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) {
+ RC.ru[j]->if_south = LOCAL_RF;
+ RC.ru[j]->function = NGFI_RRU_IF5;
+ RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE;
+ printf("Setting function for RU %d to NGFI_RRU_IF5 (raw)\n",j);
+ } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) {
+ RC.ru[j]->if_south = LOCAL_RF;
+ RC.ru[j]->function = NGFI_RRU_IF4p5;
+ RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
+ printf("Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n",j);
+ } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) {
+ RC.ru[j]->if_south = LOCAL_RF;
+ RC.ru[j]->function = NGFI_RRU_IF4p5;
+ RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
+ printf("Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j);
+ }
+ }
+
+ RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);;
+ RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr);
+ RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt;
+
+ for (i=0; inum_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i];
+ } //strcmp(local_rf, "yes") == 0
+ else {
+ printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr));
+ RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));
+ RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr));
+ RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr));
+ RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr);
+ RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
+ RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr);
+ RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr);
+
+ if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) {
+ RC.ru[j]->if_south = REMOTE_IF5;
+ RC.ru[j]->function = NGFI_RAU_IF5;
+ RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE;
+ } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) {
+ RC.ru[j]->if_south = REMOTE_IF5;
+ RC.ru[j]->function = NGFI_RAU_IF5;
+ RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE;
+ } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) {
+ RC.ru[j]->if_south = REMOTE_IF4p5;
+ RC.ru[j]->function = NGFI_RAU_IF4p5;
+ RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
+ } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) {
+ RC.ru[j]->if_south = REMOTE_IF4p5;
+ RC.ru[j]->function = NGFI_RAU_IF4p5;
+ RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
+ } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if5_mobipass") == 0) {
+ RC.ru[j]->if_south = REMOTE_IF5;
+ RC.ru[j]->function = NGFI_RAU_IF5;
+ RC.ru[j]->if_timing = synch_to_other;
+ RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF5_MOBIPASS;
+ }
+ } /* strcmp(local_rf, "yes") != 0 */
+
+ RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr);
+ RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr);
+ RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr);
+ RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr);
+ }// j=0..num_rus
+ } else {
+ RC.nb_RU = 0;
+ } // setting != NULL
+
+ return;
+}
diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c
new file mode 100644
index 0000000000..3147284e99
--- /dev/null
+++ b/executables/nr-softmodem.c
@@ -0,0 +1,1237 @@
+/*
+ * 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
+ */
+
+
+#define _GNU_SOURCE /* See feature_test_macros(7) */
+#include
+
+
+#include "T.h"
+
+#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
+#include
+
+#include "msc.h"
+
+#include "PHY/types.h"
+#include "common/ran_context.h"
+
+#include "PHY/defs_gNB.h"
+#include "common/config/config_userapi.h"
+#include "common/utils/load_module_shlib.h"
+#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
+//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "../../ARCH/COMMON/common_lib.h"
+#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h"
+
+//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "PHY/phy_vars.h"
+#include "SCHED/sched_common_vars.h"
+#include "LAYER2/MAC/mac_vars.h"
+
+#include "LAYER2/MAC/mac.h"
+#include "LAYER2/MAC/mac_proto.h"
+#include "RRC/LTE/rrc_vars.h"
+#include "PHY_INTERFACE/phy_interface_vars.h"
+#include "gnb_config.h"
+
+#ifdef SMBV
+#include "PHY/TOOLS/smbv.h"
+unsigned short config_frames[4] = {2,9,11,13};
+#endif
+
+#include "common/utils/LOG/log.h"
+#include "common/utils/LOG/vcd_signal_dumper.h"
+
+#include "UTIL/OPT/opt.h"
+
+//#include "PHY/TOOLS/time_meas.h"
+
+#ifndef OPENAIR2
+ #include "UTIL/OTG/otg_vars.h"
+#endif
+
+#if defined(ENABLE_ITTI)
+ #include "intertask_interface.h"
+#endif
+
+#include "PHY/INIT/phy_init.h"
+
+#include "system.h"
+#include
+
+#ifdef XFORMS
+ #include "PHY/TOOLS/nr_phy_scope.h"
+ #include "stats.h"
+#endif
+#include "nr-softmodem.h"
+#include "NB_IoT_interface.h"
+
+#ifdef XFORMS
+ // current status is that every UE has a DL scope for a SINGLE eNB (gnb_id=0)
+ // at eNB 0, an UL scope for every UE
+
+ FD_phy_scope_gnb *form_gnb[MAX_NUM_CCs][NUMBER_OF_UE_MAX];
+ FD_stats_form *form_stats=NULL,*form_stats_l2=NULL;
+ char title[255];
+ unsigned char scope_enb_num_ue = 2;
+ static pthread_t forms_thread; //xforms
+
+#endif //XFORMS
+
+short nr_mod_table[NR_MOD_TABLE_SIZE_SHORT] = {0,0,16384,16384,-16384,-16384,16384,16384,16384,-16384,-16384,16384,-16384,-16384,7327,7327,7327,21981,21981,7327,21981,21981,7327,-7327,7327,-21981,21981,-7327,21981,-21981,-7327,7327,-7327,21981,-21981,7327,-21981,21981,-7327,-7327,-7327,-21981,-21981,-7327,-21981,-21981,10726,10726,10726,3576,3576,10726,3576,3576,10726,17876,10726,25027,3576,17876,3576,25027,17876,10726,17876,3576,25027,10726,25027,3576,17876,17876,17876,25027,25027,17876,25027,25027,10726,-10726,10726,-3576,3576,-10726,3576,-3576,10726,-17876,10726,-25027,3576,-17876,3576,-25027,17876,-10726,17876,-3576,25027,-10726,25027,-3576,17876,-17876,17876,-25027,25027,-17876,25027,-25027,-10726,10726,-10726,3576,-3576,10726,-3576,3576,-10726,17876,-10726,25027,-3576,17876,-3576,25027,-17876,10726,-17876,3576,-25027,10726,-25027,3576,-17876,17876,-17876,25027,-25027,17876,-25027,25027,-10726,-10726,-10726,-3576,-3576,-10726,-3576,-3576,-10726,-17876,-10726,-25027,-3576,-17876,-3576,-25027,-17876,-10726,-17876,-3576,-25027,-10726,-25027,-3576,-17876,-17876,-17876,-25027,-25027,-17876,-25027,-25027,8886,8886,8886,12439,12439,8886,12439,12439,8886,5332,8886,1778,12439,5332,12439,1778,5332,8886,5332,12439,1778,8886,1778,12439,5332,5332,5332,1778,1778,5332,1778,1778,8886,19547,8886,15993,12439,19547,12439,15993,8886,23101,8886,26655,12439,23101,12439,26655,5332,19547,5332,15993,1778,19547,1778,15993,5332,23101,5332,26655,1778,23101,1778,26655,19547,8886,19547,12439,15993,8886,15993,12439,19547,5332,19547,1778,15993,5332,15993,1778,23101,8886,23101,12439,26655,8886,26655,12439,23101,5332,23101,1778,26655,5332,26655,1778,19547,19547,19547,15993,15993,19547,15993,15993,19547,23101,19547,26655,15993,23101,15993,26655,23101,19547,23101,15993,26655,19547,26655,15993,23101,23101,23101,26655,26655,23101,26655,26655,8886,-8886,8886,-12439,12439,-8886,12439,-12439,8886,-5332,8886,-1778,12439,-5332,12439,-1778,5332,-8886,5332,-12439,1778,-8886,1778,-12439,5332,-5332,5332,-1778,1778,-5332,1778,-1778,8886,-19547,8886,-15993,12439,-19547,12439,-15993,8886,-23101,8886,-26655,12439,-23101,12439,-26655,5332,-19547,5332,-15993,1778,-19547,1778,-15993,5332,-23101,5332,-26655,1778,-23101,1778,-26655,19547,-8886,19547,-12439,15993,-8886,15993,-12439,19547,-5332,19547,-1778,15993,-5332,15993,-1778,23101,-8886,23101,-12439,26655,-8886,26655,-12439,23101,-5332,23101,-1778,26655,-5332,26655,-1778,19547,-19547,19547,-15993,15993,-19547,15993,-15993,19547,-23101,19547,-26655,15993,-23101,15993,-26655,23101,-19547,23101,-15993,26655,-19547,26655,-15993,23101,-23101,23101,-26655,26655,-23101,26655,-26655,-8886,8886,-8886,12439,-12439,8886,-12439,12439,-8886,5332,-8886,1778,-12439,5332,-12439,1778,-5332,8886,-5332,12439,-1778,8886,-1778,12439,-5332,5332,-5332,1778,-1778,5332,-1778,1778,-8886,19547,-8886,15993,-12439,19547,-12439,15993,-8886,23101,-8886,26655,-12439,23101,-12439,26655,-5332,19547,-5332,15993,-1778,19547,-1778,15993,-5332,23101,-5332,26655,-1778,23101,-1778,26655,-19547,8886,-19547,12439,-15993,8886,-15993,12439,-19547,5332,-19547,1778,-15993,5332,-15993,1778,-23101,8886,-23101,12439,-26655,8886,-26655,12439,-23101,5332,-23101,1778,-26655,5332,-26655,1778,-19547,19547,-19547,15993,-15993,19547,-15993,15993,-19547,23101,-19547,26655,-15993,23101,-15993,26655,-23101,19547,-23101,15993,-26655,19547,-26655,15993,-23101,23101,-23101,26655,-26655,23101,-26655,26655,-8886,-8886,-8886,-12439,-12439,-8886,-12439,-12439,-8886,-5332,-8886,-1778,-12439,-5332,-12439,-1778,-5332,-8886,-5332,-12439,-1778,-8886,-1778,-12439,-5332,-5332,-5332,-1778,-1778,-5332,-1778,-1778,-8886,-19547,-8886,-15993,-12439,-19547,-12439,-15993,-8886,-23101,-8886,-26655,-12439,-23101,-12439,-26655,-5332,-19547,-5332,-15993,-1778,-19547,-1778,-15993,-5332,-23101,-5332,-26655,-1778,-23101,-1778,-26655,-19547,-8886,-19547,-12439,-15993,-8886,-15993,-12439,-19547,-5332,-19547,-1778,-15993,-5332,-15993,-1778,-23101,-8886,-23101,-12439,-26655,-8886,-26655,-12439,-23101,-5332,-23101,-1778,-26655,-5332,-26655,-1778,-19547,-19547,-19547,-15993,-15993,-19547,-15993,-15993,-19547,-23101,-19547,-26655,-15993,-23101,-15993,-26655,-23101,-19547,-23101,-15993,-26655,-19547,-26655,-15993,-23101,-23101,-23101,-26655,-26655,-23101,-26655,-26655};
+
+
+pthread_cond_t nfapi_sync_cond;
+pthread_mutex_t nfapi_sync_mutex;
+int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex
+
+uint8_t nfapi_mode = 0; // Default to monolithic mode
+
+pthread_cond_t sync_cond;
+pthread_mutex_t sync_mutex;
+int sync_var=-1; //!< protected by mutex \ref sync_mutex.
+int config_sync_var=-1;
+
+#if defined(ENABLE_ITTI)
+ volatile int start_gNB = 0;
+#endif
+volatile int oai_exit = 0;
+
+static clock_source_t clock_source = internal;
+static int wait_for_sync = 0;
+
+unsigned int mmapped_dma=0;
+int single_thread_flag=1;
+
+static int8_t threequarter_fs=0;
+
+uint32_t downlink_frequency[MAX_NUM_CCs][4];
+int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
+
+//Temp fix for inexisting NR upper layer
+unsigned char NB_gNB_INST = 1;
+
+#if defined(ENABLE_ITTI)
+ static char *itti_dump_file = NULL;
+#endif
+
+int UE_scan = 1;
+int UE_scan_carrier = 0;
+runmode_t mode = normal_txrx;
+
+FILE *input_fd=NULL;
+
+
+#if MAX_NUM_CCs == 1
+rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}};
+double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}};
+double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}};
+#else
+rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}};
+double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}};
+double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}};
+#endif
+
+double rx_gain_off = 0.0;
+
+double sample_rate=30.72e6;
+double bw = 10.0e6;
+
+static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/;
+
+char rf_config_file[1024]="/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat";
+
+int chain_offset=0;
+int phy_test = 0;
+uint8_t usim_test = 0;
+
+uint8_t dci_Format = 0;
+uint8_t agregation_Level =0xFF;
+
+uint8_t nb_antenna_tx = 1;
+uint8_t nb_antenna_rx = 1;
+
+char ref[128] = "internal";
+char channels[128] = "0";
+
+int rx_input_level_dBm;
+
+#ifdef XFORMS
+ extern int otg_enabled;
+ static char do_forms=0;
+#else
+ int otg_enabled;
+#endif
+//int number_of_cards = 1;
+
+
+//static NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs];
+//static nfapi_nr_config_request_t *config[MAX_NUM_CCs];
+uint32_t target_dl_mcs = 28; //maximum allowed mcs
+uint32_t target_ul_mcs = 20;
+uint32_t timing_advance = 0;
+uint8_t exit_missed_slots=1;
+uint64_t num_missed_slots=0; // counter for the number of missed slots
+
+
+extern void reset_opp_meas(void);
+extern void print_opp_meas(void);
+
+extern void init_eNB_afterRU(void);
+
+int transmission_mode=1;
+int emulate_rf = 0;
+int numerology = 0;
+char *parallel_config = NULL;
+char *worker_config = NULL;
+
+static THREAD_STRUCT thread_struct;
+void set_parallel_conf(char *parallel_conf) {
+ if(strcmp(parallel_conf,"PARALLEL_SINGLE_THREAD")==0) thread_struct.parallel_conf = PARALLEL_SINGLE_THREAD;
+ else if(strcmp(parallel_conf,"PARALLEL_RU_L1_SPLIT")==0) thread_struct.parallel_conf = PARALLEL_RU_L1_SPLIT;
+ else if(strcmp(parallel_conf,"PARALLEL_RU_L1_TRX_SPLIT")==0) thread_struct.parallel_conf = PARALLEL_RU_L1_TRX_SPLIT;
+
+ printf("[CONFIG] parallel conf is set to %d\n",thread_struct.parallel_conf);
+}
+void set_worker_conf(char *worker_conf) {
+ if(strcmp(worker_conf,"WORKER_DISABLE")==0) thread_struct.worker_conf = WORKER_DISABLE;
+ else if(strcmp(worker_conf,"WORKER_ENABLE")==0) thread_struct.worker_conf = WORKER_ENABLE;
+
+ printf("[CONFIG] worker conf is set to %d\n",thread_struct.worker_conf);
+}
+PARALLEL_CONF_t get_thread_parallel_conf(void) {
+ return thread_struct.parallel_conf;
+}
+WORKER_CONF_t get_thread_worker_conf(void) {
+ return thread_struct.worker_conf;
+}
+
+
+/* struct for ethernet specific parameters given in eNB conf file */
+eth_params_t *eth_params;
+
+openair0_config_t openair0_cfg[MAX_CARDS];
+
+double cpuf;
+
+extern char uecap_xer[1024];
+char uecap_xer_in=0;
+
+/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed
+ * this is very hackish - find a proper solution
+ */
+uint8_t abstraction_flag=0;
+
+/* forward declarations */
+void set_default_frame_parms(nfapi_nr_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]);
+
+/*---------------------BMC: timespec helpers -----------------------------*/
+
+struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
+struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
+
+struct timespec clock_difftime(struct timespec start, struct timespec end) {
+ struct timespec temp;
+
+ if ((end.tv_nsec-start.tv_nsec)<0) {
+ temp.tv_sec = end.tv_sec-start.tv_sec-1;
+ temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
+ } else {
+ temp.tv_sec = end.tv_sec-start.tv_sec;
+ temp.tv_nsec = end.tv_nsec-start.tv_nsec;
+ }
+
+ return temp;
+}
+
+void print_difftimes(void) {
+#ifdef DEBUG
+ printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
+#else
+ LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
+#endif
+}
+
+void update_difftimes(struct timespec start, struct timespec end) {
+ struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 };
+ int changed = 0;
+ diff_time = clock_difftime(start, end);
+
+ if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) {
+ min_diff_time.tv_nsec = diff_time.tv_nsec;
+ changed = 1;
+ }
+
+ if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) {
+ max_diff_time.tv_nsec = diff_time.tv_nsec;
+ changed = 1;
+ }
+
+#if 1
+
+ if (changed) print_difftimes();
+
+#endif
+}
+
+/*------------------------------------------------------------------------*/
+
+unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) {
+ return (txi + (txq<<6) + (rxi<<12) + (rxq<<18));
+}
+unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) {
+ return (dcoff_i_rxfe + (dcoff_q_rxfe<<8));
+}
+
+#if !defined(ENABLE_ITTI)
+void signal_handler(int sig) {
+ void *array[10];
+ size_t size;
+
+ if (sig==SIGSEGV) {
+ // get void*'s for all entries on the stack
+ size = backtrace(array, 10);
+ // print out all the frames to stderr
+ fprintf(stderr, "Error: signal %d:\n", sig);
+ backtrace_symbols_fd(array, size, 2);
+ exit(-1);
+ } else {
+ printf("trying to exit gracefully...\n");
+ oai_exit = 1;
+ }
+}
+#endif
+#define KNRM "\x1B[0m"
+#define KRED "\x1B[31m"
+#define KGRN "\x1B[32m"
+#define KBLU "\x1B[34m"
+#define RESET "\033[0m"
+
+#if defined(ENABLE_ITTI)
+void signal_handler_itti(int sig) {
+ // Call exit function
+ char msg[256];
+ memset(msg, 0, 256);
+ sprintf(msg, "caught signal %s\n", strsignal(sig));
+ exit_function(__FILE__, __FUNCTION__, __LINE__, msg);
+}
+#endif
+
+void exit_function(const char *file, const char *function, const int line, const char *s) {
+ int ru_id;
+
+ if (s != NULL) {
+ printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s);
+ }
+
+ oai_exit = 1;
+
+ if (RC.ru == NULL)
+ exit(-1); // likely init not completed, prevent crash or hang, exit now...
+
+ for (ru_id=0; ru_idrfdevice.trx_end_func) {
+ RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice);
+ RC.ru[ru_id]->rfdevice.trx_end_func = NULL;
+ }
+
+ if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func) {
+ RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
+ RC.ru[ru_id]->ifdevice.trx_end_func = NULL;
+ }
+ }
+
+ sleep(1); //allow lte-softmodem threads to exit first
+#if defined(ENABLE_ITTI)
+ itti_terminate_tasks (TASK_UNKNOWN);
+#endif
+ exit(1);
+}
+
+#ifdef XFORMS
+
+
+void reset_stats(FL_OBJECT *button, long arg) {
+ PHY_VARS_gNB *phy_vars_gNB = RC.gNB[0][0];
+
+ for (int i=0; idlsch[i][0]->Mlimit; j++) {
+ phy_vars_gNB->UE_stats[i].dlsch_NAK[k][j]=0;
+ phy_vars_gNB->UE_stats[i].dlsch_ACK[k][j]=0;
+ phy_vars_gNB->UE_stats[i].dlsch_trials[k][j]=0;
+ }*/
+ phy_vars_gNB->UE_stats[i].dlsch_l2_errors[k]=0;
+ phy_vars_gNB->UE_stats[i].ulsch_errors[k]=0;
+ phy_vars_gNB->UE_stats[i].ulsch_consecutive_errors=0;
+ phy_vars_gNB->UE_stats[i].dlsch_sliding_cnt=0;
+ phy_vars_gNB->UE_stats[i].dlsch_NAK_round0=0;
+ phy_vars_gNB->UE_stats[i].dlsch_mcs_offset=0;
+ }
+ }
+}
+
+static void *scope_thread(void *arg) {
+ int UE_id, CC_id;
+ int ue_cnt=0;
+# ifdef ENABLE_XFORMS_WRITE_STATS
+ FILE *gNB_stats = fopen("gNB_stats.txt", "w");
+#endif
+
+ while (!oai_exit) {
+ ue_cnt=0;
+
+ for(UE_id=0; UE_id 0) {
+ /* Last task to create, others task must be ready before its start */
+ if (itti_create_task (TASK_GNB_APP, gNB_app_task, NULL) < 0) {
+ LOG_E(GNB_APP, "Create task for gNB APP failed\n");
+ return -1;
+ }
+ }
+
+ /*
+ # if defined(ENABLE_USE_MME)
+ if (gnb_nb > 0) {
+ if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) {
+ LOG_E(SCTP, "Create task for SCTP failed\n");
+ return -1;
+ }
+
+ if (itti_create_task (TASK_S1AP, s1ap_eNB_task, NULL) < 0) {
+ LOG_E(S1AP, "Create task for S1AP failed\n");
+ return -1;
+ }
+ if(!emulate_rf){
+ if (itti_create_task (TASK_UDP, udp_eNB_task, NULL) < 0) {
+ LOG_E(UDP_, "Create task for UDP failed\n");
+ return -1;
+ }
+ }
+
+ if (itti_create_task (TASK_GTPV1_U, >pv1u_eNB_task, NULL) < 0) {
+ LOG_E(GTPU, "Create task for GTPV1U failed\n");
+ return -1;
+ }
+ }
+
+ # endif
+ */
+
+ if (gnb_nb > 0) {
+ LOG_I(NR_RRC,"Creating NR RRC gNB Task\n");
+
+ if (itti_create_task (TASK_RRC_GNB, rrc_gnb_task, NULL) < 0) {
+ LOG_E(NR_RRC, "Create task for NR RRC gNB failed\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void get_options(void) {
+ int tddflag, nonbiotflag;
+ uint32_t online_log_messages;
+ uint32_t glog_level, glog_verbosity;
+ uint32_t start_telnetsrv;
+ paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ;
+ paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
+ config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL);
+
+ if (strlen(in_path) > 0) {
+ opt_type = OPT_PCAP;
+ opt_enabled=1;
+ printf("Enabling OPT for PCAP with the following file %s \n",in_path);
+ }
+
+ if (strlen(in_ip) > 0) {
+ opt_enabled=1;
+ opt_type = OPT_WIRESHARK;
+ printf("Enabling OPT for wireshark for local interface");
+ }
+
+ config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL);
+
+ if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) {
+ set_glog_onlinelog(online_log_messages);
+ }
+
+ if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) {
+ set_glog(glog_level);
+ }
+
+ if (start_telnetsrv) {
+ load_module_shlib("telnetsrv",NULL,0,NULL);
+ }
+
+#if T_TRACER
+ paramdef_t cmdline_ttraceparams[] =CMDLINE_TTRACEPARAMS_DESC ;
+ config_process_cmdline( cmdline_ttraceparams,sizeof(cmdline_ttraceparams)/sizeof(paramdef_t),NULL);
+#endif
+
+ if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) {
+ memset((void *)&RC,0,sizeof(RC));
+ /* Read RC configuration file */
+ NRRCConfig();
+ NB_gNB_INST = RC.nb_nr_inst;
+ NB_RU = RC.nb_RU;
+ printf("Configuration: nb_rrc_inst %d, nb_nr_L1_inst %d, nb_ru %d\n",NB_gNB_INST,RC.nb_nr_L1_inst,NB_RU);
+ }
+
+ if(parallel_config != NULL) set_parallel_conf(parallel_config);
+
+ if(worker_config != NULL) set_worker_conf(worker_config);
+}
+
+
+#if T_TRACER
+ int T_nowait = 0; /* by default we wait for the tracer */
+ int T_port = 2021; /* default port to listen to to wait for the tracer */
+ int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */
+#endif
+
+
+
+void set_default_frame_parms(nfapi_nr_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
+ int CC_id;
+
+ for (CC_id=0; CC_idsubframe_config.numerology_index_mu.value =1;
+ config[CC_id]->subframe_config.duplex_mode.value = 1; //FDD
+ config[CC_id]->subframe_config.dl_cyclic_prefix_type.value = 0; //NORMAL
+ config[CC_id]->rf_config.dl_carrier_bandwidth.value = 106;
+ config[CC_id]->rf_config.ul_carrier_bandwidth.value = 106;
+ config[CC_id]->sch_config.physical_cell_id.value = 0;
+ ///dl frequency to be filled in
+ /* //Set some default values that may be overwritten while reading options
+ frame_parms[CC_id]->frame_type = FDD;
+ frame_parms[CC_id]->tdd_config = 3;
+ frame_parms[CC_id]->tdd_config_S = 0;
+ frame_parms[CC_id]->N_RB_DL = 100;
+ frame_parms[CC_id]->N_RB_UL = 100;
+ frame_parms[CC_id]->Ncp = NORMAL;
+ frame_parms[CC_id]->Ncp_UL = NORMAL;
+ frame_parms[CC_id]->Nid_cell = 0;
+ frame_parms[CC_id]->num_MBSFN_config = 0;
+ frame_parms[CC_id]->nb_antenna_ports_eNB = 1;
+ frame_parms[CC_id]->nb_antennas_tx = 1;
+ frame_parms[CC_id]->nb_antennas_rx = 1;
+
+ frame_parms[CC_id]->nushift = 0;
+
+ frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth;
+ frame_parms[CC_id]->phich_config_common.phich_duration = normal;
+ // UL RS Config
+ frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 0;//n_DMRS1 set to 0
+ frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0;
+ frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0;
+ frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0;
+
+ frame_parms[CC_id]->prach_config_common.rootSequenceIndex=22;
+ frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1;
+ frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0;
+ frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0;
+ frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0;
+
+ // downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31.
+ // downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0];
+ // downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0];
+ // downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0];
+ //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]);
+ frame_parms[CC_id]->dl_CarrierFreq=downlink_frequency[CC_id][0];
+ */
+ }
+}
+
+/*
+void init_openair0(void) {
+
+ int card;
+ int i;
+
+ for (card=0; cardrf_config.dl_carrier_bandwidth.value == 100) {
+ if (frame_parms[0]->threequarter_fs) {
+ openair0_cfg[card].sample_rate=23.04e6;
+ openair0_cfg[card].samples_per_frame = 230400;
+ openair0_cfg[card].tx_bw = 10e6;
+ openair0_cfg[card].rx_bw = 10e6;
+ } else {
+ openair0_cfg[card].sample_rate=30.72e6;
+ openair0_cfg[card].samples_per_frame = 307200;
+ openair0_cfg[card].tx_bw = 10e6;
+ openair0_cfg[card].rx_bw = 10e6;
+ }
+ } else if(config[0]->rf_config.dl_carrier_bandwidth.value == 50) {
+ openair0_cfg[card].sample_rate=15.36e6;
+ openair0_cfg[card].samples_per_frame = 153600;
+ openair0_cfg[card].tx_bw = 5e6;
+ openair0_cfg[card].rx_bw = 5e6;
+ } else if (config[0]->rf_config.dl_carrier_bandwidth.value == 25) {
+ openair0_cfg[card].sample_rate=7.68e6;
+ openair0_cfg[card].samples_per_frame = 76800;
+ openair0_cfg[card].tx_bw = 2.5e6;
+ openair0_cfg[card].rx_bw = 2.5e6;
+ } else if (config[0]->rf_config.dl_carrier_bandwidth.value == 6) {
+ openair0_cfg[card].sample_rate=1.92e6;
+ openair0_cfg[card].samples_per_frame = 19200;
+ openair0_cfg[card].tx_bw = 1.5e6;
+ openair0_cfg[card].rx_bw = 1.5e6;
+ }
+
+
+ if (config[0]->subframe_config.duplex_mode.value==TDD)
+ openair0_cfg[card].duplex_mode = duplex_mode_TDD;
+ else //FDD
+ openair0_cfg[card].duplex_mode = duplex_mode_FDD;
+
+ printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card,
+ RC.gNB[0][0]->gNB_config.rf_config.tx_antenna_ports.value,
+ RC.gNB[0][0]->gNB_config.rf_config.tx_antenna_ports.value );
+ openair0_cfg[card].Mod_id = 0;
+
+ openair0_cfg[card].num_rb_dl=config[0]->rf_config.dl_carrier_bandwidth.value;
+
+ openair0_cfg[card].clock_source = clock_source;
+
+
+ openair0_cfg[card].tx_num_channels=min(2,RC.gNB[0][0]->gNB_config.rf_config.tx_antenna_ports.value );
+ openair0_cfg[card].rx_num_channels=min(2,RC.gNB[0][0]->gNB_config.rf_config.tx_antenna_ports.value );
+
+ for (i=0; i<4; i++) {
+
+ if (irx_total_gain_dB;
+
+
+ openair0_cfg[card].configFilename = rf_config_file;
+ printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n",
+ card,i, openair0_cfg[card].tx_gain[i],
+ openair0_cfg[card].rx_gain[i],
+ openair0_cfg[card].tx_freq[i],
+ openair0_cfg[card].rx_freq[i]);
+ }
+ } // for loop on cards
+}
+*/
+
+void wait_RUs(void) {
+ LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask);
+ // wait for all RUs to be configured over fronthaul
+ pthread_mutex_lock(&RC.ru_mutex);
+
+ while (RC.ru_mask>0) {
+ pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex);
+ printf("RC.ru_mask:%02lx\n", RC.ru_mask);
+ }
+
+ pthread_mutex_unlock(&RC.ru_mutex);
+ LOG_I(PHY,"RUs configured\n");
+}
+
+void wait_gNBs(void) {
+ int i,j;
+ int waiting=1;
+
+ while (waiting==1) {
+ printf("Waiting for gNB L1 instances to all get configured ... sleeping 50ms (nb_nr_sL1_inst %d)\n",RC.nb_nr_L1_inst);
+ usleep(50*1000);
+ waiting=0;
+
+ for (i=0; iconfigured==0) {
+ waiting=1;
+ break;
+ }
+ }
+ }
+ }
+
+ printf("gNB L1 are configured\n");
+}
+
+#if defined(ENABLE_ITTI)
+/*
+ * helper function to terminate a certain ITTI task
+ */
+void terminate_task(task_id_t task_id, module_id_t mod_id) {
+ LOG_I(ENB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id);
+ MessageDef *msg;
+ msg = itti_alloc_new_message (ENB_APP, TERMINATE_MESSAGE);
+ itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg);
+}
+
+//extern void free_transport(PHY_VARS_gNB *);
+extern void nr_phy_free_RU(RU_t *);
+
+int stop_L1L2(module_id_t gnb_id) {
+ LOG_W(ENB_APP, "stopping nr-softmodem\n");
+ oai_exit = 1;
+
+ if (!RC.ru) {
+ LOG_F(ENB_APP, "no RU configured\n");
+ return -1;
+ }
+
+ /* stop trx devices, multiple carrier currently not supported by RU */
+ if (RC.ru[gnb_id]) {
+ if (RC.ru[gnb_id]->rfdevice.trx_stop_func) {
+ RC.ru[gnb_id]->rfdevice.trx_stop_func(&RC.ru[gnb_id]->rfdevice);
+ LOG_I(ENB_APP, "turned off RU rfdevice\n");
+ } else {
+ LOG_W(ENB_APP, "can not turn off rfdevice due to missing trx_stop_func callback, proceding anyway!\n");
+ }
+
+ if (RC.ru[gnb_id]->ifdevice.trx_stop_func) {
+ RC.ru[gnb_id]->ifdevice.trx_stop_func(&RC.ru[gnb_id]->ifdevice);
+ LOG_I(ENB_APP, "turned off RU ifdevice\n");
+ } else {
+ LOG_W(ENB_APP, "can not turn off ifdevice due to missing trx_stop_func callback, proceding anyway!\n");
+ }
+ } else {
+ LOG_W(ENB_APP, "no RU found for index %d\n", gnb_id);
+ return -1;
+ }
+
+ /* these tasks need to pick up new configuration */
+ terminate_task(TASK_RRC_ENB, gnb_id);
+ terminate_task(TASK_L2L1, gnb_id);
+ LOG_I(ENB_APP, "calling kill_gNB_proc() for instance %d\n", gnb_id);
+ kill_gNB_proc(gnb_id);
+ LOG_I(ENB_APP, "calling kill_RU_proc() for instance %d\n", gnb_id);
+ kill_RU_proc(gnb_id);
+ oai_exit = 0;
+
+ for (int cc_id = 0; cc_id < RC.nb_nr_CC[gnb_id]; cc_id++) {
+ //free_transport(RC.gNB[gnb_id][cc_id]);
+ phy_free_nr_gNB(RC.gNB[gnb_id][cc_id]);
+ }
+
+ nr_phy_free_RU(RC.ru[gnb_id]);
+ free_lte_top();
+ return 0;
+}
+
+/*
+ * Restart the nr-softmodem after it has been soft-stopped with stop_L1L2()
+ */
+int restart_L1L2(module_id_t gnb_id) {
+ RU_t *ru = RC.ru[gnb_id];
+ int cc_id;
+ MessageDef *msg_p = NULL;
+ LOG_W(ENB_APP, "restarting nr-softmodem\n");
+ /* block threads */
+ sync_var = -1;
+
+ for (cc_id = 0; cc_id < RC.nb_nr_L1_CC[gnb_id]; cc_id++) {
+ RC.gNB[gnb_id][cc_id]->configured = 0;
+ }
+
+ RC.ru_mask |= (1 << ru->idx);
+ /* copy the changed frame parameters to the RU */
+ /* TODO this should be done for all RUs associated to this gNB */
+ memcpy(&ru->nr_frame_parms, &RC.gNB[gnb_id][0]->frame_parms, sizeof(NR_DL_FRAME_PARMS));
+ set_function_spec_param(RC.ru[gnb_id]);
+ LOG_I(ENB_APP, "attempting to create ITTI tasks\n");
+
+ if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) {
+ LOG_E(RRC, "Create task for RRC eNB failed\n");
+ return -1;
+ } else {
+ LOG_I(RRC, "Re-created task for RRC gNB successfully\n");
+ }
+
+ if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) {
+ LOG_E(PDCP, "Create task for L2L1 failed\n");
+ return -1;
+ } else {
+ LOG_I(PDCP, "Re-created task for L2L1 successfully\n");
+ }
+
+ /* pass a reconfiguration request which will configure everything down to
+ * RC.eNB[i][j]->frame_parms, too */
+ msg_p = itti_alloc_new_message(TASK_ENB_APP, RRC_CONFIGURATION_REQ);
+ RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[gnb_id]->configuration;
+ itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(gnb_id), msg_p);
+ /* TODO XForms might need to be restarted, but it is currently (09/02/18)
+ * broken, so we cannot test it */
+ wait_gNBs();
+ init_RU_proc(ru);
+ ru->rf_map.card = 0;
+ ru->rf_map.chain = 0; /* CC_id + chain_offset;*/
+ wait_RUs();
+ init_eNB_afterRU();
+ printf("Sending sync to all threads\n");
+ pthread_mutex_lock(&sync_mutex);
+ sync_var=0;
+ pthread_cond_broadcast(&sync_cond);
+ pthread_mutex_unlock(&sync_mutex);
+ return 0;
+}
+#endif
+
+static void wait_nfapi_init(char *thread_name) {
+ printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name);
+ pthread_mutex_lock( &nfapi_sync_mutex );
+
+ while (nfapi_sync_var<0)
+ pthread_cond_wait( &nfapi_sync_cond, &nfapi_sync_mutex );
+
+ pthread_mutex_unlock(&nfapi_sync_mutex);
+ printf( "NFAPI: got sync (%s)\n", thread_name);
+}
+
+int main( int argc, char **argv ) {
+ int i;
+#if defined (XFORMS)
+ //void *status;
+#endif
+ int CC_id;
+ int ru_id;
+#if defined (XFORMS)
+ int ret;
+#endif
+ start_background_system();
+
+ ///static configuration for NR at the moment
+ if ( load_configmodule(argc,argv) == NULL) {
+ exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
+ }
+
+#ifdef DEBUG_CONSOLE
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+#endif
+ mode = normal_txrx;
+ memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS);
+ memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs);
+ configure_linux();
+ logInit();
+ printf("Reading in command-line options\n");
+ get_options ();
+
+ if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) {
+ fprintf(stderr,"Getting configuration failed\n");
+ exit(-1);
+ }
+
+#if T_TRACER
+ T_Config_Init();
+#endif
+ //randominit (0);
+ set_taus_seed (0);
+ printf("configuring for RAU/RRU\n");
+
+ if (opp_enabled ==1) {
+ reset_opp_meas();
+ }
+
+ cpuf=get_cpu_freq_GHz();
+#if defined(ENABLE_ITTI)
+ itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info);
+ // initialize mscgen log after ITTI
+ MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX);
+#endif
+
+ if (opt_type != OPT_NONE) {
+ if (init_opt(in_path, in_ip) == -1)
+ LOG_E(OPT,"failed to run OPT \n");
+ }
+
+#ifdef PDCP_USE_NETLINK
+ netlink_init();
+#if defined(PDCP_USE_NETLINK_QUEUES)
+ pdcp_netlink_init();
+#endif
+#endif
+#if !defined(ENABLE_ITTI)
+ // to make a graceful exit when ctrl-c is pressed
+ signal(SIGSEGV, signal_handler);
+ signal(SIGINT, signal_handler);
+#endif
+#ifndef PACKAGE_VERSION
+# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL"
+#endif
+ LOG_I(HW, "Version: %s\n", PACKAGE_VERSION);
+#if defined(ENABLE_ITTI)
+
+ if (RC.nb_nr_inst > 0) {
+ // don't create if node doesn't connect to RRC/S1/GTP
+ AssertFatal(create_gNB_tasks(1) == 0,"cannot create ITTI tasks\n");
+ } else {
+ printf("No ITTI, Initializing L1\n");
+ RCconfig_L1();
+ }
+
+#endif
+ /* Start the agent. If it is turned off in the configuration, it won't start */
+ RCconfig_nr_flexran();
+
+ for (i = 0; i < RC.nb_nr_L1_inst; i++) {
+ flexran_agent_start(i);
+ }
+
+ // init UE_PF_PO and mutex lock
+ pthread_mutex_init(&ue_pf_po_mutex, NULL);
+ memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs);
+ mlockall(MCL_CURRENT | MCL_FUTURE);
+ pthread_cond_init(&sync_cond,NULL);
+ pthread_mutex_init(&sync_mutex, NULL);
+#ifdef XFORMS
+ int UE_id;
+
+ if (do_forms==1) {
+ fl_initialize (&argc, argv, NULL, 0, 0);
+ form_stats_l2 = create_form_stats_form();
+ fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats");
+ form_stats = create_form_stats_form();
+ fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats");
+
+ for(UE_id=0; UE_idphy_scope_gnb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title);
+
+ if (otg_enabled) {
+ fl_set_button(form_gnb[CC_id][UE_id]->button_0,1);
+ fl_set_object_label(form_gnb[CC_id][UE_id]->button_0,"DL Traffic ON");
+ } else {
+ fl_set_button(form_gnb[CC_id][UE_id]->button_0,0);
+ fl_set_object_label(form_gnb[CC_id][UE_id]->button_0,"DL Traffic OFF");
+ }
+ } // CC_id
+ } // UE_id
+
+ threadCreate(&forms_thread, scope_thread, NULL, "scope", -1, OAI_PRIORITY_RT_LOW);
+ printf("Scope thread created, ret=%d\n",ret);
+ }
+
+#endif
+ usleep(10*1000);
+
+ if (nfapi_mode) {
+ printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n");
+ pthread_cond_init(&sync_cond,NULL);
+ pthread_mutex_init(&sync_mutex, NULL);
+ }
+
+ const char *nfapi_mode_str = "";
+
+ switch(nfapi_mode) {
+ case 0:
+ nfapi_mode_str = "MONOLITHIC";
+ break;
+
+ case 1:
+ nfapi_mode_str = "PNF";
+ break;
+
+ case 2:
+ nfapi_mode_str = "VNF";
+ break;
+
+ default:
+ nfapi_mode_str = "";
+ break;
+ }
+
+ printf("NFAPI MODE:%s\n", nfapi_mode_str);
+
+ if (nfapi_mode==2) // VNF
+ wait_nfapi_init("main?");
+
+ printf("START MAIN THREADS\n");
+ // start the main threads
+ number_of_cards = 1;
+ printf("RC.nb_nr_L1_inst:%d\n", RC.nb_nr_L1_inst);
+
+ if (RC.nb_nr_L1_inst > 0) {
+ printf("Initializing gNB threads single_thread_flag:%d wait_for_sync:%d\n", single_thread_flag,wait_for_sync);
+ init_gNB(single_thread_flag,wait_for_sync);
+ }
+
+ printf("wait_gNBs()\n");
+ wait_gNBs();
+ printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU);
+
+ if (RC.nb_RU >0) {
+ printf("Initializing RU threads\n");
+ init_RU(rf_config_file);
+
+ for (ru_id=0; ru_idrf_map.card=0;
+ RC.ru[ru_id]->rf_map.chain=CC_id+chain_offset;
+ }
+ }
+
+ config_sync_var=0;
+
+ if (nfapi_mode==1) { // PNF
+ wait_nfapi_init("main?");
+ }
+
+ printf("wait RUs\n");
+ wait_RUs();
+ printf("ALL RUs READY!\n");
+ printf("RC.nb_RU:%d\n", RC.nb_RU);
+ // once all RUs are ready initialize the rest of the gNBs ((dependence on final RU parameters after configuration)
+ printf("ALL RUs ready - init gNBs\n");
+
+ if (nfapi_mode != 1 && nfapi_mode != 2) {
+ printf("Not NFAPI mode - call init_eNB_afterRU()\n");
+ init_eNB_afterRU();
+ } else {
+ printf("NFAPI mode - DO NOT call init_gNB_afterRU()\n");
+ }
+
+ printf("ALL RUs ready - ALL gNBs ready\n");
+ // connect the TX/RX buffers
+ printf("Sending sync to all threads\n");
+ pthread_mutex_lock(&sync_mutex);
+ sync_var=0;
+ pthread_cond_broadcast(&sync_cond);
+ pthread_mutex_unlock(&sync_mutex);
+ printf("About to call end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
+ end_configmodule();
+ printf("Called end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__);
+ // wait for end of program
+ printf("TYPE TO TERMINATE\n");
+ //getchar();
+#if defined(ENABLE_ITTI)
+ printf("Entering ITTI signals handler\n");
+ itti_wait_tasks_end();
+ printf("Returned from ITTI signal handler\n");
+ oai_exit=1;
+ printf("oai_exit=%d\n",oai_exit);
+#else
+
+ while (oai_exit==0)
+ sleep(1);
+
+ printf("Terminating application - oai_exit=%d\n",oai_exit);
+#endif
+ // stop threads
+#ifdef XFORMS
+ /*
+ printf("waiting for XFORMS thread\n");
+
+ if (do_forms==1) {
+ pthread_join(forms_thread,&status);
+ fl_hide_form(form_stats->stats_form);
+ fl_free_form(form_stats->stats_form);
+
+ fl_hide_form(form_stats_l2->stats_form);
+ fl_free_form(form_stats_l2->stats_form);
+
+ for(UE_id=0; UE_idphy_scope_gNB);
+ fl_free_form(form_enb[CC_id][UE_id]->phy_scope_gNB);
+ }
+ }
+ }
+ */
+#endif
+ printf("stopping MODEM threads\n");
+ // cleanup
+ stop_gNB(NB_gNB_INST);
+ stop_RU(NB_RU);
+
+ /* release memory used by the RU/gNB threads (incomplete), after all
+ * threads have been stopped (they partially use the same memory) */
+ for (int inst = 0; inst < NB_gNB_INST; inst++) {
+ for (int cc_id = 0; cc_id < RC.nb_nr_CC[inst]; cc_id++) {
+ //free_transport(RC.gNB[inst][cc_id]);
+ phy_free_nr_gNB(RC.gNB[inst][cc_id]);
+ }
+ }
+
+ for (int inst = 0; inst < NB_RU; inst++) {
+ nr_phy_free_RU(RC.ru[inst]);
+ }
+
+ free_lte_top();
+ pthread_cond_destroy(&sync_cond);
+ pthread_mutex_destroy(&sync_mutex);
+ pthread_cond_destroy(&nfapi_sync_cond);
+ pthread_mutex_destroy(&nfapi_sync_mutex);
+ pthread_mutex_destroy(&ue_pf_po_mutex);
+
+ // *** Handle per CC_id openair0
+
+ for(ru_id=0; ru_idrfdevice.trx_end_func)
+ RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice);
+
+ if (RC.ru[ru_id]->ifdevice.trx_end_func)
+ RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
+ }
+
+ if (opt_enabled == 1)
+ terminate_opt();
+
+ logClean();
+ printf("Bye.\n");
+ return 0;
+}
diff --git a/executables/nr-softmodem.h b/executables/nr-softmodem.h
new file mode 100644
index 0000000000..b01d92e6ed
--- /dev/null
+++ b/executables/nr-softmodem.h
@@ -0,0 +1,240 @@
+#ifndef NR_SOFTMODEM_H
+#define NR_SOFTMODEM_H
+
+#define _GNU_SOURCE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include "targets/ARCH/COMMON/common_lib.h"
+#undef MALLOC
+#include "assertions.h"
+#include "msc.h"
+#include "PHY/types.h"
+
+#include "flexran_agent.h"
+#include "PHY/defs_gNB.h"
+
+#if defined(ENABLE_ITTI)
+ #if defined(ENABLE_USE_MME)
+ #include "s1ap_eNB.h"
+ #ifdef PDCP_USE_NETLINK
+ #include "SIMULATION/ETH_TRANSPORT/proto.h"
+ #endif
+ #endif
+#endif
+
+/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */
+#define CONFIG_HLP_RFCFGF "Configuration file for front-end (e.g. LMS7002M)\n"
+#define CONFIG_HLP_ULMAXE "set the eNodeB max ULSCH erros\n"
+#define CONFIG_HLP_CALUER "set UE RX calibration\n"
+#define CONFIG_HLP_CALUERM ""
+#define CONFIG_HLP_CALUERB ""
+#define CONFIG_HLP_DBGUEPR "UE run normal prach power ramping, but don't continue random-access\n"
+#define CONFIG_HLP_CALPRACH "UE run normal prach with maximum power, but don't continue random-access\n"
+#define CONFIG_HLP_NOL2CN "bypass L2 and upper layers\n"
+#define CONFIG_HLP_UERXG "set UE RX gain\n"
+#define CONFIG_HLP_UERXGOFF "external UE amplifier offset\n"
+#define CONFIG_HLP_UETXG "set UE TX gain\n"
+#define CONFIG_HLP_UENANTR "set UE number of rx antennas\n"
+#define CONFIG_HLP_UENANTT "set UE number of tx antennas\n"
+#define CONFIG_HLP_UESCAN "set UE to scan around carrier\n"
+#define CONFIG_HLP_DUMPFRAME "dump UE received frame to rxsig_frame0.dat and exit\n"
+#define CONFIG_HLP_DLSHIFT "dynamic shift for LLR compuation for TM3/4 (default 0)\n"
+#define CONFIG_HLP_UELOOP "get softmodem (UE) to loop through memory instead of acquiring from HW\n"
+#define CONFIG_HLP_PHYTST "test UE phy layer, mac disabled\n"
+#define CONFIG_HLP_DMAMAP "sets flag for improved EXMIMO UE performance\n"
+#define CONFIG_HLP_EXCCLK "tells hardware to use an external clock reference\n"
+#define CONFIG_HLP_USIM "use XOR autentication algo in case of test usim mode\n"
+#define CONFIG_HLP_NOSNGLT "Disables single-thread mode in lte-softmodem\n"
+#define CONFIG_HLP_TADV "Set timing_advance\n"
+#define CONFIG_HLP_DLF "Set the downlink frequency for all component carriers\n"
+#define CONFIG_HLP_CHOFF "Channel id offset\n"
+#define CONFIG_HLP_SOFTS "Enable soft scope and L1 and L2 stats (Xforms)\n"
+#define CONFIG_HLP_EXMCAL "Calibrate the EXMIMO borad, available files: exmimo2_2arxg.lime exmimo2_2brxg.lime \n"
+#define CONFIG_HLP_ITTIL "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n"
+#define CONFIG_HLP_DLMCS "Set the maximum downlink MCS\n"
+#define CONFIG_HLP_STMON "Enable processing timing measurement of lte softmodem on per subframe basis \n"
+#define CONFIG_HLP_PRB "Set the PRB, valid values: 6, 25, 50, 100 \n"
+#define CONFIG_HLP_MSLOTS "Skip the missed slots/subframes \n"
+#define CONFIG_HLP_ULMCS "Set the maximum uplink MCS\n"
+#define CONFIG_HLP_TDD "Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n"
+#define CONFIG_HLP_UE "Set the lte softmodem as a UE\n"
+#define CONFIG_HLP_L2MONW "Enable L2 wireshark messages on localhost \n"
+#define CONFIG_HLP_L2MONP "Enable L2 pcap messages on localhost \n"
+#define CONFIG_HLP_VCD "Enable VCD (generated file will is named openair_dump_eNB.vcd, read it with target/RT/USER/eNB.gtkw\n"
+#define CONFIG_HLP_TQFS "Apply three-quarter of sampling frequency, 23.04 Msps to reduce the data rate on USB/PCIe transfers (only valid for 20 MHz)\n"
+#define CONFIG_HLP_TPORT "tracer port\n"
+#define CONFIG_HLP_NOTWAIT "don't wait for tracer, start immediately\n"
+#define CONFIG_HLP_TNOFORK "to ease debugging with gdb\n"
+#define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n"
+
+#define CONFIG_HLP_NUMEROLOGY "adding numerology for 5G\n"
+#define CONFIG_HLP_EMULATE_RF "Emulated RF enabled(disable by defult)\n"
+#define CONFIG_HLP_PARALLEL_CMD "three config for level of parallelism 'PARALLEL_SINGLE_THREAD', 'PARALLEL_RU_L1_SPLIT', or 'PARALLEL_RU_L1_TRX_SPLIT'\n"
+#define CONFIG_HLP_WORKER_CMD "two option for worker 'WORKER_DISABLE' or 'WORKER_ENABLE'\n"
+
+/***************************************************************************************************************************************/
+/* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument
+ when calling config_get or config_getlist functions */
+
+
+/*------------------------------------------------------------------------------------------------------------------------------------------*/
+/* command line parameters defining UE running mode */
+/* optname helpstr paramflags XXXptr defXXXval type numelt */
+/*------------------------------------------------------------------------------------------------------------------------------------------*/
+#define CMDLINE_UEMODEPARAMS_DESC { \
+ {"calib-ue-rx", CONFIG_HLP_CALUER, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \
+ {"calib-ue-rx-med", CONFIG_HLP_CALUERM, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \
+ {"calib-ue-rx-byp", CONFIG_HLP_CALUERB, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \
+ {"debug-ue-prach", CONFIG_HLP_DBGUEPR, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \
+ {"no-L2-connect", CONFIG_HLP_NOL2CN, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \
+ {"calib-prach-tx", CONFIG_HLP_CALPRACH, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \
+ {"loop-memory", CONFIG_HLP_UELOOP, 0, strptr:&loopfile, defstrval:"iqs.in", TYPE_STRING,0}, \
+ {"ue-dump-frame", CONFIG_HLP_DUMPFRAME, PARAMFLAG_BOOL, iptr:&dumpframe, defintval:0, TYPE_INT, 0}, \
+ }
+#define CMDLINE_CALIBUERX_IDX 0
+#define CMDLINE_CALIBUERXMED_IDX 1
+#define CMDLINE_CALIBUERXBYP_IDX 2
+#define CMDLINE_DEBUGUEPRACH_IDX 3
+#define CMDLINE_NOL2CONNECT_IDX 4
+#define CMDLINE_CALIBPRACHTX_IDX 5
+#define CMDLINE_MEMLOOP_IDX 6
+#define CMDLINE_DUMPMEMORY_IDX 7
+/*------------------------------------------------------------------------------------------------------------------------------------------*/
+
+
+#define DEFAULT_DLF 2680000000
+
+/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+/* command line parameters common to eNodeB and UE */
+/* optname helpstr paramflags XXXptr defXXXval type numelt */
+/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+#define CMDLINE_PARAMS_DESC { \
+ {"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&rf_config_file, defstrval:NULL, TYPE_STRING, sizeof(rf_config_file)}, \
+ {"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \
+ {"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&phy_test, defintval:0, TYPE_INT, 0}, \
+ {"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&usim_test, defintval:0, TYPE_UINT8, 0}, \
+ {"mmapped-dma", CONFIG_HLP_DMAMAP, PARAMFLAG_BOOL, uptr:&mmapped_dma, defintval:0, TYPE_INT, 0}, \
+ {"external-clock", CONFIG_HLP_EXCCLK, PARAMFLAG_BOOL, uptr:&clock_source, defintval:0, TYPE_INT, 0}, \
+ {"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&wait_for_sync, defintval:0, TYPE_INT, 0}, \
+ {"single-thread-disable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&single_thread_flag, defintval:1, TYPE_INT, 0}, \
+ {"A" , CONFIG_HLP_TADV, 0, uptr:&timing_advance, defintval:0, TYPE_UINT, 0}, \
+ {"C" , CONFIG_HLP_DLF, 0, uptr:&(downlink_frequency[0][0]), defuintval:DEFAULT_DLF, TYPE_UINT, 0}, \
+ {"a" , CONFIG_HLP_CHOFF, 0, iptr:&chain_offset, defintval:0, TYPE_INT, 0}, \
+ {"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&do_forms, defintval:0, TYPE_INT8, 0}, \
+ {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, i8ptr:&threequarter_fs, defintval:0, TYPE_INT8, 0}, \
+ {"K" , CONFIG_HLP_ITTIL, PARAMFLAG_NOFREE, strptr:&itti_dump_file, defstrval:"/tmp/itti.dump", TYPE_STRING, 0}, \
+ {"m" , CONFIG_HLP_DLMCS, 0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \
+ {"t" , CONFIG_HLP_ULMCS, 0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \
+ {"W" , CONFIG_HLP_L2MONW, 0, strptr:(char **)&in_ip, defstrval:"127.0.0.1", TYPE_STRING, sizeof(in_ip)}, \
+ {"P" , CONFIG_HLP_L2MONP, 0, strptr:(char **)&in_path, defstrval:"/tmp/oai_opt.pcap", TYPE_STRING, sizeof(in_path)}, \
+ {"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \
+ {"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \
+ {"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, {"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&numerology, defintval:0, TYPE_INT, 0}, \
+ {"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&emulate_rf, defintval:0, TYPE_INT, 0}, \
+ {"parallel-config", CONFIG_HLP_PARALLEL_CMD,0, strptr:(char **)¶llel_config, defstrval:NULL, TYPE_STRING, 0}, \
+ {"worker-config", CONFIG_HLP_WORKER_CMD, 0, strptr:(char **)&worker_config, defstrval:NULL, TYPE_STRING, 0}, \
+ {"nbiot-disable", CONFIG_HLP_DISABLNBIOT,PARAMFLAG_BOOL, iptr:&nonbiotflag, defintval:0, TYPE_INT, 0} \
+ }
+
+#define CONFIG_HLP_FLOG "Enable online log \n"
+#define CONFIG_HLP_LOGL "Set the global log level, valide options: (9:trace, 8/7:debug, 6:info, 4:warn, 3:error)\n"
+#define CONFIG_HLP_LOGV "Set the global log verbosity \n"
+#define CONFIG_HLP_TELN "Start embedded telnet server \n"
+/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+/* command line parameters for LOG utility */
+/* optname helpstr paramflags XXXptr defXXXval type numelt */
+/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+#define CMDLINE_LOGPARAMS_DESC { \
+ {"R" , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \
+ {"g" , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \
+ {"G" , CONFIG_HLP_LOGV, 0, uptr:&glog_verbosity, defintval:0, TYPE_UINT16, 0}, \
+ {"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \
+ }
+#define CMDLINE_ONLINELOG_IDX 0
+#define CMDLINE_GLOGLEVEL_IDX 1
+#define CMDLINE_GLOGVERBO_IDX 2
+#define CMDLINE_STARTTELN_IDX 3
+
+
+typedef struct {
+ int *argc;
+ char **argv;
+} scopeParms_t;
+
+extern int T_port;
+extern int T_nowait;
+extern int T_dont_fork;
+
+
+/***************************************************************************************************************************************/
+/* */
+extern pthread_cond_t sync_cond;
+extern pthread_mutex_t sync_mutex;
+extern int sync_var;
+
+
+extern uint32_t downlink_frequency[MAX_NUM_CCs][4];
+extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
+
+extern int rx_input_level_dBm;
+extern uint8_t exit_missed_slots;
+extern uint64_t num_missed_slots; // counter for the number of missed slots
+
+extern int oaisim_flag;
+extern volatile int oai_exit;
+
+extern openair0_config_t openair0_cfg[MAX_CARDS];
+extern pthread_cond_t sync_cond;
+extern pthread_mutex_t sync_mutex;
+extern int sync_var;
+extern int transmission_mode;
+extern double cpuf;
+
+#if defined(ENABLE_ITTI)
+ extern volatile int start_gNB;
+#endif
+
+#include "threads_t.h"
+extern threads_t threads;
+
+// In nr-gnb.c
+extern void init_gNB(int single_thread_flag,int wait_for_sync);
+extern void stop_gNB(int);
+extern void kill_gNB_proc(int inst);
+
+// In nr-ru.c
+extern void init_RU(const char *);
+extern void init_RU_proc(RU_t *ru);
+extern void stop_RU(int nb_ru);
+extern void kill_RU_proc(int inst);
+extern void set_function_spec_param(RU_t *ru);
+
+extern void reset_opp_meas(void);
+extern void print_opp_meas(void);
+
+extern void init_fep_thread(PHY_VARS_gNB *);
+
+void init_gNB_afterRU(void);
+
+extern int stop_L1L2(module_id_t gnb_id);
+extern int restart_L1L2(module_id_t gnb_id);
+
+#endif
+
diff --git a/executables/nr-ue.c b/executables/nr-ue.c
new file mode 100644
index 0000000000..bf0dc9809a
--- /dev/null
+++ b/executables/nr-ue.c
@@ -0,0 +1,768 @@
+/*
+ * 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.0 (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ * contact@openairinterface.org
+ */
+
+#include "executables/nr-uesoftmodem.h"
+
+#include "LAYER2/NR_MAC_UE/mac.h"
+//#include "RRC/LTE/rrc_extern.h"
+#include "PHY_INTERFACE/phy_interface_extern.h"
+
+#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
+//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "fapi_nr_ue_l1.h"
+#include "PHY/phy_extern_nr_ue.h"
+#include "PHY/INIT/phy_init.h"
+#include "PHY/MODULATION/modulation_UE.h"
+#include "LAYER2/NR_MAC_UE/mac_proto.h"
+#include "RRC/NR_UE/rrc_proto.h"
+
+//#ifndef NO_RAT_NR
+#include "SCHED_NR/phy_frame_config_nr.h"
+//#endif
+#include "SCHED_NR_UE/defs.h"
+
+#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
+
+#include "common/utils/LOG/log.h"
+#include "common/utils/system.h"
+#include "common/utils/LOG/vcd_signal_dumper.h"
+
+#include "T.h"
+
+#ifdef XFORMS
+ #include "PHY/TOOLS/nr_phy_scope.h"
+
+ extern char do_forms;
+#endif
+
+
+extern double cpuf;
+//static nfapi_nr_config_request_t config_t;
+//static nfapi_nr_config_request_t* config =&config_t;
+
+/*
+ * NR SLOT PROCESSING SEQUENCE
+ *
+ * Processing occurs with following steps for connected mode:
+ *
+ * - Rx samples for a slot are received,
+ * - PDCCH processing (including DCI extraction for downlink and uplink),
+ * - PDSCH processing (including transport blocks decoding),
+ * - PUCCH/PUSCH (transmission of acknowledgements, CSI, ... or data).
+ *
+ * Time between reception of the slot and related transmission depends on UE processing performance.
+ * It is defined by the value NR_UE_CAPABILITY_SLOT_RX_TO_TX.
+ *
+ * In NR, network gives the duration between Rx slot and Tx slot in the DCI:
+ * - for reception of a PDSCH and its associated acknowledgment slot (with a PUCCH or a PUSCH),
+ * - for reception of an uplink grant and its associated PUSCH slot.
+ *
+ * So duration between reception and it associated transmission depends on its transmission slot given in the DCI.
+ * NR_UE_CAPABILITY_SLOT_RX_TO_TX means the minimum duration but higher duration can be given by the network because UE can support it.
+ *
+ * Slot k
+ * -------+------------+--------
+ * Frame | Tx samples |
+ * Subframe | buffer |
+ * Slot n -------+------------+--------
+ * ------ +------------+-------- |
+ * | Rx samples | |
+ * | buffer | |
+ * -------+------------+-------- |
+ * | |
+ * V |
+ * +------------+ |
+ * | PDCCH | |
+ * | processing | |
+ * +------------+ |
+ * | | |
+ * | v |
+ * | +------------+ |
+ * | | PDSCH | |
+ * | | processing | decoding result |
+ * | +------------+ -> ACK/NACK of PDSCH |
+ * | | |
+ * | v |
+ * | +-------------+------------+ |
+ * | | PUCCH/PUSCH | Tx samples | |
+ * | | processing | transfer | |
+ * | +-------------+------------+ |
+ * | |
+ * |/___________________________________________________________\|
+ * \ duration between reception and associated transmission /
+ *
+ * Remark: processing is done slot by slot, it can be distribute on different threads which are executed in parallel.
+ * This is an architecture optimization in order to cope with real time constraints.
+ * By example, for LTE, subframe processing is spread over 4 different threads.
+ *
+ */
+
+#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 (4) /* For LTE, this duration is fixed to 4 and it is linked to LTE standard for both modes FDD/TDD */
+#endif
+
+#define FRAME_PERIOD 100000000ULL
+#define DAQ_PERIOD 66667ULL
+
+typedef enum {
+ pss=0,
+ pbch=1,
+ si=2
+} sync_mode_t;
+
+
+PHY_VARS_NR_UE *init_nr_ue_vars(NR_DL_FRAME_PARMS *frame_parms,
+ uint8_t UE_id,
+ uint8_t abstraction_flag)
+
+{
+ PHY_VARS_NR_UE *ue;
+ ue = (PHY_VARS_NR_UE *)malloc(sizeof(PHY_VARS_NR_UE));
+ memset(ue,0,sizeof(PHY_VARS_NR_UE));
+ memcpy(&(ue->frame_parms), frame_parms, sizeof(NR_DL_FRAME_PARMS));
+ ue->Mod_id = UE_id;
+ ue->mac_enabled = 1;
+ // initialize all signal buffers
+ init_nr_ue_signal(ue,1,abstraction_flag);
+ // intialize transport
+ init_nr_ue_transport(ue,abstraction_flag);
+ return(ue);
+}
+
+/*!
+ * It performs band scanning and synchonization.
+ * \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;
+
+static void UE_synch(void *arg) {
+ syncData_t *syncD=(syncData_t *) arg;
+ int i, hw_slot_offset;
+ PHY_VARS_NR_UE *UE = syncD->UE;
+ sync_mode_t sync_mode = pbch;
+ int CC_id = UE->CC_id;
+ int freq_offset=0;
+ UE->is_synchronized = 0;
+
+ if (UE->UE_scan == 0) {
+ get_band(downlink_frequency[CC_id][0], &UE->frame_parms.eutra_band, &uplink_frequency_offset[CC_id][0], &UE->frame_parms.frame_type);
+ LOG_I( PHY, "[SCHED][UE] Check absolute frequency DL %"PRIu32", UL %"PRIu32" (oai_exit %d, rx_num_channels %d)\n",
+ downlink_frequency[0][0], downlink_frequency[0][0]+uplink_frequency_offset[0][0],
+ oai_exit, openair0_cfg[0].rx_num_channels);
+
+ for (i=0; irf_map.card].rx_num_channels; i++) {
+ openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i];
+ openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] =
+ downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
+ openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1;
+
+ if (uplink_frequency_offset[CC_id][i] != 0) //
+ openair0_cfg[UE->rf_map.card].duplex_mode = duplex_mode_FDD;
+ else //FDD
+ openair0_cfg[UE->rf_map.card].duplex_mode = duplex_mode_TDD;
+ }
+
+ sync_mode = pbch;
+ } else {
+ LOG_E(PHY,"Fixme!\n");
+ /*
+ for (i=0; irf_map.card].rx_num_channels; i++) {
+ downlink_frequency[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[CC_id].dl_min;
+ uplink_frequency_offset[UE->rf_map.card][UE->rf_map.chain+i] =
+ bands_to_scan.band_info[CC_id].ul_min-bands_to_scan.band_info[CC_id].dl_min;
+ openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i];
+ openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] =
+ downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
+ openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;
+ }
+ */
+ }
+
+ LOG_W(PHY, "Starting sync detection\n");
+
+ switch (sync_mode) {
+ /*
+ case pss:
+ LOG_I(PHY,"[SCHED][UE] Scanning band %d (%d), freq %u\n",bands_to_scan.band_info[current_band].band, current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
+ //lte_sync_timefreq(UE,current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
+ current_offset += 20000000; // increase by 20 MHz
+
+ if (current_offset > bands_to_scan.band_info[current_band].dl_max-bands_to_scan.band_info[current_band].dl_min) {
+ current_band++;
+ current_offset=0;
+ }
+
+ if (current_band==bands_to_scan.nbands) {
+ current_band=0;
+ oai_exit=1;
+ }
+
+ for (i=0; irf_map.card].rx_num_channels; i++) {
+ downlink_frequency[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[current_band].dl_min+current_offset;
+ uplink_frequency_offset[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[current_band].ul_min-bands_to_scan.band_info[0].dl_min + current_offset;
+ openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i];
+ openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
+ openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;
+
+ if (UE->UE_scan_carrier) {
+ openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1;
+ }
+ }
+
+ break;
+ */
+ case pbch:
+ LOG_I(PHY, "[UE thread Synch] Running Initial Synch (mode %d)\n",UE->mode);
+
+ if (nr_initial_sync( &syncD->proc, UE, UE->mode ) == 0) {
+ freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
+ hw_slot_offset = (UE->rx_offset<<1) / UE->frame_parms.samples_per_slot;
+ LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %d (DL %u, UL %u), UE_scan_carrier %d\n",
+ hw_slot_offset,
+ freq_offset,
+ UE->rx_total_gain_dB,
+ downlink_frequency[0][0]+freq_offset,
+ downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset,
+ UE->UE_scan_carrier );
+
+ // rerun with new cell parameters and frequency-offset
+ for (i=0; irf_map.card].rx_num_channels; i++) {
+ openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
+
+ if (freq_offset >= 0)
+ openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] += abs(freq_offset);
+ else
+ openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] -= abs(freq_offset);
+
+ openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] =
+ openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i]+uplink_frequency_offset[CC_id][i];
+ downlink_frequency[CC_id][i] = openair0_cfg[CC_id].rx_freq[i];
+ }
+
+ // reconfigure for potentially different bandwidth
+ switch(UE->frame_parms.N_RB_DL) {
+ case 6:
+ openair0_cfg[UE->rf_map.card].sample_rate =1.92e6;
+ openair0_cfg[UE->rf_map.card].rx_bw =.96e6;
+ openair0_cfg[UE->rf_map.card].tx_bw =.96e6;
+ // openair0_cfg[0].rx_gain[0] -= 12;
+ break;
+
+ case 25:
+ openair0_cfg[UE->rf_map.card].sample_rate =7.68e6;
+ openair0_cfg[UE->rf_map.card].rx_bw =2.5e6;
+ openair0_cfg[UE->rf_map.card].tx_bw =2.5e6;
+ // openair0_cfg[0].rx_gain[0] -= 6;
+ break;
+
+ case 50:
+ openair0_cfg[UE->rf_map.card].sample_rate =15.36e6;
+ openair0_cfg[UE->rf_map.card].rx_bw =5.0e6;
+ openair0_cfg[UE->rf_map.card].tx_bw =5.0e6;
+ // openair0_cfg[0].rx_gain[0] -= 3;
+ break;
+
+ case 100:
+ openair0_cfg[UE->rf_map.card].sample_rate=30.72e6;
+ openair0_cfg[UE->rf_map.card].rx_bw=10.0e6;
+ openair0_cfg[UE->rf_map.card].tx_bw=10.0e6;
+ // openair0_cfg[0].rx_gain[0] -= 0;
+ break;
+ }
+
+ if (UE->mode != loop_through_memory) {
+ UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0);
+ //UE->rfdevice.trx_set_gains_func(&openair0,&openair0_cfg[0]);
+ //UE->rfdevice.trx_stop_func(&UE->rfdevice);
+ // sleep(1);
+ //nr_init_frame_parms_ue(&UE->frame_parms);
+ /*if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) {
+ LOG_E(HW,"Could not start the device\n");
+ oai_exit=1;
+ }*/
+ }
+
+ if (UE->UE_scan_carrier == 1) {
+ UE->UE_scan_carrier = 0;
+ } else {
+ UE->is_synchronized = 1;
+ }
+ } else {
+ // initial sync failed
+ // calculate new offset and try again
+ if (UE->UE_scan_carrier == 1) {
+ if (freq_offset >= 0)
+ freq_offset += 100;
+
+ freq_offset *= -1;
+ LOG_I(PHY, "[initial_sync] trying carrier off %d Hz, rxgain %d (DL %u, UL %u)\n",
+ freq_offset,
+ UE->rx_total_gain_dB,
+ downlink_frequency[0][0]+freq_offset,
+ downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset );
+
+ for (i=0; irf_map.card].rx_num_channels; i++) {
+ openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+freq_offset;
+ openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i]+freq_offset;
+ openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
+
+ if (UE->UE_scan_carrier==1)
+ openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1;
+ }
+
+ if (UE->mode != loop_through_memory)
+ UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0);
+ }// initial_sync=0
+
+ break;
+
+ case si:
+ default:
+ break;
+ }
+ }
+}
+
+void processSubframeRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
+ // Process Rx data for one sub-frame
+ if (slot_select_nr(&UE->frame_parms, proc->frame_tx, proc->nr_tti_tx) & NR_DOWNLINK_SLOT) {
+ //clean previous FAPI MESSAGE
+ UE->rx_ind.number_pdus = 0;
+ UE->dci_ind.number_of_dcis = 0;
+ //clean previous FAPI MESSAGE
+ // call L2 for DL_CONFIG (DCI)
+ UE->dcireq.module_id = UE->Mod_id;
+ UE->dcireq.gNB_index = 0;
+ UE->dcireq.cc_id = 0;
+ UE->dcireq.frame = proc->frame_rx;
+ UE->dcireq.slot = proc->nr_tti_rx;
+ nr_ue_dcireq(&UE->dcireq); //to be replaced with function pointer later
+ NR_UE_MAC_INST_t *UE_mac = get_mac_inst(0);
+ UE_mac->scheduled_response.dl_config = &UE->dcireq.dl_config_req;
+ UE_mac->scheduled_response.ul_config = NULL;
+ UE_mac->scheduled_response.tx_request = NULL;
+ UE_mac->scheduled_response.module_id = UE->Mod_id;
+ UE_mac->scheduled_response.CC_id = 0;
+ UE_mac->scheduled_response.frame = proc->frame_rx;
+ UE_mac->scheduled_response.slot = proc->nr_tti_rx;
+ nr_ue_scheduled_response(&UE_mac->scheduled_response);
+ //write_output("uerxdata_frame.m", "uerxdata_frame", UE->common_vars.rxdata[0], UE->frame_parms.samples_per_frame, 1, 1);
+#ifdef UE_SLOT_PARALLELISATION
+ phy_procedures_slot_parallelization_nrUE_RX( UE, proc, 0, 0, 1, UE->mode, no_relay, NULL );
+#else
+ uint64_t a=rdtsc();
+ phy_procedures_nrUE_RX( UE, proc, 0, 1, UE->mode);
+ LOG_D(PHY,"phy_procedures_nrUE_RX: slot:%d, time %lu\n", proc->nr_tti_rx, (rdtsc()-a)/3500);
+ // printf(">>> nr_ue_pdcch_procedures ended\n");
+#endif
+ }
+
+ if (UE->mac_enabled==1) {
+ // trigger L2 to run ue_scheduler thru IF module
+ // [TODO] mapping right after NR initial sync
+ if(UE->if_inst != NULL && UE->if_inst->ul_indication != NULL) {
+ UE->ul_indication.module_id = 0;
+ UE->ul_indication.gNB_index = 0;
+ UE->ul_indication.cc_id = 0;
+ UE->ul_indication.frame = proc->frame_rx;
+ UE->ul_indication.slot = proc->nr_tti_rx;
+ UE->if_inst->ul_indication(&UE->ul_indication);
+ }
+ }
+}
+
+/*!
+ * \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.
+ */
+
+typedef struct processingData_s {
+ UE_nr_rxtx_proc_t proc;
+ PHY_VARS_NR_UE *UE;
+} processingData_t;
+
+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;
+ processSubframeRX(UE, proc);
+ //printf(">>> mac ended\n");
+ // Prepare the future Tx data
+#if 0
+#ifndef NO_RAT_NR
+
+ if (slot_select_nr(&UE->frame_parms, proc->frame_tx, proc->nr_tti_tx) & NR_UPLINK_SLOT)
+#else
+ if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) ||
+ (UE->frame_parms.frame_type == FDD) )
+#endif
+ if (UE->mode != loop_through_memory)
+ phy_procedures_nrUE_TX(UE,proc,0,0,UE->mode,no_relay);
+
+ //phy_procedures_UE_TX(UE,proc,0,0,UE->mode,no_relay);
+#endif
+#if 0
+
+ if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_S) &&
+ (UE->frame_parms.frame_type == TDD))
+ if (UE->mode != loop_through_memory)
+ //phy_procedures_UE_S_TX(UE,0,0,no_relay);
+ updateTimes(current, &t3, 10000, timing_proc_name);
+
+#endif
+}
+
+void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) {
+ void *rxp[NB_ANTENNAS_RX];
+ void *dummy_tx[UE->frame_parms.nb_antennas_tx];
+
+ for (int i=0; iframe_parms.nb_antennas_tx; i++)
+ dummy_tx[i]=malloc16_clear(UE->frame_parms.samples_per_subframe*4);
+
+ for(int x=0; x<10; x++) {
+ for (int i=0; iframe_parms.nb_antennas_rx; i++)
+ rxp[i] = ((void *)&UE->common_vars.rxdata[i][0]) + 4*x*UE->frame_parms.samples_per_subframe;
+
+ AssertFatal( UE->frame_parms.samples_per_subframe ==
+ UE->rfdevice.trx_read_func(&UE->rfdevice,
+ timestamp,
+ rxp,
+ UE->frame_parms.samples_per_subframe,
+ UE->frame_parms.nb_antennas_rx), "");
+ }
+
+ for (int i=0; iframe_parms.nb_antennas_tx; i++)
+ free(dummy_tx[i]);
+}
+
+void trashFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) {
+ void *dummy_tx[UE->frame_parms.nb_antennas_tx];
+
+ for (int i=0; iframe_parms.nb_antennas_tx; i++)
+ dummy_tx[i]=malloc16_clear(UE->frame_parms.samples_per_subframe*4);
+
+ void *dummy_rx[UE->frame_parms.nb_antennas_rx];
+
+ for (int i=0; iframe_parms.nb_antennas_rx; i++)
+ dummy_rx[i]=malloc16(UE->frame_parms.samples_per_subframe*4);
+
+ for (int sf=0; sfrfdevice.trx_read_func(&UE->rfdevice,
+ timestamp,
+ dummy_rx,
+ UE->frame_parms.samples_per_subframe,
+ UE->frame_parms.nb_antennas_rx);
+ }
+
+ for (int i=0; iframe_parms.nb_antennas_tx; i++)
+ free(dummy_tx[i]);
+
+ for (int i=0; iframe_parms.nb_antennas_rx; i++)
+ free(dummy_rx[i]);
+}
+
+void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) {
+ if (UE->no_timing_correction==0) {
+ LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode);
+ void *dummy_tx[UE->frame_parms.nb_antennas_tx];
+
+ for (int i=0; iframe_parms.nb_antennas_tx; i++)
+ dummy_tx[i]=malloc16_clear(UE->frame_parms.samples_per_subframe*4);
+
+ for ( int size=UE->rx_offset ; size > 0 ; size -= UE->frame_parms.samples_per_subframe ) {
+ int unitTransfer=size>UE->frame_parms.samples_per_subframe ? UE->frame_parms.samples_per_subframe : size ;
+ AssertFatal(unitTransfer ==
+ UE->rfdevice.trx_read_func(&UE->rfdevice,
+ timestamp,
+ (void **)UE->common_vars.rxdata,
+ unitTransfer,
+ UE->frame_parms.nb_antennas_rx),"");
+ }
+
+ for (int i=0; iframe_parms.nb_antennas_tx; i++)
+ free(dummy_tx[i]);
+ }
+}
+
+int computeSamplesShift(PHY_VARS_NR_UE *UE) {
+ if ( getenv("RFSIMULATOR") != 0) {
+ LOG_E(PHY,"SET rx_offset %d \n",UE->rx_offset);
+ //UE->rx_offset_diff=0;
+ return 0;
+ }
+
+ // compute TO compensation that should be applied for this frame
+ if ( UE->rx_offset < UE->frame_parms.samples_per_frame/2 &&
+ UE->rx_offset > 0 ) {
+ //LOG_I(PHY,"!!!adjusting -1 samples!!!\n");
+ return -1 ;
+ }
+
+ if ( UE->rx_offset > UE->frame_parms.samples_per_frame/2 &&
+ UE->rx_offset < UE->frame_parms.samples_per_frame ) {
+ //LOG_I(PHY,"!!!adjusting +1 samples!!!\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+void *UE_thread(void *arg) {
+ //this thread should be over the processing thread to keep in real time
+ PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg;
+ // int tx_enabled = 0;
+ openair0_timestamp timestamp;
+ void *rxp[NB_ANTENNAS_RX], *txp[NB_ANTENNAS_TX];
+ int start_rx_stream = 0;
+ const uint16_t table_sf_slot[20] = {0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9};
+ AssertFatal(0== openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), "");
+ UE->rfdevice.host_type = RAU_HOST;
+ 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);
+
+ for (int i=0; iframe_parms.slots_per_subframe;
+ int absolute_slot=0, decoded_frame_rx=INT_MAX, trashed_frames=0;
+
+ while (!oai_exit) {
+ if (syncRunning) {
+ notifiedFIFO_elt_t *res=tryPullTpool(&nf, Tpool);
+
+ if (res) {
+ syncRunning=false;
+ syncData_t *tmp=(syncData_t *)NotifiedFifoData(res);
+ // shift the frame index with all the frames we trashed meanwhile we perform the synch search
+ decoded_frame_rx=(tmp->proc.decoded_frame_rx+trashed_frames) % MAX_FRAME_NUMBER;
+ delNotifiedFIFO_elt(res);
+ } else {
+ trashFrame(UE, ×tamp);
+ trashed_frames++;
+ continue;
+ }
+ }
+
+ AssertFatal( !syncRunning, "At this point synchronisation can't be running\n");
+
+ if (!UE->is_synchronized) {
+ readFrame(UE, ×tamp);
+ notifiedFIFO_elt_t *Msg=newNotifiedFIFO_elt(sizeof(syncData_t),0,&nf,UE_synch);
+ syncData_t *syncMsg=(syncData_t *)NotifiedFifoData(Msg);
+ syncMsg->UE=UE;
+ memset(&syncMsg->proc, 0, sizeof(syncMsg->proc));
+ pushTpool(Tpool, Msg);
+ trashed_frames=0;
+ syncRunning=true;
+ continue;
+ }
+
+ if (start_rx_stream==0) {
+ start_rx_stream=1;
+ syncInFrame(UE, ×tamp);
+ UE->rx_offset=0;
+ UE->time_sync_cell=0;
+ // read in first symbol
+ AssertFatal (UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 ==
+ UE->rfdevice.trx_read_func(&UE->rfdevice,
+ ×tamp,
+ (void **)UE->common_vars.rxdata,
+ UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0,
+ UE->frame_parms.nb_antennas_rx),"");
+ // we have the decoded frame index in the return of the synch process
+ // and we shifted above to the first slot of next frame
+ decoded_frame_rx++;
+ // we do ++ first in the regular processing, so it will be beging of frame;
+ absolute_slot=decoded_frame_rx*nb_slot_frame + nb_slot_frame -1;
+ continue;
+ }
+
+ absolute_slot++;
+ // 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
+ // this is general failure in UE !!!
+ thread_idx = absolute_slot % 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);
+ curMsg->UE=UE;
+ // update thread index for received subframe
+ curMsg->proc.nr_tti_rx= slot_nr;
+ curMsg->UE->current_thread_id[slot_nr] = thread_idx;
+ curMsg->proc.subframe_rx=table_sf_slot[slot_nr];
+ curMsg->proc.nr_tti_tx = (absolute_slot + DURATION_RX_TO_TX) % nb_slot_frame;
+ curMsg->proc.subframe_tx=curMsg->proc.nr_tti_rx;
+ curMsg->proc.frame_rx = ( absolute_slot/nb_slot_frame ) % MAX_FRAME_NUMBER;
+ curMsg->proc.frame_tx = ( (absolute_slot + DURATION_RX_TO_TX) /nb_slot_frame ) % MAX_FRAME_NUMBER;
+ curMsg->proc.decoded_frame_rx=-1;
+ LOG_D(PHY,"Process slot %d thread Idx %d \n", slot_nr, thread_idx);
+
+ for (int i=0; iframe_parms.nb_antennas_rx; i++)
+ rxp[i] = (void *)&UE->common_vars.rxdata[i][UE->frame_parms.ofdm_symbol_size+
+ UE->frame_parms.nb_prefix_samples0+
+ slot_nr*UE->frame_parms.samples_per_slot];
+
+ for (int i=0; iframe_parms.nb_antennas_tx; i++)
+ txp[i] = (void *)&UE->common_vars.txdata[i][curMsg->proc.nr_tti_tx*UE->frame_parms.samples_per_slot];
+
+ int readBlockSize, writeBlockSize;
+
+ if (slot_nr<(nb_slot_frame - 1)) {
+ readBlockSize=UE->frame_parms.samples_per_slot;
+ writeBlockSize=UE->frame_parms.samples_per_slot;
+ } else {
+ UE->rx_offset_diff = computeSamplesShift(UE);
+ readBlockSize=UE->frame_parms.samples_per_slot -
+ UE->frame_parms.ofdm_symbol_size -
+ UE->frame_parms.nb_prefix_samples0 -
+ UE->rx_offset_diff;
+ writeBlockSize=UE->frame_parms.samples_per_slot -
+ UE->rx_offset_diff;
+ }
+
+ AssertFatal(readBlockSize ==
+ UE->rfdevice.trx_read_func(&UE->rfdevice,
+ ×tamp,
+ rxp,
+ readBlockSize,
+ UE->frame_parms.nb_antennas_rx),"");
+ AssertFatal( writeBlockSize ==
+ UE->rfdevice.trx_write_func(&UE->rfdevice,
+ timestamp+
+ (2*UE->frame_parms.samples_per_slot) -
+ UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 -
+ openair0_cfg[0].tx_sample_advance,
+ txp,
+ writeBlockSize,
+ UE->frame_parms.nb_antennas_tx,
+ 1),"");
+
+ if( slot_nr==(nb_slot_frame-1)) {
+ // read in first symbol of next frame and adjust for timing drift
+ int first_symbols=writeBlockSize-readBlockSize;
+
+ if ( first_symbols > 0 )
+ AssertFatal(first_symbols ==
+ UE->rfdevice.trx_read_func(&UE->rfdevice,
+ ×tamp,
+ (void **)UE->common_vars.rxdata,
+ first_symbols,
+ UE->frame_parms.nb_antennas_rx),"");
+ else
+ LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols);
+ }
+
+ curMsg->proc.timestamp_tx = timestamp+
+ (DURATION_RX_TO_TX*UE->frame_parms.samples_per_slot)-
+ UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0;
+ notifiedFIFO_elt_t *res;
+
+ while (nbSlotProcessing >= RX_NB_TH) {
+ if ( (res=tryPullTpool(&nf, Tpool)) != NULL ) {
+ nbSlotProcessing--;
+ processingData_t *tmp=(processingData_t *)res->msgData;
+
+ if (tmp->proc.decoded_frame_rx != -1)
+ decoded_frame_rx=tmp->proc.decoded_frame_rx;
+
+ pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
+ }
+
+ usleep(200);
+ }
+
+ if ( decoded_frame_rx != curMsg->proc.frame_rx &&
+ ((decoded_frame_rx+1) % MAX_FRAME_NUMBER) != curMsg->proc.frame_rx )
+ LOG_D(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 );
+
+ nbSlotProcessing++;
+ msgToPush->key=slot_nr;
+ pushTpool(Tpool, msgToPush);
+
+ if (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, Tpool);
+ nbSlotProcessing--;
+ processingData_t *tmp=(processingData_t *)res->msgData;
+
+ if (tmp->proc.decoded_frame_rx != -1)
+ decoded_frame_rx=tmp->proc.decoded_frame_rx;
+
+ pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
+ }
+ } // while !oai_exit
+
+ return NULL;
+}
+
+void init_UE(int nb_inst) {
+ int inst;
+ NR_UE_MAC_INST_t *mac_inst;
+ pthread_t threads[nb_inst];
+
+ for (inst=0; inst < nb_inst; inst++) {
+ PHY_VARS_NR_UE *UE = PHY_vars_UE_g[inst][0];
+ AssertFatal((UE->if_inst = nr_ue_if_module_init(inst)) != NULL, "can not initial IF module\n");
+ nr_l3_init_ue();
+ nr_l2_init_ue();
+ mac_inst = get_mac_inst(inst);
+ mac_inst->if_module = UE->if_inst;
+ // Initial bandwidth part configuration -- full carrier bandwidth
+ mac_inst->initial_bwp_dl.bwp_id = 0;
+ mac_inst->initial_bwp_dl.location = 0;
+ mac_inst->initial_bwp_dl.scs = UE->frame_parms.subcarrier_spacing;
+ mac_inst->initial_bwp_dl.N_RB = UE->frame_parms.N_RB_DL;
+ mac_inst->initial_bwp_dl.cyclic_prefix = UE->frame_parms.Ncp;
+ mac_inst->initial_bwp_ul.bwp_id = 0;
+ mac_inst->initial_bwp_ul.location = 0;
+ mac_inst->initial_bwp_ul.scs = UE->frame_parms.subcarrier_spacing;
+ mac_inst->initial_bwp_ul.N_RB = UE->frame_parms.N_RB_UL;
+ mac_inst->initial_bwp_ul.cyclic_prefix = UE->frame_parms.Ncp;
+ LOG_I(PHY,"Intializing UE Threads for instance %d (%p,%p)...\n",inst,PHY_vars_UE_g[inst],PHY_vars_UE_g[inst][0]);
+ threadCreate(&threads[inst], UE_thread, (void *)UE, "UEthread", -1, OAI_PRIORITY_RT_MAX);
+ }
+
+ printf("UE threads created by %ld\n", gettid());
+}
+
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
new file mode 100644
index 0000000000..8300f10675
--- /dev/null
+++ b/executables/nr-uesoftmodem.c
@@ -0,0 +1,775 @@
+/*
+ * 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
+ */
+
+
+#define _GNU_SOURCE /* See feature_test_macros(7) */
+#include
+
+#include "T.h"
+#include "assertions.h"
+#include "PHY/types.h"
+#include "PHY/defs_nr_UE.h"
+#include "common/ran_context.h"
+#include "common/config/config_userapi.h"
+#include "common/utils/load_module_shlib.h"
+//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "../../ARCH/COMMON/common_lib.h"
+#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h"
+
+//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
+
+#include "PHY/phy_vars_nr_ue.h"
+#include "PHY/LTE_TRANSPORT/transport_vars.h"
+#include "SCHED/sched_common_vars.h"
+#include "PHY/MODULATION/modulation_vars.h"
+//#include "../../SIMU/USER/init_lte.h"
+
+#include "LAYER2/MAC/mac_vars.h"
+#include "LAYER2/MAC/mac_proto.h"
+#include "RRC/LTE/rrc_vars.h"
+#include "PHY_INTERFACE/phy_interface_vars.h"
+
+#ifdef SMBV
+#include "PHY/TOOLS/smbv.h"
+unsigned short config_frames[4] = {2,9,11,13};
+#endif
+#include "common/utils/LOG/log.h"
+#include "common/utils/LOG/vcd_signal_dumper.h"
+
+#include "UTIL/OPT/opt.h"
+#include "enb_config.h"
+//#include "PHY/TOOLS/time_meas.h"
+
+#ifndef OPENAIR2
+ #include "UTIL/OTG/otg_vars.h"
+#endif
+
+#include "intertask_interface.h"
+
+#include "PHY/INIT/phy_init.h"
+#include "system.h"
+#include
+#include
+#include
+#include
+#include
+
+#ifdef XFORMS
+#include
+
+/* Callbacks, globals and object handlers */
+
+extern void reset_stats( FL_OBJECT *, long );
+
+/* Forms and Objects */
+
+typedef struct {
+ FL_FORM *stats_form;
+ void *vdata;
+ char *cdata;
+ long ldata;
+ FL_OBJECT *stats_text;
+ FL_OBJECT *stats_button;
+} FD_stats_form;
+
+extern FD_stats_form *create_form_stats_form( void );
+
+#include "PHY/TOOLS/nr_phy_scope.h"
+//#include "stats.h"
+// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0)
+// at eNB 0, an UL scope for every UE
+FD_phy_scope_nrue *form_nrue[NUMBER_OF_UE_MAX];
+//FD_lte_phy_scope_enb *form_enb[MAX_NUM_CCs][NUMBER_OF_UE_MAX];
+//FD_stats_form *form_stats=NULL,*form_stats_l2=NULL;
+char title[255];
+unsigned char scope_enb_num_ue = 2;
+static pthread_t forms_thread; //xforms
+#endif //XFORMS
+#include
+
+RAN_CONTEXT_t RC;
+volatile int start_eNB = 0;
+volatile int start_UE = 0;
+volatile int oai_exit = 0;
+
+static clock_source_t clock_source = internal;
+int single_thread_flag=1;
+
+int threequarter_fs=0;
+
+uint32_t downlink_frequency[MAX_NUM_CCs][4];
+int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
+
+extern int16_t nr_dlsch_demod_shift;
+
+int UE_scan = 0;
+int UE_scan_carrier = 0;
+int UE_fo_compensation = 0;
+runmode_t mode = normal_txrx;
+openair0_config_t openair0_cfg[MAX_CARDS];
+
+#if MAX_NUM_CCs == 1
+rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}};
+double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}};
+double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}};
+#else
+rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}};
+double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}};
+double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}};
+#endif
+
+double rx_gain_off = 0.0;
+
+double sample_rate=30.72e6;
+double bw = 10.0e6;
+
+static int tx_max_power[MAX_NUM_CCs] = {0};
+
+char rf_config_file[1024];
+
+int chain_offset=0;
+int phy_test = 0;
+uint8_t usim_test = 0;
+
+uint8_t dci_Format = 0;
+uint8_t agregation_Level =0xFF;
+
+uint8_t nb_antenna_tx = 1;
+uint8_t nb_antenna_rx = 1;
+
+char ref[128] = "internal";
+char channels[128] = "0";
+
+char *parallel_config = NULL;
+char *worker_config = NULL;
+
+static THREAD_STRUCT thread_struct;
+void set_parallel_conf(char *parallel_conf) {
+ if(strcmp(parallel_conf,"PARALLEL_SINGLE_THREAD")==0) thread_struct.parallel_conf = PARALLEL_SINGLE_THREAD;
+ else if(strcmp(parallel_conf,"PARALLEL_RU_L1_SPLIT")==0) thread_struct.parallel_conf = PARALLEL_RU_L1_SPLIT;
+ else if(strcmp(parallel_conf,"PARALLEL_RU_L1_TRX_SPLIT")==0) thread_struct.parallel_conf = PARALLEL_RU_L1_TRX_SPLIT;
+
+ printf("[CONFIG] parallel conf is set to %d\n",thread_struct.parallel_conf);
+}
+void set_worker_conf(char *worker_conf) {
+ if(strcmp(worker_conf,"WORKER_DISABLE")==0) thread_struct.worker_conf = WORKER_DISABLE;
+ else if(strcmp(worker_conf,"WORKER_ENABLE")==0) thread_struct.worker_conf = WORKER_ENABLE;
+
+ printf("[CONFIG] worker conf is set to %d\n",thread_struct.worker_conf);
+}
+PARALLEL_CONF_t get_thread_parallel_conf(void) {
+ return thread_struct.parallel_conf;
+}
+WORKER_CONF_t get_thread_worker_conf(void) {
+ return thread_struct.worker_conf;
+}
+int rx_input_level_dBm;
+
+//static int online_log_messages=0;
+
+#ifdef XFORMS
+ extern int otg_enabled;
+ int do_forms=0;
+#else
+ int otg_enabled;
+#endif
+//int number_of_cards = 1;
+
+static NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs];
+int16_t node_synch_ref[MAX_NUM_CCs];
+
+uint32_t target_dl_mcs = 28; //maximum allowed mcs
+uint32_t target_ul_mcs = 20;
+uint32_t timing_advance = 0;
+uint8_t exit_missed_slots=1;
+uint64_t num_missed_slots=0; // counter for the number of missed slots
+
+
+int transmission_mode=1;
+int numerology = 0;
+
+/* flag set by eNB conf file to specify if the radio head is local or remote (default option is local) */
+//uint8_t local_remote_radio = BBU_LOCAL_RADIO_HEAD;
+/* struct for ethernet specific parameters given in eNB conf file */
+//eth_params_t *eth_params;
+
+double cpuf;
+
+char uecap_xer[1024],uecap_xer_in=0;
+
+int oaisim_flag=0;
+int emulate_rf = 0;
+
+tpool_t *Tpool;
+
+char *usrp_args=NULL;
+char *usrp_clksrc=NULL;
+
+/* forward declarations */
+void set_default_frame_parms(NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]);
+
+
+/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed
+ * this is very hackish - find a proper solution
+ */
+uint8_t abstraction_flag=0;
+
+/*---------------------BMC: timespec helpers -----------------------------*/
+
+struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
+struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
+
+struct timespec clock_difftime(struct timespec start, struct timespec end) {
+ struct timespec temp;
+
+ if ((end.tv_nsec-start.tv_nsec)<0) {
+ temp.tv_sec = end.tv_sec-start.tv_sec-1;
+ temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
+ } else {
+ temp.tv_sec = end.tv_sec-start.tv_sec;
+ temp.tv_nsec = end.tv_nsec-start.tv_nsec;
+ }
+
+ return temp;
+}
+
+void print_difftimes(void) {
+ LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
+}
+
+void exit_function(const char *file, const char *function, const int line, const char *s) {
+ int CC_id;
+
+ if (s != NULL) {
+ printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s);
+ }
+
+ oai_exit = 1;
+
+ if (PHY_vars_UE_g && PHY_vars_UE_g[0]) {
+ for(CC_id=0; CC_idrfdevice.trx_end_func)
+ PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][CC_id]->rfdevice);
+ }
+ }
+
+ sleep(1); //allow lte-softmodem threads to exit first
+ itti_terminate_tasks (TASK_UNKNOWN);
+}
+
+#ifdef XFORMS
+
+
+void reset_stats(FL_OBJECT *button, long arg) {
+ //int i,j,k;
+ /*PHY_VARS_eNB *phy_vars_eNB = PHY_vars_eNB_g[0][0];
+
+ for (i=0; idlsch[i][0]->Mlimit; j++) {
+ phy_vars_eNB->UE_stats[i].dlsch_NAK[k][j]=0;
+ phy_vars_eNB->UE_stats[i].dlsch_ACK[k][j]=0;
+ phy_vars_eNB->UE_stats[i].dlsch_trials[k][j]=0;
+ }
+
+ phy_vars_eNB->UE_stats[i].dlsch_l2_errors[k]=0;
+ phy_vars_eNB->UE_stats[i].ulsch_errors[k]=0;
+ phy_vars_eNB->UE_stats[i].ulsch_consecutive_errors=0;
+
+ for (j=0; julsch[i]->Mlimit; j++) {
+ phy_vars_eNB->UE_stats[i].ulsch_decoding_attempts[k][j]=0;
+ phy_vars_eNB->UE_stats[i].ulsch_decoding_attempts_last[k][j]=0;
+ phy_vars_eNB->UE_stats[i].ulsch_round_errors[k][j]=0;
+ phy_vars_eNB->UE_stats[i].ulsch_round_fer[k][j]=0;
+ }
+ }
+
+ phy_vars_eNB->UE_stats[i].dlsch_sliding_cnt=0;
+ phy_vars_eNB->UE_stats[i].dlsch_NAK_round0=0;
+ phy_vars_eNB->UE_stats[i].dlsch_mcs_offset=0;
+ }*/
+}
+
+static void *scope_thread(void *arg) {
+ sleep(5);
+
+ while (!oai_exit) {
+ phy_scope_nrUE(form_nrue[0],
+ PHY_vars_UE_g[0][0],
+ 0,0,1);
+ usleep(100*1000);
+ }
+
+ pthread_exit((void *)arg);
+}
+#endif
+
+void init_scope(void) {
+#ifdef XFORMS
+ int fl_argc=1;
+
+ if (do_forms==1) {
+ char *name="5G-UE-scope";
+ fl_initialize (&fl_argc, &name, NULL, 0, 0);
+ int UE_id = 0;
+ form_nrue[UE_id] = create_phy_scope_nrue();
+ sprintf (title, "NR DL SCOPE UE");
+ fl_show_form (form_nrue[UE_id]->phy_scope_nrue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title);
+ threadCreate(&forms_thread, scope_thread, NULL, "scope", -1, OAI_PRIORITY_RT_LOW);
+ }
+
+#endif
+}
+
+
+#if defined(ENABLE_ITTI)
+void *l2l1_task(void *arg) {
+ MessageDef *message_p = NULL;
+ int result;
+ itti_set_task_real_time(TASK_L2L1);
+ itti_mark_task_ready(TASK_L2L1);
+
+ do {
+ // Wait for a message
+ itti_receive_msg (TASK_L2L1, &message_p);
+
+ switch (ITTI_MSG_ID(message_p)) {
+ case TERMINATE_MESSAGE:
+ oai_exit=1;
+ itti_exit_task ();
+ break;
+
+ case ACTIVATE_MESSAGE:
+ start_UE = 1;
+ break;
+
+ case DEACTIVATE_MESSAGE:
+ start_UE = 0;
+ break;
+
+ case MESSAGE_TEST:
+ LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p));
+ break;
+
+ default:
+ LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p));
+ break;
+ }
+
+ result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
+ AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+ } while(!oai_exit);
+
+ return NULL;
+}
+#endif
+
+int16_t dlsch_demod_shift;
+
+static void get_options(void) {
+ int CC_id;
+ int tddflag=0, nonbiotflag;
+ char *loopfile=NULL;
+ int dumpframe=0;
+ uint32_t online_log_messages;
+ uint32_t glog_level, glog_verbosity;
+ uint32_t start_telnetsrv=0;
+ paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ;
+ paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
+ config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL);
+
+ if (strlen(in_path) > 0) {
+ opt_type = OPT_PCAP;
+ opt_enabled=1;
+ printf("Enabling OPT for PCAP with the following file %s \n",in_path);
+ }
+
+ if (strlen(in_ip) > 0) {
+ opt_enabled=1;
+ opt_type = OPT_WIRESHARK;
+ printf("Enabling OPT for wireshark for local interface");
+ }
+
+ config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL);
+
+ if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) {
+ set_glog_onlinelog(online_log_messages);
+ }
+
+ if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) {
+ set_glog(glog_level);
+ }
+
+ if (start_telnetsrv) {
+ load_module_shlib("telnetsrv",NULL,0,NULL);
+ }
+
+ paramdef_t cmdline_uemodeparams[] =CMDLINE_UEMODEPARAMS_DESC;
+ paramdef_t cmdline_ueparams[] =CMDLINE_UEPARAMS_DESC;
+ config_process_cmdline( cmdline_uemodeparams,sizeof(cmdline_uemodeparams)/sizeof(paramdef_t),NULL);
+ config_process_cmdline( cmdline_ueparams,sizeof(cmdline_ueparams)/sizeof(paramdef_t),NULL);
+
+ if ( (cmdline_uemodeparams[CMDLINE_CALIBUERX_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue;
+
+ if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXMED_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_med;
+
+ if ( (cmdline_uemodeparams[CMDLINE_CALIBUERXBYP_IDX].paramflags & PARAMFLAG_PARAMSET) != 0) mode = rx_calib_ue_byp;
+
+ if (cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].uptr)
+ if ( *(cmdline_uemodeparams[CMDLINE_DEBUGUEPRACH_IDX].uptr) > 0) mode = debug_prach;
+
+ if (cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].uptr)
+ if ( *(cmdline_uemodeparams[CMDLINE_NOL2CONNECT_IDX].uptr) > 0) mode = no_L2_connect;
+
+ if (cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].uptr)
+ if ( *(cmdline_uemodeparams[CMDLINE_CALIBPRACHTX_IDX].uptr) > 0) mode = calib_prach_tx;
+
+ if (dumpframe > 0) mode = rx_dump_frame;
+
+ for (CC_id=0; CC_iddl_CarrierFreq = downlink_frequency[0][0];
+ }
+
+ UE_scan=0;
+
+ if (tddflag > 0) {
+ for (CC_id=0; CC_idframe_type = TDD;
+ }
+
+ /*if (frame_parms[0]->N_RB_DL !=0) {
+ if ( frame_parms[0]->N_RB_DL < 6 ) {
+ frame_parms[0]->N_RB_DL = 6;
+ printf ( "%i: Invalid number of ressource blocks, adjusted to 6\n",frame_parms[0]->N_RB_DL);
+ }
+ if ( frame_parms[0]->N_RB_DL > 100 ) {
+ frame_parms[0]->N_RB_DL = 100;
+ printf ( "%i: Invalid number of ressource blocks, adjusted to 100\n",frame_parms[0]->N_RB_DL);
+ }
+ if ( frame_parms[0]->N_RB_DL > 50 && frame_parms[0]->N_RB_DL < 100 ) {
+ frame_parms[0]->N_RB_DL = 50;
+ printf ( "%i: Invalid number of ressource blocks, adjusted to 50\n",frame_parms[0]->N_RB_DL);
+ }
+ if ( frame_parms[0]->N_RB_DL > 25 && frame_parms[0]->N_RB_DL < 50 ) {
+ frame_parms[0]->N_RB_DL = 25;
+ printf ( "%i: Invalid number of ressource blocks, adjusted to 25\n",frame_parms[0]->N_RB_DL);
+ }
+ UE_scan = 0;
+ frame_parms[0]->N_RB_UL=frame_parms[0]->N_RB_DL;
+ for (CC_id=1; CC_idN_RB_DL=frame_parms[0]->N_RB_DL;
+ frame_parms[CC_id]->N_RB_UL=frame_parms[0]->N_RB_UL;
+ }
+ }*/
+
+ for (CC_id=1; CC_ideutra_band = 78;
+ frame_parms[CC_id]->frame_type = FDD;
+ frame_parms[CC_id]->tdd_config = 3;
+ //frame_parms[CC_id]->tdd_config_S = 0;
+ frame_parms[CC_id]->N_RB_DL = 106;
+ frame_parms[CC_id]->N_RB_UL = 106;
+ frame_parms[CC_id]->Ncp = NORMAL;
+ //frame_parms[CC_id]->Ncp_UL = NORMAL;
+ frame_parms[CC_id]->Nid_cell = 0;
+ //frame_parms[CC_id]->num_MBSFN_config = 0;
+ frame_parms[CC_id]->nb_antenna_ports_eNB = 1;
+ frame_parms[CC_id]->nb_antennas_tx = 1;
+ frame_parms[CC_id]->nb_antennas_rx = 1;
+ //frame_parms[CC_id]->nushift = 0;
+ // NR: Init to legacy LTE 20Mhz params
+ frame_parms[CC_id]->numerology_index = 0;
+ frame_parms[CC_id]->ttis_per_subframe = 1;
+ frame_parms[CC_id]->slots_per_tti = 2;
+ }
+}
+
+void init_openair0(void) {
+ int card;
+ int i;
+
+ for (card=0; cardN_RB_DL == 106) {
+ if (numerology==0) {
+ if (frame_parms[0]->threequarter_fs) {
+ openair0_cfg[card].sample_rate=23.04e6;
+ openair0_cfg[card].samples_per_frame = 230400;
+ openair0_cfg[card].tx_bw = 10e6;
+ openair0_cfg[card].rx_bw = 10e6;
+ } else {
+ openair0_cfg[card].sample_rate=30.72e6;
+ openair0_cfg[card].samples_per_frame = 307200;
+ openair0_cfg[card].tx_bw = 10e6;
+ openair0_cfg[card].rx_bw = 10e6;
+ }
+ } else if (numerology==1) {
+ openair0_cfg[card].sample_rate=61.44e6;
+ openair0_cfg[card].samples_per_frame = 307200;
+ openair0_cfg[card].tx_bw = 20e6;
+ openair0_cfg[card].rx_bw = 20e6;
+ } else if (numerology==2) {
+ openair0_cfg[card].sample_rate=122.88e6;
+ openair0_cfg[card].samples_per_frame = 307200;
+ openair0_cfg[card].tx_bw = 40e6;
+ openair0_cfg[card].rx_bw = 40e6;
+ } else {
+ LOG_E(PHY,"Unsupported numerology!\n");
+ exit(-1);
+ }
+ } else if(frame_parms[0]->N_RB_DL == 50) {
+ openair0_cfg[card].sample_rate=15.36e6;
+ openair0_cfg[card].samples_per_frame = 153600;
+ openair0_cfg[card].tx_bw = 5e6;
+ openair0_cfg[card].rx_bw = 5e6;
+ } else if (frame_parms[0]->N_RB_DL == 25) {
+ openair0_cfg[card].sample_rate=7.68e6;
+ openair0_cfg[card].samples_per_frame = 76800;
+ openair0_cfg[card].tx_bw = 2.5e6;
+ openair0_cfg[card].rx_bw = 2.5e6;
+ } else if (frame_parms[0]->N_RB_DL == 6) {
+ openair0_cfg[card].sample_rate=1.92e6;
+ openair0_cfg[card].samples_per_frame = 19200;
+ openair0_cfg[card].tx_bw = 1.5e6;
+ openair0_cfg[card].rx_bw = 1.5e6;
+ }
+
+ if (frame_parms[0]->frame_type==TDD)
+ openair0_cfg[card].duplex_mode = duplex_mode_TDD;
+ else //FDD
+ openair0_cfg[card].duplex_mode = duplex_mode_FDD;
+
+ printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card,
+ PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx,
+ PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx);
+ openair0_cfg[card].Mod_id = 0;
+ openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL;
+ openair0_cfg[card].clock_source = clock_source;
+ openair0_cfg[card].tx_num_channels=min(2,PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx);
+ openair0_cfg[card].rx_num_channels=min(2,PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx);
+
+ for (i=0; i<4; i++) {
+ if (irx_total_gain_dB - rx_gain_off;
+ openair0_cfg[card].configFilename = rf_config_file;
+ printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n",
+ card,i, openair0_cfg[card].tx_gain[i],
+ openair0_cfg[card].rx_gain[i],
+ openair0_cfg[card].tx_freq[i],
+ openair0_cfg[card].rx_freq[i]);
+ }
+
+ if (usrp_args) openair0_cfg[card].sdr_addrs = usrp_args;
+
+ if (usrp_clksrc) {
+ if (strcmp(usrp_clksrc, "internal") == 0) {
+ openair0_cfg[card].clock_source = internal;
+ LOG_D(PHY, "USRP clock source set as internal\n");
+ } else if (strcmp(usrp_clksrc, "external") == 0) {
+ openair0_cfg[card].clock_source = external;
+ LOG_D(PHY, "USRP clock source set as external\n");
+ } else if (strcmp(usrp_clksrc, "gpsdo") == 0) {
+ openair0_cfg[card].clock_source = gpsdo;
+ LOG_D(PHY, "USRP clock source set as gpsdo\n");
+ } else {
+ openair0_cfg[card].clock_source = internal;
+ LOG_I(PHY, "USRP clock source unknown ('%s'). defaulting to internal\n", usrp_clksrc);
+ }
+ } else {
+ openair0_cfg[card].clock_source = internal;
+ LOG_I(PHY, "USRP clock source not specified. defaulting to internal\n");
+ }
+ }
+}
+
+
+int main( int argc, char **argv ) {
+ //uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2;
+ PHY_VARS_NR_UE *UE[MAX_NUM_CCs];
+ start_background_system();
+
+ if ( load_configmodule(argc,argv) == NULL) {
+ exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
+ }
+
+ CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
+ set_default_frame_parms(frame_parms);
+ mode = normal_txrx;
+ memset(openair0_cfg,0,sizeof(openair0_config_t)*MAX_CARDS);
+ memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs);
+ // initialize logging
+ logInit();
+ // get options and fill parameters from configuration file
+ get_options (); //Command-line options, enb_properties
+#if T_TRACER
+ T_Config_Init();
+#endif
+ //randominit (0);
+ set_taus_seed (0);
+ tpool_t pool;
+ Tpool = &pool;
+ char params[]="-1,-1";
+ initTpool(params, Tpool, false);
+ cpuf=get_cpu_freq_GHz();
+ itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info);
+
+ if (opt_type != OPT_NONE) {
+ if (init_opt(in_path, in_ip) == -1)
+ LOG_E(OPT,"failed to run OPT \n");
+ }
+
+#ifdef PDCP_USE_NETLINK
+ netlink_init();
+#if defined(PDCP_USE_NETLINK_QUEUES)
+ pdcp_netlink_init();
+#endif
+#endif
+#ifndef PACKAGE_VERSION
+# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL"
+#endif
+ LOG_I(HW, "Version: %s\n", PACKAGE_VERSION);
+
+ // init the parameters
+ for (int CC_id=0; CC_idnb_antennas_tx = nb_antenna_tx;
+ frame_parms[CC_id]->nb_antennas_rx = nb_antenna_rx;
+ frame_parms[CC_id]->nb_antenna_ports_eNB = 1; //initial value overwritten by initial sync later
+ LOG_I(PHY,"Set nb_rx_antenna %d , nb_tx_antenna %d \n",frame_parms[CC_id]->nb_antennas_rx, frame_parms[CC_id]->nb_antennas_tx);
+ get_band(downlink_frequency[CC_id][0], &frame_parms[CC_id]->eutra_band, &uplink_frequency_offset[CC_id][0], &frame_parms[CC_id]->frame_type);
+ }
+
+ NB_UE_INST=1;
+ NB_INST=1;
+ PHY_vars_UE_g = malloc(sizeof(PHY_VARS_NR_UE **));
+ PHY_vars_UE_g[0] = malloc(sizeof(PHY_VARS_NR_UE *)*MAX_NUM_CCs);
+
+ for (int CC_id=0; CC_id