Commit f35945e9 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/ocp-enb-cmake' into integration_2023_w08b

parents 5acdc72b 415e830c
......@@ -300,11 +300,7 @@ add_boolean_option(UE_DEBUG_TRACE False "Activate UE debug trace" ON)
add_boolean_option(UE_TIMING_TRACE False "Activate UE timing trace" ON)
set (OCP_ITTI ${OPENAIR_DIR}/common/utils/ocp_itti)
add_library(ITTI
${OCP_ITTI}/intertask_interface.cpp
${OPENAIR_DIR}/common/utils/backtrace.c
)
add_library(ITTI ${OCP_ITTI}/intertask_interface.cpp)
target_link_libraries(ITTI PRIVATE asn1_nr_rrc asn1_lte_rrc)
# asn1c skeletons have hardcoded this flag to make customized debug logs
......@@ -487,6 +483,7 @@ add_library(CONFIG_LIB
${CONFIG_ROOTDIR}/config_userapi.c
${CONFIG_ROOTDIR}/config_cmdline.c
)
target_link_libraries(CONFIG_LIB PRIVATE dl UTIL)
add_library(params_libconfig MODULE ${CONFIG_ROOTDIR}/libconfig/config_libconfig.c)
target_link_libraries(params_libconfig config)
# shared library loader
......@@ -783,7 +780,6 @@ add_library(UTIL
${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c
${OPENAIR_DIR}/common/utils/utils.c
${OPENAIR_DIR}/common/utils/system.c
${OPENAIR_DIR}/common/utils/backtrace.c
${OPENAIR_DIR}/common/utils/time_meas.c
${OPENAIR_DIR}/common/utils/time_stat.c
)
......@@ -2129,7 +2125,6 @@ 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/utils/minimal_stub.c
${T_SOURCE}
......@@ -2188,49 +2183,15 @@ target_link_libraries(lte-softmodem PRIVATE
-Wl,--start-group
lte_rrc nr_rrc s1ap m2ap x2ap m3ap GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT MME_APP SCHED_LIB SCHED_RU_LIB
PHY_COMMON PHY PHY_RU L2 L2_LTE NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB MISC_NFAPI_LTE_LIB
${RAL_LIB} ${NAS_UE_LIB} ITTI SIMU
${NAS_UE_LIB} ITTI SIMU
-Wl,--end-group z dl)
target_link_libraries(lte-softmodem PRIVATE ${LIBXML2_LIBRARIES})
target_link_libraries(lte-softmodem PRIVATE pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} sctp ${CMAKE_DL_LIBS})
target_link_libraries(lte-softmodem PRIVATE ${LIB_LMS_LIBRARIES})
target_link_libraries(lte-softmodem PRIVATE pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} sctp)
target_link_libraries(lte-softmodem PRIVATE ${T_LIB})
target_link_libraries(lte-softmodem PRIVATE asn1_nr_rrc asn1_lte_rrc)
add_executable(ocp-enb
${OPENAIR_DIR}/executables/main-ocp.c
${OPENAIR_DIR}/executables/softmodem-common.c
${OPENAIR_DIR}/executables/main-fs6.c
${OPENAIR_DIR}/executables/transport_split.c
${OPENAIR2_DIR}/ENB_APP/NB_IoT_interface.c
${OPENAIR_DIR}/executables/create_tasks.c
${OPENAIR_DIR}/executables/create_tasks_mbms.c
${OPENAIR_DIR}/radio/COMMON/common_lib.c
${OPENAIR_DIR}/radio/COMMON/record_player.c
${OPENAIR2_DIR}/RRC/NAS/nas_config.c
${OPENAIR2_DIR}/RRC/NAS/rb_config.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/multicast_link.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/socket.c
${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c
${OPENAIR_DIR}/common/utils/lte/ue_power.c
${OPENAIR_DIR}/common/utils/lte/prach_utils.c
${PHY_INTERFACE_DIR}/queue_t.c
${OPENAIR1_DIR}/PHY/TOOLS/phy_scope_interface.c
${T_SOURCE}
${SHLIB_LOADER_SOURCES}
)
add_dependencies(ocp-enb oai_iqplayer coding params_libconfig rfsimulator)
target_link_libraries (ocp-enb
-Wl,--start-group
lte_rrc nr_rrc s1ap m2ap x2ap m3ap GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT MME_APP SCHED_LIB SCHED_RU_LIB
PHY_COMMON PHY PHY_RU L2 L2_LTE NFAPI_COMMON_LIB NFAPI_LIB MISC_NFAPI_LTE_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB SIMU
${RAL_LIB} ${NAS_UE_LIB} ITTI
-Wl,--end-group z dl)
target_link_libraries (ocp-enb ${LIBXML2_LIBRARIES} pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} sctp ${CMAKE_DL_LIBS} ${LIB_LMS_LIBRARIES} ${T_LIB})
add_executable(oairu
${OPENAIR_DIR}/executables/lte-ru.c
${OPENAIR_DIR}/executables/ru_control.c
......@@ -2249,7 +2210,7 @@ target_link_libraries(oairu PRIVATE
PHY_COMMON PHY_RU UTIL
-Wl,--end-group z dl)
target_link_libraries(oairu PRIVATE pthread m CONFIG_LIB rt ${CMAKE_DL_LIBS} ${T_LIB})
target_link_libraries(oairu PRIVATE pthread m CONFIG_LIB rt ${T_LIB})
target_link_libraries(oairu PRIVATE asn1_nr_rrc asn1_lte_rrc)
# force the generation of ASN.1 so that we don't need to wait during the build
......@@ -2288,12 +2249,11 @@ target_link_libraries(lte-uesoftmodem PRIVATE
lte_rrc nr_rrc s1ap x2ap m2ap m3ap
SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT MME_APP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON
PHY_UE PHY_RU L2_UE L2_LTE SIMU NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB MISC_NFAPI_LTE_LIB
${RAL_LIB} ${NAS_UE_LIB} ITTI ${ATLAS_LIBRARIES}
${NAS_UE_LIB} ITTI ${ATLAS_LIBRARIES}
-Wl,--end-group z dl)
target_link_libraries(lte-uesoftmodem PRIVATE ${LIBXML2_LIBRARIES})
target_link_libraries(lte-uesoftmodem PRIVATE pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} sctp ${CMAKE_DL_LIBS} ${ATLAS_LIBRARIES})
target_link_libraries(lte-uesoftmodem PRIVATE ${LIB_LMS_LIBRARIES})
target_link_libraries(lte-uesoftmodem PRIVATE pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} sctp ${ATLAS_LIBRARIES})
target_link_libraries(lte-uesoftmodem PRIVATE ${T_LIB})
target_link_libraries(lte-uesoftmodem PRIVATE asn1_nr_rrc asn1_lte_rrc)
......@@ -2330,14 +2290,13 @@ add_executable(nr-softmodem
target_link_libraries(nr-softmodem PRIVATE
-Wl,--start-group
UTIL HASHTABLE SCTP_CLIENT SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_NR_COMMON PHY_RU GTPV1U SECU_CN SECU_OSA
ITTI ${RAL_LIB} ${NAS_UE_LIB} lte_rrc nr_rrc
ITTI ${NAS_UE_LIB} lte_rrc nr_rrc
ngap s1ap L2_LTE_NR L2_NR MAC_NR_COMMON NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB SIMU
x2ap f1ap m2ap m3ap e1ap
-Wl,--end-group z dl)
target_link_libraries(nr-softmodem PRIVATE ${LIBXML2_LIBRARIES})
target_link_libraries(nr-softmodem PRIVATE pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} sctp ${CMAKE_DL_LIBS} ${ATLAS_LIBRARIES})
target_link_libraries(nr-softmodem PRIVATE ${LIB_LMS_LIBRARIES})
target_link_libraries(nr-softmodem PRIVATE pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} sctp ${ATLAS_LIBRARIES})
target_link_libraries(nr-softmodem PRIVATE ${T_LIB})
target_link_libraries(nr-softmodem PRIVATE asn1_nr_rrc asn1_lte_rrc)
......@@ -2398,12 +2357,11 @@ target_link_libraries(nr-uesoftmodem PRIVATE
nr_rrc SECU_CN SECU_OSA UTIL HASHTABLE SCHED_RU_LIB SCHED_NR_UE_LIB
PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB
NFAPI_USER_LIB MISC_NFAPI_NR_LIB
${RAL_LIB} ITTI ${ATLAS_LIBRARIES} LIB_5GNAS_GNB LIB_NAS_SIMUE ${NAS_SIM_LIB} SIMU
ITTI ${ATLAS_LIBRARIES} LIB_5GNAS_GNB LIB_NAS_SIMUE ${NAS_SIM_LIB} SIMU
-Wl,--end-group z dl)
target_link_libraries(nr-uesoftmodem PRIVATE ${LIBXML2_LIBRARIES})
target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS} ${ATLAS_LIBRARIES})
target_link_libraries(nr-uesoftmodem PRIVATE ${LIB_LMS_LIBRARIES})
target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${ATLAS_LIBRARIES})
target_link_libraries(nr-uesoftmodem PRIVATE ${T_LIB})
target_link_libraries(nr-uesoftmodem PRIVATE asn1_nr_rrc asn1_lte_rrc)
......@@ -2546,7 +2504,6 @@ target_link_libraries(nr_dlsim PRIVATE
m pthread ${ATLAS_LIBRARIES} ${T_LIB} ITTI ${OPENSSL_LIBRARIES} dl
)
target_link_libraries(nr_dlsim PRIVATE asn1_nr_rrc asn1_lte_rrc)
target_compile_definitions(nr_dlsim PUBLIC -DPHYSICAL_SIMULATOR)
add_executable(nr_prachsim
${OPENAIR1_DIR}/SIMULATION/NR_PHY/prachsim.c
......@@ -2598,7 +2555,6 @@ target_link_libraries(nr_ulsim PRIVATE
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_NR MAC_UE_NR MAC_NR_COMMON lte_rrc nr_rrc CONFIG_LIB L2_LTE_NR L2_NR HASHTABLE x2ap SECU_CN ngap NFAPI_COMMON_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -lz -Wl,--end-group
m pthread ${ATLAS_LIBRARIES} ${T_LIB} ITTI ${OPENSSL_LIBRARIES} dl
)
target_compile_definitions(nr_ulsim PUBLIC -DPHYSICAL_SIMULATOR)
target_link_libraries(nr_ulsim PRIVATE asn1_nr_rrc asn1_lte_rrc)
foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim)
......
......@@ -179,12 +179,10 @@ def GetParametersFromXML(action):
#local variable air_interface
air_interface = test.findtext('air_interface')
if (air_interface is None) or (air_interface.lower() not in ['nr','lte','ocp']):
if (air_interface is None) or (air_interface.lower() not in ['nr','lte']):
RAN.air_interface[RAN.eNB_instance] = 'lte-softmodem'
elif (air_interface.lower() in ['nr','lte']):
else:
RAN.air_interface[RAN.eNB_instance] = air_interface.lower() +'-softmodem'
else :
RAN.air_interface[RAN.eNB_instance] = 'ocp-enb'
cmd_prefix = test.findtext('cmd_prefix')
if cmd_prefix is not None: RAN.cmd_prefix = cmd_prefix
......@@ -211,12 +209,10 @@ def GetParametersFromXML(action):
#local variable air_interface
air_interface = test.findtext('air_interface')
if (air_interface is None) or (air_interface.lower() not in ['nr','lte','ocp']):
if (air_interface is None) or (air_interface.lower() not in ['nr','lte']):
RAN.air_interface[RAN.eNB_instance] = 'lte-softmodem'
elif (air_interface.lower() in ['nr','lte']):
else:
RAN.air_interface[RAN.eNB_instance] = air_interface.lower() +'-softmodem'
else :
RAN.air_interface[RAN.eNB_instance] = 'ocp-enb'
elif action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Terminate_UE' or action == 'CheckStatusUE' or action == 'DataEnable_UE' or action == 'DataDisable_UE':
CiTestObj.ue_ids = test.findtext('id').split(' ')
......@@ -239,12 +235,11 @@ def GetParametersFromXML(action):
#local variable air_interface
air_interface = test.findtext('air_interface')
if (air_interface is None) or (air_interface.lower() not in ['nr','lte','ocp']):
if (air_interface is None) or (air_interface.lower() not in ['nr','lte']):
CiTestObj.air_interface = 'lte-uesoftmodem'
elif (air_interface.lower() in ['nr','lte']):
CiTestObj.air_interface = air_interface.lower() +'-uesoftmodem'
else :
#CiTestObj.air_interface = 'ocp-enb'
logging.error('OCP UE -- NOT SUPPORTED')
CiTestObj.cmd_prefix = test.findtext('cmd_prefix') or ""
......@@ -258,13 +253,10 @@ def GetParametersFromXML(action):
#local variable air_interface
air_interface = test.findtext('air_interface')
if (air_interface is None) or (air_interface.lower() not in ['nr','lte','ocp']):
if (air_interface is None) or (air_interface.lower() not in ['nr','lte']):
CiTestObj.air_interface = 'lte-uesoftmodem'
elif (air_interface.lower() in ['nr','lte']):
else:
CiTestObj.air_interface = air_interface.lower() +'-uesoftmodem'
else :
#CiTestObj.air_interface = 'ocp-enb'
logging.error('OCP UE -- NOT SUPPORTED')
elif action == 'Ping':
CiTestObj.ping_args = test.findtext('ping_args')
......
......@@ -131,11 +131,7 @@ class RANManagement():
mySSH = SSH.SSHConnection()
mySSH.open(lIpAddr, lUserName, lPassWord)
# Check if we build an 5G-NR gNB or an LTE eNB or an OCP eNB
result = re.search('--eNBocp', self.Build_eNB_args)
if result is not None:
self.air_interface[self.eNB_instance] = 'ocp-enb'
else:
# Check if we build an 5G-NR gNB or an LTE eNB
result = re.search('--RU', self.Build_eNB_args)
if result is not None:
self.air_interface[self.eNB_instance] = 'oairu'
......@@ -286,7 +282,7 @@ class RANManagement():
mySSH.command('ls ran_build/build', '\$', 3)
mySSH.command('ls ran_build/build', '\$', 3)
#check if we have the build corresponding to the air interface keywords (nr-softmode, lte-softmodem, ocp-enb)
#check if we have the build corresponding to the air interface keywords (nr-softmode, lte-softmodem)
logging.info('CHECK Build with IP='+lIpAddr+' SourcePath='+lSourcePath)
result = re.search(self.air_interface[self.eNB_instance], mySSH.getBefore())
if result is None:
......@@ -367,7 +363,7 @@ class RANManagement():
#Get pcap on enb and/or gnb if enabled in the xml
if self.eNB_Trace=='yes':
if ((self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb')):
if self.air_interface[self.eNB_instance] == 'lte-softmodem':
pcapfile_prefix="enb_"
else:
pcapfile_prefix="gnb_"
......@@ -452,7 +448,7 @@ class RANManagement():
#hack UHD_RFNOC_DIR variable for gNB / N310 on RHEL8 server:
#if the USRP address is in the xml then we are using an eth USRP (N3xx)
if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'):
if self.air_interface[self.eNB_instance] == 'lte-softmodem':
gNB = False
else:
gNB = True
......@@ -468,7 +464,7 @@ class RANManagement():
monitor_file='../ci-scripts/stats_monitor.py'
conf_file='../ci-scripts/stats_monitor_conf.yaml'
if self.eNB_Stats=='yes':
if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'):
if self.air_interface[self.eNB_instance] == 'lte-softmodem':
mySSH.command('echo $USER; nohup python3 ' + monitor_file + ' ' + conf_file + ' ' + self.testCase_id + ' enb 2>&1 > enb_stats_monitor_execution.log &', '\$', 5)
else:
mySSH.command('echo $USER; nohup python3 ' + monitor_file + ' ' + conf_file + ' ' + self.testCase_id + ' gnb 2>&1 > gnb_stats_monitor_execution.log &', '\$', 5)
......@@ -491,7 +487,7 @@ class RANManagement():
mySSH.command('killall --signal SIGKILL record', '\$', 5)
mySSH.close()
doLoop = False
logging.error('\u001B[1;37;41m eNB/gNB/ocp-eNB logging system did not show got sync! \u001B[0m')
logging.error('\u001B[1;37;41m eNB/gNB logging system did not show got sync! \u001B[0m')
HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK)
# In case of T tracer recording, we need to kill tshark on EPC side
localEpcIpAddr = EPC.IPAddress
......@@ -548,7 +544,7 @@ class RANManagement():
HTML.CreateHtmlTestRow(f'{self.cmd_prefix} {self.air_interface[self.eNB_instance]} -O {config_file} {extra_options}', 'OK', CONST.ALL_PROCESSES_OK)
logging.debug('\u001B[1m Initialize eNB/gNB/ocp-eNB Completed\u001B[0m')
logging.debug('\u001B[1m Initialize eNB/gNB Completed\u001B[0m')
def CheckeNBProcess(self, status_queue):
try:
......@@ -609,19 +605,19 @@ class RANManagement():
mySSH = SSH.SSHConnection()
mySSH.open(lIpAddr, lUserName, lPassWord)
mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5)
if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'):
if self.air_interface[self.eNB_instance] == 'lte-softmodem':
nodeB_prefix = 'e'
else:
nodeB_prefix = 'g'
mySSH.command('stdbuf -o0 ps -aux | grep --color=never -e softmodem -e ocp-enb | grep -v grep', '\$', 5)
result = re.search('(-softmodem|ocp)', mySSH.getBefore())
mySSH.command('stdbuf -o0 ps -aux | grep --color=never -e softmodem | grep -v grep', '\$', 5)
result = re.search('-softmodem', mySSH.getBefore())
if result is not None:
mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT -r .*-softmodem ocp-enb || true', '\$', 5)
mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT -r .*-softmodem || true', '\$', 5)
time.sleep(10)
mySSH.command('stdbuf -o0 ps -aux | grep --color=never -e softmodem -e ocp-enb | grep -v grep', '\$', 5)
result = re.search('(-softmodem|ocp)', mySSH.getBefore())
mySSH.command('stdbuf -o0 ps -aux | grep --color=never -e softmodem | grep -v grep', '\$', 5)
result = re.search('-softmodem', mySSH.getBefore())
if result is not None:
mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL -r .*-softmodem ocp-enb || true', '\$', 5)
mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL -r .*-softmodem || true', '\$', 5)
time.sleep(5)
mySSH.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5)
#stopping tshark (valid if eNB and enabled in xml, will not harm otherwise)
......@@ -1083,7 +1079,7 @@ class RANManagement():
#post processing depending on the node type
if not nodeB_prefix_found:
if (self.air_interface[self.eNB_instance] == 'lte-softmodem') or (self.air_interface[self.eNB_instance] == 'ocp-enb'):
if self.air_interface[self.eNB_instance] == 'lte-softmodem':
nodeB_prefix = 'e'
else:
nodeB_prefix = 'g'
......
<!--
Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The OpenAirInterface Software Alliance licenses this file to You under
the OAI Public License, Version 1.1 (the "License"); you may not use this file
except in compliance with the License.
You may obtain a copy of the License at
http://www.openairinterface.org/?page_id=698
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
For more information about the OpenAirInterface (OAI) Software Alliance:
contact@openairinterface.org
-->
<testCaseList>
<htmlTabRef>build-tab</htmlTabRef>
<htmlTabName>Build</htmlTabName>
<htmlTabIcon>wrench</htmlTabIcon>
<TestCaseRequestedList>
010101
</TestCaseRequestedList>
<TestCaseExclusionList></TestCaseExclusionList>
<testCase id="010101">
<class>Build_eNB</class>
<desc>Build eNB OCP (USRP)</desc>
<Build_eNB_args>-w USRP -c --eNBocp --ninja</Build_eNB_args>
</testCase>
</testCaseList>
......@@ -93,8 +93,6 @@ Options:
enable cmake debugging messages
--eNB
Makes the LTE softmodem
--eNBocp
Makes the OCP LTE softmodem
--gNB
Makes the NR softmodem
--RU
......@@ -248,10 +246,6 @@ function main() {
eNB=1
echo_info "Will compile eNB"
shift;;
--eNBocp)
eNBocp=1
echo_info "Will compile OCP eNB"
shift;;
--gNB)
gNB=1
echo_info "Will compile gNB"
......@@ -451,7 +445,7 @@ function main() {
########################################################
# to be discussed
if [ "$eNB" = "1" -o "$eNBocp" = "1" -o "$gNB" = "1" ] ; then
if [ "$eNB" = "1" -o "$gNB" = "1" ] ; then
if [ "$HW" = "None" -a "$TP" = "None" ] ; then
echo_info "No local radio head and no transport protocol selected"
fi
......@@ -526,9 +520,6 @@ function main() {
if [ "$eNB" = "1" ] ; then
execlist="$execlist lte-softmodem"
fi
if [ "$eNBocp" = "1" ] ; then
execlist="$execlist ocp-enb"
fi
if [ "$gNB" = "1" ] ; then
execlist="$execlist nr-softmodem nr-cuup"
fi
......@@ -654,7 +645,7 @@ function main() {
####################################################
# Build RF device and transport protocol libraries #
####################################################
if [ "$eNB" = "1" -o "$eNBocp" = "1" -o "$UE" = "1" -o "$gNB" = "1" -o "$RU" = "1" -o "$nrUE" = "1" ] ; then
if [ "$eNB" = "1" -o "$UE" = "1" -o "$gNB" = "1" -o "$RU" = "1" -o "$nrUE" = "1" ] ; then
# build RF device libraries
if [ "$HW" != "None" ] ; then
......
......@@ -28,7 +28,6 @@
#include <sys/types.h>
#include <unistd.h>
#include <platform_types.h>
#include "backtrace.h"
#define _Assert_Exit_ \
if (getenv("gdbStacks")) { \
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <execinfo.h>
#include <common/utils/backtrace.h>
/* Obtain a backtrace and print it to stdout. */
void display_backtrace(void) {
void *array[10];
size_t size;
char **strings;
size_t i;
char *test=getenv("NO_BACKTRACE");
if (test!=0) abort();
size = backtrace(array, 10);
strings = backtrace_symbols(array, size);
printf("Obtained %u stack frames.\n", (unsigned int)size);
for (i = 0; i < size; i++)
printf("%s\n", strings[i]);
free(strings);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <signal.h>
#ifndef BACKTRACE_H_
#define BACKTRACE_H_
#ifdef __cplusplus
extern "C" {
#endif
void display_backtrace(void);
#ifdef __cplusplus
}
#endif
#endif /* BACKTRACE_H_ */
......@@ -504,7 +504,6 @@ int proccmd_exit(char *buf, int debug, telnet_printfunc_t prnt)
{
if (debug > 0)
prnt("process module received %s\n",buf);
end_configmodule();
exit_fun("telnet server received exit command\n");
return 0;
}
......
thread-pool-test: thread-pool.c thread-pool.h
gcc -g -O3 thread-pool.c -I ${OPENAIR_DIR}/nfapi/open-nFAPI/nfapi/public_inc -I ${OPENAIR_DIR}/ -I ${OPENAIR_DIR}/common/utils/ -I. ${OPENAIR_DIR}/common/utils/backtrace.c -I ${OPENAIR_DIR}/openair2/COMMON ${OPENAIR_DIR}/common/utils/system.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 -lpthread -ldl -D TEST_THREAD_POOL -DMAX_NUM_CCs=1 -I../LOG -I../../utils/T -o thread-pool-test
gcc -g -O3 thread-pool.c -I ${OPENAIR_DIR}/nfapi/open-nFAPI/nfapi/public_inc -I ${OPENAIR_DIR}/ -I ${OPENAIR_DIR}/common/utils/ -I. -I ${OPENAIR_DIR}/openair2/COMMON ${OPENAIR_DIR}/common/utils/system.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 -lpthread -ldl -D TEST_THREAD_POOL -DMAX_NUM_CCs=1 -I../LOG -I../../utils/T -o thread-pool-test
......@@ -890,7 +890,6 @@ INPUT = \
@CMAKE_CURRENT_SOURCE_DIR@/../common/config/config_userapi.c \
@CMAKE_CURRENT_SOURCE_DIR@/../common/oai_asn1.h \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/time_meas.h \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/backtrace.c \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/time_stat.h \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/load_module_shlib.h \
@CMAKE_CURRENT_SOURCE_DIR@/../common/utils/time_meas.c \
......@@ -2549,7 +2548,6 @@ INPUT = \
@CMAKE_CURRENT_SOURCE_DIR@/../executables/create_tasks.h \
@CMAKE_CURRENT_SOURCE_DIR@/../executables/softmodem-common.c \
@CMAKE_CURRENT_SOURCE_DIR@/../executables/rt_profiling.h \
@CMAKE_CURRENT_SOURCE_DIR@/../executables/split_headers.h \
@CMAKE_CURRENT_SOURCE_DIR@/../executables/create_tasks.c \
@CMAKE_CURRENT_SOURCE_DIR@/../executables/nr-uesoftmodem.c \
@CMAKE_CURRENT_SOURCE_DIR@/../executables/nr-uesoftmodem.h \
......
......@@ -109,196 +109,6 @@ route add default oaitun_ue1
or specify the outgoing route in the traffic generator (like option “-I”
in ping command).
## Split 6 DL 4G
The contract describes to reuse the uplink existing if4p5 and to develop
is this work the downlink “functional split 6”.
The customer required after signature to develop also the uplink
functional split 6. This is accepted, as long as the whole work is
research with no delivery completeness warranty.
### Simulation
To be able to verify the new features and to help in all future
developments, Open Cells added and improved the Rf board simulator
during this contract.
We added the channel modeling simulation, that offer to simulate various
3GPP defined channels.
### Main loop
The main log is in RF simulator is in
`targets/RT/USER/lte-ru.c and targets/RT/USER/lte-enb.c`
As this piece of SW is very complex and doesn’t meet our goals
(functional split 6), a cleaned version replaces these 2 files in
executables/ocp-main.c (openair1/SCHED/prach\_procedures.c is also
replaced by this new file as it only launching the RACH actual work in a
way not compatible with our FS6).
The main loop cadences the I/Q samples reception, signal processing and
I/Q samples sending.
The main loop uses extensively function pointers to call the right
processing function depending on the split case.
A lot of OAI reduntant global variables contains the same semantic data: time,frame, subframe.
The reworked main loop take care of a uniq variable that comes directly from harware: RF board sampling number.
To use OAI, we need to set all OAI variables that derivates from this timestamp value. The function setAllfromTS() implements this.
### Splitted main level
When FS6 is actived, a main loop for DU (du_fs6()) a main loop for CU case replaces the uniq eNB main loop.
Each of these main loops calls initialization of OAI LTE data and the FS6 transport layer initialization.
Then, it runs a infinite loop on: set time, call UL and DL. The time comes from the RF board, so the DU sends the time to the CU.
This is enough for RF board dialog, but the FS6 is higher in SW layers,
we need to cut higher functions inside downlink and uplink procedures.
As much as possible, the FS6 code is in the directory OPENAIR_DIR/executables. When a given OAI piece of code is small or need complex changes, it is reworked in the file fs6-main.c. The functions naming keeps the OAI function name, adding suffix _fromsplit() or _tosplit().
When this organization would lead to large code copy, it is better to insert modifications in OAI code. This is done in two files:
- openair1/SCHED/phy_procedures_lte_eNb.c: to send signaling channels computation results
- the function sendFs6Ulharq() centralizes all signaling channels forwarding to CU
- openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c: to deal with FS6 user plane split
- sendFs6Ul() is used once to forward user plane to CU
### DownLink
The main procedure is phy\_procedures\_eNB\_TX()
This is building the common channels (beacon, multi-UE signaling).
The FS6 split breaks this function into pieces:
* The multi-UE signals, built by common\_signal\_procedures(),
subframe2harq\_pid(), generate\_dci\_top(), subframe2harq\_pid()
* These functions run in the DU, nevertheless all context has to be sent
(it is also needed partially for UL spitting)
* Run in the DU also to meet the requirement of pushing
in DU the data encoded with large redundancy (&gt;3 redundancy)
* the per UE data: pdsch\_procedures() needs further splitting:
* dlsch\_encoding\_all() that makes the encoding: turbo code
and lte\_rate\_matching\_turbo() that will be in the DU (some
unlikely cases can reach redundancy up to x3, when MCS is very
low (negative SINR cases)).
* dlsch\_encoding() output needs to be transmitted between the
DU and the CU for functional split 6.
* dlsch\_scrambling() that will go in the DU
* dlsch\_modulation() that will go in the DU
The du user plane data is made of expanded bit in OAI at FS6 split level. 1 pair of functions compact back these bits into 8bits/byte before sending data and expand it again in the DU data reception (functions: fs6Dl(un)pack()).
### Uplink
The uplink require configuration that is part of the DL transmission.
It interprets the signalling to extract the RACH and the per UE data
channels.
Ocp-main.c:rxtx() calls directly the entry procedure
phy\_procedures\_eNB\_uespec\_RX() calls:
* rx\_ulsch() that demodulate and extract soft bits per UE.
* This function runs in the DU
* the output data will be processes in the DU, so it needs to be
transmitted to the DU
* ulsch\_decoding() that do lte\_rate\_matching\_turbo\_rx()
sub\_block\_deinterleaving\_turbo()
then turbo decode that is in the CU
* fill\_ulsch\_cqi\_indication() fill\_crc\_indication() , fill\_rx\_indication()
* DU performs the signal processing of each channel data, prepare and sent to the CU the computed result
* Random access channel detection runs in the DU
* the DU reports to the CU only the detected temprary identifier for RACH response
### signaling data in each direction (UL and DL)
* each LTE channel needs to be propagated between CU and DU
* the simplest are the almost static data such as PSS/SSS, that need only static eNB parameters and primary information (frame numbering)
* all the other channels require data transmission CU to DU and DU to CU
* the general design push all the low level processing for these channels in the DU
* the CU interface transports only signal processing results (UL) or configuration to create the RF signal (DL case)
* HARQ is detected in the DU, then only the ACK or NACK is reported to CU
* the CU have to control the power and MCS (modulation and coding scheme)
* the DU performs the signal processing and report only the decoded data like the CQI
* as the DU performas the modulation, scrambling and puncturing, each data packet is associated with the LTE parameters required for these features
* in DL, the CU associates the control parameters and the user plane data
* in UL, the CU sends upfront the scheduled UL data to the DU. So, the DU have the required knowledge to decode the next subframes in time.
### UDP transport layer
A general UDP transport layer is in executables/transport\_split.c
Linux offers a UDP socket builtin timeout, that we use.
In and out buffers are memory zones that contains compacted
(concatenated) UDP chunks.
For output, sendSubFrame() sends each UDP chunk
For input, receiveSubFrame() collects all UDP chunks for a group (a
subframe in OAI LTE case). It returns in the following cases:
- all chunks are received
- a timeout expired
- a chunk from the next subframe already arrived
### Functional split 6 usage
The ocp cleaned main hale to be used: run ocp-softmodem instead of
lte-softmodem.
The functionality and parameters is the same, enhanced with FS6 mode.
The end line option “--split73” enables the fs6 (also called split 7.3) mode and decided to be cu or du.
Example:
```bash
./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug --split73 cu:127.0.0.1
```
Run the CU init of the split 6 eNB, that will call du on 127.0.0.1 address
```bash
./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug --split73 du:127.0.0.1
```
will run the du, calling the cu on 127.0.0.1
If the CU and the DU are not on the same machine, the remote address of each side need to be specified as per this example
```bash
./ocp-softmodem -O $OPENAIR_DIR/enb.fs6.example.conf --rfsim --log_config.phy_log_level debug --split73 du:192.168.1.55
```
runs the functional split 6 DU
```bash
./lte-uesoftmodem -C 2685000000 -r 50 --rfsim --rfsimulator.serveraddr 192.168.1.1 -d
```
Runs the UE (to have the UE signal scope, compile it with make uescope)
CU+DU+UE can run with option `--noS1` to avoid to use a EPC and/or with `--rfsim` to simulate RF board
## 5G and F1
Today 5G achievement is limited to physical layer.
......
......@@ -36,7 +36,6 @@
#include "RRC/LTE/rrc_defs.h"
# include "enb_app.h"
# include "openair2/LAYER2/MAC/mac_proto.h"
#include <executables/split_headers.h>
#include <openair3/ocp-gtpu/gtp_itf.h>
extern RAN_CONTEXT_t RC;
......@@ -52,12 +51,13 @@ int create_tasks(uint32_t enb_nb) {
AssertFatal(rc >= 0, "Create task for eNB APP failed\n");
rrc_enb_init();
itti_mark_task_ready(TASK_RRC_ENB);
if (get_softmodem_params()->emulate_l1 || (EPC_MODE_ENABLED && split73 != SPLIT73_DU)) {
if (get_softmodem_params()->emulate_l1 || EPC_MODE_ENABLED) {
rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL);
AssertFatal(rc >= 0, "Create task for SCTP failed\n");
}
if (EPC_MODE_ENABLED && ! ( split73==SPLIT73_DU ) ) {
if (EPC_MODE_ENABLED) {
rc = itti_create_task(TASK_S1AP, s1ap_eNB_task, NULL);
AssertFatal(rc >= 0, "Create task for S1AP failed\n");
rc = itti_create_task(TASK_GTPV1_U, gtpv1uTask, NULL);
......
......@@ -84,7 +84,6 @@ unsigned short config_frames[4] = {2,9,11,13};
#include "lte-softmodem.h"
#include "NB_IoT_interface.h"
#include <executables/split_headers.h>
#if USING_GPROF
# include "sys/gmon.h"
......@@ -146,14 +145,6 @@ int otg_enabled;
uint64_t num_missed_slots=0; // counter for the number of missed slots
int split73=0;
void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) {
AssertFatal(false, "Must not be called in this context\n");
}
void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat) {
AssertFatal(false, "Must not be called in this context\n");
}
RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mask,pthread_mutex_t *ru_mutex,pthread_cond_t *ru_cond);
RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mask,pthread_mutex_t *ru_mutex,pthread_cond_t *ru_cond);
......
/*
* 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
*
* Author and copyright: Laurent Thomas, open-cells.com
*
* 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 <stdint.h>
#include <common/utils/LOG/log.h>
#include <common/utils/system.h>
#include <common/config/config_userapi.h>
#include "executables/lte-softmodem.h"
#include <openair1/PHY/defs_eNB.h>
#include <openair1/PHY/phy_extern.h>
#include <nfapi/oai_integration/vendor_ext.h>
#include <openair1/SCHED/fapi_l1.h>
#include <openair1/PHY/INIT/phy_init.h>
#include <openair2/LAYER2/MAC/mac_extern.h>
#include <openair1/PHY/LTE_REFSIG/lte_refsig.h>
#include <nfapi/oai_integration/nfapi_pnf.h>
#include <executables/split_headers.h>
#include <nfapi/oai_integration/vendor_ext.h>
#include <openair1/PHY/INIT/lte_init.c>
#include <openair1/PHY/LTE_ESTIMATION/lte_estimation.h>
#include <executables/split_headers.h>
#include <openair1/PHY/CODING/coding_extern.h>
#include <threadPool/thread-pool.h>
#include "PHY/sse_intrin.h"
#define FS6_BUF_SIZE 1000*1000
static UDPsock_t sockFS6;
int sum(uint8_t *b, int s) {
int sum=0;
for (int i=0; i < s; i++)
sum+=b[i];
return sum;
}
extern double cpuf;
typedef struct m {
uint64_t iterations;
uint64_t sum;
uint64_t maxArray[11];
} Meas;
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 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 T_TRACER
LOG_W(PHY,"%s",txt2);
#else
printf("%s",txt2);
#endif
}
}
void updateTimes(uint64_t start, Meas *M, int period, char *txt)
{
if (start!=0) {
uint64_t end=rdtsc_oai();
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 initStaticTime(a) static __thread uint64_t a={0}
#define pickStaticTime(a) do { a=rdtsc_oai(); } while (0)
#define initRefTimes(a) static __thread Meas a= {0}
static inline int cmpintRev(const void *a, const void *b) {
uint64_t *aa=(uint64_t *)a;
uint64_t *bb=(uint64_t *)b;
return (int)(*bb-*aa);
}
static inline void printMeas2(char *txt, Meas *M, int period, bool MaxMin) {
if (M->iterations%period == 0 ) {
char txt2[512];
sprintf(txt2,"%s avg=%" PRIu64 " iterations=%" PRIu64 " %s=%"
PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 "\n",
txt,
M->sum/M->iterations,
M->iterations,
MaxMin?"max":"min",
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 T_TRACER
LOG_W(PHY,"%s",txt2);
#else
printf("%s",txt2);
#endif
}
}
static inline void updateTimesReset(uint64_t start, Meas *M, int period, bool MaxMin, char *txt) {
if (start!=0) {
uint64_t end=rdtsc_oai();
long long diff=(end-start)/(cpuf*1000);
M->maxArray[0]=diff;
M->sum+=diff;
M->iterations++;
if ( MaxMin)
qsort(M->maxArray, 11, sizeof(uint64_t), cmpint);
else
qsort(M->maxArray, 11, sizeof(uint64_t), cmpintRev);
printMeas2(txt,M,period, MaxMin);
if (M->iterations%period == 0 ) {
bzero(M,sizeof(*M));
if (!MaxMin)
for (int i=0; i<11; i++)
M->maxArray[i]=INT_MAX;
}
}
}
static inline void measTransportTime(uint64_t DuSend, uint64_t CuMicroSec, Meas *M, int period, bool MaxMin, char *txt) {
if (DuSend!=0) {
uint64_t end=rdtsc_oai();
long long diff=(end-DuSend)/(cpuf*1000)-CuMicroSec;
M->maxArray[0]=diff;
M->sum+=diff;
M->iterations++;
if ( MaxMin)
qsort(M->maxArray, 11, sizeof(uint64_t), cmpint);
else
qsort(M->maxArray, 11, sizeof(uint64_t), cmpintRev);
printMeas2(txt,M,period, MaxMin);
if (M->iterations%period == 0 ) {
bzero(M,sizeof(*M));
if (!MaxMin)
for (int i=0; i<11; i++)
M->maxArray[i]=INT_MAX;
}
}
}
#define ceil16_bytes(a) ((((a+15)/16)*16)/8)
static void fs6Dlunpack(void *out, void *in, int szUnpacked) {
static uint64_t *lut=NULL;
if (!lut) {
lut=(uint64_t *) malloc(sizeof(*lut)*256);
for (int i=0; i <256; i++)
for (int j=0; j<8; j++)
((uint8_t *)(lut+i))[7-j]=(i>>j)&1;
}
int64_t *out_64 = (int64_t *)out;
int sz=ceil16_bytes(szUnpacked);
for (int i=0; i<sz; i++)
out_64[i]=lut[((uint8_t *)in)[i]];
return;
}
static void fs6Dlpack(void *out, void *in, int szUnpacked) {
__m128i zeros=_mm_set1_epi8(0);
__m128i shuffle=_mm_set_epi8(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7);
const int loop=ceil16_bytes(szUnpacked)/sizeof(uint16_t);
__m128i *iter=(__m128i *)in;
for (int i=0; i < loop; i++) {
__m128i tmp=_mm_shuffle_epi8(_mm_cmpgt_epi8(*iter++,zeros),shuffle);
((uint16_t *)out)[i]=(uint16_t)_mm_movemask_epi8(tmp);
}
}
void prach_eNB_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc) {
fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone);
if (is_prach_subframe(&eNB->frame_parms, proc->frame_prach,proc->subframe_prach)<=0)
return;
RU_t *ru;
int aa=0;
int ru_aa;
for (int i=0; i<eNB->num_RU; i++) {
ru=eNB->RU_list[i];
for (ru_aa=0,aa=0; ru_aa<ru->nb_rx; ru_aa++,aa++) {
eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[i]->prach_rxsigF[0][ru_aa];
int ce_level;
for (ce_level=0; ce_level<4; ce_level++)
eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[i]->prach_rxsigF_br[ce_level][ru_aa];
}
}
ocp_rx_prach(eNB,
proc,
eNB->RU_list[0],
header->max_preamble,
header->max_preamble_energy,
header->max_preamble_delay,
header->avg_preamble_energy,
proc->frame_prach,
0,
false
);
// run PRACH detection for CE-level 0 only for now when br_flag is set
/* fixme: seems not operational and may overwrite regular LTE prach detection
* OAI code can call is sequence
rx_prach(eNB,
eNB->RU_list[0],
header->max_preamble,
header->max_preamble_energy,
header->max_preamble_delay,
header->avg_preamble_energy,
frame,
0,
true
);
*/
LOG_D(PHY,"RACH detection index 0: max preamble: %u, energy: %u, delay: %u, avg energy: %u\n",
header->max_preamble[0],
header->max_preamble_energy[0],
header->max_preamble_delay[0],
header->avg_preamble_energy[0]
);
return;
}
void prach_eNB_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc) {
fs6_ul_t *header=(fs6_ul_t *) commonUDPdata(bufferZone);
uint16_t *max_preamble=header->max_preamble;
uint16_t *max_preamble_energy=header->max_preamble_energy;
uint16_t *max_preamble_delay=header->max_preamble_delay;
uint16_t *avg_preamble_energy=header->avg_preamble_energy;
int subframe=proc->subframe_prach;
int frame=proc->frame_prach;
// Fixme: not clear why we call twice with "br" and without
int br_flag=0;
if (br_flag==1) {
int prach_mask;
prach_mask = is_prach_subframe (&eNB->frame_parms, proc->frame_prach_br, proc->subframe_prach_br);
eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br;
int ind = 0;
int ce_level = 0;
/* Save for later, it doesn't work
for (int ind=0,ce_level=0;ce_level<4;ce_level++) {
if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[ce_level]==1)&&
(prach_mask&(1<<(1+ce_level)) > 0) && // prach is active and CE level has finished its repetitions
(eNB->prach_vars_br.repetition_number[ce_level]==
eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) {
*/
if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) {
if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) {
eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++;
eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind]; //
eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind];
// note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4
eNB->preamble_list_br[ind].preamble_rel8.rnti = 1 + subframe + (60*(eNB->prach_vars_br.first_frame[ce_level] % 40));
eNB->preamble_list_br[ind].instance_length = 0; //don't know exactly what this is
eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type = 1 + ce_level; // CE Level
LOG_I (PHY, "Filling NFAPI indication for RACH %d CELevel %d (mask %x) : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n",
ind,
ce_level,
prach_mask,
eNB->preamble_list_br[ind].preamble_rel8.timing_advance,
eNB->preamble_list_br[ind].preamble_rel8.preamble, eNB->preamble_list_br[ind].preamble_rel8.rnti, eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type);
}
}
/*
ind++;
}
} */// ce_level
} else if ((eNB->prach_energy_counter == 100) &&
(max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) {
LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n",
eNB->Mod_id,
eNB->CC_id,
frame,
subframe,
max_preamble[0],
max_preamble_energy[0]/10,
max_preamble_energy[0]%10,
max_preamble_delay[0]);
pthread_mutex_lock(&eNB->UL_INFO_mutex);
eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 1;
eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = &eNB->preamble_list[0];
eNB->UL_INFO.rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG;
eNB->UL_INFO.rach_ind.header.message_id = NFAPI_RACH_INDICATION;
eNB->UL_INFO.rach_ind.sfn_sf = frame<<4 | subframe;
eNB->preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG;
eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0];
eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0];
eNB->preamble_list[0].preamble_rel8.rnti = 1+subframe; // note: fid is implicitly 0 here
eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0;
eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is
if (NFAPI_MODE==NFAPI_MODE_PNF) { // If NFAPI PNF then we need to send the message to the VNF
LOG_D(PHY,"Filling NFAPI indication for RACH : SFN_SF:%d TA %d, Preamble %d, rnti %x, rach_resource_type %d\n",
NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf),
eNB->preamble_list[0].preamble_rel8.timing_advance,
eNB->preamble_list[0].preamble_rel8.preamble,
eNB->preamble_list[0].preamble_rel8.rnti,
eNB->preamble_list[0].preamble_rel13.rach_resource_type);
oai_nfapi_rach_ind(&eNB->UL_INFO.rach_ind);
eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 0;
}
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
} // max_preamble_energy > prach_I0 + 100
else {
eNB->measurements.prach_I0 = ((eNB->measurements.prach_I0*900)>>10) + ((avg_preamble_energy[0]*124)>>10);
if (eNB->prach_energy_counter < 100)
eNB->prach_energy_counter++;
}
}
void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask,
uint16_t rnti,
int32_t stat) {
static int current_fsf=-1;
int fsf=frame*16+subframe;
uint8_t *bufferZone=eNB->FS6bufferZone;
commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone;
// move to the end
uint8_t *firstFreeByte=bufferZone;
int curBlock=0;
if ( current_fsf != fsf ) {
for (int i=0; i < FirstUDPheader->nbBlocks; i++) {
AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,"");
firstFreeByte+=alignedSize(firstFreeByte);
curBlock++;
}
commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte;
FirstUDPheader->nbBlocks++;
newUDPheader->blockID=curBlock;
newUDPheader->contentBytes=sizeof(fs6_ul_t)+sizeof(fs6_ul_uespec_uci_t);
hULUEuci(newUDPheader)->type=fs6ULcch;
hULUEuci(newUDPheader)->nb_active_ue=0;
} else
for (int i=0; i < FirstUDPheader->nbBlocks-1; i++) {
AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,"");
firstFreeByte+=alignedSize(firstFreeByte);
curBlock++;
}
LOG_D(PHY,"FS6 du, block: %d: adding ul harq/sr: %d, rnti: %d, ueid: %d\n",
curBlock, type, rnti, UEid);
commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte;
fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(newUDPheader)+1);
tmp+=hULUEuci(newUDPheader)->nb_active_ue;
tmp->type=type;
tmp->UEid=UEid;
tmp->frame=frame;
tmp->subframe=subframe;
if (uci != NULL)
memcpy(&tmp->uci, uci, sizeof(*uci));
else
tmp->uci.ue_id=0xFFFF;
if (harq_ack != NULL)
memcpy(tmp->harq_ack, harq_ack, 4);
tmp->tdd_mapping_mode=tdd_mapping_mode;
tmp->tdd_multiplexing_mask=tdd_multiplexing_mask;
tmp->n0_subband_power_dB=eNB->measurements.n0_subband_power_dB[0][0];
tmp->rnti=rnti;
tmp->stat=stat;
hULUEuci(newUDPheader)->nb_active_ue++;
newUDPheader->contentBytes+=sizeof(fs6_ul_uespec_uci_element_t);
}
void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) {
uint8_t *bufferZone=eNB->FS6bufferZone;
commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone;
// move to the end
uint8_t *firstFreeByte=bufferZone;
int curBlock=0;
for (int i=0; i < FirstUDPheader->nbBlocks; i++) {
AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,"");
firstFreeByte+=alignedSize(firstFreeByte);
curBlock++;
}
commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte;
FirstUDPheader->nbBlocks++;
newUDPheader->blockID=curBlock;
newUDPheader->contentBytes=sizeof(fs6_ul_t)+sizeof(fs6_ul_uespec_t) + dataLen;
hULUE(newUDPheader)->type=fs6ULsch;
hULUE(newUDPheader)->UE_id=UE_id;
hULUE(newUDPheader)->harq_id=harq_pid;
memcpy(hULUE(newUDPheader)->ulsch_power,
eNB->pusch_vars[UE_id]->ulsch_power,
sizeof(int)*2);
hULUE(newUDPheader)->cqi_crc_status=eNB->ulsch[UE_id]->harq_processes[harq_pid]->cqi_crc_status;
hULUE(newUDPheader)->O_ACK=eNB->ulsch[UE_id]->harq_processes[harq_pid]->O_ACK;
memcpy(hULUE(newUDPheader)->o_ACK, eNB->ulsch[UE_id]->harq_processes[harq_pid]->o_ACK,
sizeof(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o_ACK));
hULUE(newUDPheader)->ta=lte_est_timing_advance_pusch(&eNB->frame_parms, eNB->pusch_vars[UE_id]->drs_ch_estimates_time);
hULUE(newUDPheader)->segment=segmentID;
memcpy(hULUE(newUDPheader)->o, eNB->ulsch[UE_id]->harq_processes[harq_pid]->o,
sizeof(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o));
memcpy(hULUE(newUDPheader)+1, data, dataLen);
hULUE(newUDPheader)->segLen=dataLen;
hULUE(newUDPheader)->r_offset=r_offset;
hULUE(newUDPheader)->G=eNB->ulsch[UE_id]->harq_processes[harq_pid]->G;
}
void pusch_procedures_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
uint32_t harq_pid;
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
const int subframe = proc->subframe_rx;
const int frame = proc->frame_rx;
for (int i = 0; i < NUMBER_OF_UE_MAX; i++) {
LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i];
if (ulsch->ue_type > NOCE)
harq_pid = 0;
else
harq_pid= subframe2harq_pid(&eNB->frame_parms,frame,subframe);
LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid];
if (ulsch->rnti>0)
LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d active: %d handled:%d]\n",
i, harq_pid, frame,subframe,i,ulsch->rnti,
ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->status, ulsch_harq->handled);
if ((ulsch) &&
(ulsch->rnti>0) &&
(ulsch_harq->status == ACTIVE) &&
((ulsch_harq->frame == frame) || (ulsch_harq->repetition_number >1) ) &&
((ulsch_harq->subframe == subframe) || (ulsch_harq->repetition_number >1) ) &&
(ulsch_harq->handled == 0)) {
// UE has ULSCH scheduling
for (int rb=0;
rb<=ulsch_harq->nb_rb;
rb++) {
int rb2 = rb+ulsch_harq->first_rb;
eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31));
}
LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d \n",
eNB->Mod_id, frame, subframe, i);
uint8_t nPRS= fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1];
ulsch->cyclicShift = (ulsch_harq->n_DMRS2 +
fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift +
nPRS)%12;
AssertFatal(ulsch_harq->TBS>0,"illegal TBS %d\n",ulsch_harq->TBS);
LOG_D(PHY,
"[eNB %d][PUSCH %d] Frame %d Subframe %d Demodulating PUSCH: dci_alloc %d, rar_alloc %d, round %d, first_rb %d, nb_rb %d, Qm %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, ), O_ACK %d, beta_cqi %d \n",
eNB->Mod_id,harq_pid,frame,subframe,
ulsch_harq->dci_alloc,
ulsch_harq->rar_alloc,
ulsch_harq->round,
ulsch_harq->first_rb,
ulsch_harq->nb_rb,
ulsch_harq->Qm,
ulsch_harq->TBS,
ulsch_harq->rvidx,
ulsch->cyclicShift,
ulsch_harq->n_DMRS2,
fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift,
ulsch_harq->O_ACK,
ulsch->beta_offset_cqi_times8);
start_meas(&eNB->ulsch_demodulation_stats);
eNB->FS6bufferZone=bufferZone;
rx_ulsch(eNB, proc, i);
stop_meas(&eNB->ulsch_demodulation_stats);
// TBD: add datablock for transmission
start_meas(&eNB->ulsch_decoding_stats);
ulsch_decoding(eNB,proc,
i,
0, // control_only_flag
ulsch_harq->V_UL_DAI,
ulsch_harq->nb_rb>20 ? 1 : 0);
stop_meas(&eNB->ulsch_decoding_stats);
}
}
}
void phy_procedures_eNB_uespec_RX_tosplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
//RX processing for ue-specific resources
LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
const int subframe = proc->subframe_rx;
const int frame = proc->frame_rx;
/* TODO: use correct rxdata */
if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) return;
LOG_D (PHY, "[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n", eNB->Mod_id, frame, subframe);
eNB->rb_mask_ul[0] = 0;
eNB->rb_mask_ul[1] = 0;
eNB->rb_mask_ul[2] = 0;
eNB->rb_mask_ul[3] = 0;
// Fix me here, these should be locked
eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus = 0;
eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs = 0;
// Call SRS first since all others depend on presence of SRS or lack thereof
srs_procedures (eNB, proc);
eNB->first_run_I0_measurements = 0;
uci_procedures (eNB, proc);
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) { // If PNF or monolithic
pusch_procedures_tosplit(bufferZone, bufSize, eNB,proc);
}
lte_eNB_I0_measurements (eNB, subframe, 0, eNB->first_run_I0_measurements);
int min_I0=1000,max_I0=0;
if ((frame==0) && (subframe==4)) {
for (int i=0; i<eNB->frame_parms.N_RB_UL; i++) {
if (i==(eNB->frame_parms.N_RB_UL>>1) - 1) i+=2;
if (eNB->measurements.n0_subband_power_tot_dB[i]<min_I0)
min_I0 = eNB->measurements.n0_subband_power_tot_dB[i];
if (eNB->measurements.n0_subband_power_tot_dB[i]>max_I0)
max_I0 = eNB->measurements.n0_subband_power_tot_dB[i];
}
LOG_I (PHY, "max_I0 %d, min_I0 %d\n", max_I0, min_I0);
}
return;
}
void fill_rx_indication_from_split(uint8_t *bufferZone, PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe, ul_propagation_t *ul_propa) {
nfapi_rx_indication_pdu_t *pdu;
int timing_advance_update;
uint32_t harq_pid;
if (eNB->ulsch[UE_id]->ue_type > 0)
harq_pid = 0;
else
harq_pid = subframe2harq_pid (&eNB->frame_parms,
frame, subframe);
pthread_mutex_lock(&eNB->UL_INFO_mutex);
eNB->UL_INFO.rx_ind.sfn_sf = frame<<4| subframe;
eNB->UL_INFO.rx_ind.rx_indication_body.tl.tag = NFAPI_RX_INDICATION_BODY_TAG;
pdu = &eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list[eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus];
// pdu->rx_ue_information.handle = eNB->ulsch[UE_id]->handle;
pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG;
pdu->rx_ue_information.rnti = eNB->ulsch[UE_id]->rnti;
pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG;
pdu->rx_indication_rel8.length = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3;
pdu->rx_indication_rel8.offset = 1; // DJP - I dont understand - but broken unless 1 ???? 0; // filled in at the end of the UL_INFO formation
AssertFatal(pdu->rx_indication_rel8.length <= NFAPI_RX_IND_DATA_MAX, "Invalid PDU len %d\n",
pdu->rx_indication_rel8.length);
memcpy(pdu->rx_ind_data,
eNB->ulsch[UE_id]->harq_processes[harq_pid]->decodedBytes,
pdu->rx_indication_rel8.length);
// estimate timing advance for MAC
timing_advance_update = ul_propa[UE_id].ta;
// if (timing_advance_update > 10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);}
// if (timing_advance_update < -10) { dump_ulsch(eNB,frame,subframe,UE_id); exit(-1);}
switch (eNB->frame_parms.N_RB_DL) {
case 6: /* nothing to do */
break;
case 15:
timing_advance_update /= 2;
break;
case 25:
timing_advance_update /= 4;
break;
case 50:
timing_advance_update /= 8;
break;
case 75:
timing_advance_update /= 12;
break;
case 100:
timing_advance_update /= 16;
break;
default:
abort ();
}
// put timing advance command in 0..63 range
timing_advance_update += 31;
if (timing_advance_update < 0)
timing_advance_update = 0;
if (timing_advance_update > 63)
timing_advance_update = 63;
pdu->rx_indication_rel8.timing_advance = timing_advance_update;
// estimate UL_CQI for MAC (from antenna port 0 only)
int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0]) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
if (SNRtimes10 < -640)
pdu->rx_indication_rel8.ul_cqi = 0;
else if (SNRtimes10 > 635)
pdu->rx_indication_rel8.ul_cqi = 255;
else
pdu->rx_indication_rel8.ul_cqi = (640 + SNRtimes10) / 5;
LOG_D(PHY,"[PUSCH %d] Frame %d Subframe %d Filling RX_indication with SNR %d (%d), timing_advance %d (update %d)\n",
harq_pid,frame,subframe,SNRtimes10,pdu->rx_indication_rel8.ul_cqi,pdu->rx_indication_rel8.timing_advance,
timing_advance_update);
eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus++;
eNB->UL_INFO.rx_ind.sfn_sf = frame<<4 | subframe;
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
}
void pusch_procedures_fromsplit(uint8_t *bufferZone, int bufSize, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, ul_propagation_t *ul_propa) {
//LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
const int subframe = proc->subframe_rx;
const int frame = proc->frame_rx;
uint32_t harq_pid;
uint32_t harq_pid0 = subframe2harq_pid(&eNB->frame_parms,frame,subframe);
for (int i = 0; i < NUMBER_OF_UE_MAX; i++) {
LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i];
if (ulsch->ue_type > NOCE) harq_pid = 0;
else harq_pid=harq_pid0;
LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid];
if (ulsch->rnti>0)
LOG_D(PHY,"eNB->ulsch[%d]->harq_processes[harq_pid:%d] SFN/SF:%04d%d: PUSCH procedures, UE %d/%x ulsch_harq[status:%d SFN/SF:%04d%d handled:%d]\n",
i, harq_pid, frame,subframe,i,ulsch->rnti,
ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled);
if ((ulsch) &&
(ulsch->rnti>0) &&
(ulsch_harq->status == ACTIVE) &&
(ulsch_harq->frame == frame) &&
(ulsch_harq->subframe == subframe) &&
(ulsch_harq->handled == 0)) {
// UE has ULSCH scheduling
for (int rb=0;
rb<=ulsch_harq->nb_rb;
rb++) {
int rb2 = rb+ulsch_harq->first_rb;
eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31));
}
start_meas(&eNB->ulsch_decoding_stats);
// This is a new packet, so compute quantities regarding segmentation
ulsch_harq->B = ulsch_harq->TBS+24;
lte_segmentation(NULL,
NULL,
ulsch_harq->B,
&ulsch_harq->C,
&ulsch_harq->Cplus,
&ulsch_harq->Cminus,
&ulsch_harq->Kplus,
&ulsch_harq->Kminus,
&ulsch_harq->F);
ulsch_decoding_data(eNB, proc, i, harq_pid,
ulsch_harq->nb_rb>20 ? 1 : 0);
stop_meas(&eNB->ulsch_decoding_stats);
} // if ((ulsch) &&
// (ulsch->rnti>0) &&
// (ulsch_harq->status == ACTIVE))
else if ((ulsch) &&
(ulsch->rnti>0) &&
(ulsch_harq->status == ACTIVE) &&
(ulsch_harq->frame == frame) &&
(ulsch_harq->subframe == subframe) &&
(ulsch_harq->handled == 1)) {
// this harq process is stale, kill it, this 1024 frames later (10s), consider reducing that
ulsch_harq->status = SCH_IDLE;
ulsch_harq->handled = 0;
ulsch->harq_mask &= ~(1 << harq_pid);
LOG_W (PHY, "Removing stale ULSCH config for UE %x harq_pid %d (harq_mask is now 0x%2.2x)\n", ulsch->rnti, harq_pid, ulsch->harq_mask);
}
} // for (i=0; i<NUMBER_OF_UE_MAX; i++)
while (proc->nbDecode > 0) {
notifiedFIFO_elt_t *req=pullTpool(proc->respDecode, proc->threadPool);
if (req == NULL)
break; // Tpool has been stopped
postDecode(proc, req);
delNotifiedFIFO_elt(req);
}
}
void recvFs6Ul(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, ul_propagation_t *ul_propa) {
void *bufPtr=bufferZone;
for (int i=0; i < nbBlocks; i++) { //nbBlocks is the actual received blocks
if ( ((commonUDP_t *)bufPtr)->contentBytes > sizeof(fs6_ul_t) ) {
int type=hULUE(bufPtr)->type;
if ( type == fs6ULsch) {
LTE_eNB_ULSCH_t *ulsch =eNB->ulsch[hULUE(bufPtr)->UE_id];
LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[hULUE(bufPtr)->harq_id];
memcpy(ulsch_harq->eUL+hULUE(bufPtr)->r_offset,
hULUE(bufPtr)+1,
hULUE(bufPtr)->segLen);
memcpy(eNB->pusch_vars[hULUE(bufPtr)->UE_id]->ulsch_power,
hULUE(bufPtr)->ulsch_power,
sizeof(int)*2);
ulsch_harq->G=hULUE(bufPtr)->G;
ulsch_harq->cqi_crc_status=hULUE(bufPtr)->cqi_crc_status;
//ulsch_harq->O_ACK= hULUE(bufPtr)->O_ACK;
memcpy(ulsch_harq->o_ACK, hULUE(bufPtr)->o_ACK,
sizeof(ulsch_harq->o_ACK));
memcpy(ulsch_harq->o,hULUE(bufPtr)->o, sizeof(ulsch_harq->o));
ul_propa[hULUE(bufPtr)->UE_id].ta=hULUE(bufPtr)->ta;
LOG_D(PHY,"Received ulsch data for: rnti:%x, cqi_crc_status %d O_ACK: %d, segment: %d, seglen: %d \n",
ulsch->rnti, ulsch_harq->cqi_crc_status, ulsch_harq->O_ACK,hULUE(bufPtr)->segment, hULUE(bufPtr)->segLen);
} else if ( type == fs6ULcch ) {
int nb_uci=hULUEuci(bufPtr)->nb_active_ue;
fs6_ul_uespec_uci_element_t *tmp=(fs6_ul_uespec_uci_element_t *)(hULUEuci(bufPtr)+1);
for (int j=0; j < nb_uci ; j++) {
LOG_D(PHY,"FS6 cu, block: %d/%d: received ul harq/sr: %d, rnti: %d, ueid: %d\n",
i, j, type, tmp->rnti, tmp->UEid);
eNB->measurements.n0_subband_power_dB[0][0]=tmp->n0_subband_power_dB;
if (tmp->uci.ue_id != 0xFFFF)
memcpy(&eNB->uci_vars[tmp->UEid],&tmp->uci, sizeof(tmp->uci));
if ( tmp->type == fs6ULindicationHarq )
fill_uci_harq_indication (tmp->UEid, eNB, &eNB->uci_vars[tmp->UEid],
tmp->frame, tmp->subframe, tmp->harq_ack,
tmp->tdd_mapping_mode, tmp->tdd_multiplexing_mask);
else if ( tmp->type == fs6ULindicationSr )
fill_sr_indication(tmp->UEid, eNB,tmp->rnti,tmp->frame,tmp->subframe,tmp->stat);
else
LOG_E(PHY, "Split FS6: impossible UL harq type\n");
tmp++;
}
} else
LOG_E(PHY, "FS6 ul packet type impossible\n" );
}
bufPtr+=alignedSize(bufPtr);
}
}
void phy_procedures_eNB_uespec_RX_fromsplit(uint8_t *bufferZone, int nbBlocks,PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc) {
// The configuration arrived in Dl, so we can extract the UL data
ul_propagation_t ul_propa[NUMBER_OF_UE_MAX];
recvFs6Ul(bufferZone, nbBlocks, eNB, ul_propa);
// dirty memory allocation in OAI...
for (int i = 0; i < NUMBER_OF_UCI_MAX; i++)
if ( eNB->uci_vars[i].frame == proc->frame_rx &&
eNB->uci_vars[i].subframe == proc->subframe_rx )
eNB->uci_vars[i].active=0;
pusch_procedures_fromsplit(bufferZone, nbBlocks, eNB, proc, ul_propa);
}
void rcvFs6DL(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, int frame, int subframe) {
void *bufPtr=bufferZone;
for (int i=0; i < nbBlocks; i++) { //nbBlocks is the actual received blocks
if ( ((commonUDP_t *)bufPtr)->contentBytes > sizeof(fs6_dl_t) ) {
int type=hDLUE(bufPtr)->type;
if ( type == fs6DlConfig) {
int curUE=hDLUE(bufPtr)->UE_id;
LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[curUE][0];
LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch0->harq_processes[hDLUE(bufPtr)->harq_pid];
#ifdef PHY_TX_THREAD
dlsch0->active[subframe] = 1;
#else
dlsch0->active = 1;
#endif
dlsch0->harq_ids[frame%2][subframe]=hDLUE(bufPtr)->harq_pid;
dlsch0->rnti=hDLUE(bufPtr)->rnti;
dlsch0->sqrt_rho_a=hDLUE(bufPtr)->sqrt_rho_a;
dlsch0->sqrt_rho_b=hDLUE(bufPtr)->sqrt_rho_b;
dlsch_harq->nb_rb=hDLUE(bufPtr)->nb_rb;
memcpy(dlsch_harq->rb_alloc, hDLUE(bufPtr)->rb_alloc, sizeof(hDLUE(bufPtr)->rb_alloc));
dlsch_harq->Qm=hDLUE(bufPtr)->Qm;
dlsch_harq->Nl=hDLUE(bufPtr)->Nl;
dlsch_harq->pdsch_start=hDLUE(bufPtr)->pdsch_start;
#ifdef PHY_TX_THREAD
dlsch_harq->CEmode = hDLUE(bufPtr)->CEmode;
dlsch_harq->i0=hDLUE(bufPtr)->i0;
dlsch_harq->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag;
#else
dlsch0->i0=hDLUE(bufPtr)->i0;
dlsch0->sib1_br_flag=hDLUE(bufPtr)->sib1_br_flag;
#endif
fs6Dlunpack(dlsch_harq->eDL,
hDLUE(bufPtr)+1, hDLUE(bufPtr)->dataLen);
LOG_D(PHY,"received %d bits, in harq id: %di fsf: %d.%d, sum %d\n",
hDLUE(bufPtr)->dataLen, hDLUE(bufPtr)->harq_pid, frame, subframe, sum(dlsch_harq->eDL, hDLUE(bufPtr)->dataLen));
} else if (type == fs6UlConfig) {
int nbUE=(((commonUDP_t *)bufPtr)->contentBytes - sizeof(fs6_dl_t)) / sizeof( fs6_dl_ulsched_t ) ;
#define cpyVal(a) memcpy(&ulsch_harq->a,&hTxULUE(bufPtr)->a, sizeof(ulsch_harq->a))
for ( int i=0; i < nbUE; i++ ) {
int curUE=hTxULUE(bufPtr)->UE_id;
LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[curUE];
LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[hTxULUE(bufPtr)->harq_pid];
ulsch->ue_type=hTxULUE(bufPtr)->ue_type;
ulsch->harq_mask=hTxULUE(bufPtr)->harq_mask;
ulsch->Mlimit=hTxULUE(bufPtr)->Mlimit;
ulsch->max_turbo_iterations=hTxULUE(bufPtr)->max_turbo_iterations;
ulsch->bundling=hTxULUE(bufPtr)->bundling;
ulsch->beta_offset_cqi_times8=hTxULUE(bufPtr)->beta_offset_cqi_times8;
ulsch->beta_offset_ri_times8=hTxULUE(bufPtr)->beta_offset_ri_times8;
ulsch->beta_offset_harqack_times8=hTxULUE(bufPtr)->beta_offset_harqack_times8;
ulsch->Msg3_active=hTxULUE(bufPtr)->Msg3_active;
ulsch->cyclicShift=hTxULUE(bufPtr)->cyclicShift;
ulsch->cooperation_flag=hTxULUE(bufPtr)->cooperation_flag;
ulsch->num_active_cba_groups=hTxULUE(bufPtr)->num_active_cba_groups;
memcpy(ulsch->cba_rnti,hTxULUE(bufPtr)->cba_rnti,sizeof(ulsch->cba_rnti));//NUM_MAX_CBA_GROUP];
ulsch->rnti=hTxULUE(bufPtr)->rnti;
ulsch_harq->nb_rb=hTxULUE(bufPtr)->nb_rb;
ulsch_harq->handled=0;
ulsch_harq->status = ACTIVE;
ulsch_harq->frame = frame;
ulsch_harq->subframe = subframe;
ulsch_harq->first_rb=hTxULUE(bufPtr)->first_rb;
ulsch_harq->O_RI=hTxULUE(bufPtr)->O_RI;
ulsch_harq->Or1=hTxULUE(bufPtr)->Or1;
ulsch_harq->Msc_initial=hTxULUE(bufPtr)->Msc_initial;
ulsch_harq->Nsymb_initial=hTxULUE(bufPtr)->Nsymb_initial;
ulsch_harq->V_UL_DAI=hTxULUE(bufPtr)->V_UL_DAI;
ulsch_harq->Qm=hTxULUE(bufPtr)->Qm;
ulsch_harq->srs_active=hTxULUE(bufPtr)->srs_active;
ulsch_harq->TBS=hTxULUE(bufPtr)->TBS;
ulsch_harq->Nsymb_pusch=hTxULUE(bufPtr)->Nsymb_pusch;
cpyVal(dci_alloc);
cpyVal(rar_alloc);
cpyVal(status);
cpyVal(Msg3_flag);
cpyVal(phich_active);
cpyVal(phich_ACK);
cpyVal(previous_first_rb);
cpyVal(B);
cpyVal(G);
//cpyVal(o);
cpyVal(uci_format);
cpyVal(Or2);
cpyVal(o_RI);
cpyVal(o_ACK);
cpyVal(O_ACK);
//cpyVal(q);
cpyVal(o_RCC);
cpyVal(q_ACK);
cpyVal(q_RI);
cpyVal(RTC);
cpyVal(ndi);
cpyVal(round);
cpyVal(rvidx);
cpyVal(Nl);
cpyVal(n_DMRS);
cpyVal(previous_n_DMRS);
cpyVal(n_DMRS2);
cpyVal(delta_TF);
cpyVal(repetition_number );
cpyVal(total_number_of_repetitions);
LOG_D(PHY,"Received request to perform ulsch for: rnti:%d, fsf: %d/%d, O_ACK: %d\n",
ulsch->rnti, frame, subframe, ulsch_harq->O_ACK);
}
} else if ( type == fs6ULConfigCCH ) {
fs6_dl_uespec_ulcch_element_t *tmp=(fs6_dl_uespec_ulcch_element_t *)(hTxULcch(bufPtr)+1);
for (int i=0; i< hTxULcch(bufPtr)->nb_active_ue; i++ )
memcpy(&eNB->uci_vars[tmp->UE_id], &tmp->cch_vars, sizeof(tmp->cch_vars));
} else
LOG_E(PHY, "Impossible block in fs6 DL\n");
}
bufPtr+=alignedSize(bufPtr);
}
}
void phy_procedures_eNB_TX_fromsplit(uint8_t *bufferZone, int nbBlocks, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas ) {
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
int subframe=proc->subframe_tx;
int frame=proc->frame_tx;
//LTE_UL_eNB_HARQ_t *ulsch_harq;
eNB->pdcch_vars[subframe&1].num_pdcch_symbols=hDL(bufferZone)->num_pdcch_symbols;
eNB->pdcch_vars[subframe&1].num_dci=hDL(bufferZone)->num_dci;
uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci = hDL(bufferZone)->num_mdci;
eNB->pbch_configured=true;
memcpy(eNB->pbch_pdu,hDL(bufferZone)->pbch_pdu, 4);
// Remove all scheduled DL, we will populate from the CU sending
for (int UE_id=0; UE_id<NUMBER_OF_DLSCH_MAX; UE_id++) {
LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0];
if ( dlsch0 && dlsch0->rnti>0 ) {
#ifdef PHY_TX_THREAD
dlsch0->active[subframe] = 0;
#else
dlsch0->active = 0;
#endif
}
}
rcvFs6DL(bufferZone, nbBlocks, eNB, frame, subframe);
if (do_meas==1) {
start_meas(&eNB->phy_proc_tx);
start_meas(&eNB->dlsch_common_and_dci);
}
// clear the transmit data array for the current subframe
for (int aa = 0; aa < fp->nb_antenna_ports_eNB; aa++) {
memset (&eNB->common_vars.txdataF[aa][subframe * fp->ofdm_symbol_size * (fp->symbols_per_tti)],
0, fp->ofdm_symbol_size * (fp->symbols_per_tti) * sizeof (int32_t));
}
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
if (is_pmch_subframe(frame,subframe,fp)) {
pmch_procedures(eNB,proc,0);
} else {
// this is not a pmch subframe, so generate PSS/SSS/PBCH
common_signal_procedures(eNB,frame, subframe);
}
}
// clear previous allocation information for all UEs
for (int i = 0; i < NUMBER_OF_UE_MAX; i++) {
//if (eNB->dlsch[i][0])
//eNB->dlsch[i][0]->subframe_tx[subframe] = 0;
}
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
for (int i=0; i< hDL(bufferZone)->num_dci; i++)
eNB->pdcch_vars[subframe&1].dci_alloc[i]=hDL(bufferZone)->dci_alloc[i];
LOG_D (PHY, "Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %" PRIu8 ")\n", frame, subframe, hDL(bufferZone)->num_dci);
generate_dci_top(hDL(bufferZone)->num_pdcch_symbols,
hDL(bufferZone)->num_dci,
&eNB->pdcch_vars[subframe&1].dci_alloc[0],
0,
hDL(bufferZone)->amp,
fp,
eNB->common_vars.txdataF,
subframe);
if (num_mdci > 0) {
LOG_D (PHY, "[eNB %" PRIu8 "] Frame %d, subframe %d: Calling generate_mdci_top (mpdcch) (num_dci %" PRIu8 ")\n", eNB->Mod_id, frame, subframe, num_mdci);
generate_mdci_top (eNB, frame, subframe, AMP, eNB->common_vars.txdataF);
}
}
for (int UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0];
LTE_eNB_DLSCH_t *dlsch1 = eNB->dlsch[UE_id][1];
if ((dlsch0)&&(dlsch0->rnti>0)&&
#ifdef PHY_TX_THREAD
(dlsch0->active[subframe] == 1)
#else
(dlsch0->active == 1)
#endif
) {
uint64_t sum=0;
for ( int i= subframe * fp->ofdm_symbol_size * (fp->symbols_per_tti);
i< (subframe+1) * fp->ofdm_symbol_size * (fp->symbols_per_tti);
i++)
sum+=((int32_t *)(eNB->common_vars.txdataF[0]))[i];
LOG_D(PHY,"frame: %d, subframe: %d, sum of dlsch mod v1: %lx\n", frame, subframe, sum);
int harq_pid=dlsch0->harq_ids[frame%2][subframe];
pdsch_procedures(eNB,
proc,
harq_pid,
dlsch0,
dlsch1);
}
}
eNB->phich_vars[subframe&1]=hDL(bufferZone)->phich_vars;
generate_phich_top(eNB,
proc,
AMP);
}
#define cpyToDu(a) hTxULUE(newUDPheader)->a=ulsch->a
#define cpyToDuHarq(a) hTxULUE(newUDPheader)->a=ulsch_harq->a
#define memcpyToDuHarq(a) memcpy(&hTxULUE(newUDPheader)->a,&ulsch_harq->a, sizeof(ulsch_harq->a));
void appendFs6TxULUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int curUE, LTE_eNB_ULSCH_t *ulsch, int frame, int subframe) {
commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone;
// move to the end
uint8_t *firstFreeByte=bufferZone;
int curBlock=0;
for (int i=0; i < FirstUDPheader->nbBlocks; i++) {
AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,"");
firstFreeByte+=alignedSize(firstFreeByte);
curBlock++;
}
commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte;
FirstUDPheader->nbBlocks++;
newUDPheader->blockID=curBlock;
newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_ulsched_t);
// We skip the fs6 DL header, that is populated by caller
// This header will be duplicated during sending
hTxULUE(newUDPheader)->type=fs6UlConfig;
hTxULUE(newUDPheader)->UE_id=curUE;
int harq_pid;
if (ulsch->ue_type > NOCE)
// LTE-M case
harq_pid = 0;
else
harq_pid = subframe2harq_pid(fp, frame, subframe);
LTE_UL_eNB_HARQ_t *ulsch_harq=ulsch->harq_processes[harq_pid];
hTxULUE(newUDPheader)->harq_pid=harq_pid;
cpyToDu(ue_type);
cpyToDu(harq_mask);
cpyToDu(Mlimit);
cpyToDu(max_turbo_iterations);
cpyToDu(bundling);
cpyToDu(beta_offset_cqi_times8);
cpyToDu(beta_offset_ri_times8);
cpyToDu(beta_offset_harqack_times8);
cpyToDu(Msg3_active);
cpyToDu(cyclicShift);
cpyToDu(cooperation_flag);
cpyToDu(num_active_cba_groups);
memcpy(hTxULUE(newUDPheader)->cba_rnti,ulsch->cba_rnti,sizeof(ulsch->cba_rnti));//NUM_MAX_CBA_GROUP];
cpyToDu(rnti);
cpyToDuHarq(nb_rb);
cpyToDuHarq(Msc_initial);
cpyToDuHarq(Nsymb_initial);
cpyToDuHarq(O_RI);
cpyToDuHarq(Or1);
cpyToDuHarq(first_rb);
cpyToDuHarq(V_UL_DAI);
cpyToDuHarq(Qm);
cpyToDuHarq(srs_active);
cpyToDuHarq(TBS);
cpyToDuHarq(Nsymb_pusch);
memcpyToDuHarq(dci_alloc);
memcpyToDuHarq(rar_alloc);
memcpyToDuHarq(status);
memcpyToDuHarq(Msg3_flag);
memcpyToDuHarq(phich_active);
memcpyToDuHarq(phich_ACK);
memcpyToDuHarq(previous_first_rb);
memcpyToDuHarq(B);
memcpyToDuHarq(G);
//memcpyToDuHarq(o);
memcpyToDuHarq(uci_format);
memcpyToDuHarq(Or2);
memcpyToDuHarq(o_RI);
memcpyToDuHarq(o_ACK);
memcpyToDuHarq(O_ACK);
//memcpyToDuHarq(q);
memcpyToDuHarq(o_RCC);
memcpyToDuHarq(q_ACK);
memcpyToDuHarq(q_RI);
memcpyToDuHarq(RTC);
memcpyToDuHarq(ndi);
memcpyToDuHarq(round);
memcpyToDuHarq(rvidx);
memcpyToDuHarq(Nl);
memcpyToDuHarq(n_DMRS);
memcpyToDuHarq(previous_n_DMRS);
memcpyToDuHarq(n_DMRS2);
memcpyToDuHarq(delta_TF);
memcpyToDuHarq(repetition_number );
memcpyToDuHarq(total_number_of_repetitions);
LOG_D(PHY,"Added request to perform ulsch for: rnti:%x, fsf: %d/%d\n", ulsch->rnti, frame, subframe);
}
void appendFs6DLUE(uint8_t *bufferZone, LTE_DL_FRAME_PARMS *fp, int UE_id, int8_t harq_pid, LTE_eNB_DLSCH_t *dlsch0, LTE_DL_eNB_HARQ_t *harqData, int frame, int subframe) {
commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone;
// move to the end
uint8_t *firstFreeByte=bufferZone;
int curBlock=0;
for (int i=0; i < FirstUDPheader->nbBlocks; i++) {
AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,"");
firstFreeByte+=alignedSize(firstFreeByte);
curBlock++;
}
int UEdataLen= get_G(fp,
harqData->nb_rb,
harqData->rb_alloc,
harqData->Qm,
harqData->Nl,
harqData->pdsch_start,
frame,subframe,
0);
AssertFatal(firstFreeByte+ceil16_bytes(UEdataLen)+sizeof(fs6_dl_t) <= bufferZone+FS6_BUF_SIZE, "");
commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte;
FirstUDPheader->nbBlocks++;
newUDPheader->blockID=curBlock;
newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_t) + ceil16_bytes(UEdataLen);
// We skip the fs6 DL header, that is populated by caller
// This header will be duplicated during sending
hDLUE(newUDPheader)->type=fs6DlConfig;
hDLUE(newUDPheader)->UE_id=UE_id;
hDLUE(newUDPheader)->harq_pid=harq_pid;
hDLUE(newUDPheader)->rnti=dlsch0->rnti;
hDLUE(newUDPheader)->sqrt_rho_a=dlsch0->sqrt_rho_a;
hDLUE(newUDPheader)->sqrt_rho_b=dlsch0->sqrt_rho_b;
hDLUE(newUDPheader)->nb_rb=harqData->nb_rb;
memcpy(hDLUE(newUDPheader)->rb_alloc, harqData->rb_alloc, sizeof(harqData->rb_alloc));
hDLUE(newUDPheader)->Qm=harqData->Qm;
hDLUE(newUDPheader)->Nl=harqData->Nl;
hDLUE(newUDPheader)->pdsch_start=harqData->pdsch_start;
#ifdef PHY_TX_THREAD
hDLUE(newUDPheader)->CEmode=harqData->CEmode;
hDLUE(newUDPheader)->i0=harqData->i0;
hDLUE(newUDPheader)->sib1_br_flag=harqData->sib1_br_flag;
#else
hDLUE(newUDPheader)->i0=dlsch0->i0;
hDLUE(newUDPheader)->sib1_br_flag=dlsch0->sib1_br_flag;
#endif
hDLUE(newUDPheader)->dataLen=UEdataLen;
fs6Dlpack(hDLUE(newUDPheader)+1, harqData->eDL, UEdataLen);
LOG_D(PHY,"sending %d bits, in harq id: %di fsf: %d.%d, sum %d\n",
UEdataLen, harq_pid, frame, subframe, sum(harqData->eDL, UEdataLen));
//for (int i=0; i < UEdataLen; i++)
//LOG_D(PHY,"buffer ei[%d]:%hhx\n", i, ( (uint8_t *)(hDLUE(newUDPheader)+1) )[i]);
}
void appendFs6DLUEcch(uint8_t *bufferZone, PHY_VARS_eNB *eNB, int frame, int subframe) {
commonUDP_t *FirstUDPheader=(commonUDP_t *) bufferZone;
// move to the end
uint8_t *firstFreeByte=bufferZone;
int curBlock=0;
for (int i=0; i < FirstUDPheader->nbBlocks; i++) {
AssertFatal( ((commonUDP_t *) firstFreeByte)->blockID==curBlock,"");
firstFreeByte+=alignedSize(firstFreeByte);
curBlock++;
}
commonUDP_t *newUDPheader=(commonUDP_t *) firstFreeByte;
bool first_UE=true;
for (int i = 0; i < NUMBER_OF_UCI_MAX; i++) {
LTE_eNB_UCI *uci = &(eNB->uci_vars[i]);
if ((uci->active == 1) && (uci->frame == frame) && (uci->subframe == subframe)) {
LOG_D(PHY,"Frame %d, subframe %d: adding uci procedures (type %d) for %d \n",
frame,
subframe,
uci->type,
i);
if ( first_UE ) {
FirstUDPheader->nbBlocks++;
newUDPheader->blockID=curBlock;
newUDPheader->contentBytes=sizeof(fs6_dl_t)+sizeof(fs6_dl_uespec_ulcch_t);
hTxULcch(newUDPheader)->type=fs6ULConfigCCH;
hTxULcch(newUDPheader)->nb_active_ue=0;
first_UE=false;
}
fs6_dl_uespec_ulcch_element_t *tmp=(fs6_dl_uespec_ulcch_element_t *)(hTxULcch(newUDPheader)+1);
tmp+=hTxULcch(newUDPheader)->nb_active_ue;
tmp->UE_id=i;
memcpy(&tmp->cch_vars,uci, sizeof(tmp->cch_vars));
hTxULcch(newUDPheader)->nb_active_ue++;
newUDPheader->contentBytes+=sizeof(fs6_dl_uespec_ulcch_element_t);
}
}
}
void phy_procedures_eNB_TX_tosplit(uint8_t *bufferZone, PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int do_meas, uint8_t *buf, int bufSize) {
int frame=proc->frame_tx;
int subframe=proc->subframe_tx;
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
if ((fp->frame_type == TDD) && (subframe_select (fp, subframe) == SF_UL)) {
LOG_W(HW,"no sending in eNB_TX\n");
return;
}
// clear previous allocation information for all UEs
for (int i = 0; i < NUMBER_OF_UE_MAX; i++) {
//if (eNB->dlsch[i][0])
//eNB->dlsch[i][0]->subframe_tx[subframe] = 0;
}
// Send to DU the UL scheduled for future UL subframe
for (int i=0; i<NUMBER_OF_UE_MAX; i++) {
int harq_pid;
LTE_eNB_ULSCH_t *ulsch = eNB->ulsch[i];
if (ulsch == NULL)
continue;
if (ulsch->ue_type > NOCE)
harq_pid = 0;
else
harq_pid= subframe2harq_pid(&eNB->frame_parms,frame,subframe);
LTE_UL_eNB_HARQ_t *ulsch_harq = ulsch->harq_processes[harq_pid];
if (ulsch->rnti>0) {
LOG_D(PHY,"check in UL scheduled harq %d: rnti %d, tx frame %d/%d, ulsch: %d, %d/%d (handled: %d)\n",
harq_pid, ulsch->rnti, frame, subframe, ulsch_harq->status, ulsch_harq->frame, ulsch_harq->subframe, ulsch_harq->handled);
}
for (int k=0; k<8; k++) {
ulsch_harq = ulsch->harq_processes[k];
if (ulsch_harq == NULL)
continue;
if ((ulsch->rnti>0) &&
(ulsch_harq->status == ACTIVE) &&
(ulsch_harq->frame == frame) &&
(ulsch_harq->subframe == subframe) &&
(ulsch_harq->handled == 0)
)
appendFs6TxULUE(bufferZone,
fp,
i,
ulsch,
frame,
subframe
);
}
}
appendFs6DLUEcch(bufferZone,
eNB,
frame,
subframe
);
uint8_t num_pdcch_symbols = eNB->pdcch_vars[subframe&1].num_pdcch_symbols;
uint8_t num_dci = eNB->pdcch_vars[subframe&1].num_dci;
uint8_t num_mdci = eNB->mpdcch_vars[subframe&1].num_dci;
memcpy(hDL(bufferZone)->pbch_pdu,eNB->pbch_pdu,4);
if ( num_dci <= 8 )
LOG_D(PHY,"num_pdcch_symbols %"PRIu8",number dci %"PRIu8"\n",num_pdcch_symbols, num_dci);
else {
LOG_E(PHY, "Num dci too large for current FS6 implementation, reducing to 8 dci (was %d)\n", num_dci);
num_dci=8;
}
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
hDL(bufferZone)->num_pdcch_symbols=num_pdcch_symbols;
hDL(bufferZone)->num_dci=num_dci;
hDL(bufferZone)->num_mdci=num_mdci;
hDL(bufferZone)->amp=AMP;
for (int i=0; i< hDL(bufferZone)->num_dci; i++)
hDL(bufferZone)->dci_alloc[i]=eNB->pdcch_vars[subframe&1].dci_alloc[i];
LOG_D(PHY, "pbch configured: %d\n", eNB->pbch_configured);
}
if (do_meas==1) stop_meas(&eNB->dlsch_common_and_dci);
if (do_meas==1) start_meas(&eNB->dlsch_ue_specific);
for (int UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) {
LTE_eNB_DLSCH_t *dlsch0 = eNB->dlsch[UE_id][0];
if ((dlsch0)&&(dlsch0->rnti>0)&&
#ifdef PHY_TX_THREAD
(dlsch0->active[subframe] == 1)
#else
(dlsch0->active == 1)
#endif
) {
// get harq_pid
int harq_pid = dlsch0->harq_ids[frame%2][subframe];
AssertFatal(harq_pid>=0,"harq_pid is negative\n");
if (harq_pid>=8) {
if (dlsch0->ue_type == NOCE)
LOG_E(PHY,"harq_pid:%d corrupt must be 0-7 UE_id:%d frame:%d subframe:%d rnti:%x [ %1d.%1d.%1d.%1d.%1d.%1d.%1d.%1d\n", harq_pid,UE_id,frame,subframe,dlsch0->rnti,
dlsch0->harq_ids[frame%2][0],
dlsch0->harq_ids[frame%2][1],
dlsch0->harq_ids[frame%2][2],
dlsch0->harq_ids[frame%2][3],
dlsch0->harq_ids[frame%2][4],
dlsch0->harq_ids[frame%2][5],
dlsch0->harq_ids[frame%2][6],
dlsch0->harq_ids[frame%2][7]);
} else {
if (dlsch_procedures(eNB,
proc,
harq_pid,
dlsch0,
&eNB->UE_stats[(uint32_t)UE_id])) {
// data in: dlsch0 harq_processes[harq_pid]->e
/* length
get_G(fp,
dlsch_harq->nb_rb,
dlsch_harq->rb_alloc,
dlsch_harq->Qm,
dlsch_harq->Nl,
dlsch_harq->pdsch_start,
frame,subframe,
0)
need harq_pid
*/
LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch0->harq_processes[harq_pid];
appendFs6DLUE(bufferZone,
fp,
UE_id,
harq_pid,
dlsch0,
dlsch_harq,
frame,
subframe
);
}
}
} else if ((dlsch0)&&(dlsch0->rnti>0)&&
#ifdef PHY_TX_THREAD
(dlsch0->active[subframe] == 0)
#else
(dlsch0->active == 0)
#endif
) {
// clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later)
//dlsch0->subframe_tx[subframe]=0;
}
}
hDL(bufferZone)->phich_vars=eNB->phich_vars[subframe&1];
if (do_meas==1) stop_meas(&eNB->dlsch_ue_specific);
if (do_meas==1) stop_meas(&eNB->phy_proc_tx);
// MBMS is not working in OAI
if (hDL(bufferZone)->num_mdci) abort();
return;
}
void *DL_du_fs6(void *arg) {
RU_t *ru=(RU_t *)arg;
static uint64_t lastTS;
L1_rxtx_proc_t L1proc= {0};
// We pick the global thread pool from the legacy code global vars
L1proc.threadPool=RC.eNB[0][0]->proc.L1_proc.threadPool;
L1proc.respEncode=RC.eNB[0][0]->proc.L1_proc.respEncode;
L1proc.respDecode=RC.eNB[0][0]->proc.L1_proc.respDecode;
initStaticTime(begingWait);
initStaticTime(begingProcessing);
initRefTimes(fullLoop);
initRefTimes(DuHigh);
initRefTimes(DuLow);
initRefTimes(transportTime);
while (1) {
for (int i=0; i<ru->num_eNB; i++) {
initBufferZone(bufferZone);
pickStaticTime(begingWait);
int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentCUv0 );
updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait CU");
if (nb_blocks > 0) {
if ( lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti < hUDP(bufferZone)->timestamp) {
LOG_E(HW,"Missed a subframe: expecting: %lu, received %lu\n",
lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti,
hUDP(bufferZone)->timestamp);
} else if ( lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti > hUDP(bufferZone)->timestamp) {
LOG_E(HW,"Received a subframe in past time from CU (dropping it): expecting: %lu, received %lu\n",
lastTS+ru->eNB_list[i]->frame_parms.samples_per_tti,
hUDP(bufferZone)->timestamp);
}
pickStaticTime(begingProcessing);
lastTS=hUDP(bufferZone)->timestamp;
setAllfromTS(hUDP(bufferZone)->timestamp - sf_ahead*ru->eNB_list[i]->frame_parms.samples_per_tti, &L1proc);
measTransportTime(hDL(bufferZone)->DuClock, hDL(bufferZone)->CuSpentMicroSec,
&transportTime, 1000, false, "Transport time, to CU + from CU for one subframe");
phy_procedures_eNB_TX_fromsplit( bufferZone, nb_blocks, ru->eNB_list[i], &L1proc, 1);
updateTimesReset(begingProcessing, &DuHigh, 1000, false, "DU high layer1 processing for DL");
} else
LOG_E(PHY,"DL not received for subframe\n");
}
pickStaticTime(begingProcessing);
feptx_prec(ru, L1proc.frame_tx,L1proc.subframe_tx );
feptx_ofdm(ru, L1proc.frame_tx,L1proc.subframe_tx );
ocp_tx_rf(ru, &L1proc);
updateTimesReset(begingProcessing, &DuLow, 1000, false, "DU low layer1 processing for DL");
if ( IS_SOFTMODEM_RFSIM )
return NULL;
}
return NULL;
}
void UL_du_fs6(RU_t *ru, L1_rxtx_proc_t *proc) {
initStaticTime(begingWait);
initRefTimes(fullLoop);
pickStaticTime(begingWait);
rx_rf(ru, proc);
updateTimesReset(begingWait, &fullLoop, 1000, false, "DU wait USRP");
// front end processing: convert from time domain to frequency domain
// fills rxdataF buffer
fep_full(ru, proc->subframe_rx);
// Fixme: datamodel issue
PHY_VARS_eNB *eNB = RC.eNB[0][0];
if (NFAPI_MODE==NFAPI_MODE_PNF) {
// I am a PNF and I need to let nFAPI know that we have a (sub)frame tick
//add_subframe(&frame, &subframe, 4);
//oai_subframe_ind(proc->frame_tx, proc->subframe_tx);
oai_subframe_ind(proc->frame_rx, proc->subframe_rx);
}
initBufferZone(bufferZone);
hUDP(bufferZone)->timestamp=proc->timestamp_rx;
prach_eNB_tosplit(bufferZone, FS6_BUF_SIZE, eNB, proc );
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
phy_procedures_eNB_uespec_RX_tosplit(bufferZone, FS6_BUF_SIZE, eNB, proc );
}
if (hUDP(bufferZone)->nbBlocks==0) {
hUDP(bufferZone)->nbBlocks=1; // We have to send the signaling, even is there is no user plan data (no UE)
hUDP(bufferZone)->blockID=0;
hUDP(bufferZone)->contentBytes=sizeof(fs6_ul_t);
}
for (int i=0; i<ru->num_eNB; i++) {
sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_ul_t), CTsentDUv0);
}
}
void DL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t DuClock, uint64_t startCycle) {
initRefTimes(CUprocessing);
// Fixme: datamodel issue
PHY_VARS_eNB *eNB = RC.eNB[0][0];
pthread_mutex_lock(&eNB->UL_INFO_mutex);
eNB->UL_INFO.frame = proc->frame_rx;
eNB->UL_INFO.subframe = proc->subframe_rx;
eNB->UL_INFO.module_id = eNB->Mod_id;
eNB->UL_INFO.CC_id = eNB->CC_id;
eNB->if_inst->UL_indication(&eNB->UL_INFO, proc);
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
initBufferZone(bufferZone);
phy_procedures_eNB_TX_tosplit(bufferZone, eNB, proc, 1, bufferZone, FS6_BUF_SIZE);
hUDP(bufferZone)->timestamp=proc->timestamp_tx;
if (hUDP(bufferZone)->nbBlocks==0) {
hUDP(bufferZone)->nbBlocks=1; // We have to send the signaling, even is there is no user plan data (no UE)
hUDP(bufferZone)->blockID=0;
hUDP(bufferZone)->contentBytes=sizeof(fs6_dl_t);
}
hDL(bufferZone)->DuClock=DuClock;
hDL(bufferZone)->CuSpentMicroSec=(rdtsc_oai()-startCycle)/(cpuf*1000);
updateTimesReset(startCycle, &CUprocessing, 1000, true,"CU entire processing from recv to send");
sendSubFrame(&sockFS6, bufferZone, sizeof(fs6_dl_t), CTsentCUv0 );
return;
}
void UL_cu_fs6(RU_t *ru, L1_rxtx_proc_t *proc, uint64_t *TS, uint64_t *DuClock, uint64_t *startProcessing) {
initBufferZone(bufferZone);
initStaticTime(begingWait);
initRefTimes(fullLoop);
pickStaticTime(begingWait);
int nb_blocks=receiveSubFrame(&sockFS6, bufferZone, sizeof(bufferZone), CTsentDUv0 );
* DuClock=hUDP(bufferZone)->senderClock;
* startProcessing=rdtsc_oai();
updateTimesReset(begingWait, &fullLoop, 1000, false, "CU wait DU");
if (nb_blocks ==0) {
LOG_W(PHY, "CU lost a subframe\n");
return;
}
if (nb_blocks != hUDP(bufferZone)->nbBlocks )
LOG_W(PHY, "received %d blocks for %d expected\n", nb_blocks, hUDP(bufferZone)->nbBlocks);
if ( *TS != hUDP(bufferZone)->timestamp ) {
LOG_W(HW, "CU received time: %lu instead of %lu expected\n", hUDP(bufferZone)->timestamp, *TS);
*TS=hUDP(bufferZone)->timestamp;
}
setAllfromTS(hUDP(bufferZone)->timestamp, proc);
PHY_VARS_eNB *eNB = RC.eNB[0][0];
if (is_prach_subframe(&eNB->frame_parms, proc->frame_prach,proc->subframe_prach)>0)
prach_eNB_fromsplit(bufferZone, sizeof(bufferZone), eNB, proc);
release_UE_in_freeList(eNB->Mod_id);
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
phy_procedures_eNB_uespec_RX_fromsplit(bufferZone, nb_blocks, eNB, proc);
}
}
void *cu_fs6(void *arg) {
setbuf(stdout, NULL);
setbuf(stderr, NULL);
RU_t *ru = (RU_t *)arg;
//RU_proc_t *proc = &ru->proc;
fill_rf_config(ru,ru->rf_config_file);
init_frame_parms(ru->frame_parms,1);
phy_init_RU(ru);
wait_sync("ru_thread");
char remoteIP[1024];
strncpy(remoteIP,get_softmodem_params()->split73+3, 1023); //three first char should be cu: or du:
char port_def[256]=DU_PORT;
for (int i=0; i <1000; i++)
if (remoteIP[i]==':') {
strncpy(port_def,remoteIP+i+1,255);
remoteIP[i]=0;
break;
}
AssertFatal(createUDPsock(NULL, CU_PORT, remoteIP, port_def, &sockFS6), "");
L1_rxtx_proc_t L1proc= {0};
// We pick the global thread pool from the legacy code global vars
L1proc.threadPool=RC.eNB[0][0]->proc.L1_proc.threadPool;
L1proc.respEncode=RC.eNB[0][0]->proc.L1_proc.respEncode;
L1proc.respDecode=RC.eNB[0][0]->proc.L1_proc.respDecode;
uint64_t timeStamp=0;
initStaticTime(begingWait);
initStaticTime(begingWait2);
initRefTimes(waitDUAndProcessingUL);
initRefTimes(makeSendDL);
initRefTimes(fullLoop);
uint64_t DuClock=0, startProcessing=0;
while(1) {
timeStamp+=ru->frame_parms->samples_per_tti;
updateTimesReset(begingWait, &fullLoop, 1000, true, "CU for full SubFrame (must be less 1ms)");
pickStaticTime(begingWait);
UL_cu_fs6(ru, &L1proc, &timeStamp, &DuClock, &startProcessing);
updateTimesReset(begingWait, &waitDUAndProcessingUL, 1000, true,"CU Time in wait Rx + Ul processing");
pickStaticTime(begingWait2);
DL_cu_fs6(ru, &L1proc, DuClock, startProcessing);
updateTimesReset(begingWait2, &makeSendDL, 1000, true,"CU Time in DL build+send");
}
return NULL;
}
void *du_fs6(void *arg) {
setbuf(stdout, NULL);
setbuf(stderr, NULL);
RU_t *ru = (RU_t *)arg;
//RU_proc_t *proc = &ru->proc;
fill_rf_config(ru,ru->rf_config_file);
init_frame_parms(ru->frame_parms,1);
phy_init_RU(ru);
init_rf(ru);
wait_sync("ru_thread");
char remoteIP[1024];
strncpy(remoteIP,get_softmodem_params()->split73+3,1023); //three first char should be cu: or du:
char port_def[256]=CU_PORT;
for (int i=0; i <1000; i++)
if (remoteIP[i]==':') {
strncpy(port_def,remoteIP+i+1,255);
remoteIP[i]=0;
break;
}
AssertFatal(createUDPsock(NULL, DU_PORT, remoteIP, port_def, &sockFS6), "");
if (ru->rfdevice.trx_start_func(&ru->rfdevice) != 0)
LOG_E(HW,"Could not start the RF device\n");
else
LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
initStaticTime(begingWait);
initRefTimes(waitRxAndProcessingUL);
initRefTimes(fullLoop);
pthread_t t;
if ( !IS_SOFTMODEM_RFSIM )
threadCreate(&t, DL_du_fs6, (void *)ru, "MainDuTx", -1, OAI_PRIORITY_RT_MAX);
L1_rxtx_proc_t L1proc= {0};
// We pick the global thread pool from the legacy code global vars
L1proc.threadPool=RC.eNB[0][0]->proc.L1_proc.threadPool;
L1proc.respEncode=RC.eNB[0][0]->proc.L1_proc.respEncode;
L1proc.respDecode=RC.eNB[0][0]->proc.L1_proc.respDecode;
while(!oai_exit) {
updateTimesReset(begingWait, &fullLoop, 1000, true,"DU for full SubFrame (must be less 1ms)");
pickStaticTime(begingWait);
UL_du_fs6(ru, &L1proc);
if ( IS_SOFTMODEM_RFSIM )
DL_du_fs6((void *)ru);
updateTimesReset(begingWait, &waitRxAndProcessingUL, 1000, true,"DU Time in wait Rx + Ul processing");
}
ru->rfdevice.trx_end_func(&ru->rfdevice);
LOG_I(PHY,"RU %d rf device stopped\n",ru->idx);
return NULL;
}
/*
* 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
*
* Author and copyright: Laurent Thomas, open-cells.com
*
* 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
*/
/*
* This file replaces
* executables/lte-softmodem.c
* executables/rt_wrapper.c
* executables/lte-ru.c
* executables/lte-enb.c
* executables/ru_control.c
* openair1/SCHED/prach_procedures.c
* The merger of OpenAir central code to this branch
* should check if these 3 files are modified and analyze if code code has to be copied in here
*/
#define _GNU_SOURCE
#include <pthread.h>
#include <common/utils/LOG/log.h>
#include <common/utils/system.h>
#include <common/utils/assertions.h>
static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
#include <common/config/config_userapi.h>
#include "executables/lte-softmodem.h"
#include <openair1/PHY/defs_eNB.h>
#include <openair1/PHY/phy_extern.h>
#include <nfapi/oai_integration/vendor_ext.h>
#include <openair1/SCHED/fapi_l1.h>
#include <openair1/PHY/INIT/phy_init.h>
#include <openair2/LAYER2/MAC/mac_extern.h>
#include <openair1/PHY/LTE_REFSIG/lte_refsig.h>
#include <nfapi/oai_integration/nfapi_pnf.h>
#include <executables/split_headers.h>
#include <common/utils/threadPool/thread-pool.h>
#include <openair2/ENB_APP/NB_IoT_interface.h>
#include <common/utils/load_module_shlib.h>
#include <targets/COMMON/create_tasks.h>
#include <openair1/PHY/TOOLS/phy_scope_interface.h>
#include <openair2/UTIL/OPT/opt.h>
#include <openair1/SIMULATION/TOOLS/sim.h>
#include <openair1/PHY/phy_vars.h>
#include <openair2/LAYER2/MAC/mac_vars.h>
#include <openair2/RRC/LTE/rrc_vars.h>
pthread_cond_t nfapi_sync_cond;
pthread_mutex_t nfapi_sync_mutex;
int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex
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;
int oai_exit = 0;
double cpuf;
THREAD_STRUCT thread_struct;
extern uint16_t sf_ahead; // Bell Labs
//uint16_t sf_ahead=4;
//uint16_t slot_ahead=6;
int otg_enabled;
uint64_t downlink_frequency[MAX_NUM_CCs][4];
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
int split73;
char *split73_config;
int split73;
AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB]= {0};
AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]= {0};
static void *ru_thread( void *param );
void kill_RU_proc(RU_t *ru) {
}
void kill_eNB_proc(int inst) {
}
void free_transport(PHY_VARS_eNB *eNB) {
}
void reset_opp_meas(void) {
}
extern void phy_free_RU(RU_t *);
void exit_function(const char *file, const char *function, const int line, const char *s) {
if (s != NULL) {
printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s);
}
close_log_mem();
oai_exit = 1;
sleep(1); //allow lte-softmodem threads to exit first
exit(1);
}
// Fixme: there are many mistakes in the datamodel and in redondant variables
// TDD is also mode complex
void setAllfromTS(uint64_t TS, L1_rxtx_proc_t *proc) {
for (int i=0; i < RC.nb_inst; i++) {
for (int j=0; j<RC.nb_CC[i]; j++) {
LTE_DL_FRAME_PARMS *fp=&RC.eNB[i][j]->frame_parms;
uint64_t TStx=TS+(sf_ahead)*fp->samples_per_tti;
uint64_t TSrach=TS;//-fp->samples_per_tti;
proc->timestamp_rx= TS;
proc->timestamp_tx= TStx;
proc->subframe_rx= (TS / fp->samples_per_tti)%10;
proc->subframe_prach=(TSrach / fp->samples_per_tti)%10;
proc->subframe_prach_br=(TSrach / fp->samples_per_tti)%10;
proc->frame_rx= (TS / (fp->samples_per_tti*10))&1023;
proc->frame_prach= (TSrach / (fp->samples_per_tti*10))&1023;
proc->frame_prach_br=(TSrach / (fp->samples_per_tti*10))&1023;
proc->frame_tx= (TStx / (fp->samples_per_tti*10))&1023;
proc->subframe_tx= (TStx / fp->samples_per_tti)%10;
}
}
return;
}
void init_RU_proc(RU_t *ru) {
pthread_t t;
switch(split73) {
case SPLIT73_CU:
threadCreate(&t, cu_fs6, (void *)ru, "MainCu", -1, OAI_PRIORITY_RT_MAX);
break;
case SPLIT73_DU:
threadCreate(&t, du_fs6, (void *)ru, "MainDuRx", -1, OAI_PRIORITY_RT_MAX);
break;
default:
threadCreate(&t, ru_thread, (void *)ru, "MainRu", -1, OAI_PRIORITY_RT_MAX);
}
}
// Create per UE structures
void init_transport(PHY_VARS_eNB *eNB) {
LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
LOG_I(PHY, "Initialise transport\n");
for (int i=0; i<NUMBER_OF_DLSCH_MAX; i++) {
LOG_D(PHY,"Allocating Transport Channel Buffers for DLSCH, UE %d\n",i);
for (int j=0; j<2; j++) {
AssertFatal( (eNB->dlsch[i][j] = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL,0,fp)) != NULL,
"Can't get eNB dlsch structures for UE %d \n", i);
eNB->dlsch[i][j]->rnti=0;
LOG_D(PHY,"dlsch[%d][%d] => %p rnti:%d\n",i,j,eNB->dlsch[i][j], eNB->dlsch[i][j]->rnti);
}
}
for (int i=0; i<NUMBER_OF_ULSCH_MAX; i++) {
LOG_D(PHY,"Allocating Transport Channel Buffers for ULSCH, UE %d\n",i);
AssertFatal((eNB->ulsch[1+i] = new_eNB_ulsch(MAX_TURBO_ITERATIONS,fp->N_RB_UL, 0)) != NULL,
"Can't get eNB ulsch structures\n");
// this is the transmission mode for the signalling channels
// this will be overwritten with the real transmission mode by the RRC once the UE is connected
eNB->transmission_mode[i] = fp->nb_antenna_ports_eNB==1 ? 1 : 2;
}
// ULSCH for RA
AssertFatal( (eNB->ulsch[0] = new_eNB_ulsch(MAX_TURBO_ITERATIONS, fp->N_RB_UL, 0)) !=NULL,
"Can't get eNB ulsch structures\n");
eNB->dlsch_SI = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
LOG_D(PHY,"eNB %d.%d : SI %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_SI);
eNB->dlsch_ra = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
LOG_D(PHY,"eNB %d.%d : RA %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_ra);
eNB->dlsch_MCH = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
LOG_D(PHY,"eNB %d.%d : MCH %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_MCH);
eNB->rx_total_gain_dB=130;
for(int i=0; i<NUMBER_OF_UE_MAX; i++)
eNB->mu_mimo_mode[i].dl_pow_off = 2;
eNB->check_for_total_transmissions = 0;
eNB->check_for_MUMIMO_transmissions = 0;
eNB->FULL_MUMIMO_transmissions = 0;
eNB->check_for_SUMIMO_transmissions = 0;
fp->pucch_config_common.deltaPUCCH_Shift = 1;
if (eNB->use_DTX == 0)
fill_subframe_mask(eNB);
}
void init_eNB_afterRU(void) {
for (int inst=0; inst<RC.nb_inst; inst++) {
for (int CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) {
PHY_VARS_eNB *eNB = RC.eNB[inst][CC_id];
eNB->frame_parms.nb_antennas_rx = 0;
eNB->frame_parms.nb_antennas_tx = 0;
eNB->prach_vars.rxsigF[0] = (int16_t **)malloc16(64*sizeof(int16_t *));
for (int ce_level=0; ce_level<4; ce_level++) {
eNB->prach_vars_br.rxsigF[ce_level] = (int16_t **)malloc16(64*sizeof(int16_t *));
}
for (int ru_id=0,aa=0; ru_id<eNB->num_RU; ru_id++) {
eNB->frame_parms.nb_antennas_rx += eNB->RU_list[ru_id]->nb_rx;
eNB->frame_parms.nb_antennas_tx += eNB->RU_list[ru_id]->nb_tx;
AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL,
"RU %d : common.rxdataF is NULL\n",
eNB->RU_list[ru_id]->idx);
AssertFatal(eNB->RU_list[ru_id]->prach_rxsigF!=NULL,
"RU %d : prach_rxsigF is NULL\n",
eNB->RU_list[ru_id]->idx);
for (int i=0; i<eNB->RU_list[ru_id]->nb_rx; aa++,i++) {
LOG_I(PHY,"Attaching RU %d antenna %d to eNB antenna %d\n",eNB->RU_list[ru_id]->idx,i,aa);
eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[ru_id]->prach_rxsigF[0][i];
for (int ce_level=0; ce_level<4; ce_level++)
eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[ru_id]->prach_rxsigF_br[ce_level][i];
}
}
AssertFatal( eNB->frame_parms.nb_antennas_rx > 0 && eNB->frame_parms.nb_antennas_rx < 5, "");
AssertFatal( eNB->frame_parms.nb_antennas_tx > 0 && eNB->frame_parms.nb_antennas_rx < 5, "");
phy_init_lte_eNB(eNB,0,0);
// need to copy rxdataF after L1 variables are allocated
for (int inst=0; inst<RC.nb_inst; inst++) {
for (int CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) {
PHY_VARS_eNB *eNB = RC.eNB[inst][CC_id];
for (int ru_id=0,aa=0; ru_id<eNB->num_RU; ru_id++) {
for (int i=0; i<eNB->RU_list[ru_id]->nb_rx; aa++,i++)
eNB->common_vars.rxdataF[aa] = eNB->RU_list[ru_id]->common.rxdataF[i];
}
}
}
LOG_I(PHY,"inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx);
init_transport(eNB);
//init_precoding_weights(RC.eNB[inst][CC_id]);
}
}
}
void init_eNB(int single_thread_flag,int wait_for_sync) {
AssertFatal(RC.eNB != NULL,"RC.eNB must have been allocated\n");
for (int inst=0; inst<RC.nb_L1_inst; inst++) {
AssertFatal(RC.eNB[inst] != NULL,"RC.eNB[%d] must have been allocated\n", inst);
for (int CC_id=0; CC_id<RC.nb_L1_CC[inst]; CC_id++) {
AssertFatal(RC.eNB[inst][CC_id] != NULL,"RC.eNB[%d][%d] must have been allocated\n", inst, CC_id);
PHY_VARS_eNB *eNB = RC.eNB[inst][CC_id];
eNB->abstraction_flag = 0;
eNB->single_thread_flag = single_thread_flag;
AssertFatal((eNB->if_inst = IF_Module_init(inst))!=NULL,"Cannot register interface");
eNB->if_inst->schedule_response = schedule_response;
eNB->if_inst->PHY_config_req = phy_config_request;
memset((void *)&eNB->UL_INFO,0,sizeof(eNB->UL_INFO));
memset((void *)&eNB->Sched_INFO,0,sizeof(eNB->Sched_INFO));
pthread_mutex_init( &eNB->UL_INFO_mutex, NULL);
LOG_I(PHY,"Setting indication lists\n");
eNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = eNB->rx_pdu_list;
eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list;
eNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = eNB->sr_pdu_list;
eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list;
eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_pdu_list = eNB->cqi_pdu_list;
eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list;
eNB->prach_energy_counter = 0;
}
}
SET_LOG_DEBUG(PRACH);
}
void stop_eNB(int nb_inst) {
for (int inst=0; inst<nb_inst; inst++) {
LOG_I(PHY,"Killing eNB %d processing threads\n",inst);
kill_eNB_proc(inst);
}
}
// this is for RU with local RF unit
void fill_rf_config(RU_t *ru, char *rf_config_file) {
int i;
LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
openair0_config_t *cfg = &ru->openair0_cfg;
//printf("////////////////numerology in config = %d\n",numerology);
int numerology = 0; //get_softmodem_params()->numerology;
if(fp->N_RB_DL == 100) {
if(numerology == 0) {
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(numerology == 1) {
cfg->sample_rate=61.44e6;
cfg->samples_per_frame = 307200;
cfg->tx_bw = 20e6;
cfg->rx_bw = 20e6;
} else if(numerology == 2) {
cfg->sample_rate=122.88e6;
cfg->samples_per_frame = 307200;
cfg->tx_bw = 40e6;
cfg->rx_bw = 40e6;
} else {
LOG_E(PHY,"Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology);
cfg->sample_rate=30.72e6;
cfg->samples_per_frame = 307200;
cfg->tx_bw = 10e6;
cfg->rx_bw = 10e6;
}
} else if(fp->N_RB_DL == 50) {
cfg->sample_rate=15.36e6;
cfg->samples_per_frame = 153600;
cfg->tx_bw = 5e6;
cfg->rx_bw = 5e6;
} else if (fp->N_RB_DL == 25) {
cfg->sample_rate=7.68e6;
cfg->samples_per_frame = 76800;
cfg->tx_bw = 2.5e6;
cfg->rx_bw = 2.5e6;
} else if (fp->N_RB_DL == 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_DL %d\n",fp->N_RB_DL);
if (fp->frame_type==TDD)
cfg->duplex_mode = duplex_mode_TDD;
else //FDD
cfg->duplex_mode = duplex_mode_FDD;
cfg->Mod_id = 0;
cfg->num_rb_dl=fp->N_RB_DL;
cfg->tx_num_channels=ru->nb_tx;
cfg->rx_num_channels=ru->nb_rx;
cfg->clock_source=get_softmodem_params()->clock_source;
for (i=0; i<ru->nb_tx; i++) {
cfg->tx_freq[i] = (double)fp->dl_CarrierFreq;
cfg->rx_freq[i] = (double)fp->ul_CarrierFreq;
cfg->tx_gain[i] = (double)ru->att_tx;
cfg->rx_gain[i] = ru->max_rxgain-(double)ru->att_rx;
cfg->configFilename = rf_config_file;
LOG_I(PHY,"channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n",
i, cfg->tx_gain[i],
cfg->rx_gain[i],
cfg->tx_freq[i],
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) {
//uint16_t N_TA_offset = 0;
LTE_DL_FRAME_PARMS *frame_parms;
AssertFatal(ru, "ru is NULL");
frame_parms = ru->frame_parms;
LOG_I(PHY,"setup_RU_buffers: frame_parms = %p\n",frame_parms);
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;
ru->sf_extension /= 2;
ru->end_of_burst_delay /= 2;
} else if (frame_parms->N_RB_DL == 25) {
ru->N_TA_offset = 624/4;
ru->sf_extension /= 4;
ru->end_of_burst_delay /= 4;
} else {
LOG_E(PHY,"not handled, todo\n");
exit(1);
}
} else {
ru->N_TA_offset = 0;
ru->sf_extension = 0;
ru->end_of_burst_delay = 0;
}
return(0);
}
#if 0
void init_precoding_weights(PHY_VARS_eNB *eNB) {
int layer,ru_id,aa,re,ue,tb;
LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
RU_t *ru;
LTE_eNB_DLSCH_t *dlsch;
// init precoding weigths
for (ue=0; ue<NUMBER_OF_UE_MAX; ue++) {
for (tb=0; tb<2; tb++) {
dlsch = eNB->dlsch[ue][tb];
for (layer=0; layer<4; layer++) {
int nb_tx=0;
for (ru_id=0; ru_id<RC.nb_RU; ru_id++) {
ru = RC.ru[ru_id];
nb_tx+=ru->nb_tx;
}
dlsch->ue_spec_bf_weights[layer] = (int32_t **)malloc16(nb_tx*sizeof(int32_t *));
for (aa=0; aa<nb_tx; aa++) {
dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t));
for (re=0; re<fp->ofdm_symbol_size; re++) {
dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff;
}
}
}
}
}
}
#endif
void ocp_rx_prach(PHY_VARS_eNB *eNB,
L1_rxtx_proc_t *proc,
RU_t *ru,
uint16_t *max_preamble,
uint16_t *max_preamble_energy,
uint16_t *max_preamble_delay,
uint16_t *avg_preamble_energy,
uint16_t Nf,
uint8_t tdd_mapindex,
uint8_t br_flag) {
int i;
int prach_mask=0;
if (br_flag == 0) {
rx_prach0(eNB,ru,proc->frame_prach, proc->subframe_prach,
max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,0,0);
} else { // This is procedure for eMTC, basically handling the repetitions
prach_mask = is_prach_subframe(&eNB->frame_parms,proc->frame_prach_br,proc->subframe_prach_br);
for (i=0; i<4; i++) {
if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i]==1) &&
((prach_mask&(1<<(i+1))) > 0)) { // check that prach CE level is active now
// if first reception in group of repetitions store frame for later (in RA-RNTI for Msg2)
if (eNB->prach_vars_br.repetition_number[i]==0)
eNB->prach_vars_br.first_frame[i]=proc->frame_prach_br;
// increment repetition number
eNB->prach_vars_br.repetition_number[i]++;
// do basic PRACH reception
rx_prach0(eNB,ru,proc->frame_prach, proc->subframe_prach_br,
max_preamble,max_preamble_energy,max_preamble_delay,avg_preamble_energy,Nf,tdd_mapindex,1,i);
// if last repetition, clear counter
if (eNB->prach_vars_br.repetition_number[i] == eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[i]) {
eNB->prach_vars_br.repetition_number[i]=0;
}
}
} /* for i ... */
} /* else br_flag == 0 */
}
void prach_procedures_ocp(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int br_flag) {
uint16_t max_preamble[4],max_preamble_energy[4],max_preamble_delay[4],avg_preamble_energy[4];
RU_t *ru;
int aa=0;
int ru_aa;
for (int i=0; i<eNB->num_RU; i++) {
ru=eNB->RU_list[i];
for (ru_aa=0,aa=0; ru_aa<ru->nb_rx; ru_aa++,aa++) {
eNB->prach_vars.rxsigF[0][aa] = eNB->RU_list[i]->prach_rxsigF[0][ru_aa];
int ce_level;
if (br_flag==1)
for (ce_level=0; ce_level<4; ce_level++)
eNB->prach_vars_br.rxsigF[ce_level][aa] = eNB->RU_list[i]->prach_rxsigF_br[ce_level][ru_aa];
}
}
// run PRACH detection for CE-level 0 only for now when br_flag is set
ocp_rx_prach(eNB,
proc,
eNB->RU_list[0],
&max_preamble[0],
&max_preamble_energy[0],
&max_preamble_delay[0],
&avg_preamble_energy[0],
proc->frame_prach,
0
,br_flag
);
LOG_D(PHY,"RACH detection index 0: max preamble: %u, energy: %u, delay: %u, avg energy: %u\n",
max_preamble[0],
max_preamble_energy[0],
max_preamble_delay[0],
avg_preamble_energy[0]
);
if (br_flag==1) {
int prach_mask;
prach_mask = is_prach_subframe (&eNB->frame_parms, proc->frame_prach_br, proc->subframe_prach_br);
eNB->UL_INFO.rach_ind_br.rach_indication_body.preamble_list = eNB->preamble_list_br;
int ind = 0;
int ce_level = 0;
/* Save for later, it doesn't work
for (int ind=0,ce_level=0;ce_level<4;ce_level++) {
if ((eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[ce_level]==1)&&
(prach_mask&(1<<(1+ce_level)) > 0) && // prach is active and CE level has finished its repetitions
(eNB->prach_vars_br.repetition_number[ce_level]==
eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_numRepetitionPerPreambleAttempt[ce_level])) {
*/
if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) {
if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) {
eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++;
eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind]; //
eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind];
// note: fid is implicitly 0 here, this is the rule for eMTC RA-RNTI from 36.321, Section 5.1.4
eNB->preamble_list_br[ind].preamble_rel8.rnti = 1 + proc->subframe_prach + (60*(eNB->prach_vars_br.first_frame[ce_level] % 40));
eNB->preamble_list_br[ind].instance_length = 0; //don't know exactly what this is
eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type = 1 + ce_level; // CE Level
LOG_I (PHY, "Filling NFAPI indication for RACH %d CELevel %d (mask %x) : TA %d, Preamble %d, rnti %x, rach_resource_type %d\n",
ind,
ce_level,
prach_mask,
eNB->preamble_list_br[ind].preamble_rel8.timing_advance,
eNB->preamble_list_br[ind].preamble_rel8.preamble, eNB->preamble_list_br[ind].preamble_rel8.rnti, eNB->preamble_list_br[ind].preamble_rel13.rach_resource_type);
}
}
/*
ind++;
}
} */// ce_level
} else if ((eNB->prach_energy_counter == 100) &&
(max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) {
LOG_I(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n",
eNB->Mod_id,
eNB->CC_id,
proc->frame_prach,
proc->subframe_prach,
max_preamble[0],
max_preamble_energy[0]/10,
max_preamble_energy[0]%10,
max_preamble_delay[0]);
pthread_mutex_lock(&eNB->UL_INFO_mutex);
eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 1;
eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = &eNB->preamble_list[0];
eNB->UL_INFO.rach_ind.rach_indication_body.tl.tag = NFAPI_RACH_INDICATION_BODY_TAG;
eNB->UL_INFO.rach_ind.header.message_id = NFAPI_RACH_INDICATION;
eNB->UL_INFO.rach_ind.sfn_sf = proc->frame_prach<<4 | proc->subframe_prach;
eNB->preamble_list[0].preamble_rel8.tl.tag = NFAPI_PREAMBLE_REL8_TAG;
eNB->preamble_list[0].preamble_rel8.timing_advance = max_preamble_delay[0];
eNB->preamble_list[0].preamble_rel8.preamble = max_preamble[0];
eNB->preamble_list[0].preamble_rel8.rnti = 1+proc->subframe_prach; // note: fid is implicitly 0 here
eNB->preamble_list[0].preamble_rel13.rach_resource_type = 0;
eNB->preamble_list[0].instance_length = 0; //don't know exactly what this is
if (NFAPI_MODE==NFAPI_MODE_PNF) { // If NFAPI PNF then we need to send the message to the VNF
LOG_D(PHY,"Filling NFAPI indication for RACH : SFN_SF:%d TA %d, Preamble %d, rnti %x, rach_resource_type %d\n",
NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf),
eNB->preamble_list[0].preamble_rel8.timing_advance,
eNB->preamble_list[0].preamble_rel8.preamble,
eNB->preamble_list[0].preamble_rel8.rnti,
eNB->preamble_list[0].preamble_rel13.rach_resource_type);
oai_nfapi_rach_ind(&eNB->UL_INFO.rach_ind);
eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles = 0;
}
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
} // max_preamble_energy > prach_I0 + 100
else {
eNB->measurements.prach_I0 = ((eNB->measurements.prach_I0*900)>>10) + ((avg_preamble_energy[0]*124)>>10);
if (eNB->prach_energy_counter < 100)
eNB->prach_energy_counter++;
}
} // else br_flag
void prach_eNB(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc, int frame,int subframe) {
// check if we have to detect PRACH first
if (is_prach_subframe(&eNB->frame_parms, frame,subframe)>0) {
prach_procedures_ocp(eNB, proc, 0);
prach_procedures_ocp(eNB, proc, 1);
}
}
static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) {
AssertFatal( eNB !=NULL, "");
if (NFAPI_MODE==NFAPI_MODE_PNF) {
// I am a PNF and I need to let nFAPI know that we have a (sub)frame tick
//add_subframe(&frame, &subframe, 4);
//oai_subframe_ind(proc->frame_tx, proc->subframe_tx);
oai_subframe_ind(proc->frame_rx, proc->subframe_rx);
}
AssertFatal( !(NFAPI_MODE==NFAPI_MODE_PNF &&
eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0), "");
prach_eNB(eNB,proc,proc->frame_rx,proc->subframe_rx);
release_UE_in_freeList(eNB->Mod_id);
// UE-specific RX processing for subframe n
if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
phy_procedures_eNB_uespec_RX(eNB, proc);
}
pthread_mutex_lock(&eNB->UL_INFO_mutex);
eNB->UL_INFO.frame = proc->frame_rx;
eNB->UL_INFO.subframe = proc->subframe_rx;
eNB->UL_INFO.module_id = eNB->Mod_id;
eNB->UL_INFO.CC_id = eNB->CC_id;
eNB->if_inst->UL_indication(&eNB->UL_INFO, proc);
pthread_mutex_unlock(&eNB->UL_INFO_mutex);
phy_procedures_eNB_TX(eNB, proc, 1);
return(0);
}
void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc) {
LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
void *rxp[ru->nb_rx];
unsigned int rxs;
int i;
openair0_timestamp ts=0, timestamp_rx;
static openair0_timestamp old_ts=0;
for (i=0; i<ru->nb_rx; i++)
//receive in the next slot
rxp[i] = (void *)&ru->common.rxdata[i][((proc->subframe_rx+1)%10)*fp->samples_per_tti];
rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
&ts,
rxp,
fp->samples_per_tti,
ru->nb_rx);
timestamp_rx = ts-ru->ts_offset;
// AssertFatal(rxs == fp->samples_per_tti,
// "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs);
if(rxs != fp->samples_per_tti) {
LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs);
#if defined(USRP_REC_PLAY)
exit_fun("Exiting IQ record/playback");
#else
//exit_fun( "problem receiving samples" );
LOG_E(PHY, "problem receiving samples");
#endif
}
if (old_ts != 0 && timestamp_rx - old_ts != fp->samples_per_tti) {
LOG_E(HW,"impossible shift in rx stream, rx: %ld, previous rx distance: %ld, should be %d\n", timestamp_rx, proc->timestamp_rx - old_ts, fp->samples_per_tti);
//ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti);
//proc->timestamp_rx = ts-ru->ts_offset;
}
old_ts=timestamp_rx;
setAllfromTS(timestamp_rx, proc);
}
void ocp_tx_rf(RU_t *ru, L1_rxtx_proc_t *proc) {
LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
void *txp[ru->nb_tx];
int i;
lte_subframe_t SF_type = subframe_select(fp,proc->subframe_tx%10);
lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10);
int sf_extension = 0;
if ((SF_type == SF_DL) ||
(SF_type == SF_S)) {
int siglen=fp->samples_per_tti;
radio_tx_burst_flag_t flags = TX_BURST_MIDDLE;
if (SF_type == SF_S) {
/* end_of_burst_delay is used to stop TX only "after a while".
* If we stop right after effective signal, with USRP B210 and
* B200mini, we observe a high EVM on the S subframe (on the
* PSS).
* A value of 400 (for 30.72MHz) solves this issue. This is
* the default.
*/
siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0)
+ (fp->dl_symbols_in_S_subframe - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples)
+ ru->end_of_burst_delay;
flags = TX_BURST_END;
}
if (fp->frame_type == TDD &&
SF_type == SF_DL &&
prevSF_type == SF_UL) {
flags = TX_BURST_START;
sf_extension = ru->sf_extension;
}
#if defined(__x86_64) || defined(__i386__)
sf_extension = (sf_extension)&0xfffffff8;
#elif defined(__arm__) || defined(__aarch64__)
sf_extension = (sf_extension)&0xfffffffc;
#endif
for (i=0; i<ru->nb_tx; i++)
txp[i] = (void *)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension];
/* add fail safe for late command end */
// prepare tx buffer pointers
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, subframe %d\n",ru->idx,
(long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->subframe_tx);
}
return;
}
static void *ru_thread( void *param ) {
setbuf(stdout, NULL);
setbuf(stderr, NULL);
RU_t *ru = (RU_t *)param;
L1_rxtx_proc_t L1proc= {0};
// We pick the global thread pool from the legacy code global vars
L1proc.threadPool=RC.eNB[0][0]->proc.L1_proc.threadPool;
L1proc.respEncode=RC.eNB[0][0]->proc.L1_proc.respEncode;
L1proc.respDecode=RC.eNB[0][0]->proc.L1_proc.respDecode;
if (ru->if_south == LOCAL_RF) { // configure RF parameters only
fill_rf_config(ru,ru->rf_config_file);
init_frame_parms(ru->frame_parms,1);
phy_init_RU(ru);
init_rf(ru);
}
AssertFatal(setup_RU_buffers(ru)==0, "Exiting, cannot initialize RU Buffers\n");
LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx);
wait_sync("ru_thread");
// Start RF device if any
if (ru->rfdevice.trx_start_func(&ru->rfdevice) != 0)
LOG_E(HW,"Could not start the RF device\n");
else
LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
// This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
while (!oai_exit) {
// synchronization on input FH interface, acquire signals/data and block
rx_rf(ru, &L1proc);
// do RX front-end processing (frequency-shift, dft) if needed
fep_full(ru, L1proc.subframe_rx);
// At this point, all information for subframe has been received on FH interface
// If this proc is to provide synchronization, do so
// Fixme: not used
// wakeup_slaves(proc);
for (int i=0; i<ru->num_eNB; i++) {
char string[20];
sprintf(string,"Incoming RU %d",ru->idx);
if (rxtx(ru->eNB_list[i],&L1proc,string) < 0)
LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",
ru->eNB_list[i]->Mod_id,ru->eNB_list[i]->CC_id);
}
// do TX front-end processing if needed (precoding and/or IDFTs)
feptx_prec(ru, L1proc.frame_tx, L1proc.subframe_tx);
// do OFDM if needed
feptx_ofdm(ru, L1proc.frame_tx, L1proc.subframe_tx);
// do outgoing fronthaul (south) if needed
ocp_tx_rf(ru, &L1proc);
}
LOG_W(PHY,"Exiting ru_thread \n");
ru->rfdevice.trx_end_func(&ru->rfdevice);
LOG_I(PHY,"RU %d rf device stopped\n",ru->idx);
return NULL;
}
int init_rf(RU_t *ru) {
char name[256];
pthread_getname_np(pthread_self(),name, 255);
pthread_setname_np(pthread_self(),"UHD for OAI");
int ret=openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
pthread_setname_np(pthread_self(),name);
return ret;
}
void ocp_init_RU(RU_t *ru, char *rf_config_file, int send_dmrssync) {
PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL;
int i;
int CC_id;
// read in configuration file)
LOG_I(PHY,"configuring RU from file\n");
LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",
RC.nb_L1_inst,RC.nb_RU,get_nprocs());
if (RC.nb_CC != 0)
for (i=0; i<RC.nb_L1_inst; i++)
for (CC_id=0; CC_id<RC.nb_CC[i]; CC_id++)
RC.eNB[i][CC_id]->num_RU=0;
LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU);
ru->rf_config_file = rf_config_file;
ru->idx = 0;
ru->ts_offset = 0;
if (ru->is_slave == 1) {
ru->in_synch = 0;
ru->generate_dmrs_sync = 0;
} else {
ru->in_synch = 1;
ru->generate_dmrs_sync=send_dmrssync;
}
ru->cmd = EMPTY;
ru->south_out_cnt= 0;
// ru->generate_dmrs_sync = (ru->is_slave == 0) ? 1 : 0;
if (ru->generate_dmrs_sync == 1) {
generate_ul_ref_sigs();
ru->dmrssync = (int16_t *)malloc16_clear(ru->frame_parms->ofdm_symbol_size*2*sizeof(int16_t));
}
ru->wakeup_L1_sleeptime = 2000;
ru->wakeup_L1_sleep_cnt_max = 3;
if (ru->num_eNB > 0) {
AssertFatal(ru->eNB_list[0], "ru->eNB_list is not initialized\n");
} else {
LOG_E(PHY,"Wrong data model, assigning eNB 0, carrier 0 to RU 0\n");
ru->eNB_list[0] = RC.eNB[0][0];
ru->num_eNB=1;
}
eNB0 = ru->eNB_list[0];
// datamodel error in regular OAI: a RU uses one single eNB carrier parameters!
ru->frame_parms = &eNB0->frame_parms;
for (i=0; i<ru->num_eNB; i++) {
eNB0 = ru->eNB_list[i];
int ruIndex=eNB0->num_RU++;
eNB0->RU_list[ruIndex] = ru;
}
}
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(RC.ru[inst]);
}
}
/* --------------------------------------------------------*/
/* from here function to use configuration module */
static int DEFBFW[] = {0x00007fff};
void ocpRCconfig_RU(RU_t *ru) {
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 ) {
LOG_W(PHY, "Calling RCconfig_RU while no ru\n");
RC.nb_RU = 0;
return;
} // setting != NULL
ru->idx = 0;
ru->if_timing = synch_to_ext_device;
paramdef_t *vals=RUParamList.paramarray[0];
if (RC.nb_L1_inst >0)
ru->num_eNB = vals[RU_ENB_LIST_IDX].numelt;
else
ru->num_eNB = 0;
for (int i=0; i<ru->num_eNB; i++)
ru->eNB_list[i] = RC.eNB[vals[RU_ENB_LIST_IDX].iptr[i]][0];
if (config_isparamset(vals, RU_SDR_ADDRS)) {
ru->openair0_cfg.sdr_addrs = strdup(*(vals[RU_SDR_ADDRS].strptr));
}
if (config_isparamset(vals, RU_SDR_CLK_SRC)) {
char *paramVal=*(vals[RU_SDR_CLK_SRC].strptr);
LOG_D(PHY, "RU clock source set as %s\n", paramVal);
if (strcmp(paramVal, "internal") == 0) {
ru->openair0_cfg.clock_source = internal;
} else if (strcmp(paramVal, "external") == 0) {
ru->openair0_cfg.clock_source = external;
} else if (strcmp(paramVal, "gpsdo") == 0) {
ru->openair0_cfg.clock_source = gpsdo;
} else {
LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", paramVal);
}
}
if (strcmp(*(vals[RU_LOCAL_RF_IDX].strptr), "yes") == 0) {
if ( !(config_isparamset(vals,RU_LOCAL_IF_NAME_IDX)) ) {
ru->if_south = LOCAL_RF;
ru->function = eNodeB_3GPP;
} else {
ru->eth_params.local_if_name = strdup(*(vals[RU_LOCAL_IF_NAME_IDX].strptr));
ru->eth_params.my_addr = strdup(*(vals[RU_LOCAL_ADDRESS_IDX].strptr));
ru->eth_params.remote_addr = strdup(*(vals[RU_REMOTE_ADDRESS_IDX].strptr));
ru->eth_params.my_portc = *(vals[RU_LOCAL_PORTC_IDX].uptr);
ru->eth_params.remote_portc = *(vals[RU_REMOTE_PORTC_IDX].uptr);
ru->eth_params.my_portd = *(vals[RU_LOCAL_PORTD_IDX].uptr);
ru->eth_params.remote_portd = *(vals[RU_REMOTE_PORTD_IDX].uptr);
}
ru->max_pdschReferenceSignalPower = *(vals[RU_MAX_RS_EPRE_IDX].uptr);;
ru->max_rxgain = *(vals[RU_MAX_RXGAIN_IDX].uptr);
ru->num_bands = vals[RU_BAND_LIST_IDX].numelt;
/* sf_extension is in unit of samples for 30.72MHz here, has to be scaled later */
ru->sf_extension = *(vals[RU_SF_EXTENSION_IDX].uptr);
ru->end_of_burst_delay = *(vals[RU_END_OF_BURST_DELAY_IDX].uptr);
for (int i=0; i<ru->num_bands; i++)
ru->band[i] = vals[RU_BAND_LIST_IDX].iptr[i];
} else {
ru->eth_params.local_if_name = strdup(*(vals[RU_LOCAL_IF_NAME_IDX].strptr));
ru->eth_params.my_addr = strdup(*(vals[RU_LOCAL_ADDRESS_IDX].strptr));
ru->eth_params.remote_addr = strdup(*(vals[RU_REMOTE_ADDRESS_IDX].strptr));
ru->eth_params.my_portc = *(vals[RU_LOCAL_PORTC_IDX].uptr);
ru->eth_params.remote_portc = *(vals[RU_REMOTE_PORTC_IDX].uptr);
ru->eth_params.my_portd = *(vals[RU_LOCAL_PORTD_IDX].uptr);
ru->eth_params.remote_portd = *(vals[RU_REMOTE_PORTD_IDX].uptr);
} /* strcmp(local_rf, "yes") != 0 */
ru->nb_tx = *(vals[RU_NB_TX_IDX].uptr);
ru->nb_rx = *(vals[RU_NB_RX_IDX].uptr);
ru->att_tx = *(vals[RU_ATT_TX_IDX].uptr);
ru->att_rx = *(vals[RU_ATT_RX_IDX].uptr);
return;
}
static void get_options(void) {
CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
get_common_options(SOFTMODEM_ENB_BIT);
CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP);
if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) {
memset((void *)&RC,0,sizeof(RC));
/* Read RC configuration file */
RCConfig();
NB_eNB_INST = RC.nb_inst;
printf("Configuration: nb_rrc_inst %d, nb_L1_inst %d, nb_ru %d\n",NB_eNB_INST,RC.nb_L1_inst,RC.nb_RU);
if (!IS_SOFTMODEM_NONBIOT) {
load_NB_IoT();
printf(" nb_nbiot_rrc_inst %d, nb_nbiot_L1_inst %d, nb_nbiot_macrlc_inst %d\n",
RC.nb_nb_iot_rrc_inst, RC.nb_nb_iot_L1_inst, RC.nb_nb_iot_macrlc_inst);
} else {
printf("All Nb-IoT instances disabled\n");
RC.nb_nb_iot_rrc_inst=RC.nb_nb_iot_L1_inst=RC.nb_nb_iot_macrlc_inst=0;
}
}
}
void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
int CC_id;
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
frame_parms[CC_id] = (LTE_DL_FRAME_PARMS *) malloc(sizeof(LTE_DL_FRAME_PARMS));
/* 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_pdcp(void) {
pdcp_layer_init();
uint32_t pdcp_initmask = (IS_SOFTMODEM_NOS1) ?
(PDCP_USE_NETLINK_BIT | LINK_ENB_PDCP_TO_IP_DRIVER_BIT) : LINK_ENB_PDCP_TO_GTPV1U_BIT;
if (IS_SOFTMODEM_NOS1)
pdcp_initmask = pdcp_initmask | ENB_NAS_USE_TUN_BIT | SOFTMODEM_NOKRNMOD_BIT ;
pdcp_initmask = pdcp_initmask | ENB_NAS_USE_TUN_W_MBMS_BIT;
if ( split73!=SPLIT73_DU)
pdcp_module_init(pdcp_initmask, 0);
pdcp_set_rlc_data_req_func(rlc_data_req);
pdcp_set_pdcp_data_ind_func(pdcp_data_ind);
}
}
static void wait_nfapi_init(char *thread_name) {
LOG_I(ENB_APP, "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);
LOG_I(ENB_APP, "NFAPI: got sync (%s)\n", thread_name);
}
void terminate_task(module_id_t mod_id, task_id_t from, task_id_t to) {
LOG_I(ENB_APP, "sending TERMINATE_MESSAGE from task %s (%d) to task %s (%d)\n",
itti_get_task_name(from), from, itti_get_task_name(to), to);
MessageDef *msg;
msg = itti_alloc_new_message (from, 0, TERMINATE_MESSAGE);
itti_send_msg_to_task (to, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg);
}
int main ( int argc, char **argv ) {
//mtrace();
int i;
int CC_id = 0;
sf_ahead=4; // Bell Labs
AssertFatal(load_configmodule(argc,argv,0), "[SOFTMODEM] Error, configuration module init failed\n");
logInit();
printf("Reading in command-line options\n");
get_options ();
AssertFatal(!CONFIG_ISFLAGSET(CONFIG_ABORT),"Getting configuration failed\n");
EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1;
#if T_TRACER
T_Config_Init();
#endif
set_latency_target();
set_softmodem_sighandler();
cpuf=get_cpu_freq_GHz();
set_taus_seed (0);
if (opp_enabled ==1)
reset_opp_meas();
itti_init(TASK_MAX, tasks_info);
init_opt();
#ifndef PACKAGE_VERSION
# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL"
#endif
LOG_I(HW, "Version: %s\n", PACKAGE_VERSION);
/* Read configuration */
if (RC.nb_inst > 0) {
// Allocate memory from RC variable
read_config_and_init();
} else {
printf("RC.nb_inst = 0, Initializing L1\n");
RCconfig_L1();
}
// RU thread and some L1 procedure aren't necessary in VNF or L2 FAPI simulator.
// but RU thread deals with pre_scd and this is necessary in VNF and simulator.
// some initialization is necessary and init_ru_vnf do this.
RU_t ru;
if ( NFAPI_MODE != NFAPI_MODE_VNF) {
ocpRCconfig_RU(&ru);
LOG_I(PHY,
"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",
RC.nb_L1_inst, RC.nb_RU, get_nprocs());
}
if ( strlen(get_softmodem_params()->split73) > 0 ) {
char tmp[1024]= {0};
strncpy(tmp,get_softmodem_params()->split73, 1023);
tmp[2]=0;
if ( strncasecmp(tmp,"cu", 2)==0 )
split73=SPLIT73_CU;
else if ( strncasecmp(tmp,"du", 2)==0 )
split73=SPLIT73_DU;
else
AssertFatal(false,"split73 syntax: <cu|du>:<remote ip addr>[:<ip port>] (string found: %s) \n",get_softmodem_params()->split73);
}
if (RC.nb_inst > 0) {
/* Start the agent. If it is turned off in the configuration, it won't start */
/* initializes PDCP and sets correct RLC Request/PDCP Indication callbacks */
init_pdcp();
AssertFatal(create_tasks(1)==0,"cannot create ITTI tasks\n");
for (int enb_id = 0; enb_id < RC.nb_inst; enb_id++) {
MessageDef *msg_p = itti_alloc_new_message (TASK_ENB_APP, 0, RRC_CONFIGURATION_REQ);
RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration;
itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
}
}
if (RC.nb_inst > 0) {
protocol_ctxt_t ctxt;
ctxt.module_id = 0 ;
ctxt.instance = 0;
ctxt.rnti = 0;
ctxt.enb_flag = 1;
ctxt.frame = 0;
ctxt.subframe = 0;
pdcp_run(&ctxt);
}
/* start threads if only L1 or not a CU */
if (RC.nb_inst == 0 || NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MODE_VNF) {
// 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)*MAX_MOBILES_PER_ENB*MAX_NUM_CCs);
pthread_cond_init(&sync_cond,NULL);
pthread_mutex_init(&sync_mutex, NULL);
if (NFAPI_MODE!=NFAPI_MONOLITHIC) {
LOG_I(ENB_APP,"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);
}
if (NFAPI_MODE==NFAPI_MODE_VNF) {// VNF
#if defined(PRE_SCD_THREAD)
init_ru_vnf(); // ru pointer is necessary for pre_scd.
#endif
wait_nfapi_init("main?");
}
LOG_I(ENB_APP,"START MAIN THREADS\n");
// start the main threads
number_of_cards = 1;
printf("RC.nb_L1_inst:%d\n", RC.nb_L1_inst);
if (RC.nb_L1_inst > 0) {
printf("Initializing eNB threads single_thread_flag:%d wait_for_sync:%d\n",
get_softmodem_params()->single_thread_flag,
get_softmodem_params()->wait_for_sync);
init_eNB(get_softmodem_params()->single_thread_flag,
get_softmodem_params()->wait_for_sync);
}
for (int x=0; x < RC.nb_L1_inst; x++)
for (int CC_id=0; CC_id<RC.nb_L1_CC[x]; CC_id++) {
L1_rxtx_proc_t *L1proc= &RC.eNB[x][CC_id]->proc.L1_proc;
L1proc->threadPool=(tpool_t *)malloc(sizeof(tpool_t));
L1proc->respEncode=(notifiedFIFO_t *) malloc(sizeof(notifiedFIFO_t));
L1proc->respDecode=(notifiedFIFO_t *) malloc(sizeof(notifiedFIFO_t));
initTpool(get_softmodem_params()->threadPoolConfig, L1proc->threadPool,cpumeas(CPUMEAS_GETSTATE));
initNotifiedFIFO(L1proc->respEncode);
initNotifiedFIFO(L1proc->respDecode);
}
}
printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU);
if (RC.nb_RU >0 && NFAPI_MODE!=NFAPI_MODE_VNF) {
printf("Initializing RU threads\n");
ocp_init_RU(&ru,
get_softmodem_params()->rf_config_file,
get_softmodem_params()->send_dmrs_sync);
ru.rf_map.card=0;
ru.rf_map.chain=CC_id+(get_softmodem_params()->chain_offset);
init_RU_proc(&ru);
config_sync_var=0;
if (NFAPI_MODE==NFAPI_MODE_PNF) { // PNF
wait_nfapi_init("main?");
}
LOG_I(ENB_APP,"RC.nb_RU:%d\n", RC.nb_RU);
// once all RUs are ready intiailize the rest of the eNBs ((dependence on final RU parameters after configuration)
printf("ALL RUs ready - init eNBs\n");
sleep(1);
if (NFAPI_MODE!=NFAPI_MODE_PNF && NFAPI_MODE!=NFAPI_MODE_VNF) {
LOG_I(ENB_APP,"Not NFAPI mode - call init_eNB_afterRU()\n");
init_eNB_afterRU();
} else {
LOG_I(ENB_APP,"NFAPI mode - DO NOT call init_eNB_afterRU()\n");
}
LOG_UI(ENB_APP,"ALL RUs ready - ALL eNBs ready\n");
// connect the TX/RX buffers
sleep(1); /* wait for thread activation */
LOG_I(ENB_APP,"Sending sync to all threads\n");
pthread_mutex_lock(&sync_mutex);
sync_var=0;
pthread_cond_broadcast(&sync_cond);
pthread_mutex_unlock(&sync_mutex);
config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS);
}
create_tasks_mbms(1);
// wait for end of program
LOG_UI(ENB_APP,"TYPE <CTRL-C> TO TERMINATE\n");
// CI -- Flushing the std outputs for the previous marker to show on the eNB / DU / CU log file
fflush(stdout);
fflush(stderr);
// end of CI modifications
//getchar();
if(IS_SOFTMODEM_DOSCOPE)
load_softscope("enb", NULL);
itti_wait_tasks_end();
oai_exit=1;
LOG_I(ENB_APP,"oai_exit=%d\n",oai_exit);
// stop threads
if (RC.nb_inst == 0) {
if(IS_SOFTMODEM_DOSCOPE)
end_forms();
LOG_I(ENB_APP,"stopping MODEM threads\n");
stop_eNB(NB_eNB_INST);
stop_RU(RC.nb_RU);
/* release memory used by the RU/eNB threads (incomplete), after all
* threads have been stopped (they partially use the same memory) */
for (int inst = 0; inst < NB_eNB_INST; inst++) {
for (int cc_id = 0; cc_id < RC.nb_CC[inst]; cc_id++) {
free_transport(RC.eNB[inst][cc_id]);
phy_free_lte_eNB(RC.eNB[inst][cc_id]);
}
}
free_lte_top();
end_configmodule();
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);
}
terminate_opt();
logClean();
printf("Bye.\n");
return 0;
}
......@@ -56,7 +56,6 @@
#include "openair2/ENB_APP/enb_paramdef.h"
#include "system.h"
#include <executables/split_headers.h>
#include <executables/softmodem-common.h>
#include <executables/thread-common.h>
......
......@@ -153,19 +153,8 @@ int otg_enabled;
uint32_t timing_advance = 0;
uint64_t num_missed_slots=0; // counter for the number of missed slots
#include <executables/split_headers.h>
#include <SIMULATION/ETH_TRANSPORT/proto.h>
int split73=0;
void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) {
AssertFatal(false, "Must not be called in this context\n");
}
void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask,
uint16_t rnti, int32_t stat) {
AssertFatal(false, "Must not be called in this context\n");
}
extern void reset_opp_meas(void);
extern void print_opp_meas(void);
......
......@@ -108,7 +108,6 @@ extern "C"
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*-----------------------------------------------------------------------------------------------------------------------------------------------------*/
#define RF_CONFIG_FILE softmodem_params.rf_config_file
#define SPLIT73 softmodem_params.split73
#define TP_CONFIG softmodem_params.threadPoolConfig
#define PHY_TEST softmodem_params.phy_test
#define DO_RA softmodem_params.do_ra
......@@ -138,7 +137,6 @@ extern "C"
extern int usrp_tx_thread;
#define CMDLINE_PARAMS_DESC { \
{"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:&RF_CONFIG_FILE, defstrval:NULL, TYPE_STRING, 0},\
{"split73", CONFIG_HLP_SPLIT73, 0, strptr:&SPLIT73, defstrval:NULL, TYPE_STRING, 0}, \
{"thread-pool", CONFIG_HLP_TPOOL, 0, strptr:&TP_CONFIG, defstrval:"-1,-1,-1,-1,-1,-1,-1,-1", TYPE_STRING, 0}, \
{"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&PHY_TEST, defintval:0, TYPE_INT, 0}, \
{"do-ra", CONFIG_HLP_DORA, PARAMFLAG_BOOL, iptr:&DO_RA, defintval:0, TYPE_INT, 0}, \
......@@ -210,7 +208,6 @@ extern int usrp_tx_thread;
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s3a = { config_checkstr_assign_integer, \
{"MONOLITHIC", "PNF", "VNF","UE_STUB_PNF","UE_STUB_OFFNET","STANDALONE_PNF"}, \
{NFAPI_MONOLITHIC, NFAPI_MODE_PNF, NFAPI_MODE_VNF,NFAPI_UE_STUB_PNF,NFAPI_UE_STUB_OFFNET,NFAPI_MODE_STANDALONE_PNF}, \
......@@ -292,7 +289,6 @@ typedef struct {
uint64_t optmask;
//THREAD_STRUCT thread_struct;
char *rf_config_file;
char *split73;
char *threadPoolConfig;
int phy_test;
int do_ra;
......
/*
* 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
*
* Author and copyright: Laurent Thomas, open-cells.com
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef __SPLIT_HEADERS_H
#define __SPLIT_HEADERS_H
#include <stdint.h>
#include <stdbool.h>
#include <openair1/PHY/defs_eNB.h>
#include <common/utils/telnetsrv/telnetsrv_proccmd.h>
#define CU_PORT "7878"
#define DU_PORT "8787"
#define SPLIT73_CU 1
#define SPLIT73_DU 2
extern int split73;
#define MTU 65536
#define UDP_TIMEOUT 900000L // in micro second (struct timeval, NOT struct timespec)
// linux may timeout for a much longer time (up to 10ms)
#define blockAlign 32 //bytes to align memory for SIMD copy (256 bits vectors)
// FS6 transport configuration and handler
typedef struct {
char *sourceIP;
char *sourcePort;
char *destIP;
char *destPort;
struct addrinfo *destAddr;
int sockHandler;
} UDPsock_t;
#define CTsentCUv0 0xA500
#define CTsentDUv0 0x5A00
// Main FS6 transport layer header
// All packets starts with this header
typedef struct commonUDP_s {
uint64_t timestamp; // id of the group (subframe for LTE)
uint16_t nbBlocks; // total number of blocks for this timestamp
uint16_t blockID; // id: 0..nbBocks-1
uint16_t contentType; // defines the content format
uint16_t contentBytes; // will be sent in a UDP packet, so must be < 2^16 bytes
uint64_t senderClock;
} commonUDP_t;
// FS6 UL common header (DU to CU)
// gives the RACH detection data and is always sent to inform the CU that a subframe arrived
typedef struct {
uint16_t max_preamble[4];
uint16_t max_preamble_energy[4];
uint16_t max_preamble_delay[4];
uint16_t avg_preamble_energy[4];
} fs6_ul_t;
// FS6 DL common header (CU to DU)
// gives the DCI configuration from each subframe
typedef struct {
uint8_t pbch_pdu[4];
int num_pdcch_symbols;
int num_dci;
DCI_ALLOC_t dci_alloc[8];
int num_mdci;
int amp;
LTE_eNB_PHICH phich_vars;
uint64_t DuClock;
uint64_t CuSpentMicroSec;
} fs6_dl_t;
// a value to type all sub packets,
// to detect errors, and to be able to extend to other versions
// the first byte of each sub structure should match one of these values
enum pckType {
fs6UlConfig=25,
fs6DlConfig=26,
fs6ULConfigCCH=27,
fs6ULsch=28,
fs6ULcch=29,
fs6ULindicationHarq=40,
fs6ULindicationSr=41,
};
// CU to DU definition of a future UL subframe decode
// defines a UE future data plane
typedef struct {
enum pckType type:8;
uint16_t UE_id;
int8_t harq_pid;
UE_type_t ue_type;
uint8_t dci_alloc;
uint8_t rar_alloc;
SCH_status_t status;
uint8_t Msg3_flag;
uint8_t subframe;
uint32_t frame;
uint8_t handled;
uint8_t phich_active;
uint8_t phich_ACK;
uint16_t previous_first_rb;
uint32_t B;
uint32_t G;
UCI_format_t uci_format;
uint8_t Or2;
uint8_t o_RI[2];
uint8_t o_ACK[4];
uint8_t O_ACK;
uint8_t o_RCC;
int16_t q_ACK[MAX_ACK_PAYLOAD];
int16_t q_RI[MAX_RI_PAYLOAD];
uint32_t RTC[MAX_NUM_ULSCH_SEGMENTS];
uint8_t ndi;
uint8_t round;
uint8_t rvidx;
uint8_t Nl;
uint8_t n_DMRS;
uint8_t previous_n_DMRS;
uint8_t n_DMRS2;
int32_t delta_TF;
uint32_t repetition_number ;
uint32_t total_number_of_repetitions;
uint16_t harq_mask;
uint16_t nb_rb;
uint8_t Qm;
uint16_t first_rb;
uint8_t O_RI;
uint8_t Or1;
uint16_t Msc_initial;
uint8_t Nsymb_initial;
uint8_t V_UL_DAI;
uint8_t srs_active;
uint32_t TBS;
uint8_t Nsymb_pusch;
uint8_t Mlimit;
uint8_t max_turbo_iterations;
uint8_t bundling;
uint16_t beta_offset_cqi_times8;
uint16_t beta_offset_ri_times8;
uint16_t beta_offset_harqack_times8;
uint8_t Msg3_active;
uint16_t rnti;
uint8_t cyclicShift;
uint8_t cooperation_flag;
uint8_t num_active_cba_groups;
uint16_t cba_rnti[4];//NUM_MAX_CBA_GROUP];
} fs6_dl_ulsched_t;
// CU to DU defintion of a DL packet for a given UE
// The data itself is padded at the end of this structure
typedef struct {
enum pckType type:8;
int UE_id;
int8_t harq_pid;
uint16_t rnti;
int16_t sqrt_rho_a;
int16_t sqrt_rho_b;
CEmode_t CEmode:8;
uint16_t nb_rb;
uint8_t Qm;
int8_t Nl;
uint8_t pdsch_start;
uint8_t sib1_br_flag;
uint16_t i0;
uint32_t rb_alloc[4];
int dataLen;
} fs6_dl_uespec_t;
// CU to DU definition of CCH channel
typedef struct {
int16_t UE_id;
LTE_eNB_UCI cch_vars;
} fs6_dl_uespec_ulcch_element_t;
// header to group all UE CCH channels definitions in one UDP packet
typedef struct {
enum pckType type:8;
int16_t nb_active_ue;
} fs6_dl_uespec_ulcch_t;
// code internal, not transmitted as this
typedef struct {
int ta;
} ul_propagation_t;
// One UE UL data, data plane, UE data appended after the header
typedef struct {
enum pckType type:8;
short UE_id;
uint8_t harq_id;
uint8_t segment;
int segLen;
int r_offset;
int G;
int ulsch_power[2];
uint8_t o_ACK[4];
uint8_t O_ACK;
int ta;
uint8_t o[MAX_CQI_BYTES];
uint8_t cqi_crc_status;
} fs6_ul_uespec_t;
// UL UCI (control plane), per UE
typedef struct {
enum pckType type:8;
int UEid;
int frame;
int subframe;
LTE_eNB_UCI uci;
uint8_t harq_ack[4];
uint8_t tdd_mapping_mode;
uint16_t tdd_multiplexing_mask;
unsigned short n0_subband_power_dB;
uint16_t rnti;
int32_t stat;
} fs6_ul_uespec_uci_element_t;
// all segments UCI grouped in one UDP packet
typedef struct {
enum pckType type:8;
int16_t nb_active_ue;
} fs6_ul_uespec_uci_t;
bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result);
int receiveSubFrame(UDPsock_t *sock, void *bufferZone, int bufferSize, uint16_t contentType);
int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType);
#define initBufferZone(xBuf) \
uint8_t xBuf[FS6_BUF_SIZE]; \
((commonUDP_t *)xBuf)->nbBlocks=0;
#define hUDP(xBuf) ((commonUDP_t *)xBuf)
#define hDL(xBuf) ((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))
#define hUL(xBuf) ((fs6_ul_t*)(((commonUDP_t *)xBuf)+1))
#define hDLUE(xBuf) ((fs6_dl_uespec_t*) (((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))+1))
#define hTxULUE(xBuf) ((fs6_dl_ulsched_t*) (((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))+1))
#define hTxULcch(xBuf) ((fs6_dl_uespec_ulcch_t*) (((fs6_dl_t*)(((commonUDP_t *)xBuf)+1))+1))
#define hULUE(xBuf) ((fs6_ul_uespec_t*) (((fs6_ul_t*)(((commonUDP_t *)xBuf)+1))+1))
#define hULUEuci(xBuf) ((fs6_ul_uespec_uci_t*) (((fs6_ul_t*)(((commonUDP_t *)xBuf)+1))+1))
static inline size_t alignedSize(uint8_t *ptr) {
commonUDP_t *header=(commonUDP_t *) ptr;
return ((header->contentBytes+sizeof(commonUDP_t)+blockAlign-1)/blockAlign)*blockAlign;
}
static inline void *commonUDPdata(uint8_t *ptr) {
return (void *) (((commonUDP_t *)ptr)+1);
}
void setAllfromTS(uint64_t TS, L1_rxtx_proc_t *proc);
void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB,LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask,
uint16_t rnti, int32_t stat);
void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset);
void *cu_fs6(void *arg);
void *du_fs6(void *arg);
void fill_rf_config(RU_t *ru, char *rf_config_file);
int init_rf(RU_t *ru);
void rx_rf(RU_t *ru, L1_rxtx_proc_t *proc);
void tx_rf(RU_t *ru, L1_rxtx_proc_t *proc);
void common_signal_procedures (PHY_VARS_eNB *eNB,int frame, int subframe);
void pmch_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, int fembms_flag);
bool dlsch_procedures(PHY_VARS_eNB *eNB,
L1_rxtx_proc_t *proc,
int harq_pid,
LTE_eNB_DLSCH_t *dlsch,
LTE_eNB_UE_stats *ue_stats) ;
void postDecode(L1_rxtx_proc_t *proc, notifiedFIFO_elt_t *req);
void pdsch_procedures(PHY_VARS_eNB *eNB,
L1_rxtx_proc_t *proc,
int harq_pid,
LTE_eNB_DLSCH_t *dlsch,
LTE_eNB_DLSCH_t *dlsch1);
void srs_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc);
void uci_procedures(PHY_VARS_eNB *eNB,
L1_rxtx_proc_t *proc);
void ocp_rx_prach(PHY_VARS_eNB *eNB,
L1_rxtx_proc_t *proc,
RU_t *ru,
uint16_t *max_preamble,
uint16_t *max_preamble_energy,
uint16_t *max_preamble_delay,
uint16_t *avg_preamble_energy,
uint16_t Nf,
uint8_t tdd_mapindex,
uint8_t br_flag);
void rx_prach0(PHY_VARS_eNB *eNB,
RU_t *ru,
int frame_prach,
int subframe,
uint16_t *max_preamble,
uint16_t *max_preamble_energy,
uint16_t *max_preamble_delay,
uint16_t *avg_preamble_energy,
uint16_t Nf,
uint8_t tdd_mapindex,
uint8_t br_flag,
uint8_t ce_level
);
void ocp_tx_rf(RU_t *ru, L1_rxtx_proc_t *proc);
// mistakes in main OAI
void phy_init_RU(RU_t *);
void fep_full(RU_t *ru, int subframe);
void feptx_prec(RU_t *ru,int frame,int subframe);
void feptx_ofdm(RU_t *ru, int frame, int subframe);
void oai_subframe_ind(uint16_t sfn, uint16_t sf);
void softmodem_printresources(int sig, telnet_printfunc_t pf);
extern uint16_t sf_ahead;
#endif
/*
* 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
*
* Author and copyright: Laurent Thomas, open-cells.com
*
* 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/split_headers.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <netdb.h>
#include "executables/lte-softmodem.h"
bool createUDPsock (char *sourceIP, char *sourcePort, char *destIP, char *destPort, UDPsock_t *result) {
struct addrinfo hints= {0}, *servinfo, *p;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
int status;
if ((status = getaddrinfo(sourceIP, sourcePort, &hints, &servinfo)) != 0) {
LOG_E(GTPU,"getaddrinfo error: %s\n", gai_strerror(status));
return false;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((result->sockHandler = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
LOG_W(GTPU,"socket: %s\n", strerror(errno));
continue;
}
if (bind(result->sockHandler, p->ai_addr, p->ai_addrlen) == -1) {
close(result->sockHandler);
LOG_W(GTPU,"bind: %s\n", strerror(errno));
continue;
}
break; // if we get here, we must have connected successfully
}
if (p == NULL) {
// looped off the end of the list with no successful bind
LOG_E(GTPU,"failed to bind socket: %s %s \n",sourceIP,sourcePort);
return false;
}
freeaddrinfo(servinfo); // all done with this structure
if ((status = getaddrinfo(destIP, destPort, &hints, &servinfo)) != 0) {
LOG_E(GTPU,"getaddrinfo error: %s\n", gai_strerror(status));
return false;
}
if (servinfo) {
result->destAddr=servinfo;
} else {
LOG_E(PHY,"No valid UDP addr: %s:%s\n",destIP, destPort);
return false;
}
int enable=1;
AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable))==0,"");
struct timeval tv= {0,UDP_TIMEOUT};
if (IS_SOFTMODEM_RFSIM)
tv.tv_sec=2; //debug: wait 2 seconds for human understanding
AssertFatal(setsockopt(result->sockHandler, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) ==0,"");
// Make a send/recv buffer larger than a a couple of subframe
// so the kernel will store for us in and out paquets
int buff=1000*1000*10;
AssertFatal ( setsockopt(result->sockHandler, SOL_SOCKET, SO_SNDBUF, &buff, sizeof(buff)) == 0, "");
AssertFatal ( setsockopt(result->sockHandler, SOL_SOCKET, SO_RCVBUF, &buff, sizeof(buff)) == 0, "");
return true;
}
// sock: udp socket
// bufferZone: a reception area of bufferSize
int receiveSubFrame(UDPsock_t *sock, void *bufferZone, int bufferSize, uint16_t contentType) {
int rcved=0;
commonUDP_t *bufOrigin=(commonUDP_t *)bufferZone;
static uint8_t crossData[65536];
static int crossDataSize=0;
if (crossDataSize) {
LOG_D(HW,"copy a block received in previous subframe\n");
memcpy(bufferZone, crossData, crossDataSize);
rcved=1;
bufferZone+=crossDataSize;
crossDataSize=0;
}
do {
//read all subframe data from the control unit
int ret=recv(sock->sockHandler, bufferZone, bufferSize, 0);
if ( ret==-1) {
if ( errno == EWOULDBLOCK || errno== EINTR ) {
LOG_I(HW,"Received: Timeout, subframe incomplete\n");
return rcved;
} else {
LOG_E(HW,"Critical issue in socket: %s\n", strerror(errno));
return -1;
}
} else {
if (hUDP(bufferZone)->contentType != contentType)
abort();
if (rcved && bufOrigin->timestamp != hUDP(bufferZone)->timestamp ) {
if ( hUDP(bufferZone)->timestamp > bufOrigin->timestamp ) {
LOG_W(HW,"Received data for TS: %lu before end of TS : %lu completion\n",
hUDP(bufferZone)->timestamp,
bufOrigin->timestamp);
memcpy(crossData, bufferZone, ret );
crossDataSize=ret;
return rcved;
} else {
LOG_W(HW,"Dropping late packet\n");
continue;
}
}
rcved++;
bufferZone+=ret;
}
LOG_D(HW,"Received: blocks: %d/%d, size %d, TS: %lu\n",
rcved, bufOrigin->nbBlocks, ret, bufOrigin->timestamp);
} while ( rcved == 0 || rcved < bufOrigin->nbBlocks );
return rcved;
}
int sendSubFrame(UDPsock_t *sock, void *bufferZone, ssize_t secondHeaderSize, uint16_t contentType) {
commonUDP_t *UDPheader=(commonUDP_t *)bufferZone ;
UDPheader->contentType=contentType;
UDPheader->senderClock=rdtsc_oai();
int nbBlocks=UDPheader->nbBlocks;
int blockId=0;
if (nbBlocks <= 0 ) {
LOG_E(PHY,"FS6: can't send blocks: %d\n", nbBlocks);
return 0;
}
do {
if (blockId > 0 ) {
commonUDP_t *currentHeader=(commonUDP_t *)bufferZone;
currentHeader->timestamp=UDPheader->timestamp;
currentHeader->nbBlocks=UDPheader->nbBlocks;
currentHeader->blockID=blockId;
currentHeader->contentType=UDPheader->contentType;
memcpy(commonUDPdata((void *)currentHeader), commonUDPdata(bufferZone), secondHeaderSize);
}
blockId++;
int sz=alignedSize(bufferZone);
// Let's use the first address returned by getaddrinfo()
int ret=sendto(sock->sockHandler, bufferZone, sz, 0,
sock->destAddr->ai_addr, sock->destAddr->ai_addrlen);
if ( ret != sz )
LOG_W(HW,"Wrote socket doesn't return size %d (val: %d, errno:%d, %s)\n",
sz, ret, errno, strerror(errno));
LOG_D(HW,"Sent: TS: %lu, blocks %d/%d, block size : %d \n",
UDPheader->timestamp, UDPheader->nbBlocks-nbBlocks, UDPheader->nbBlocks, sz);
bufferZone+=sz;
nbBlocks--;
} while (nbBlocks);
return 0;
}
......@@ -39,7 +39,6 @@
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "prach_extern.h"
#include <openair1/PHY/LTE_TRANSPORT/transport_proto.h>
#include <executables/split_headers.h>
#include "common/utils/lte/prach_utils.h"
void rx_prach0(PHY_VARS_eNB *eNB,
......
......@@ -41,7 +41,6 @@
#include "RRC/LTE/rrc_extern.h"
#include "PHY_INTERFACE/phy_interface.h"
#include "transport_proto.h"
#include <executables/split_headers.h>
extern int oai_exit;
......@@ -321,12 +320,6 @@ int ulsch_decoding_data(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc,
else
E = ulsch_harq->Qm * ((GpmodC==0?0:1) + (Gp/ulsch_harq->C));
if ( split73 == SPLIT73_DU ) {
sendFs6Ul(eNB, UE_id, harq_pid, r, ulsch_harq->eUL+r_offset, E*sizeof(int16_t), r_offset);
r_offset += E;
continue;
}
union turboReqUnion id= {.s={ulsch->rnti,proc->frame_rx,proc->subframe_rx,0,0}};
notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(turboDecode_t),
id.p,
......
......@@ -2,14 +2,14 @@ oai_dfts_sse4: oai_dfts.c
gcc -O3 -std=gnu99 -msse4.1 -o oai_dfts_sse4 oai_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR_TARGETS/COMMON -I$$OPENAIR_HOME/radio/COMMON -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -I$$OPENAIR_HOME/common/utils/msc -I$$OPENAIR_HOME/nfapi/open-nFAPI/nfapi/public_inc -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS
oai_dfts_avx2: oai_dfts.c
gcc -O2 -std=gnu99 -mavx2 -g -ggdb -o oai_dfts_avx2 oai_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c $$OPENAIR_HOME/common/utils/backtrace.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR_TARGETS/COMMON -I$$OPENAIR_HOME/radio/COMMON -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -I$$OPENAIR_HOME/common/utils/msc -I$$OPENAIR_HOME/nfapi/open-nFAPI/nfapi/public_inc -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS
gcc -O2 -std=gnu99 -mavx2 -g -ggdb -o oai_dfts_avx2 oai_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR_TARGETS/COMMON -I$$OPENAIR_HOME/radio/COMMON -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -I$$OPENAIR_HOME/common/utils/msc -I$$OPENAIR_HOME/nfapi/open-nFAPI/nfapi/public_inc -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS
oai_dfts_avx2.s: oai_dfts.c
gcc -O2 -std=gnu99 -mavx2 -S oai_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c $$OPENAIR_HOME/common/utils/backtrace.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR_TARGETS/COMMON -I$$OPENAIR_HOME/radio/COMMON -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -I$$OPENAIR_HOME/common/utils/msc -I$$OPENAIR_HOME/nfapi/open-nFAPI/nfapi/public_inc -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS
gcc -O2 -std=gnu99 -mavx2 -S oai_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR_TARGETS/COMMON -I$$OPENAIR_HOME/radio/COMMON -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -I$$OPENAIR_HOME/common/utils/msc -I$$OPENAIR_HOME/nfapi/open-nFAPI/nfapi/public_inc -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS
oai_dfts_sse4.s: oai_dfts.c
gcc -O2 -std=gnu99 -msse4.1 -S oai_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c $$OPENAIR_HOME/common/utils/backtrace.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR_TARGETS/COMMON -I$$OPENAIR_HOME/radio/COMMON -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -I$$OPENAIR_HOME/common/utils/msc -I$$OPENAIR_HOME/nfapi/open-nFAPI/nfapi/public_inc -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS
gcc -O2 -std=gnu99 -msse4.1 -S oai_dfts.c time_meas.c ../../SIMULATION/TOOLS/taus.c -I$$OPENAIR_HOME -I$$OPENAIR1_DIR -I$$OPENAIR_TARGETS -I$$OPENAIR_TARGETS/COMMON -I$$OPENAIR_HOME/radio/COMMON -I$$OPENAIR2_DIR -I$$OPENAIR2_DIR/COMMON -I$$OPENAIR_HOME/common/utils -I$$OPENAIR_HOME/common/utils/T -I$$OPENAIR_HOME/common/utils/msc -I$$OPENAIR_HOME/nfapi/open-nFAPI/nfapi/public_inc -DMR_MAIN -DNB_ANTENNAS_RX=1 -lm -lpthread # -DD256STATS #-DD64STATS
dft_cycles_avx2: oai_dfts_avx2
......
......@@ -759,7 +759,6 @@ typedef struct PHY_VARS_eNB_s {
int32_t pusch_stats_mcs[NUMBER_OF_UE_MAX][10240];
int32_t pusch_stats_bsr[NUMBER_OF_UE_MAX][10240];
int32_t pusch_stats_BO[NUMBER_OF_UE_MAX][10240];
uint8_t *FS6bufferZone;
int32_t pusch_signal_threshold;
} PHY_VARS_eNB;
......
......@@ -47,7 +47,6 @@
#include <time.h>
#include "intertask_interface.h"
#include <executables/split_headers.h>
#define MBMS_NFAPI_SCHEDULER
......@@ -724,12 +723,8 @@ void srs_procedures(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
}
}
void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat) {
if ( split73 == SPLIT73_DU ) {
sendFs6Ulharq(fs6ULindicationSr, UEid, eNB, NULL, frame, subframe, NULL,0,0, rnti, stat);
return;
}
void fill_sr_indication(int UEid, PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,uint32_t stat)
{
pthread_mutex_lock(&eNB->UL_INFO_mutex);
nfapi_sr_indication_t *sr_ind = &eNB->UL_INFO.sr_ind;
nfapi_sr_indication_body_t *sr_ind_body = &sr_ind->sr_indication_body;
......@@ -1862,12 +1857,8 @@ void fill_ulsch_harq_indication (PHY_VARS_eNB *eNB, LTE_UL_eNB_HARQ_t *ulsch_har
#define packetError(ConD, fmt, args...) if (!(ConD)) { LOG_E(PHY, fmt, args); goodPacket=false; }
void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask) {
if ( split73 == SPLIT73_DU ) {
sendFs6Ulharq(fs6ULindicationHarq, UEid, eNB, uci, frame, subframe, harq_ack, tdd_mapping_mode, tdd_multiplexing_mask, 0, 0);
return;
}
void fill_uci_harq_indication (int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask)
{
int DLSCH_id=find_dlsch(uci->rnti,eNB,SEARCH_EXIST);
//AssertFatal(DLSCH_id>=0,"DLSCH_id doesn't exist rnti:%x\n", uci->rnti);
......
......@@ -56,7 +56,6 @@
#include "unitary_defs.h"
#include "dummy_functions.c"
#include "executables/thread-common.h"
#include "executables/split_headers.h"
#include "common/ran_context.h"
void feptx_ofdm(RU_t *ru, int frame, int subframe);
void feptx_prec(RU_t *ru, int frame, int subframe);
......@@ -92,14 +91,6 @@ static int cmpdouble(const void *p1, const void *p2) {
RAN_CONTEXT_t RC;
int emulate_rf = 0;
int split73=0;
void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) {
AssertFatal(false, "Must not be called in this context\n");
}
void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat) {
AssertFatal(false, "Must not be called in this context\n");
}
void handler(int sig) {
void *array[10];
size_t size;
......
......@@ -52,7 +52,6 @@
#include "common/config/config_load_configmodule.h"
#include "executables/thread-common.h"
#include "executables/lte-softmodem.h"
#include "executables/split_headers.h"
#include "common/ran_context.h"
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
......@@ -91,14 +90,6 @@ static int cmpdouble(const void *p1, const void *p2) {
}
RAN_CONTEXT_t RC;
int split73=0;
void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) {
AssertFatal(false, "Must not be called in this context\n");
}
void sendFs6Ulharq(enum pckType type, int UEid, PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, int subframe, uint8_t *harq_ack, uint8_t tdd_mapping_mode, uint16_t tdd_multiplexing_mask, uint16_t rnti, int32_t stat) {
AssertFatal(false, "Must not be called in this context\n");
}
extern void fep_full(RU_t *ru, int subframe);
extern void ru_fep_full_2thread(RU_t *ru, int subframe);
//extern void eNB_fep_full(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc);
......
......@@ -32,7 +32,6 @@
#include <nr_pdcp/nr_pdcp.h>
#include <softmodem-common.h>
#include <nr-softmodem.h>
#include <split_headers.h>
#include "gnb_app.h"
#include "assertions.h"
......
......@@ -2063,7 +2063,6 @@ UE_RNTI(module_id_t mod_idP,
}
//LOG_D(MAC, "[eNB %d] Couldn't find RNTI for UE %d\n", mod_idP, ue_idP);
//display_backtrace();
return (NOT_A_RNTI);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment