diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 5802f13052d409150d27a25262399de90f33ae3a..76f85cd8983202f12ea3bad6a6e4d681ba4af275 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -317,6 +317,8 @@ if (NOT ${ret} STREQUAL 0) message(FATAL_ERROR "${ret}: error") endif (NOT ${ret} STREQUAL 0) file(GLOB rrc_source ${RRC_FULL_DIR}/*.c) +file(GLOB rrc_h ${RRC_FULL_DIR}/*.h) +set(rrc_h ${rrc_h} ${RRC_FULL_DIR}/asn1_constants.h) add_custom_target ( rrc_flag ALL ${OPENAIR_CMAKE}/tools/make_asn1c_includes.sh "${RRC_FULL_DIR}" "${RRC_GRAMMAR}" "LTE_" @@ -374,6 +376,16 @@ if (NOT ${ret} STREQUAL 0) endif (NOT ${ret} STREQUAL 0) file(GLOB S1AP_source ${S1AP_C_DIR}/*.c) +set(S1AP_OAI_generated + ${S1AP_C_DIR}/s1ap_decoder.c + ${S1AP_C_DIR}/s1ap_encoder.c + ${S1AP_C_DIR}/s1ap_xer_print.c + ${S1AP_C_DIR}/s1ap_compare.c + ${S1AP_C_DIR}/s1ap_ies_defs.h + ) +file(GLOB s1ap_h ${S1AP_C_DIR}/*.h) +set(s1ap_h ${s1ap_h} ) + add_custom_target ( s1ap_flag ALL ${OPENAIR_CMAKE}/tools/make_asn1c_includes.sh "${S1AP_C_DIR}" "${S1AP_ASN_DIR}/${S1AP_ASN_FILES}" "S1AP_" -fno-include-deps @@ -1085,6 +1097,7 @@ add_dependencies(SCHED_UE_LIB rrc_flag) set(SCHED_SRC_NBIOT ${OPENAIR1_DIR}/SCHED_NBIOT/phy_procedures_lte_eNb_NB_IoT.c + ${OPENAIR1_DIR}/SCHED_NBIOT/phy_procedures_lte_eNb_nbiot.c ${OPENAIR1_DIR}/SCHED_NBIOT/phy_procedures_lte_common_NB_IoT.c ${OPENAIR1_DIR}/SCHED_NBIOT/IF_Module_L1_primitives_NB_IoT.c ${OPENAIR1_DIR}/SCHED_NBIOT/pusch_pc_NB_IoT.c @@ -1147,58 +1160,39 @@ include_directories(${NFAPI_USER_DIR}) # Layer 1 ############################# -<<<<<<< HEAD set(PHY_SRC # depend on code generation from asn1c ${RRC_FULL_DIR}/asn1_constants.h # actual source ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pss.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/npss_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/sss.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/nsss_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pilots.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pilots_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pilots_mbsfn.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_coding.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_coding_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_modulation.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_modulation_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_demodulation.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_demodulation_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_llr_computation.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/power_control.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_decoding.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_scrambling.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_scrambling_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/uci_tools.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/uci_tools_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs_NB_IoT.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_Isc_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pbch.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/npbch_NB_IoT.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/SIB_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/phich.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pcfich.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pucch.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/prach.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/nprach_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pmch.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pch.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/group_hopping.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/group_hopping_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/srs_modulation.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/drs_modulation.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_modulation.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_coding.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_decoding.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_decoding_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/rar_tools.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/print_stats.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/initial_sync.c @@ -1212,23 +1206,52 @@ set(PHY_SRC ${OPENAIR1_DIR}/PHY/MODULATION/beamforming.c ${OPENAIR1_DIR}/PHY/MODULATION/compute_bf_weights.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c - ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_time.c - ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_time_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_timefreq.c - ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_timefreq_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_adjust_sync.c - ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_adjust_sync_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_channel_estimation.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_bf_channel_estimation.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_dl_mbsfn_channel_estimation.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c - ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_est_freq_offset.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ue_measurements.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_eNB_measurements.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/adjust_gain.c -======= +) + + # NBIOT +set(PHY_SRC_NBIOT + # depend on code generation from asn1c + ${RRC_FULL_DIR}/asn1_constants.h + # actual source + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/npss_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/nsss_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/pilots_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/dlsch_coding_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/dlsch_modulation_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/dlsch_demodulation_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/dlsch_scrambling_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/dci_tools_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/uci_tools_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/lte_mcs_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/lte_Isc_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/npbch_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/SIB_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/dci_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/nprach_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/group_hopping_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/ulsch_demodulation_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_TRANSPORT/ulsch_decoding_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_ESTIMATION/freq_equalization_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_ESTIMATION/lte_sync_time_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_ESTIMATION/lte_sync_timefreq_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_ESTIMATION/lte_adjust_sync_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_ESTIMATION/lte_ul_channel_estimation_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_REFSIG/lte_dl_cell_spec_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_REFSIG/lte_gold_NB_IoT.c + ${OPENAIR1_DIR}/PHY/NBIoT_REFSIG/lte_ul_ref_NB_IoT.c +) + set(PHY_TURBOSRC ${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c ${OPENAIR1_DIR}/PHY/CODING/3gpplte.c @@ -1261,16 +1284,12 @@ set(PHY_SRC_COMMON ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/srs_modulation.c ${OPENAIR1_DIR}/PHY/MODULATION/ofdm_mod.c ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_sync_time.c ->>>>>>> origin/develop ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_cell_spec.c - ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_cell_spec_NB_IoT.c ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_uespec.c - ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_gold.c - ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_gold_NB_IoT.c + ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_gold.c ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_gold_mbsfn.c ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_dl_mbsfn.c ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_ul_ref.c - ${OPENAIR1_DIR}/PHY/LTE_REFSIG/lte_ul_ref_NB_IoT.c ${OPENAIR1_DIR}/PHY/CODING/lte_segmentation.c ${OPENAIR1_DIR}/PHY/CODING/lte_segmentation_NB_IoT.c ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte.c @@ -1403,6 +1422,8 @@ add_library(PHY_UE ${PHY_SRC_UE}) add_dependencies(PHY_UE rrc_flag) add_library(PHY_RU ${PHY_SRC_RU}) add_dependencies(PHY_RU rrc_flag) +add_library(PHY_NBIOT ${PHY_SRC_NBIOT}) +add_dependencies(PHY_NBIOT rrc_flag) #Library for mex functions #########################3 @@ -1440,10 +1461,21 @@ set(RLC_UM_DIR ${OPENAIR2_DIR}/LAYER2/RLC/UM_v9.3.0) set(RLC_AM_DIR ${OPENAIR2_DIR}/LAYER2/RLC/AM_v9.3.0) set(RLC_TM_DIR ${OPENAIR2_DIR}/LAYER2/RLC/TM_v9.3.0) set(RRC_DIR ${OPENAIR2_DIR}/RRC/LTE) +set(RRC_NBIOT_DIR ${OPENAIR2_DIR}/RRC/NBIOT) set(PDCP_DIR ${OPENAIR2_DIR}/LAYER2/PDCP_v10.1.0) -set(L2_SRC + +#NBIOT +set(L2_SRC_NBIOT ${PHY_INTERFACE_DIR}/IF_Module_NB_IoT.c ${PHY_INTERFACE_DIR}/IF_Module_L2_primitives_NB_IoT.c + ${RRC_DIR}/rrc_eNB_NB_IoT.c + ${RRC_DIR}/rrc_eNB_UE_context_NB_IoT.c + ${RRC_DIR}/rrc_common_NB_IoT.c + ${RRC_DIR}/L2_interface_NB_IoT.c + ) + + +set(L2_SRC ${OPENAIR2_DIR}/LAYER2/openair2_proc.c ${PDCP_DIR}/pdcp.c ${PDCP_DIR}/pdcp_fifo.c @@ -1479,16 +1511,11 @@ set(L2_SRC ${RLC_DIR}/rlc.c ${RLC_DIR}/rlc_rrc.c ${RLC_DIR}/rlc_mpls.c -# ${RRC_DIR}/rrc_UE.c ${RRC_DIR}/rrc_eNB.c - #${RRC_DIR}/rrc_eNB_NB_IoT.c ${RRC_DIR}/rrc_eNB_S1AP.c ${RRC_DIR}/rrc_eNB_UE_context.c - ${RRC_DIR}/rrc_eNB_UE_context_NB_IoT.c ${RRC_DIR}/rrc_common.c - ${RRC_DIR}/rrc_common_NB_IoT.c ${RRC_DIR}/L2_interface.c - ${RRC_DIR}/L2_interface_NB_IoT.c ${RRC_DIR}/L2_interface_common.c ${RRC_DIR}/L2_interface_ue.c ) @@ -1534,11 +1561,25 @@ set(L2_SRC_UE ${RRC_DIR}/L2_interface_ue.c ) +#NBIOT +set (MAC_SRC_NBIOT + ${MAC_DIR}/main_NB_IoT.c + ${MAC_DIR}/eNB_scheduler_NB_IoT.c + ${MAC_DIR}/eNB_scheduler_dlsch_NB_IoT.c + ${MAC_DIR}/eNB_scheduler_ulsch_NB_IoT.c + ${MAC_DIR}/eNB_scheduler_bch_NB_IoT.c + ${MAC_DIR}/output_handler_NB_IoT.c + ${MAC_DIR}/eNB_scheduler_RA_NB_IoT.c + ${MAC_DIR}/config_NB_IoT.c + ${MAC_DIR}/schedule_tool_NB_IoT.c + ) + + + set (MAC_SRC #${PHY_INTERFACE_DIR}/phy_stub_UE.c ${PHY_INTERFACE_DIR}/IF_Module.c ${MAC_DIR}/main.c - ${MAC_DIR}/main_NB_IoT.c #${MAC_DIR}/main_ue.c #${MAC_DIR}/ue_procedures.c #${MAC_DIR}/ra_procedures.c @@ -1546,20 +1587,12 @@ set (MAC_SRC ${MAC_DIR}/rar_tools.c #${MAC_DIR}/rar_tools_ue.c ${MAC_DIR}/eNB_scheduler.c - ${MAC_DIR}/eNB_scheduler_NB_IoT.c ${MAC_DIR}/eNB_scheduler_dlsch.c - ${MAC_DIR}/eNB_scheduler_dlsch_NB_IoT.c ${MAC_DIR}/eNB_scheduler_ulsch.c - ${MAC_DIR}/eNB_scheduler_ulsch_NB_IoT.c ${MAC_DIR}/eNB_scheduler_mch.c ${MAC_DIR}/eNB_scheduler_bch.c - ${MAC_DIR}/eNB_scheduler_bch_NB_IoT.c ${MAC_DIR}/eNB_scheduler_primitives.c - ${MAC_DIR}/output_handler_NB_IoT.c ${MAC_DIR}/eNB_scheduler_RA.c - ${MAC_DIR}/eNB_scheduler_RA_NB_IoT.c - ${MAC_DIR}/config_NB_IoT.c - ${MAC_DIR}/schedule_tool_NB_IoT.c ${MAC_DIR}/eNB_scheduler_fairRR.c ${MAC_DIR}/eNB_scheduler_phytest.c ${MAC_DIR}/pre_processor.c @@ -1582,12 +1615,17 @@ set (ENB_APP_SRC ${OPENAIR2_DIR}/ENB_APP/enb_config.c ${OPENAIR2_DIR}/ENB_APP/enb_config_SL.c ${OPENAIR2_DIR}/ENB_APP/enb_config_eMTC.c + ${OPENAIR2_DIR}/ENB_APP/NB_IoT_config.c ${OPENAIR2_DIR}/ENB_APP/RRC_config_tools.c ) + + add_library(L2 ${L2_SRC} ${MAC_SRC} + ${L2_SRC_NBIOT} + ${MAC_SRC_NBIOT} ${ENB_APP_SRC}) # ${OPENAIR2_DIR}/RRC/L2_INTERFACE/openair_rrc_L2_interface.c) add_dependencies(L2 rrc_flag s1ap_flag x2_flag) @@ -1895,12 +1933,6 @@ if(NAS_UE) endif() -# nbiot -add_definitions("-DNUMBER_OF_UE_MAX_NB_IoT=16") -set (NBIOT_SOURCES - ${OPENAIR2_DIR}/ENB_APP/NB_IoT_config.c -) -add_library(NB_IoT MODULE ${NBIOT_SOURCES} ) # shared library loader set (SHLIB_LOADER_SOURCES @@ -2159,6 +2191,7 @@ add_definitions(-DASN1_MINIMUM_VERSION=924) add_executable(lte-softmodem ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_TARGETS}/RT/USER/lte-enb.c + ${OPENAIR_TARGETS}/RT/USER/lte-enb-nbiot.c ${OPENAIR_TARGETS}/RT/USER/lte-ru.c ${OPENAIR_TARGETS}/RT/USER/ru_control.c ${OPENAIR_TARGETS}/RT/USER/lte-softmodem.c @@ -2185,11 +2218,13 @@ add_dependencies(lte-softmodem rrc_flag s1ap_flag x2_flag) target_link_libraries (lte-softmodem -Wl,--start-group - RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU LFDS L2 + RRC_LIB S1AP_LIB S1AP_ENB F1AP_LIB F1AP X2AP_LIB X2AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_NBIOT PHY_RU LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${FLPT_MSG_LIB} ${ASYNC_IF_LIB} ${FLEXRAN_AGENT_LIB} ${FSPT_MSG_LIB} ${PROTO_AGENT_LIB} LFDS7 NFAPI_COMMON_LIB NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB -Wl,--end-group z dl) + + add_executable(cu_test ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/cu_test.c ${OPENAIR2_DIR}/LAYER2/PROTO_AGENT/proto_agent_handler.c @@ -2328,6 +2363,7 @@ add_executable(test_epc_generate_scenario ${OPENAIR3_DIR}/TEST/EPC_TEST/generate_scenario.c ${OPENAIR3_DIR}/TEST/EPC_TEST/generate_scenario.h ${OPENAIR2_DIR}/ENB_APP/enb_config.h + ${OPENAIR2_DIR}/ENB_APP/NB_IoT_config.h ${OPENAIR2_DIR}/COMMON/commonDef.h ${OPENAIR2_DIR}/COMMON/messages_def.h ${OPENAIR3_DIR}/S1AP/s1ap_eNB_defs.h @@ -2405,6 +2441,45 @@ endif (${T_TRACER}) # Generated specific cases is not regular code ############################################### +##################"" +# itti symbolic debug print require to generate a specific include file +######################################## + +# retrieve the compiler options to send it to gccxml +get_directory_property( DirDefs COMPILE_DEFINITIONS ) +foreach( d ${DirDefs} ) + list(APPEND itti_compiler_options "-D${d}") +endforeach() +get_directory_property( DirDefs INCLUDE_DIRECTORIES ) +foreach( d ${DirDefs} ) + list(APPEND itti_compiler_options "-I${d}") +endforeach() + +# castxml doesn't work with c11 (gcc 5 default) +# force castxml and clang compilation with gnu89 standard +# we can't use cXX standard as pthread_rwlock_t is gnu standard +list(APPEND itti_compiler_options "-std=gnu89") +set (ITTI_H ${ITTI_DIR}/intertask_interface_types.h) +if(EXISTS /usr/bin/gccxml) + set(xml_command gccxml ${itti_compiler_options} -fxml=${OPENAIR_BIN_DIR}/messages.xml ${ITTI_H}) +else() + set(xml_command castxml --castxml-gccxml ${itti_compiler_options} ${ITTI_H} -o ${OPENAIR_BIN_DIR}/messages.xml) +endif() + +add_custom_command ( + OUTPUT ${OPENAIR_BIN_DIR}/messages.xml + COMMAND ${xml_command} + DEPENDS ${S1AP_OAI_generated} ${RRC_FULL_DIR}/asn1_constants.h + ) + +add_custom_command ( + OUTPUT ${OPENAIR_BIN_DIR}/messages_xml.h + COMMAND sed -e 's/ *//' -e 's/\"/\\\\\"/g' -e 's/^/\"/' -e 's/$$/\\\\n\"/' ${OPENAIR_BIN_DIR}/messages.xml > ${OPENAIR_BIN_DIR}/messages_xml.h + DEPENDS ${OPENAIR_BIN_DIR}/messages.xml ${RRC_FULL_DIR}/asn1_constants.h + ) + + + ################ # Kernel modules ############### diff --git a/common/ran_context.h b/common/ran_context.h old mode 100644 new mode 100755 index c0b58d2af2cc79bc09b179245a1d3e132b278ad9..4280f18ed070b1475afd1426d9a9329392954f30 --- a/common/ran_context.h +++ b/common/ran_context.h @@ -88,7 +88,7 @@ typedef struct { /// RRC context variables struct eNB_RRC_INST_s **rrc; /// NB_IoT RRC context variables - //struct eNB_RRC_INST_NB_IoT_s **nb_iot_rrc; + struct eNB_RRC_INST_NB_IoT_s **nbiotrrc; /// MAC context variables struct eNB_MAC_INST_s **mac; /// NB_IoT MAC context variables diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c old mode 100644 new mode 100755 index 746ee5834877d0d231060a5e7e2827e595208987..127a11d322b7a9e240ccb3214b9d8bc301a773f8 --- a/openair1/PHY/INIT/lte_init.c +++ b/openair1/PHY/INIT/lte_init.c @@ -18,20 +18,6 @@ * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ -/*! \file phy_procedures_lte_eNB.c - * \brief Implementation of eNB procedures from 36.213 LTE specifications - * \author R. Knopp, F. Kaltenberger, N. Nikaein, X. Foukas - * \date 2011 - * \version 0.1 - * \company Eurecom - * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr, x.foukas@sms.ed.ac.uk - * last changes: M. Kanj, V. Savaux - * date: 2018 - * company: b<>com - * \email: matthieu.kanj@b-com.com, vincent.savaux@b-com.com - * \note - * \warning - */ #include "PHY/defs_eNB.h" #include "phy_init.h" @@ -48,35 +34,15 @@ #include "common/utils/LOG/vcd_signal_dumper.h" #include "assertions.h" #include <math.h> -#include "PHY/LTE_REFSIG/defs.h" extern uint32_t from_earfcn(int eutra_bandP,uint32_t dl_earfcn); extern int32_t get_uldl_offset(int eutra_bandP); extern uint16_t prach_root_sequence_map0_3[838]; extern uint16_t prach_root_sequence_map4[138]; - -uint8_t dmrs1_tab[8] = {0,2,3,4,6,8,9,10}; +uint8_t dmrs1_tab[8] = { 0, 2, 3, 4, 6, 8, 9, 10 }; -void phy_config_mib(LTE_DL_FRAME_PARMS *fp, - uint8_t N_RB_DL, - uint8_t Nid_cell, - uint8_t Ncp, - uint8_t frame_type, - uint8_t p_eNB, - PHICH_CONFIG_COMMON *phich_config) -{ - fp->N_RB_DL = N_RB_DL; - fp->Nid_cell = Nid_cell; - fp->nushift = Nid_cell%6; - fp->Ncp = Ncp; - fp->frame_type = frame_type; - fp->nb_antenna_ports_eNB = p_eNB; - fp->phich_config_common.phich_resource = phich_config->phich_resource; - fp->phich_config_common.phich_duration = phich_config->phich_duration; -} - int N_RB_DL_array[6] = { 6, 15, 25, 50, 75, 100 }; int @@ -118,6 +84,37 @@ l1_north_init_eNB () return(0); } +//Check with Raymond. (The question is that where to initialize RC.eNB (RC.eNB_NB_IoT) ulsim.c & dlsim.c?) +int +l1_north_init_NB_IoT() +{ + int j; + + if (RC.L1_NB_IoT != NULL) + { + AssertFatal(RC.L1_NB_IoT!=NULL,"RC.L1_NB_IoT is null\n"); + LOG_I(PHY,"RC.L1_NB_IoT = %p\n",RC.L1_NB_IoT); + + for (j=0; j<NbIoT_L1_ParamList.numelt; j++) { + AssertFatal(RC.L1_NB_IoT[j]!=NULL,"RC.eNB_NB_IoT[%d] is null\n",i); + LOG_I(PHY,"RC.L1_NB_IoT = %p\n",RC.L1_NB_IoT); + + + if ((RC.L1_NB_IoT[j]->if_inst_NB_IoT = IF_Module_init_NB_IoT(j))<0) return(-1); + LOG_I(PHY,"RC.L1_NB_IoT = %p\n",RC.L1_NB_IoT); + + RC.L1_NB_IoT[j]->if_inst_NB_IoT->PHY_config_req = PHY_config_req_NB_IoT; + RC.L1_NB_IoT[j]->if_inst_NB_IoT->schedule_response = schedule_response_NB_IoT; + + } + } + else + { + LOG_I(PHY,"%s() Not installing PHY callbacks - RC.nb_nb_iot_L1_inst:%d RC.L1_NB_IoT:%p\n", __FUNCTION__, RC.nb_nb_iot_L1_inst, RC.L1_NB_IoT); + } + return(0); +} + void phy_config_request(PHY_Config_t *phy_config) { @@ -419,13 +416,11 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB, ); LOG_D(PHY,"[MSC_NEW][FRAME 00000][PHY_eNB][MOD %02"PRIu8"][]\n", eNB->Mod_id); - LOG_I (PHY, "[eNB %" PRIu8 "] Initializing DL_FRAME_PARMS : N_RB_DL %" PRIu8 ", PHICH Resource %d, PHICH Duration %d\n", eNB->Mod_id, fp->N_RB_DL, fp->phich_config_common.phich_resource, fp->phich_config_common.phich_duration); LOG_D (PHY, "[MSC_NEW][FRAME 00000][PHY_eNB][MOD %02" PRIu8 "][]\n", eNB->Mod_id); - lte_gold (fp, eNB->lte_gold_table, fp->Nid_cell); generate_pcfich_reg_mapping (fp); generate_phich_reg_mapping (fp); @@ -635,334 +630,3 @@ void install_schedule_handlers(IF_Module_t *if_inst) if_inst->schedule_response = schedule_response; } - - - -void phy_init_lte_top_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms) -{ - - crcTableInit_NB_IoT(); - - //ccodedot11_init(); - //ccodedot11_init_inv(); - ccodelte_init_NB_IoT(); - ccodelte_init2_NB_IoT(); - //ccodelte_init_inv(); - - //treillis_table_init(); - - //phy_generate_viterbi_tables(); - //phy_generate_viterbi_tables_lte(); - - //init_td8(); - // init_td16(); -#ifdef __AVX2__ - // init_td16avx2(); -#endif - - //lte_sync_time_init_NB_IoT(frame_parms); - - //generate_ul_ref_sigs(); - //generate_ul_ref_sigs_rx(); - generate_ul_ref_sigs_rx_NB_IoT(); - - // generate_64qam_table(); - //generate_16qam_table(); - // generate_RIV_tables(); - - init_unscrambling_lut_NB_IoT(); - // init_scrambling_lut(); - - //set_taus_seed(1328); - -} - - - -int phy_init_lte_eNB_NB_IoT(PHY_VARS_eNB_NB_IoT *eNB, - unsigned char is_secondary_eNB, - unsigned char abstraction_flag) -{ - - // shortcuts - NB_IoT_DL_FRAME_PARMS* const fp = &eNB->frame_parms; - NB_IoT_eNB_COMMON* const common_vars = &eNB->common_vars; - NB_IoT_eNB_PUSCH** const pusch_vars = eNB->pusch_vars; - NB_IoT_eNB_SRS* const srs_vars = eNB->srs_vars; - NB_IoT_eNB_PRACH* const prach_vars = &eNB->prach_vars; - - int i, j, eNB_id, UE_id; - int re; - - - eNB->total_dlsch_bitrate = 0; - eNB->total_transmitted_bits = 0; - eNB->total_system_throughput = 0; - eNB->check_for_MUMIMO_transmissions=0; - - - if (eNB->node_function != NGFI_RRU_IF4p5_NB_IoT) { - // lte_gold_NB_IoT(fp,eNB->lte_gold_table_NB_IoT,fp->Nid_cell); ****** uncomment when this function is used - 16/02/2018 - // generate_pcfich_reg_mapping(fp); - // generate_phich_reg_mapping(fp); - - for (UE_id=0; UE_id<NUMBER_OF_UE_MAX_NB_IoT; UE_id++) { - eNB->first_run_timing_advance[UE_id] = - 1; ///This flag used to be static. With multiple eNBs this does no longer work, hence we put it in the structure. However it has to be initialized with 1, which is performed here. - - // clear whole structure - bzero( &eNB->UE_stats[UE_id], sizeof(NB_IoT_eNB_UE_stats) ); - - eNB->physicalConfigDedicated[UE_id] = NULL; - } - - eNB->first_run_I0_measurements = 1; ///This flag used to be static. With multiple eNBs this does no longer work, hence we put it in the structure. However it has to be initialized with 1, which is performed here. - } - - // for (eNB_id=0; eNB_id<3; eNB_id++) { - { - eNB_id=0; - if (abstraction_flag==0) { - - // TX vars - if (eNB->node_function != NGFI_RCC_IF4p5_NB_IoT) - - common_vars->txdata[eNB_id] = (int32_t**)malloc16(fp->nb_antennas_tx*sizeof(int32_t*)); - common_vars->txdataF[eNB_id] = (int32_t **)malloc16(NB_ANTENNA_PORTS_ENB*sizeof(int32_t*)); - common_vars->txdataF_BF[eNB_id] = (int32_t **)malloc16(fp->nb_antennas_tx*sizeof(int32_t*)); - - if (eNB->node_function != NGFI_RRU_IF5_NB_IoT) { - for (i=0; i<NB_ANTENNA_PORTS_ENB; i++) { - if (i<fp->nb_antenna_ports_eNB || i==5) { - common_vars->txdataF[eNB_id][i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t) ); -#ifdef DEBUG_PHY - printf("[openair][LTE_PHY][INIT] common_vars->txdataF[%d][%d] = %p (%lu bytes)\n", - eNB_id,i,common_vars->txdataF[eNB_id][i], - fp->ofdm_symbol_size*fp->symbols_per_tti*10*sizeof(int32_t)); -#endif - } - } - } - - for (i=0; i<fp->nb_antennas_tx; i++) { - common_vars->txdataF_BF[eNB_id][i] = (int32_t*)malloc16_clear(fp->ofdm_symbol_size*sizeof(int32_t) ); - if (eNB->node_function != NGFI_RCC_IF4p5_NB_IoT) - - // Allocate 10 subframes of I/Q TX signal data (time) if not - common_vars->txdata[eNB_id][i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); - -#ifdef DEBUG_PHY - printf("[openair][LTE_PHY][INIT] common_vars->txdata[%d][%d] = %p (%lu bytes)\n",eNB_id,i,common_vars->txdata[eNB_id][i], - fp->samples_per_tti*10*sizeof(int32_t)); -#endif - } - - for (i=0; i<NB_ANTENNA_PORTS_ENB; i++) { - if (i<fp->nb_antenna_ports_eNB || i==5) { - common_vars->beam_weights[eNB_id][i] = (int32_t **)malloc16_clear(fp->nb_antennas_tx*sizeof(int32_t*)); - for (j=0; j<fp->nb_antennas_tx; j++) { - common_vars->beam_weights[eNB_id][i][j] = (int32_t *)malloc16_clear(fp->ofdm_symbol_size*sizeof(int32_t)); - // antenna ports 0-3 are mapped on antennas 0-3 - // antenna port 4 is mapped on antenna 0 - // antenna ports 5-14 are mapped on all antennas - if (((i<4) && (i==j)) || ((i==4) && (j==0))) { - for (re=0; re<fp->ofdm_symbol_size; re++) - common_vars->beam_weights[eNB_id][i][j][re] = 0x00007fff; - } - else if (i>4) { - for (re=0; re<fp->ofdm_symbol_size; re++) - common_vars->beam_weights[eNB_id][i][j][re] = 0x00007fff/fp->nb_antennas_tx; - } -#ifdef DEBUG_PHY - msg("[openair][LTE_PHY][INIT] lte_common_vars->beam_weights[%d][%d][%d] = %p (%zu bytes)\n", - eNB_id,i,j,common_vars->beam_weights[eNB_id][i][j], - fp->ofdm_symbol_size*sizeof(int32_t)); -#endif - } - } - } - - - // RX vars - if (eNB->node_function != NGFI_RCC_IF4p5_NB_IoT) { - common_vars->rxdata[eNB_id] = (int32_t**)malloc16(fp->nb_antennas_rx*sizeof(int32_t*) ); - common_vars->rxdata_7_5kHz[eNB_id] = (int32_t**)malloc16(fp->nb_antennas_rx*sizeof(int32_t*) ); - } - - common_vars->rxdataF[eNB_id] = (int32_t**)malloc16(fp->nb_antennas_rx*sizeof(int32_t*) ); - - - for (i=0; i<fp->nb_antennas_rx; i++) { - if (eNB->node_function != NGFI_RCC_IF4p5_NB_IoT) { - // allocate 2 subframes of I/Q signal data (time) if not an RCC (no time-domain signals) - common_vars->rxdata[eNB_id][i] = (int32_t*)malloc16_clear( fp->samples_per_tti*10*sizeof(int32_t) ); - - if (eNB->node_function != NGFI_RRU_IF5_NB_IoT) - // allocate 2 subframes of I/Q signal data (time, 7.5 kHz offset) - common_vars->rxdata_7_5kHz[eNB_id][i] = (int32_t*)malloc16_clear( 2*fp->samples_per_tti*2*sizeof(int32_t) ); - } - - if (eNB->node_function != NGFI_RRU_IF5_NB_IoT) - // allocate 2 subframes of I/Q signal data (frequency) - common_vars->rxdataF[eNB_id][i] = (int32_t*)malloc16_clear(sizeof(int32_t)*(2*fp->ofdm_symbol_size*fp->symbols_per_tti) ); - -#ifdef DEBUG_PHY - printf("[openair][LTE_PHY][INIT] common_vars->rxdata[%d][%d] = %p (%lu bytes)\n",eNB_id,i,common_vars->rxdata[eNB_id][i],fp->samples_per_tti*10*sizeof(int32_t)); - if (eNB->node_function != NGFI_RRU_IF5_NB_IoT) - printf("[openair][LTE_PHY][INIT] common_vars->rxdata_7_5kHz[%d][%d] = %p (%lu bytes)\n",eNB_id,i,common_vars->rxdata_7_5kHz[eNB_id][i],fp->samples_per_tti*2*sizeof(int32_t)); -#endif - common_vars->rxdataF[eNB_id][i] = (int32_t*)malloc16_clear(sizeof(int32_t)*(fp->ofdm_symbol_size*fp->symbols_per_tti) ); - } - - - if ((eNB->node_function != NGFI_RRU_IF4p5_NB_IoT)&&(eNB->node_function != NGFI_RRU_IF5_NB_IoT)) { - - // Channel estimates for SRS - for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { - - srs_vars[UE_id].srs_ch_estimates[eNB_id] = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - srs_vars[UE_id].srs_ch_estimates_time[eNB_id] = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - - for (i=0; i<fp->nb_antennas_rx; i++) { - srs_vars[UE_id].srs_ch_estimates[eNB_id][i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size ); - srs_vars[UE_id].srs_ch_estimates_time[eNB_id][i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2 ); - } - } //UE_id - - common_vars->sync_corr[eNB_id] = (uint32_t*)malloc16_clear( LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*sizeof(uint32_t)*fp->samples_per_tti ); - } - } // abstraction_flag = 0 - else { //UPLINK abstraction = 1 - eNB->sinr_dB = (double*) malloc16_clear( fp->N_RB_DL*12*sizeof(double) ); - } - } //eNB_id - - - - if (abstraction_flag==0) { - if ((eNB->node_function != NGFI_RRU_IF4p5_NB_IoT)&&(eNB->node_function != NGFI_RRU_IF5_NB_IoT)) { - generate_ul_ref_sigs_rx(); - - // SRS - for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { - srs_vars[UE_id].srs = (int32_t*)malloc16_clear(2*fp->ofdm_symbol_size*sizeof(int32_t)); - } - } - } - - - - // ULSCH VARS, skip if NFGI_RRU_IF4 - - - if ((eNB->node_function!=NGFI_RRU_IF4p5_NB_IoT)&&(eNB->node_function != NGFI_RRU_IF5_NB_IoT)) - - prach_vars->prachF = (int16_t*)malloc16_clear( 1024*2*sizeof(int16_t) ); - - /* number of elements of an array X is computed as sizeof(X) / sizeof(X[0]) */ - AssertFatal(fp->nb_antennas_rx <= sizeof(prach_vars->rxsigF) / sizeof(prach_vars->rxsigF[0]), - "nb_antennas_rx too large"); - for (i=0; i<fp->nb_antennas_rx; i++) { - prach_vars->rxsigF[i] = (int16_t*)malloc16_clear( fp->ofdm_symbol_size*12*2*sizeof(int16_t) ); -#ifdef DEBUG_PHY - printf("[openair][LTE_PHY][INIT] prach_vars->rxsigF[%d] = %p\n",i,prach_vars->rxsigF[i]); -#endif - } - - if ((eNB->node_function != NGFI_RRU_IF4p5_NB_IoT)&&(eNB->node_function != NGFI_RRU_IF5_NB_IoT)) { - - AssertFatal(fp->nb_antennas_rx <= sizeof(prach_vars->prach_ifft) / sizeof(prach_vars->prach_ifft[0]), - "nb_antennas_rx too large"); - for (i=0; i<fp->nb_antennas_rx; i++) { - prach_vars->prach_ifft[i] = (int16_t*)malloc16_clear(1024*2*sizeof(int16_t)); -#ifdef DEBUG_PHY - printf("[openair][LTE_PHY][INIT] prach_vars->prach_ifft[%d] = %p\n",i,prach_vars->prach_ifft[i]); -#endif - } - - for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { - - //FIXME - pusch_vars[UE_id] = (NB_IoT_eNB_PUSCH*)malloc16_clear( NUMBER_OF_UE_MAX*sizeof(NB_IoT_eNB_PUSCH) ); - - if (abstraction_flag==0) { - for (eNB_id=0; eNB_id<3; eNB_id++) { - - pusch_vars[UE_id]->rxdataF_ext[eNB_id] = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - pusch_vars[UE_id]->rxdataF_ext2[eNB_id] = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - pusch_vars[UE_id]->drs_ch_estimates[eNB_id] = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - pusch_vars[UE_id]->drs_ch_estimates_time[eNB_id] = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - pusch_vars[UE_id]->rxdataF_comp[eNB_id] = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - pusch_vars[UE_id]->ul_ch_mag[eNB_id] = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - pusch_vars[UE_id]->ul_ch_magb[eNB_id] = (int32_t**)malloc16( fp->nb_antennas_rx*sizeof(int32_t*) ); - - for (i=0; i<fp->nb_antennas_rx; i++) { - // RK 2 times because of output format of FFT! - // FIXME We should get rid of this - pusch_vars[UE_id]->rxdataF_ext[eNB_id][i] = (int32_t*)malloc16_clear( 2*sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); - pusch_vars[UE_id]->rxdataF_ext2[eNB_id][i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); - pusch_vars[UE_id]->drs_ch_estimates[eNB_id][i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); - pusch_vars[UE_id]->drs_ch_estimates_time[eNB_id][i] = (int32_t*)malloc16_clear( 2*2*sizeof(int32_t)*fp->ofdm_symbol_size ); - pusch_vars[UE_id]->rxdataF_comp[eNB_id][i] = (int32_t*)malloc16_clear( sizeof(int32_t)*fp->N_RB_UL*12*fp->symbols_per_tti ); - pusch_vars[UE_id]->ul_ch_mag[eNB_id][i] = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 ); - pusch_vars[UE_id]->ul_ch_magb[eNB_id][i] = (int32_t*)malloc16_clear( fp->symbols_per_tti*sizeof(int32_t)*fp->N_RB_UL*12 ); - } - } //eNB_id - - pusch_vars[UE_id]->llr = (int16_t*)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); - } // abstraction_flag - } //UE_id - - - if (abstraction_flag==0) { - if (is_secondary_eNB) { - for (eNB_id=0; eNB_id<3; eNB_id++) { - eNB->dl_precoder_SeNB[eNB_id] = (int **)malloc16(4*sizeof(int*)); - - if (eNB->dl_precoder_SeNB[eNB_id]) { -#ifdef DEBUG_PHY - printf("[openair][SECSYS_PHY][INIT] eNB->dl_precoder_SeNB[%d] allocated at %p\n",eNB_id, - eNB->dl_precoder_SeNB[eNB_id]); -#endif - } else { - printf("[openair][SECSYS_PHY][INIT] eNB->dl_precoder_SeNB[%d] not allocated\n",eNB_id); - return(-1); - } - - for (j=0; j<fp->nb_antennas_tx; j++) { - eNB->dl_precoder_SeNB[eNB_id][j] = (int *)malloc16(2*sizeof(int)*(fp->ofdm_symbol_size)); // repeated format (hence the '2*') - - if (eNB->dl_precoder_SeNB[eNB_id][j]) { -#ifdef DEBUG_PHY - printf("[openair][LTE_PHY][INIT] eNB->dl_precoder_SeNB[%d][%d] allocated at %p\n",eNB_id,j, - eNB->dl_precoder_SeNB[eNB_id][j]); -#endif - memset(eNB->dl_precoder_SeNB[eNB_id][j],0,2*sizeof(int)*(fp->ofdm_symbol_size)); - } else { - printf("[openair][LTE_PHY][INIT] eNB->dl_precoder_SeNB[%d][%d] not allocated\n",eNB_id,j); - return(-1); - } - } //for(j=...nb_antennas_tx - - } //for(eNB_id... - } - } -/* - for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) - eNB->UE_stats_ptr[UE_id] = &eNB->UE_stats[UE_id]; - - //defaul value until overwritten by RRCConnectionReconfiguration - if (fp->nb_antenna_ports_eNB==2) - eNB->pdsch_config_dedicated->p_a = dBm3; - else - eNB->pdsch_config_dedicated->p_a = dB0; - - init_prach_tables(839); - */ - } // node_function != NGFI_RRU_IF4p5 - - return (0); - -} - - diff --git a/openair1/PHY/LTE_ESTIMATION/freq_equalization_NB_IoT.c b/openair1/PHY/NBIoT_ESTIMATION/freq_equalization_NB_IoT.c similarity index 100% rename from openair1/PHY/LTE_ESTIMATION/freq_equalization_NB_IoT.c rename to openair1/PHY/NBIoT_ESTIMATION/freq_equalization_NB_IoT.c diff --git a/openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_NB_IoT.c b/openair1/PHY/NBIoT_ESTIMATION/lte_adjust_sync_NB_IoT.c similarity index 100% rename from openair1/PHY/LTE_ESTIMATION/lte_adjust_sync_NB_IoT.c rename to openair1/PHY/NBIoT_ESTIMATION/lte_adjust_sync_NB_IoT.c diff --git a/openair1/PHY/LTE_ESTIMATION/lte_sync_time_NB_IoT.c b/openair1/PHY/NBIoT_ESTIMATION/lte_sync_time_NB_IoT.c similarity index 100% rename from openair1/PHY/LTE_ESTIMATION/lte_sync_time_NB_IoT.c rename to openair1/PHY/NBIoT_ESTIMATION/lte_sync_time_NB_IoT.c diff --git a/openair1/PHY/LTE_ESTIMATION/lte_sync_timefreq_NB_IoT.c b/openair1/PHY/NBIoT_ESTIMATION/lte_sync_timefreq_NB_IoT.c similarity index 100% rename from openair1/PHY/LTE_ESTIMATION/lte_sync_timefreq_NB_IoT.c rename to openair1/PHY/NBIoT_ESTIMATION/lte_sync_timefreq_NB_IoT.c diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation_NB_IoT.c b/openair1/PHY/NBIoT_ESTIMATION/lte_ul_channel_estimation_NB_IoT.c similarity index 100% rename from openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation_NB_IoT.c rename to openair1/PHY/NBIoT_ESTIMATION/lte_ul_channel_estimation_NB_IoT.c diff --git a/openair1/PHY/LTE_REFSIG/lte_dl_cell_spec_NB_IoT.c b/openair1/PHY/NBIoT_REFSIG/lte_dl_cell_spec_NB_IoT.c similarity index 100% rename from openair1/PHY/LTE_REFSIG/lte_dl_cell_spec_NB_IoT.c rename to openair1/PHY/NBIoT_REFSIG/lte_dl_cell_spec_NB_IoT.c diff --git a/openair1/PHY/LTE_REFSIG/lte_gold_NB_IoT.c b/openair1/PHY/NBIoT_REFSIG/lte_gold_NB_IoT.c similarity index 100% rename from openair1/PHY/LTE_REFSIG/lte_gold_NB_IoT.c rename to openair1/PHY/NBIoT_REFSIG/lte_gold_NB_IoT.c diff --git a/openair1/PHY/LTE_REFSIG/lte_ul_ref_NB_IoT.c b/openair1/PHY/NBIoT_REFSIG/lte_ul_ref_NB_IoT.c similarity index 100% rename from openair1/PHY/LTE_REFSIG/lte_ul_ref_NB_IoT.c rename to openair1/PHY/NBIoT_REFSIG/lte_ul_ref_NB_IoT.c diff --git a/openair1/SCHED_NBIOT/phy_procedures_lte_eNb_nbiot.c b/openair1/SCHED_NBIOT/phy_procedures_lte_eNb_nbiot.c new file mode 100755 index 0000000000000000000000000000000000000000..be84cb2a9e71b1e43297e6ce8e6a228c239c19cf --- /dev/null +++ b/openair1/SCHED_NBIOT/phy_procedures_lte_eNb_nbiot.c @@ -0,0 +1,3902 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file phy_procedures_lte_eNB.c + * \brief Implementation of eNB procedures from 36.213 LTE specifications + * \author R. Knopp, F. Kaltenberger, N. Nikaein, X. Foukas + * \date 2011 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,navid.nikaein@eurecom.fr, x.foukas@sms.ed.ac.uk + * \last changes: M. Kanj, V. Savaux + * \date: 2018 + * \company: b<>com + * \email: matthieu.kanj@b-com.com, vincent.savaux@b-com.com + * \note + * \warning + */ + +#include "PHY/defs.h" +#include "PHY/extern.h" +#include "SCHED/defs.h" +#include "SCHED/extern.h" + +///////// NB-IoT testing ///////////////////// +#include "PHY/defs_NB_IoT.h" +#include "PHY/vars_NB_IoT.h" +///////////////////////////////////////////// +#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/LTE_TRANSPORT/if5_tools.h" +#include "openair1/SCHED/defs_NB_IoT.h" + +#ifdef EMOS +#include "SCHED/phy_procedures_emos.h" +#endif + +////// NB-IoT testing ///////////// +#include "PHY/CODING/extern.h" +#include "PHY/LTE_ESTIMATION/defs_NB_IoT.h" +#include "PHY/LTE_TRANSPORT/proto_NB_IoT.h" +//////////////////////////////////// +//#define DEBUG_PHY_PROC (Already defined in cmake) +//#define DEBUG_ULSCH + +#include "LAYER2/MAC/extern.h" +#include "LAYER2/MAC/defs.h" +#include "UTIL/LOG/log.h" +#include "UTIL/LOG/vcd_signal_dumper.h" + +#include "T.h" + +#include "assertions.h" +#include "msc.h" + +#include <time.h> + +#if defined(ENABLE_ITTI) +# include "intertask_interface.h" +#endif + + +#if defined(FLEXRAN_AGENT_SB_IF) +//Agent-related headers +#include "ENB_APP/flexran_agent_extern.h" +#include "ENB_APP/CONTROL_MODULES/MAC/flexran_agent_mac.h" +#include "LAYER2/MAC/flexran_agent_mac_proto.h" +#endif + +//#define DIAG_PHY + +#define NS_PER_SLOT 500000 + +#define PUCCH 1 + +void exit_fun(const char* s); + +extern int exit_openair; +struct timespec start_fh, start_fh_prev; +int start_fh_sf, start_fh_prev_sf; +// Fix per CC openair rf/if device update +// extern openair0_device openair0; + +unsigned char dlsch_input_buffer[2700] __attribute__ ((aligned(32))); +int eNB_sync_buffer0[640*6] __attribute__ ((aligned(32))); +int eNB_sync_buffer1[640*6] __attribute__ ((aligned(32))); +int *eNB_sync_buffer[2] = {eNB_sync_buffer0, eNB_sync_buffer1}; + +extern uint16_t hundred_times_log10_NPRB[100]; + +unsigned int max_peak_val; +int max_sync_pos; + +int harq_pid_updated[NUMBER_OF_UE_MAX][8] = {{0}}; +int harq_pid_round[NUMBER_OF_UE_MAX][8] = {{0}}; + +//DCI_ALLOC_t dci_alloc[8]; + +#ifdef EMOS +fifo_dump_emos_eNB emos_dump_eNB; +#endif + +#if defined(SMBV) +extern const char smbv_fname[]; +extern unsigned short config_frames[4]; +extern uint8_t smbv_frame_cnt; +#endif + +#ifdef DIAG_PHY +extern int rx_sig_fifo; +#endif + + +uint8_t is_SR_subframe(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,uint8_t UE_id) +{ + + const int subframe = proc->subframe_rx; + const int frame = proc->frame_rx; + + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking for SR TXOp(sr_ConfigIndex %d)\n", + eNB->Mod_id,eNB->ulsch[UE_id]->rnti,frame,subframe, + eNB->scheduling_request_config[UE_id].sr_ConfigIndex); + + if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 4) { // 5 ms SR period + if ((subframe%5) == eNB->scheduling_request_config[UE_id].sr_ConfigIndex) + return(1); + } else if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 14) { // 10 ms SR period + if (subframe==(eNB->scheduling_request_config[UE_id].sr_ConfigIndex-5)) + return(1); + } else if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 34) { // 20 ms SR period + if ((10*(frame&1)+subframe) == (eNB->scheduling_request_config[UE_id].sr_ConfigIndex-15)) + return(1); + } else if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 74) { // 40 ms SR period + if ((10*(frame&3)+subframe) == (eNB->scheduling_request_config[UE_id].sr_ConfigIndex-35)) + return(1); + } else if (eNB->scheduling_request_config[UE_id].sr_ConfigIndex <= 154) { // 80 ms SR period + if ((10*(frame&7)+subframe) == (eNB->scheduling_request_config[UE_id].sr_ConfigIndex-75)) + return(1); + } + + return(0); +} + + +int32_t add_ue(int16_t rnti, PHY_VARS_eNB *eNB) +{ + uint8_t i; + + + LOG_D(PHY,"[eNB %d/%d] Adding UE with rnti %x\n", + eNB->Mod_id, + eNB->CC_id, + (uint16_t)rnti); + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + if ((eNB->dlsch[i]==NULL) || (eNB->ulsch[i]==NULL)) { + MSC_LOG_EVENT(MSC_PHY_ENB, "0 Failed add ue %"PRIx16" (ENOMEM)", rnti); + LOG_E(PHY,"Can't add UE, not enough memory allocated\n"); + return(-1); + } else { + if (eNB->UE_stats[i].crnti==0) { + MSC_LOG_EVENT(MSC_PHY_ENB, "0 Add ue %"PRIx16" ", rnti); + LOG_D(PHY,"UE_id %d associated with rnti %x\n",i, (uint16_t)rnti); + eNB->dlsch[i][0]->rnti = rnti; + eNB->ulsch[i]->rnti = rnti; + eNB->UE_stats[i].crnti = rnti; + + eNB->UE_stats[i].Po_PUCCH1_below = 0; + eNB->UE_stats[i].Po_PUCCH1_above = (int32_t)pow(10.0,.1*(eNB->frame_parms.ul_power_control_config_common.p0_NominalPUCCH+eNB->rx_total_gain_dB)); + eNB->UE_stats[i].Po_PUCCH = (int32_t)pow(10.0,.1*(eNB->frame_parms.ul_power_control_config_common.p0_NominalPUCCH+eNB->rx_total_gain_dB)); + LOG_D(PHY,"Initializing Po_PUCCH: p0_NominalPUCCH %d, gain %d => %d\n", + eNB->frame_parms.ul_power_control_config_common.p0_NominalPUCCH, + eNB->rx_total_gain_dB, + eNB->UE_stats[i].Po_PUCCH); + + return(i); + } + } + } + return(-1); +} + +int mac_phy_remove_ue(module_id_t Mod_idP,rnti_t rntiP) { + uint8_t i; + int CC_id; + PHY_VARS_eNB *eNB; + + for (CC_id=0;CC_id<MAX_NUM_CCs;CC_id++) { + eNB = PHY_vars_eNB_g[Mod_idP][CC_id]; + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + if ((eNB->dlsch[i]==NULL) || (eNB->ulsch[i]==NULL)) { + MSC_LOG_EVENT(MSC_PHY_ENB, "0 Failed remove ue %"PRIx16" (ENOMEM)", rntiP); + LOG_E(PHY,"Can't remove UE, not enough memory allocated\n"); + return(-1); + } else { + if (eNB->UE_stats[i].crnti==rntiP) { + MSC_LOG_EVENT(MSC_PHY_ENB, "0 Removed ue %"PRIx16" ", rntiP); + + LOG_D(PHY,"eNB %d removing UE %d with rnti %x\n",eNB->Mod_id,i,rntiP); + + //LOG_D(PHY,("[PHY] UE_id %d\n",i); + clean_eNb_dlsch(eNB->dlsch[i][0]); + clean_eNb_ulsch(eNB->ulsch[i]); + //eNB->UE_stats[i].crnti = 0; + memset(&eNB->UE_stats[i],0,sizeof(LTE_eNB_UE_stats)); + // mac_exit_wrapper("Removing UE"); + + + return(i); + } + } + } + } + MSC_LOG_EVENT(MSC_PHY_ENB, "0 Failed remove ue %"PRIx16" (not found)", rntiP); + return(-1); +} + +int8_t find_next_ue_index(PHY_VARS_eNB *eNB) +{ + uint8_t i; + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + if (eNB->UE_stats[i].crnti==0) { + /*if ((eNB->dlsch[i]) && + (eNB->dlsch[i][0]) && + (eNB->dlsch[i][0]->rnti==0))*/ + LOG_D(PHY,"Next free UE id is %d\n",i); + return(i); + } + } + + return(-1); +} + +int get_ue_active_harq_pid(const uint8_t Mod_id,const uint8_t CC_id,const uint16_t rnti, const int frame, const uint8_t subframe,uint8_t *harq_pid,uint8_t *round,const uint8_t harq_flag) +{ + LTE_eNB_DLSCH_t *DLSCH_ptr; + LTE_eNB_ULSCH_t *ULSCH_ptr; + uint8_t ulsch_subframe,ulsch_frame; + int i; + int8_t UE_id = find_ue(rnti,PHY_vars_eNB_g[Mod_id][CC_id]); + + if (UE_id==-1) { + LOG_D(PHY,"Cannot find UE with rnti %x (Mod_id %d, CC_id %d)\n",rnti, Mod_id, CC_id); + *round=0; + return(-1); + } + + if ((harq_flag == openair_harq_DL) || (harq_flag == openair_harq_RA)) {// this is a DL request + + DLSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->dlsch[(uint32_t)UE_id][0]; + + if (harq_flag == openair_harq_RA) { + if (DLSCH_ptr->harq_processes[0] != NULL) { + *harq_pid = 0; + *round = DLSCH_ptr->harq_processes[0]->round; + return 0; + } else { + return -1; + } + } + + /* let's go synchronous for the moment - maybe we can change at some point */ + i = (frame * 10 + subframe) % 8; + + if (DLSCH_ptr->harq_processes[i]->status == ACTIVE) { + *harq_pid = i; + *round = DLSCH_ptr->harq_processes[i]->round; + } else if (DLSCH_ptr->harq_processes[i]->status == SCH_IDLE) { + *harq_pid = i; + *round = 0; + } else { + printf("%s:%d: bad state for harq process - PLEASE REPORT!!\n", __FILE__, __LINE__); + abort(); + } + } else { // This is a UL request + + ULSCH_ptr = PHY_vars_eNB_g[Mod_id][CC_id]->ulsch[(uint32_t)UE_id]; + ulsch_subframe = pdcch_alloc2ul_subframe(&PHY_vars_eNB_g[Mod_id][CC_id]->frame_parms,subframe); + ulsch_frame = pdcch_alloc2ul_frame(&PHY_vars_eNB_g[Mod_id][CC_id]->frame_parms,frame,subframe); + // Note this is for TDD configuration 3,4,5 only + *harq_pid = subframe2harq_pid(&PHY_vars_eNB_g[Mod_id][CC_id]->frame_parms, + ulsch_frame, + ulsch_subframe); + *round = ULSCH_ptr->harq_processes[*harq_pid]->round; + LOG_T(PHY,"[eNB %d][PUSCH %d] Frame %d subframe %d Checking HARQ, round %d\n",Mod_id,*harq_pid,frame,subframe,*round); + } + + return(0); +} + +int16_t get_target_pusch_rx_power(const module_id_t module_idP, const uint8_t CC_id) +{ + return PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.ul_power_control_config_common.p0_NominalPUSCH; +} + +int16_t get_target_pucch_rx_power(const module_id_t module_idP, const uint8_t CC_id) +{ + return PHY_vars_eNB_g[module_idP][CC_id]->frame_parms.ul_power_control_config_common.p0_NominalPUCCH; +} + +#ifdef EMOS +void phy_procedures_emos_eNB_TX(unsigned char subframe, PHY_VARS_eNB *eNB) +{ + +} +#endif + +void phy_procedures_eNB_S_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,relaying_type_t r_type) +{ + UNUSED(r_type); + int subframe = proc->subframe_rx; + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_S_RX(%d)\n", eNB->Mod_id,proc->frame_rx, subframe); +#endif + + + if (eNB->abstraction_flag == 0) { + lte_eNB_I0_measurements(eNB, + subframe, + 0, + eNB->first_run_I0_measurements); + } + +#ifdef PHY_ABSTRACTION + else { + lte_eNB_I0_measurements_emul(eNB, + 0); + } + +#endif + + +} + + + +#ifdef EMOS +void phy_procedures_emos_eNB_RX(unsigned char subframe,PHY_VARS_eNB *eNB) +{ + + uint8_t aa; + uint16_t last_subframe_emos; + uint16_t pilot_pos1 = 3 - eNB->frame_parms.Ncp, pilot_pos2 = 10 - 2*eNB->frame_parms.Ncp; + uint32_t bytes; + + last_subframe_emos=0; + + + + +#ifdef EMOS_CHANNEL + + //if (last_slot%2==1) // this is for all UL subframes + if (subframe==3) + for (aa=0; aa<eNB->frame_parms.nb_antennas_rx; aa++) { + memcpy(&emos_dump_eNB.channel[aa][last_subframe_emos*2*eNB->frame_parms.N_RB_UL*12], + &eNB->pusch_vars[0]->drs_ch_estimates[0][aa][eNB->frame_parms.N_RB_UL*12*pilot_pos1], + eNB->frame_parms.N_RB_UL*12*sizeof(int)); + memcpy(&emos_dump_eNB.channel[aa][(last_subframe_emos*2+1)*eNB->frame_parms.N_RB_UL*12], + &eNB->pusch_vars[0]->drs_ch_estimates[0][aa][eNB->frame_parms.N_RB_UL*12*pilot_pos2], + eNB->frame_parms.N_RB_UL*12*sizeof(int)); + } + +#endif + + if (subframe==4) { + emos_dump_eNB.timestamp = rt_get_time_ns(); + emos_dump_eNB.frame_tx = eNB->proc[subframe].frame_rx; + emos_dump_eNB.rx_total_gain_dB = eNB->rx_total_gain_dB; + emos_dump_eNB.mimo_mode = eNB->transmission_mode[0]; + memcpy(&emos_dump_eNB.measurements, + &eNB->measurements[0], + sizeof(PHY_MEASUREMENTS_eNB)); + memcpy(&emos_dump_eNB.UE_stats[0],&eNB->UE_stats[0],NUMBER_OF_UE_MAX*sizeof(LTE_eNB_UE_stats)); + + bytes = rtf_put(CHANSOUNDER_FIFO_MINOR, &emos_dump_eNB, sizeof(fifo_dump_emos_eNB)); + + //bytes = rtf_put(CHANSOUNDER_FIFO_MINOR, "test", sizeof("test")); + if (bytes!=sizeof(fifo_dump_emos_eNB)) { + LOG_W(PHY,"[eNB %d] Frame %d, subframe %d, Problem writing EMOS data to FIFO (bytes=%d, size=%d)\n", + eNB->Mod_id,eNB->proc[(subframe+1)%10].frame_rx, subframe,bytes,sizeof(fifo_dump_emos_eNB)); + } else { + if (eNB->proc[(subframe+1)%10].frame_tx%100==0) { + LOG_I(PHY,"[eNB %d] Frame %d (%d), subframe %d, Writing %d bytes EMOS data to FIFO\n", + eNB->Mod_id,eNB->proc[(subframe+1)%10].frame_rx, ((fifo_dump_emos_eNB*)&emos_dump_eNB)->frame_tx, subframe, bytes); + } + } + } +} +#endif + + +#define AMP_OVER_SQRT2 ((AMP*ONE_OVER_SQRT2_Q15)>>15) +#define AMP_OVER_2 (AMP>>1) +int QPSK[4]= {AMP_OVER_SQRT2|(AMP_OVER_SQRT2<<16),AMP_OVER_SQRT2|((65536-AMP_OVER_SQRT2)<<16),((65536-AMP_OVER_SQRT2)<<16)|AMP_OVER_SQRT2,((65536-AMP_OVER_SQRT2)<<16)|(65536-AMP_OVER_SQRT2)}; +int QPSK2[4]= {AMP_OVER_2|(AMP_OVER_2<<16),AMP_OVER_2|((65536-AMP_OVER_2)<<16),((65536-AMP_OVER_2)<<16)|AMP_OVER_2,((65536-AMP_OVER_2)<<16)|(65536-AMP_OVER_2)}; + + + +unsigned int taus(void); +DCI_PDU DCI_pdu_tmp; + + +void pmch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,PHY_VARS_RN *rn,relaying_type_t r_type) { + + +#if defined(Rel10) || defined(Rel14) + MCH_PDU *mch_pduP; + MCH_PDU mch_pdu; + // uint8_t sync_area=255; +#endif + + int subframe = proc->subframe_tx; + + if (eNB->abstraction_flag==0) { + // This is DL-Cell spec pilots in Control region + generate_pilots_slot(eNB, + eNB->common_vars.txdataF[0], + AMP, + subframe<<1,1); + } + +#if defined(Rel10) || defined(Rel14) + // if mcch is active, send regardless of the node type: eNB or RN + // when mcch is active, MAC sched does not allow MCCH and MTCH multiplexing + mch_pduP = mac_xface->get_mch_sdu(eNB->Mod_id, + eNB->CC_id, + proc->frame_tx, + subframe); + + switch (r_type) { + case no_relay: + if ((mch_pduP->Pdu_size > 0) && (mch_pduP->sync_area == 0)) // TEST: only transmit mcch for sync area 0 + LOG_I(PHY,"[eNB%"PRIu8"] Frame %d subframe %d : Got MCH pdu for MBSFN (MCS %"PRIu8", TBS %d) \n", + eNB->Mod_id,proc->frame_tx,subframe,mch_pduP->mcs, + eNB->dlsch_MCH->harq_processes[0]->TBS>>3); + else { + LOG_D(PHY,"[DeNB %"PRIu8"] Frame %d subframe %d : Do not transmit MCH pdu for MBSFN sync area %"PRIu8" (%s)\n", + eNB->Mod_id,proc->frame_tx,subframe,mch_pduP->sync_area, + (mch_pduP->Pdu_size == 0)? "Empty MCH PDU":"Let RN transmit for the moment"); + mch_pduP = NULL; + } + + break; + + case multicast_relay: + if ((mch_pduP->Pdu_size > 0) && ((mch_pduP->mcch_active == 1) || mch_pduP->msi_active==1)) { + LOG_I(PHY,"[RN %"PRIu8"] Frame %d subframe %d: Got the MCH PDU for MBSFN sync area %"PRIu8" (MCS %"PRIu8", TBS %"PRIu16")\n", + rn->Mod_id,rn->frame, subframe, + mch_pduP->sync_area,mch_pduP->mcs,mch_pduP->Pdu_size); + } else if (rn->mch_avtive[subframe%5] == 1) { // SF2 -> SF7, SF3 -> SF8 + mch_pduP= &mch_pdu; + memcpy(&mch_pduP->payload, // could be a simple copy + rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->b, + rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->TBS>>3); + mch_pduP->Pdu_size = (uint16_t) (rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->TBS>>3); + mch_pduP->mcs = rn->dlsch_rn_MCH[subframe%5]->harq_processes[0]->mcs; + LOG_I(PHY,"[RN %"PRIu8"] Frame %d subframe %d: Forward the MCH PDU for MBSFN received on SF %d sync area %"PRIu8" (MCS %"PRIu8", TBS %"PRIu16")\n", + rn->Mod_id,rn->frame, subframe,subframe%5, + rn->sync_area[subframe%5],mch_pduP->mcs,mch_pduP->Pdu_size); + } else { + mch_pduP=NULL; + } + + rn->mch_avtive[subframe]=0; + break; + + default: + LOG_W(PHY,"[eNB %"PRIu8"] Frame %d subframe %d: unknown relaying type %d \n", + eNB->Mod_id,proc->frame_tx,subframe,r_type); + mch_pduP=NULL; + break; + }// switch + + if (mch_pduP) { + fill_eNB_dlsch_MCH(eNB,mch_pduP->mcs,1,0); + // Generate PMCH + generate_mch(eNB,proc,(uint8_t*)mch_pduP->payload); + } else { + LOG_D(PHY,"[eNB/RN] Frame %d subframe %d: MCH not generated \n",proc->frame_tx,subframe); + } + +#endif +} + +int16_t buffer_npusch[153600]; +int16_t buffer_npusch_ext[153600]; +//int32_t llr_msg5[16]; +//int32_t y_msg5[16]; + +void common_signal_procedures (PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) { + + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + int **txdataF = eNB->common_vars.txdataF[0]; + //////////////////////////////////////////////////////// to uncomment for LTE, uint8_t *pbch_pdu=&eNB->pbch_pdu[0]; + int subframe = proc->subframe_tx; + int frame = proc->frame_tx; + RA_TEMPLATE *RA_template = (RA_TEMPLATE *)&eNB_mac_inst[eNB->Mod_id].common_channels[eNB->CC_id].RA_template[0]; + //int With_NSSS=0; + int framerx = proc->frame_rx; + int subframerx = proc->subframe_rx; + /////////////////////////////////////////////////ACK /////////////////////////////////////// + + NB_IoT_eNB_NULSCH_t **ulsch_NB_IoT = &eNB->ulsch_NB_IoT[0];//[0][0]; + + //////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////// Decoding ACK //////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////// + if(subframe==proc->subframe_msg5 && frame==proc->frame_msg5 && proc->flag_msg5==1 && proc->counter_msg5>0) + { + + printf("\n\n msg5 received in frame %d subframe %d \n\n",framerx,subframerx); + + if (proc->counter_msg5 ==2) + { + proc->frame_dscr_msg5 = framerx; + proc->subframe_dscr_msg5 = subframerx; + } + /* + rx_ulsch_Gen_NB_IoT(eNB, + proc, + 0,//eNB_id, // this is the effective sector id + 0,//UE_id, + ulsch_NB_IoT, + 2,//npusch_format, // 1, 2 + 22,//UL_RB_ID_NB_IoT, // 22 , to be included in // to be replaced by NB_IoT_start ?? + 1,//subcarrier_spacing, // 0 (3.75 KHz) or 1 (15 KHz) + 65522,//rnti_tmp, //= 65522 + proc->subframe_dscr_msg5,//subframerx,//scrambling_subframe_msg3, // first received subframe + proc->frame_dscr_msg5,//framerx,// scrambling_frame_msg3, // first received frame + 4,//nb_slot, // total number of occupied slots + 0, // I_sc + 1, // Nsc_RU + 2, // Mcs + 88, // A = TBS + proc->counter_msg5, + subframerx, //current_rx_subframe, + 0); // data (0) or control (1) + */ + + + proc->subframe_msg5++; + proc->counter_msg5--; + + + } + //////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////// RX NPUSH ////////////////////////////////////// + + if(subframe==proc->subframe_real && proc->flag_msg3==1 && frame==proc->frame_msg3 && proc->counter_msg3>0) ///&& frame == ???? + { + proc->subframe_real++; + if(proc->subframe_real==10) ///&& frame == ???? + { + proc->subframe_real=0; + proc->frame_msg3++; + } + if (proc->counter_msg3 ==8) + { + proc->frame_dscr_msg3 = framerx; + proc->subframe_dscr_msg3 = subframerx; + } + //printf("frame %d in demod NPUSCH = \n",frame); + /////////////////////////////////////////////////// NPUSH DEMOD //////////////////////////////////// + // LTE_eNB_COMMON *common_vars = &eNB->common_vars; + /* + rx_ulsch_Gen_NB_IoT(eNB, + proc, + 0,//eNB_id, // this is the effective sector id + 0,//UE_id, + ulsch_NB_IoT, + 1,//npusch_format, // 1, 2 + 22,//UL_RB_ID_NB_IoT, // 22 , to be included in // to be replaced by NB_IoT_start ?? + 1,//subcarrier_spacing, // 0 (3.75 KHz) or 1 (15 KHz) + 65522,//rnti_tmp, //= 65522 + proc->subframe_dscr_msg3,//subframerx,//scrambling_subframe_msg3, // first received subframe + proc->frame_dscr_msg3,//framerx,// scrambling_frame_msg3, // first received frame + 16,//nb_slot, // total number of occupied slots + 11, // I_sc + 1, // Nsc_RU + 2, // Mcs + 88, // A = TBS + proc->counter_msg3, + subframerx, + 0); // data (0) or control (1) + */ + proc->counter_msg3--; + + } + + + +////////////////////////////////////////////////////////////////////////////////////////////////// +if(proc->flag_msg4 == 1 && proc->counter_msg4 > 0) +{ + + if(frame == proc->frame_msg4 && subframe == proc->subframe_msg4) + { + NB_IoT_eNB_NDLSCH_t *rar = eNB->ndlsch_RAR; + //uint8_t tab_rar[15]; + //uint8_t tab_rar[18]; + uint8_t tab_rar[7]; + uint8_t *nas_id = &eNB->msg3_pdu[0]; + //uint8_t *NAS_tab = &eNB->tab_nas; + // avoid subframe 9 and subframe 0 of next frame + /* tab_rar[0]=63; + tab_rar[1]=60; + tab_rar[2]=0; + tab_rar[3]=nas_id[0]; // NAS part 1 + tab_rar[4]=nas_id[1]; // NAS part 2 + tab_rar[5]=nas_id[2]; // NAS part 3 + tab_rar[6]=nas_id[3]; // NAS part 4 + tab_rar[7]=nas_id[4]; // NAS part 5 + tab_rar[8]=nas_id[5]; // NAS part 6 + tab_rar[9]=48; + tab_rar[10]=3; + tab_rar[11]=0; + tab_rar[12]=24; + tab_rar[13]=145; + tab_rar[14]=8;*/ + +/* + tab_rar[0]=63; + tab_rar[1]=60; + tab_rar[2]=0; + tab_rar[3]=nas_id[0]; // NAS part 1 + tab_rar[4]=nas_id[1]; // NAS part 2 + tab_rar[5]=nas_id[2]; // NAS part 3 + tab_rar[6]=nas_id[3]; // NAS part 4 + tab_rar[7]=nas_id[4]; // NAS part 5 + tab_rar[8]=nas_id[5]; // NAS part 6 + tab_rar[9]=48; + tab_rar[10]=19; + tab_rar[11]=176; + tab_rar[12]=216; + tab_rar[13]=134; + tab_rar[14]=114; + tab_rar[15]=68; + tab_rar[16]=32; + tab_rar[17]=32; + +*/ + + tab_rar[0]=28; + tab_rar[1]=nas_id[0]; // NAS part 1 + tab_rar[2]=nas_id[1]; // NAS part 2 + tab_rar[3]=nas_id[2]; // NAS part 3 + tab_rar[4]=nas_id[3]; // NAS part 4 + tab_rar[5]=nas_id[4]; // NAS part 5 + tab_rar[6]=nas_id[5]; // NAS part 5 + + + proc->flag_scrambling =1; + printf("\n RAR sentttttt frame %d, subframe %d", frame, subframe); + + + proc->counter_msg4--; + proc->subframe_msg4 =subframe+1; + + + } + + +} + +/////////////////////////////////////////////////////////////////////////////// + common_signal_procedures_NB_IoT(eNB,proc); + + + +/////////////////////////// END /////////////////////////////////////// + +/* + // generate Cell-Specific Reference Signals for both slots + if (eNB->abstraction_flag==0) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,1); + generate_pilots_slot(eNB, + txdataF, + AMP, + subframe<<1,0); + // check that 2nd slot is for DL + if (subframe_select(fp,subframe) == SF_DL) + generate_pilots_slot(eNB, + txdataF, + AMP, + (subframe<<1)+1,0); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_RS_TX,0); + } +*/ +//////////////////////////// for NB-IoT testing ///////////////////////////// +/* + // First half of PSS/SSS (FDD, slot 0) + if (subframe == 0) { + if ((fp->frame_type == FDD) && + (eNB->abstraction_flag==0)) { + generate_pss(txdataF, + AMP, + fp, + (fp->Ncp==NORMAL) ? 6 : 5, + 0); + generate_sss(txdataF, + AMP, + fp, + (fp->Ncp==NORMAL) ? 5 : 4, + 0); + + } + */ + ///////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////// for NB-IoT testing ///////////////////////////// + /* + // generate PBCH (Physical Broadcast CHannel) info + if ((frame&3) == 0) { + pbch_pdu[2] = 0; + + // FIXME setting pbch_pdu[2] to zero makes the switch statement easier: remove all the or-operators + switch (fp->N_RB_DL) { + case 6: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (0<<5); + break; + + case 15: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (1<<5); + break; + + case 25: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (2<<5); + break; + + case 50: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (3<<5); + break; + + case 75: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (4<<5); + break; + + case 100: + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (5<<5); + break; + + default: + // FIXME if we get here, this should be flagged as an error, right? + pbch_pdu[2] = (pbch_pdu[2]&0x1f) | (2<<5); + break; + } + + pbch_pdu[2] = (pbch_pdu[2]&0xef) | + ((fp->phich_config_common.phich_duration << 4)&0x10); + + switch (fp->phich_config_common.phich_resource) { + case oneSixth: + pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (0<<2); + break; + + case half: + pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (1<<2); + break; + + case one: + pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (2<<2); + break; + + case two: + pbch_pdu[2] = (pbch_pdu[2]&0xf3) | (3<<2); + break; + + default: + // unreachable + break; + } + + pbch_pdu[2] = (pbch_pdu[2]&0xfc) | ((frame>>8)&0x3); + pbch_pdu[1] = frame&0xfc; + pbch_pdu[0] = 0; + } + */ + ////////////////////////////////////////////////////////////////END//////////////////////////////////////////////// + /* + //////////////////////////// for NB-IoT testing ///////////////////////////// + /// First half of SSS (TDD, slot 1) + + if ((fp->frame_type == TDD)&& + (eNB->abstraction_flag==0)){ + generate_sss(txdataF, + AMP, + fp, + (fp->Ncp==NORMAL) ? 6 : 5, + 1); + } + + /// generate PBCH + if (eNB->abstraction_flag==0) { + generate_pbch(&eNB->pbch, + txdataF, + AMP, + fp, + pbch_pdu, + frame&3); + } +#ifdef PHY_ABSTRACTION + else { + generate_pbch_emul(eNB,pbch_pdu); + } +#endif + + } + else if ((subframe == 1) && + (fp->frame_type == TDD)&& + (eNB->abstraction_flag==0)) { + generate_pss(txdataF, + AMP, + fp, + 2, + 2); + } + + // Second half of PSS/SSS (FDD, slot 10) + else if ((subframe == 5) && + (fp->frame_type == FDD) && + (eNB->abstraction_flag==0)) { + generate_pss(txdataF, + AMP, + &eNB->frame_parms, + (fp->Ncp==NORMAL) ? 6 : 5, + 10); + generate_sss(txdataF, + AMP, + &eNB->frame_parms, + (fp->Ncp==NORMAL) ? 5 : 4, + 10); + + } + + // Second-half of SSS (TDD, slot 11) + else if ((subframe == 5) && + (fp->frame_type == TDD) && + (eNB->abstraction_flag==0)) { + generate_sss(txdataF, + AMP, + fp, + (fp->Ncp==NORMAL) ? 6 : 5, + 11); + } + + // Second half of PSS (TDD, slot 12) + else if ((subframe == 6) && + (fp->frame_type == TDD) && + (eNB->abstraction_flag==0)) { + generate_pss(txdataF, + AMP, + fp, + 2, + 12); + } + */ + ///////////////////////////////////////////////////////////////////////// +} + +void generate_eNB_dlsch_params(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,const int UE_id) { + + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + int frame = proc->frame_tx; + int subframe = proc->subframe_tx; + + // if we have SI_RNTI, configure dlsch parameters and CCE index + if (dci_alloc->rnti == SI_RNTI) { + LOG_D(PHY,"Generating dlsch params for SI_RNTI\n"); + generate_eNB_dlsch_params_from_dci(frame, + subframe, + &dci_alloc->dci_pdu[0], + dci_alloc->rnti, + dci_alloc->format, + &eNB->dlsch_SI, + fp, + NULL, + SI_RNTI, + 0, + P_RNTI, + eNB->UE_stats[0].DL_pmi_single, + 0); + + + eNB->dlsch_SI->nCCE[subframe] = dci_alloc->firstCCE; + + LOG_T(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resource for common DCI (SI) => %"PRIu8"\n",eNB->Mod_id,frame,subframe, + eNB->dlsch_SI->nCCE[subframe]); + +#if defined(SMBV) + + // configure SI DCI + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, SI in SF %d DCI %"PRIu32"\n",frame,subframe,i); + smbv_configure_common_dci(smbv_fname,(smbv_frame_cnt*10) + (subframe), "SI", dci_alloc, i); + } + +#endif + + + } else if (dci_alloc->ra_flag == 1) { // This is format 1A allocation for RA + // configure dlsch parameters and CCE index + LOG_D(PHY,"Generating dlsch params for RA_RNTI\n"); + generate_eNB_dlsch_params_from_dci(frame, + subframe, + &dci_alloc->dci_pdu[0], + dci_alloc->rnti, + dci_alloc->format, + &eNB->dlsch_ra, + fp, + NULL, + SI_RNTI, + dci_alloc->rnti, + P_RNTI, + eNB->UE_stats[0].DL_pmi_single, + 0); + + + eNB->dlsch_ra->nCCE[subframe] = dci_alloc->firstCCE; + + LOG_D(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resource for common DCI (RA) => %"PRIu8"\n",eNB->Mod_id,frame,subframe, + eNB->dlsch_ra->nCCE[subframe]); +#if defined(SMBV) + + // configure RA DCI + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, RA in SF %d DCI %"PRIu32"\n",frame,subframe,i); + smbv_configure_common_dci(smbv_fname,(smbv_frame_cnt*10) + (subframe), "RA", dci_alloc, i); + } + +#endif + + } + + else if ((dci_alloc->format != format0)&& + (dci_alloc->format != format3)&& + (dci_alloc->format != format3A)&& + (dci_alloc->format != format4)){ // this is a normal DLSCH allocation + + + + if (UE_id>=0) { +#if defined(SMBV) + // Configure this user + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, SF %d (SMBV SF %d) Configuring user %d with RNTI %"PRIu16" in TM%"PRIu8"\n",frame,subframe,(smbv_frame_cnt*10) + (subframe),UE_id+1, + dci_alloc->rnti,eNB->transmission_mode[(uint8_t)UE_id]); + smbv_configure_user(smbv_fname,UE_id+1,eNB->transmission_mode[(uint8_t)UE_id],dci_alloc->rnti); + } + +#endif + + LOG_D(PHY,"Generating dlsch params for RNTI %x\n",dci_alloc->rnti); + //fill the dlsch structures + generate_eNB_dlsch_params_from_dci(frame, + subframe, + &dci_alloc->dci_pdu[0], + dci_alloc->rnti, + dci_alloc->format, + eNB->dlsch[(uint8_t)UE_id], + fp, + &eNB->pdsch_config_dedicated[UE_id], + SI_RNTI, + 0, + P_RNTI, + eNB->UE_stats[(uint8_t)UE_id].DL_pmi_single, + eNB->transmission_mode[(uint8_t)UE_id]<7?0:eNB->transmission_mode[(uint8_t)UE_id]); + LOG_D(PHY,"[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d subframe %d: Generated dlsch params\n", + eNB->Mod_id,dci_alloc->rnti,eNB->dlsch[(uint8_t)UE_id][0]->current_harq_pid,frame,subframe); + + + T(T_ENB_PHY_DLSCH_UE_DCI, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), + T_INT(dci_alloc->rnti), T_INT(dci_alloc->format), + T_INT(eNB->dlsch[(int)UE_id][0]->current_harq_pid), + T_INT(eNB->dlsch[(int)UE_id][0]->harq_processes[eNB->dlsch[(int)UE_id][0]->current_harq_pid]->mcs), + T_INT(eNB->dlsch[(int)UE_id][0]->harq_processes[eNB->dlsch[(int)UE_id][0]->current_harq_pid]->TBS)); + + eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe] = dci_alloc->firstCCE; + + LOG_D(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resource for ue DCI (PDSCH %"PRIx16") => %"PRIu8"\n",eNB->Mod_id,frame,subframe, + dci_alloc->rnti,eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe]); + +#if defined(SMBV) + + // configure UE-spec DCI + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, PDSCH in SF %d DCI %"PRIu32"\n",frame,subframe,i); + smbv_configure_ue_spec_dci(smbv_fname,(smbv_frame_cnt*10) + (subframe), UE_id+1,dci_alloc, i); + } + +#endif + + LOG_D(PHY,"[eNB %"PRIu8"][DCI][PDSCH %"PRIx16"] Frame %d subframe %d UE_id %"PRId8" Generated DCI format %d, aggregation %d\n", + eNB->Mod_id, dci_alloc->rnti, + frame, subframe,UE_id, + dci_alloc->format, + 1<<dci_alloc->L); + } else { + LOG_D(PHY,"[eNB %"PRIu8"][PDSCH] Frame %d : No UE_id with corresponding rnti %"PRIx16", dropping DLSCH\n", + eNB->Mod_id,frame,dci_alloc->rnti); + } + } + +} + +void generate_eNB_ulsch_params(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,DCI_ALLOC_t *dci_alloc,const int UE_id) { + + int harq_pid; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + int frame = proc->frame_tx; + int subframe = proc->subframe_tx; + /* + uint16_t srsPeriodicity=0; + uint16_t srsOffset=0; + uint16_t srsConfigIndex=0; + uint16_t do_srs=0; + */ + uint16_t is_srs_pos=0; + + LOG_D(PHY, + "[eNB %"PRIu8"][PUSCH %"PRIu8"] Frame %d subframe %d UL Frame %"PRIu32", UL Subframe %"PRIu8", Generated ULSCH (format0) DCI (rnti %"PRIx16", dci %"PRIx8"), aggregation %d\n", + eNB->Mod_id, + subframe2harq_pid(fp, + pdcch_alloc2ul_frame(fp,frame,subframe), + pdcch_alloc2ul_subframe(fp,subframe)), + frame, + subframe, + pdcch_alloc2ul_frame(fp,frame,subframe), + pdcch_alloc2ul_subframe(fp,subframe), + dci_alloc->rnti, + dci_alloc->dci_pdu[0], + 1<<dci_alloc->L); + + is_srs_pos = is_srs_occasion_common(fp,pdcch_alloc2ul_frame(fp,frame,subframe),pdcch_alloc2ul_subframe(fp,subframe)); + /* + if (is_srs_pos && eNB->soundingrs_ul_config_dedicated[UE_id].srsConfigDedicatedSetup) { + srsConfigIndex = eNB->soundingrs_ul_config_dedicated[UE_id].srs_ConfigIndex; + compute_srs_pos(fp->frame_type, srsConfigIndex, &srsPeriodicity, &srsOffset); + if ((((10*pdcch_alloc2ul_frame(fp,frame,subframe)+pdcch_alloc2ul_subframe(fp,subframe)) % srsPeriodicity) == srsOffset)) { + do_srs = 1; + } + } + LOG_D(PHY,"frame %d (%d), subframe %d (%d), UE_id %d: is_srs_pos %d, do_SRS %d, index %d, period %d, offset %d \n", + frame,pdcch_alloc2ul_frame(fp,frame,subframe),subframe,pdcch_alloc2ul_subframe(fp,subframe), + UE_id,is_srs_pos,do_srs,srsConfigIndex,srsPeriodicity,srsOffset); + */ + + generate_eNB_ulsch_params_from_dci(eNB, + proc, + &dci_alloc->dci_pdu[0], + dci_alloc->rnti, + format0, + UE_id, + SI_RNTI, + 0, + P_RNTI, + CBA_RNTI, + is_srs_pos); + + LOG_T(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resources for UE spec DCI (PUSCH %"PRIx16") => %d\n", + eNB->Mod_id,frame,subframe,dci_alloc->rnti, + dci_alloc->firstCCE); + +#if defined(SMBV) + + // configure UE-spec DCI for UL Grant + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, SF %d UL DCI %"PRIu32"\n",frame,subframe,i); + smbv_configure_ue_spec_dci(smbv_fname,(smbv_frame_cnt*10) + (subframe), UE_id+1, &DCI_pdu->dci_alloc[i], i); + } + +#endif + + + // get the hard_pid for this subframe + harq_pid = subframe2harq_pid(fp, + pdcch_alloc2ul_frame(fp,frame,subframe), + pdcch_alloc2ul_subframe(fp,subframe)); + + if (harq_pid==255) { // should not happen, log an error and exit, this is a fatal error + LOG_E(PHY,"[eNB %"PRIu8"] Frame %d: Bad harq_pid for ULSCH allocation\n",eNB->Mod_id,frame); + mac_xface->macphy_exit("FATAL\n"); + } + + if ((dci_alloc->rnti >= CBA_RNTI) && (dci_alloc->rnti < P_RNTI)) + eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->subframe_cba_scheduling_flag = 1; + else + eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag = 1; + + T(T_ENB_PHY_ULSCH_UE_DCI, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), + T_INT(dci_alloc->rnti), T_INT(harq_pid), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->mcs), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->round), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->first_rb), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->nb_rb), + T_INT(eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->TBS), + T_INT(dci_alloc->L), + T_INT(dci_alloc->firstCCE)); +} + +void pdsch_procedures(PHY_VARS_eNB *eNB, + eNB_rxtx_proc_t *proc, + LTE_eNB_DLSCH_t *dlsch, + LTE_eNB_DLSCH_t *dlsch1, + LTE_eNB_UE_stats *ue_stats, + int ra_flag, + int num_pdcch_symbols) { + + int frame=proc->frame_tx; + int subframe=proc->subframe_tx; + int harq_pid = dlsch->current_harq_pid; + LTE_DL_eNB_HARQ_t *dlsch_harq=dlsch->harq_processes[harq_pid]; + int input_buffer_length = dlsch_harq->TBS/8; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + uint8_t *DLSCH_pdu=NULL; + uint8_t DLSCH_pdu_tmp[input_buffer_length+4]; //[768*8]; + uint8_t DLSCH_pdu_rar[256]; + int i; + + LOG_D(PHY, + "[eNB %"PRIu8"][PDSCH %"PRIx16"/%"PRIu8"] Frame %d, subframe %d: Generating PDSCH/DLSCH with input size = %"PRIu16", G %d, nb_rb %"PRIu16", mcs %"PRIu8", pmi_alloc %"PRIx64", rv %"PRIu8" (round %"PRIu8")\n", + eNB->Mod_id, dlsch->rnti,harq_pid, + frame, subframe, input_buffer_length, + get_G(fp, + dlsch_harq->nb_rb, + dlsch_harq->rb_alloc, + get_Qm(dlsch_harq->mcs), + dlsch_harq->Nl, + num_pdcch_symbols, + frame, + subframe, + dlsch_harq->mimo_mode==TM7?7:0), + dlsch_harq->nb_rb, + dlsch_harq->mcs, + pmi2hex_2Ar1(dlsch_harq->pmi_alloc), + dlsch_harq->rvidx, + dlsch_harq->round); + +#if defined(MESSAGE_CHART_GENERATOR_PHY) + MSC_LOG_TX_MESSAGE( + MSC_PHY_ENB,MSC_PHY_UE, + NULL,0, + "%05u:%02u PDSCH/DLSCH input size = %"PRIu16", G %d, nb_rb %"PRIu16", mcs %"PRIu8", pmi_alloc %"PRIx16", rv %"PRIu8" (round %"PRIu8")", + frame, subframe, + input_buffer_length, + get_G(fp, + dlsch_harq->nb_rb, + dlsch_harq->rb_alloc, + get_Qm(dlsch_harq->mcs), + dlsch_harq->Nl, + num_pdcch_symbols, + frame, + subframe, + dlsch_harq->mimo_mode==TM7?7:0), + dlsch_harq->nb_rb, + dlsch_harq->mcs, + pmi2hex_2Ar1(dlsch_harq->pmi_alloc), + dlsch_harq->rvidx, + dlsch_harq->round); +#endif + + if (ue_stats) ue_stats->dlsch_sliding_cnt++; + + if (dlsch_harq->round == 0) { + + if (ue_stats) + ue_stats->dlsch_trials[harq_pid][0]++; + + if (eNB->mac_enabled==1) { + if (ra_flag == 0) { + DLSCH_pdu = mac_xface->get_dlsch_sdu(eNB->Mod_id, + eNB->CC_id, + frame, + dlsch->rnti, + 0); + } + else { + int16_t crnti = mac_xface->fill_rar(eNB->Mod_id, + eNB->CC_id, + frame, + DLSCH_pdu_rar, + fp->N_RB_UL, + input_buffer_length); + DLSCH_pdu = DLSCH_pdu_rar; + + int UE_id; + + if (crnti!=0) + UE_id = add_ue(crnti,eNB); + else + UE_id = -1; + + if (UE_id==-1) { + LOG_W(PHY,"[eNB] Max user count reached.\n"); + mac_xface->cancel_ra_proc(eNB->Mod_id, + eNB->CC_id, + frame, + crnti); + } else { + eNB->UE_stats[(uint32_t)UE_id].mode = RA_RESPONSE; + // Initialize indicator for first SR (to be cleared after ConnectionSetup is acknowledged) + eNB->first_sr[(uint32_t)UE_id] = 1; + + + /* + * In FAPI style we don-t need to process the RAR because we have all the parameters for getting the MSG3 given by the + * UL_CONFIG.request + * 1) this data are given at the same time with the DLSCH PDU containing the RAR + * 2) wee need to do a mapping of this parameters OAI->FAPI + */ + + + /*this for MSG3*/ + //the problem of OAI is that i don't have any DCI0 for scheduling the info for getting Msg3 (because is direclty given in RAR) + //so i should gather the information directly form RAR before sending it + //In FAPI style apporach so we directly get it from the next UL-config given in the Sched_rsp + //so most probably i don't care about it because i will receive all the information for get Msg3 + generate_eNB_ulsch_params_from_rar(DLSCH_pdu, + frame, + subframe, + eNB->ulsch[(uint32_t)UE_id], + fp); + + LOG_D(PHY,"[eNB][RAPROC] Frame %d subframe %d, Activated Msg3 demodulation for UE %"PRId8" in frame %"PRIu32", subframe %"PRIu8"\n", + frame, + subframe, + UE_id, + eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, + eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); + + /* TODO: get rid of this hack. The problem is that the eNodeB may + * sometimes wrongly generate PHICH because somewhere 'phich_active' was + * not reset to 0, due to an unidentified reason. When adding this + * resetting here the problem seems to disappear completely. + */ + LOG_D(PHY, "hack: set phich_active to 0 for UE %d fsf %d %d all HARQs\n", UE_id, frame, subframe); + for (i = 0; i < 8; i++) + eNB->ulsch[(uint32_t)UE_id]->harq_processes[i]->phich_active = 0; + + mac_xface->set_msg3_subframe(eNB->Mod_id, eNB->CC_id, frame, subframe, (uint16_t)crnti, + eNB->ulsch[UE_id]->Msg3_frame, eNB->ulsch[UE_id]->Msg3_subframe); + + T(T_ENB_PHY_MSG3_ALLOCATION, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), + T_INT(UE_id), T_INT((uint16_t)crnti), T_INT(1 /* 1 is for initial transmission*/), + T_INT(eNB->ulsch[UE_id]->Msg3_frame), T_INT(eNB->ulsch[UE_id]->Msg3_subframe)); + } + if (ue_stats) ue_stats->total_TBS_MAC += dlsch_harq->TBS; + } + } + else { + DLSCH_pdu = DLSCH_pdu_tmp; + + for (i=0; i<input_buffer_length; i++) + DLSCH_pdu[i] = (unsigned char)(taus()&0xff); + } + +#if defined(SMBV) + + // Configures the data source of allocation (allocation is configured by DCI) + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, Configuring PDSCH payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); + // smbv_configure_datalist_for_user(smbv_fname, find_ue(dlsch->rnti,eNB)+1, DLSCH_pdu, input_buffer_length); + } + +#endif + + + +#ifdef DEBUG_PHY_PROC +#ifdef DEBUG_DLSCH + LOG_T(PHY,"eNB DLSCH SDU: \n"); + + //eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe] = DCI_pdu->dci_alloc[i].firstCCE; + + LOG_D(PHY,"[eNB %"PRIu8"] Frame %d subframe %d : CCE resource for ue DCI (PDSCH %"PRIx16") => %"PRIu8"/%u\n",eNB->Mod_id,eNB->proc[sched_subframe].frame_tx,subframe, + DCI_pdu->dci_alloc[i].rnti,eNB->dlsch[(uint8_t)UE_id][0]->nCCE[subframe],DCI_pdu->dci_alloc[i].firstCCE); + + + for (i=0; i<dlsch_harq->TBS>>3; i++) + LOG_T(PHY,"%"PRIx8".",DLSCH_pdu[i]); + + LOG_T(PHY,"\n"); +#endif +#endif + } else { + ue_stats->dlsch_trials[harq_pid][dlsch_harq->round]++; +#ifdef DEBUG_PHY_PROC +#ifdef DEBUG_DLSCH + LOG_D(PHY,"[eNB] This DLSCH is a retransmission\n"); +#endif +#endif + } + + if (eNB->abstraction_flag==0) { + + LOG_D(PHY,"Generating DLSCH/PDSCH %d\n",ra_flag); + // 36-212 + start_meas(&eNB->dlsch_encoding_stats); + //encoding + eNB->te(eNB, + DLSCH_pdu, + num_pdcch_symbols, + dlsch, + frame,subframe, + &eNB->dlsch_rate_matching_stats, + &eNB->dlsch_turbo_encoding_stats, + &eNB->dlsch_interleaving_stats); + stop_meas(&eNB->dlsch_encoding_stats); + // 36-211 + start_meas(&eNB->dlsch_scrambling_stats); + //scrambling + dlsch_scrambling(fp, + 0, + dlsch, + get_G(fp, + dlsch_harq->nb_rb, + dlsch_harq->rb_alloc, + get_Qm(dlsch_harq->mcs), + dlsch_harq->Nl, + num_pdcch_symbols, + frame,subframe, + 0), + 0, + subframe<<1); + stop_meas(&eNB->dlsch_scrambling_stats); + + start_meas(&eNB->dlsch_modulation_stats); + + + //modulation + dlsch_modulation(eNB, + eNB->common_vars.txdataF[0], + AMP, + subframe, + num_pdcch_symbols, + dlsch, + dlsch1); + + stop_meas(&eNB->dlsch_modulation_stats); + } + + +#ifdef PHY_ABSTRACTION + else { + start_meas(&eNB->dlsch_encoding_stats); + dlsch_encoding_emul(eNB, + DLSCH_pdu, + dlsch); + stop_meas(&eNB->dlsch_encoding_stats); + } + +#endif + dlsch->active = 0; +} + +void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB, + eNB_rxtx_proc_t *proc, + relaying_type_t r_type, + PHY_VARS_RN *rn, + int do_meas, + int do_pdcch_flag) +{ + UNUSED(rn); + int frame=proc->frame_tx; + int subframe=proc->subframe_tx; + // uint16_t input_buffer_length; + uint32_t i,aa; //j; + uint8_t harq_pid; + DCI_PDU *DCI_pdu; + DCI_PDU DCI_pdu_tmp; + int8_t UE_id=0; + // uint8_t num_pdcch_symbols=0; + uint8_t ul_subframe; + uint32_t ul_frame; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + // DCI_ALLOC_t *dci_alloc=(DCI_ALLOC_t *)NULL; + + int offset = eNB->CC_id;//proc == &eNB->proc.proc_rxtx[0] ? 0 : 1; + +#if defined(SMBV) + // counts number of allocations in subframe + // there is at least one allocation for PDCCH + uint8_t smbv_alloc_cnt = 1;Exiting eNB thread RXn_TXnp4 + +#endif + + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)==SF_UL)) return; + + // VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+offset,1); + // if (do_meas==1) start_meas(&eNB->phy_proc_tx); + + T(T_ENB_PHY_DL_TICK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe)); + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + // If we've dropped the UE, go back to PRACH mode for this UE + if ((frame==0)&&(subframe==0)) { + if (eNB->UE_stats[i].crnti > 0) { + LOG_I(PHY,"UE %d : rnti %x\n",i,eNB->UE_stats[i].crnti); + } + } + if (eNB->UE_stats[i].ulsch_consecutive_errors == ULSCH_max_consecutive_errors) { + LOG_W(PHY,"[eNB %d, CC %d] frame %d, subframe %d, UE %d: ULSCH consecutive error count reached %u, triggering UL Failure\n", + eNB->Mod_id,eNB->CC_id,frame,subframe, i, eNB->UE_stats[i].ulsch_consecutive_errors); + eNB->UE_stats[i].ulsch_consecutive_errors=0; + mac_xface->UL_failure_indication(eNB->Mod_id, + eNB->CC_id, + frame, + eNB->UE_stats[i].crnti, + subframe); + + } + + + } + + // Get scheduling info for next subframe + // This is called only for the CC_id = 0 and triggers scheduling for all CC_id's + /* if (eNB->mac_enabled==1) { + if (eNB->CC_id == 0) { + mac_xface->eNB_dlsch_ulsch_scheduler(eNB->Mod_id,0,frame,subframe);//,1); + } + }*/ + + // clear the transmit data array for the current subframe + if (eNB->abstraction_flag==0) { + for (aa=0; aa<fp->nb_antenna_ports_eNB; aa++) { + memset(&eNB->common_vars.txdataF[0][aa][subframe*fp->ofdm_symbol_size*(fp->symbols_per_tti)], + 0,fp->ofdm_symbol_size*(fp->symbols_per_tti)*sizeof(int32_t)); + } + } + +/////////////////////////////////////////////////////////////////////////////////// +// test if there is detection, + //if yes proceed to setting flag to indicate that there is something to transmit + // another flag to indicate that DCI is transmitted + // flag to encode DCI + // store the PDU of DCI + // add two variable for frame and subframe , in order to know next transmission + // varible to indicate the remaining repetition to transmit + + ///////////////////////////////////////////////////////////////////////////////////////////// + + // if (is_pmch_subframe(frame,subframe,fp)) { + // pmch_procedures(eNB,proc,rn,r_type); +// } + // else { + // this is not a pmch subframe, so generate PSS/SSS/PBCH + common_signal_procedures(eNB,proc); + // } +/* +#if defined(SMBV) + + // PBCH takes one allocation + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + if (subframe==0) + smbv_alloc_cnt++; + } + +#endif +*/ + if (eNB->mac_enabled==1) { + // Parse DCI received from MAC + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,1); + DCI_pdu = mac_xface->get_dci_sdu(eNB->Mod_id, + eNB->CC_id, + frame, + subframe); + } + else { + DCI_pdu = &DCI_pdu_tmp; + +#ifdef EMOS_CHANNEL + // fill_dci_emos(DCI_pdu,eNB); +#else + // fill_dci(DCI_pdu,eNB,proc); + // clear previous allocation information for all UEs + /* for (i=0; i<NUMBER_OF_UE_MAX; i++) { + if (eNB->dlsch[i][0]){ + for (j=0; j<8; j++) + eNB->dlsch[i][0]->harq_processes[j]->round = 0; + } + } +*/ +#endif + } + + // clear existing ulsch dci allocations before applying info from MAC (this is table +// ul_subframe = pdcch_alloc2ul_subframe(fp,subframe); + // ul_frame = pdcch_alloc2ul_frame(fp,frame,subframe); +/* + if ((subframe_select(fp,ul_subframe)==SF_UL) || + (fp->frame_type == FDD)) { + harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + + // clear DCI allocation maps for new subframe + for (i=0; i<NUMBER_OF_UE_MAX; i++) + if (eNB->ulsch[i]) { + eNB->ulsch[i]->harq_processes[harq_pid]->dci_alloc=0; + eNB->ulsch[i]->harq_processes[harq_pid]->rar_alloc=0; + } + }*/ +/* + // clear previous allocation information for all UEs + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + if (eNB->dlsch[i][0]) + eNB->dlsch[i][0]->subframe_tx[subframe] = 0; + } +*/ + /* save old HARQ information needed for PHICH generation */ + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + if (eNB->ulsch[i]) { + /* Store first_rb and n_DMRS for correct PHICH generation below. + * For PHICH generation we need "old" values of last scheduling + * for this HARQ process. 'generate_eNB_dlsch_params' below will + * overwrite first_rb and n_DMRS and 'generate_phich_top', done + * after 'generate_eNB_dlsch_params', would use the "new" values + * instead of the "old" ones. + * + * This has been tested for FDD only, may be wrong for TDD. + * + * TODO: maybe we should restructure the code to be sure it + * is done correctly. The main concern is if the code + * changes and first_rb and n_DMRS are modified before + * we reach here, then the PHICH processing will be wrong, + * using wrong first_rb and n_DMRS values to compute + * ngroup_PHICH and nseq_PHICH. + * + * TODO: check if that works with TDD. + */ + if ((subframe_select(fp,ul_subframe)==SF_UL) || + (fp->frame_type == FDD)) { + harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe); + eNB->ulsch[i]->harq_processes[harq_pid]->previous_first_rb = + eNB->ulsch[i]->harq_processes[harq_pid]->first_rb; + eNB->ulsch[i]->harq_processes[harq_pid]->previous_n_DMRS = + eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS; + } + } + } + +/* + // loop over all DCIs for this subframe to generate DLSCH allocations + for (i=0; i<DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci ; i++) { + LOG_D(PHY,"[eNB] Subframe %d: DCI %d/%d : rnti %x, CCEind %d\n",subframe,i,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci,DCI_pdu->dci_alloc[i].rnti,DCI_pdu->dci_alloc[i].firstCCE); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].rnti); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].format); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->dci_alloc[i].firstCCE); + dci_alloc = &DCI_pdu->dci_alloc[i]; + + if ((dci_alloc->rnti<= P_RNTI) && + (dci_alloc->ra_flag!=1)) { + if (eNB->mac_enabled==1) + UE_id = find_ue((int16_t)dci_alloc->rnti,eNB); + else + UE_id = i; + } + else UE_id=0; + + // generate_eNB_dlsch_params(eNB,proc,dci_alloc,UE_id); + + } +*/ + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,(frame*10)+subframe); +/* + // Apply physicalConfigDedicated if needed + // This is for UEs that have received this IE, which changes these DL and UL configuration, we apply after a delay for the eNodeB UL parameters + phy_config_dedicated_eNB_step2(eNB); + + // Now loop again over the DCIs for UL configuration + for (i=0; i<DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci ; i++) { + dci_alloc = &DCI_pdu->dci_alloc[i]; + + if (dci_alloc->format == format0) { // this is a ULSCH allocation + if (eNB->mac_enabled==1) + UE_id = find_ue((int16_t)dci_alloc->rnti,eNB); + else + UE_id = i; + + if (UE_id<0) { // should not happen, log an error and exit, this is a fatal error + LOG_E(PHY,"[eNB %"PRIu8"] Frame %d: Unknown UE_id for rnti %"PRIx16"\n",eNB->Mod_id,frame,dci_alloc->rnti); + mac_xface->macphy_exit("FATAL\n"); + } + //generate_eNB_ulsch_params(eNB,proc,dci_alloc,UE_id); + } + } + +*/ + + // if we have DCI to generate do it now + if ((DCI_pdu->Num_common_dci + DCI_pdu->Num_ue_spec_dci)>0) { + + + } else { // for emulation!! + eNB->num_ue_spec_dci[(subframe)&1]=0; + eNB->num_common_dci[(subframe)&1]=0; + } + +/* + if (eNB->abstraction_flag == 0) { + if (do_pdcch_flag) { + if (DCI_pdu->Num_ue_spec_dci+DCI_pdu->Num_common_dci > 0) { + LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (common %"PRIu8",ue_spec %"PRIu8")\n",eNB->Mod_id,frame, subframe, + DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci); + } + + num_pdcch_symbols = generate_dci_top(DCI_pdu->Num_ue_spec_dci, + DCI_pdu->Num_common_dci, + DCI_pdu->dci_alloc, + 0, + AMP, + fp, + eNB->common_vars.txdataF[0], + subframe); + } + else { + num_pdcch_symbols = DCI_pdu->num_pdcch_symbols; + LOG_D(PHY,"num_pdcch_symbols %"PRIu8" (dci common %"PRIu8", dci uespec %"PRIu8")\n",num_pdcch_symbols, + DCI_pdu->Num_common_dci,DCI_pdu->Num_ue_spec_dci); + } + } + +#ifdef PHY_ABSTRACTION // FIXME this ifdef seems suspicious + else { + LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_to_emul\n",eNB->Mod_id,frame, subframe); + num_pdcch_symbols = generate_dci_top_emul(eNB,DCI_pdu->Num_ue_spec_dci,DCI_pdu->Num_common_dci,DCI_pdu->dci_alloc,subframe); + } + +#endif +*/ + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,DCI_pdu->num_pdcch_symbols); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PDCCH_TX,0); +/* +#if defined(SMBV) + // Sets up PDCCH and DCI table + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4) && ((DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci)>0)) { + LOG_D(PHY,"[SMBV] Frame %3d, SF %d PDCCH, number of DCIs %d\n",frame,subframe,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci); + dump_dci(fp,&DCI_pdu->dci_alloc[0]); + // smbv_configure_pdcch(smbv_fname,(smbv_frame_cnt*10) + (subframe),num_pdcch_symbols,DCI_pdu->Num_common_dci+DCI_pdu->Num_ue_spec_dci); + } +#endif + + // Check for SI activity + //MP: eNB->dlsch_SI->active is set by the function generate_dlsch_params_from_dci (depending on the DCI content) + if ((eNB->dlsch_SI) && (eNB->dlsch_SI->active == 1)) { + + // pdsch_procedures(eNB,proc,eNB->dlsch_SI,(LTE_eNB_DLSCH_t*)NULL,(LTE_eNB_UE_stats*)NULL,0,num_pdcch_symbols); + +#if defined(SMBV) + + // Configures the data source of allocation (allocation is configured by DCI) + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, Configuring SI payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); + // smbv_configure_datalist_for_alloc(smbv_fname, smbv_alloc_cnt++, (smbv_frame_cnt*10) + (subframe), DLSCH_pdu, input_buffer_length); + } + +#endif + } +*/ + // Check for RA activity + if ((eNB->dlsch_ra) && (eNB->dlsch_ra->active == 1)) { +/* +#if defined(SMBV) + + // Configures the data source of allocation (allocation is configured by DCI) + if (smbv_is_config_frame(frame) && (smbv_frame_cnt < 4)) { + LOG_D(PHY,"[SMBV] Frame %3d, Configuring RA payload in SF %d alloc %"PRIu8"\n",frame,(smbv_frame_cnt*10) + (subframe),smbv_alloc_cnt); + smbv_configure_datalist_for_alloc(smbv_fname, smbv_alloc_cnt++, (smbv_frame_cnt*10) + (subframe), dlsch_input_buffer, input_buffer_length); + } + +#endif +*/ + + LOG_D(PHY,"[eNB %"PRIu8"][RAPROC] Frame %d, subframe %d: Calling generate_dlsch (RA),Msg3 frame %"PRIu32", Msg3 subframe %"PRIu8"\n", + eNB->Mod_id, + frame, subframe, + eNB->ulsch[(uint32_t)UE_id]->Msg3_frame, + eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe); + + // pdsch_procedures(eNB,proc,eNB->dlsch_ra,(LTE_eNB_DLSCH_t*)NULL,(LTE_eNB_UE_stats*)NULL,1,num_pdcch_symbols); + + eNB->dlsch_ra->active = 0; + } + + // Now scan UE specific DLSCH + for (UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) + { + if ((eNB->dlsch[(uint8_t)UE_id][0])&& + (eNB->dlsch[(uint8_t)UE_id][0]->rnti>0)&& + (eNB->dlsch[(uint8_t)UE_id][0]->active == 1)) { + + //pdsch_procedures(eNB,proc,eNB->dlsch[(uint8_t)UE_id][0],eNB->dlsch[(uint8_t)UE_id][1],&eNB->UE_stats[(uint32_t)UE_id],0,num_pdcch_symbols); + + } + + else if ((eNB->dlsch[(uint8_t)UE_id][0])&& + (eNB->dlsch[(uint8_t)UE_id][0]->rnti>0)&& + (eNB->dlsch[(uint8_t)UE_id][0]->active == 0)) { + + // clear subframe TX flag since UE is not scheduled for PDSCH in this subframe (so that we don't look for PUCCH later) + //eNB->dlsch[(uint8_t)UE_id][0]->subframe_tx[subframe]=0; + } + } + + // if we have PHICH to generate + + if (is_phich_subframe(fp,subframe)) + { + /* generate_phich_top(eNB, + proc, + AMP, + 0);*/ + } + + /* + if (frame>=10 && subframe>=9) { + write_output("/tmp/txsigF0.m","txsF0", &eNB->common_vars.txdataF[0][0][0],120*eNB->frame_parms.ofdm_symbol_size,1,1); + write_output("/tmp/txsigF1.m","txsF1", &eNB->common_vars.txdataF[0][0][0],120*eNB->frame_parms.ofdm_symbol_size,1,1); + abort(); + } + */ + +#ifdef EMOS + // phy_procedures_emos_eNB_TX(subframe, eNB); +#endif + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_TX+offset,0); + if (do_meas==1) stop_meas(&eNB->phy_proc_tx); + +} + +void process_Msg3(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,uint8_t UE_id, uint8_t harq_pid) +{ + // this prepares the demodulation of the first PUSCH of a new user, containing Msg3 + int subframe = proc->subframe_rx; + int frame = proc->frame_rx; + + LOG_D(PHY,"[eNB %d][RAPROC] frame %d : subframe %d : process_Msg3 UE_id %d (active %d, subframe %d, frame %d)\n", + eNB->Mod_id, + frame,subframe, + UE_id,eNB->ulsch[(uint32_t)UE_id]->Msg3_active, + eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe, + eNB->ulsch[(uint32_t)UE_id]->Msg3_frame); + eNB->ulsch[(uint32_t)UE_id]->Msg3_flag = 0; + + if ((eNB->ulsch[(uint32_t)UE_id]->Msg3_active == 1) && + (eNB->ulsch[(uint32_t)UE_id]->Msg3_subframe == subframe) && + (eNB->ulsch[(uint32_t)UE_id]->Msg3_frame == (uint32_t)frame)) { + + // harq_pid = 0; + + eNB->ulsch[(uint32_t)UE_id]->Msg3_active = 0; + eNB->ulsch[(uint32_t)UE_id]->Msg3_flag = 1; + eNB->ulsch[(uint32_t)UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag=1; + LOG_D(PHY,"[eNB %d][RAPROC] frame %d, subframe %d: Setting subframe_scheduling_flag (Msg3) for UE %d\n", + eNB->Mod_id, + frame,subframe,UE_id); + } +} + + +// This function retrieves the harq_pid of the corresponding DLSCH process +// and updates the error statistics of the DLSCH based on the received ACK +// info from UE along with the round index. It also performs the fine-grain +// rate-adaptation based on the error statistics derived from the ACK/NAK process + +void process_HARQ_feedback(uint8_t UE_id, + PHY_VARS_eNB *eNB, + eNB_rxtx_proc_t *proc, + uint8_t pusch_flag, + uint8_t *pucch_payload, + uint8_t pucch_sel, + uint8_t SR_payload) +{ + + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + uint8_t dl_harq_pid[8],dlsch_ACK[8],dl_subframe; + LTE_eNB_DLSCH_t *dlsch = eNB->dlsch[(uint32_t)UE_id][0]; + LTE_eNB_UE_stats *ue_stats = &eNB->UE_stats[(uint32_t)UE_id]; + LTE_DL_eNB_HARQ_t *dlsch_harq_proc; + uint8_t subframe_m4,M,m; + int mp; + int all_ACKed=1,nb_alloc=0,nb_ACK=0; + int frame = proc->frame_rx; + int subframe = proc->subframe_rx; + int harq_pid = subframe2harq_pid( fp,frame,subframe); + + if (fp->frame_type == FDD) { //FDD + subframe_m4 = (subframe<4) ? subframe+6 : subframe-4; + + dl_harq_pid[0] = dlsch->harq_ids[subframe_m4]; + M=1; + + if (pusch_flag == 1) { + dlsch_ACK[0] = eNB->ulsch[(uint8_t)UE_id]->harq_processes[harq_pid]->o_ACK[0]; + if (dlsch->subframe_tx[subframe_m4]==1) + LOG_D(PHY,"[eNB %d] Frame %d: Received ACK/NAK %d on PUSCH for subframe %d\n",eNB->Mod_id, + frame,dlsch_ACK[0],subframe_m4); + } + else { + dlsch_ACK[0] = pucch_payload[0]; + LOG_D(PHY,"[eNB %d] Frame %d: Received ACK/NAK %d on PUCCH for subframe %d\n",eNB->Mod_id, + frame,dlsch_ACK[0],subframe_m4); + /* + if (dlsch_ACK[0]==0) + AssertFatal(0,"Exiting on NAK on PUCCH\n"); + */ + } + + +#if defined(MESSAGE_CHART_GENERATOR_PHY) + MSC_LOG_RX_MESSAGE( + MSC_PHY_ENB,MSC_PHY_UE, + NULL,0, + "%05u:%02u %s received %s rnti %x harq id %u tx SF %u", + frame,subframe, + (pusch_flag == 1)?"PUSCH":"PUCCH", + (dlsch_ACK[0])?"ACK":"NACK", + dlsch->rnti, + dl_harq_pid[0], + subframe_m4 + ); +#endif + } else { // TDD Handle M=1,2 cases only + + M=ul_ACK_subframe2_M(fp, + subframe); + + // Now derive ACK information for TDD + if (pusch_flag == 1) { // Do PUSCH ACK/NAK first + // detect missing DAI + //FK: this code is just a guess + //RK: not exactly, yes if scheduled from PHICH (i.e. no DCI format 0) + // otherwise, it depends on how many of the PDSCH in the set are scheduled, we can leave it like this, + // but we have to adapt the code below. For example, if only one out of 2 are scheduled, only 1 bit o_ACK is used + + dlsch_ACK[0] = eNB->ulsch[(uint8_t)UE_id]->harq_processes[harq_pid]->o_ACK[0]; + dlsch_ACK[1] = (eNB->pucch_config_dedicated[UE_id].tdd_AckNackFeedbackMode == bundling) + ?eNB->ulsch[(uint8_t)UE_id]->harq_processes[harq_pid]->o_ACK[0]:eNB->ulsch[(uint8_t)UE_id]->harq_processes[harq_pid]->o_ACK[1]; + } + + else { // PUCCH ACK/NAK + if ((SR_payload == 1)&&(pucch_sel!=2)) { // decode Table 7.3 if multiplexing and SR=1 + nb_ACK = 0; + + if (M == 2) { + if ((pucch_payload[0] == 1) && (pucch_payload[1] == 1)) // b[0],b[1] + nb_ACK = 1; + else if ((pucch_payload[0] == 1) && (pucch_payload[1] == 0)) + nb_ACK = 2; + } else if (M == 3) { + if ((pucch_payload[0] == 1) && (pucch_payload[1] == 1)) + nb_ACK = 1; + else if ((pucch_payload[0] == 1) && (pucch_payload[1] == 0)) + nb_ACK = 2; + else if ((pucch_payload[0] == 0) && (pucch_payload[1] == 1)) + nb_ACK = 3; + } + } else if (pucch_sel == 2) { // bundling or M=1 + dlsch_ACK[0] = pucch_payload[0]; + dlsch_ACK[1] = pucch_payload[0]; + } else { // multiplexing with no SR, this is table 10.1 + if (M==1) + dlsch_ACK[0] = pucch_payload[0]; + else if (M==2) { + if (((pucch_sel == 1) && (pucch_payload[0] == 1) && (pucch_payload[1] == 1)) || + ((pucch_sel == 0) && (pucch_payload[0] == 0) && (pucch_payload[1] == 1))) + dlsch_ACK[0] = 1; + else + dlsch_ACK[0] = 0; + + if (((pucch_sel == 1) && (pucch_payload[0] == 1) && (pucch_payload[1] == 1)) || + ((pucch_sel == 1) && (pucch_payload[0] == 0) && (pucch_payload[1] == 0))) + dlsch_ACK[1] = 1; + else + dlsch_ACK[1] = 0; + } + } + } + } + + // handle case where positive SR was transmitted with multiplexing + if ((SR_payload == 1)&&(pucch_sel!=2)&&(pusch_flag == 0)) { + nb_alloc = 0; + + for (m=0; m<M; m++) { + dl_subframe = ul_ACK_subframe2_dl_subframe(fp, + subframe, + m); + + if (dlsch->subframe_tx[dl_subframe]==1) + nb_alloc++; + } + + if (nb_alloc == nb_ACK) + all_ACKed = 1; + else + all_ACKed = 0; + } + + + for (m=0,mp=-1; m<M; m++) { + + dl_subframe = ul_ACK_subframe2_dl_subframe(fp, + subframe, + m); + + if (dlsch->subframe_tx[dl_subframe]==1) { + if (pusch_flag == 1) + mp++; + else + mp = m; + + dl_harq_pid[m] = dlsch->harq_ids[dl_subframe]; + harq_pid_updated[UE_id][dl_harq_pid[m]] = 1; + + if ((pucch_sel != 2)&&(pusch_flag == 0)) { // multiplexing + if ((SR_payload == 1)&&(all_ACKed == 1)) + dlsch_ACK[m] = 1; + else + dlsch_ACK[m] = 0; + } + + if (dl_harq_pid[m]<dlsch->Mdlharq) { + dlsch_harq_proc = dlsch->harq_processes[dl_harq_pid[m]]; +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x/%d] subframe %d, status %d, round %d (mcs %d, rv %d, TBS %d)\n",eNB->Mod_id, + dlsch->rnti,dl_harq_pid[m],dl_subframe, + dlsch_harq_proc->status,dlsch_harq_proc->round, + dlsch->harq_processes[dl_harq_pid[m]]->mcs, + dlsch->harq_processes[dl_harq_pid[m]]->rvidx, + dlsch->harq_processes[dl_harq_pid[m]]->TBS); + + if (dlsch_harq_proc->status==DISABLED) + LOG_E(PHY,"dlsch_harq_proc is disabled? \n"); + +#endif + + if ((dl_harq_pid[m]<dlsch->Mdlharq) && + (dlsch_harq_proc->status == ACTIVE)) { + // dl_harq_pid of DLSCH is still active + + if ( dlsch_ACK[mp]==0) { + // Received NAK +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x/%d] M = %d, m= %d, mp=%d NAK Received in round %d, requesting retransmission\n",eNB->Mod_id, + dlsch->rnti,dl_harq_pid[m],M,m,mp,dlsch_harq_proc->round); +#endif + + T(T_ENB_PHY_DLSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), T_INT(dlsch->rnti), + T_INT(dl_harq_pid[m])); + + if (dlsch_harq_proc->round == 0) + ue_stats->dlsch_NAK_round0++; + + ue_stats->dlsch_NAK[dl_harq_pid[m]][dlsch_harq_proc->round]++; + + + // then Increment DLSCH round index + dlsch_harq_proc->round++; + + + if (dlsch_harq_proc->round == dlsch->Mlimit) { + // This was the last round for DLSCH so reset round and increment l2_error counter +#ifdef DEBUG_PHY_PROC + LOG_W(PHY,"[eNB %d][PDSCH %x/%d] DLSCH retransmissions exhausted, dropping packet\n",eNB->Mod_id, + dlsch->rnti,dl_harq_pid[m]); +#endif +#if defined(MESSAGE_CHART_GENERATOR_PHY) + MSC_LOG_EVENT(MSC_PHY_ENB, "0 HARQ DLSCH Failed RNTI %"PRIx16" round %u", + dlsch->rnti, + dlsch_harq_proc->round); +#endif + + dlsch_harq_proc->round = 0; + ue_stats->dlsch_l2_errors[dl_harq_pid[m]]++; + dlsch_harq_proc->status = SCH_IDLE; + dlsch->harq_ids[dl_subframe] = dlsch->Mdlharq; + } + } else { +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x/%d] ACK Received in round %d, resetting process\n",eNB->Mod_id, + dlsch->rnti,dl_harq_pid[m],dlsch_harq_proc->round); +#endif + + T(T_ENB_PHY_DLSCH_UE_ACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), T_INT(dlsch->rnti), + T_INT(dl_harq_pid[m])); + + ue_stats->dlsch_ACK[dl_harq_pid[m]][dlsch_harq_proc->round]++; + + // Received ACK so set round to 0 and set dlsch_harq_pid IDLE + dlsch_harq_proc->round = 0; + dlsch_harq_proc->status = SCH_IDLE; + dlsch->harq_ids[dl_subframe] = dlsch->Mdlharq; + + ue_stats->total_TBS = ue_stats->total_TBS + + eNB->dlsch[(uint8_t)UE_id][0]->harq_processes[dl_harq_pid[m]]->TBS; + /* + ue_stats->total_transmitted_bits = ue_stats->total_transmitted_bits + + eNB->dlsch[(uint8_t)UE_id][0]->harq_processes[dl_harq_pid[m]]->TBS; + */ + } + + // Do fine-grain rate-adaptation for DLSCH + if (ue_stats->dlsch_NAK_round0 > dlsch->error_threshold) { + if (ue_stats->dlsch_mcs_offset == 1) + ue_stats->dlsch_mcs_offset=0; + else + ue_stats->dlsch_mcs_offset=-1; + } + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[process_HARQ_feedback] Frame %d Setting round to %d for pid %d (subframe %d)\n",frame, + dlsch_harq_proc->round,dl_harq_pid[m],subframe); +#endif + harq_pid_round[UE_id][dl_harq_pid[m]] = dlsch_harq_proc->round; + // Clear NAK stats and adjust mcs offset + // after measurement window timer expires + if (ue_stats->dlsch_sliding_cnt == dlsch->ra_window_size) { + if ((ue_stats->dlsch_mcs_offset == 0) && (ue_stats->dlsch_NAK_round0 < 2)) + ue_stats->dlsch_mcs_offset = 1; + + if ((ue_stats->dlsch_mcs_offset == 1) && (ue_stats->dlsch_NAK_round0 > 2)) + ue_stats->dlsch_mcs_offset = 0; + + if ((ue_stats->dlsch_mcs_offset == 0) && (ue_stats->dlsch_NAK_round0 > 2)) + ue_stats->dlsch_mcs_offset = -1; + + if ((ue_stats->dlsch_mcs_offset == -1) && (ue_stats->dlsch_NAK_round0 < 2)) + ue_stats->dlsch_mcs_offset = 0; + + ue_stats->dlsch_NAK_round0 = 0; + ue_stats->dlsch_sliding_cnt = 0; + } + } + } + } + } +} + +void get_n1_pucch_eNB(PHY_VARS_eNB *eNB, + eNB_rxtx_proc_t *proc, + uint8_t UE_id, + int16_t *n1_pucch0, + int16_t *n1_pucch1, + int16_t *n1_pucch2, + int16_t *n1_pucch3) +{ + + LTE_DL_FRAME_PARMS *frame_parms=&eNB->frame_parms; + uint8_t nCCE0,nCCE1; + int sf; + int frame = proc->frame_rx; + int subframe = proc->subframe_rx; + + if (frame_parms->frame_type == FDD ) { + sf = (subframe<4) ? (subframe+6) : (subframe-4); + + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[sf]>0) { + *n1_pucch0 = frame_parms->pucch_config_common.n1PUCCH_AN + eNB->dlsch[(uint32_t)UE_id][0]->nCCE[sf]; + *n1_pucch1 = -1; + } else { + *n1_pucch0 = -1; + *n1_pucch1 = -1; + } + } else { + + switch (frame_parms->tdd_config) { + case 1: // DL:S:UL:UL:DL:DL:S:UL:UL:DL + if (subframe == 2) { // ACK subframes 5 and 6 + /* if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[6]>0) { + nCCE1 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[6]; + *n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN; + } + else + *n1_pucch1 = -1;*/ + + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[5]>0) { + nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[5]; + *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0+ frame_parms->pucch_config_common.n1PUCCH_AN; + } else + *n1_pucch0 = -1; + + *n1_pucch1 = -1; + } else if (subframe == 3) { // ACK subframe 9 + + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[9]>0) { + nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[9]; + *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 +frame_parms->pucch_config_common.n1PUCCH_AN; + } else + *n1_pucch0 = -1; + + *n1_pucch1 = -1; + + } else if (subframe == 7) { // ACK subframes 0 and 1 + //harq_ack[0].nCCE; + //harq_ack[1].nCCE; + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[0]>0) { + nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[0]; + *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 + frame_parms->pucch_config_common.n1PUCCH_AN; + } else + *n1_pucch0 = -1; + + *n1_pucch1 = -1; + } else if (subframe == 8) { // ACK subframes 4 + //harq_ack[4].nCCE; + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[4]>0) { + nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[4]; + *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 + frame_parms->pucch_config_common.n1PUCCH_AN; + } else + *n1_pucch0 = -1; + + *n1_pucch1 = -1; + } else { + LOG_D(PHY,"[eNB %d] frame %d: phy_procedures_lte.c: get_n1pucch, illegal subframe %d for tdd_config %d\n", + eNB->Mod_id, + frame, + subframe,frame_parms->tdd_config); + return; + } + + break; + + case 3: // DL:S:UL:UL:UL:DL:DL:DL:DL:DL + if (subframe == 2) { // ACK subframes 5,6 and 1 (S in frame-2), forget about n-11 for the moment (S-subframe) + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[6]>0) { + nCCE1 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[6]; + *n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN; + } else + *n1_pucch1 = -1; + + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[5]>0) { + nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[5]; + *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0+ frame_parms->pucch_config_common.n1PUCCH_AN; + } else + *n1_pucch0 = -1; + } else if (subframe == 3) { // ACK subframes 7 and 8 + LOG_D(PHY,"get_n1_pucch_eNB : subframe 3, subframe_tx[7] %d, subframe_tx[8] %d\n", + eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[7],eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[8]); + + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[8]>0) { + nCCE1 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[8]; + *n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN; + LOG_D(PHY,"nCCE1 %d, n1_pucch1 %d\n",nCCE1,*n1_pucch1); + } else + *n1_pucch1 = -1; + + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[7]>0) { + nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[7]; + *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 +frame_parms->pucch_config_common.n1PUCCH_AN; + LOG_D(PHY,"nCCE0 %d, n1_pucch0 %d\n",nCCE0,*n1_pucch0); + } else + *n1_pucch0 = -1; + } else if (subframe == 4) { // ACK subframes 9 and 0 + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[0]>0) { + nCCE1 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[0]; + *n1_pucch1 = get_Np(frame_parms->N_RB_DL,nCCE1,1) + nCCE1 + frame_parms->pucch_config_common.n1PUCCH_AN; + } else + *n1_pucch1 = -1; + + if (eNB->dlsch[(uint32_t)UE_id][0]->subframe_tx[9]>0) { + nCCE0 = eNB->dlsch[(uint32_t)UE_id][0]->nCCE[9]; + *n1_pucch0 = get_Np(frame_parms->N_RB_DL,nCCE0,0) + nCCE0 +frame_parms->pucch_config_common.n1PUCCH_AN; + } else + *n1_pucch0 = -1; + } else { + LOG_D(PHY,"[eNB %d] Frame %d: phy_procedures_lte.c: get_n1pucch, illegal subframe %d for tdd_config %d\n", + eNB->Mod_id,frame,subframe,frame_parms->tdd_config); + return; + } + + break; + } // switch tdd_config + + // Don't handle the case M>2 + *n1_pucch2 = -1; + *n1_pucch3 = -1; + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////// NB-IoT testing //////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void prach_procedures_NB_IoT(PHY_VARS_eNB *eNB) { + // LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + // uint16_t preamble_energy_list[64],preamble_delay_list[64]; + // uint16_t preamble_max,preamble_energy_max; + // uint16_t preamble_max=0; + // uint16_t i; + // int8_t UE_id; + uint16_t rnti[4],preamble_index[4],timing_advance_preamble[4]; + // uint16_t i; + // int frame,subframe; + + uint8_t subframe = eNB->proc.subframe_prach; + int frame = eNB->proc.frame_prach; + // uint8_t CC_id = eNB->CC_id; + uint32_t detection=0; + //uint16_t estimated_TA=2; + + if (eNB->abstraction_flag == 0) { + /* rx_prach(eNB, + preamble_energy_list, + preamble_delay_list, + frame, + 0);*/ + detection = rx_nprach_NB_IoT(eNB,frame,subframe,rnti,preamble_index,timing_advance_preamble); + } + + if(detection == 1) ////////////////////////// to be moved to handle_rach_NB_IoT + { + + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + ////////////////////////////////////////////////////////// + eNB->UL_INFO.nrach_ind.number_of_initial_scs_detected = 1; //!!!!!!!!!!!!! // should be set to zero in every call of UL_indication !!!!!!!!!!!!!!!!!!!!!!! + eNB->UL_INFO.nrach_ind.nrach_pdu_list[0].nrach_indication_rel13.rnti = rnti[0]; + eNB->UL_INFO.nrach_ind.nrach_pdu_list[0].nrach_indication_rel13.initial_sc = preamble_index[0]; + eNB->UL_INFO.nrach_ind.nrach_pdu_list[0].nrach_indication_rel13.timing_advance = timing_advance_preamble[0]; + eNB->UL_INFO.nrach_ind.nrach_pdu_list[0].nrach_indication_rel13.nrach_ce_level = 2; + + eNB->UL_INFO.frame = frame; + eNB->UL_INFO.subframe = subframe; + eNB->UL_INFO.hypersfn = eNB->proc.proc_rxtx[0].HFN; + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + + /*initiate_ra_proc(UL_info->module_id, + UL_info->CC_id, + NFAPI_SFNSF2SFN(UL_info->rach_ind.sfn_sf), + NFAPI_SFNSF2SF(UL_info->rach_ind.sfn_sf), + UL_info->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.preamble, + UL_info->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.timing_advance, + UL_info->rach_ind.rach_indication_body.preamble_list[0].preamble_rel8.rnti); + mac_xface->initiate_ra_proc(eNB->Mod_id, + eNB->CC_id, + frame, + preamble_index[0], + (int16_t) timing_advance_preamble[0], + 0,subframe,0);*/ + } + +} +//////////////////////////////////////////////////////////// END /////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void prach_procedures(PHY_VARS_eNB *eNB) { + + // LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + // uint16_t preamble_energy_list[64],preamble_delay_list[64]; + // uint16_t preamble_max,preamble_energy_max; + // uint16_t preamble_max=0; + // uint16_t i; + // int8_t UE_id; + int subframe = eNB->proc.subframe_prach; + int frame = eNB->proc.frame_prach; + // uint8_t CC_id = eNB->CC_id; + + + uint32_t detection=0; + uint16_t estimated_TA=2; + /*VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1); + memset(&preamble_energy_list[0],0,64*sizeof(uint16_t)); + memset(&preamble_delay_list[0],0,64*sizeof(uint16_t));*/ + + if (eNB->abstraction_flag == 0) { + /*LOG_D(PHY,"[eNB %d][RAPROC] Frame %d, Subframe %d : PRACH RX Signal Power : %d dBm\n",eNB->Mod_id, + frame,subframe,dB_fixed(signal_energy(&eNB->common_vars.rxdata[0][0][subframe*fp->samples_per_tti],512)) - eNB->rx_total_gain_dB); + + + rx_prach(eNB, + preamble_energy_list, + preamble_delay_list, + frame, + 0);*/ + //usleep(100); + + //detection = rx_nprach_NB_IoT(eNB); + // detection = rx_nprach_NB_IoT(eNB,frame,subframe,rnti,preamble_index,timing_advance_preamble); + + /* } else { + for (UE_id=0; UE_id<NB_UE_INST; UE_id++) { + + LOG_D(PHY,"[RAPROC] UE_id %d (%p), generate_prach %d, UE RSI %d, eNB RSI %d preamble index %d\n", + UE_id,PHY_vars_UE_g[UE_id][CC_id],PHY_vars_UE_g[UE_id][CC_id]->generate_prach, + PHY_vars_UE_g[UE_id][CC_id]->frame_parms.prach_config_common.rootSequenceIndex, + fp->prach_config_common.rootSequenceIndex, + PHY_vars_UE_g[UE_id][CC_id]->prach_PreambleIndex); + + if ((PHY_vars_UE_g[UE_id][CC_id]->generate_prach==1) && + (PHY_vars_UE_g[UE_id][CC_id]->frame_parms.prach_config_common.rootSequenceIndex == + fp->prach_config_common.rootSequenceIndex) ) { + preamble_energy_list[PHY_vars_UE_g[UE_id][CC_id]->prach_PreambleIndex] = 800; + preamble_delay_list[PHY_vars_UE_g[UE_id][CC_id]->prach_PreambleIndex] = 5; + + } + } */ + } + + /*preamble_energy_max = preamble_energy_list[0]; + preamble_max = 0; + + for (i=1; i<64; i++) { + if (preamble_energy_max < preamble_energy_list[i]) { + preamble_energy_max = preamble_energy_list[i]; + preamble_max = i; + } + } + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[RAPROC] Most likely preamble %d, energy %d dB delay %d\n", + preamble_max, + preamble_energy_list[preamble_max], + preamble_delay_list[preamble_max]); +#endif + + if (preamble_energy_list[preamble_max] > 580) { + + UE_id = find_next_ue_index(eNB); + + if (UE_id>=0) { + eNB->UE_stats[(uint32_t)UE_id].UE_timing_offset = preamble_delay_list[preamble_max]&0x1FFF; //limit to 13 (=11+2) bits + + eNB->UE_stats[(uint32_t)UE_id].sector = 0; + LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure (UE_id %d) with preamble %d, energy %d.%d dB, delay %d\n", + eNB->Mod_id, + eNB->CC_id, + frame, + subframe, + UE_id, + preamble_max, + preamble_energy_max/10, + preamble_energy_max%10, + preamble_delay_list[preamble_max]); + + T(T_ENB_PHY_INITIATE_RA_PROCEDURE, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(UE_id), + T_INT(preamble_max), T_INT(preamble_energy_max), T_INT(preamble_delay_list[preamble_max])); + + if (eNB->mac_enabled==1) { + uint8_t update_TA = 4; + uint8_t update_TA2 = 1; + switch (fp->N_RB_DL) { + case 6: + update_TA = 16; + break; + + case 25: + update_TA = 4; + break; + + case 50: + update_TA = 2; + break; + + case 75: + update_TA = 3; + update_TA2 = 2; + case 100: + update_TA = 1; + break; + } + + */ + /////////////////////////////////////////// NB-IoT testing ////////////////////////// + if(detection == 1) + { + mac_xface->initiate_ra_proc(eNB->Mod_id, + eNB->CC_id, + frame, + eNB->preamble_index_NB_IoT, + estimated_TA, + 0,subframe,0); + + } + ///////////////////////////////////////////////////////////////////////////////////// +/* + mac_xface->initiate_ra_proc(eNB->Mod_id, + eNB->CC_id, + frame, + preamble_max, + preamble_delay_list[preamble_max]*update_TA/update_TA2, + 0,subframe,0); + } + + } else { + MSC_LOG_EVENT(MSC_PHY_ENB, "0 RA Failed add user, too many"); + LOG_I(PHY,"[eNB %d][RAPROC] frame %d, subframe %d: Unable to add user, max user count reached\n", + eNB->Mod_id,frame, subframe); + } + } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0);*/ +} + +void pucch_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,int UE_id,int harq_pid,uint8_t do_srs) +{ + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + uint8_t SR_payload = 0,*pucch_payload=NULL,pucch_payload0[2]= {0,0},pucch_payload1[2]= {0,0}; + int16_t n1_pucch0 = -1, n1_pucch1 = -1, n1_pucch2 = -1, n1_pucch3 = -1; + uint8_t do_SR = 0; + uint8_t pucch_sel = 0; + int32_t metric0=0,metric1=0,metric0_SR=0; + ANFBmode_t bundling_flag; + PUCCH_FMT_t format; + const int subframe = proc->subframe_rx; + const int frame = proc->frame_rx; + + if ((eNB->dlsch[UE_id][0]) && + (eNB->dlsch[UE_id][0]->rnti>0) && + (eNB->ulsch[UE_id]->harq_processes[harq_pid]->subframe_scheduling_flag==0)) { + + // check SR availability + do_SR = is_SR_subframe(eNB,proc,UE_id); + // do_SR = 0; + + // Now ACK/NAK + // First check subframe_tx flag for earlier subframes + + get_n1_pucch_eNB(eNB, + proc, + UE_id, + &n1_pucch0, + &n1_pucch1, + &n1_pucch2, + &n1_pucch3); + + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d, subframe %d Checking for PUCCH (%d,%d,%d,%d) SR %d\n", + eNB->Mod_id,eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,do_SR); + + if ((n1_pucch0==-1) && (n1_pucch1==-1) && (do_SR==0)) { // no TX PDSCH that have to be checked and no SR for this UE_id + } else { + // otherwise we have some PUCCH detection to do + + // Null out PUCCH PRBs for noise measurement + switch(fp->N_RB_UL) { + case 6: + eNB->rb_mask_ul[0] |= (0x1 | (1<<5)); //position 5 + break; + case 15: + eNB->rb_mask_ul[0] |= (0x1 | (1<<14)); // position 14 + break; + case 25: + eNB->rb_mask_ul[0] |= (0x1 | (1<<24)); // position 24 + break; + case 50: + eNB->rb_mask_ul[0] |= 0x1; + eNB->rb_mask_ul[1] |= (1<<17); // position 49 (49-32) + break; + case 75: + eNB->rb_mask_ul[0] |= 0x1; + eNB->rb_mask_ul[2] |= (1<<10); // position 74 (74-64) + break; + case 100: + eNB->rb_mask_ul[0] |= 0x1; + eNB->rb_mask_ul[3] |= (1<<3); // position 99 (99-96) + break; + default: + LOG_E(PHY,"Unknown number for N_RB_UL %d\n",fp->N_RB_UL); + break; + } + + if (do_SR == 1) { + eNB->UE_stats[UE_id].sr_total++; + + + if (eNB->abstraction_flag == 0) { + metric0_SR = rx_pucch(eNB, + pucch_format1, + UE_id, + eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, + 0, // n2_pucch + do_srs, // shortened format + &SR_payload, + frame, + subframe, + PUCCH1_THRES); + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking SR is %d (SR n1pucch is %d)\n", + eNB->Mod_id, + eNB->ulsch[UE_id]->rnti, + frame, + subframe, + SR_payload, + eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex); + } +#ifdef PHY_ABSTRACTION + else { + metric0_SR = rx_pucch_emul(eNB, + proc, + UE_id, + pucch_format1, + 0, + &SR_payload); + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Checking SR (UE SR %d/%d)\n",eNB->Mod_id, + eNB->ulsch[UE_id]->rnti,frame,subframe,SR_payload,eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex); + } +#endif + }// do_SR==1 + + if ((n1_pucch0==-1) && (n1_pucch1==-1)) { // just check for SR + } else if (fp->frame_type==FDD) { // FDD + // if SR was detected, use the n1_pucch from SR, else use n1_pucch0 + // n1_pucch0 = (SR_payload==1) ? eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex:n1_pucch0; + + LOG_D(PHY,"Demodulating PUCCH for ACK/NAK: n1_pucch0 %d (%d), SR_payload %d\n",n1_pucch0,eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex,SR_payload); + + if (eNB->abstraction_flag == 0) { + metric0 = rx_pucch(eNB, + pucch_format1a, + UE_id, + (uint16_t)n1_pucch0, + 0, //n2_pucch + do_srs, // shortened format + pucch_payload0, + frame, + subframe, + PUCCH1a_THRES); + } +#ifdef PHY_ABSTRACTION + else { + metric0 = rx_pucch_emul(eNB, + proc, + UE_id, + pucch_format1a, + 0, + pucch_payload0); + } +#endif + + /* cancel SR detection if reception on n1_pucch0 is better than on SR PUCCH resource index */ + if (do_SR && metric0 > metric0_SR) SR_payload = 0; + + if (do_SR && metric0 <= metric0_SR) { + /* when transmitting ACK/NACK on SR PUCCH resource index, SR payload is always 1 */ + SR_payload = 1; + + if (eNB->abstraction_flag == 0) { + metric0=rx_pucch(eNB, + pucch_format1a, + UE_id, + eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, + 0, //n2_pucch + do_srs, // shortened format + pucch_payload0, + frame, + subframe, + PUCCH1a_THRES); + } +#ifdef PHY_ABSTRACTION + else { + metric0 = rx_pucch_emul(eNB, + proc, + UE_id, + pucch_format1a, + 0, + pucch_payload0); + } +#endif + } + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d pucch1a (FDD) payload %d (metric %d)\n", + eNB->Mod_id, + eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + pucch_payload0[0],metric0); +#endif + + process_HARQ_feedback(UE_id,eNB,proc, + 0,// pusch_flag + pucch_payload0, + 2, + SR_payload); + } // FDD + else { //TDD + + bundling_flag = eNB->pucch_config_dedicated[UE_id].tdd_AckNackFeedbackMode; + + // fix later for 2 TB case and format1b + + if ((fp->frame_type==FDD) || + (bundling_flag==bundling) || + ((fp->frame_type==TDD)&&(fp->tdd_config==1)&&((subframe!=2)&&(subframe!=7)))) { + format = pucch_format1a; + } else { + format = pucch_format1b; + } + + // if SR was detected, use the n1_pucch from SR + if (SR_payload==1) { +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK (%d,%d,%d,%d) format %d with SR\n",eNB->Mod_id, + eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,format); +#endif + + if (eNB->abstraction_flag == 0) + metric0 = rx_pucch(eNB, + format, + UE_id, + eNB->scheduling_request_config[UE_id].sr_PUCCH_ResourceIndex, + 0, //n2_pucch + do_srs, // shortened format + pucch_payload0, + frame, + subframe, + PUCCH1a_THRES); + else { +#ifdef PHY_ABSTRACTION + metric0 = rx_pucch_emul(eNB,proc, + UE_id, + format, + 0, + pucch_payload0); +#endif + } + } else { //using n1_pucch0/n1_pucch1 resources +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d Checking ACK/NAK (%d,%d,%d,%d) format %d\n",eNB->Mod_id, + eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + n1_pucch0,n1_pucch1,n1_pucch2,n1_pucch3,format); +#endif + metric0=0; + metric1=0; + + // Check n1_pucch0 metric + if (n1_pucch0 != -1) { + if (eNB->abstraction_flag == 0) + metric0 = rx_pucch(eNB, + format, + UE_id, + (uint16_t)n1_pucch0, + 0, // n2_pucch + do_srs, // shortened format + pucch_payload0, + frame, + subframe, + PUCCH1a_THRES); + else { +#ifdef PHY_ABSTRACTION + metric0 = rx_pucch_emul(eNB, + proc, + UE_id, + format, + 0, + pucch_payload0); +#endif + } + } + + // Check n1_pucch1 metric + if (n1_pucch1 != -1) { + if (eNB->abstraction_flag == 0) + metric1 = rx_pucch(eNB, + format, + UE_id, + (uint16_t)n1_pucch1, + 0, //n2_pucch + do_srs, // shortened format + pucch_payload1, + frame, + subframe, + PUCCH1a_THRES); + else { +#ifdef PHY_ABSTRACTION + metric1 = rx_pucch_emul(eNB, + proc, + UE_id, + format, + 1, + pucch_payload1); +#endif + } + } + } + + if (SR_payload == 1) { + pucch_payload = pucch_payload0; + + if (bundling_flag == bundling) + pucch_sel = 2; + } else if (bundling_flag == multiplexing) { // multiplexing + no SR + pucch_payload = (metric1>metric0) ? pucch_payload1 : pucch_payload0; + pucch_sel = (metric1>metric0) ? 1 : 0; + } else { // bundling + no SR + if (n1_pucch1 != -1) + pucch_payload = pucch_payload1; + else if (n1_pucch0 != -1) + pucch_payload = pucch_payload0; + + pucch_sel = 2; // indicate that this is a bundled ACK/NAK + } + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d ACK/NAK metric 0 %d, metric 1 %d, sel %d, (%d,%d)\n",eNB->Mod_id, + eNB->dlsch[UE_id][0]->rnti, + frame,subframe, + metric0,metric1,pucch_sel,pucch_payload[0],pucch_payload[1]); +#endif + process_HARQ_feedback(UE_id,eNB,proc, + 0,// pusch_flag + pucch_payload, + pucch_sel, + SR_payload); + } // TDD + } + + if (SR_payload == 1) { + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n",eNB->Mod_id, + eNB->ulsch[UE_id]->rnti,frame,subframe); + eNB->UE_stats[UE_id].sr_received++; + + if (eNB->first_sr[UE_id] == 1) { // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4 + eNB->first_sr[UE_id] = 0; + eNB->dlsch[UE_id][0]->harq_processes[0]->round=0; + eNB->dlsch[UE_id][0]->harq_processes[0]->status=SCH_IDLE; + LOG_D(PHY,"[eNB %d][SR %x] Frame %d subframe %d First SR\n", + eNB->Mod_id, + eNB->ulsch[UE_id]->rnti,frame,subframe); + } + + if (eNB->mac_enabled==1) { + mac_xface->SR_indication(eNB->Mod_id, + eNB->CC_id, + frame, + eNB->dlsch[UE_id][0]->rnti,subframe); + } + } + } +} + + +void cba_procedures(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,int UE_id,int harq_pid) { + + uint8_t access_mode; + int num_active_cba_groups; + const int subframe = proc->subframe_rx; + const int frame = proc->frame_rx; + uint16_t rnti=0; + int ret=0; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + if (eNB->ulsch[UE_id]==NULL) return; + + num_active_cba_groups = eNB->ulsch[UE_id]->num_active_cba_groups; + + if ((num_active_cba_groups > 0) && + (eNB->ulsch[UE_id]->cba_rnti[UE_id%num_active_cba_groups]>0) && + (eNB->ulsch[UE_id]->harq_processes[harq_pid]->subframe_cba_scheduling_flag==1)) { + rnti=0; + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d Checking PUSCH/ULSCH CBA Reception for UE %d with cba rnti %x mode %s\n", + eNB->Mod_id,harq_pid, + frame,subframe, + UE_id, (uint16_t)eNB->ulsch[UE_id]->cba_rnti[UE_id%num_active_cba_groups],mode_string[eNB->UE_stats[UE_id].mode]); +#endif + + if (eNB->abstraction_flag==0) { + rx_ulsch(eNB,proc, + eNB->UE_stats[UE_id].sector, // this is the effective sector id + UE_id, + eNB->ulsch, + 0); + } + +#ifdef PHY_ABSTRACTION + else { + rx_ulsch_emul(eNB,proc, + eNB->UE_stats[UE_id].sector, // this is the effective sector id + UE_id); + } + +#endif + + if (eNB->abstraction_flag == 0) { + ret = ulsch_decoding(eNB,proc, + UE_id, + 0, // control_only_flag + eNB->ulsch[UE_id]->harq_processes[harq_pid]->V_UL_DAI, + eNB->ulsch[UE_id]->harq_processes[harq_pid]->nb_rb>20 ? 1 : 0); + } + +#ifdef PHY_ABSTRACTION + else { + ret = ulsch_decoding_emul(eNB, + proc, + UE_id, + &rnti); + } + +#endif + + if (eNB->ulsch[UE_id]->harq_processes[harq_pid]->cqi_crc_status == 1) { +#ifdef DEBUG_PHY_PROC + + print_CQI(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o,eNB->ulsch[UE_id]->harq_processes[harq_pid]->uci_format,0,fp->N_RB_DL); +#endif + access_mode = UNKNOWN_ACCESS; + extract_CQI(eNB->ulsch[UE_id]->harq_processes[harq_pid]->o, + eNB->ulsch[UE_id]->harq_processes[harq_pid]->uci_format, + &eNB->UE_stats[UE_id], + fp->N_RB_DL, + &rnti, &access_mode); + eNB->UE_stats[UE_id].rank = eNB->ulsch[UE_id]->harq_processes[harq_pid]->o_RI[0]; + } + + eNB->ulsch[UE_id]->harq_processes[harq_pid]->subframe_cba_scheduling_flag=0; + eNB->ulsch[UE_id]->harq_processes[harq_pid]->status= SCH_IDLE; + + if ((num_active_cba_groups > 0) && + (UE_id + num_active_cba_groups < NUMBER_OF_UE_MAX) && + (eNB->ulsch[UE_id+num_active_cba_groups]->cba_rnti[UE_id%num_active_cba_groups] > 0 ) && + (eNB->ulsch[UE_id+num_active_cba_groups]->num_active_cba_groups> 0)) { +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d harq_pid %d resetting the subframe_scheduling_flag for Ue %d cba groups %d members\n", + eNB->Mod_id,harq_pid,frame,subframe,UE_id,harq_pid, + UE_id+num_active_cba_groups, UE_id%eNB->ulsch[UE_id]->num_active_cba_groups); +#endif + eNB->ulsch[UE_id+num_active_cba_groups]->harq_processes[harq_pid]->subframe_cba_scheduling_flag=1; + eNB->ulsch[UE_id+num_active_cba_groups]->harq_processes[harq_pid]->status= CBA_ACTIVE; + eNB->ulsch[UE_id+num_active_cba_groups]->harq_processes[harq_pid]->TBS=eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS; + } + + if (ret == (1+MAX_TURBO_ITERATIONS)) { + eNB->UE_stats[UE_id].ulsch_round_errors[harq_pid][eNB->ulsch[UE_id]->harq_processes[harq_pid]->round]++; + eNB->ulsch[UE_id]->harq_processes[harq_pid]->phich_active = 1; + eNB->ulsch[UE_id]->harq_processes[harq_pid]->phich_ACK = 0; + eNB->ulsch[UE_id]->harq_processes[harq_pid]->round++; + } // ulsch in error + else { + LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d subframe %d ULSCH received, setting round to 0, PHICH ACK\n", + eNB->Mod_id,harq_pid, + frame,subframe); + + eNB->ulsch[UE_id]->harq_processes[harq_pid]->phich_active = 1; + eNB->ulsch[UE_id]->harq_processes[harq_pid]->phich_ACK = 1; + eNB->ulsch[UE_id]->harq_processes[harq_pid]->round = 0; + eNB->UE_stats[UE_id].ulsch_consecutive_errors = 0; +#ifdef DEBUG_PHY_PROC +#ifdef DEBUG_ULSCH + LOG_D(PHY,"[eNB] Frame %d, Subframe %d : ULSCH SDU (RX harq_pid %d) %d bytes:", + frame,subframe, + harq_pid,eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3); + + for (j=0; j<eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3; j++) + LOG_T(PHY,"%x.",eNB->ulsch[UE_id]->harq_processes[harq_pid]->b[j]); + + LOG_T(PHY,"\n"); +#endif +#endif + + if (access_mode > UNKNOWN_ACCESS) { + LOG_D(PHY,"[eNB %d] Frame %d, Subframe %d : received ULSCH SDU from CBA transmission, UE (%d,%x), CBA (group %d, rnti %x)\n", + eNB->Mod_id, frame,subframe, + UE_id, eNB->ulsch[UE_id]->rnti, + UE_id % eNB->ulsch[UE_id]->num_active_cba_groups, eNB->ulsch[UE_id]->cba_rnti[UE_id%num_active_cba_groups]); + + // detect if there is a CBA collision + if ((eNB->cba_last_reception[UE_id%num_active_cba_groups] == 0 ) && + (eNB->mac_enabled==1)) { + mac_xface->rx_sdu(eNB->Mod_id, + eNB->CC_id, + frame,subframe, + eNB->ulsch[UE_id]->rnti, + eNB->ulsch[UE_id]->harq_processes[harq_pid]->b, + eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3, + harq_pid, + NULL); + + eNB->cba_last_reception[UE_id%num_active_cba_groups]+=1;//(subframe); + } else { + if (eNB->cba_last_reception[UE_id%num_active_cba_groups] == 1 ) + LOG_N(PHY,"[eNB%d] Frame %d subframe %d : first CBA collision detected \n ", + eNB->Mod_id,frame,subframe); + + LOG_N(PHY,"[eNB%d] Frame %d subframe %d : CBA collision set SR for UE %d in group %d \n ", + eNB->Mod_id,frame,subframe, + eNB->cba_last_reception[UE_id%num_active_cba_groups],UE_id%num_active_cba_groups ); + + eNB->cba_last_reception[UE_id%num_active_cba_groups]+=1; + + mac_xface->SR_indication(eNB->Mod_id, + eNB->CC_id, + frame, + eNB->dlsch[UE_id][0]->rnti,subframe); + } + } // UNKNOWN_ACCESS + } // ULSCH CBA not in error + } + +} + +typedef struct { + PHY_VARS_eNB *eNB; + int slot; +} fep_task; + +void fep0(PHY_VARS_eNB *eNB,int slot) { + + eNB_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + int l; + + // printf("fep0: slot %d\n",slot); + + remove_7_5_kHz(eNB,(slot&1)+(proc->subframe_rx<<1)); + for (l=0; l<fp->symbols_per_tti/2; l++) { + slot_fep_ul(fp, + &eNB->common_vars, + l, + (slot&1)+(proc->subframe_rx<<1), + 0, + 0 + ); + } +} + + + +extern int oai_exit; + +static void *fep_thread(void *param) { + + pthread_setname_np( pthread_self(), "UEfep"); + PHY_VARS_eNB *eNB = (PHY_VARS_eNB *)param; + eNB_proc_t *proc = &eNB->proc; + while (!oai_exit) { + + if (wait_on_condition(&proc->mutex_fep,&proc->cond_fep,&proc->instance_cnt_fep,"fep thread")<0) break; + fep0(eNB,0); + if (release_thread(&proc->mutex_fep,&proc->instance_cnt_fep,"fep thread")<0) break; + + if (pthread_cond_signal(&proc->cond_fep) != 0) { + printf("[eNB] ERROR pthread_cond_signal for fep thread exit\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return NULL; + } + } + + + + return(NULL); +} + +void init_fep_thread(PHY_VARS_eNB *eNB,pthread_attr_t *attr_fep) { + + eNB_proc_t *proc = &eNB->proc; + + proc->instance_cnt_fep = -1; + + pthread_mutex_init( &proc->mutex_fep, NULL); + pthread_cond_init( &proc->cond_fep, NULL); + + pthread_create(&proc->pthread_fep, attr_fep, fep_thread, (void*)eNB); + + +} + +/* +extern void *td_thread(void*); + +void init_td_thread(PHY_VARS_eNB *eNB,pthread_attr_t *attr_td) { + + eNB_proc_t *proc = &eNB->proc; + + proc->tdp.eNB = eNB; + proc->instance_cnt_td = -1; + + pthread_mutex_init( &proc->mutex_td, NULL); + pthread_cond_init( &proc->cond_td, NULL); + + pthread_create(&proc->pthread_td, attr_td, td_thread, (void*)&proc->tdp); + +} + + +extern void *te_thread(void*); + +void init_te_thread(PHY_VARS_eNB *eNB,pthread_attr_t *attr_te) { + + eNB_proc_t *proc = &eNB->proc; + + proc->tep.eNB = eNB; + proc->instance_cnt_te = -1; + + pthread_mutex_init( &proc->mutex_te, NULL); + pthread_cond_init( &proc->cond_te, NULL); + + printf("Creating te_thread\n"); + pthread_create(&proc->pthread_te, attr_te, te_thread, (void*)&proc->tep); + +} +*/ + +void eNB_fep_full_2thread(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc_rxtx) { + + eNB_proc_t *proc = &eNB->proc; + + struct timespec wait; + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP,1); + start_meas(&eNB->ofdm_demod_stats); + + if (pthread_mutex_timedlock(&proc->mutex_fep,&wait) != 0) { + printf("[eNB] ERROR pthread_mutex_lock for fep thread (IC %d)\n", proc->instance_cnt_fep); + exit_fun( "error locking mutex_fep" ); + return; + } + + if (proc->instance_cnt_fep==0) { + printf("[eNB] FEP thread busy\n"); + exit_fun("FEP thread busy"); + pthread_mutex_unlock( &proc->mutex_fep ); + return; + } + + ++proc->instance_cnt_fep; + + + if (pthread_cond_signal(&proc->cond_fep) != 0) { + printf("[eNB] ERROR pthread_cond_signal for fep thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return; + } + + pthread_mutex_unlock( &proc->mutex_fep ); + + // call second slot in this symbol + fep0(eNB,1); + + wait_on_busy_condition(&proc->mutex_fep,&proc->cond_fep,&proc->instance_cnt_fep,"fep thread"); + + stop_meas(&eNB->ofdm_demod_stats); +} + + + +void eNB_fep_full(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc_rxtx) { + + int l; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP,1); + start_meas(&eNB->ofdm_demod_stats); + remove_7_5_kHz(eNB,proc_rxtx->subframe_rx<<1); + remove_7_5_kHz(eNB,1+(proc_rxtx->subframe_rx<<1)); + for (l=0; l<fp->symbols_per_tti/2; l++) { + slot_fep_ul(fp, + &eNB->common_vars, + l, + (proc_rxtx->subframe_rx)<<1, + 0, + 0 + ); + slot_fep_ul(fp, + &eNB->common_vars, + l, + 1+((proc_rxtx->subframe_rx)<<1), + 0, + 0 + ); + } + stop_meas(&eNB->ofdm_demod_stats); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_SLOT_FEP,0); + + if (eNB->node_function == NGFI_RRU_IF4p5) { + /// **** send_IF4 of rxdataF to RCC (no prach now) **** /// + LOG_D(PHY,"send_IF4p5 (PULFFT): frame %d, subframe %d\n",proc_rxtx->frame_rx,proc_rxtx->subframe_rx); + send_IF4p5(eNB, proc_rxtx->frame_rx, proc_rxtx->subframe_rx, IF4p5_PULFFT, 0); + start_fh_prev = start_fh; + start_fh_prev_sf = start_fh_sf; + clock_gettime( CLOCK_MONOTONIC, &start_fh); + start_fh_sf = proc_rxtx->subframe_rx; + } +} + +void eNB_fep_rru_if5(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc_rxtx) { + + eNB_proc_t *proc=&eNB->proc; + uint8_t seqno=0; + + /// **** send_IF5 of rxdata to BBU **** /// + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 ); + send_IF5(eNB, proc->timestamp_rx, proc->subframe_rx, &seqno, IF5_RRH_GW_UL); + start_fh_prev = start_fh; + start_fh_prev_sf = start_fh_sf; + clock_gettime( CLOCK_MONOTONIC, &start_fh); + start_fh_sf = proc->subframe_rx; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 ); + +} + +void do_prach(PHY_VARS_eNB *eNB,int frame,int subframe) { + + eNB_proc_t *proc = &eNB->proc; + // LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + +if(frame%2==0 && subframe==9) +{ + // check if we have to detect PRACH first + //if (is_prach_subframe(fp,frame,subframe)>0) { + /* accept some delay in processing - up to 5ms */ + int i; + for (i = 0; i < 10 && proc->instance_cnt_prach == 0; i++) { + LOG_W(PHY,"[eNB] Frame %d Subframe %d, eNB PRACH thread busy (IC %d)!!\n", frame,subframe,proc->instance_cnt_prach); + usleep(500); + } + if (proc->instance_cnt_prach == 0) { + exit_fun( "PRACH thread busy" ); + return; + } + + // wake up thread for PRACH RX + if (pthread_mutex_lock(&proc->mutex_prach) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach); + exit_fun( "error locking mutex_prach" ); + return; + } + + ++proc->instance_cnt_prach; + // set timing for prach thread + proc->frame_prach = frame; + proc->subframe_prach = subframe; + + // the thread can now be woken up + if (pthread_cond_signal(&proc->cond_prach) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH thread %d\n", proc->thread_index); + exit_fun( "ERROR pthread_cond_signal" ); + return; + } + + pthread_mutex_unlock( &proc->mutex_prach ); + //} + } + +} + +void phy_procedures_eNB_common_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc){ + + + // eNB_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + const int subframe = proc->subframe_rx; + const int frame = proc->frame_rx; + // int offset = (eNB->single_thread_flag==1) ? 0 : (subframe&1); + + /// VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_ENB+offset, proc->frame_rx ); + /// VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_ENB+offset, proc->subframe_rx ); + + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) { + + if (eNB->node_function == NGFI_RRU_IF4p5) { + /// **** in TDD during DL send_IF4 of ULTICK to RCC **** /// + send_IF4p5(eNB, proc->frame_rx, proc->subframe_rx, IF4p5_PULTICK, 0); + } + return; + } + + + ///VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_COMMON+offset, 1 ); + /// start_meas(&eNB->phy_proc_rx); + LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_common_RX(%d)\n",eNB->Mod_id,frame,subframe); + + + if (eNB->fep) eNB->fep(eNB,proc); + + ///VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_COMMON+offset, 0 ); +} + +/* +void fill_rx_indication_NB_IoT(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,uint8_t data_or_control, uint8_t msg3_flag) +{ + nfapi_rx_indication_pdu_t *pdu; + + pthread_mutex_lock(&eNB->UL_INFO_mutex); + + eNB->UL_INFO.RX_NPUSCH.number_of_pdus = 1; + //eNB->UL_INFO.RX_NPUSCH.rx_pdu_list.rx_ue_information.tl.tag = NFAPI_RX_INDICATION_BODY_TAG; // do we need this ?? + //eNB->UL_INFO.RX_NPUSCH.rx_pdu_list.rx_ue_information.rnti = rnti; // rnti should be got from eNB structure + //pdu = &eNB->UL_INFO.RX_NPUSCH.rx_pdu_list[eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus]; + pdu = &eNB->UL_INFO.RX_NPUSCH.rx_pdu_list[0]; + // pdu->rx_ue_information.handle = eNB->ulsch[UE_id]->handle; + // pdu->rx_ue_information.tl.tag = NFAPI_RX_UE_INFORMATION_TAG; + //pdu->rx_indication_rel8.tl.tag = NFAPI_RX_INDICATION_REL8_TAG; + pdu->rx_ue_information.rnti = eNB->ulsch_NB_IoT[0]->rnti; + + + if(msg3_flag == 1) + { + pdu->rx_indication_rel8.length = 6; //eNB->ulsch_NB_IoT[0]->harq_process->TBS>>3; + int m =0; + for(m=0; m<6;m++) + { + pdu->data[m] = eNB->ulsch_NB_IoT[0]->harq_process->b[2+m]; + printf(" pdu content = %d \n", eNB->ulsch_NB_IoT[0]->harq_process->b[2+m]); + } + + } else { + + pdu->data = eNB->ulsch_NB_IoT[0]->harq_process->b; + } + //pdu->data = eNB->ulsch_NB_IoT[UE_id]->harq_processes[harq_pid]->b; + //eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus++; + //eNB->UL_INFO.rx_ind.sfn_sf = frame<<4 | subframe; + + // do we need to transmit timing ?? however, the nfapi structure does not include timing paramters !!!!! + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + +} +*/ + +void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc,const relaying_type_t r_type) +{ + //RX processing for ue-specific resources (i + UNUSED(r_type); + uint32_t ret=0,i,j,k; + uint32_t harq_pid, harq_idx, round; + uint8_t nPRS; + int sync_pos; + uint16_t rnti=0; + uint8_t access_mode; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + + const int subframe = proc->subframe_rx; + const int frame = proc->frame_rx; + int offset = eNB->CC_id;//(proc == &eNB->proc.proc_rxtx[0]) ? 0 : 1; + + uint16_t srsPeriodicity; + uint16_t srsOffset; + uint16_t do_srs=0; + uint16_t is_srs_pos=0; + + T(T_ENB_PHY_UL_TICK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe)); + + T(T_ENB_PHY_INPUT_SIGNAL, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(0), + T_BUFFER(&eNB->common_vars.rxdata[0][0][subframe*eNB->frame_parms.samples_per_tti], + eNB->frame_parms.samples_per_tti * 4)); + + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) return; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC+offset, 1 ); + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d] Frame %d: Doing phy_procedures_eNB_uespec_RX(%d)\n",eNB->Mod_id,frame, subframe); +#endif + + + eNB->rb_mask_ul[0]=0; + eNB->rb_mask_ul[1]=0; + eNB->rb_mask_ul[2]=0; + eNB->rb_mask_ul[3]=0; + + // Check for active processes in current subframe + harq_pid = subframe2harq_pid(fp, + frame,subframe); + + // reset the cba flag used for collision detection + for (i=0; i < NUM_MAX_CBA_GROUP; i++) { + eNB->cba_last_reception[i]=0; + } + + is_srs_pos = is_srs_occasion_common(fp,frame,subframe); + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + + // Do SRS processing + // check if there is SRS and we have to use shortened format + // TODO: check for exceptions in transmission of SRS together with ACK/NACK + do_srs=0; + if (is_srs_pos && eNB->soundingrs_ul_config_dedicated[i].srsConfigDedicatedSetup ) { + compute_srs_pos(fp->frame_type, eNB->soundingrs_ul_config_dedicated[i].srs_ConfigIndex, &srsPeriodicity, &srsOffset); + if (((10*frame+subframe) % srsPeriodicity) == srsOffset) { + do_srs = 1; + } + } + + if (do_srs==1) { + if (lte_srs_channel_estimation(fp, + &eNB->common_vars, + &eNB->srs_vars[i], + &eNB->soundingrs_ul_config_dedicated[i], + subframe, + 0/*eNB_id*/)) { + LOG_E(PHY,"problem processing SRS\n"); + } + } + + // Do PUCCH processing + + pucch_procedures(eNB,proc,i,harq_pid, do_srs); + + + // check for Msg3 + if (eNB->mac_enabled==1) { + if (eNB->UE_stats[i].mode == RA_RESPONSE) { + process_Msg3(eNB,proc,i,harq_pid); + } + } + + + eNB->pusch_stats_rb[i][(frame*10)+subframe] = -63; + eNB->pusch_stats_round[i][(frame*10)+subframe] = 0; + eNB->pusch_stats_mcs[i][(frame*10)+subframe] = -63; + + if ((eNB->ulsch[i]) && + (eNB->ulsch[i]->rnti>0) && + (eNB->ulsch[i]->harq_processes[harq_pid]->subframe_scheduling_flag==1)) { + // UE is has ULSCH scheduling + round = eNB->ulsch[i]->harq_processes[harq_pid]->round; + + for (int rb=0; + rb<=eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb; + rb++) { + int rb2 = rb+eNB->ulsch[i]->harq_processes[harq_pid]->first_rb; + eNB->rb_mask_ul[rb2>>5] |= (1<<(rb2&31)); + } + + + if (eNB->ulsch[i]->Msg3_flag == 1) { + LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for Msg3 in Sector %d\n", + eNB->Mod_id, + frame, + subframe, + eNB->UE_stats[i].sector); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_MSG3,1); + } else { + + LOG_D(PHY,"[eNB %d] frame %d, subframe %d: Scheduling ULSCH Reception for UE %d Mode %s\n", + eNB->Mod_id, + frame, + subframe, + i, + mode_string[eNB->UE_stats[i].mode]); + } + + + nPRS = fp->pusch_config_common.ul_ReferenceSignalsPUSCH.nPRS[subframe<<1]; + + eNB->ulsch[i]->cyclicShift = (eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS2 + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift + + nPRS)%12; + + if (fp->frame_type == FDD ) { + int sf = (subframe<4) ? (subframe+6) : (subframe-4); + + if (eNB->dlsch[i][0]->subframe_tx[sf]>0) { // we have downlink transmission + eNB->ulsch[i]->harq_processes[harq_pid]->O_ACK = 1; + } else { + eNB->ulsch[i]->harq_processes[harq_pid]->O_ACK = 0; + } + } + + 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, mcs %d, TBS %d, rv %d, cyclic_shift %d (n_DMRS2 %d, cyclicShift_common %d, nprs %d), O_ACK %d \n", + eNB->Mod_id,harq_pid,frame,subframe, + eNB->ulsch[i]->harq_processes[harq_pid]->dci_alloc, + eNB->ulsch[i]->harq_processes[harq_pid]->rar_alloc, + eNB->ulsch[i]->harq_processes[harq_pid]->round, + eNB->ulsch[i]->harq_processes[harq_pid]->first_rb, + eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb, + eNB->ulsch[i]->harq_processes[harq_pid]->mcs, + eNB->ulsch[i]->harq_processes[harq_pid]->TBS, + eNB->ulsch[i]->harq_processes[harq_pid]->rvidx, + eNB->ulsch[i]->cyclicShift, + eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS2, + fp->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift, + nPRS, + eNB->ulsch[i]->harq_processes[harq_pid]->O_ACK); + eNB->pusch_stats_rb[i][(frame*10)+subframe] = eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb; + eNB->pusch_stats_round[i][(frame*10)+subframe] = eNB->ulsch[i]->harq_processes[harq_pid]->round; + eNB->pusch_stats_mcs[i][(frame*10)+subframe] = eNB->ulsch[i]->harq_processes[harq_pid]->mcs; + start_meas(&eNB->ulsch_demodulation_stats); + + if (eNB->abstraction_flag==0) { + rx_ulsch(eNB,proc, + eNB->UE_stats[i].sector, // this is the effective sector id + i, + eNB->ulsch, + 0); + } + +#ifdef PHY_ABSTRACTION + else { + rx_ulsch_emul(eNB,proc, + eNB->UE_stats[i].sector, // this is the effective sector id + i); + } + +#endif + stop_meas(&eNB->ulsch_demodulation_stats); + + + start_meas(&eNB->ulsch_decoding_stats); + + if (eNB->abstraction_flag == 0) { + ret = ulsch_decoding(eNB,proc, + i, + 0, // control_only_flag + eNB->ulsch[i]->harq_processes[harq_pid]->V_UL_DAI, + eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb>20 ? 1 : 0); + } + +#ifdef PHY_ABSTRACTION + else { + ret = ulsch_decoding_emul(eNB, + proc, + i, + &rnti); + } + +#endif + stop_meas(&eNB->ulsch_decoding_stats); + + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) RSSI (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d\n", + eNB->Mod_id,harq_pid, + frame,subframe, + eNB->ulsch[i]->rnti, + dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), + dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), + eNB->UE_stats[i].UL_rssi[0], + eNB->UE_stats[i].UL_rssi[1], + eNB->measurements->n0_power_dB[0], + eNB->measurements->n0_power_dB[1], + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[1], + ret); + + //compute the expected ULSCH RX power (for the stats) + eNB->ulsch[(uint32_t)i]->harq_processes[harq_pid]->delta_TF = + get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0); // 0 means bw_factor is not considered + + eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][eNB->ulsch[i]->harq_processes[harq_pid]->round]++; +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d harq_pid %d Clearing subframe_scheduling_flag\n", + eNB->Mod_id,harq_pid,frame,subframe,i,harq_pid); +#endif + eNB->ulsch[i]->harq_processes[harq_pid]->subframe_scheduling_flag=0; + + if (eNB->ulsch[i]->harq_processes[harq_pid]->cqi_crc_status == 1) { +#ifdef DEBUG_PHY_PROC + //if (((frame%10) == 0) || (frame < 50)) + print_CQI(eNB->ulsch[i]->harq_processes[harq_pid]->o,eNB->ulsch[i]->harq_processes[harq_pid]->uci_format,0,fp->N_RB_DL); +#endif + extract_CQI(eNB->ulsch[i]->harq_processes[harq_pid]->o, + eNB->ulsch[i]->harq_processes[harq_pid]->uci_format, + &eNB->UE_stats[i], + fp->N_RB_DL, + &rnti, &access_mode); + eNB->UE_stats[i].rank = eNB->ulsch[i]->harq_processes[harq_pid]->o_RI[0]; + + } + + if (eNB->ulsch[i]->Msg3_flag == 1) + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_ULSCH_MSG3,0); + + if (ret == (1+MAX_TURBO_ITERATIONS)) { + T(T_ENB_PHY_ULSCH_UE_NACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(eNB->ulsch[i]->rnti), + T_INT(harq_pid)); + + eNB->UE_stats[i].ulsch_round_errors[harq_pid][eNB->ulsch[i]->harq_processes[harq_pid]->round]++; + eNB->ulsch[i]->harq_processes[harq_pid]->phich_active = 1; + eNB->ulsch[i]->harq_processes[harq_pid]->phich_ACK = 0; + eNB->ulsch[i]->harq_processes[harq_pid]->round++; + + LOG_D(PHY,"[eNB][PUSCH %d] Increasing to round %d\n",harq_pid,eNB->ulsch[i]->harq_processes[harq_pid]->round); + + if (eNB->ulsch[i]->Msg3_flag == 1) { + + LOG_D(PHY,"[eNB %d/%d][RAPROC] frame %d, subframe %d, UE %d: Error receiving ULSCH (Msg3), round %d/%d\n", + eNB->Mod_id, + eNB->CC_id, + frame,subframe, i, + eNB->ulsch[i]->harq_processes[harq_pid]->round-1, + fp->maxHARQ_Msg3Tx-1); + /*dump_ulsch(eNB,proc,i); + exit(-1);*/ + + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) RSSI (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d\n", + eNB->Mod_id,harq_pid, + frame,subframe, + eNB->ulsch[i]->rnti, + dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), + dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), + eNB->UE_stats[i].UL_rssi[0], + eNB->UE_stats[i].UL_rssi[1], + eNB->measurements->n0_power_dB[0], + eNB->measurements->n0_power_dB[1], + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[1], + ret); + + if (eNB->ulsch[i]->harq_processes[harq_pid]->round == + fp->maxHARQ_Msg3Tx) { + LOG_D(PHY,"[eNB %d][RAPROC] maxHARQ_Msg3Tx reached, abandoning RA procedure for UE %d\n", + eNB->Mod_id, i); + eNB->UE_stats[i].mode = PRACH; + if (eNB->mac_enabled==1) { + mac_xface->cancel_ra_proc(eNB->Mod_id, + eNB->CC_id, + frame, + eNB->UE_stats[i].crnti); + } + mac_phy_remove_ue(eNB->Mod_id,eNB->UE_stats[i].crnti); + + eNB->ulsch[(uint32_t)i]->Msg3_active = 0; + //eNB->ulsch[i]->harq_processes[harq_pid]->phich_active = 0; + + } else { + // activate retransmission for Msg3 (signalled to UE PHY by PHICH (not MAC/DCI) + eNB->ulsch[(uint32_t)i]->Msg3_active = 1; + + get_Msg3_alloc_ret(fp, + subframe, + frame, + &eNB->ulsch[i]->Msg3_frame, + &eNB->ulsch[i]->Msg3_subframe); + + mac_xface->set_msg3_subframe(eNB->Mod_id, eNB->CC_id, frame, subframe, eNB->ulsch[i]->rnti, + eNB->ulsch[i]->Msg3_frame, eNB->ulsch[i]->Msg3_subframe); + + T(T_ENB_PHY_MSG3_ALLOCATION, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), + T_INT(i), T_INT(eNB->ulsch[i]->rnti), T_INT(0 /* 0 is for retransmission*/), + T_INT(eNB->ulsch[i]->Msg3_frame), T_INT(eNB->ulsch[i]->Msg3_subframe)); + } + LOG_D(PHY,"[eNB] Frame %d, Subframe %d: Msg3 in error, i = %d \n", frame,subframe,i); + } // This is Msg3 error + + else { //normal ULSCH + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d Error receiving ULSCH, round %d/%d (ACK %d,%d)\n", + eNB->Mod_id,harq_pid, + frame,subframe, i, + eNB->ulsch[i]->harq_processes[harq_pid]->round-1, + eNB->ulsch[i]->Mlimit, + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[1]); + +#if defined(MESSAGE_CHART_GENERATOR_PHY) + MSC_LOG_RX_DISCARDED_MESSAGE( + MSC_PHY_ENB,MSC_PHY_UE, + NULL,0, + "%05u:%02u ULSCH received rnti %x harq id %u round %d", + frame,subframe, + eNB->ulsch[i]->rnti,harq_pid, + eNB->ulsch[i]->harq_processes[harq_pid]->round-1 + ); +#endif + + if (eNB->ulsch[i]->harq_processes[harq_pid]->round== eNB->ulsch[i]->Mlimit) { + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d UE %d ULSCH Mlimit %d reached\n", + eNB->Mod_id,harq_pid, + frame,subframe, i, + eNB->ulsch[i]->Mlimit); + + eNB->ulsch[i]->harq_processes[harq_pid]->round=0; + eNB->ulsch[i]->harq_processes[harq_pid]->phich_active=0; + eNB->UE_stats[i].ulsch_errors[harq_pid]++; + eNB->UE_stats[i].ulsch_consecutive_errors++; + + /*if (eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb > 20) { + dump_ulsch(eNB,proc,i); + exit(-1); + }*/ + // indicate error to MAC + if (eNB->mac_enabled == 1) + mac_xface->rx_sdu(eNB->Mod_id, + eNB->CC_id, + frame,subframe, + eNB->ulsch[i]->rnti, + NULL, + 0, + harq_pid, + &eNB->ulsch[i]->Msg3_flag); + } + } + } // ulsch in error + else { + + + + T(T_ENB_PHY_ULSCH_UE_ACK, T_INT(eNB->Mod_id), T_INT(frame), T_INT(subframe), T_INT(i), T_INT(eNB->ulsch[i]->rnti), + T_INT(harq_pid)); + + if (eNB->ulsch[i]->Msg3_flag == 1) { + LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d subframe %d ULSCH received, setting round to 0, PHICH ACK\n", + eNB->Mod_id,harq_pid, + frame,subframe); + LOG_D(PHY,"[eNB %d][PUSCH %d] frame %d subframe %d RNTI %x RX power (%d,%d) RSSI (%d,%d) N0 (%d,%d) dB ACK (%d,%d), decoding iter %d\n", + eNB->Mod_id,harq_pid, + frame,subframe, + eNB->ulsch[i]->rnti, + dB_fixed(eNB->pusch_vars[i]->ulsch_power[0]), + dB_fixed(eNB->pusch_vars[i]->ulsch_power[1]), + eNB->UE_stats[i].UL_rssi[0], + eNB->UE_stats[i].UL_rssi[1], + eNB->measurements->n0_power_dB[0], + eNB->measurements->n0_power_dB[1], + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[1], + ret); + } +#if defined(MESSAGE_CHART_GENERATOR_PHY) + MSC_LOG_RX_MESSAGE( + MSC_PHY_ENB,MSC_PHY_UE, + NULL,0, + "%05u:%02u ULSCH received rnti %x harq id %u", + frame,subframe, + eNB->ulsch[i]->rnti,harq_pid + ); +#endif + for (j=0; j<fp->nb_antennas_rx; j++) + //this is the RSSI per RB + eNB->UE_stats[i].UL_rssi[j] = + + dB_fixed(eNB->pusch_vars[i]->ulsch_power[j]* + (eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb*12)/ + fp->ofdm_symbol_size) - + eNB->rx_total_gain_dB - + hundred_times_log10_NPRB[eNB->ulsch[i]->harq_processes[harq_pid]->nb_rb-1]/100 - + get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 0)/100; + + eNB->ulsch[i]->harq_processes[harq_pid]->phich_active = 1; + eNB->ulsch[i]->harq_processes[harq_pid]->phich_ACK = 1; + eNB->ulsch[i]->harq_processes[harq_pid]->round = 0; + eNB->UE_stats[i].ulsch_consecutive_errors = 0; + + if (eNB->ulsch[i]->Msg3_flag == 1) { + if (eNB->mac_enabled==1) { + + LOG_I(PHY,"[eNB %d][RAPROC] Frame %d Terminating ra_proc for harq %d, UE %d\n", + eNB->Mod_id, + frame,harq_pid,i); + if (eNB->mac_enabled) + mac_xface->rx_sdu(eNB->Mod_id, + eNB->CC_id, + frame,subframe, + eNB->ulsch[i]->rnti, + eNB->ulsch[i]->harq_processes[harq_pid]->b, + eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3, + harq_pid, + &eNB->ulsch[i]->Msg3_flag); + + // one-shot msg3 detection by MAC: empty PDU (e.g. CRNTI) + if (eNB->ulsch[i]->Msg3_flag == 0 ) { + eNB->UE_stats[i].mode = PRACH; + mac_xface->cancel_ra_proc(eNB->Mod_id, + eNB->CC_id, + frame, + eNB->UE_stats[i].crnti); + mac_phy_remove_ue(eNB->Mod_id,eNB->UE_stats[i].crnti); + eNB->ulsch[(uint32_t)i]->Msg3_active = 0; + } // Msg3_flag == 0 + + } // mac_enabled==1 + + eNB->UE_stats[i].mode = PUSCH; + eNB->ulsch[i]->Msg3_flag = 0; + + LOG_D(PHY,"[eNB %d][RAPROC] Frame %d : RX Subframe %d Setting UE %d mode to PUSCH\n",eNB->Mod_id,frame,subframe,i); + + for (k=0; k<8; k++) { //harq_processes + for (j=0; j<eNB->dlsch[i][0]->Mlimit; j++) { + eNB->UE_stats[i].dlsch_NAK[k][j]=0; + eNB->UE_stats[i].dlsch_ACK[k][j]=0; + eNB->UE_stats[i].dlsch_trials[k][j]=0; + } + + eNB->UE_stats[i].dlsch_l2_errors[k]=0; + eNB->UE_stats[i].ulsch_errors[k]=0; + eNB->UE_stats[i].ulsch_consecutive_errors=0; + + for (j=0; j<eNB->ulsch[i]->Mlimit; j++) { + eNB->UE_stats[i].ulsch_decoding_attempts[k][j]=0; + eNB->UE_stats[i].ulsch_decoding_attempts_last[k][j]=0; + eNB->UE_stats[i].ulsch_round_errors[k][j]=0; + eNB->UE_stats[i].ulsch_round_fer[k][j]=0; + } + } + + eNB->UE_stats[i].dlsch_sliding_cnt=0; + eNB->UE_stats[i].dlsch_NAK_round0=0; + eNB->UE_stats[i].dlsch_mcs_offset=0; + } // Msg3_flag==1 + else { // Msg3_flag == 0 + +#ifdef DEBUG_PHY_PROC +#ifdef DEBUG_ULSCH + LOG_D(PHY,"[eNB] Frame %d, Subframe %d : ULSCH SDU (RX harq_pid %d) %d bytes:",frame,subframe, + harq_pid,eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3); + + for (j=0; j<eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3; j++) + LOG_T(PHY,"%x.",eNB->ulsch[i]->harq_processes[harq_pid]->b[j]); + + LOG_T(PHY,"\n"); +#endif +#endif + + if (eNB->mac_enabled==1) { + + mac_xface->rx_sdu(eNB->Mod_id, + eNB->CC_id, + frame,subframe, + eNB->ulsch[i]->rnti, + eNB->ulsch[i]->harq_processes[harq_pid]->b, + eNB->ulsch[i]->harq_processes[harq_pid]->TBS>>3, + harq_pid, + NULL); + +#ifdef LOCALIZATION + start_meas(&eNB->localization_stats); + aggregate_eNB_UE_localization_stats(eNB, + i, + frame, + subframe, + get_hundred_times_delta_IF_eNB(eNB,i,harq_pid, 1)/100); + stop_meas(&eNB->localization_stats); +#endif + + } // mac_enabled==1 + } // Msg3_flag == 0 + + // estimate timing advance for MAC + if (eNB->abstraction_flag == 0) { + sync_pos = lte_est_timing_advance_pusch(eNB,i); + eNB->UE_stats[i].timing_advance_update = sync_pos - fp->nb_prefix_samples/4; //to check + } + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d] frame %d, subframe %d: user %d: timing advance = %d\n", + eNB->Mod_id, + frame, subframe, + i, + eNB->UE_stats[i].timing_advance_update); +#endif + + + } // ulsch not in error + + // process HARQ feedback +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d][PDSCH %x] Frame %d subframe %d, Processing HARQ feedback for UE %d (after PUSCH)\n",eNB->Mod_id, + eNB->dlsch[i][0]->rnti, + frame,subframe, + i); +#endif + process_HARQ_feedback(i, + eNB,proc, + 1, // pusch_flag + 0, + 0, + 0); + +#ifdef DEBUG_PHY_PROC + LOG_D(PHY,"[eNB %d] Frame %d subframe %d, sect %d: received ULSCH harq_pid %d for UE %d, ret = %d, CQI CRC Status %d, ACK %d,%d, ulsch_errors %d/%d\n", + eNB->Mod_id,frame,subframe, + eNB->UE_stats[i].sector, + harq_pid, + i, + ret, + eNB->ulsch[i]->harq_processes[harq_pid]->cqi_crc_status, + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[0], + eNB->ulsch[i]->harq_processes[harq_pid]->o_ACK[1], + eNB->UE_stats[i].ulsch_errors[harq_pid], + eNB->UE_stats[i].ulsch_decoding_attempts[harq_pid][0]); +#endif + + // dump stats to VCD + if (i==0) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_MCS0+harq_pid,eNB->pusch_stats_mcs[0][(frame*10)+subframe]); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_RB0+harq_pid,eNB->pusch_stats_rb[0][(frame*10)+subframe]); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_ROUND0+harq_pid,eNB->pusch_stats_round[0][(frame*10)+subframe]); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_RSSI0+harq_pid,dB_fixed(eNB->pusch_vars[0]->ulsch_power[0])); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_RES0+harq_pid,ret); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_SFN0+harq_pid,(frame*10)+subframe); + } + } // ulsch[0] && ulsch[0]->rnti>0 && ulsch[0]->subframe_scheduling_flag == 1 + + + // update ULSCH statistics for tracing + if ((frame % 100 == 0) && (subframe == 4)) { + for (harq_idx=0; harq_idx<8; harq_idx++) { + for (round=0; round<eNB->ulsch[i]->Mlimit; round++) { + if ((eNB->UE_stats[i].ulsch_decoding_attempts[harq_idx][round] - + eNB->UE_stats[i].ulsch_decoding_attempts_last[harq_idx][round]) != 0) { + eNB->UE_stats[i].ulsch_round_fer[harq_idx][round] = + (100*(eNB->UE_stats[i].ulsch_round_errors[harq_idx][round] - + eNB->UE_stats[i].ulsch_round_errors_last[harq_idx][round]))/ + (eNB->UE_stats[i].ulsch_decoding_attempts[harq_idx][round] - + eNB->UE_stats[i].ulsch_decoding_attempts_last[harq_idx][round]); + } else { + eNB->UE_stats[i].ulsch_round_fer[harq_idx][round] = 0; + } + + eNB->UE_stats[i].ulsch_decoding_attempts_last[harq_idx][round] = + eNB->UE_stats[i].ulsch_decoding_attempts[harq_idx][round]; + eNB->UE_stats[i].ulsch_round_errors_last[harq_idx][round] = + eNB->UE_stats[i].ulsch_round_errors[harq_idx][round]; + } + } + } + + if ((frame % 100 == 0) && (subframe==4)) { + eNB->UE_stats[i].dlsch_bitrate = (eNB->UE_stats[i].total_TBS - + eNB->UE_stats[i].total_TBS_last); + + eNB->UE_stats[i].total_TBS_last = eNB->UE_stats[i].total_TBS; + } + + // CBA (non-LTE) + cba_procedures(eNB,proc,i,harq_pid); + } // loop i=0 ... NUMBER_OF_UE_MAX-1 + + if (eNB->abstraction_flag == 0) { + lte_eNB_I0_measurements(eNB, + subframe, + 0, + eNB->first_run_I0_measurements); + eNB->first_run_I0_measurements = 0; + } + +#ifdef PHY_ABSTRACTION + else { + lte_eNB_I0_measurements_emul(eNB, + 0); + } + +#endif + //} + +#ifdef EMOS + phy_procedures_emos_eNB_RX(subframe,eNB); +#endif + +#if defined(FLEXRAN_AGENT_SB_IF) +#ifndef DISABLE_SF_TRIGGER + //Send subframe trigger to the controller + if (mac_agent_registered[eNB->Mod_id]) { + agent_mac_xface[eNB->Mod_id]->flexran_agent_send_sf_trigger(eNB->Mod_id); + } +#endif +#endif + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC+offset, 0 ); + + stop_meas(&eNB->phy_proc_rx); + +} + +#undef DEBUG_PHY_PROC + +#if defined(Rel10) || defined(Rel14) +int phy_procedures_RN_eNB_TX(unsigned char last_slot, unsigned char next_slot, relaying_type_t r_type) +{ + + int do_proc=0;// do nothing + + switch(r_type) { + case no_relay: + do_proc= no_relay; // perform the normal eNB operation + break; + + case multicast_relay: + if (((next_slot >>1) < 6) || ((next_slot >>1) > 8)) + do_proc = 0; // do nothing + else // SF#6, SF#7 and SF#8 + do_proc = multicast_relay; // do PHY procedures eNB TX + + break; + + default: // should'not be here + LOG_W(PHY,"Not supported relay type %d, do nothing\n", r_type); + do_proc=0; + break; + } + + return do_proc; +} +#endif diff --git a/openair2/COMMON/platform_types_NB_IoT.h b/openair2/COMMON/platform_types_NB_IoT.h index 5acf5e6cc39d346ac237a1f44f4e24625d83bf9b..2da92ac60237b344d54dab0f1ec192e08160e620 100644 --- a/openair2/COMMON/platform_types_NB_IoT.h +++ b/openair2/COMMON/platform_types_NB_IoT.h @@ -20,7 +20,7 @@ */ /* - platform_types.h + platform_types_NB_IoT.h ------------------- AUTHOR : Lionel GAUTHIER COMPANY : EURECOM @@ -47,19 +47,30 @@ typedef uint16_t rnti_NB_IoT_t; #ifndef _BOOLEAN_T_DEFINED_NB_IoT_ #define _BOOLEAN_T_DEFINED_NB_IoT_ -typedef signed char boolean_NB_IoT_t; +typedef signed char boolean_t; #if !defined(TRUE) -#define TRUE (boolean_NB_IoT_t)0x01 +#define TRUE (boolean_t)0x01 #endif #if !defined(FALSE) -#define FALSE (boolean_NB_IoT_t)0x00 +#define FALSE (boolean_t)0x00 #endif #define BOOL_NOT(b) (b^TRUE) -#endif /* _BOOLEAN_T_DEFINED_ */ +#endif + +///NB-IoT +typedef boolean_t srb1bis_flag_t; +#define SRB1BIS_FLAG_NO FALSE +#define SRB1BIS_FLAG_YES TRUE + +typedef boolean_t mib_flag_t; +#define MIB_FLAG_YES TRUE +#define MIB_FLAG_NO FALSE + +/* _BOOLEAN_T_DEFINED_ */ /* //----------------------------------------------------------------------------- // GENERIC ACCESS STRATUM TYPES diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 04a4329208db96499a0f788029f6d447ce49b2e7..6a815f679a3bfc543c8d9f92acf41b03dd7c718d 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -280,60 +280,6 @@ typedef struct RrcConfigurationReq_s { long ue_TimersAndConstants_n310[MAX_NUM_CCs]; long ue_TimersAndConstants_n311[MAX_NUM_CCs]; long ue_TransmissionMode[MAX_NUM_CCs]; - - //NB-IoT------------------------------------------------------------ - - //RACH - long rach_raResponseWindowSize_NB[MAX_NUM_CCs]; - long rach_macContentionResolutionTimer_NB[MAX_NUM_CCs]; - long rach_powerRampingStep_NB[MAX_NUM_CCs]; - long rach_preambleInitialReceivedTargetPower_NB[MAX_NUM_CCs]; - long rach_preambleTransMax_CE_NB[MAX_NUM_CCs]; - //BCCH - long bcch_modificationPeriodCoeff_NB[MAX_NUM_CCs]; - //PCCH - long pcch_defaultPagingCycle_NB[MAX_NUM_CCs]; - long pcch_nB_NB[MAX_NUM_CCs]; - long pcch_npdcch_NumRepetitionPaging_NB[MAX_NUM_CCs]; - //NPRACH - long nprach_CP_Length[MAX_NUM_CCs]; - long nprach_rsrp_range[MAX_NUM_CCs]; - long nprach_Periodicity[MAX_NUM_CCs]; - long nprach_StartTime[MAX_NUM_CCs]; - long nprach_SubcarrierOffset[MAX_NUM_CCs]; - long nprach_NumSubcarriers[MAX_NUM_CCs]; - long nprach_SubcarrierMSG3_RangeStart[MAX_NUM_CCs]; - long maxNumPreambleAttemptCE_NB[MAX_NUM_CCs]; - long numRepetitionsPerPreambleAttempt_NB[MAX_NUM_CCs]; - long npdcch_NumRepetitions_RA[MAX_NUM_CCs]; - long npdcch_StartSF_CSS_RA[MAX_NUM_CCs]; - long npdcch_Offset_RA[MAX_NUM_CCs]; - //NPDSCH - long npdsch_nrs_Power[MAX_NUM_CCs]; - //NPUSCH - long npusch_ack_nack_numRepetitions_NB[MAX_NUM_CCs]; - long npusch_srs_SubframeConfig_NB[MAX_NUM_CCs]; - long npusch_threeTone_CyclicShift_r13[MAX_NUM_CCs]; - long npusch_sixTone_CyclicShift_r13[MAX_NUM_CCs]; - BOOLEAN_t npusch_groupHoppingEnabled[MAX_NUM_CCs]; - long npusch_groupAssignmentNPUSCH_r13[MAX_NUM_CCs]; - - //DL_GapConfig - long dl_GapThreshold_NB[MAX_NUM_CCs]; - long dl_GapPeriodicity_NB[MAX_NUM_CCs]; - long dl_GapDurationCoeff_NB[MAX_NUM_CCs]; - //Uplink power control Common - long npusch_p0_NominalNPUSCH[MAX_NUM_CCs]; - long npusch_alpha[MAX_NUM_CCs]; - long deltaPreambleMsg3[MAX_NUM_CCs]; - //UE timers and constants - long ue_TimersAndConstants_t300_NB[MAX_NUM_CCs]; - long ue_TimersAndConstants_t301_NB[MAX_NUM_CCs]; - long ue_TimersAndConstants_t310_NB[MAX_NUM_CCs]; - long ue_TimersAndConstants_t311_NB[MAX_NUM_CCs]; - long ue_TimersAndConstants_n310_NB[MAX_NUM_CCs]; - long ue_TimersAndConstants_n311_NB[MAX_NUM_CCs]; - //--------------------------------------------------------------------------- int eMBMS_configured; int eMTC_configured; int SL_configured; diff --git a/openair2/ENB_APP/NB_IoT_config.c b/openair2/ENB_APP/NB_IoT_config.c old mode 100644 new mode 100755 diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 9fcbb6bd24a923bd602f43ff38174079f1102d72..0c96fc785dcdc9e7a84483d4bfb1c16e435593d2 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -59,64 +59,6 @@ extern RAN_CONTEXT_t RC; - ///////////////////////////// NB-IoT parameters ///////////////////////////////////// - - //NB-IoT------------------------------------------------------------ - - //RACH - RRC_CONFIGURATION_REQ (msg_p).rach_raResponseWindowSize_NB[CC_id] = enb_properties->properties[enb_id]->rach_raResponseWindowSize_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_macContentionResolutionTimer_NB[CC_id] = enb_properties->properties[enb_id]->rach_macContentionResolutionTimer_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_powerRampingStep_NB[CC_id] = enb_properties->properties[enb_id]->rach_powerRampingStep_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_preambleInitialReceivedTargetPower_NB[CC_id] = enb_properties->properties[enb_id]->rach_preambleInitialReceivedTargetPower_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).rach_preambleTransMax_CE_NB[CC_id] = enb_properties->properties[enb_id]->rach_preambleTransMax_CE_NB[CC_id]; - //BCCH - RRC_CONFIGURATION_REQ (msg_p).bcch_modificationPeriodCoeff_NB[CC_id] = enb_properties->properties[enb_id]->bcch_modificationPeriodCoeff_NB[CC_id]; - //PCCH - RRC_CONFIGURATION_REQ (msg_p).pcch_defaultPagingCycle_NB[CC_id] = enb_properties->properties[enb_id]->pcch_defaultPagingCycle_NB[CC_id]; - //NPRACH - RRC_CONFIGURATION_REQ (msg_p).nprach_CP_Length[CC_id] = enb_properties->properties[enb_id]->nprach_CP_Length[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).nprach_rsrp_range[CC_id] = enb_properties->properties[enb_id]->nprach_rsrp_range[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).nprach_Periodicity[CC_id] = enb_properties->properties[enb_id]->nprach_Periodicity[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).nprach_StartTime[CC_id] = enb_properties->properties[enb_id]->nprach_StartTime[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).nprach_SubcarrierOffset[CC_id] = enb_properties->properties[enb_id]->nprach_SubcarrierOffset[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).nprach_NumSubcarriers[CC_id] = enb_properties->properties[enb_id]->nprach_NumSubcarriers[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).nprach_SubcarrierMSG3_RangeStart[CC_id] = enb_properties->properties[enb_id]->nprach_SubcarrierMSG3_RangeStart[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).maxNumPreambleAttemptCE_NB[CC_id] = enb_properties->properties[enb_id]->maxNumPreambleAttemptCE_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).npdcch_NumRepetitions_RA[CC_id] = enb_properties->properties[enb_id]->npdcch_NumRepetitions_RA[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).npdcch_StartSF_CSS_RA[CC_id] = enb_properties->properties[enb_id]->npdcch_StartSF_CSS_RA[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).npdcch_Offset_RA[CC_id] = enb_properties->properties[enb_id]->npdcch_Offset_RA[CC_id]; - //NPDSCH - RRC_CONFIGURATION_REQ (msg_p).npdsch_nrs_Power[CC_id] = enb_properties->properties[enb_id]->npdsch_nrs_Power[CC_id]; - //NPUSCH - RRC_CONFIGURATION_REQ (msg_p).npusch_ack_nack_numRepetitions_NB[CC_id] = enb_properties->properties[enb_id]->npusch_ack_nack_numRepetitions_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).npusch_srs_SubframeConfig_NB[CC_id] = enb_properties->properties[enb_id]->npusch_srs_SubframeConfig_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).npusch_threeTone_CyclicShift_r13[CC_id] = enb_properties->properties[enb_id]->npusch_threeTone_CyclicShift_r13[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).npusch_sixTone_CyclicShift_r13[CC_id] = enb_properties->properties[enb_id]->npusch_sixTone_CyclicShift_r13[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).npusch_groupHoppingEnabled[CC_id] = enb_properties->properties[enb_id]->npusch_groupHoppingEnabled[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).npusch_groupAssignmentNPUSCH_r13[CC_id] = enb_properties->properties[enb_id]->npusch_groupAssignmentNPUSCH_r13[CC_id]; - //DL_GapConfig - RRC_CONFIGURATION_REQ (msg_p).dl_GapThreshold_NB[CC_id] = enb_properties->properties[enb_id]->dl_GapThreshold_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).dl_GapPeriodicity_NB[CC_id] = enb_properties->properties[enb_id]->dl_GapPeriodicity_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).dl_GapDurationCoeff_NB[CC_id] = enb_properties->properties[enb_id]->dl_GapDurationCoeff_NB[CC_id]; - //Uplink power control Common - RRC_CONFIGURATION_REQ (msg_p).npusch_p0_NominalNPUSCH[CC_id] = enb_properties->properties[enb_id]->npusch_p0_NominalNPUSCH[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).npusch_alpha[CC_id] = enb_properties->properties[enb_id]->npusch_alpha[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).deltaPreambleMsg3[CC_id] = enb_properties->properties[enb_id]->deltaPreambleMsg3[CC_id]; - //UE timers and constants - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300_NB[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_t300_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301_NB[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_t301_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310_NB[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_t310_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311_NB[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_t311_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310_NB[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_n310_NB[CC_id]; - RRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311_NB[CC_id] = enb_properties->properties[enb_id]->ue_TimersAndConstants_n311_NB[CC_id]; - - //////////////////////////////////////////////////////////////////////////////////// - } - - itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p); -} - -/*------------------------------------------------------------------------------*/ static uint32_t eNB_app_register(ngran_node_t node_type,uint32_t enb_id_start, uint32_t enb_id_end) { uint32_t enb_id; diff --git a/openair2/LAYER2/MAC/defs_NB_IoT.h b/openair2/LAYER2/MAC/defs_NB_IoT.h old mode 100755 new mode 100644 index 511b2b4912c31180ae87604c1677c24bb37b343a..133d009746fc6bfdfed8b03e3ace7ad4ee4d8d4c --- a/openair2/LAYER2/MAC/defs_NB_IoT.h +++ b/openair2/LAYER2/MAC/defs_NB_IoT.h @@ -22,9 +22,11 @@ #include "openair2/PHY_INTERFACE/IF_Module_NB_IoT.h" #include "config_NB_IoT.h" // MAC definition -#define MAX_FRAME 0xfffff -#define NUM_FRAME 0x100000 -#define MAX_SUBFRAME 10485760 +//#define MAX_FRAME 0xfffff +//#define NUM_FRAME 0x100000 +//#define MAX_SUBFRAME 10485760 +#define MAX_FRAME 0xfff +#define MAX_SUBFRAME 40960 #define MAX(a, b) (((a)>(b))?(a):(b)) @@ -62,8 +64,8 @@ /*!\brief DTCH DRB1 logical channel */ #define DTCH 3 // LCID /*!\brief MCCH logical channel */ -//#define MCCH 4 -#define MCCH 62 +#define MCCH 4 +//#define MCCH 62 /*!\brief MTCH logical channel */ #define MTCH 1 // DLSCH LCHAN ID @@ -209,9 +211,12 @@ typedef struct { int prev; // MSG4 complete int RRC_connected; + uint8_t flag_schedule_success; // UE active flag int active; - + //boolean_t active; + + uint8_t allocated_data_size_ul; } UE_TEMPLATE_NB_IoT; // link list of uplink resource node @@ -327,6 +332,7 @@ typedef struct { /// DCI template and MAC connection parameters for UEs UE_TEMPLATE_NB_IoT UE_template_NB_IoT[MAX_MAX_MOBILES_PER_ENB_NB_IoT]; + UE_SCHED_CTRL_NB_IoT_t UE_sched_ctrl_NB_IoT[MAX_MAX_MOBILES_PER_ENB_NB_IoT]; /// NPDCCH Period and searching space info NPDCCH_config_dedicated_NB_IoT_t NPDCCH_config_dedicated; //int next[MAX_MAX_MOBILES_PER_ENB_NB_IoT]; @@ -631,6 +637,8 @@ typedef struct { nprach_parameters_NB_IoT_t nprach_list[3]; +nfapi_config_request_t config; + //DLSF Table DLSF_INFO_t DLSF_information; diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c index e3e8d4449d236b14757e20230e2e71447d939ee5..856ed9591820372f5505de16020c418c35eacaf1 100755 --- a/openair2/LAYER2/MAC/eNB_scheduler.c +++ b/openair2/LAYER2/MAC/eNB_scheduler.c @@ -1,1031 +1,1021 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file eNB_scheduler.c - * \brief eNB scheduler top level function operates on per subframe basis - * \author Navid Nikaein and Raymond Knopp - * \date 2010 - 2014 - * \email: navid.nikaein@eurecom.fr - * \version 0.5 - * @ingroup _mac - - */ - -#include "assertions.h" - -#include "PHY/defs.h" -#include "PHY/extern.h" - -//#include "PHY/LTE_TRANSPORT/dci_NB_IoT.h" - -#include "SCHED/defs.h" -#include "SCHED/extern.h" - -#include "LAYER2/MAC/defs.h" - -#include "targets/RT/USER/lte-softmodem.h" -#include "LAYER2/MAC/mac.h" -#include "LAYER2/MAC/mac_extern.h" - -#include "LAYER2/MAC/mac_proto.h" -#include "common/utils/LOG/log.h" -#include "nfapi/oai_integration/vendor_ext.h" -#include "common/utils/LOG/vcd_signal_dumper.h" -#include "UTIL/OPT/opt.h" -#include "OCG.h" -#include "OCG_extern.h" - -#include "RRC/LTE/rrc_extern.h" -#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" - -//#include "LAYER2/MAC/pre_processor.c" -#include "pdcp.h" - -//Agent-related headers -#include "flexran_agent_extern.h" -#include "flexran_agent_mac.h" - -/* for fair round robin SCHED */ -#include "eNB_scheduler_fairRR.h" - -#if defined(ENABLE_ITTI) - #include "intertask_interface.h" -#endif - -#include "assertions.h" - -#define ENABLE_MAC_PAYLOAD_DEBUG -#define DEBUG_eNB_SCHEDULER 1 - -extern RAN_CONTEXT_t RC; - - -uint16_t pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 }; - -//----------------------------------------------------------------------------- -/* - * Schedule periodic SRS - */ -void schedule_SRS(module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP) -//----------------------------------------------------------------------------- -{ - int CC_id = 0; - int UE_id = -1; - uint8_t TSFC = 0; - uint8_t srs_SubframeConfig = 0; - uint16_t srsPeriodicity = 0; - uint16_t srsOffset = 0; - uint16_t deltaTSFC = 0; // bitmap - // table for TSFC (Period) and deltaSFC (offset) - const uint16_t deltaTSFCTabType1[15][2] = { {1, 1}, {1, 2}, {2, 2}, {1, 5}, {2, 5}, {4, 5}, {8, 5}, {3, 5}, {12, 5}, {1, 10}, {2, 10}, {4, 10}, {8, 10}, {351, 10}, {383, 10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD - const uint16_t deltaTSFCTabType2[14][2] = { {2, 5}, {6, 5}, {10, 5}, {18, 5}, {14, 5}, {22, 5}, {26, 5}, {30, 5}, {70, 10}, {74, 10}, {194, 10}, {326, 10}, {586, 10}, {210, 10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &(eNB->UE_list); - nfapi_ul_config_request_body_t *ul_req = NULL; - UE_sched_ctrl *UE_scheduling_control = NULL; - COMMON_channels_t *cc = eNB->common_channels; - LTE_SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon = NULL; - struct LTE_SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated = NULL; - - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - soundingRS_UL_ConfigCommon = &(cc[CC_id].radioResourceConfigCommon->soundingRS_UL_ConfigCommon); - - /* Check if SRS is enabled in this frame/subframe */ - if (soundingRS_UL_ConfigCommon) { - srs_SubframeConfig = soundingRS_UL_ConfigCommon->choice.setup.srs_SubframeConfig; - - if (cc[CC_id].tdd_Config == NULL) { // FDD - deltaTSFC = deltaTSFCTabType1[srs_SubframeConfig][0]; - TSFC = deltaTSFCTabType1[srs_SubframeConfig][1]; - } else { // TDD - deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0]; - TSFC = deltaTSFCTabType2[srs_SubframeConfig][1]; - } - - /* Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC) */ - uint16_t tmp = (subframeP % TSFC); - - if ((1 << tmp) & deltaTSFC) { - /* This is an SRS subframe, loop over UEs */ - for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { - if (!UE_list->active[UE_id]) { - continue; - } - - /* Drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet */ - if (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) { - continue; - } - - AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, - "physicalConfigDedicated is null for UE %d\n", - UE_id); - - /* CDRX condition on Active Time and SRS type-0 report (36.321 5.7) */ - UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]); - - /* Test if Active Time not running since 6+ subframes */ - if (UE_scheduling_control->cdrx_configured == TRUE && UE_scheduling_control->in_active_time == FALSE) { - /* - * TODO: 6+ subframes condition not checked here - */ - continue; - } - - ul_req = &(eNB->UL_req[CC_id].ul_config_request_body); - - if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated) != NULL) { - if (soundingRS_UL_ConfigDedicated->present == LTE_SoundingRS_UL_ConfigDedicated_PR_setup) { - get_srs_pos(&cc[CC_id], - soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex, - &srsPeriodicity, - &srsOffset); - - if (((10 * frameP + subframeP) % srsPeriodicity) == srsOffset) { - // Program SRS - ul_req->srs_present = 1; - nfapi_ul_config_request_pdu_t *ul_config_pdu = &(ul_req->ul_config_pdu_list[ul_req->number_of_pdus]); - memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_SRS_PDU_TYPE; - ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_srs_pdu)); - ul_config_pdu->srs_pdu.srs_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG; - ul_config_pdu->srs_pdu.srs_pdu_rel8.size = (uint8_t)sizeof(nfapi_ul_config_srs_pdu); - ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; - ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth; - ul_config_pdu->srs_pdu.srs_pdu_rel8.frequency_domain_position = soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; - ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_hopping_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth;; - ul_config_pdu->srs_pdu.srs_pdu_rel8.transmission_comb = soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb; - ul_config_pdu->srs_pdu.srs_pdu_rel8.i_srs = soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex; - ul_config_pdu->srs_pdu.srs_pdu_rel8.sounding_reference_cyclic_shift = soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; - - eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; - eNB->UL_req[CC_id].header.message_id = NFAPI_UL_CONFIG_REQUEST; - ul_req->number_of_pdus++; - } // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) - } // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) - } // if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL) - } // end for loop on UE_id - } // if((1<<tmp) & deltaTSFC) - } // SRS config not NULL - } // end for loop on CC_id -} - -//----------------------------------------------------------------------------- -/* -* Schedule the CSI (CQI/PMI/RI/PTI/CRI) periodic reception -*/ -void schedule_CSI(module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP) -//----------------------------------------------------------------------------- -{ - int CC_id = 0; - int UE_id = 0; - int H = 0; - uint16_t Npd = 0; - uint16_t N_OFFSET_CQI = 0; - struct LTE_CQI_ReportPeriodic *cqi_ReportPeriodic = NULL; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - COMMON_channels_t *cc = NULL; - nfapi_ul_config_request_body_t *ul_req = NULL; - UE_sched_ctrl *UE_scheduling_control = NULL; - - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - cc = &eNB->common_channels[CC_id]; - - for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { - if (UE_list->active[UE_id] == FALSE) { - continue; - } - - /* Drop the allocation if the UE hasn't sent RRCConnectionSetupComplete yet */ - if (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) { - continue; - } - - AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, - "physicalConfigDedicated is null for UE %d\n", - UE_id); - /* - * CDRX condition on Active Time and CSI report on PUCCH (36.321 5.7). - * Here we consider classic periodic reports on PUCCH without PUSCH simultaneous transmission condition. - * TODO: add the handling or test on simultaneous PUCCH/PUSCH transmission - */ - UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]); - - if (UE_scheduling_control->cdrx_configured == TRUE) { - /* Test if CQI masking activated */ - if (UE_scheduling_control->cqi_mask_boolean == TRUE) { - // CQI masking => test if onDurationTime not running since 6+ subframe - if (UE_scheduling_control->on_duration_timer == 0) { - /* - * TODO: 6+ subframes condition not checked here - */ - continue; - } - } else { // No CQI masking => test if Active Time not running since 6+ subframe - if (UE_scheduling_control->in_active_time == FALSE) { - /* - * TODO: 6+ subframes condition not checked here - */ - continue; - } - } - } - - ul_req = &(eNB->UL_req[CC_id].ul_config_request_body); - - if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL) { - cqi_ReportPeriodic = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic; - - if (cqi_ReportPeriodic != NULL) { - /* Rel8 Periodic CSI (CQI/PMI/RI) reporting */ - if (cqi_ReportPeriodic->present != LTE_CQI_ReportPeriodic_PR_release) { - get_csi_params(cc, cqi_ReportPeriodic, &Npd, &N_OFFSET_CQI, &H); - - if ((((frameP * 10) + subframeP) % Npd) == N_OFFSET_CQI) { // CQI periodic opportunity - UE_scheduling_control->feedback_cnt[CC_id] = (((frameP * 10) + subframeP) / Npd) % H; - - // Program CQI - nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; - memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); - - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; - ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu)); - ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; - ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = get_rel8_dl_cqi_pmi_size(&UE_list->UE_sched_ctrl[UE_id], CC_id, cc, get_tmode(module_idP, CC_id, UE_id), cqi_ReportPeriodic); - ul_req->number_of_pdus++; - ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) - // PUT rel10-13 UCI options here -#endif - } else if (cqi_ReportPeriodic->choice.setup.ri_ConfigIndex != NULL) { - if ((((frameP * 10) + subframeP) % ((H * Npd) << (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex / 161))) == - N_OFFSET_CQI + (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex % 161)) { // RI opportunity - - // Program RI - nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; - memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); - - ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; - ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu)); - ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; - ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; - ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = (cc->p_eNB == 2) ? 1 : 2; - RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; - ul_req->number_of_pdus++; - ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - } - } - } // if CSI Periodic is not release state - } // if (cqi_ReportPeriodic != NULL) - } // if cqi_ReportConfig != NULL - } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { - } // for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { -} - -//----------------------------------------------------------------------------- -/* -* Schedule a possible Scheduling Request reception -*/ -void -schedule_SR (module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP) -//----------------------------------------------------------------------------- -{ - int skip_ue = 0; - int is_harq = 0; - int pdu_list_index = 0; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &eNB->UE_list; - nfapi_ul_config_request_t *ul_req = NULL; - nfapi_ul_config_request_body_t *ul_req_body = NULL; - LTE_SchedulingRequestConfig_t *SRconfig = NULL; - nfapi_ul_config_sr_information sr; - - for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; - - for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { - if (!UE_list->active[UE_id]) { - continue; - } - - if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) continue; - - if ((SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig) != NULL) { - if (SRconfig->present == LTE_SchedulingRequestConfig_PR_setup) { - if (SRconfig->choice.setup.sr_ConfigIndex <= 4) { // 5 ms SR period - if ((subframeP % 5) != SRconfig->choice.setup.sr_ConfigIndex) continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 14) { // 10 ms SR period - if (subframeP != (SRconfig->choice.setup.sr_ConfigIndex - 5)) continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 34) { // 20 ms SR period - if ((10 * (frameP & 1) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 15)) continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 74) { // 40 ms SR period - if ((10 * (frameP & 3) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 35)) continue; - } else if (SRconfig->choice.setup.sr_ConfigIndex <= 154) { // 80 ms SR period - if ((10 * (frameP & 7) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 75)) continue; - } - } // SRconfig->present == SchedulingRequestConfig_PR_setup) - } // SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL) - - /* If we get here there is some PUCCH1 reception to schedule for SR */ - ul_req = &(eNB->UL_req[CC_id]); - ul_req_body = &(ul_req->ul_config_request_body); - skip_ue = 0; - is_harq = 0; - pdu_list_index = 0; - - /* Check that there is no existing UL grant for ULSCH which overrides the SR */ - for (int i = 0; i < ul_req_body->number_of_pdus; i++) { - if (((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) || - (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) || - (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) || - (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) && - (ul_req_body->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { - skip_ue = 1; - pdu_list_index = i; - break; - } - /* If there is already an HARQ pdu, convert to SR_HARQ */ - else if ((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) && - (ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { - is_harq = 1; - pdu_list_index = i; - break; - } - } - - /* Drop the allocation because ULSCH will handle it with BSR */ - if (skip_ue == 1) continue; - - LOG_D(MAC, "Frame %d, Subframe %d : Scheduling SR for UE %d/%x is_harq:%d \n", - frameP, - subframeP, - UE_id, - UE_list->UE_template[CC_id][UE_id].rnti, - is_harq); - - /* Check Rel10 or Rel8 SR */ -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) - if ((UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) && - (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020) && - (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)) { - sr.sr_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG; - sr.sr_information_rel10.number_of_pucch_resources = 1; - sr.sr_information_rel10.pucch_index_p1 = *UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10; - - LOG_D(MAC, "REL10 PUCCH INDEX P1:%d \n", sr.sr_information_rel10.pucch_index_p1); - - } else -#endif - { - sr.sr_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG; - sr.sr_information_rel8.pucch_index = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex; - - LOG_D(MAC, "REL8 PUCCH INDEX:%d\n", sr.sr_information_rel8.pucch_index); - } - - /* If there is already an HARQ pdu, convert to SR_HARQ */ - if (is_harq) { - nfapi_ul_config_harq_information harq = ul_req_body->ul_config_pdu_list[pdu_list_index].uci_harq_pdu.harq_information; - ul_req_body->ul_config_pdu_list[pdu_list_index].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; - ul_req_body->ul_config_pdu_list[pdu_list_index].uci_sr_harq_pdu.sr_information = sr; - ul_req_body->ul_config_pdu_list[pdu_list_index].uci_sr_harq_pdu.harq_information = harq; - } else { - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel11.tl.tag = 0; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel13.tl.tag = 0; - ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.sr_information = sr; - ul_req_body->number_of_pdus++; - } // if (is_harq) - - ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; - - } // for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) - } // for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) -} - -void -check_ul_failure(module_id_t module_idP, int CC_id, int UE_id, - frame_t frameP, sub_frame_t subframeP) { - UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; - nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; - uint16_t rnti = UE_RNTI(module_idP, UE_id); - COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; - - // check uplink failure - if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 0) && - (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) { - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 1) - LOG_I(MAC, "UE %d rnti %x: UL Failure timer %d \n", UE_id, rnti, - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); - - if (UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) { - UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 1; - // add a format 1A dci for this UE to request an RA procedure (only one UE per subframe) - nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req[CC_id].dl_config_request_body.dl_config_pdu_list[DL_req[CC_id].dl_config_request_body.number_pdu]; - memset((void *) dl_config_pdu, 0,sizeof(nfapi_dl_config_request_pdu_t)); - dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; - dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), - UE_list->UE_sched_ctrl[UE_id]. - dl_cqi[CC_id], format1A); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power - AssertFatal((cc[CC_id].mib->message.dl_Bandwidth >= 0) && (cc[CC_id].mib->message.dl_Bandwidth < 6), - "illegal dl_Bandwidth %d\n", - (int) cc[CC_id].mib->message.dl_Bandwidth); - dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = pdcch_order_table[cc[CC_id].mib->message.dl_Bandwidth]; - DL_req[CC_id].dl_config_request_body.number_dci++; - DL_req[CC_id].dl_config_request_body.number_pdu++; - DL_req[CC_id].dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; - LOG_D(MAC, - "UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n", - UE_id, rnti, - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer, - dl_config_pdu->dci_dl_pdu. - dci_dl_pdu_rel8.resource_block_coding); - } else { // ra_pdcch_sent==1 - LOG_D(MAC, - "UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n", - UE_id, rnti, - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); - - if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer % 80) == 0) UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0; // resend every 8 frames - } - - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++; - - // check threshold - if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 4000) { - // note: probably ul_failure_timer should be less than UE radio link failure time(see T310/N310/N311) - if (NODE_IS_DU(RC.rrc[module_idP]->node_type)) { - MessageDef *m = itti_alloc_new_message(TASK_MAC_ENB, F1AP_UE_CONTEXT_RELEASE_REQ); - F1AP_UE_CONTEXT_RELEASE_REQ(m).rnti = rnti; - F1AP_UE_CONTEXT_RELEASE_REQ(m).cause = F1AP_CAUSE_RADIO_NETWORK; - F1AP_UE_CONTEXT_RELEASE_REQ(m).cause_value = 1; // 1 = F1AP_CauseRadioNetwork_rl_failure - F1AP_UE_CONTEXT_RELEASE_REQ(m).rrc_container = NULL; - F1AP_UE_CONTEXT_RELEASE_REQ(m).rrc_container_length = 0; - itti_send_msg_to_task(TASK_DU_F1, module_idP, m); - } else { - // inform RRC of failure and clear timer - LOG_I(MAC, "UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n", - UE_id, - rnti); - mac_eNB_rrc_ul_failure(module_idP, - CC_id, - frameP, - subframeP, - rnti); - } - - UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; - UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; - } - } // ul_failure_timer>0 -} - -void -clear_nfapi_information(eNB_MAC_INST *eNB, int CC_idP, - frame_t frameP, sub_frame_t subframeP) { - nfapi_dl_config_request_t *DL_req = &eNB->DL_req[0]; - nfapi_ul_config_request_t *UL_req = &eNB->UL_req[0]; - nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[CC_idP][subframeP]; - nfapi_tx_request_t *TX_req = &eNB->TX_req[0]; - eNB->pdu_index[CC_idP] = 0; - - if (NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MONOLITHIC) { // monolithic or PNF - DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1; - DL_req[CC_idP].dl_config_request_body.number_dci = 0; - DL_req[CC_idP].dl_config_request_body.number_pdu = 0; - DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0; - DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000; - DL_req[CC_idP].sfn_sf = subframeP + (frameP<<4); - HI_DCI0_req->hi_dci0_request_body.sfnsf = subframeP + (frameP<<4); - HI_DCI0_req->hi_dci0_request_body.number_of_dci = 0; - UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0; - UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now - UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now - TX_req[CC_idP].tx_request_body.number_of_pdus = 0; - } -} - -void -copy_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { - int CC_id; - eNB_MAC_INST *mac = RC.mac[module_idP]; - - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][subframeP]; - nfapi_ul_config_request_t *ul_req = &mac->UL_req[CC_id]; - nfapi_ul_config_request_pdu_t *ul_req_pdu = ul_req->ul_config_request_body.ul_config_pdu_list; - *ul_req = *ul_req_tmp; - // Restore the pointer - ul_req->ul_config_request_body.ul_config_pdu_list = ul_req_pdu; - ul_req->sfn_sf = (frameP<<4) + subframeP; - ul_req_tmp->ul_config_request_body.number_of_pdus = 0; - - if (ul_req->ul_config_request_body.number_of_pdus>0) { - LOG_D(PHY, "%s() active NOW (frameP:%d subframeP:%d) pdus:%d\n", __FUNCTION__, frameP, subframeP, ul_req->ul_config_request_body.number_of_pdus); - } - - memcpy((void *)ul_req->ul_config_request_body.ul_config_pdu_list, - (void *)ul_req_tmp->ul_config_request_body.ul_config_pdu_list, - ul_req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t)); - } -} - -void -eNB_dlsch_ulsch_scheduler(module_id_t module_idP, - frame_t frameP, - sub_frame_t subframeP) -{ - int mbsfn_status[MAX_NUM_CCs]; - protocol_ctxt_t ctxt; - rnti_t rnti = 0; - int CC_id = 0; - int UE_id = -1; - eNB_MAC_INST *eNB = RC.mac[module_idP]; - UE_list_t *UE_list = &(eNB->UE_list); - COMMON_channels_t *cc = eNB->common_channels; - UE_sched_ctrl *UE_scheduling_control = NULL; - - start_meas(&(eNB->eNB_scheduler)); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_IN); - - eNB->frame = frameP; - eNB->subframe = subframeP; - - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - mbsfn_status[CC_id] = 0; - - /* Clear vrb_maps */ - memset(cc[CC_id].vrb_map, 0, 100); - memset(cc[CC_id].vrb_map_UL, 0, 100); - -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) - cc[CC_id].mcch_active = 0; -#endif - clear_nfapi_information(RC.mac[module_idP], CC_id, frameP, subframeP); - } - - /* Refresh UE list based on UEs dropped by PHY in previous subframe */ - for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { - if (UE_list->active[UE_id]) { - rnti = UE_RNTI(module_idP, UE_id); - CC_id = UE_PCCID(module_idP, UE_id); - - UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]); - - if (((frameP & 127) == 0) && (subframeP == 0)) { - LOG_I(MAC,"UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n", - rnti, - UE_scheduling_control->ul_out_of_sync == 0 ? "in synch" : "out of sync", - UE_list->UE_template[CC_id][UE_id].phr_info, - UE_scheduling_control->dl_cqi[CC_id], - (5 * UE_scheduling_control->pusch_snr[CC_id] - 640) / 10, - (5 * UE_scheduling_control->pucch1_snr[CC_id] - 640) / 10); - } - - RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP] = -63; - - if (UE_id == UE_list->head) { - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP]); - } - - /* Set and increment CDRX related timers */ - if (UE_scheduling_control->cdrx_configured == TRUE) { - boolean_t harq_active_time_condition = FALSE; - UE_TEMPLATE *UE_template = NULL; - - unsigned long active_time_condition = 0; // variable used only for tracing purpose - - /* (UL and DL) HARQ RTT timers and DRX retransmission timers */ - for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) { - /* DL asynchronous HARQ process */ - if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > 0) { - UE_scheduling_control->drx_retransmission_timer[harq_process_id]++; - - if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > UE_scheduling_control->drx_retransmission_timer_thres[harq_process_id]) { - UE_scheduling_control->drx_retransmission_timer[harq_process_id] = 0; - } - } - - if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 0) { - UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id]++; - - if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 8) { - /* Note: here drx_retransmission_timer is restarted instead of started in the specification */ - UE_scheduling_control->drx_retransmission_timer[harq_process_id] = 1; // started when HARQ RTT timer expires - UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] = 0; - } - } - - /* UL asynchronous HARQ process: only UL HARQ RTT timer is implemented (hence not implemented) */ - if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 0) { - UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id]++; - - if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 4) { - /* - * TODO: implement the handling of UL asynchronous HARQ - * drx_ULRetransmissionTimer should be (re)started here - */ - UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] = 0; - } - } - - /* UL synchronous HARQ process */ - if (UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] > 0) { - UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id]++; - - if (UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] > 5) { - harq_active_time_condition = TRUE; - UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] = 0; - active_time_condition = 5; // for tracing purpose - } - } - } - - /* On duration timer */ - if (UE_scheduling_control->on_duration_timer > 0) { - UE_scheduling_control->on_duration_timer++; - - if (UE_scheduling_control->on_duration_timer > UE_scheduling_control->on_duration_timer_thres) { - UE_scheduling_control->on_duration_timer = 0; - } - } - - /* DRX inactivity timer */ - if (UE_scheduling_control->drx_inactivity_timer > 0) { - UE_scheduling_control->drx_inactivity_timer++; - - if (UE_scheduling_control->drx_inactivity_timer > (UE_scheduling_control->drx_inactivity_timer_thres + 1)) { - /* Note: the +1 on the threshold is due to information in table C-1 of 36.321 */ - UE_scheduling_control->drx_inactivity_timer = 0; - - /* When timer expires switch into short or long DRX cycle */ - if (UE_scheduling_control->drx_shortCycle_timer_thres > 0) { - UE_scheduling_control->in_short_drx_cycle = TRUE; - UE_scheduling_control->drx_shortCycle_timer = 0; - UE_scheduling_control->in_long_drx_cycle = FALSE; - } else { - UE_scheduling_control->in_long_drx_cycle = TRUE; - } - } - } - - /* Short DRX Cycle */ - if (UE_scheduling_control->in_short_drx_cycle == TRUE) { - UE_scheduling_control->drx_shortCycle_timer++; - - /* When the Short DRX cycles are over, switch to long DRX cycle */ - if (UE_scheduling_control->drx_shortCycle_timer > UE_scheduling_control->drx_shortCycle_timer_thres) { - UE_scheduling_control->drx_shortCycle_timer = 0; - UE_scheduling_control->in_short_drx_cycle = FALSE; - UE_scheduling_control->in_long_drx_cycle = TRUE; - UE_scheduling_control->drx_longCycle_timer = 0; - } - } else { - UE_scheduling_control->drx_shortCycle_timer = 0; - } - - /* Long DRX Cycle */ - if (UE_scheduling_control->in_long_drx_cycle == TRUE) { - UE_scheduling_control->drx_longCycle_timer++; - - if (UE_scheduling_control->drx_longCycle_timer > UE_scheduling_control->drx_longCycle_timer_thres) { - UE_scheduling_control->drx_longCycle_timer = 1; - } - } else { - UE_scheduling_control->drx_longCycle_timer = 0; - } - - /* Check for error cases */ - if ((UE_scheduling_control->in_short_drx_cycle == TRUE) && (UE_scheduling_control->in_long_drx_cycle == TRUE)) { - LOG_E(MAC, "Error in C-DRX: UE id %d is in both short and long DRX cycle. Should not happen. Back it to long cycle only\n", UE_id); - UE_scheduling_control->in_short_drx_cycle = FALSE; - } - - /* Condition to start On Duration Timer */ - if (UE_scheduling_control->in_short_drx_cycle == TRUE && UE_scheduling_control->on_duration_timer == 0) { - if (((frameP * 10) + subframeP) % (UE_scheduling_control->short_drx_cycle_duration) == - (UE_scheduling_control->drx_start_offset) % (UE_scheduling_control->short_drx_cycle_duration)) { - - UE_scheduling_control->on_duration_timer = 1; - } - } else if (UE_scheduling_control->in_long_drx_cycle == TRUE && UE_scheduling_control->on_duration_timer == 0) { - if (((frameP * 10) + subframeP) % (UE_scheduling_control->drx_longCycle_timer_thres) == - (UE_scheduling_control->drx_start_offset)) { - - UE_scheduling_control->on_duration_timer = 1; - } - } - - /* Update Active Time status of UE - * Based on 36.321 5.7 the differents conditions for the UE to be in Acttive Should be check ONLY - * here for the current subframe. The variable 'UE_scheduling_control->in_active_time' should be updated - * ONLY here. The variable can then be used for testing the actual state of the UE for scheduling purpose. - */ - UE_template = &(UE_list->UE_template[CC_id][UE_id]); - /* (a)synchronous HARQ processes handling for Active Time */ - for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) { - if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > 0) { - harq_active_time_condition = TRUE; - active_time_condition = 2; // for tracing purpose - break; - } - } - - /* Active time conditions */ - if (UE_scheduling_control->on_duration_timer > 0 || - UE_scheduling_control->drx_inactivity_timer > 1 || - harq_active_time_condition || - UE_template->ul_SR > 0) { - - UE_scheduling_control->in_active_time = TRUE; - - } else { - UE_scheduling_control->in_active_time = FALSE; - } - - /* BEGIN VCD */ - if (UE_id == 0) { - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_ON_DURATION_TIMER, (unsigned long) UE_scheduling_control->on_duration_timer); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_INACTIVITY, (unsigned long) UE_scheduling_control->drx_inactivity_timer); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_SHORT_CYCLE, (unsigned long) UE_scheduling_control->drx_shortCycle_timer); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_LONG_CYCLE, (unsigned long) UE_scheduling_control->drx_longCycle_timer); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_RETRANSMISSION_HARQ0, (unsigned long) UE_scheduling_control->drx_retransmission_timer[0]); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME, (unsigned long) UE_scheduling_control->in_active_time); - - /* For tracing purpose */ - if (UE_template->ul_SR > 0) { - active_time_condition = 1; - } else if ((UE_scheduling_control->on_duration_timer > 0) && (active_time_condition == 0)) { - active_time_condition = 3; - } else if ((UE_scheduling_control->drx_inactivity_timer > 1) && (active_time_condition == 0)) { - active_time_condition = 4; - } - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME_CONDITION, (unsigned long) active_time_condition); - } - /* END VCD */ - - /* DCI0 ongoing timer */ - if (UE_scheduling_control->dci0_ongoing_timer > 0) { - if (UE_scheduling_control->dci0_ongoing_timer > 7) { - UE_scheduling_control->dci0_ongoing_timer = 0; - } else { - UE_scheduling_control->dci0_ongoing_timer++; - } - } - - } else { // else: CDRX not configured - /* Note: (UL) HARQ RTT timers processing is done here and can be used by other features than CDRX */ - /* HARQ RTT timers */ - for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) { - if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 0) { - UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id]++; - - if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 8) { - UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] = 0; - } - } - - if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 0) { - UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id]++; - - if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 4) { - UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] = 0; - } - } - } // end loop harq process - } // end else CDRX not configured - - /* Increment these timers, they are cleared when we receive an sdu */ - UE_scheduling_control->ul_inactivity_timer++; - UE_scheduling_control->cqi_req_timer++; - - LOG_D(MAC, "UE %d/%x : ul_inactivity %d, cqi_req %d\n", - UE_id, - rnti, - UE_scheduling_control->ul_inactivity_timer, - UE_scheduling_control->cqi_req_timer); - - check_ul_failure(module_idP, CC_id, UE_id, frameP, subframeP); - - if (UE_scheduling_control->ue_reestablishment_reject_timer > 0) { - UE_scheduling_control->ue_reestablishment_reject_timer++; - - if (UE_scheduling_control->ue_reestablishment_reject_timer >= UE_scheduling_control->ue_reestablishment_reject_timer_thres) { - UE_scheduling_control->ue_reestablishment_reject_timer = 0; - - - /* Clear reestablish_rnti_map */ - if (UE_scheduling_control->ue_reestablishment_reject_timer_thres > 20) { - for (int ue_id_l = 0; ue_id_l < MAX_MOBILES_PER_ENB; ue_id_l++) { - if (reestablish_rnti_map[ue_id_l][0] == rnti) { - /* Clear currentC-RNTI from map */ - reestablish_rnti_map[ue_id_l][0] = 0; - reestablish_rnti_map[ue_id_l][1] = 0; - break; - } - } - - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, rnti, 0, 0,module_idP); - rrc_rlc_remove_ue(&ctxt); - pdcp_remove_UE(&ctxt); - } - - /* Note: This should not be done in the MAC! */ - for (int ii=0; ii<MAX_MOBILES_PER_ENB; ii++) { - LTE_eNB_ULSCH_t *ulsch = RC.eNB[module_idP][CC_id]->ulsch[ii]; - - if((ulsch != NULL) && (ulsch->rnti == rnti)) { - void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch); - - LOG_I(MAC, "clean_eNb_ulsch UE %x \n", rnti); - - clean_eNb_ulsch(ulsch); - } - } - - for (int ii=0; ii<MAX_MOBILES_PER_ENB; ii++) { - LTE_eNB_DLSCH_t *dlsch = RC.eNB[module_idP][CC_id]->dlsch[ii][0]; - - if((dlsch != NULL) && (dlsch->rnti == rnti)) { - void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch); - - LOG_I(MAC, "clean_eNb_dlsch UE %x \n", rnti); - - clean_eNb_dlsch(dlsch); - } - } - - for (int j = 0; j < 10; j++) { - nfapi_ul_config_request_body_t *ul_req_tmp = NULL; - ul_req_tmp = &(eNB->UL_req_tmp[CC_id][j].ul_config_request_body); - - if (ul_req_tmp) { - int pdu_number = ul_req_tmp->number_of_pdus; - - for (int pdu_index = pdu_number-1; pdu_index >= 0; pdu_index--) { - if (ul_req_tmp->ul_config_pdu_list[pdu_index].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) { - LOG_I(MAC, "remove UE %x from ul_config_pdu_list %d/%d\n", - rnti, - pdu_index, - pdu_number); - - if (pdu_index < pdu_number -1) { - memcpy(&ul_req_tmp->ul_config_pdu_list[pdu_index], - &ul_req_tmp->ul_config_pdu_list[pdu_index+1], - (pdu_number-1-pdu_index) * sizeof(nfapi_ul_config_request_pdu_t)); - } - - ul_req_tmp->number_of_pdus--; - } - } // end for pdu_index - } // end if (ul_req_tmp) - } // end for j - - rrc_mac_remove_ue(module_idP,rnti); - - } // end if (UE_scheduling_control->ue_reestablishment_reject_timer >= UE_scheduling_control->ue_reestablishment_reject_timer_thres) - } // end if (UE_scheduling_control->ue_reestablishment_reject_timer > 0) - } // end if UE active - } // end for loop on UE_id - -#if (!defined(PRE_SCD_THREAD)) - - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP, module_idP); - pdcp_run(&ctxt); - rrc_rx_tx(&ctxt, CC_id); - -#endif -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) - - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - if (cc[CC_id].MBMS_flag > 0) { - start_meas(&RC.mac[module_idP]->schedule_mch); - mbsfn_status[CC_id] = schedule_MBMS(module_idP, CC_id, frameP, subframeP); - stop_meas(&RC.mac[module_idP]->schedule_mch); - } - } - -#endif - - static int debug_flag = 0; - void (*schedule_ulsch_p)(module_id_t module_idP, frame_t frameP, sub_frame_t subframe) = NULL; - void (*schedule_ue_spec_p)(module_id_t module_idP, frame_t frameP, sub_frame_t subframe, int *mbsfn_flag) = NULL; - - if (eNB->scheduler_mode == SCHED_MODE_DEFAULT) { - schedule_ulsch_p = schedule_ulsch; - schedule_ue_spec_p = schedule_dlsch; - } else if (eNB->scheduler_mode == SCHED_MODE_FAIR_RR) { - memset(dlsch_ue_select, 0, sizeof(dlsch_ue_select)); - schedule_ulsch_p = schedule_ulsch_fairRR; - schedule_ue_spec_p = schedule_ue_spec_fairRR; - } - - if(debug_flag == 0){ - LOG_E(MAC,"SCHED_MODE = %d\n", eNB->scheduler_mode); - debug_flag = 1; - } - - /* This schedules MIB */ - if ((subframeP == 0) && (frameP & 3) == 0) - schedule_mib(module_idP, frameP, subframeP); - - if (get_softmodem_params()->phy_test == 0) { - /* This schedules SI for legacy LTE and eMTC starting in subframeP */ - schedule_SI(module_idP, frameP, subframeP); - /* This schedules Paging in subframeP */ - schedule_PCH(module_idP,frameP,subframeP); - /* This schedules Random-Access for legacy LTE and eMTC starting in subframeP */ - schedule_RA(module_idP, frameP, subframeP); - /* Copy previously scheduled UL resources (ULSCH + HARQ) */ - copy_ulreq(module_idP, frameP, subframeP); - /* This schedules SRS in subframeP */ - schedule_SRS(module_idP, frameP, subframeP); - - /* This schedules ULSCH in subframeP (dci0) */ - if (schedule_ulsch_p != NULL) { - schedule_ulsch_p(module_idP, frameP, subframeP); - } else { - LOG_E(MAC," %s %d: schedule_ulsch_p is NULL, function not called\n", - __FILE__, - __LINE__); - } - - /* This schedules UCI_SR in subframeP */ - schedule_SR(module_idP, frameP, subframeP); - /* This schedules UCI_CSI in subframeP */ - schedule_CSI(module_idP, frameP, subframeP); -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - /* This schedules DLSCH in subframeP for BR UE*/ - schedule_ue_spec_br(module_idP, frameP, subframeP); -#endif - /* This schedules DLSCH in subframeP */ - if (schedule_ue_spec_p != NULL) { - schedule_ue_spec_p(module_idP, frameP, subframeP, mbsfn_status); - } else { - LOG_E(MAC," %s %d: schedule_ue_spec_p is NULL, function not called\n", - __FILE__, - __LINE__); - } - - } else { - schedule_ulsch_phy_test(module_idP,frameP,subframeP); - schedule_ue_spec_phy_test(module_idP,frameP,subframeP,mbsfn_status); - } - - /* Allocate CCEs for good after scheduling is done */ - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - if (cc[CC_id].tdd_Config == NULL || !(is_UL_sf(&cc[CC_id],subframeP))) { - allocate_CCEs(module_idP, CC_id, frameP, subframeP, 2); - } - } - - if (flexran_agent_get_mac_xface(module_idP) && subframeP == 9) { - flexran_agent_slice_update(module_idP); - } - - stop_meas(&(eNB->eNB_scheduler)); - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_OUT); -} - +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file eNB_scheduler.c + * \brief eNB scheduler top level function operates on per subframe basis + * \author Navid Nikaein and Raymond Knopp + * \date 2010 - 2014 + * \email: navid.nikaein@eurecom.fr + * \version 0.5 + * @ingroup _mac + + */ + +#include "assertions.h" + +#include "targets/RT/USER/lte-softmodem.h" +#include "LAYER2/MAC/mac.h" +#include "LAYER2/MAC/mac_extern.h" + +#include "LAYER2/MAC/mac_proto.h" +#include "common/utils/LOG/log.h" +#include "nfapi/oai_integration/vendor_ext.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "OCG.h" +#include "OCG_extern.h" + +#include "RRC/LTE/rrc_extern.h" +#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" + +//#include "LAYER2/MAC/pre_processor.c" +#include "pdcp.h" + +//Agent-related headers +#include "flexran_agent_extern.h" +#include "flexran_agent_mac.h" + +/* for fair round robin SCHED */ +#include "eNB_scheduler_fairRR.h" + +#if defined(ENABLE_ITTI) + #include "intertask_interface.h" +#endif + +#include "assertions.h" + +#define ENABLE_MAC_PAYLOAD_DEBUG +#define DEBUG_eNB_SCHEDULER 1 + +extern RAN_CONTEXT_t RC; + + +uint16_t pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 }; + +//----------------------------------------------------------------------------- +/* + * Schedule periodic SRS + */ +void schedule_SRS(module_id_t module_idP, + frame_t frameP, + sub_frame_t subframeP) +//----------------------------------------------------------------------------- +{ + int CC_id = 0; + int UE_id = -1; + uint8_t TSFC = 0; + uint8_t srs_SubframeConfig = 0; + uint16_t srsPeriodicity = 0; + uint16_t srsOffset = 0; + uint16_t deltaTSFC = 0; // bitmap + // table for TSFC (Period) and deltaSFC (offset) + const uint16_t deltaTSFCTabType1[15][2] = { {1, 1}, {1, 2}, {2, 2}, {1, 5}, {2, 5}, {4, 5}, {8, 5}, {3, 5}, {12, 5}, {1, 10}, {2, 10}, {4, 10}, {8, 10}, {351, 10}, {383, 10} }; // Table 5.5.3.3-2 3GPP 36.211 FDD + const uint16_t deltaTSFCTabType2[14][2] = { {2, 5}, {6, 5}, {10, 5}, {18, 5}, {14, 5}, {22, 5}, {26, 5}, {30, 5}, {70, 10}, {74, 10}, {194, 10}, {326, 10}, {586, 10}, {210, 10} }; // Table 5.5.3.3-2 3GPP 36.211 TDD + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &(eNB->UE_list); + nfapi_ul_config_request_body_t *ul_req = NULL; + UE_sched_ctrl *UE_scheduling_control = NULL; + COMMON_channels_t *cc = eNB->common_channels; + LTE_SoundingRS_UL_ConfigCommon_t *soundingRS_UL_ConfigCommon = NULL; + struct LTE_SoundingRS_UL_ConfigDedicated *soundingRS_UL_ConfigDedicated = NULL; + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + soundingRS_UL_ConfigCommon = &(cc[CC_id].radioResourceConfigCommon->soundingRS_UL_ConfigCommon); + + /* Check if SRS is enabled in this frame/subframe */ + if (soundingRS_UL_ConfigCommon) { + srs_SubframeConfig = soundingRS_UL_ConfigCommon->choice.setup.srs_SubframeConfig; + + if (cc[CC_id].tdd_Config == NULL) { // FDD + deltaTSFC = deltaTSFCTabType1[srs_SubframeConfig][0]; + TSFC = deltaTSFCTabType1[srs_SubframeConfig][1]; + } else { // TDD + deltaTSFC = deltaTSFCTabType2[srs_SubframeConfig][0]; + TSFC = deltaTSFCTabType2[srs_SubframeConfig][1]; + } + + /* Sounding reference signal subframes are the subframes satisfying ns/2 mod TSFC (- deltaTSFC) */ + uint16_t tmp = (subframeP % TSFC); + + if ((1 << tmp) & deltaTSFC) { + /* This is an SRS subframe, loop over UEs */ + for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { + if (!UE_list->active[UE_id]) { + continue; + } + + /* Drop the allocation if the UE hasn't send RRCConnectionSetupComplete yet */ + if (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) { + continue; + } + + AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, + "physicalConfigDedicated is null for UE %d\n", + UE_id); + + /* CDRX condition on Active Time and SRS type-0 report (36.321 5.7) */ + UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]); + + /* Test if Active Time not running since 6+ subframes */ + if (UE_scheduling_control->cdrx_configured == TRUE && UE_scheduling_control->in_active_time == FALSE) { + /* + * TODO: 6+ subframes condition not checked here + */ + continue; + } + + ul_req = &(eNB->UL_req[CC_id].ul_config_request_body); + + if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated) != NULL) { + if (soundingRS_UL_ConfigDedicated->present == LTE_SoundingRS_UL_ConfigDedicated_PR_setup) { + get_srs_pos(&cc[CC_id], + soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex, + &srsPeriodicity, + &srsOffset); + + if (((10 * frameP + subframeP) % srsPeriodicity) == srsOffset) { + // Program SRS + ul_req->srs_present = 1; + nfapi_ul_config_request_pdu_t *ul_config_pdu = &(ul_req->ul_config_pdu_list[ul_req->number_of_pdus]); + memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_SRS_PDU_TYPE; + ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_srs_pdu)); + ul_config_pdu->srs_pdu.srs_pdu_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SRS_PDU_REL8_TAG; + ul_config_pdu->srs_pdu.srs_pdu_rel8.size = (uint8_t)sizeof(nfapi_ul_config_srs_pdu); + ul_config_pdu->srs_pdu.srs_pdu_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_Bandwidth; + ul_config_pdu->srs_pdu.srs_pdu_rel8.frequency_domain_position = soundingRS_UL_ConfigDedicated->choice.setup.freqDomainPosition; + ul_config_pdu->srs_pdu.srs_pdu_rel8.srs_hopping_bandwidth = soundingRS_UL_ConfigDedicated->choice.setup.srs_HoppingBandwidth;; + ul_config_pdu->srs_pdu.srs_pdu_rel8.transmission_comb = soundingRS_UL_ConfigDedicated->choice.setup.transmissionComb; + ul_config_pdu->srs_pdu.srs_pdu_rel8.i_srs = soundingRS_UL_ConfigDedicated->choice.setup.srs_ConfigIndex; + ul_config_pdu->srs_pdu.srs_pdu_rel8.sounding_reference_cyclic_shift = soundingRS_UL_ConfigDedicated->choice.setup.cyclicShift; + + eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; + eNB->UL_req[CC_id].header.message_id = NFAPI_UL_CONFIG_REQUEST; + ul_req->number_of_pdus++; + } // if (((10*frameP+subframeP) % srsPeriodicity) == srsOffset) + } // if (soundingRS_UL_ConfigDedicated->present == SoundingRS_UL_ConfigDedicated_PR_setup) + } // if ((soundingRS_UL_ConfigDedicated = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->soundingRS_UL_ConfigDedicated)!=NULL) + } // end for loop on UE_id + } // if((1<<tmp) & deltaTSFC) + } // SRS config not NULL + } // end for loop on CC_id +} + +//----------------------------------------------------------------------------- +/* +* Schedule the CSI (CQI/PMI/RI/PTI/CRI) periodic reception +*/ +void schedule_CSI(module_id_t module_idP, + frame_t frameP, + sub_frame_t subframeP) +//----------------------------------------------------------------------------- +{ + int CC_id = 0; + int UE_id = 0; + int H = 0; + uint16_t Npd = 0; + uint16_t N_OFFSET_CQI = 0; + struct LTE_CQI_ReportPeriodic *cqi_ReportPeriodic = NULL; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + COMMON_channels_t *cc = NULL; + nfapi_ul_config_request_body_t *ul_req = NULL; + UE_sched_ctrl *UE_scheduling_control = NULL; + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + cc = &eNB->common_channels[CC_id]; + + for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { + if (UE_list->active[UE_id] == FALSE) { + continue; + } + + /* Drop the allocation if the UE hasn't sent RRCConnectionSetupComplete yet */ + if (mac_eNB_get_rrc_status(module_idP, UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED) { + continue; + } + + AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL, + "physicalConfigDedicated is null for UE %d\n", + UE_id); + /* + * CDRX condition on Active Time and CSI report on PUCCH (36.321 5.7). + * Here we consider classic periodic reports on PUCCH without PUSCH simultaneous transmission condition. + * TODO: add the handling or test on simultaneous PUCCH/PUSCH transmission + */ + UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]); + + if (UE_scheduling_control->cdrx_configured == TRUE) { + /* Test if CQI masking activated */ + if (UE_scheduling_control->cqi_mask_boolean == TRUE) { + // CQI masking => test if onDurationTime not running since 6+ subframe + if (UE_scheduling_control->on_duration_timer == 0) { + /* + * TODO: 6+ subframes condition not checked here + */ + continue; + } + } else { // No CQI masking => test if Active Time not running since 6+ subframe + if (UE_scheduling_control->in_active_time == FALSE) { + /* + * TODO: 6+ subframes condition not checked here + */ + continue; + } + } + } + + ul_req = &(eNB->UL_req[CC_id].ul_config_request_body); + + if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig != NULL) { + cqi_ReportPeriodic = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic; + + if (cqi_ReportPeriodic != NULL) { + /* Rel8 Periodic CSI (CQI/PMI/RI) reporting */ + if (cqi_ReportPeriodic->present != LTE_CQI_ReportPeriodic_PR_release) { + get_csi_params(cc, cqi_ReportPeriodic, &Npd, &N_OFFSET_CQI, &H); + + if ((((frameP * 10) + subframeP) % Npd) == N_OFFSET_CQI) { // CQI periodic opportunity + UE_scheduling_control->feedback_cnt[CC_id] = (((frameP * 10) + subframeP) / Npd) % H; + + // Program CQI + nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); + + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; + ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu)); + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = get_rel8_dl_cqi_pmi_size(&UE_list->UE_sched_ctrl[UE_id], CC_id, cc, get_tmode(module_idP, CC_id, UE_id), cqi_ReportPeriodic); + ul_req->number_of_pdus++; + ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) + // PUT rel10-13 UCI options here +#endif + } else if (cqi_ReportPeriodic->choice.setup.ri_ConfigIndex != NULL) { + if ((((frameP * 10) + subframeP) % ((H * Npd) << (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex / 161))) == + N_OFFSET_CQI + (*cqi_ReportPeriodic->choice.setup.ri_ConfigIndex % 161)) { // RI opportunity + + // Program RI + nfapi_ul_config_request_pdu_t *ul_config_pdu = &ul_req->ul_config_pdu_list[ul_req->number_of_pdus]; + memset((void *) ul_config_pdu, 0, sizeof(nfapi_ul_config_request_pdu_t)); + + ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_CQI_PDU_TYPE; + ul_config_pdu->pdu_size = 2 + (uint8_t) (2 + sizeof(nfapi_ul_config_uci_cqi_pdu)); + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ul_config_pdu->uci_cqi_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_CQI_INFORMATION_REL8_TAG; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.pucch_index = cqi_ReportPeriodic->choice.setup.cqi_PUCCH_ResourceIndex; + ul_config_pdu->uci_cqi_pdu.cqi_information.cqi_information_rel8.dl_cqi_pmi_size = (cc->p_eNB == 2) ? 1 : 2; + RC.mac[module_idP]->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; + ul_req->number_of_pdus++; + ul_req->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + } + } + } // if CSI Periodic is not release state + } // if (cqi_ReportPeriodic != NULL) + } // if cqi_ReportConfig != NULL + } // for (UE_id=UE_list->head; UE_id>=0; UE_id=UE_list->next[UE_id]) { + } // for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { +} + +//----------------------------------------------------------------------------- +/* +* Schedule a possible Scheduling Request reception +*/ +void +schedule_SR (module_id_t module_idP, + frame_t frameP, + sub_frame_t subframeP) +//----------------------------------------------------------------------------- +{ + int skip_ue = 0; + int is_harq = 0; + int pdu_list_index = 0; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &eNB->UE_list; + nfapi_ul_config_request_t *ul_req = NULL; + nfapi_ul_config_request_body_t *ul_req_body = NULL; + LTE_SchedulingRequestConfig_t *SRconfig = NULL; + nfapi_ul_config_sr_information sr; + + for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + eNB->UL_req[CC_id].sfn_sf = (frameP << 4) + subframeP; + + for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { + if (!UE_list->active[UE_id]) { + continue; + } + + if (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) continue; + + if ((SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig) != NULL) { + if (SRconfig->present == LTE_SchedulingRequestConfig_PR_setup) { + if (SRconfig->choice.setup.sr_ConfigIndex <= 4) { // 5 ms SR period + if ((subframeP % 5) != SRconfig->choice.setup.sr_ConfigIndex) continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 14) { // 10 ms SR period + if (subframeP != (SRconfig->choice.setup.sr_ConfigIndex - 5)) continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 34) { // 20 ms SR period + if ((10 * (frameP & 1) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 15)) continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 74) { // 40 ms SR period + if ((10 * (frameP & 3) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 35)) continue; + } else if (SRconfig->choice.setup.sr_ConfigIndex <= 154) { // 80 ms SR period + if ((10 * (frameP & 7) + subframeP) != (SRconfig->choice.setup.sr_ConfigIndex - 75)) continue; + } + } // SRconfig->present == SchedulingRequestConfig_PR_setup) + } // SRconfig = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig)!=NULL) + + /* If we get here there is some PUCCH1 reception to schedule for SR */ + ul_req = &(eNB->UL_req[CC_id]); + ul_req_body = &(ul_req->ul_config_request_body); + skip_ue = 0; + is_harq = 0; + pdu_list_index = 0; + + /* Check that there is no existing UL grant for ULSCH which overrides the SR */ + for (int i = 0; i < ul_req_body->number_of_pdus; i++) { + if (((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_PDU_TYPE) || + (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_HARQ_PDU_TYPE) || + (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_RI_PDU_TYPE) || + (ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_ULSCH_CQI_HARQ_RI_PDU_TYPE)) && + (ul_req_body->ul_config_pdu_list[i].ulsch_pdu.ulsch_pdu_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { + skip_ue = 1; + pdu_list_index = i; + break; + } + /* If there is already an HARQ pdu, convert to SR_HARQ */ + else if ((ul_req_body->ul_config_pdu_list[i].pdu_type == NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE) && + (ul_req_body->ul_config_pdu_list[i].uci_harq_pdu.ue_information.ue_information_rel8.rnti == UE_list->UE_template[CC_id][UE_id].rnti)) { + is_harq = 1; + pdu_list_index = i; + break; + } + } + + /* Drop the allocation because ULSCH will handle it with BSR */ + if (skip_ue == 1) continue; + + LOG_D(MAC, "Frame %d, Subframe %d : Scheduling SR for UE %d/%x is_harq:%d \n", + frameP, + subframeP, + UE_id, + UE_list->UE_template[CC_id][UE_id].rnti, + is_harq); + + /* Check Rel10 or Rel8 SR */ +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) + if ((UE_list-> UE_template[CC_id][UE_id].physicalConfigDedicated->ext2) && + (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020) && + (UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020)) { + sr.sr_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL10_TAG; + sr.sr_information_rel10.number_of_pucch_resources = 1; + sr.sr_information_rel10.pucch_index_p1 = *UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->ext2->schedulingRequestConfig_v1020->sr_PUCCH_ResourceIndexP1_r10; + + LOG_D(MAC, "REL10 PUCCH INDEX P1:%d \n", sr.sr_information_rel10.pucch_index_p1); + + } else +#endif + { + sr.sr_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_SR_INFORMATION_REL8_TAG; + sr.sr_information_rel8.pucch_index = UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated->schedulingRequestConfig->choice.setup.sr_PUCCH_ResourceIndex; + + LOG_D(MAC, "REL8 PUCCH INDEX:%d\n", sr.sr_information_rel8.pucch_index); + } + + /* If there is already an HARQ pdu, convert to SR_HARQ */ + if (is_harq) { + nfapi_ul_config_harq_information harq = ul_req_body->ul_config_pdu_list[pdu_list_index].uci_harq_pdu.harq_information; + ul_req_body->ul_config_pdu_list[pdu_list_index].pdu_type = NFAPI_UL_CONFIG_UCI_SR_HARQ_PDU_TYPE; + ul_req_body->ul_config_pdu_list[pdu_list_index].uci_sr_harq_pdu.sr_information = sr; + ul_req_body->ul_config_pdu_list[pdu_list_index].uci_sr_harq_pdu.harq_information = harq; + } else { + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].pdu_type = NFAPI_UL_CONFIG_UCI_SR_PDU_TYPE; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel8.rnti = UE_list->UE_template[CC_id][UE_id].rnti; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel11.tl.tag = 0; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.ue_information.ue_information_rel13.tl.tag = 0; + ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus].uci_sr_pdu.sr_information = sr; + ul_req_body->number_of_pdus++; + } // if (is_harq) + + ul_req_body->tl.tag = NFAPI_UL_CONFIG_REQUEST_BODY_TAG; + + } // for (int UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) + } // for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) +} + +void +check_ul_failure(module_id_t module_idP, int CC_id, int UE_id, + frame_t frameP, sub_frame_t subframeP) { + UE_list_t *UE_list = &RC.mac[module_idP]->UE_list; + nfapi_dl_config_request_t *DL_req = &RC.mac[module_idP]->DL_req[0]; + uint16_t rnti = UE_RNTI(module_idP, UE_id); + COMMON_channels_t *cc = RC.mac[module_idP]->common_channels; + + // check uplink failure + if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 0) && + (UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync == 0)) { + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer == 1) + LOG_I(MAC, "UE %d rnti %x: UL Failure timer %d \n", UE_id, rnti, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); + + if (UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent == 0) { + UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 1; + // add a format 1A dci for this UE to request an RA procedure (only one UE per subframe) + nfapi_dl_config_request_pdu_t *dl_config_pdu = &DL_req[CC_id].dl_config_request_body.dl_config_pdu_list[DL_req[CC_id].dl_config_request_body.number_pdu]; + memset((void *) dl_config_pdu, 0,sizeof(nfapi_dl_config_request_pdu_t)); + dl_config_pdu->pdu_type = NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE; + dl_config_pdu->pdu_size = (uint8_t) (2 + sizeof(nfapi_dl_config_dci_dl_pdu)); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format = NFAPI_DL_DCI_FORMAT_1A; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level = get_aggregation(get_bw_index(module_idP, CC_id), + UE_list->UE_sched_ctrl[UE_id]. + dl_cqi[CC_id], format1A); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti = rnti; + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type = 1; // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power = 6000; // equal to RS power + AssertFatal((cc[CC_id].mib->message.dl_Bandwidth >= 0) && (cc[CC_id].mib->message.dl_Bandwidth < 6), + "illegal dl_Bandwidth %d\n", + (int) cc[CC_id].mib->message.dl_Bandwidth); + dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = pdcch_order_table[cc[CC_id].mib->message.dl_Bandwidth]; + DL_req[CC_id].dl_config_request_body.number_dci++; + DL_req[CC_id].dl_config_request_body.number_pdu++; + DL_req[CC_id].dl_config_request_body.tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG; + LOG_D(MAC, + "UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n", + UE_id, rnti, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer, + dl_config_pdu->dci_dl_pdu. + dci_dl_pdu_rel8.resource_block_coding); + } else { // ra_pdcch_sent==1 + LOG_D(MAC, + "UE %d rnti %x: sent PDCCH order for RAPROC waiting (failure timer %d) \n", + UE_id, rnti, + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer); + + if ((UE_list->UE_sched_ctrl[UE_id].ul_failure_timer % 80) == 0) UE_list->UE_sched_ctrl[UE_id].ra_pdcch_order_sent = 0; // resend every 8 frames + } + + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer++; + + // check threshold + if (UE_list->UE_sched_ctrl[UE_id].ul_failure_timer > 4000) { + // note: probably ul_failure_timer should be less than UE radio link failure time(see T310/N310/N311) + if (NODE_IS_DU(RC.rrc[module_idP]->node_type)) { + MessageDef *m = itti_alloc_new_message(TASK_MAC_ENB, F1AP_UE_CONTEXT_RELEASE_REQ); + F1AP_UE_CONTEXT_RELEASE_REQ(m).rnti = rnti; + F1AP_UE_CONTEXT_RELEASE_REQ(m).cause = F1AP_CAUSE_RADIO_NETWORK; + F1AP_UE_CONTEXT_RELEASE_REQ(m).cause_value = 1; // 1 = F1AP_CauseRadioNetwork_rl_failure + F1AP_UE_CONTEXT_RELEASE_REQ(m).rrc_container = NULL; + F1AP_UE_CONTEXT_RELEASE_REQ(m).rrc_container_length = 0; + itti_send_msg_to_task(TASK_DU_F1, module_idP, m); + } else { + // inform RRC of failure and clear timer + LOG_I(MAC, "UE %d rnti %x: UL Failure after repeated PDCCH orders: Triggering RRC \n", + UE_id, + rnti); + mac_eNB_rrc_ul_failure(module_idP, + CC_id, + frameP, + subframeP, + rnti); + } + + UE_list->UE_sched_ctrl[UE_id].ul_failure_timer = 0; + UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync = 1; + } + } // ul_failure_timer>0 +} + +void +clear_nfapi_information(eNB_MAC_INST *eNB, int CC_idP, + frame_t frameP, sub_frame_t subframeP) { + nfapi_dl_config_request_t *DL_req = &eNB->DL_req[0]; + nfapi_ul_config_request_t *UL_req = &eNB->UL_req[0]; + nfapi_hi_dci0_request_t *HI_DCI0_req = &eNB->HI_DCI0_req[CC_idP][subframeP]; + nfapi_tx_request_t *TX_req = &eNB->TX_req[0]; + eNB->pdu_index[CC_idP] = 0; + + if (NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MONOLITHIC) { // monolithic or PNF + DL_req[CC_idP].dl_config_request_body.number_pdcch_ofdm_symbols = 1; + DL_req[CC_idP].dl_config_request_body.number_dci = 0; + DL_req[CC_idP].dl_config_request_body.number_pdu = 0; + DL_req[CC_idP].dl_config_request_body.number_pdsch_rnti = 0; + DL_req[CC_idP].dl_config_request_body.transmission_power_pcfich = 6000; + DL_req[CC_idP].sfn_sf = subframeP + (frameP<<4); + HI_DCI0_req->hi_dci0_request_body.sfnsf = subframeP + (frameP<<4); + HI_DCI0_req->hi_dci0_request_body.number_of_dci = 0; + UL_req[CC_idP].ul_config_request_body.number_of_pdus = 0; + UL_req[CC_idP].ul_config_request_body.rach_prach_frequency_resources = 0; // ignored, handled by PHY for now + UL_req[CC_idP].ul_config_request_body.srs_present = 0; // ignored, handled by PHY for now + TX_req[CC_idP].tx_request_body.number_of_pdus = 0; + } +} + +void +copy_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP) { + int CC_id; + eNB_MAC_INST *mac = RC.mac[module_idP]; + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + nfapi_ul_config_request_t *ul_req_tmp = &mac->UL_req_tmp[CC_id][subframeP]; + nfapi_ul_config_request_t *ul_req = &mac->UL_req[CC_id]; + nfapi_ul_config_request_pdu_t *ul_req_pdu = ul_req->ul_config_request_body.ul_config_pdu_list; + *ul_req = *ul_req_tmp; + // Restore the pointer + ul_req->ul_config_request_body.ul_config_pdu_list = ul_req_pdu; + ul_req->sfn_sf = (frameP<<4) + subframeP; + ul_req_tmp->ul_config_request_body.number_of_pdus = 0; + + if (ul_req->ul_config_request_body.number_of_pdus>0) { + LOG_D(PHY, "%s() active NOW (frameP:%d subframeP:%d) pdus:%d\n", __FUNCTION__, frameP, subframeP, ul_req->ul_config_request_body.number_of_pdus); + } + + memcpy((void *)ul_req->ul_config_request_body.ul_config_pdu_list, + (void *)ul_req_tmp->ul_config_request_body.ul_config_pdu_list, + ul_req->ul_config_request_body.number_of_pdus*sizeof(nfapi_ul_config_request_pdu_t)); + } +} + +void +eNB_dlsch_ulsch_scheduler(module_id_t module_idP, + frame_t frameP, + sub_frame_t subframeP) +{ + int mbsfn_status[MAX_NUM_CCs]; + protocol_ctxt_t ctxt; + rnti_t rnti = 0; + int CC_id = 0; + int UE_id = -1; + eNB_MAC_INST *eNB = RC.mac[module_idP]; + UE_list_t *UE_list = &(eNB->UE_list); + COMMON_channels_t *cc = eNB->common_channels; + UE_sched_ctrl *UE_scheduling_control = NULL; + + start_meas(&(eNB->eNB_scheduler)); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_IN); + + eNB->frame = frameP; + eNB->subframe = subframeP; + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + mbsfn_status[CC_id] = 0; + + /* Clear vrb_maps */ + memset(cc[CC_id].vrb_map, 0, 100); + memset(cc[CC_id].vrb_map_UL, 0, 100); + +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) + cc[CC_id].mcch_active = 0; +#endif + clear_nfapi_information(RC.mac[module_idP], CC_id, frameP, subframeP); + } + + /* Refresh UE list based on UEs dropped by PHY in previous subframe */ + for (UE_id = 0; UE_id < MAX_MOBILES_PER_ENB; UE_id++) { + if (UE_list->active[UE_id]) { + rnti = UE_RNTI(module_idP, UE_id); + CC_id = UE_PCCID(module_idP, UE_id); + + UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]); + + if (((frameP & 127) == 0) && (subframeP == 0)) { + LOG_I(MAC,"UE rnti %x : %s, PHR %d dB DL CQI %d PUSCH SNR %d PUCCH SNR %d\n", + rnti, + UE_scheduling_control->ul_out_of_sync == 0 ? "in synch" : "out of sync", + UE_list->UE_template[CC_id][UE_id].phr_info, + UE_scheduling_control->dl_cqi[CC_id], + (5 * UE_scheduling_control->pusch_snr[CC_id] - 640) / 10, + (5 * UE_scheduling_control->pucch1_snr[CC_id] - 640) / 10); + } + + RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP] = -63; + + if (UE_id == UE_list->head) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE0_BSR, RC.eNB[module_idP][CC_id]->pusch_stats_bsr[UE_id][(frameP * 10) + subframeP]); + } + + /* Set and increment CDRX related timers */ + if (UE_scheduling_control->cdrx_configured == TRUE) { + boolean_t harq_active_time_condition = FALSE; + UE_TEMPLATE *UE_template = NULL; + + unsigned long active_time_condition = 0; // variable used only for tracing purpose + + /* (UL and DL) HARQ RTT timers and DRX retransmission timers */ + for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) { + /* DL asynchronous HARQ process */ + if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > 0) { + UE_scheduling_control->drx_retransmission_timer[harq_process_id]++; + + if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > UE_scheduling_control->drx_retransmission_timer_thres[harq_process_id]) { + UE_scheduling_control->drx_retransmission_timer[harq_process_id] = 0; + } + } + + if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 0) { + UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id]++; + + if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 8) { + /* Note: here drx_retransmission_timer is restarted instead of started in the specification */ + UE_scheduling_control->drx_retransmission_timer[harq_process_id] = 1; // started when HARQ RTT timer expires + UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] = 0; + } + } + + /* UL asynchronous HARQ process: only UL HARQ RTT timer is implemented (hence not implemented) */ + if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 0) { + UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id]++; + + if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 4) { + /* + * TODO: implement the handling of UL asynchronous HARQ + * drx_ULRetransmissionTimer should be (re)started here + */ + UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] = 0; + } + } + + /* UL synchronous HARQ process */ + if (UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] > 0) { + UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id]++; + + if (UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] > 5) { + harq_active_time_condition = TRUE; + UE_scheduling_control->ul_synchronous_harq_timer[CC_id][harq_process_id] = 0; + active_time_condition = 5; // for tracing purpose + } + } + } + + /* On duration timer */ + if (UE_scheduling_control->on_duration_timer > 0) { + UE_scheduling_control->on_duration_timer++; + + if (UE_scheduling_control->on_duration_timer > UE_scheduling_control->on_duration_timer_thres) { + UE_scheduling_control->on_duration_timer = 0; + } + } + + /* DRX inactivity timer */ + if (UE_scheduling_control->drx_inactivity_timer > 0) { + UE_scheduling_control->drx_inactivity_timer++; + + if (UE_scheduling_control->drx_inactivity_timer > (UE_scheduling_control->drx_inactivity_timer_thres + 1)) { + /* Note: the +1 on the threshold is due to information in table C-1 of 36.321 */ + UE_scheduling_control->drx_inactivity_timer = 0; + + /* When timer expires switch into short or long DRX cycle */ + if (UE_scheduling_control->drx_shortCycle_timer_thres > 0) { + UE_scheduling_control->in_short_drx_cycle = TRUE; + UE_scheduling_control->drx_shortCycle_timer = 0; + UE_scheduling_control->in_long_drx_cycle = FALSE; + } else { + UE_scheduling_control->in_long_drx_cycle = TRUE; + } + } + } + + /* Short DRX Cycle */ + if (UE_scheduling_control->in_short_drx_cycle == TRUE) { + UE_scheduling_control->drx_shortCycle_timer++; + + /* When the Short DRX cycles are over, switch to long DRX cycle */ + if (UE_scheduling_control->drx_shortCycle_timer > UE_scheduling_control->drx_shortCycle_timer_thres) { + UE_scheduling_control->drx_shortCycle_timer = 0; + UE_scheduling_control->in_short_drx_cycle = FALSE; + UE_scheduling_control->in_long_drx_cycle = TRUE; + UE_scheduling_control->drx_longCycle_timer = 0; + } + } else { + UE_scheduling_control->drx_shortCycle_timer = 0; + } + + /* Long DRX Cycle */ + if (UE_scheduling_control->in_long_drx_cycle == TRUE) { + UE_scheduling_control->drx_longCycle_timer++; + + if (UE_scheduling_control->drx_longCycle_timer > UE_scheduling_control->drx_longCycle_timer_thres) { + UE_scheduling_control->drx_longCycle_timer = 1; + } + } else { + UE_scheduling_control->drx_longCycle_timer = 0; + } + + /* Check for error cases */ + if ((UE_scheduling_control->in_short_drx_cycle == TRUE) && (UE_scheduling_control->in_long_drx_cycle == TRUE)) { + LOG_E(MAC, "Error in C-DRX: UE id %d is in both short and long DRX cycle. Should not happen. Back it to long cycle only\n", UE_id); + UE_scheduling_control->in_short_drx_cycle = FALSE; + } + + /* Condition to start On Duration Timer */ + if (UE_scheduling_control->in_short_drx_cycle == TRUE && UE_scheduling_control->on_duration_timer == 0) { + if (((frameP * 10) + subframeP) % (UE_scheduling_control->short_drx_cycle_duration) == + (UE_scheduling_control->drx_start_offset) % (UE_scheduling_control->short_drx_cycle_duration)) { + + UE_scheduling_control->on_duration_timer = 1; + } + } else if (UE_scheduling_control->in_long_drx_cycle == TRUE && UE_scheduling_control->on_duration_timer == 0) { + if (((frameP * 10) + subframeP) % (UE_scheduling_control->drx_longCycle_timer_thres) == + (UE_scheduling_control->drx_start_offset)) { + + UE_scheduling_control->on_duration_timer = 1; + } + } + + /* Update Active Time status of UE + * Based on 36.321 5.7 the differents conditions for the UE to be in Acttive Should be check ONLY + * here for the current subframe. The variable 'UE_scheduling_control->in_active_time' should be updated + * ONLY here. The variable can then be used for testing the actual state of the UE for scheduling purpose. + */ + UE_template = &(UE_list->UE_template[CC_id][UE_id]); + /* (a)synchronous HARQ processes handling for Active Time */ + for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) { + if (UE_scheduling_control->drx_retransmission_timer[harq_process_id] > 0) { + harq_active_time_condition = TRUE; + active_time_condition = 2; // for tracing purpose + break; + } + } + + /* Active time conditions */ + if (UE_scheduling_control->on_duration_timer > 0 || + UE_scheduling_control->drx_inactivity_timer > 1 || + harq_active_time_condition || + UE_template->ul_SR > 0) { + + UE_scheduling_control->in_active_time = TRUE; + + } else { + UE_scheduling_control->in_active_time = FALSE; + } + + /* BEGIN VCD */ + if (UE_id == 0) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_ON_DURATION_TIMER, (unsigned long) UE_scheduling_control->on_duration_timer); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_INACTIVITY, (unsigned long) UE_scheduling_control->drx_inactivity_timer); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_SHORT_CYCLE, (unsigned long) UE_scheduling_control->drx_shortCycle_timer); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_LONG_CYCLE, (unsigned long) UE_scheduling_control->drx_longCycle_timer); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_RETRANSMISSION_HARQ0, (unsigned long) UE_scheduling_control->drx_retransmission_timer[0]); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME, (unsigned long) UE_scheduling_control->in_active_time); + + /* For tracing purpose */ + if (UE_template->ul_SR > 0) { + active_time_condition = 1; + } else if ((UE_scheduling_control->on_duration_timer > 0) && (active_time_condition == 0)) { + active_time_condition = 3; + } else if ((UE_scheduling_control->drx_inactivity_timer > 1) && (active_time_condition == 0)) { + active_time_condition = 4; + } + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DRX_ACTIVE_TIME_CONDITION, (unsigned long) active_time_condition); + } + /* END VCD */ + + /* DCI0 ongoing timer */ + if (UE_scheduling_control->dci0_ongoing_timer > 0) { + if (UE_scheduling_control->dci0_ongoing_timer > 7) { + UE_scheduling_control->dci0_ongoing_timer = 0; + } else { + UE_scheduling_control->dci0_ongoing_timer++; + } + } + + } else { // else: CDRX not configured + /* Note: (UL) HARQ RTT timers processing is done here and can be used by other features than CDRX */ + /* HARQ RTT timers */ + for (int harq_process_id = 0; harq_process_id < 8; harq_process_id++) { + if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 0) { + UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id]++; + + if (UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] > 8) { + UE_scheduling_control->harq_rtt_timer[CC_id][harq_process_id] = 0; + } + } + + if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 0) { + UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id]++; + + if (UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] > 4) { + UE_scheduling_control->ul_harq_rtt_timer[CC_id][harq_process_id] = 0; + } + } + } // end loop harq process + } // end else CDRX not configured + + /* Increment these timers, they are cleared when we receive an sdu */ + UE_scheduling_control->ul_inactivity_timer++; + UE_scheduling_control->cqi_req_timer++; + + LOG_D(MAC, "UE %d/%x : ul_inactivity %d, cqi_req %d\n", + UE_id, + rnti, + UE_scheduling_control->ul_inactivity_timer, + UE_scheduling_control->cqi_req_timer); + + check_ul_failure(module_idP, CC_id, UE_id, frameP, subframeP); + + if (UE_scheduling_control->ue_reestablishment_reject_timer > 0) { + UE_scheduling_control->ue_reestablishment_reject_timer++; + + if (UE_scheduling_control->ue_reestablishment_reject_timer >= UE_scheduling_control->ue_reestablishment_reject_timer_thres) { + UE_scheduling_control->ue_reestablishment_reject_timer = 0; + + + /* Clear reestablish_rnti_map */ + if (UE_scheduling_control->ue_reestablishment_reject_timer_thres > 20) { + for (int ue_id_l = 0; ue_id_l < MAX_MOBILES_PER_ENB; ue_id_l++) { + if (reestablish_rnti_map[ue_id_l][0] == rnti) { + /* Clear currentC-RNTI from map */ + reestablish_rnti_map[ue_id_l][0] = 0; + reestablish_rnti_map[ue_id_l][1] = 0; + break; + } + } + + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, rnti, 0, 0,module_idP); + rrc_rlc_remove_ue(&ctxt); + pdcp_remove_UE(&ctxt); + } + + /* Note: This should not be done in the MAC! */ + for (int ii=0; ii<MAX_MOBILES_PER_ENB; ii++) { + LTE_eNB_ULSCH_t *ulsch = RC.eNB[module_idP][CC_id]->ulsch[ii]; + + if((ulsch != NULL) && (ulsch->rnti == rnti)) { + void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch); + + LOG_I(MAC, "clean_eNb_ulsch UE %x \n", rnti); + + clean_eNb_ulsch(ulsch); + } + } + + for (int ii=0; ii<MAX_MOBILES_PER_ENB; ii++) { + LTE_eNB_DLSCH_t *dlsch = RC.eNB[module_idP][CC_id]->dlsch[ii][0]; + + if((dlsch != NULL) && (dlsch->rnti == rnti)) { + void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch); + + LOG_I(MAC, "clean_eNb_dlsch UE %x \n", rnti); + + clean_eNb_dlsch(dlsch); + } + } + + for (int j = 0; j < 10; j++) { + nfapi_ul_config_request_body_t *ul_req_tmp = NULL; + ul_req_tmp = &(eNB->UL_req_tmp[CC_id][j].ul_config_request_body); + + if (ul_req_tmp) { + int pdu_number = ul_req_tmp->number_of_pdus; + + for (int pdu_index = pdu_number-1; pdu_index >= 0; pdu_index--) { + if (ul_req_tmp->ul_config_pdu_list[pdu_index].ulsch_pdu.ulsch_pdu_rel8.rnti == rnti) { + LOG_I(MAC, "remove UE %x from ul_config_pdu_list %d/%d\n", + rnti, + pdu_index, + pdu_number); + + if (pdu_index < pdu_number -1) { + memcpy(&ul_req_tmp->ul_config_pdu_list[pdu_index], + &ul_req_tmp->ul_config_pdu_list[pdu_index+1], + (pdu_number-1-pdu_index) * sizeof(nfapi_ul_config_request_pdu_t)); + } + + ul_req_tmp->number_of_pdus--; + } + } // end for pdu_index + } // end if (ul_req_tmp) + } // end for j + + rrc_mac_remove_ue(module_idP,rnti); + + } // end if (UE_scheduling_control->ue_reestablishment_reject_timer >= UE_scheduling_control->ue_reestablishment_reject_timer_thres) + } // end if (UE_scheduling_control->ue_reestablishment_reject_timer > 0) + } // end if UE active + } // end for loop on UE_id + +#if (!defined(PRE_SCD_THREAD)) + + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frameP, subframeP, module_idP); + pdcp_run(&ctxt); + rrc_rx_tx(&ctxt, CC_id); + +#endif +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) + + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + if (cc[CC_id].MBMS_flag > 0) { + start_meas(&RC.mac[module_idP]->schedule_mch); + mbsfn_status[CC_id] = schedule_MBMS(module_idP, CC_id, frameP, subframeP); + stop_meas(&RC.mac[module_idP]->schedule_mch); + } + } + +#endif + + static int debug_flag = 0; + void (*schedule_ulsch_p)(module_id_t module_idP, frame_t frameP, sub_frame_t subframe) = NULL; + void (*schedule_ue_spec_p)(module_id_t module_idP, frame_t frameP, sub_frame_t subframe, int *mbsfn_flag) = NULL; + + if (eNB->scheduler_mode == SCHED_MODE_DEFAULT) { + schedule_ulsch_p = schedule_ulsch; + schedule_ue_spec_p = schedule_dlsch; + } else if (eNB->scheduler_mode == SCHED_MODE_FAIR_RR) { + memset(dlsch_ue_select, 0, sizeof(dlsch_ue_select)); + schedule_ulsch_p = schedule_ulsch_fairRR; + schedule_ue_spec_p = schedule_ue_spec_fairRR; + } + + if(debug_flag == 0){ + LOG_E(MAC,"SCHED_MODE = %d\n", eNB->scheduler_mode); + debug_flag = 1; + } + + /* This schedules MIB */ + if ((subframeP == 0) && (frameP & 3) == 0) + schedule_mib(module_idP, frameP, subframeP); + + if (get_softmodem_params()->phy_test == 0) { + /* This schedules SI for legacy LTE and eMTC starting in subframeP */ + schedule_SI(module_idP, frameP, subframeP); + /* This schedules Paging in subframeP */ + schedule_PCH(module_idP,frameP,subframeP); + /* This schedules Random-Access for legacy LTE and eMTC starting in subframeP */ + schedule_RA(module_idP, frameP, subframeP); + /* Copy previously scheduled UL resources (ULSCH + HARQ) */ + copy_ulreq(module_idP, frameP, subframeP); + /* This schedules SRS in subframeP */ + schedule_SRS(module_idP, frameP, subframeP); + + /* This schedules ULSCH in subframeP (dci0) */ + if (schedule_ulsch_p != NULL) { + schedule_ulsch_p(module_idP, frameP, subframeP); + } else { + LOG_E(MAC," %s %d: schedule_ulsch_p is NULL, function not called\n", + __FILE__, + __LINE__); + } + + /* This schedules UCI_SR in subframeP */ + schedule_SR(module_idP, frameP, subframeP); + /* This schedules UCI_CSI in subframeP */ + schedule_CSI(module_idP, frameP, subframeP); +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + /* This schedules DLSCH in subframeP for BR UE*/ + schedule_ue_spec_br(module_idP, frameP, subframeP); +#endif + /* This schedules DLSCH in subframeP */ + if (schedule_ue_spec_p != NULL) { + schedule_ue_spec_p(module_idP, frameP, subframeP, mbsfn_status); + } else { + LOG_E(MAC," %s %d: schedule_ue_spec_p is NULL, function not called\n", + __FILE__, + __LINE__); + } + + } else { + schedule_ulsch_phy_test(module_idP,frameP,subframeP); + schedule_ue_spec_phy_test(module_idP,frameP,subframeP,mbsfn_status); + } + + /* Allocate CCEs for good after scheduling is done */ + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + if (cc[CC_id].tdd_Config == NULL || !(is_UL_sf(&cc[CC_id],subframeP))) { + allocate_CCEs(module_idP, CC_id, frameP, subframeP, 2); + } + } + + if (flexran_agent_get_mac_xface(module_idP) && subframeP == 9) { + flexran_agent_slice_update(module_idP); + } + + stop_meas(&(eNB->eNB_scheduler)); + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, VCD_FUNCTION_OUT); +} + diff --git a/openair2/LAYER2/MAC/proto_NB_IoT.h b/openair2/LAYER2/MAC/proto_NB_IoT.h index d9107f53c63d79263a14093767cfd645b776ef54..a197448a1fec14e53d78238750cf267e26be0007 100755 --- a/openair2/LAYER2/MAC/proto_NB_IoT.h +++ b/openair2/LAYER2/MAC/proto_NB_IoT.h @@ -1,252 +1,251 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file LAYER2/MAC/proto_NB_IoT.h - * \brief MAC functions prototypes for eNB and UE - * \author NTUST BMW Lab./Nick HO, Xavier LIU, Calvin HSU - * \date 2017 - 2018 - * \email: nick133371@gmail.com, sephiroth7277@gmail.com , kai-hsiang.hsu@eurecom.fr - * \version 1.0 - * \author Navid Nikaein and Raymond Knopp - * \date 2010 - 2014 - * \email navid.nikaein@eurecom.fr - * \version 1.0 - */ - -#ifndef __LAYER2_MAC_PROTO_NB_IoT_H__ -#define __LAYER2_MAC_PROTO_NB_IoT_H__ - -#include "openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h" -#include "LAYER2/MAC/defs_NB_IoT.h" -#include "COMMON/platform_types.h" -#include "openair2/RRC/LTE/defs_NB_IoT.h" -/** \addtogroup _mac - * @{ - */ - -void initiate_ra_proc_NB_IoT(module_id_t module_idP,int CC_id,frame_t frameP, uint16_t preamble_index,int16_t timing_offset,uint8_t sect_id,sub_frame_t subframe,uint8_t f_id); - - -void mac_top_init_eNB_NB_IoT(void); -int l2_init_eNB_NB_IoT(void); - - - -void config_mib_fapi_NB_IoT( - int physCellId, - uint8_t eutra_band, - int Ncp, - int Ncp_UL, - int p_eNB, - int p_rx_eNB, - int dl_CarrierFreq, - int ul_CarrierFreq, - long *eutraControlRegionSize, - BCCH_BCH_Message_NB_t *mib_NB_IoT - ); - -void config_sib2_fapi_NB_IoT( - int physCellId, - RadioResourceConfigCommonSIB_NB_r13_t *radioResourceConfigCommon - ); - - -///config -void rrc_mac_config_req_NB_IoT( - module_id_t Mod_idP, - int CC_idP, - int rntiP, - rrc_eNB_carrier_data_NB_IoT_t *carrier, - SystemInformationBlockType1_NB_t *sib1_NB_IoT, - RadioResourceConfigCommonSIB_NB_r13_t *radioResourceConfigCommon, - PhysicalConfigDedicated_NB_r13_t *physicalConfigDedicated, - LogicalChannelConfig_NB_r13_t *logicalChannelConfig, //FIXME: decide how to use it - uint8_t ded_flag, - uint8_t ue_list_ded_num); - -uint32_t get_SIB23_size(void); - -///system -void init_mac_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst); -//void init_rrc_NB_IoT(); -void release_mac_inst(uint8_t order); -eNB_MAC_INST_NB_IoT *get_mac_inst(uint8_t order); -uint8_t register_mac_inst(eNB_MAC_INST_NB_IoT *inst, uint8_t order); - -///tool -void init_tool(sib1_NB_IoT_sched_t *config); -void UE_info_setting(UE_TEMPLATE_NB_IoT *UE_info); -UE_TEMPLATE_NB_IoT *get_ue_from_rnti(eNB_MAC_INST_NB_IoT *inst, rnti_t rnti); - -///scheduler -void eNB_dlsch_ulsch_scheduler_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe); -void eNB_scheduler_computing_flag_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe, uint32_t *scheduler_flags, uint32_t *common_flags, uint32_t *max_subframe); - -//Calvin temp define self-tools -int init_debug(eNB_MAC_INST_NB_IoT *inst); -void maintain_available_resource(eNB_MAC_INST_NB_IoT *mac_inst); -void extend_available_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, int max_subframe); -available_resource_DL_t *check_sibs_resource(eNB_MAC_INST_NB_IoT *mac_inst, int check_start_subframe, int check_end_subframe, int num_subframe, int *residual_subframe, int *out_last_subframe, int *out_first_subframe); -uint32_t calculate_DLSF(eNB_MAC_INST_NB_IoT *mac_inst, int abs_start_subframe, int abs_end_subframe); -void init(eNB_MAC_INST_NB_IoT *mac_inst); -void init_dl_list(eNB_MAC_INST_NB_IoT *mac_inst); -int is_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); -void fill_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, available_resource_DL_t *node, int start_subframe, int end_subframe, schedule_result_t *new_node); -available_resource_DL_t *check_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, int check_subframe, int num_subframes, int *out_last_subframe, int *out_first_subframe); -void print_available_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst); -void print_schedule_result_DL(void); -void print_schedule_result_UL(void); -void add_ue(eNB_MAC_INST_NB_IoT *mac_inst, uint16_t rnti, ce_level_t ce, uint32_t PHR, uint32_t ul_total_buffer); -void remove_ue(eNB_MAC_INST_NB_IoT *mac_inst, uint16_t rnti, ce_level_t ce); -// SIBs -void schedule_sibs(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t sibs_order, int start_subframe); - -//RA -void msg3_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti); -void msg4_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti); -void schedule_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst); -void init_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint8_t preamble_index, ce_level_t ce_level, uint32_t sfn_id, uint16_t ta); -void schedule_rar_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); -void receive_msg3_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti, uint32_t phr, uint32_t ul_total_buffer, uint8_t* ccch_sdu, uint8_t* msg4_rrc_sdu); -void schedule_msg3_retransimission_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); -void schedule_msg4_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); -void fill_rar_NB_IoT(eNB_MAC_INST_NB_IoT *inst, RA_TEMPLATE_NB_IoT *ra_template, uint8_t msg3_schedule_delay, uint8_t msg3_rep, sched_temp_UL_NB_IoT_t *schedule_template); -void receive_msg4_ack_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t rnti); -int fill_msg4_NB_IoT(eNB_MAC_INST_NB_IoT *inst, RA_TEMPLATE_NB_IoT *ra_template); -int fill_msg4_NB_IoT_fixed(eNB_MAC_INST_NB_IoT *inst, RA_TEMPLATE_NB_IoT *ra_template); - - -//USS -void schedule_uss_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, uint32_t subframe, uint32_t frame, uint32_t hypersfn, int index_ss); - -//DATA -uint8_t *parse_ulsch_header( uint8_t *mac_header, - uint8_t *num_ce, - uint8_t *num_sdu, - uint8_t *rx_ces, - uint8_t *rx_lcids, - uint16_t *rx_lengths, - uint16_t tb_length ); - -/*******UL Scheduler**********/ -void print_scheduling_result_UL(void); -void print_available_UL_resource(void); -/*set nprach configuration at intial time*/ -void setting_nprach(void); -/*Uplink main scheduler*/ -//int schedule_UL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst,UE_TEMPLATE_NB_IoT *UE_info, uint32_t subframe, uint32_t frame, uint32_t H_SFN); -int schedule_UL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst,UE_TEMPLATE_NB_IoT *UE_info, uint32_t subframe, uint32_t frame, uint32_t H_SFN, UE_SCHED_CTRL_NB_IoT_t *UE_sched_info); -/*Check available uplink resource list, if there is available uplink resource, return 0, otherwise, return 1*/ -int Check_UL_resource(uint32_t DL_end, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info, int multi_tone, int fmt2_flag); -/*Get I Repetition number in DCI*/ -int get_I_REP(int N_rep); -/*Get N REP from preamble repeat*/ -int get_N_REP(int CE_level); -/*Get TBS from mcs, multi-tone, Iru*/ -int get_TBS_UL_NB_IoT(uint32_t mcs,uint32_t multi_tone,int Iru); -/*get I tbs from mcs and multi-tone*/ -int get_I_TBS_NB_IoT(int x,int y); -/*Get DCI REP from R max and R*/ -int get_DCI_REP(uint32_t R,uint32_t R_max); -/*Check single tone resource list*/ -int single_tone_ru_allocation(uint32_t uplink_time, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info, int fmt2_flag); -/*Check multi tone resource list*/ -int multi_tone_ru_allocation(uint32_t uplink_time, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info); -/*Generate scheduling result of DCI N0 and Uplink config*/ -void generate_scheduling_result_UL(int32_t DCI_subframe, int32_t DCI_end_subframe, uint32_t UL_subframe, uint32_t UL_end_subframe, DCIFormatN0_t *DCI_inst, rnti_t rnti, uint8_t *ul_debug_str, uint8_t *dl_debug_str, uint8_t msg3_flag); -/*Adjust UL resource by removing the used resource*/ -void adjust_UL_resource_list(sched_temp_UL_NB_IoT_t *NPUSCH_info); -/*Initialize resource by nprach configuration*/ -void Initialize_Resource(void); -/*Function to extend uplink resource grid*/ -//void add_UL_Resource(eNB_MAC_INST_NB_IoT *mac_inst); -void add_UL_Resource(void); -/*Get ACK/NAK resource field*/ -int get_resource_field_value(int subcarrier, int k0); -/*Get DL Repetition index*/ -uint8_t get_index_Rep_dl(uint16_t R); - -/*******DL Scheduler********/ -//void schedule_DL_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, UE_TEMPLATE_NB_IoT *UE_info, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start); -int check_resource_NPDCCH_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, sched_temp_DL_NB_IoT_t *NPDCCH_info, uint32_t cdd_num, uint32_t dci_rep); -int check_resource_NPDSCH_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, sched_temp_DL_NB_IoT_t *NPDSCH_info, uint32_t sf_end, uint32_t I_delay, uint32_t R_max, uint32_t R_dl, uint32_t n_sf); -int check_resource_DL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, uint32_t dlsf_require, sched_temp_DL_NB_IoT_t *schedule_info); -uint32_t get_I_mcs(int CE_level); -uint32_t get_max_tbs(uint32_t I_tbs); -uint32_t get_tbs(uint32_t data_size, uint32_t I_tbs, uint32_t *I_sf); -uint32_t get_num_sf(uint32_t I_sf); - -////// -uint8_t get_UL_I_TBS_from_MCS_NB_IoT(uint8_t I_mcs, uint8_t N_sc_RU, uint8_t Msg3_flag); - -uint8_t test_signle_tone_UL_NB_IoT(uint8_t subcarrier_spacing, uint8_t I_sc, uint8_t npush_format); -////// - -uint32_t get_scheduling_delay(uint32_t I_delay, uint32_t R_max); -uint32_t get_HARQ_delay(int subcarrier_spacing, uint32_t HARQ_delay_index); -//void generate_scheduling_result_DL(uint32_t DCI_subframe, uint32_t NPDSCH_subframe, uint32_t HARQ_subframe, DCIFormatN1_t *DCI, rnti_t rnti, uint32_t TBS, uint8_t *DLSCH_pdu); -//void generate_scheduling_result_DL(sched_temp_DL_NB_IoT_t* DCI_info, sched_temp_DL_NB_IoT_t* NPDSCH_info, sched_temp_UL_NB_IoT_t* HARQ_info, DCIFormatN1_t *DCI_inst, rnti_t rnti, uint32_t TBS, uint8_t *DLSCH_pdu); -void generate_scheduling_result_DL(uint32_t NPDCCH_sf_end, uint32_t NPDCCH_sf_start, uint32_t NPDSCH_sf_end, uint32_t NPDSCH_sf_start, uint32_t HARQ_sf_end, uint32_t HARQ_sf_start, DCIFormatN1_t *DCI_pdu, rnti_t rnti, uint32_t TBS, uint8_t *DLSCH_pdu); -//void fill_DCI_N1(DCIFormatN1_t *DCI_N1, UE_TEMPLATE_NB_IoT *UE_info, uint32_t scheddly, uint32_t I_sf, uint32_t I_harq); - -//Transfrom source into hyperSF, Frame, Subframe format -void convert_system_number(uint32_t source_sf,uint32_t *hyperSF, uint32_t *frame, uint32_t *subframe); -//Trnasform hyperSF, Frame, Subframe format into subframe unit -uint32_t convert_system_number_sf(uint32_t hyperSF, uint32_t frame, uint32_t subframe); -/*input start position amd num_dlsf DL subframe, caculate the last subframe number*/ -uint32_t cal_num_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF, uint32_t frame, uint32_t subframe, uint32_t* hyperSF_result, uint32_t* frame_result, uint32_t* subframe_result, uint32_t num_dlsf_require); -void init_dlsf_info(eNB_MAC_INST_NB_IoT *mac_inst, DLSF_INFO_t *DLSF_info); -uint32_t generate_dlsch_header_NB_IoT(uint8_t *pdu, uint32_t num_sdu, logical_chan_id_t *logical_channel, uint32_t *sdu_length, uint8_t flag_drx, uint8_t flag_ta, uint32_t TBS); -void maintain_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, sched_temp_DL_NB_IoT_t *NPDCCH_info, sched_temp_DL_NB_IoT_t *NPDSCH_info); -void init_tool_sib1(eNB_MAC_INST_NB_IoT *mac_inst); -//int is_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); -/**DL test , delete**/ -available_resource_DL_t* new_dl_node(uint32_t start_subframe, uint32_t end_subframe, uint32_t dlsf); -void initialize_dl_resource(available_resource_DL_t *DL_Resource_node, uint32_t start_subframe, uint32_t end_subframe, uint32_t dlsf); -void insert_dl_resource(available_resource_DL_t *DL_Resource_node); -void insert_schedule_result(schedule_result_t **list, int subframe, schedule_result_t *node); -//interface with IF - -uint8_t *parse_ulsch_header_NB_IoT( uint8_t *mac_header, uint8_t *num_ce, uint8_t *num_sdu, uint8_t *rx_ces, uint8_t *rx_lcids, uint16_t *rx_lengths, uint16_t tb_length); - -void rx_sdu_NB_IoT(module_id_t module_id, int CC_id, frame_t frame, sub_frame_t subframe, uint16_t rnti, uint8_t *sdu, uint16_t length); - -int output_handler(eNB_MAC_INST_NB_IoT *mac_inst, module_id_t module_id, int CC_id, uint32_t hypersfn, uint32_t frame, uint32_t subframe, uint8_t MIB_flag, uint8_t SIB1_flag, uint32_t current_time); -// main - -void mac_top_init_eNB_NB_IoT(void); - -uint32_t to_earfcn_NB_IoT(int eutra_bandP,uint32_t dl_CarrierFreq, float m_dl); - -uint32_t from_earfcn_NB_IoT(int eutra_bandP,uint32_t dl_earfcn, float m_dl); - -int32_t get_uldl_offset_NB_IoT(int eutra_band); - - -/***Preprocessor***/ -void preprocessor_uss_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, uint32_t subframe, uint32_t frame, uint32_t hypersfn, int UE_list_index); -void sort_UEs_uss(void); -int schedule_DL_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, UE_TEMPLATE_NB_IoT *UE_info, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info); -void fill_DCI_N0(DCIFormatN0_t *DCI_N0, UE_TEMPLATE_NB_IoT *UE_info, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info); -void fill_DCI_N1(DCIFormatN1_t *DCI_N1, UE_TEMPLATE_NB_IoT *UE_info, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info); -void USS_scheduling_module(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe, uint8_t number_UE_list); - -#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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file LAYER2/MAC/proto_NB_IoT.h + * \brief MAC functions prototypes for eNB and UE + * \author NTUST BMW Lab./Nick HO, Xavier LIU, Calvin HSU + * \date 2017 - 2018 + * \email: nick133371@gmail.com, sephiroth7277@gmail.com , kai-hsiang.hsu@eurecom.fr + * \version 1.0 + * \author Navid Nikaein and Raymond Knopp + * \date 2010 - 2014 + * \email navid.nikaein@eurecom.fr + * \version 1.0 + */ + +#ifndef __LAYER2_MAC_PROTO_NB_IoT_H__ +#define __LAYER2_MAC_PROTO_NB_IoT_H__ + +#include "openair1/PHY/LTE_TRANSPORT/defs_NB_IoT.h" +#include "LAYER2/MAC/defs_NB_IoT.h" +#include "COMMON/platform_types.h" +#include "openair2/RRC/LITE/defs_NB_IoT.h" +/** \addtogroup _mac + * @{ + */ + +void initiate_ra_proc_NB_IoT(module_id_t module_idP,int CC_id,frame_t frameP, uint16_t preamble_index,int16_t timing_offset,uint8_t sect_id,sub_frame_t subframe,uint8_t f_id); + + +void mac_top_init_eNB_NB_IoT(void); +int l2_init_eNB_NB_IoT(void); + + + +void config_mib_fapi_NB_IoT( + int physCellId, + uint8_t eutra_band, + int Ncp, + int Ncp_UL, + int p_eNB, + int p_rx_eNB, + int dl_CarrierFreq, + int ul_CarrierFreq, + long *eutraControlRegionSize, + BCCH_BCH_Message_NB_t *mib_NB_IoT + ); + +void config_sib2_fapi_NB_IoT( + int physCellId, + RadioResourceConfigCommonSIB_NB_r13_t *radioResourceConfigCommon + ); + + +///config +void rrc_mac_config_req_NB_IoT( + module_id_t Mod_idP, + int CC_idP, + int rntiP, + rrc_eNB_carrier_data_NB_IoT_t *carrier, + SystemInformationBlockType1_NB_t *sib1_NB_IoT, + RadioResourceConfigCommonSIB_NB_r13_t *radioResourceConfigCommon, + PhysicalConfigDedicated_NB_r13_t *physicalConfigDedicated, + LogicalChannelConfig_NB_r13_t *logicalChannelConfig, //FIXME: decide how to use it + uint8_t ded_flag, + uint8_t ue_list_ded_num); + +uint32_t get_SIB23_size(void); + +///system +void init_mac_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst); +//void init_rrc_NB_IoT(); +void release_mac_inst(uint8_t order); +eNB_MAC_INST_NB_IoT *get_mac_inst(uint8_t order); +uint8_t register_mac_inst(eNB_MAC_INST_NB_IoT *inst, uint8_t order); + +///tool +void init_tool(sib1_NB_IoT_sched_t *config); +void UE_info_setting(UE_TEMPLATE_NB_IoT *UE_info); +UE_TEMPLATE_NB_IoT *get_ue_from_rnti(eNB_MAC_INST_NB_IoT *inst, rnti_t rnti); + +///scheduler +void eNB_dlsch_ulsch_scheduler_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe); +void eNB_scheduler_computing_flag_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe, uint32_t *scheduler_flags, uint32_t *common_flags, uint32_t *max_subframe); + +//Calvin temp define self-tools +int init_debug(eNB_MAC_INST_NB_IoT *inst); +void maintain_available_resource(eNB_MAC_INST_NB_IoT *mac_inst); +void extend_available_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, int max_subframe); +available_resource_DL_t *check_sibs_resource(eNB_MAC_INST_NB_IoT *mac_inst, int check_start_subframe, int check_end_subframe, int num_subframe, int *residual_subframe, int *out_last_subframe, int *out_first_subframe); +uint32_t calculate_DLSF(eNB_MAC_INST_NB_IoT *mac_inst, int abs_start_subframe, int abs_end_subframe); +void init(eNB_MAC_INST_NB_IoT *mac_inst); +void init_dl_list(eNB_MAC_INST_NB_IoT *mac_inst); +int is_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +void fill_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, available_resource_DL_t *node, int start_subframe, int end_subframe, schedule_result_t *new_node); +available_resource_DL_t *check_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, int check_subframe, int num_subframes, int *out_last_subframe, int *out_first_subframe); +void print_available_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst); +void print_schedule_result_DL(void); +void print_schedule_result_UL(void); +void add_ue_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint16_t rnti, ce_level_t ce, uint32_t PHR, uint32_t ul_total_buffer); +void remove_ue(eNB_MAC_INST_NB_IoT *mac_inst, uint16_t rnti, ce_level_t ce); +// SIBs +void schedule_sibs(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t sibs_order, int start_subframe); + +//RA +void msg3_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti); +void msg4_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti); +void schedule_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst); +void init_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint8_t preamble_index, ce_level_t ce_level, uint32_t sfn_id, uint16_t ta); +void schedule_rar_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +void receive_msg3_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti, uint32_t phr, uint32_t ul_total_buffer, uint8_t* ccch_sdu, uint8_t* msg4_rrc_sdu); +void schedule_msg3_retransimission_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +void schedule_msg4_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +void fill_rar_NB_IoT(eNB_MAC_INST_NB_IoT *inst, RA_TEMPLATE_NB_IoT *ra_template, uint8_t msg3_schedule_delay, uint8_t msg3_rep, sched_temp_UL_NB_IoT_t *schedule_template); +void receive_msg4_ack_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t rnti); +int fill_msg4_NB_IoT(eNB_MAC_INST_NB_IoT *inst, RA_TEMPLATE_NB_IoT *ra_template); +int fill_msg4_NB_IoT_fixed(eNB_MAC_INST_NB_IoT *inst, RA_TEMPLATE_NB_IoT *ra_template); + + +//USS +void schedule_uss_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, uint32_t subframe, uint32_t frame, uint32_t hypersfn, int index_ss); + +//DATA +uint8_t *parse_ulsch_header( uint8_t *mac_header, + uint8_t *num_ce, + uint8_t *num_sdu, + uint8_t *rx_ces, + uint8_t *rx_lcids, + uint16_t *rx_lengths, + uint16_t tb_length ); + +/*******UL Scheduler**********/ +void print_scheduling_result_UL(void); +void print_available_UL_resource(void); +/*set nprach configuration at intial time*/ +void setting_nprach(void); +/*Uplink main scheduler*/ +//int schedule_UL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst,UE_TEMPLATE_NB_IoT *UE_info, uint32_t subframe, uint32_t frame, uint32_t H_SFN); +int schedule_UL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst,UE_TEMPLATE_NB_IoT *UE_info, uint32_t subframe, uint32_t frame, uint32_t H_SFN, UE_SCHED_CTRL_NB_IoT_t *UE_sched_info); +/*Check available uplink resource list, if there is available uplink resource, return 0, otherwise, return 1*/ +int Check_UL_resource(uint32_t DL_end, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info, int multi_tone, int fmt2_flag); +/*Get I Repetition number in DCI*/ +int get_I_REP(int N_rep); +/*Get N REP from preamble repeat*/ +int get_N_REP(int CE_level); +/*Get TBS from mcs, multi-tone, Iru*/ +int get_TBS_UL_NB_IoT(uint32_t mcs,uint32_t multi_tone,int Iru); +/*get I tbs from mcs and multi-tone*/ +int get_I_TBS_NB_IoT(int x,int y); +/*Get DCI REP from R max and R*/ +int get_DCI_REP(uint32_t R,uint32_t R_max); +/*Check single tone resource list*/ +int single_tone_ru_allocation(uint32_t uplink_time, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info, int fmt2_flag); +/*Check multi tone resource list*/ +int multi_tone_ru_allocation(uint32_t uplink_time, int total_ru, sched_temp_UL_NB_IoT_t *NPUSCH_info); +/*Generate scheduling result of DCI N0 and Uplink config*/ +void generate_scheduling_result_UL(int32_t DCI_subframe, int32_t DCI_end_subframe, uint32_t UL_subframe, uint32_t UL_end_subframe, DCIFormatN0_t *DCI_inst, rnti_t rnti, uint8_t *ul_debug_str, uint8_t *dl_debug_str, uint8_t msg3_flag); +/*Adjust UL resource by removing the used resource*/ +void adjust_UL_resource_list(sched_temp_UL_NB_IoT_t *NPUSCH_info); +/*Initialize resource by nprach configuration*/ +void Initialize_Resource(void); +/*Function to extend uplink resource grid*/ +//void add_UL_Resource(eNB_MAC_INST_NB_IoT *mac_inst); +void add_UL_Resource(void); +/*Get ACK/NAK resource field*/ +int get_resource_field_value(int subcarrier, int k0); +/*Get DL Repetition index*/ +uint8_t get_index_Rep_dl(uint16_t R); + +/*******DL Scheduler********/ +//void schedule_DL_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, UE_TEMPLATE_NB_IoT *UE_info, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start); +int check_resource_NPDCCH_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, sched_temp_DL_NB_IoT_t *NPDCCH_info, uint32_t cdd_num, uint32_t dci_rep); +int check_resource_NPDSCH_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, sched_temp_DL_NB_IoT_t *NPDSCH_info, uint32_t sf_end, uint32_t I_delay, uint32_t R_max, uint32_t R_dl, uint32_t n_sf); +int check_resource_DL_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, uint32_t dlsf_require, sched_temp_DL_NB_IoT_t *schedule_info); +uint32_t get_I_mcs(int CE_level); +uint32_t get_max_tbs(uint32_t I_tbs); +uint32_t get_tbs(uint32_t data_size, uint32_t I_tbs, uint32_t *I_sf); +uint32_t get_num_sf(uint32_t I_sf); + +////// +uint8_t get_UL_I_TBS_from_MCS_NB_IoT(uint8_t I_mcs, uint8_t N_sc_RU, uint8_t Msg3_flag); + +uint8_t test_signle_tone_UL_NB_IoT(uint8_t subcarrier_spacing, uint8_t I_sc, uint8_t npush_format); +////// + +uint32_t get_scheduling_delay(uint32_t I_delay, uint32_t R_max); +uint32_t get_HARQ_delay(int subcarrier_spacing, uint32_t HARQ_delay_index); +//void generate_scheduling_result_DL(uint32_t DCI_subframe, uint32_t NPDSCH_subframe, uint32_t HARQ_subframe, DCIFormatN1_t *DCI, rnti_t rnti, uint32_t TBS, uint8_t *DLSCH_pdu); +//void generate_scheduling_result_DL(sched_temp_DL_NB_IoT_t* DCI_info, sched_temp_DL_NB_IoT_t* NPDSCH_info, sched_temp_UL_NB_IoT_t* HARQ_info, DCIFormatN1_t *DCI_inst, rnti_t rnti, uint32_t TBS, uint8_t *DLSCH_pdu); +void generate_scheduling_result_DL(uint32_t NPDCCH_sf_end, uint32_t NPDCCH_sf_start, uint32_t NPDSCH_sf_end, uint32_t NPDSCH_sf_start, uint32_t HARQ_sf_end, uint32_t HARQ_sf_start, DCIFormatN1_t *DCI_pdu, rnti_t rnti, uint32_t TBS, uint8_t *DLSCH_pdu); +//void fill_DCI_N1(DCIFormatN1_t *DCI_N1, UE_TEMPLATE_NB_IoT *UE_info, uint32_t scheddly, uint32_t I_sf, uint32_t I_harq); + +//Transfrom source into hyperSF, Frame, Subframe format +void convert_system_number(uint32_t source_sf,uint32_t *hyperSF, uint32_t *frame, uint32_t *subframe); +//Trnasform hyperSF, Frame, Subframe format into subframe unit +uint32_t convert_system_number_sf(uint32_t hyperSF, uint32_t frame, uint32_t subframe); +/*input start position amd num_dlsf DL subframe, caculate the last subframe number*/ +uint32_t cal_num_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t hyperSF, uint32_t frame, uint32_t subframe, uint32_t* hyperSF_result, uint32_t* frame_result, uint32_t* subframe_result, uint32_t num_dlsf_require); +void init_dlsf_info(eNB_MAC_INST_NB_IoT *mac_inst, DLSF_INFO_t *DLSF_info); +uint32_t generate_dlsch_header_NB_IoT(uint8_t *pdu, uint32_t num_sdu, logical_chan_id_t *logical_channel, uint32_t *sdu_length, uint8_t flag_drx, uint8_t flag_ta, uint32_t TBS); +void maintain_resource_DL(eNB_MAC_INST_NB_IoT *mac_inst, sched_temp_DL_NB_IoT_t *NPDCCH_info, sched_temp_DL_NB_IoT_t *NPDSCH_info); +void init_tool_sib1(eNB_MAC_INST_NB_IoT *mac_inst); +//int is_dlsf(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe); +/**DL test , delete**/ +available_resource_DL_t* new_dl_node(uint32_t start_subframe, uint32_t end_subframe, uint32_t dlsf); +void initialize_dl_resource(available_resource_DL_t *DL_Resource_node, uint32_t start_subframe, uint32_t end_subframe, uint32_t dlsf); +void insert_dl_resource(available_resource_DL_t *DL_Resource_node); +void insert_schedule_result(schedule_result_t **list, int subframe, schedule_result_t *node); +//interface with IF + +uint8_t *parse_ulsch_header_NB_IoT( uint8_t *mac_header, uint8_t *num_ce, uint8_t *num_sdu, uint8_t *rx_ces, uint8_t *rx_lcids, uint16_t *rx_lengths, uint16_t tb_length); + +void rx_sdu_NB_IoT(module_id_t module_id, int CC_id, frame_t frame, sub_frame_t subframe, uint16_t rnti, uint8_t *sdu, uint16_t length); + +int output_handler(eNB_MAC_INST_NB_IoT *mac_inst, module_id_t module_id, int CC_id, uint32_t hypersfn, uint32_t frame, uint32_t subframe, uint8_t MIB_flag, uint8_t SIB1_flag, uint32_t current_time); +// main + + +uint32_t to_earfcn_NB_IoT(int eutra_bandP,uint32_t dl_CarrierFreq, float m_dl); + +uint32_t from_earfcn_NB_IoT(int eutra_bandP,uint32_t dl_earfcn, float m_dl); + +int32_t get_uldl_offset_NB_IoT(int eutra_band); + + +/***Preprocessor***/ +void preprocessor_uss_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, uint32_t subframe, uint32_t frame, uint32_t hypersfn, int UE_list_index); +void sort_UEs_uss(void); +int schedule_DL_NB_IoT(module_id_t module_id, eNB_MAC_INST_NB_IoT *mac_inst, UE_TEMPLATE_NB_IoT *UE_info, uint32_t hyperSF_start, uint32_t frame_start, uint32_t subframe_start, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info); +void fill_DCI_N0(DCIFormatN0_t *DCI_N0, UE_TEMPLATE_NB_IoT *UE_info, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info); +void fill_DCI_N1(DCIFormatN1_t *DCI_N1, UE_TEMPLATE_NB_IoT *UE_info, UE_SCHED_CTRL_NB_IoT_t *UE_sched_ctrl_info); +void USS_scheduling_module(eNB_MAC_INST_NB_IoT *mac_inst, uint32_t abs_subframe, uint8_t number_UE_list); + +#endif diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c old mode 100644 new mode 100755 index 1907f14d9cc00fb239f35224a9dd64141b389625..37613d993bb13b7a6cde115e67d1bda3a54e6141 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -1,2334 +1,2336 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file pdcp.c - * \brief pdcp interface with RLC - * \author Navid Nikaein and Lionel GAUTHIER - * \date 2009-2012 - * \email navid.nikaein@eurecom.fr - * \version 1.0 - */ - -#define PDCP_C - -#define MBMS_MULTICAST_OUT - -#include "assertions.h" -#include "hashtable.h" -#include "pdcp.h" -#include "pdcp_util.h" -#include "pdcp_sequence_manager.h" -#include "LAYER2/RLC/rlc.h" -#include "LAYER2/MAC/mac_extern.h" -#include "RRC/LTE/rrc_proto.h" -#include "pdcp_primitives.h" -#include "OCG.h" -#include "OCG_extern.h" -#include "otg_rx.h" -#include "common/utils/LOG/log.h" -#include <inttypes.h> -#include "platform_constants.h" -#include "nfapi/oai_integration/vendor_ext.h" -#include "common/utils/LOG/vcd_signal_dumper.h" -#include "msc.h" -#include "common/ngran_types.h" -#include "targets/COMMON/openairinterface5g_limits.h" -#include "targets/RT/USER/lte-softmodem.h" -#include "SIMULATION/ETH_TRANSPORT/proto.h" -#include "UTIL/OSA/osa_defs.h" -#include "openair2/RRC/NAS/nas_config.h" -# include "intertask_interface.h" - - -# include "gtpv1u_eNB_task.h" -# include "gtpv1u.h" - -#include "ENB_APP/enb_config.h" - - - -extern int otg_enabled; -extern uint8_t nfapi_mode; -#include "common/ran_context.h" -extern RAN_CONTEXT_t RC; -hash_table_t *pdcp_coll_p = NULL; - -#ifdef MBMS_MULTICAST_OUT - #include <sys/types.h> - #include <sys/socket.h> - #include <netinet/in.h> - #include <netinet/ip.h> - #include <netinet/udp.h> - #include <unistd.h> - - static int mbms_socket = -1; -#endif - - - -#ifdef NB_IOT -#include "openair2/RRC/LITE/proto_NB_IoT.h" -#undef maxDRB -#define maxDRB maxDRB_NB_r13 -#endif - -/* pdcp module parameters and related functions*/ -static pdcp_params_t pdcp_params= {0,NULL}; - -uint64_t get_pdcp_optmask(void) { - return pdcp_params.optmask; -} -//----------------------------------------------------------------------------- -/* - * If PDCP_UNIT_TEST is set here then data flow between PDCP and RLC is broken - * and PDCP has no longer anything to do with RLC. In this case, after it's handed - * an SDU it appends PDCP header and returns (by filling in incoming pointer parameters) - * this mem_block_t to be dissected for testing purposes. For further details see test - * code at targets/TEST/PDCP/test_pdcp.c:test_pdcp_data_req() - */ -boolean_t pdcp_data_req( - protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - const confirm_t confirmP, - const sdu_size_t sdu_buffer_sizeP, - unsigned char *const sdu_buffer_pP, - const pdcp_transmission_mode_t modeP, - const uint32_t *const sourceL2Id, - const uint32_t *const destinationL2Id -) -//----------------------------------------------------------------------------- -{ - pdcp_t *pdcp_p = NULL; - uint8_t i = 0; - uint8_t pdcp_header_len = 0; - uint8_t pdcp_tailer_len = 0; - uint16_t pdcp_pdu_size = 0; - uint16_t current_sn = 0; - mem_block_t *pdcp_pdu_p = NULL; - rlc_op_status_t rlc_status; - boolean_t ret = TRUE; - hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; - hashtable_rc_t h_rc; - uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 : 0; - uint16_t pdcp_uid=0; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_IN); - CHECK_CTXT_ARGS(ctxt_pP); -#if T_TRACER - - if (ctxt_pP->enb_flag != ENB_FLAG_NO) - T(T_ENB_PDCP_DL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_buffer_sizeP)); - -#endif - - if (sdu_buffer_sizeP == 0) { - LOG_W(PDCP, "Handed SDU is of size 0! Ignoring...\n"); - return FALSE; - } - - /* - * XXX MAX_IP_PACKET_SIZE is 4096, shouldn't this be MAX SDU size, which is 8188 bytes? - */ - AssertFatal(sdu_buffer_sizeP<= MAX_IP_PACKET_SIZE,"Requested SDU size (%d) is bigger than that can be handled by PDCP (%u)!\n", - sdu_buffer_sizeP, MAX_IP_PACKET_SIZE); - - if (modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT) { - AssertError (rb_idP < NB_RB_MBMS_MAX, return FALSE, "RB id is too high (%u/%d) %u %u!\n", rb_idP, NB_RB_MBMS_MAX, ctxt_pP->module_id, ctxt_pP->rnti); - } else { - if (srb_flagP) { - AssertError (rb_idP < 3, return FALSE, "RB id is too high (%u/%d) %u %u!\n", rb_idP, 3, ctxt_pP->module_id, ctxt_pP->rnti); - } else { - AssertError (rb_idP < LTE_maxDRB, return FALSE, "RB id is too high (%u/%d) %u %u!\n", rb_idP, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); - } - } - - key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); - h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); - - if (h_rc != HASH_TABLE_OK) { - if (modeP != PDCP_TRANSMISSION_MODE_TRANSPARENT) { - LOG_W(PDCP, PROTOCOL_CTXT_FMT" Instance is not configured for rb_id %d Ignoring SDU...\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - rb_idP); - ctxt_pP->configured=FALSE; - return FALSE; - } - } else { - // instance for a given RB is configured - ctxt_pP->configured=TRUE; - } - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); - } else { - start_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); - } - - // PDCP transparent mode for MBMS traffic - - if (modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT) { - LOG_D(PDCP, " [TM] Asking for a new mem_block of size %d\n",sdu_buffer_sizeP); - pdcp_pdu_p = get_free_mem_block(sdu_buffer_sizeP, __func__); - - if (pdcp_pdu_p != NULL) { - memcpy(&pdcp_pdu_p->data[0], sdu_buffer_pP, sdu_buffer_sizeP); - - if( LOG_DEBUGFLAG(DEBUG_PDCP) ) { - rlc_util_print_hex_octets(PDCP, - (unsigned char *)&pdcp_pdu_p->data[0], - sdu_buffer_sizeP); - LOG_UI(PDCP, "Before rlc_data_req 1, srb_flagP: %d, rb_idP: %d \n", srb_flagP, rb_idP); - } - - rlc_status = pdcp_params.send_rlc_data_req_func(ctxt_pP, srb_flagP, NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)?MBMS_FLAG_NO:MBMS_FLAG_YES, rb_idP, muiP, - confirmP, sdu_buffer_sizeP, pdcp_pdu_p,NULL,NULL); - } else { - rlc_status = RLC_OP_STATUS_OUT_OF_RESSOURCES; - LOG_E(PDCP,PROTOCOL_CTXT_FMT" PDCP_DATA_REQ SDU DROPPED, OUT OF MEMORY \n", - PROTOCOL_CTXT_ARGS(ctxt_pP)); - } - } else { - // calculate the pdcp header and trailer size - if (srb_flagP) { - pdcp_header_len = PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE; - pdcp_tailer_len = PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE; - } else { - pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; - pdcp_tailer_len = 0; - } - - pdcp_pdu_size = sdu_buffer_sizeP + pdcp_header_len + pdcp_tailer_len; - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT"Data request notification pdu size %d (header%d, trailer%d)\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), - pdcp_pdu_size, - pdcp_header_len, - pdcp_tailer_len); - /* - * Allocate a new block for the new PDU (i.e. PDU header and SDU payload) - */ - pdcp_pdu_p = get_free_mem_block(pdcp_pdu_size, __func__); - - if (pdcp_pdu_p != NULL) { - /* - * Create a Data PDU with header and append data - * - * Place User Plane PDCP Data PDU header first - */ - if (srb_flagP) { // this Control plane PDCP Data PDU - pdcp_control_plane_data_pdu_header pdu_header; - pdu_header.sn = pdcp_get_next_tx_seq_number(pdcp_p); - current_sn = pdu_header.sn; - memset(&pdu_header.mac_i[0],0,PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE); - memset(&pdcp_pdu_p->data[sdu_buffer_sizeP + pdcp_header_len],0,PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE); - - if (pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == FALSE) { - LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); - return FALSE; - } - } else { - pdcp_user_plane_data_pdu_header_with_long_sn pdu_header; - pdu_header.dc = (modeP == PDCP_TRANSMISSION_MODE_DATA) ? PDCP_DATA_PDU_BIT_SET : PDCP_CONTROL_PDU_BIT_SET; - pdu_header.sn = pdcp_get_next_tx_seq_number(pdcp_p); - current_sn = pdu_header.sn ; - - if (pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == FALSE) { - LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); - return FALSE; - } - } - - /* - * Validate incoming sequence number, there might be a problem with PDCP initialization - */ - if (current_sn > pdcp_calculate_max_seq_num_for_given_size(pdcp_p->seq_num_size)) { - LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Generated sequence number (%"PRIu16") is greater than a sequence number could ever be!\n"\ - "There must be a problem with PDCP initialization, ignoring this PDU...\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), - current_sn); - free_mem_block(pdcp_pdu_p, __func__); - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); - return FALSE; - } - - LOG_D(PDCP, "Sequence number %d is assigned to current PDU\n", current_sn); - /* Then append data... */ - memcpy(&pdcp_pdu_p->data[pdcp_header_len], sdu_buffer_pP, sdu_buffer_sizeP); - - //For control plane data that are not integrity protected, - // the MAC-I field is still present and should be padded with padding bits set to 0. - // NOTE: user-plane data are never integrity protected - for (i=0; i<pdcp_tailer_len; i++) { - pdcp_pdu_p->data[pdcp_header_len + sdu_buffer_sizeP + i] = 0x00;// pdu_header.mac_i[i]; - } - - if ((pdcp_p->security_activated != 0) && - (((pdcp_p->cipheringAlgorithm) != 0) || - ((pdcp_p->integrityProtAlgorithm) != 0))) { - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].apply_security); - } else { - start_meas(&UE_pdcp_stats[ctxt_pP->module_id].apply_security); - } - - pdcp_apply_security(ctxt_pP, - pdcp_p, - srb_flagP, - rb_idP % LTE_maxDRB, - pdcp_header_len, - current_sn, - pdcp_pdu_p->data, - sdu_buffer_sizeP); - - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].apply_security); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].apply_security); - } - } - - /* Print octets of outgoing data in hexadecimal form */ - LOG_D(PDCP, "Following content with size %d will be sent over RLC (PDCP PDU header is the first two bytes)\n", - pdcp_pdu_size); - //util_print_hex_octets(PDCP, (unsigned char*)pdcp_pdu_p->data, pdcp_pdu_size); - //util_flush_hex_octets(PDCP, (unsigned char*)pdcp_pdu->data, pdcp_pdu_size); - } else { - LOG_E(PDCP, "Cannot create a mem_block for a PDU!\n"); - - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); - } - - LOG_E(PDCP, "[FRAME %5u][%s][PDCP][MOD %u][RB %u] PDCP_DATA_REQ SDU DROPPED, OUT OF MEMORY \n", - ctxt_pP->frame, - (ctxt_pP->enb_flag) ? "eNB" : "UE", - ctxt_pP->module_id, - rb_idP); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); - return FALSE; - } - - /* - * Ask sublayer to transmit data and check return value - * to see if RLC succeeded - */ - LOG_DUMPMSG(PDCP,DEBUG_PDCP,(char *)pdcp_pdu_p->data,pdcp_pdu_size, - "[MSG] PDCP DL %s PDU on rb_id %d\n",(srb_flagP)? "CONTROL" : "DATA", rb_idP); - - if ((pdcp_pdu_p!=NULL) && (srb_flagP == 0) && (ctxt_pP->enb_flag == 1)) { - LOG_D(PDCP, "pdcp data req on drb %d, size %d, rnti %x, node_type %d \n", - rb_idP, pdcp_pdu_size, ctxt_pP->rnti, RC.rrc[ctxt_pP->module_id]->node_type); - - if (ctxt_pP->enb_flag == ENB_FLAG_YES && NODE_IS_DU(RC.rrc[ctxt_pP->module_id]->node_type)) { - LOG_E(PDCP, "Can't be DU, bad node type %d \n", RC.rrc[ctxt_pP->module_id]->node_type); - ret=FALSE; - } else { - rlc_status = pdcp_params.send_rlc_data_req_func(ctxt_pP, srb_flagP, MBMS_FLAG_NO, rb_idP, muiP, - confirmP, pdcp_pdu_size, pdcp_pdu_p,sourceL2Id, - destinationL2Id); - - switch (rlc_status) { - case RLC_OP_STATUS_OK: - LOG_D(PDCP, "Data sending request over RLC succeeded!\n"); - ret=TRUE; - break; - - case RLC_OP_STATUS_BAD_PARAMETER: - LOG_W(PDCP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); - ret= FALSE; - break; - - case RLC_OP_STATUS_INTERNAL_ERROR: - LOG_W(PDCP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); - ret= FALSE; - break; - - case RLC_OP_STATUS_OUT_OF_RESSOURCES: - LOG_W(PDCP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); - ret= FALSE; - break; - - default: - LOG_W(PDCP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); - ret= FALSE; - break; - } // switch case - } /* end if node_type is not DU */ - } else { // SRB - if (ctxt_pP->enb_flag == ENB_FLAG_YES && NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) { - // DL transfer - MessageDef *message_p; - // Note: the acyual task must be TASK_PDCP_ENB, but this task is not created - message_p = itti_alloc_new_message (TASK_PDCP_ENB, F1AP_DL_RRC_MESSAGE); - F1AP_DL_RRC_MESSAGE (message_p).rrc_container = &pdcp_pdu_p->data[0] ; - F1AP_DL_RRC_MESSAGE (message_p).rrc_container_length = pdcp_pdu_size; - F1AP_DL_RRC_MESSAGE (message_p).gNB_CU_ue_id = 0; - F1AP_DL_RRC_MESSAGE (message_p).gNB_DU_ue_id = 0; - F1AP_DL_RRC_MESSAGE (message_p).old_gNB_DU_ue_id = 0xFFFFFFFF; // unknown - F1AP_DL_RRC_MESSAGE (message_p).rnti = ctxt_pP->rnti; - F1AP_DL_RRC_MESSAGE (message_p).srb_id = rb_idP; - F1AP_DL_RRC_MESSAGE (message_p).execute_duplication = 1; - F1AP_DL_RRC_MESSAGE (message_p).RAT_frequency_priority_information.en_dc = 0; - itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); - //CU_send_DL_RRC_MESSAGE_TRANSFER(ctxt_pP->module_id, message_p); - LOG_I(PDCP, "Send F1AP_DL_RRC_MESSAGE with ITTI\n"); - ret=TRUE; - } else { - rlc_status = rlc_data_req(ctxt_pP - , srb_flagP - , MBMS_FLAG_NO - , rb_idP - , muiP - , confirmP - , pdcp_pdu_size - , pdcp_pdu_p - ,NULL - ,NULL - ); - - switch (rlc_status) { - case RLC_OP_STATUS_OK: - LOG_D(PDCP, "Data sending request over RLC succeeded!\n"); - ret=TRUE; - break; - - case RLC_OP_STATUS_BAD_PARAMETER: - LOG_W(PDCP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); - ret= FALSE; - break; - - case RLC_OP_STATUS_INTERNAL_ERROR: - LOG_W(PDCP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); - ret= FALSE; - break; - - case RLC_OP_STATUS_OUT_OF_RESSOURCES: - LOG_W(PDCP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); - ret= FALSE; - break; - - default: - LOG_W(PDCP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); - ret= FALSE; - break; - } // switch case - } - } - } - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); - } - - /* - * Control arrives here only if rlc_data_req() returns RLC_OP_STATUS_OK - * so we return TRUE afterwards - */ - - for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { - if (pdcp_enb[ctxt_pP->module_id].rnti[pdcp_uid] == ctxt_pP->rnti ) - break; - } - - //LOG_I(PDCP,"ueid %d lcid %d tx seq num %d\n", pdcp_uid, rb_idP+rb_offset, current_sn); - Pdcp_stats_tx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; - Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; - Pdcp_stats_tx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=current_sn; - Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); - return ret; -} - - -//----------------------------------------------------------------------------- -boolean_t -pdcp_data_ind( - const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const MBMS_flag_t MBMS_flagP, - const rb_id_t rb_idP, - const sdu_size_t sdu_buffer_sizeP, - mem_block_t *const sdu_buffer_pP -) -//----------------------------------------------------------------------------- -{ - pdcp_t *pdcp_p = NULL; - list_t *sdu_list_p = NULL; - mem_block_t *new_sdu_p = NULL; - uint8_t pdcp_header_len = 0; - uint8_t pdcp_tailer_len = 0; - pdcp_sn_t sequence_number = 0; - volatile sdu_size_t payload_offset = 0; - rb_id_t rb_id = rb_idP; - boolean_t packet_forwarded = FALSE; - hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; - hashtable_rc_t h_rc; - uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 :0; - uint16_t pdcp_uid=0; - MessageDef *message_p = NULL; - uint8_t *gtpu_buffer_p = NULL; - uint32_t rx_hfn_for_count; - int pdcp_sn_for_count; - int security_ok; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_IN); - LOG_DUMPMSG(PDCP,DEBUG_PDCP,(char *)sdu_buffer_pP->data,sdu_buffer_sizeP, - "[MSG] PDCP UL %s PDU on rb_id %d\n", (srb_flagP)? "CONTROL" : "DATA", rb_idP); -#if T_TRACER - - if (ctxt_pP->enb_flag != ENB_FLAG_NO) - T(T_ENB_PDCP_UL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_buffer_sizeP)); - -#endif - - if (MBMS_flagP) { - AssertError (rb_idP < NB_RB_MBMS_MAX, return FALSE, - "RB id is too high (%u/%d) %u rnti %x!\n", - rb_idP, - NB_RB_MBMS_MAX, - ctxt_pP->module_id, - ctxt_pP->rnti); - - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - LOG_D(PDCP, "e-MBMS Data indication notification for PDCP entity from eNB %u to UE %x " - "and radio bearer ID %d rlc sdu size %d ctxt_pP->enb_flag %d\n", - ctxt_pP->module_id, - ctxt_pP->rnti, - rb_idP, - sdu_buffer_sizeP, - ctxt_pP->enb_flag); - } else { - LOG_D(PDCP, "Data indication notification for PDCP entity from UE %x to eNB %u " - "and radio bearer ID %d rlc sdu size %d ctxt_pP->enb_flag %d\n", - ctxt_pP->rnti, - ctxt_pP->module_id, - rb_idP, - sdu_buffer_sizeP, - ctxt_pP->enb_flag); - } - } else { - rb_id = rb_idP % LTE_maxDRB; - AssertError (rb_id < LTE_maxDRB, return FALSE, "RB id is too high (%u/%d) %u UE %x!\n", - rb_id, - LTE_maxDRB, - ctxt_pP->module_id, - ctxt_pP->rnti); - AssertError (rb_id > 0, return FALSE, "RB id is too low (%u/%d) %u UE %x!\n", - rb_id, - LTE_maxDRB, - ctxt_pP->module_id, - ctxt_pP->rnti); - key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_id, srb_flagP); - - h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); - - if (h_rc != HASH_TABLE_OK) { - LOG_W(PDCP, - PROTOCOL_CTXT_FMT"Could not get PDCP instance key 0x%"PRIx64"\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - key); - free_mem_block(sdu_buffer_pP, __func__); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return FALSE; - } - } - - sdu_list_p = &pdcp_sdu_list; - - if (sdu_buffer_sizeP == 0) { - LOG_W(PDCP, "SDU buffer size is zero! Ignoring this chunk!\n"); - return FALSE; - } - - if (ctxt_pP->enb_flag) { - start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); - } else { - start_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); - } - - /* - * Parse the PDU placed at the beginning of SDU to check - * if incoming SN is in line with RX window - */ - - if (MBMS_flagP == 0 ) { - if (srb_flagP) { //SRB1/2 - pdcp_header_len = PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE; - pdcp_tailer_len = PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE; - sequence_number = pdcp_get_sequence_number_of_pdu_with_SRB_sn((unsigned char *)sdu_buffer_pP->data); - } else { // DRB - pdcp_tailer_len = 0; - - if (pdcp_p->seq_num_size == 7) { - pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_SHORT_SN_HEADER_SIZE; - sequence_number = pdcp_get_sequence_number_of_pdu_with_short_sn((unsigned char *)sdu_buffer_pP->data); - } else if (pdcp_p->seq_num_size == 12) { - pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; - sequence_number = pdcp_get_sequence_number_of_pdu_with_long_sn((unsigned char *)sdu_buffer_pP->data); - } else { - //sequence_number = 4095; - LOG_E(PDCP, - PROTOCOL_PDCP_CTXT_FMT"wrong sequence number (%d) for this pdcp entity \n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - pdcp_p->seq_num_size); - exit(1); - } - - //uint8_t dc = pdcp_get_dc_filed((unsigned char*)sdu_buffer_pP->data); - } - - /* - * Check if incoming SDU is long enough to carry a PDU header - */ - if (sdu_buffer_sizeP < pdcp_header_len + pdcp_tailer_len ) { - LOG_W(PDCP, - PROTOCOL_PDCP_CTXT_FMT"Incoming (from RLC) SDU is short of size (size:%d)! Ignoring...\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - sdu_buffer_sizeP); - free_mem_block(sdu_buffer_pP, __func__); - - if (ctxt_pP->enb_flag) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return FALSE; - } - -#if 0 - - /* Removed by Cedric */ - if (pdcp_is_rx_seq_number_valid(sequence_number, pdcp_p, srb_flagP) == TRUE) { - LOG_T(PDCP, "Incoming PDU has a sequence number (%d) in accordance with RX window\n", sequence_number); - /* if (dc == PDCP_DATA_PDU ) - LOG_D(PDCP, "Passing piggybacked SDU to NAS driver...\n"); - else - LOG_D(PDCP, "Passing piggybacked SDU to RRC ...\n");*/ - } else { - Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - LOG_E(PDCP, - PROTOCOL_PDCP_CTXT_FMT"Incoming PDU has an unexpected sequence number (%d), RX window synchronisation have probably been lost!\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - sequence_number); - /* - * XXX Till we implement in-sequence delivery and duplicate discarding - * mechanism all out-of-order packets will be delivered to RRC/IP - */ - LOG_W(PDCP, "Ignoring PDU...\n"); - free_mem_block(sdu_buffer_pP, __func__); - return FALSE; - } - -#endif - - // SRB1/2: control-plane data - if (srb_flagP) { - /* process as described in 36.323 5.1.2.2 */ - if (sequence_number < pdcp_p->next_pdcp_rx_sn) { - rx_hfn_for_count = pdcp_p->rx_hfn + 1; - pdcp_sn_for_count = sequence_number; - } else { - rx_hfn_for_count = pdcp_p->rx_hfn; - pdcp_sn_for_count = sequence_number; - } - - if (pdcp_p->security_activated == 1) { - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); - } else { - start_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); - } - - security_ok = pdcp_validate_security(ctxt_pP, - pdcp_p, - srb_flagP, - rb_idP, - pdcp_header_len, - rx_hfn_for_count, - pdcp_sn_for_count, - sdu_buffer_pP->data, - sdu_buffer_sizeP - pdcp_tailer_len) == 0; - - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); - } - } else { - security_ok = 1; - } - - if (security_ok == 0) { - LOG_W(PDCP, - PROTOCOL_PDCP_CTXT_FMT"security not validated for incoming PDCP SRB PDU\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); - LOG_W(PDCP, "Ignoring PDU...\n"); - free_mem_block(sdu_buffer_pP, __func__); - /* TODO: indicate integrity verification failure to upper layer */ - return FALSE; - } - - if (sequence_number < pdcp_p->next_pdcp_rx_sn) - pdcp_p->rx_hfn++; - - pdcp_p->next_pdcp_rx_sn = sequence_number + 1; - - if (pdcp_p->next_pdcp_rx_sn > pdcp_p->maximum_pdcp_rx_sn) { - pdcp_p->next_pdcp_rx_sn = 0; - pdcp_p->rx_hfn++; - } - - //rrc_lite_data_ind(module_id, //Modified MW - L2 Interface - MSC_LOG_TX_MESSAGE( - (ctxt_pP->enb_flag == ENB_FLAG_NO)? MSC_PDCP_UE:MSC_PDCP_ENB, - (ctxt_pP->enb_flag == ENB_FLAG_NO)? MSC_RRC_UE:MSC_RRC_ENB, - NULL,0, - PROTOCOL_PDCP_CTXT_FMT" DATA-IND len %u", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - sdu_buffer_sizeP - pdcp_header_len - pdcp_tailer_len); - - rrc_data_ind(ctxt_pP, - rb_id, - sdu_buffer_sizeP - pdcp_header_len - pdcp_tailer_len, - (uint8_t *)&sdu_buffer_pP->data[pdcp_header_len]); - free_mem_block(sdu_buffer_pP, __func__); - - // free_mem_block(new_sdu, __func__); - if (ctxt_pP->enb_flag) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return TRUE; - } /* if (srb_flagP) */ - - /* - * DRBs - */ - payload_offset=pdcp_header_len;// PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; - - switch (pdcp_p->rlc_mode) { - case RLC_MODE_AM: { - /* process as described in 36.323 5.1.2.1.2 */ - int reordering_window; - - if (pdcp_p->seq_num_size == 7) - reordering_window = REORDERING_WINDOW_SN_7BIT; - else - reordering_window = REORDERING_WINDOW_SN_12BIT; - - if (sequence_number - pdcp_p->last_submitted_pdcp_rx_sn > reordering_window || - (pdcp_p->last_submitted_pdcp_rx_sn - sequence_number >= 0 && - pdcp_p->last_submitted_pdcp_rx_sn - sequence_number < reordering_window)) { - /* TODO: specs say to decipher and do header decompression */ - LOG_W(PDCP, - PROTOCOL_PDCP_CTXT_FMT"discard PDU, out of\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); - LOG_W(PDCP, "Ignoring PDU...\n"); - free_mem_block(sdu_buffer_pP, __func__); - /* TODO: indicate integrity verification failure to upper layer */ - return FALSE; - } else if (pdcp_p->next_pdcp_rx_sn - sequence_number > reordering_window) { - pdcp_p->rx_hfn++; - rx_hfn_for_count = pdcp_p->rx_hfn; - pdcp_sn_for_count = sequence_number; - pdcp_p->next_pdcp_rx_sn = sequence_number + 1; - } else if (sequence_number - pdcp_p->next_pdcp_rx_sn >= reordering_window) { - rx_hfn_for_count = pdcp_p->rx_hfn - 1; - pdcp_sn_for_count = sequence_number; - } else if (sequence_number >= pdcp_p->next_pdcp_rx_sn) { - rx_hfn_for_count = pdcp_p->rx_hfn; - pdcp_sn_for_count = sequence_number; - pdcp_p->next_pdcp_rx_sn = sequence_number + 1; - - if (pdcp_p->next_pdcp_rx_sn > pdcp_p->maximum_pdcp_rx_sn) { - pdcp_p->next_pdcp_rx_sn = 0; - pdcp_p->rx_hfn++; - } - } else { /* sequence_number < pdcp_p->next_pdcp_rx_sn */ - rx_hfn_for_count = pdcp_p->rx_hfn; - pdcp_sn_for_count = sequence_number; - } - - if (pdcp_p->security_activated == 1) { - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); - } else { - start_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); - } - - security_ok = pdcp_validate_security(ctxt_pP, - pdcp_p, - srb_flagP, - rb_idP, - pdcp_header_len, - rx_hfn_for_count, - pdcp_sn_for_count, - sdu_buffer_pP->data, - sdu_buffer_sizeP - pdcp_tailer_len) == 0; - - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); - } - } else { - security_ok = 1; - } - - if (security_ok == 0) { - LOG_W(PDCP, - PROTOCOL_PDCP_CTXT_FMT"security not validated for incoming PDPC DRB RLC/AM PDU\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); - LOG_W(PDCP, "Ignoring PDU...\n"); - free_mem_block(sdu_buffer_pP, __func__); - /* TODO: indicate integrity verification failure to upper layer */ - return FALSE; - } - - /* TODO: specs say we have to store this PDU in a list and then deliver - * stored packets to upper layers according to a well defined - * procedure. The code below that deals with delivery is today - * too complex to do this properly, so we only send the current - * received packet. This is not correct and has to be fixed - * some day. - * In the meantime, let's pretend the last submitted PDCP SDU - * is the current one. - * TODO: we also have to deal with re-establishment PDU (control PDUs) - * that contain no SDU. - */ - pdcp_p->last_submitted_pdcp_rx_sn = sequence_number; - break; - } /* case RLC_MODE_AM */ - - case RLC_MODE_UM: - - /* process as described in 36.323 5.1.2.1.3 */ - if (sequence_number < pdcp_p->next_pdcp_rx_sn) { - pdcp_p->rx_hfn++; - } - - rx_hfn_for_count = pdcp_p->rx_hfn; - pdcp_sn_for_count = sequence_number; - pdcp_p->next_pdcp_rx_sn = sequence_number + 1; - - if (pdcp_p->next_pdcp_rx_sn > pdcp_p->maximum_pdcp_rx_sn) { - pdcp_p->next_pdcp_rx_sn = 0; - pdcp_p->rx_hfn++; - } - - if (pdcp_p->security_activated == 1) { - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); - } else { - start_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); - } - - security_ok = pdcp_validate_security(ctxt_pP, - pdcp_p, - srb_flagP, - rb_idP, - pdcp_header_len, - rx_hfn_for_count, - pdcp_sn_for_count, - sdu_buffer_pP->data, - sdu_buffer_sizeP - pdcp_tailer_len) == 0; - - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); - } - } else { - security_ok = 1; - } - - if (security_ok == 0) { - LOG_W(PDCP, - PROTOCOL_PDCP_CTXT_FMT"security not validated for incoming PDPC DRB RLC/UM PDU\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); - LOG_W(PDCP, "Ignoring PDU...\n"); - free_mem_block(sdu_buffer_pP, __func__); - /* TODO: indicate integrity verification failure to upper layer */ - return FALSE; - } - - break; - - default: - LOG_E(PDCP, "bad RLC mode, cannot happen.\n"); - exit(1); - } /* switch (pdcp_p->rlc_mode) */ - } else { /* MBMS_flagP == 0 */ - payload_offset=0; - } - - if (otg_enabled==1) { - LOG_D(OTG,"Discarding received packed\n"); - free_mem_block(sdu_buffer_pP, __func__); - - if (ctxt_pP->enb_flag) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return TRUE; - } - - // XXX Decompression would be done at this point - /* - * After checking incoming sequence number PDCP header - * has to be stripped off so here we copy SDU buffer starting - * from its second byte (skipping 0th and 1st octets, i.e. - * PDCP header) - */ - - if (LINK_ENB_PDCP_TO_GTPV1U) { - if ((TRUE == ctxt_pP->enb_flag) && (FALSE == srb_flagP)) { - LOG_D(PDCP, "Sending packet to GTP, Calling GTPV1U_ENB_TUNNEL_DATA_REQ ue %x rab %u len %u\n", - ctxt_pP->rnti, - rb_id + 4, - sdu_buffer_sizeP - payload_offset ); - MSC_LOG_TX_MESSAGE( - MSC_PDCP_ENB, - MSC_GTPU_ENB, - NULL,0, - "0 GTPV1U_ENB_TUNNEL_DATA_REQ ue %x rab %u len %u", - ctxt_pP->rnti, - rb_id + 4, - sdu_buffer_sizeP - payload_offset); - //LOG_T(PDCP,"Sending to GTPV1U %d bytes\n", sdu_buffer_sizeP - payload_offset); - gtpu_buffer_p = itti_malloc(TASK_PDCP_ENB, TASK_GTPV1_U, - sdu_buffer_sizeP - payload_offset + GTPU_HEADER_OVERHEAD_MAX); - AssertFatal(gtpu_buffer_p != NULL, "OUT OF MEMORY"); - memcpy(>pu_buffer_p[GTPU_HEADER_OVERHEAD_MAX], &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset); - message_p = itti_alloc_new_message(TASK_PDCP_ENB, GTPV1U_ENB_TUNNEL_DATA_REQ); - AssertFatal(message_p != NULL, "OUT OF MEMORY"); - GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).buffer = gtpu_buffer_p; - GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).length = sdu_buffer_sizeP - payload_offset; - GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).offset = GTPU_HEADER_OVERHEAD_MAX; - GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rnti = ctxt_pP->rnti; - GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rab_id = rb_id + 4; - itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); - packet_forwarded = TRUE; - } - } else { - packet_forwarded = FALSE; - } - -#ifdef MBMS_MULTICAST_OUT - - if ((MBMS_flagP != 0) && (mbms_socket != -1)) { - struct iphdr *ip_header = (struct iphdr *)&sdu_buffer_pP->data[payload_offset]; - struct udphdr *udp_header = (struct udphdr *)&sdu_buffer_pP->data[payload_offset + sizeof(struct iphdr)]; - struct sockaddr_in dest_addr; - dest_addr.sin_family = AF_INET; - dest_addr.sin_port = udp_header->dest; - dest_addr.sin_addr.s_addr = ip_header->daddr; - - sendto(mbms_socket, &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset, MSG_DONTWAIT, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); - //packet_forwarded = TRUE; - - } - -#endif - - if (FALSE == packet_forwarded) { - new_sdu_p = get_free_mem_block(sdu_buffer_sizeP - payload_offset + sizeof (pdcp_data_ind_header_t), __func__); - - if (new_sdu_p) { - if ((MBMS_flagP == 0) && (pdcp_p->rlc_mode == RLC_MODE_AM)) { - pdcp_p->last_submitted_pdcp_rx_sn = sequence_number; - } - - /* - * Prepend PDCP indication header which is going to be removed at pdcp_fifo_flush_sdus() - */ - memset(new_sdu_p->data, 0, sizeof (pdcp_data_ind_header_t)); - ((pdcp_data_ind_header_t *) new_sdu_p->data)->data_size = sdu_buffer_sizeP - payload_offset; - AssertFatal((sdu_buffer_sizeP - payload_offset >= 0), "invalid PDCP SDU size!"); - - // Here there is no virtualization possible - // set ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst for IP layer here - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - ((pdcp_data_ind_header_t *) new_sdu_p->data)->rb_id = rb_id; - - if (EPC_MODE_ENABLED) { - /* for the UE compiled in S1 mode, we need 1 here - * for the UE compiled in noS1 mode, we need 0 - * TODO: be sure of this - */ - if (NFAPI_MODE == NFAPI_UE_STUB_PNF ) { -#ifdef UESIM_EXPANSION - - if (UE_NAS_USE_TUN) { - ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = ctxt_pP->module_id; - } else { - ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = 0; - } - -#else - ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = ctxt_pP->module_id; -#endif - } else { // nfapi_mode - if (UE_NAS_USE_TUN) { - ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = ctxt_pP->module_id; - } else { - ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = 1; - } - } // nfapi_mode - } - } else { - ((pdcp_data_ind_header_t *) new_sdu_p->data)->rb_id = rb_id + (ctxt_pP->module_id * LTE_maxDRB); - ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = ctxt_pP->module_id; - } - - if( LOG_DEBUGFLAG(DEBUG_PDCP) ) { - static uint32_t pdcp_inst = 0; - ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = pdcp_inst++; - LOG_D(PDCP, "inst=%d size=%d\n", ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst, ((pdcp_data_ind_header_t *) new_sdu_p->data)->data_size); - } - - memcpy(&new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], - &sdu_buffer_pP->data[payload_offset], - sdu_buffer_sizeP - payload_offset); - list_add_tail_eurecom (new_sdu_p, sdu_list_p); - } - - /* Print octets of incoming data in hexadecimal form */ - LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n", - sdu_buffer_sizeP - payload_offset + (int)sizeof(pdcp_data_ind_header_t), - sdu_buffer_sizeP - payload_offset); - //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); - //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); - } - - /* Update PDCP statistics */ - for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { - if (pdcp_enb[ctxt_pP->module_id].rnti[pdcp_uid] == ctxt_pP->rnti ) { - break; - } - } - - Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; - Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); - Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); - Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number; - Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; - free_mem_block(sdu_buffer_pP, __func__); - - if (ctxt_pP->enb_flag) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); - return TRUE; -} - -void pdcp_update_stats(const protocol_ctxt_t *const ctxt_pP) { - uint16_t pdcp_uid = 0; - uint8_t rb_id = 0; - - // these stats are measured for both eNB and UE on per seond basis - for (rb_id =0; rb_id < NB_RB_MAX; rb_id ++) { - for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { - //printf("frame %d and subframe %d \n", pdcp_enb[ctxt_pP->module_id].frame, pdcp_enb[ctxt_pP->module_id].subframe); - // tx stats - if (Pdcp_stats_tx_window_ms[ctxt_pP->module_id][pdcp_uid] > 0 && - pdcp_enb[ctxt_pP->module_id].sfn % Pdcp_stats_tx_window_ms[ctxt_pP->module_id][pdcp_uid] == 0) { - // unit: bit/s - Pdcp_stats_tx_throughput_w[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]*8; - Pdcp_stats_tx_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; - Pdcp_stats_tx_bytes_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; - - if (Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id] > 0) { - Pdcp_stats_tx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=(Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]); - } else { - Pdcp_stats_tx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - } - - // reset the tmp vars - Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - } - - if (Pdcp_stats_rx_window_ms[ctxt_pP->module_id][pdcp_uid] > 0 && - pdcp_enb[ctxt_pP->module_id].sfn % Pdcp_stats_rx_window_ms[ctxt_pP->module_id][pdcp_uid] == 0) { - // rx stats - Pdcp_stats_rx_goodput_w[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]*8; - Pdcp_stats_rx_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; - Pdcp_stats_rx_bytes_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; - - if(Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id] > 0) { - Pdcp_stats_rx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]= (Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]); - } else { - Pdcp_stats_rx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - } - - // reset the tmp vars - Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; - } - } - } -} - - -//----------------------------------------------------------------------------- -void -pdcp_run ( - const protocol_ctxt_t *const ctxt_pP -) -//----------------------------------------------------------------------------- -{ - if (ctxt_pP->enb_flag) { - start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); - } else { - start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); - } - - pdcp_enb[ctxt_pP->module_id].sfn++; // range: 0 to 18,446,744,073,709,551,615 - pdcp_enb[ctxt_pP->module_id].frame=ctxt_pP->frame; // 1023 - pdcp_enb[ctxt_pP->module_id].subframe= ctxt_pP->subframe; - pdcp_update_stats(ctxt_pP); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_IN); - MessageDef *msg_p; - int result; - protocol_ctxt_t ctxt; - - do { - // Checks if a message has been sent to PDCP sub-task - itti_poll_msg (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, &msg_p); - - if (msg_p != NULL) { - switch (ITTI_MSG_ID(msg_p)) { - case RRC_DCCH_DATA_REQ: - PROTOCOL_CTXT_SET_BY_MODULE_ID( - &ctxt, - RRC_DCCH_DATA_REQ (msg_p).module_id, - RRC_DCCH_DATA_REQ (msg_p).enb_flag, - RRC_DCCH_DATA_REQ (msg_p).rnti, - RRC_DCCH_DATA_REQ (msg_p).frame, - 0, - RRC_DCCH_DATA_REQ (msg_p).eNB_index); - LOG_D(PDCP, PROTOCOL_CTXT_FMT"Received %s from %s: instance %d, rb_id %d, muiP %d, confirmP %d, mode %d\n", - PROTOCOL_CTXT_ARGS(&ctxt), - ITTI_MSG_NAME (msg_p), - ITTI_MSG_ORIGIN_NAME(msg_p), - ITTI_MSG_INSTANCE (msg_p), - RRC_DCCH_DATA_REQ (msg_p).rb_id, - RRC_DCCH_DATA_REQ (msg_p).muip, - RRC_DCCH_DATA_REQ (msg_p).confirmp, - RRC_DCCH_DATA_REQ (msg_p).mode); - LOG_D(PDCP, "Before calling pdcp_data_req from pdcp_run! RRC_DCCH_DATA_REQ (msg_p).rb_id: %d \n", RRC_DCCH_DATA_REQ (msg_p).rb_id); - result = pdcp_data_req (&ctxt, - SRB_FLAG_YES, - RRC_DCCH_DATA_REQ (msg_p).rb_id, - RRC_DCCH_DATA_REQ (msg_p).muip, - RRC_DCCH_DATA_REQ (msg_p).confirmp, - RRC_DCCH_DATA_REQ (msg_p).sdu_size, - RRC_DCCH_DATA_REQ (msg_p).sdu_p, - RRC_DCCH_DATA_REQ (msg_p).mode, - NULL, NULL - ); - - if (result != TRUE) - LOG_E(PDCP, "PDCP data request failed!\n"); - - // Message buffer has been processed, free it now. - result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_REQ (msg_p).sdu_p); - AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); - break; - - case RRC_PCCH_DATA_REQ: { - sdu_size_t sdu_buffer_sizeP; - sdu_buffer_sizeP = RRC_PCCH_DATA_REQ(msg_p).sdu_size; - uint8_t CC_id = RRC_PCCH_DATA_REQ(msg_p).CC_id; - uint8_t ue_index = RRC_PCCH_DATA_REQ(msg_p).ue_index; - RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_paging[ue_index] = sdu_buffer_sizeP; - - if (sdu_buffer_sizeP > 0) { - memcpy(RC.rrc[ctxt_pP->module_id]->carrier[CC_id].paging[ue_index], RRC_PCCH_DATA_REQ(msg_p).sdu_p, sdu_buffer_sizeP); - } - - //paging pdcp log - LOG_D(PDCP, "PDCP Received RRC_PCCH_DATA_REQ CC_id %d length %d \n", CC_id, sdu_buffer_sizeP); - } - break; - - default: - LOG_E(PDCP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p)); - break; - } - - result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); - AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); - } - } while(msg_p != NULL); - - // IP/NAS -> PDCP traffic : TX, read the pkt from the upper layer buffer - // if (LINK_ENB_PDCP_TO_GTPV1U && ctxt_pP->enb_flag == ENB_FLAG_NO) { - if (!EPC_MODE_ENABLED || ctxt_pP->enb_flag == ENB_FLAG_NO ) { - pdcp_fifo_read_input_sdus(ctxt_pP); - } - - // PDCP -> NAS/IP traffic: RX - if (ctxt_pP->enb_flag) { - start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); - } else { - start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); - } - - pdcp_fifo_flush_sdus(ctxt_pP); - - if (ctxt_pP->enb_flag) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); - } - - if (ctxt_pP->enb_flag) { - stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); - } else { - stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_OUT); -} - -void pdcp_init_stats_UE(module_id_t mod, uint16_t uid) { - Pdcp_stats_tx_window_ms[mod][uid] = 100; - Pdcp_stats_rx_window_ms[mod][uid] = 100; - - for (int i = 0; i < NB_RB_MAX; ++i) { - Pdcp_stats_tx_bytes[mod][uid][i] = 0; - Pdcp_stats_tx_bytes_w[mod][uid][i] = 0; - Pdcp_stats_tx_bytes_tmp_w[mod][uid][i] = 0; - Pdcp_stats_tx[mod][uid][i] = 0; - Pdcp_stats_tx_w[mod][uid][i] = 0; - Pdcp_stats_tx_tmp_w[mod][uid][i] = 0; - Pdcp_stats_tx_sn[mod][uid][i] = 0; - Pdcp_stats_tx_throughput_w[mod][uid][i] = 0; - Pdcp_stats_tx_aiat[mod][uid][i] = 0; - Pdcp_stats_tx_aiat_w[mod][uid][i] = 0; - Pdcp_stats_tx_aiat_tmp_w[mod][uid][i] = 0; - Pdcp_stats_tx_iat[mod][uid][i] = 0; - Pdcp_stats_rx[mod][uid][i] = 0; - Pdcp_stats_rx_w[mod][uid][i] = 0; - Pdcp_stats_rx_tmp_w[mod][uid][i] = 0; - Pdcp_stats_rx_bytes[mod][uid][i] = 0; - Pdcp_stats_rx_bytes_w[mod][uid][i] = 0; - Pdcp_stats_rx_bytes_tmp_w[mod][uid][i] = 0; - Pdcp_stats_rx_sn[mod][uid][i] = 0; - Pdcp_stats_rx_goodput_w[mod][uid][i] = 0; - Pdcp_stats_rx_aiat[mod][uid][i] = 0; - Pdcp_stats_rx_aiat_w[mod][uid][i] = 0; - Pdcp_stats_rx_aiat_tmp_w[mod][uid][i] = 0; - Pdcp_stats_rx_iat[mod][uid][i] = 0; - Pdcp_stats_rx_outoforder[mod][uid][i] = 0; - } -} - -void pdcp_add_UE(const protocol_ctxt_t *const ctxt_pP) { - int i, ue_flag=1; //, ret=-1; to be decied later - - for (i=0; i < MAX_MOBILES_PER_ENB; i++) { - if (pdcp_enb[ctxt_pP->module_id].rnti[i] == ctxt_pP->rnti) { - ue_flag=-1; - break; - } - } - - if (ue_flag == 1 ) { - for (i=0; i < MAX_MOBILES_PER_ENB ; i++) { - if (pdcp_enb[ctxt_pP->module_id].rnti[i] == 0 ) { - pdcp_enb[ctxt_pP->module_id].rnti[i]=ctxt_pP->rnti; - pdcp_enb[ctxt_pP->module_id].uid[i]=i; - pdcp_enb[ctxt_pP->module_id].num_ues++; - printf("add new uid is %d %x\n\n", i, ctxt_pP->rnti); - pdcp_init_stats_UE(ctxt_pP->module_id, i); - // ret=1; - break; - } - } - } - - //return ret; -} - -//----------------------------------------------------------------------------- -boolean_t -pdcp_remove_UE( - const protocol_ctxt_t *const ctxt_pP -) -//----------------------------------------------------------------------------- -{ - LTE_DRB_Identity_t srb_id = 0; - LTE_DRB_Identity_t drb_id = 0; - hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; - hashtable_rc_t h_rc; - int i; - // check and remove SRBs first - - for(int i = 0; i<MAX_MOBILES_PER_ENB; i++) { - if(pdcp_eNB_UE_instance_to_rnti[i] == ctxt_pP->rnti) { - pdcp_eNB_UE_instance_to_rnti[i] = NOT_A_RNTI; - break; - } - } - - for (srb_id=1; srb_id<3; srb_id++) { - key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); - h_rc = hashtable_remove(pdcp_coll_p, key); - } - - for (drb_id=0; drb_id<LTE_maxDRB; drb_id++) { - key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); - h_rc = hashtable_remove(pdcp_coll_p, key); - } - - (void)h_rc; /* remove gcc warning "set but not used" */ - - // remove ue for pdcp enb inst - for (i=0; i < MAX_MOBILES_PER_ENB; i++) { - if (pdcp_enb[ctxt_pP->module_id].rnti[i] == ctxt_pP->rnti ) { - LOG_I(PDCP, "remove uid is %d/%d %x\n", i, - pdcp_enb[ctxt_pP->module_id].uid[i], - pdcp_enb[ctxt_pP->module_id].rnti[i]); - pdcp_enb[ctxt_pP->module_id].uid[i]=0; - pdcp_enb[ctxt_pP->module_id].rnti[i]=0; - pdcp_enb[ctxt_pP->module_id].num_ues--; - break; - } - } - - return 1; -} - - -//----------------------------------------------------------------------------- -boolean_t -rrc_pdcp_config_asn1_req ( - const protocol_ctxt_t *const ctxt_pP, - LTE_SRB_ToAddModList_t *const srb2add_list_pP, - LTE_DRB_ToAddModList_t *const drb2add_list_pP, - LTE_DRB_ToReleaseList_t *const drb2release_list_pP, - const uint8_t security_modeP, - uint8_t *const kRRCenc_pP, - uint8_t *const kRRCint_pP, - uint8_t *const kUPenc_pP, - LTE_PMCH_InfoList_r9_t *const pmch_InfoList_r9_pP, - rb_id_t *const defaultDRB -) -//----------------------------------------------------------------------------- -{ - long int lc_id = 0; - LTE_DRB_Identity_t srb_id = 0; - long int mch_id = 0; - rlc_mode_t rlc_type = RLC_MODE_NONE; - LTE_DRB_Identity_t drb_id = 0; - LTE_DRB_Identity_t *pdrb_id_p = NULL; - uint8_t drb_sn = 12; - uint8_t srb_sn = 5; // fixed sn for SRBs - uint8_t drb_report = 0; - long int cnt = 0; - uint16_t header_compression_profile = 0; - config_action_t action = CONFIG_ACTION_ADD; - LTE_SRB_ToAddMod_t *srb_toaddmod_p = NULL; - LTE_DRB_ToAddMod_t *drb_toaddmod_p = NULL; - pdcp_t *pdcp_p = NULL; - hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; - hashtable_rc_t h_rc; - hash_key_t key_defaultDRB = HASHTABLE_NOT_A_KEY_VALUE; - hashtable_rc_t h_defaultDRB_rc; - int i,j; - LTE_MBMS_SessionInfoList_r9_t *mbms_SessionInfoList_r9_p = NULL; - LTE_MBMS_SessionInfo_r9_t *MBMS_SessionInfo_p = NULL; - LOG_T(PDCP, PROTOCOL_CTXT_FMT" %s() SRB2ADD %p DRB2ADD %p DRB2RELEASE %p\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - __FUNCTION__, - srb2add_list_pP, - drb2add_list_pP, - drb2release_list_pP); - - // srb2add_list does not define pdcp config, we use rlc info to setup the pdcp dcch0 and dcch1 channels - - if (srb2add_list_pP != NULL) { - for (cnt=0; cnt<srb2add_list_pP->list.count; cnt++) { - srb_id = srb2add_list_pP->list.array[cnt]->srb_Identity; - srb_toaddmod_p = srb2add_list_pP->list.array[cnt]; - rlc_type = RLC_MODE_AM; - lc_id = srb_id; - key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); - h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); - - if (h_rc == HASH_TABLE_OK) { - action = CONFIG_ACTION_MODIFY; - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_MODIFY key 0x%"PRIx64"\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - key); - } else { - action = CONFIG_ACTION_ADD; - pdcp_p = calloc(1, sizeof(pdcp_t)); - h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); - - if (h_rc != HASH_TABLE_OK) { - LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64" FAILED\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - key); - free(pdcp_p); - return TRUE; - } else { - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64"\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - key); - } - } - - if (srb_toaddmod_p->rlc_Config) { - switch (srb_toaddmod_p->rlc_Config->present) { - case LTE_SRB_ToAddMod__rlc_Config_PR_NOTHING: - break; - - case LTE_SRB_ToAddMod__rlc_Config_PR_explicitValue: - switch (srb_toaddmod_p->rlc_Config->choice.explicitValue.present) { - case LTE_RLC_Config_PR_NOTHING: - break; - - default: - pdcp_config_req_asn1 ( - ctxt_pP, - pdcp_p, - SRB_FLAG_YES, - rlc_type, - action, - lc_id, - mch_id, - srb_id, - srb_sn, - 0, // drb_report - 0, // header compression - security_modeP, - kRRCenc_pP, - kRRCint_pP, - kUPenc_pP); - break; - } - - break; - - case LTE_SRB_ToAddMod__rlc_Config_PR_defaultValue: - pdcp_config_req_asn1 ( - ctxt_pP, - pdcp_p, - SRB_FLAG_YES, - rlc_type, - action, - lc_id, - mch_id, - srb_id, - srb_sn, - 0, // drb_report - 0, // header compression - security_modeP, - kRRCenc_pP, - kRRCint_pP, - kUPenc_pP); - // already the default values - break; - - default: - DevParam(srb_toaddmod_p->rlc_Config->present, ctxt_pP->module_id, ctxt_pP->rnti); - break; - } - } - } - } - - // reset the action - - if (drb2add_list_pP != NULL) { - for (cnt=0; cnt<drb2add_list_pP->list.count; cnt++) { - drb_toaddmod_p = drb2add_list_pP->list.array[cnt]; - drb_id = drb_toaddmod_p->drb_Identity;// + drb_id_offset; - - if (drb_toaddmod_p->logicalChannelIdentity) { - lc_id = *(drb_toaddmod_p->logicalChannelIdentity); - } else { - LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" logicalChannelIdentity is missing in DRB-ToAddMod information element!\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); - continue; - } - - if (lc_id == 1 || lc_id == 2) { - LOG_E(RLC, PROTOCOL_CTXT_FMT" logicalChannelIdentity = %ld is invalid in RRC message when adding DRB!\n", PROTOCOL_CTXT_ARGS(ctxt_pP), lc_id); - continue; - } - - DevCheck4(drb_id < LTE_maxDRB, drb_id, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); - key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); - h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); - - if (h_rc == HASH_TABLE_OK) { - action = CONFIG_ACTION_MODIFY; - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_MODIFY key 0x%"PRIx64"\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - key); - } else { - action = CONFIG_ACTION_ADD; - pdcp_p = calloc(1, sizeof(pdcp_t)); - h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); - - // save the first configured DRB-ID as the default DRB-ID - if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { - key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); - h_defaultDRB_rc = hashtable_insert(pdcp_coll_p, key_defaultDRB, pdcp_p); - } else { - h_defaultDRB_rc = HASH_TABLE_OK; // do not trigger any error handling if this is not a default DRB - } - - if (h_defaultDRB_rc != HASH_TABLE_OK) { - LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD default DRB key 0x%"PRIx64" FAILED\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - key_defaultDRB); - free(pdcp_p); - return TRUE; - } else if (h_rc != HASH_TABLE_OK) { - LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64" FAILED\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - key); - free(pdcp_p); - return TRUE; - } else { - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64"\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), - key); - } - } - - if (drb_toaddmod_p->pdcp_Config) { - if (drb_toaddmod_p->pdcp_Config->discardTimer) { - // set the value of the timer - } - - if (drb_toaddmod_p->pdcp_Config->rlc_AM) { - drb_report = drb_toaddmod_p->pdcp_Config->rlc_AM->statusReportRequired; - drb_sn = LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits; // default SN size - rlc_type = RLC_MODE_AM; - } - - if (drb_toaddmod_p->pdcp_Config->rlc_UM) { - drb_sn = drb_toaddmod_p->pdcp_Config->rlc_UM->pdcp_SN_Size; - rlc_type =RLC_MODE_UM; - } - - switch (drb_toaddmod_p->pdcp_Config->headerCompression.present) { - case LTE_PDCP_Config__headerCompression_PR_NOTHING: - case LTE_PDCP_Config__headerCompression_PR_notUsed: - header_compression_profile=0x0; - break; - - case LTE_PDCP_Config__headerCompression_PR_rohc: - - // parse the struc and get the rohc profile - if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0001) { - header_compression_profile=0x0001; - } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0002) { - header_compression_profile=0x0002; - } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0003) { - header_compression_profile=0x0003; - } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0004) { - header_compression_profile=0x0004; - } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0006) { - header_compression_profile=0x0006; - } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0101) { - header_compression_profile=0x0101; - } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0102) { - header_compression_profile=0x0102; - } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0103) { - header_compression_profile=0x0103; - } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0104) { - header_compression_profile=0x0104; - } else { - header_compression_profile=0x0; - LOG_W(PDCP,"unknown header compresion profile\n"); - } - - // set the applicable profile - break; - - default: - LOG_W(PDCP,PROTOCOL_PDCP_CTXT_FMT"[RB %ld] unknown drb_toaddmod->PDCP_Config->headerCompression->present \n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), drb_id); - break; - } - - pdcp_config_req_asn1 ( - ctxt_pP, - pdcp_p, - SRB_FLAG_NO, - rlc_type, - action, - lc_id, - mch_id, - drb_id, - drb_sn, - drb_report, - header_compression_profile, - security_modeP, - kRRCenc_pP, - kRRCint_pP, - kUPenc_pP); - } - } - } - - if (drb2release_list_pP != NULL) { - for (cnt=0; cnt<drb2release_list_pP->list.count; cnt++) { - pdrb_id_p = drb2release_list_pP->list.array[cnt]; - drb_id = *pdrb_id_p; - key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); - h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); - - if (h_rc != HASH_TABLE_OK) { - LOG_E(PDCP, PROTOCOL_CTXT_FMT" PDCP REMOVE FAILED drb_id %ld\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - drb_id); - continue; - } - - lc_id = pdcp_p->lcid; - action = CONFIG_ACTION_REMOVE; - pdcp_config_req_asn1 ( - ctxt_pP, - pdcp_p, - SRB_FLAG_NO, - rlc_type, - action, - lc_id, - mch_id, - drb_id, - 0, - 0, - 0, - security_modeP, - kRRCenc_pP, - kRRCint_pP, - kUPenc_pP); - h_rc = hashtable_remove(pdcp_coll_p, key); - - if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { - // default DRB being removed. nevertheless this shouldn't happen as removing default DRB is not allowed in standard - key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); - h_defaultDRB_rc = hashtable_get(pdcp_coll_p, key_defaultDRB, (void **)&pdcp_p); - - if (h_defaultDRB_rc == HASH_TABLE_OK) { - h_defaultDRB_rc = hashtable_remove(pdcp_coll_p, key_defaultDRB); - } else { - LOG_E(PDCP, PROTOCOL_CTXT_FMT" PDCP REMOVE FAILED default DRB\n", PROTOCOL_CTXT_ARGS(ctxt_pP)); - } - } else { - key_defaultDRB = HASH_TABLE_OK; // do not trigger any error handling if this is not a default DRB - } - } - } - - if (pmch_InfoList_r9_pP != NULL) { - for (i=0; i<pmch_InfoList_r9_pP->list.count; i++) { - mbms_SessionInfoList_r9_p = &(pmch_InfoList_r9_pP->list.array[i]->mbms_SessionInfoList_r9); - - for (j=0; j<mbms_SessionInfoList_r9_p->list.count; j++) { - MBMS_SessionInfo_p = mbms_SessionInfoList_r9_p->list.array[j]; - - if (MBMS_SessionInfo_p->sessionId_r9) - lc_id = MBMS_SessionInfo_p->sessionId_r9->buf[0]; - else - lc_id = MBMS_SessionInfo_p->logicalChannelIdentity_r9; - - mch_id = MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[2]; //serviceId is 3-octet string - // mch_id = j; - - // can set the mch_id = i - if (ctxt_pP->enb_flag) { - drb_id = (mch_id * LTE_maxSessionPerPMCH ) + lc_id ;//+ (LTE_maxDRB + 3)*MAX_MOBILES_PER_ENB; // 1 - - if (pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == TRUE) { - action = CONFIG_ACTION_MBMS_MODIFY; - } else { - action = CONFIG_ACTION_MBMS_ADD; - } - } else { - drb_id = (mch_id * LTE_maxSessionPerPMCH ) + lc_id; // + (LTE_maxDRB + 3); // 15 - - if (pdcp_mbms_array_ue[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == TRUE) { - action = CONFIG_ACTION_MBMS_MODIFY; - } else { - action = CONFIG_ACTION_MBMS_ADD; - } - } - - LOG_D(PDCP, "lc_id (%02ld) mch_id(%02x,%02x,%02x) drb_id(%ld) action(%d)\n", - lc_id, - MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[0], - MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[1], - MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[2], - drb_id, - action); - pdcp_config_req_asn1 ( - ctxt_pP, - NULL, // unused for MBMS - SRB_FLAG_NO, - RLC_MODE_NONE, - action, - lc_id, - mch_id, - drb_id, - 0, // unused for MBMS - 0, // unused for MBMS - 0, // unused for MBMS - 0, // unused for MBMS - NULL, // unused for MBMS - NULL, // unused for MBMS - NULL); // unused for MBMS - } - } - } - - return 0; -} - -//----------------------------------------------------------------------------- -boolean_t -pdcp_config_req_asn1 ( - const protocol_ctxt_t *const ctxt_pP, - pdcp_t *const pdcp_pP, - const srb_flag_t srb_flagP, - const rlc_mode_t rlc_modeP, - const config_action_t actionP, - const uint16_t lc_idP, - const uint16_t mch_idP, - const rb_id_t rb_idP, - const uint8_t rb_snP, - const uint8_t rb_reportP, - const uint16_t header_compression_profileP, - const uint8_t security_modeP, - uint8_t *const kRRCenc_pP, - uint8_t *const kRRCint_pP, - uint8_t *const kUPenc_pP) -//----------------------------------------------------------------------------- -{ - switch (actionP) { - case CONFIG_ACTION_ADD: - DevAssert(pdcp_pP != NULL); - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - pdcp_pP->is_ue = FALSE; - pdcp_add_UE(ctxt_pP); - - //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti; - // pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; - if( srb_flagP == SRB_FLAG_NO ) { - for(int i = 0; i<MAX_MOBILES_PER_ENB; i++) { - if(pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] == NOT_A_RNTI) { - break; - } - - pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; - } - - pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; - pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; - } - - //pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; - } else { - pdcp_pP->is_ue = TRUE; - pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; - } - - pdcp_pP->is_srb = (srb_flagP == SRB_FLAG_YES) ? TRUE : FALSE; - pdcp_pP->lcid = lc_idP; - pdcp_pP->rb_id = rb_idP; - pdcp_pP->header_compression_profile = header_compression_profileP; - pdcp_pP->status_report = rb_reportP; - - if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits) { - pdcp_pP->seq_num_size = 12; - pdcp_pP->maximum_pdcp_rx_sn = (1 << 12) - 1; - } else if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) { - pdcp_pP->seq_num_size = 7; - pdcp_pP->maximum_pdcp_rx_sn = (1 << 7) - 1; - } else { - pdcp_pP->seq_num_size = 5; - pdcp_pP->maximum_pdcp_rx_sn = (1 << 5) - 1; - } - - pdcp_pP->rlc_mode = rlc_modeP; - pdcp_pP->next_pdcp_tx_sn = 0; - pdcp_pP->next_pdcp_rx_sn = 0; - pdcp_pP->tx_hfn = 0; - pdcp_pP->rx_hfn = 0; - pdcp_pP->last_submitted_pdcp_rx_sn = 4095; - pdcp_pP->first_missing_pdu = -1; - LOG_I(PDCP, PROTOCOL_PDCP_CTXT_FMT" Action ADD LCID %d (%s id %d) " - "configured with SN size %d bits and RLC %s\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), - lc_idP, - (srb_flagP == SRB_FLAG_YES) ? "SRB" : "DRB", - rb_idP, - pdcp_pP->seq_num_size, - (rlc_modeP == RLC_MODE_AM ) ? "AM" : (rlc_modeP == RLC_MODE_TM) ? "TM" : "UM"); - - /* Setup security */ - if (security_modeP != 0xff) { - pdcp_config_set_security( - ctxt_pP, - pdcp_pP, - rb_idP, - lc_idP, - security_modeP, - kRRCenc_pP, - kRRCint_pP, - kUPenc_pP); - } - - break; - - case CONFIG_ACTION_MODIFY: - DevAssert(pdcp_pP != NULL); - pdcp_pP->header_compression_profile=header_compression_profileP; - pdcp_pP->status_report = rb_reportP; - pdcp_pP->rlc_mode = rlc_modeP; - - /* Setup security */ - if (security_modeP != 0xff) { - pdcp_config_set_security( - ctxt_pP, - pdcp_pP, - rb_idP, - lc_idP, - security_modeP, - kRRCenc_pP, - kRRCint_pP, - kUPenc_pP); - } - - if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) { - pdcp_pP->seq_num_size = 7; - } else if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits) { - pdcp_pP->seq_num_size = 12; - } else { - pdcp_pP->seq_num_size=5; - } - - LOG_I(PDCP,PROTOCOL_PDCP_CTXT_FMT" Action MODIFY LCID %d " - "RB id %d reconfigured with SN size %d and RLC %s \n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), - lc_idP, - rb_idP, - rb_snP, - (rlc_modeP == RLC_MODE_AM) ? "AM" : (rlc_modeP == RLC_MODE_TM) ? "TM" : "UM"); - break; - - case CONFIG_ACTION_REMOVE: - DevAssert(pdcp_pP != NULL); - //#warning "TODO pdcp_module_id_to_rnti" - //pdcp_module_id_to_rnti[ctxt_pP.module_id ][dst_id] = NOT_A_RNTI; - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_REMOVE LCID %d RBID %d configured\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), - lc_idP, - rb_idP); - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - // pdcp_remove_UE(ctxt_pP); - } - - /* Security keys */ - if (pdcp_pP->kUPenc != NULL) { - free(pdcp_pP->kUPenc); - } - - if (pdcp_pP->kRRCint != NULL) { - free(pdcp_pP->kRRCint); - } - - if (pdcp_pP->kRRCenc != NULL) { - free(pdcp_pP->kRRCenc); - } - - memset(pdcp_pP, 0, sizeof(pdcp_t)); - break; - - case CONFIG_ACTION_MBMS_ADD: - case CONFIG_ACTION_MBMS_MODIFY: - LOG_D(PDCP," %s service_id/mch index %d, session_id/lcid %d, rbid %d configured\n", - //PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), - actionP == CONFIG_ACTION_MBMS_ADD ? "CONFIG_ACTION_MBMS_ADD" : "CONFIG_ACTION_MBMS_MODIFY", - mch_idP, - lc_idP, - rb_idP); - - if (ctxt_pP->enb_flag == ENB_FLAG_YES) { - pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = TRUE ; - pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_idP][lc_idP].rb_id = rb_idP; - } else { - pdcp_mbms_array_ue[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = TRUE ; - pdcp_mbms_array_ue[ctxt_pP->module_id][mch_idP][lc_idP].rb_id = rb_idP; - } - - break; - - case CONFIG_ACTION_SET_SECURITY_MODE: - pdcp_config_set_security( - ctxt_pP, - pdcp_pP, - rb_idP, - lc_idP, - security_modeP, - kRRCenc_pP, - kRRCint_pP, - kUPenc_pP); - break; - - default: - DevParam(actionP, ctxt_pP->module_id, ctxt_pP->rnti); - break; - } - - return 0; -} - -//----------------------------------------------------------------------------- -void -pdcp_config_set_security( - const protocol_ctxt_t *const ctxt_pP, - pdcp_t *const pdcp_pP, - const rb_id_t rb_idP, - const uint16_t lc_idP, - const uint8_t security_modeP, - uint8_t *const kRRCenc, - uint8_t *const kRRCint, - uint8_t *const kUPenc) -//----------------------------------------------------------------------------- -{ - DevAssert(pdcp_pP != NULL); - - if ((security_modeP >= 0) && (security_modeP <= 0x77)) { - pdcp_pP->cipheringAlgorithm = security_modeP & 0x0f; - pdcp_pP->integrityProtAlgorithm = (security_modeP>>4) & 0xf; - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_SET_SECURITY_MODE: cipheringAlgorithm %d integrityProtAlgorithm %d\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), - pdcp_pP->cipheringAlgorithm, - pdcp_pP->integrityProtAlgorithm); - pdcp_pP->kRRCenc = kRRCenc; - pdcp_pP->kRRCint = kRRCint; - pdcp_pP->kUPenc = kUPenc; - /* Activate security */ - pdcp_pP->security_activated = 1; - - MSC_LOG_EVENT( - (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, - "0 Set security ciph %X integ %x UE %"PRIx16" ", - pdcp_pP->cipheringAlgorithm, - pdcp_pP->integrityProtAlgorithm, - ctxt_pP->rnti); - } - /*]SecurityModeFailure*/ - else if(security_modeP == -1){ - // in this way in pdcp_data_req_NB_IoT function you never call "pdcp_apply_security" - // and we never call pdcp_validate_security in NB_pdcp_data_indi - pdcp_pP->security_activated = 0; - pdcp_pP->cipheringAlgorithm = 0; - pdcp_pP->integrityProtAlgorithm = 0; - } - else { - MSC_LOG_EVENT( - (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, - "0 Set security failed UE %"PRIx16" ", - ctxt_pP->rnti); - LOG_E(PDCP,PROTOCOL_PDCP_CTXT_FMT" bad security mode %d", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), - security_modeP); - } -} - -//----------------------------------------------------------------------------- -// MP: seems to be no more used (old code) -void -rrc_pdcp_config_req ( - const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const uint32_t actionP, - const rb_id_t rb_idP, - const uint8_t security_modeP) -//----------------------------------------------------------------------------- -{ - pdcp_t *pdcp_p = NULL; - hash_key_t key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); - hashtable_rc_t h_rc; - h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); - - if (h_rc == HASH_TABLE_OK) { - /* - * Initialize sequence number state variables of relevant PDCP entity - */ - switch (actionP) { - case CONFIG_ACTION_ADD: - pdcp_p->is_srb = srb_flagP; - pdcp_p->rb_id = rb_idP; - - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - pdcp_p->is_ue = TRUE; - pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; - } else { - pdcp_p->is_ue = FALSE; - } - - pdcp_p->next_pdcp_tx_sn = 0; - pdcp_p->next_pdcp_rx_sn = 0; - pdcp_p->tx_hfn = 0; - pdcp_p->rx_hfn = 0; - /* SN of the last PDCP SDU delivered to upper layers */ - pdcp_p->last_submitted_pdcp_rx_sn = 4095; - - if (rb_idP < DTCH) { // SRB - pdcp_p->seq_num_size = 5; - } else { // DRB - pdcp_p->seq_num_size = 12; - } - - pdcp_p->first_missing_pdu = -1; - LOG_D(PDCP,PROTOCOL_PDCP_CTXT_FMT" Config request : Action ADD: radio bearer id %d (already added) configured\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), - rb_idP); - break; - - case CONFIG_ACTION_MODIFY: - break; - - case CONFIG_ACTION_REMOVE: - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_REMOVE: radio bearer id %d configured\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), - rb_idP); - pdcp_p->next_pdcp_tx_sn = 0; - pdcp_p->next_pdcp_rx_sn = 0; - pdcp_p->tx_hfn = 0; - pdcp_p->rx_hfn = 0; - pdcp_p->last_submitted_pdcp_rx_sn = 4095; - pdcp_p->seq_num_size = 0; - pdcp_p->first_missing_pdu = -1; - pdcp_p->security_activated = 0; - h_rc = hashtable_remove(pdcp_coll_p, key); - break; - - case CONFIG_ACTION_SET_SECURITY_MODE: - if ((security_modeP >= 0) && (security_modeP <= 0x77)) { - pdcp_p->cipheringAlgorithm= security_modeP & 0x0f; - pdcp_p->integrityProtAlgorithm = (security_modeP>>4) & 0xf; - LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_SET_SECURITY_MODE: cipheringAlgorithm %d integrityProtAlgorithm %d\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), - pdcp_p->cipheringAlgorithm, - pdcp_p->integrityProtAlgorithm ); - } else { - LOG_W(PDCP,PROTOCOL_PDCP_CTXT_FMT" bad security mode %d", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), security_modeP); - } - - break; - - default: - DevParam(actionP, ctxt_pP->module_id, ctxt_pP->rnti); - break; - } - } else { - switch (actionP) { - case CONFIG_ACTION_ADD: - pdcp_p = calloc(1, sizeof(pdcp_t)); - h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); - - if (h_rc != HASH_TABLE_OK) { - LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" PDCP ADD FAILED\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); - free(pdcp_p); - } else { - pdcp_p->is_srb = srb_flagP; - pdcp_p->rb_id = rb_idP; - - if (ctxt_pP->enb_flag == ENB_FLAG_NO) { - pdcp_p->is_ue = TRUE; - pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; - } else { - pdcp_p->is_ue = FALSE; - } - - pdcp_p->next_pdcp_tx_sn = 0; - pdcp_p->next_pdcp_rx_sn = 0; - pdcp_p->tx_hfn = 0; - pdcp_p->rx_hfn = 0; - /* SN of the last PDCP SDU delivered to upper layers */ - pdcp_p->last_submitted_pdcp_rx_sn = 4095; - - if (rb_idP < DTCH) { // SRB - pdcp_p->seq_num_size = 5; - } else { // DRB - pdcp_p->seq_num_size = 12; - } - - pdcp_p->first_missing_pdu = -1; - LOG_D(PDCP,PROTOCOL_PDCP_CTXT_FMT" Inserting PDCP instance in collection key 0x%"PRIx64"\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), key); - LOG_D(PDCP,PROTOCOL_PDCP_CTXT_FMT" Config request : Action ADD: radio bearer id %d configured\n", - PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), - rb_idP); - } - - break; - - case CONFIG_ACTION_REMOVE: - LOG_D(PDCP, PROTOCOL_CTXT_FMT" CONFIG_REQ PDCP CONFIG_ACTION_REMOVE PDCP instance not found\n", - PROTOCOL_CTXT_ARGS(ctxt_pP)); - break; - - default: - LOG_E(PDCP, PROTOCOL_CTXT_FMT" CONFIG_REQ PDCP NOT FOUND\n", - PROTOCOL_CTXT_ARGS(ctxt_pP)); - } - } -} - -pdcp_data_ind_func_t get_pdcp_data_ind_func() { - return pdcp_params.pdcp_data_ind_func; -} - -void pdcp_set_rlc_data_req_func(send_rlc_data_req_func_t send_rlc_data_req) { - pdcp_params.send_rlc_data_req_func = send_rlc_data_req; -} - -void pdcp_set_pdcp_data_ind_func(pdcp_data_ind_func_t pdcp_data_ind) { - pdcp_params.pdcp_data_ind_func = pdcp_data_ind; -} - -uint64_t pdcp_module_init( uint64_t pdcp_optmask ) { - /* temporary enforce netlink when UE_NAS_USE_TUN is set, - this is while switching from noS1 as build option - to noS1 as config option */ - if ( pdcp_optmask & UE_NAS_USE_TUN_BIT) { - pdcp_params.optmask = pdcp_params.optmask | PDCP_USE_NETLINK_BIT ; - } - - pdcp_params.optmask = pdcp_params.optmask | pdcp_optmask ; - LOG_I(PDCP, "pdcp init,%s %s\n", - ((LINK_ENB_PDCP_TO_GTPV1U)?"usegtp":""), - ((PDCP_USE_NETLINK)?"usenetlink":"")); - - if (PDCP_USE_NETLINK) { - nas_getparams(); - - if(UE_NAS_USE_TUN) { - int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 )?MAX_NUMBER_NETIF:1; - netlink_init_tun("ue",num_if); - LOG_I(PDCP, "UE pdcp will use tun interface\n"); - } else if(ENB_NAS_USE_TUN) { - netlink_init_tun("enb",1); - nas_config(1, 1, 1, "enb"); - LOG_I(PDCP, "ENB pdcp will use tun interface\n"); - } else { - LOG_I(PDCP, "pdcp will use kernel modules\n"); - netlink_init(); - } - } - return pdcp_params.optmask ; -} - - -//----------------------------------------------------------------------------- -void -pdcp_free ( - void *pdcp_pP -) -//----------------------------------------------------------------------------- -{ - pdcp_t *pdcp_p = (pdcp_t *)pdcp_pP; - - if (pdcp_p != NULL) { - if (pdcp_p->kUPenc != NULL) { - free(pdcp_p->kUPenc); - } - - if (pdcp_p->kRRCint != NULL) { - free(pdcp_p->kRRCint); - } - - if (pdcp_p->kRRCenc != NULL) { - free(pdcp_p->kRRCenc); - } - - memset(pdcp_pP, 0, sizeof(pdcp_t)); - free(pdcp_pP); - } -} - -//----------------------------------------------------------------------------- -void pdcp_module_cleanup (void) -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void pdcp_layer_init(void) -//----------------------------------------------------------------------------- -{ - module_id_t instance; - int i,j; - mbms_session_id_t session_id; - mbms_service_id_t service_id; - /* - * Initialize SDU list - */ - list_init(&pdcp_sdu_list, NULL); - pdcp_coll_p = hashtable_create ((LTE_maxDRB + 2) * NUMBER_OF_UE_MAX, NULL, pdcp_free); - AssertFatal(pdcp_coll_p != NULL, "UNRECOVERABLE error, PDCP hashtable_create failed"); - - for (instance = 0; instance < MAX_MOBILES_PER_ENB; instance++) { - for (service_id = 0; service_id < LTE_maxServiceCount; service_id++) { - for (session_id = 0; session_id < LTE_maxSessionPerPMCH; session_id++) { - memset(&pdcp_mbms_array_ue[instance][service_id][session_id], 0, sizeof(pdcp_mbms_t)); - } - } - - pdcp_eNB_UE_instance_to_rnti[instance] = NOT_A_RNTI; - } - - pdcp_eNB_UE_instance_to_rnti_index = 0; - - for (instance = 0; instance < NUMBER_OF_eNB_MAX; instance++) { - for (service_id = 0; service_id < LTE_maxServiceCount; service_id++) { - for (session_id = 0; session_id < LTE_maxSessionPerPMCH; session_id++) { - memset(&pdcp_mbms_array_eNB[instance][service_id][session_id], 0, sizeof(pdcp_mbms_t)); - } - } - } - -#ifdef MBMS_MULTICAST_OUT - mbms_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - - if (mbms_socket == -1) - LOG_W(PDCP, "Could not create RAW socket, MBMS packets will not be put to the network\n"); - -#endif - LOG_I(PDCP, "PDCP layer has been initialized\n"); - pdcp_output_sdu_bytes_to_write=0; - pdcp_output_header_bytes_to_write=0; - pdcp_input_sdu_remaining_size_to_read=0; - memset(pdcp_enb, 0, sizeof(pdcp_enb_t)); - memset(Pdcp_stats_tx_window_ms, 0, sizeof(Pdcp_stats_tx_window_ms)); - memset(Pdcp_stats_rx_window_ms, 0, sizeof(Pdcp_stats_rx_window_ms)); - - for (i = 0; i < MAX_eNB; i++) { - for (j = 0; j < MAX_MOBILES_PER_ENB; j++) { - Pdcp_stats_tx_window_ms[i][j]=100; - Pdcp_stats_rx_window_ms[i][j]=100; - } - } - - memset(Pdcp_stats_tx, 0, sizeof(Pdcp_stats_tx)); - memset(Pdcp_stats_tx_w, 0, sizeof(Pdcp_stats_tx_w)); - memset(Pdcp_stats_tx_tmp_w, 0, sizeof(Pdcp_stats_tx_tmp_w)); - memset(Pdcp_stats_tx_bytes, 0, sizeof(Pdcp_stats_tx_bytes)); - memset(Pdcp_stats_tx_bytes_w, 0, sizeof(Pdcp_stats_tx_bytes_w)); - memset(Pdcp_stats_tx_bytes_tmp_w, 0, sizeof(Pdcp_stats_tx_bytes_tmp_w)); - memset(Pdcp_stats_tx_sn, 0, sizeof(Pdcp_stats_tx_sn)); - memset(Pdcp_stats_tx_throughput_w, 0, sizeof(Pdcp_stats_tx_throughput_w)); - memset(Pdcp_stats_tx_aiat, 0, sizeof(Pdcp_stats_tx_aiat)); - memset(Pdcp_stats_tx_iat, 0, sizeof(Pdcp_stats_tx_iat)); - memset(Pdcp_stats_rx, 0, sizeof(Pdcp_stats_rx)); - memset(Pdcp_stats_rx_w, 0, sizeof(Pdcp_stats_rx_w)); - memset(Pdcp_stats_rx_tmp_w, 0, sizeof(Pdcp_stats_rx_tmp_w)); - memset(Pdcp_stats_rx_bytes, 0, sizeof(Pdcp_stats_rx_bytes)); - memset(Pdcp_stats_rx_bytes_w, 0, sizeof(Pdcp_stats_rx_bytes_w)); - memset(Pdcp_stats_rx_bytes_tmp_w, 0, sizeof(Pdcp_stats_rx_bytes_tmp_w)); - memset(Pdcp_stats_rx_sn, 0, sizeof(Pdcp_stats_rx_sn)); - memset(Pdcp_stats_rx_goodput_w, 0, sizeof(Pdcp_stats_rx_goodput_w)); - memset(Pdcp_stats_rx_aiat, 0, sizeof(Pdcp_stats_rx_aiat)); - memset(Pdcp_stats_rx_iat, 0, sizeof(Pdcp_stats_rx_iat)); - memset(Pdcp_stats_rx_outoforder, 0, sizeof(Pdcp_stats_rx_outoforder)); -} - - -//----------------------------------------------------------------------------- -void pdcp_layer_cleanup (void) -//----------------------------------------------------------------------------- -{ - list_free (&pdcp_sdu_list); - hashtable_destroy(&pdcp_coll_p); -#ifdef MBMS_MULTICAST_OUT - - if(mbms_socket != -1) { - close(mbms_socket); - mbms_socket = -1; - } - -#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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file pdcp.c + * \brief pdcp interface with RLC + * \author Navid Nikaein and Lionel GAUTHIER + * \date 2009-2012 + * \email navid.nikaein@eurecom.fr + * \version 1.0 + */ + +#define PDCP_C + +#define MBMS_MULTICAST_OUT + +#include "assertions.h" +#include "hashtable.h" +#include "pdcp.h" +#include "pdcp_util.h" +#include "pdcp_sequence_manager.h" +#include "LAYER2/RLC/rlc.h" +#include "LAYER2/MAC/mac_extern.h" +#include "RRC/LTE/rrc_proto.h" +#include "pdcp_primitives.h" +#include "OCG.h" +#include "OCG_extern.h" +#include "otg_rx.h" +#include "common/utils/LOG/log.h" +#include <inttypes.h> +#include "platform_constants.h" +#include "nfapi/oai_integration/vendor_ext.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "msc.h" +#include "common/ngran_types.h" +#include "targets/COMMON/openairinterface5g_limits.h" +#include "targets/RT/USER/lte-softmodem.h" +#include "SIMULATION/ETH_TRANSPORT/proto.h" +#include "UTIL/OSA/osa_defs.h" +#include "openair2/RRC/NAS/nas_config.h" +# include "intertask_interface.h" +#include "enb_paramdef.h" + +# include "gtpv1u_eNB_task.h" +# include "gtpv1u.h" + +#include "ENB_APP/enb_config.h" + + + +extern int otg_enabled; +extern uint8_t nfapi_mode; +#include "common/ran_context.h" +extern RAN_CONTEXT_t RC; +hash_table_t *pdcp_coll_p = NULL; + +#ifdef MBMS_MULTICAST_OUT + #include <sys/types.h> + #include <sys/socket.h> + #include <netinet/in.h> + #include <netinet/ip.h> + #include <netinet/udp.h> + #include <unistd.h> + + static int mbms_socket = -1; +#endif + +ccparams_NB_IoT_t NBconfig ; +memset((void *)&NBconfig,0,sizeof(ccparams_NB_IoT_t)); +if (NBconfig.NB_IoT_configured > 0) +{ +#include "openair2/RRC/LITE/proto_NB_IoT.h" +#undef maxDRB +#define maxDRB maxDRB_NB_r13 +#endif +} + +/* pdcp module parameters and related functions*/ +static pdcp_params_t pdcp_params= {0,NULL}; + +uint64_t get_pdcp_optmask(void) { + return pdcp_params.optmask; +} +//----------------------------------------------------------------------------- +/* + * If PDCP_UNIT_TEST is set here then data flow between PDCP and RLC is broken + * and PDCP has no longer anything to do with RLC. In this case, after it's handed + * an SDU it appends PDCP header and returns (by filling in incoming pointer parameters) + * this mem_block_t to be dissected for testing purposes. For further details see test + * code at targets/TEST/PDCP/test_pdcp.c:test_pdcp_data_req() + */ +boolean_t pdcp_data_req( + protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + const confirm_t confirmP, + const sdu_size_t sdu_buffer_sizeP, + unsigned char *const sdu_buffer_pP, + const pdcp_transmission_mode_t modeP, + const uint32_t *const sourceL2Id, + const uint32_t *const destinationL2Id +) +//----------------------------------------------------------------------------- +{ + pdcp_t *pdcp_p = NULL; + uint8_t i = 0; + uint8_t pdcp_header_len = 0; + uint8_t pdcp_tailer_len = 0; + uint16_t pdcp_pdu_size = 0; + uint16_t current_sn = 0; + mem_block_t *pdcp_pdu_p = NULL; + rlc_op_status_t rlc_status; + boolean_t ret = TRUE; + hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_rc; + uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 : 0; + uint16_t pdcp_uid=0; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_IN); + CHECK_CTXT_ARGS(ctxt_pP); +#if T_TRACER + + if (ctxt_pP->enb_flag != ENB_FLAG_NO) + T(T_ENB_PDCP_DL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_buffer_sizeP)); + +#endif + + if (sdu_buffer_sizeP == 0) { + LOG_W(PDCP, "Handed SDU is of size 0! Ignoring...\n"); + return FALSE; + } + + /* + * XXX MAX_IP_PACKET_SIZE is 4096, shouldn't this be MAX SDU size, which is 8188 bytes? + */ + AssertFatal(sdu_buffer_sizeP<= MAX_IP_PACKET_SIZE,"Requested SDU size (%d) is bigger than that can be handled by PDCP (%u)!\n", + sdu_buffer_sizeP, MAX_IP_PACKET_SIZE); + + if (modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT) { + AssertError (rb_idP < NB_RB_MBMS_MAX, return FALSE, "RB id is too high (%u/%d) %u %u!\n", rb_idP, NB_RB_MBMS_MAX, ctxt_pP->module_id, ctxt_pP->rnti); + } else { + if (srb_flagP) { + AssertError (rb_idP < 3, return FALSE, "RB id is too high (%u/%d) %u %u!\n", rb_idP, 3, ctxt_pP->module_id, ctxt_pP->rnti); + } else { + AssertError (rb_idP < LTE_maxDRB, return FALSE, "RB id is too high (%u/%d) %u %u!\n", rb_idP, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); + } + } + + key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); + h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); + + if (h_rc != HASH_TABLE_OK) { + if (modeP != PDCP_TRANSMISSION_MODE_TRANSPARENT) { + LOG_W(PDCP, PROTOCOL_CTXT_FMT" Instance is not configured for rb_id %d Ignoring SDU...\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + rb_idP); + ctxt_pP->configured=FALSE; + return FALSE; + } + } else { + // instance for a given RB is configured + ctxt_pP->configured=TRUE; + } + + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); + } else { + start_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); + } + + // PDCP transparent mode for MBMS traffic + + if (modeP == PDCP_TRANSMISSION_MODE_TRANSPARENT) { + LOG_D(PDCP, " [TM] Asking for a new mem_block of size %d\n",sdu_buffer_sizeP); + pdcp_pdu_p = get_free_mem_block(sdu_buffer_sizeP, __func__); + + if (pdcp_pdu_p != NULL) { + memcpy(&pdcp_pdu_p->data[0], sdu_buffer_pP, sdu_buffer_sizeP); + + if( LOG_DEBUGFLAG(DEBUG_PDCP) ) { + rlc_util_print_hex_octets(PDCP, + (unsigned char *)&pdcp_pdu_p->data[0], + sdu_buffer_sizeP); + LOG_UI(PDCP, "Before rlc_data_req 1, srb_flagP: %d, rb_idP: %d \n", srb_flagP, rb_idP); + } + + rlc_status = pdcp_params.send_rlc_data_req_func(ctxt_pP, srb_flagP, NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)?MBMS_FLAG_NO:MBMS_FLAG_YES, rb_idP, muiP, + confirmP, sdu_buffer_sizeP, pdcp_pdu_p,NULL,NULL); + } else { + rlc_status = RLC_OP_STATUS_OUT_OF_RESSOURCES; + LOG_E(PDCP,PROTOCOL_CTXT_FMT" PDCP_DATA_REQ SDU DROPPED, OUT OF MEMORY \n", + PROTOCOL_CTXT_ARGS(ctxt_pP)); + } + } else { + // calculate the pdcp header and trailer size + if (srb_flagP) { + pdcp_header_len = PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE; + pdcp_tailer_len = PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE; + } else { + pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; + pdcp_tailer_len = 0; + } + + pdcp_pdu_size = sdu_buffer_sizeP + pdcp_header_len + pdcp_tailer_len; + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT"Data request notification pdu size %d (header%d, trailer%d)\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), + pdcp_pdu_size, + pdcp_header_len, + pdcp_tailer_len); + /* + * Allocate a new block for the new PDU (i.e. PDU header and SDU payload) + */ + pdcp_pdu_p = get_free_mem_block(pdcp_pdu_size, __func__); + + if (pdcp_pdu_p != NULL) { + /* + * Create a Data PDU with header and append data + * + * Place User Plane PDCP Data PDU header first + */ + if (srb_flagP) { // this Control plane PDCP Data PDU + pdcp_control_plane_data_pdu_header pdu_header; + pdu_header.sn = pdcp_get_next_tx_seq_number(pdcp_p); + current_sn = pdu_header.sn; + memset(&pdu_header.mac_i[0],0,PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE); + memset(&pdcp_pdu_p->data[sdu_buffer_sizeP + pdcp_header_len],0,PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE); + + if (pdcp_serialize_control_plane_data_pdu_with_SRB_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == FALSE) { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); + + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); + return FALSE; + } + } else { + pdcp_user_plane_data_pdu_header_with_long_sn pdu_header; + pdu_header.dc = (modeP == PDCP_TRANSMISSION_MODE_DATA) ? PDCP_DATA_PDU_BIT_SET : PDCP_CONTROL_PDU_BIT_SET; + pdu_header.sn = pdcp_get_next_tx_seq_number(pdcp_p); + current_sn = pdu_header.sn ; + + if (pdcp_serialize_user_plane_data_pdu_with_long_sn_buffer((unsigned char *)pdcp_pdu_p->data, &pdu_header) == FALSE) { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Cannot fill PDU buffer with relevant header fields!\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p)); + + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); + return FALSE; + } + } + + /* + * Validate incoming sequence number, there might be a problem with PDCP initialization + */ + if (current_sn > pdcp_calculate_max_seq_num_for_given_size(pdcp_p->seq_num_size)) { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" Generated sequence number (%"PRIu16") is greater than a sequence number could ever be!\n"\ + "There must be a problem with PDCP initialization, ignoring this PDU...\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), + current_sn); + free_mem_block(pdcp_pdu_p, __func__); + + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); + return FALSE; + } + + LOG_D(PDCP, "Sequence number %d is assigned to current PDU\n", current_sn); + /* Then append data... */ + memcpy(&pdcp_pdu_p->data[pdcp_header_len], sdu_buffer_pP, sdu_buffer_sizeP); + + //For control plane data that are not integrity protected, + // the MAC-I field is still present and should be padded with padding bits set to 0. + // NOTE: user-plane data are never integrity protected + for (i=0; i<pdcp_tailer_len; i++) { + pdcp_pdu_p->data[pdcp_header_len + sdu_buffer_sizeP + i] = 0x00;// pdu_header.mac_i[i]; + } + + if ((pdcp_p->security_activated != 0) && + (((pdcp_p->cipheringAlgorithm) != 0) || + ((pdcp_p->integrityProtAlgorithm) != 0))) { + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].apply_security); + } else { + start_meas(&UE_pdcp_stats[ctxt_pP->module_id].apply_security); + } + + pdcp_apply_security(ctxt_pP, + pdcp_p, + srb_flagP, + rb_idP % LTE_maxDRB, + pdcp_header_len, + current_sn, + pdcp_pdu_p->data, + sdu_buffer_sizeP); + + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].apply_security); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].apply_security); + } + } + + /* Print octets of outgoing data in hexadecimal form */ + LOG_D(PDCP, "Following content with size %d will be sent over RLC (PDCP PDU header is the first two bytes)\n", + pdcp_pdu_size); + //util_print_hex_octets(PDCP, (unsigned char*)pdcp_pdu_p->data, pdcp_pdu_size); + //util_flush_hex_octets(PDCP, (unsigned char*)pdcp_pdu->data, pdcp_pdu_size); + } else { + LOG_E(PDCP, "Cannot create a mem_block for a PDU!\n"); + + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); + } + + LOG_E(PDCP, "[FRAME %5u][%s][PDCP][MOD %u][RB %u] PDCP_DATA_REQ SDU DROPPED, OUT OF MEMORY \n", + ctxt_pP->frame, + (ctxt_pP->enb_flag) ? "eNB" : "UE", + ctxt_pP->module_id, + rb_idP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); + return FALSE; + } + + /* + * Ask sublayer to transmit data and check return value + * to see if RLC succeeded + */ + LOG_DUMPMSG(PDCP,DEBUG_PDCP,(char *)pdcp_pdu_p->data,pdcp_pdu_size, + "[MSG] PDCP DL %s PDU on rb_id %d\n",(srb_flagP)? "CONTROL" : "DATA", rb_idP); + + if ((pdcp_pdu_p!=NULL) && (srb_flagP == 0) && (ctxt_pP->enb_flag == 1)) { + LOG_D(PDCP, "pdcp data req on drb %d, size %d, rnti %x, node_type %d \n", + rb_idP, pdcp_pdu_size, ctxt_pP->rnti, RC.rrc[ctxt_pP->module_id]->node_type); + + if (ctxt_pP->enb_flag == ENB_FLAG_YES && NODE_IS_DU(RC.rrc[ctxt_pP->module_id]->node_type)) { + LOG_E(PDCP, "Can't be DU, bad node type %d \n", RC.rrc[ctxt_pP->module_id]->node_type); + ret=FALSE; + } else { + rlc_status = pdcp_params.send_rlc_data_req_func(ctxt_pP, srb_flagP, MBMS_FLAG_NO, rb_idP, muiP, + confirmP, pdcp_pdu_size, pdcp_pdu_p,sourceL2Id, + destinationL2Id); + + switch (rlc_status) { + case RLC_OP_STATUS_OK: + LOG_D(PDCP, "Data sending request over RLC succeeded!\n"); + ret=TRUE; + break; + + case RLC_OP_STATUS_BAD_PARAMETER: + LOG_W(PDCP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); + ret= FALSE; + break; + + case RLC_OP_STATUS_INTERNAL_ERROR: + LOG_W(PDCP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); + ret= FALSE; + break; + + case RLC_OP_STATUS_OUT_OF_RESSOURCES: + LOG_W(PDCP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); + ret= FALSE; + break; + + default: + LOG_W(PDCP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); + ret= FALSE; + break; + } // switch case + } /* end if node_type is not DU */ + } else { // SRB + if (ctxt_pP->enb_flag == ENB_FLAG_YES && NODE_IS_CU(RC.rrc[ctxt_pP->module_id]->node_type)) { + // DL transfer + MessageDef *message_p; + // Note: the acyual task must be TASK_PDCP_ENB, but this task is not created + message_p = itti_alloc_new_message (TASK_PDCP_ENB, F1AP_DL_RRC_MESSAGE); + F1AP_DL_RRC_MESSAGE (message_p).rrc_container = &pdcp_pdu_p->data[0] ; + F1AP_DL_RRC_MESSAGE (message_p).rrc_container_length = pdcp_pdu_size; + F1AP_DL_RRC_MESSAGE (message_p).gNB_CU_ue_id = 0; + F1AP_DL_RRC_MESSAGE (message_p).gNB_DU_ue_id = 0; + F1AP_DL_RRC_MESSAGE (message_p).old_gNB_DU_ue_id = 0xFFFFFFFF; // unknown + F1AP_DL_RRC_MESSAGE (message_p).rnti = ctxt_pP->rnti; + F1AP_DL_RRC_MESSAGE (message_p).srb_id = rb_idP; + F1AP_DL_RRC_MESSAGE (message_p).execute_duplication = 1; + F1AP_DL_RRC_MESSAGE (message_p).RAT_frequency_priority_information.en_dc = 0; + itti_send_msg_to_task (TASK_CU_F1, ctxt_pP->module_id, message_p); + //CU_send_DL_RRC_MESSAGE_TRANSFER(ctxt_pP->module_id, message_p); + LOG_I(PDCP, "Send F1AP_DL_RRC_MESSAGE with ITTI\n"); + ret=TRUE; + } else { + rlc_status = rlc_data_req(ctxt_pP + , srb_flagP + , MBMS_FLAG_NO + , rb_idP + , muiP + , confirmP + , pdcp_pdu_size + , pdcp_pdu_p + ,NULL + ,NULL + ); + + switch (rlc_status) { + case RLC_OP_STATUS_OK: + LOG_D(PDCP, "Data sending request over RLC succeeded!\n"); + ret=TRUE; + break; + + case RLC_OP_STATUS_BAD_PARAMETER: + LOG_W(PDCP, "Data sending request over RLC failed with 'Bad Parameter' reason!\n"); + ret= FALSE; + break; + + case RLC_OP_STATUS_INTERNAL_ERROR: + LOG_W(PDCP, "Data sending request over RLC failed with 'Internal Error' reason!\n"); + ret= FALSE; + break; + + case RLC_OP_STATUS_OUT_OF_RESSOURCES: + LOG_W(PDCP, "Data sending request over RLC failed with 'Out of Resources' reason!\n"); + ret= FALSE; + break; + + default: + LOG_W(PDCP, "RLC returned an unknown status code after PDCP placed the order to send some data (Status Code:%d)\n", rlc_status); + ret= FALSE; + break; + } // switch case + } + } + } + + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_req); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_req); + } + + /* + * Control arrives here only if rlc_data_req() returns RLC_OP_STATUS_OK + * so we return TRUE afterwards + */ + + for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { + if (pdcp_enb[ctxt_pP->module_id].rnti[pdcp_uid] == ctxt_pP->rnti ) + break; + } + + //LOG_I(PDCP,"ueid %d lcid %d tx seq num %d\n", pdcp_uid, rb_idP+rb_offset, current_sn); + Pdcp_stats_tx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_tx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; + Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=sdu_buffer_sizeP; + Pdcp_stats_tx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=current_sn; + Pdcp_stats_tx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_tx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_OUT); + return ret; +} + + +//----------------------------------------------------------------------------- +boolean_t +pdcp_data_ind( + const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_idP, + const sdu_size_t sdu_buffer_sizeP, + mem_block_t *const sdu_buffer_pP +) +//----------------------------------------------------------------------------- +{ + pdcp_t *pdcp_p = NULL; + list_t *sdu_list_p = NULL; + mem_block_t *new_sdu_p = NULL; + uint8_t pdcp_header_len = 0; + uint8_t pdcp_tailer_len = 0; + pdcp_sn_t sequence_number = 0; + volatile sdu_size_t payload_offset = 0; + rb_id_t rb_id = rb_idP; + boolean_t packet_forwarded = FALSE; + hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_rc; + uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 :0; + uint16_t pdcp_uid=0; + MessageDef *message_p = NULL; + uint8_t *gtpu_buffer_p = NULL; + uint32_t rx_hfn_for_count; + int pdcp_sn_for_count; + int security_ok; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_IN); + LOG_DUMPMSG(PDCP,DEBUG_PDCP,(char *)sdu_buffer_pP->data,sdu_buffer_sizeP, + "[MSG] PDCP UL %s PDU on rb_id %d\n", (srb_flagP)? "CONTROL" : "DATA", rb_idP); +#if T_TRACER + + if (ctxt_pP->enb_flag != ENB_FLAG_NO) + T(T_ENB_PDCP_UL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_buffer_sizeP)); + +#endif + + if (MBMS_flagP) { + AssertError (rb_idP < NB_RB_MBMS_MAX, return FALSE, + "RB id is too high (%u/%d) %u rnti %x!\n", + rb_idP, + NB_RB_MBMS_MAX, + ctxt_pP->module_id, + ctxt_pP->rnti); + + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + LOG_D(PDCP, "e-MBMS Data indication notification for PDCP entity from eNB %u to UE %x " + "and radio bearer ID %d rlc sdu size %d ctxt_pP->enb_flag %d\n", + ctxt_pP->module_id, + ctxt_pP->rnti, + rb_idP, + sdu_buffer_sizeP, + ctxt_pP->enb_flag); + } else { + LOG_D(PDCP, "Data indication notification for PDCP entity from UE %x to eNB %u " + "and radio bearer ID %d rlc sdu size %d ctxt_pP->enb_flag %d\n", + ctxt_pP->rnti, + ctxt_pP->module_id, + rb_idP, + sdu_buffer_sizeP, + ctxt_pP->enb_flag); + } + } else { + rb_id = rb_idP % LTE_maxDRB; + AssertError (rb_id < LTE_maxDRB, return FALSE, "RB id is too high (%u/%d) %u UE %x!\n", + rb_id, + LTE_maxDRB, + ctxt_pP->module_id, + ctxt_pP->rnti); + AssertError (rb_id > 0, return FALSE, "RB id is too low (%u/%d) %u UE %x!\n", + rb_id, + LTE_maxDRB, + ctxt_pP->module_id, + ctxt_pP->rnti); + key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_id, srb_flagP); + + h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); + + if (h_rc != HASH_TABLE_OK) { + LOG_W(PDCP, + PROTOCOL_CTXT_FMT"Could not get PDCP instance key 0x%"PRIx64"\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + key); + free_mem_block(sdu_buffer_pP, __func__); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); + return FALSE; + } + } + + sdu_list_p = &pdcp_sdu_list; + + if (sdu_buffer_sizeP == 0) { + LOG_W(PDCP, "SDU buffer size is zero! Ignoring this chunk!\n"); + return FALSE; + } + + if (ctxt_pP->enb_flag) { + start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); + } else { + start_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); + } + + /* + * Parse the PDU placed at the beginning of SDU to check + * if incoming SN is in line with RX window + */ + + if (MBMS_flagP == 0 ) { + if (srb_flagP) { //SRB1/2 + pdcp_header_len = PDCP_CONTROL_PLANE_DATA_PDU_SN_SIZE; + pdcp_tailer_len = PDCP_CONTROL_PLANE_DATA_PDU_MAC_I_SIZE; + sequence_number = pdcp_get_sequence_number_of_pdu_with_SRB_sn((unsigned char *)sdu_buffer_pP->data); + } else { // DRB + pdcp_tailer_len = 0; + + if (pdcp_p->seq_num_size == 7) { + pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_SHORT_SN_HEADER_SIZE; + sequence_number = pdcp_get_sequence_number_of_pdu_with_short_sn((unsigned char *)sdu_buffer_pP->data); + } else if (pdcp_p->seq_num_size == 12) { + pdcp_header_len = PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; + sequence_number = pdcp_get_sequence_number_of_pdu_with_long_sn((unsigned char *)sdu_buffer_pP->data); + } else { + //sequence_number = 4095; + LOG_E(PDCP, + PROTOCOL_PDCP_CTXT_FMT"wrong sequence number (%d) for this pdcp entity \n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + pdcp_p->seq_num_size); + exit(1); + } + + //uint8_t dc = pdcp_get_dc_filed((unsigned char*)sdu_buffer_pP->data); + } + + /* + * Check if incoming SDU is long enough to carry a PDU header + */ + if (sdu_buffer_sizeP < pdcp_header_len + pdcp_tailer_len ) { + LOG_W(PDCP, + PROTOCOL_PDCP_CTXT_FMT"Incoming (from RLC) SDU is short of size (size:%d)! Ignoring...\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + sdu_buffer_sizeP); + free_mem_block(sdu_buffer_pP, __func__); + + if (ctxt_pP->enb_flag) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); + return FALSE; + } + +#if 0 + + /* Removed by Cedric */ + if (pdcp_is_rx_seq_number_valid(sequence_number, pdcp_p, srb_flagP) == TRUE) { + LOG_T(PDCP, "Incoming PDU has a sequence number (%d) in accordance with RX window\n", sequence_number); + /* if (dc == PDCP_DATA_PDU ) + LOG_D(PDCP, "Passing piggybacked SDU to NAS driver...\n"); + else + LOG_D(PDCP, "Passing piggybacked SDU to RRC ...\n");*/ + } else { + Pdcp_stats_rx_outoforder[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + LOG_E(PDCP, + PROTOCOL_PDCP_CTXT_FMT"Incoming PDU has an unexpected sequence number (%d), RX window synchronisation have probably been lost!\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + sequence_number); + /* + * XXX Till we implement in-sequence delivery and duplicate discarding + * mechanism all out-of-order packets will be delivered to RRC/IP + */ + LOG_W(PDCP, "Ignoring PDU...\n"); + free_mem_block(sdu_buffer_pP, __func__); + return FALSE; + } + +#endif + + // SRB1/2: control-plane data + if (srb_flagP) { + /* process as described in 36.323 5.1.2.2 */ + if (sequence_number < pdcp_p->next_pdcp_rx_sn) { + rx_hfn_for_count = pdcp_p->rx_hfn + 1; + pdcp_sn_for_count = sequence_number; + } else { + rx_hfn_for_count = pdcp_p->rx_hfn; + pdcp_sn_for_count = sequence_number; + } + + if (pdcp_p->security_activated == 1) { + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); + } else { + start_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); + } + + security_ok = pdcp_validate_security(ctxt_pP, + pdcp_p, + srb_flagP, + rb_idP, + pdcp_header_len, + rx_hfn_for_count, + pdcp_sn_for_count, + sdu_buffer_pP->data, + sdu_buffer_sizeP - pdcp_tailer_len) == 0; + + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); + } + } else { + security_ok = 1; + } + + if (security_ok == 0) { + LOG_W(PDCP, + PROTOCOL_PDCP_CTXT_FMT"security not validated for incoming PDCP SRB PDU\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); + LOG_W(PDCP, "Ignoring PDU...\n"); + free_mem_block(sdu_buffer_pP, __func__); + /* TODO: indicate integrity verification failure to upper layer */ + return FALSE; + } + + if (sequence_number < pdcp_p->next_pdcp_rx_sn) + pdcp_p->rx_hfn++; + + pdcp_p->next_pdcp_rx_sn = sequence_number + 1; + + if (pdcp_p->next_pdcp_rx_sn > pdcp_p->maximum_pdcp_rx_sn) { + pdcp_p->next_pdcp_rx_sn = 0; + pdcp_p->rx_hfn++; + } + + //rrc_lite_data_ind(module_id, //Modified MW - L2 Interface + MSC_LOG_TX_MESSAGE( + (ctxt_pP->enb_flag == ENB_FLAG_NO)? MSC_PDCP_UE:MSC_PDCP_ENB, + (ctxt_pP->enb_flag == ENB_FLAG_NO)? MSC_RRC_UE:MSC_RRC_ENB, + NULL,0, + PROTOCOL_PDCP_CTXT_FMT" DATA-IND len %u", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + sdu_buffer_sizeP - pdcp_header_len - pdcp_tailer_len); + + rrc_data_ind(ctxt_pP, + rb_id, + sdu_buffer_sizeP - pdcp_header_len - pdcp_tailer_len, + (uint8_t *)&sdu_buffer_pP->data[pdcp_header_len]); + free_mem_block(sdu_buffer_pP, __func__); + + // free_mem_block(new_sdu, __func__); + if (ctxt_pP->enb_flag) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); + return TRUE; + } /* if (srb_flagP) */ + + /* + * DRBs + */ + payload_offset=pdcp_header_len;// PDCP_USER_PLANE_DATA_PDU_LONG_SN_HEADER_SIZE; + + switch (pdcp_p->rlc_mode) { + case RLC_MODE_AM: { + /* process as described in 36.323 5.1.2.1.2 */ + int reordering_window; + + if (pdcp_p->seq_num_size == 7) + reordering_window = REORDERING_WINDOW_SN_7BIT; + else + reordering_window = REORDERING_WINDOW_SN_12BIT; + + if (sequence_number - pdcp_p->last_submitted_pdcp_rx_sn > reordering_window || + (pdcp_p->last_submitted_pdcp_rx_sn - sequence_number >= 0 && + pdcp_p->last_submitted_pdcp_rx_sn - sequence_number < reordering_window)) { + /* TODO: specs say to decipher and do header decompression */ + LOG_W(PDCP, + PROTOCOL_PDCP_CTXT_FMT"discard PDU, out of\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); + LOG_W(PDCP, "Ignoring PDU...\n"); + free_mem_block(sdu_buffer_pP, __func__); + /* TODO: indicate integrity verification failure to upper layer */ + return FALSE; + } else if (pdcp_p->next_pdcp_rx_sn - sequence_number > reordering_window) { + pdcp_p->rx_hfn++; + rx_hfn_for_count = pdcp_p->rx_hfn; + pdcp_sn_for_count = sequence_number; + pdcp_p->next_pdcp_rx_sn = sequence_number + 1; + } else if (sequence_number - pdcp_p->next_pdcp_rx_sn >= reordering_window) { + rx_hfn_for_count = pdcp_p->rx_hfn - 1; + pdcp_sn_for_count = sequence_number; + } else if (sequence_number >= pdcp_p->next_pdcp_rx_sn) { + rx_hfn_for_count = pdcp_p->rx_hfn; + pdcp_sn_for_count = sequence_number; + pdcp_p->next_pdcp_rx_sn = sequence_number + 1; + + if (pdcp_p->next_pdcp_rx_sn > pdcp_p->maximum_pdcp_rx_sn) { + pdcp_p->next_pdcp_rx_sn = 0; + pdcp_p->rx_hfn++; + } + } else { /* sequence_number < pdcp_p->next_pdcp_rx_sn */ + rx_hfn_for_count = pdcp_p->rx_hfn; + pdcp_sn_for_count = sequence_number; + } + + if (pdcp_p->security_activated == 1) { + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); + } else { + start_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); + } + + security_ok = pdcp_validate_security(ctxt_pP, + pdcp_p, + srb_flagP, + rb_idP, + pdcp_header_len, + rx_hfn_for_count, + pdcp_sn_for_count, + sdu_buffer_pP->data, + sdu_buffer_sizeP - pdcp_tailer_len) == 0; + + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); + } + } else { + security_ok = 1; + } + + if (security_ok == 0) { + LOG_W(PDCP, + PROTOCOL_PDCP_CTXT_FMT"security not validated for incoming PDPC DRB RLC/AM PDU\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); + LOG_W(PDCP, "Ignoring PDU...\n"); + free_mem_block(sdu_buffer_pP, __func__); + /* TODO: indicate integrity verification failure to upper layer */ + return FALSE; + } + + /* TODO: specs say we have to store this PDU in a list and then deliver + * stored packets to upper layers according to a well defined + * procedure. The code below that deals with delivery is today + * too complex to do this properly, so we only send the current + * received packet. This is not correct and has to be fixed + * some day. + * In the meantime, let's pretend the last submitted PDCP SDU + * is the current one. + * TODO: we also have to deal with re-establishment PDU (control PDUs) + * that contain no SDU. + */ + pdcp_p->last_submitted_pdcp_rx_sn = sequence_number; + break; + } /* case RLC_MODE_AM */ + + case RLC_MODE_UM: + + /* process as described in 36.323 5.1.2.1.3 */ + if (sequence_number < pdcp_p->next_pdcp_rx_sn) { + pdcp_p->rx_hfn++; + } + + rx_hfn_for_count = pdcp_p->rx_hfn; + pdcp_sn_for_count = sequence_number; + pdcp_p->next_pdcp_rx_sn = sequence_number + 1; + + if (pdcp_p->next_pdcp_rx_sn > pdcp_p->maximum_pdcp_rx_sn) { + pdcp_p->next_pdcp_rx_sn = 0; + pdcp_p->rx_hfn++; + } + + if (pdcp_p->security_activated == 1) { + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); + } else { + start_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); + } + + security_ok = pdcp_validate_security(ctxt_pP, + pdcp_p, + srb_flagP, + rb_idP, + pdcp_header_len, + rx_hfn_for_count, + pdcp_sn_for_count, + sdu_buffer_pP->data, + sdu_buffer_sizeP - pdcp_tailer_len) == 0; + + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].validate_security); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].validate_security); + } + } else { + security_ok = 1; + } + + if (security_ok == 0) { + LOG_W(PDCP, + PROTOCOL_PDCP_CTXT_FMT"security not validated for incoming PDPC DRB RLC/UM PDU\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); + LOG_W(PDCP, "Ignoring PDU...\n"); + free_mem_block(sdu_buffer_pP, __func__); + /* TODO: indicate integrity verification failure to upper layer */ + return FALSE; + } + + break; + + default: + LOG_E(PDCP, "bad RLC mode, cannot happen.\n"); + exit(1); + } /* switch (pdcp_p->rlc_mode) */ + } else { /* MBMS_flagP == 0 */ + payload_offset=0; + } + + if (otg_enabled==1) { + LOG_D(OTG,"Discarding received packed\n"); + free_mem_block(sdu_buffer_pP, __func__); + + if (ctxt_pP->enb_flag) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); + return TRUE; + } + + // XXX Decompression would be done at this point + /* + * After checking incoming sequence number PDCP header + * has to be stripped off so here we copy SDU buffer starting + * from its second byte (skipping 0th and 1st octets, i.e. + * PDCP header) + */ + + if (LINK_ENB_PDCP_TO_GTPV1U) { + if ((TRUE == ctxt_pP->enb_flag) && (FALSE == srb_flagP)) { + LOG_D(PDCP, "Sending packet to GTP, Calling GTPV1U_ENB_TUNNEL_DATA_REQ ue %x rab %u len %u\n", + ctxt_pP->rnti, + rb_id + 4, + sdu_buffer_sizeP - payload_offset ); + MSC_LOG_TX_MESSAGE( + MSC_PDCP_ENB, + MSC_GTPU_ENB, + NULL,0, + "0 GTPV1U_ENB_TUNNEL_DATA_REQ ue %x rab %u len %u", + ctxt_pP->rnti, + rb_id + 4, + sdu_buffer_sizeP - payload_offset); + //LOG_T(PDCP,"Sending to GTPV1U %d bytes\n", sdu_buffer_sizeP - payload_offset); + gtpu_buffer_p = itti_malloc(TASK_PDCP_ENB, TASK_GTPV1_U, + sdu_buffer_sizeP - payload_offset + GTPU_HEADER_OVERHEAD_MAX); + AssertFatal(gtpu_buffer_p != NULL, "OUT OF MEMORY"); + memcpy(>pu_buffer_p[GTPU_HEADER_OVERHEAD_MAX], &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset); + message_p = itti_alloc_new_message(TASK_PDCP_ENB, GTPV1U_ENB_TUNNEL_DATA_REQ); + AssertFatal(message_p != NULL, "OUT OF MEMORY"); + GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).buffer = gtpu_buffer_p; + GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).length = sdu_buffer_sizeP - payload_offset; + GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).offset = GTPU_HEADER_OVERHEAD_MAX; + GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rnti = ctxt_pP->rnti; + GTPV1U_ENB_TUNNEL_DATA_REQ(message_p).rab_id = rb_id + 4; + itti_send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); + packet_forwarded = TRUE; + } + } else { + packet_forwarded = FALSE; + } + +#ifdef MBMS_MULTICAST_OUT + + if ((MBMS_flagP != 0) && (mbms_socket != -1)) { + struct iphdr *ip_header = (struct iphdr *)&sdu_buffer_pP->data[payload_offset]; + struct udphdr *udp_header = (struct udphdr *)&sdu_buffer_pP->data[payload_offset + sizeof(struct iphdr)]; + struct sockaddr_in dest_addr; + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = udp_header->dest; + dest_addr.sin_addr.s_addr = ip_header->daddr; + + sendto(mbms_socket, &sdu_buffer_pP->data[payload_offset], sdu_buffer_sizeP - payload_offset, MSG_DONTWAIT, (struct sockaddr*)&dest_addr, sizeof(dest_addr)); + //packet_forwarded = TRUE; + + } + +#endif + + if (FALSE == packet_forwarded) { + new_sdu_p = get_free_mem_block(sdu_buffer_sizeP - payload_offset + sizeof (pdcp_data_ind_header_t), __func__); + + if (new_sdu_p) { + if ((MBMS_flagP == 0) && (pdcp_p->rlc_mode == RLC_MODE_AM)) { + pdcp_p->last_submitted_pdcp_rx_sn = sequence_number; + } + + /* + * Prepend PDCP indication header which is going to be removed at pdcp_fifo_flush_sdus() + */ + memset(new_sdu_p->data, 0, sizeof (pdcp_data_ind_header_t)); + ((pdcp_data_ind_header_t *) new_sdu_p->data)->data_size = sdu_buffer_sizeP - payload_offset; + AssertFatal((sdu_buffer_sizeP - payload_offset >= 0), "invalid PDCP SDU size!"); + + // Here there is no virtualization possible + // set ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst for IP layer here + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + ((pdcp_data_ind_header_t *) new_sdu_p->data)->rb_id = rb_id; + + if (EPC_MODE_ENABLED) { + /* for the UE compiled in S1 mode, we need 1 here + * for the UE compiled in noS1 mode, we need 0 + * TODO: be sure of this + */ + if (NFAPI_MODE == NFAPI_UE_STUB_PNF ) { +#ifdef UESIM_EXPANSION + + if (UE_NAS_USE_TUN) { + ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = ctxt_pP->module_id; + } else { + ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = 0; + } + +#else + ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = ctxt_pP->module_id; +#endif + } else { // nfapi_mode + if (UE_NAS_USE_TUN) { + ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = ctxt_pP->module_id; + } else { + ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = 1; + } + } // nfapi_mode + } + } else { + ((pdcp_data_ind_header_t *) new_sdu_p->data)->rb_id = rb_id + (ctxt_pP->module_id * LTE_maxDRB); + ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = ctxt_pP->module_id; + } + + if( LOG_DEBUGFLAG(DEBUG_PDCP) ) { + static uint32_t pdcp_inst = 0; + ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst = pdcp_inst++; + LOG_D(PDCP, "inst=%d size=%d\n", ((pdcp_data_ind_header_t *) new_sdu_p->data)->inst, ((pdcp_data_ind_header_t *) new_sdu_p->data)->data_size); + } + + memcpy(&new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], + &sdu_buffer_pP->data[payload_offset], + sdu_buffer_sizeP - payload_offset); + list_add_tail_eurecom (new_sdu_p, sdu_list_p); + } + + /* Print octets of incoming data in hexadecimal form */ + LOG_D(PDCP, "Following content has been received from RLC (%d,%d)(PDCP header has already been removed):\n", + sdu_buffer_sizeP - payload_offset + (int)sizeof(pdcp_data_ind_header_t), + sdu_buffer_sizeP - payload_offset); + //util_print_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); + //util_flush_hex_octets(PDCP, &new_sdu_p->data[sizeof (pdcp_data_ind_header_t)], sdu_buffer_sizeP - payload_offset); + } + + /* Update PDCP statistics */ + for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { + if (pdcp_enb[ctxt_pP->module_id].rnti[pdcp_uid] == ctxt_pP->rnti ) { + break; + } + } + + Pdcp_stats_rx[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]++; + Pdcp_stats_rx_bytes[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); + Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(sdu_buffer_sizeP - payload_offset); + Pdcp_stats_rx_sn[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=sequence_number; + Pdcp_stats_rx_aiat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+= (pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]+=(pdcp_enb[ctxt_pP->module_id].sfn - Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]); + Pdcp_stats_rx_iat[ctxt_pP->module_id][pdcp_uid][rb_idP+rb_offset]=pdcp_enb[ctxt_pP->module_id].sfn; + free_mem_block(sdu_buffer_pP, __func__); + + if (ctxt_pP->enb_flag) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].data_ind); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].data_ind); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_IND,VCD_FUNCTION_OUT); + return TRUE; +} + +void pdcp_update_stats(const protocol_ctxt_t *const ctxt_pP) { + uint16_t pdcp_uid = 0; + uint8_t rb_id = 0; + + // these stats are measured for both eNB and UE on per seond basis + for (rb_id =0; rb_id < NB_RB_MAX; rb_id ++) { + for (pdcp_uid=0; pdcp_uid< MAX_MOBILES_PER_ENB; pdcp_uid++) { + //printf("frame %d and subframe %d \n", pdcp_enb[ctxt_pP->module_id].frame, pdcp_enb[ctxt_pP->module_id].subframe); + // tx stats + if (Pdcp_stats_tx_window_ms[ctxt_pP->module_id][pdcp_uid] > 0 && + pdcp_enb[ctxt_pP->module_id].sfn % Pdcp_stats_tx_window_ms[ctxt_pP->module_id][pdcp_uid] == 0) { + // unit: bit/s + Pdcp_stats_tx_throughput_w[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]*8; + Pdcp_stats_tx_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; + Pdcp_stats_tx_bytes_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; + + if (Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id] > 0) { + Pdcp_stats_tx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=(Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]); + } else { + Pdcp_stats_tx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + } + + // reset the tmp vars + Pdcp_stats_tx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_tx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_tx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + } + + if (Pdcp_stats_rx_window_ms[ctxt_pP->module_id][pdcp_uid] > 0 && + pdcp_enb[ctxt_pP->module_id].sfn % Pdcp_stats_rx_window_ms[ctxt_pP->module_id][pdcp_uid] == 0) { + // rx stats + Pdcp_stats_rx_goodput_w[ctxt_pP->module_id][pdcp_uid][rb_id]=Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]*8; + Pdcp_stats_rx_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; + Pdcp_stats_rx_bytes_w[ctxt_pP->module_id][pdcp_uid][rb_id]= Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]; + + if(Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id] > 0) { + Pdcp_stats_rx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]= (Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]/Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]); + } else { + Pdcp_stats_rx_aiat_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + } + + // reset the tmp vars + Pdcp_stats_rx_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_rx_bytes_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + Pdcp_stats_rx_aiat_tmp_w[ctxt_pP->module_id][pdcp_uid][rb_id]=0; + } + } + } +} + + +//----------------------------------------------------------------------------- +void +pdcp_run ( + const protocol_ctxt_t *const ctxt_pP +) +//----------------------------------------------------------------------------- +{ + if (ctxt_pP->enb_flag) { + start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); + } else { + start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); + } + + pdcp_enb[ctxt_pP->module_id].sfn++; // range: 0 to 18,446,744,073,709,551,615 + pdcp_enb[ctxt_pP->module_id].frame=ctxt_pP->frame; // 1023 + pdcp_enb[ctxt_pP->module_id].subframe= ctxt_pP->subframe; + pdcp_update_stats(ctxt_pP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_IN); + MessageDef *msg_p; + int result; + protocol_ctxt_t ctxt; + + do { + // Checks if a message has been sent to PDCP sub-task + itti_poll_msg (ctxt_pP->enb_flag ? TASK_PDCP_ENB : TASK_PDCP_UE, &msg_p); + + if (msg_p != NULL) { + switch (ITTI_MSG_ID(msg_p)) { + case RRC_DCCH_DATA_REQ: + PROTOCOL_CTXT_SET_BY_MODULE_ID( + &ctxt, + RRC_DCCH_DATA_REQ (msg_p).module_id, + RRC_DCCH_DATA_REQ (msg_p).enb_flag, + RRC_DCCH_DATA_REQ (msg_p).rnti, + RRC_DCCH_DATA_REQ (msg_p).frame, + 0, + RRC_DCCH_DATA_REQ (msg_p).eNB_index); + LOG_D(PDCP, PROTOCOL_CTXT_FMT"Received %s from %s: instance %d, rb_id %d, muiP %d, confirmP %d, mode %d\n", + PROTOCOL_CTXT_ARGS(&ctxt), + ITTI_MSG_NAME (msg_p), + ITTI_MSG_ORIGIN_NAME(msg_p), + ITTI_MSG_INSTANCE (msg_p), + RRC_DCCH_DATA_REQ (msg_p).rb_id, + RRC_DCCH_DATA_REQ (msg_p).muip, + RRC_DCCH_DATA_REQ (msg_p).confirmp, + RRC_DCCH_DATA_REQ (msg_p).mode); + LOG_D(PDCP, "Before calling pdcp_data_req from pdcp_run! RRC_DCCH_DATA_REQ (msg_p).rb_id: %d \n", RRC_DCCH_DATA_REQ (msg_p).rb_id); + result = pdcp_data_req (&ctxt, + SRB_FLAG_YES, + RRC_DCCH_DATA_REQ (msg_p).rb_id, + RRC_DCCH_DATA_REQ (msg_p).muip, + RRC_DCCH_DATA_REQ (msg_p).confirmp, + RRC_DCCH_DATA_REQ (msg_p).sdu_size, + RRC_DCCH_DATA_REQ (msg_p).sdu_p, + RRC_DCCH_DATA_REQ (msg_p).mode, + NULL, NULL + ); + + if (result != TRUE) + LOG_E(PDCP, "PDCP data request failed!\n"); + + // Message buffer has been processed, free it now. + result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), RRC_DCCH_DATA_REQ (msg_p).sdu_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + break; + + case RRC_PCCH_DATA_REQ: { + sdu_size_t sdu_buffer_sizeP; + sdu_buffer_sizeP = RRC_PCCH_DATA_REQ(msg_p).sdu_size; + uint8_t CC_id = RRC_PCCH_DATA_REQ(msg_p).CC_id; + uint8_t ue_index = RRC_PCCH_DATA_REQ(msg_p).ue_index; + RC.rrc[ctxt_pP->module_id]->carrier[CC_id].sizeof_paging[ue_index] = sdu_buffer_sizeP; + + if (sdu_buffer_sizeP > 0) { + memcpy(RC.rrc[ctxt_pP->module_id]->carrier[CC_id].paging[ue_index], RRC_PCCH_DATA_REQ(msg_p).sdu_p, sdu_buffer_sizeP); + } + + //paging pdcp log + LOG_D(PDCP, "PDCP Received RRC_PCCH_DATA_REQ CC_id %d length %d \n", CC_id, sdu_buffer_sizeP); + } + break; + + default: + LOG_E(PDCP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } + } while(msg_p != NULL); + + // IP/NAS -> PDCP traffic : TX, read the pkt from the upper layer buffer + // if (LINK_ENB_PDCP_TO_GTPV1U && ctxt_pP->enb_flag == ENB_FLAG_NO) { + if (!EPC_MODE_ENABLED || ctxt_pP->enb_flag == ENB_FLAG_NO ) { + pdcp_fifo_read_input_sdus(ctxt_pP); + } + + // PDCP -> NAS/IP traffic: RX + if (ctxt_pP->enb_flag) { + start_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); + } else { + start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); + } + + pdcp_fifo_flush_sdus(ctxt_pP); + + if (ctxt_pP->enb_flag) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); + } + + if (ctxt_pP->enb_flag) { + stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_run); + } else { + stop_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_run); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_RUN, VCD_FUNCTION_OUT); +} + +void pdcp_init_stats_UE(module_id_t mod, uint16_t uid) { + Pdcp_stats_tx_window_ms[mod][uid] = 100; + Pdcp_stats_rx_window_ms[mod][uid] = 100; + + for (int i = 0; i < NB_RB_MAX; ++i) { + Pdcp_stats_tx_bytes[mod][uid][i] = 0; + Pdcp_stats_tx_bytes_w[mod][uid][i] = 0; + Pdcp_stats_tx_bytes_tmp_w[mod][uid][i] = 0; + Pdcp_stats_tx[mod][uid][i] = 0; + Pdcp_stats_tx_w[mod][uid][i] = 0; + Pdcp_stats_tx_tmp_w[mod][uid][i] = 0; + Pdcp_stats_tx_sn[mod][uid][i] = 0; + Pdcp_stats_tx_throughput_w[mod][uid][i] = 0; + Pdcp_stats_tx_aiat[mod][uid][i] = 0; + Pdcp_stats_tx_aiat_w[mod][uid][i] = 0; + Pdcp_stats_tx_aiat_tmp_w[mod][uid][i] = 0; + Pdcp_stats_tx_iat[mod][uid][i] = 0; + Pdcp_stats_rx[mod][uid][i] = 0; + Pdcp_stats_rx_w[mod][uid][i] = 0; + Pdcp_stats_rx_tmp_w[mod][uid][i] = 0; + Pdcp_stats_rx_bytes[mod][uid][i] = 0; + Pdcp_stats_rx_bytes_w[mod][uid][i] = 0; + Pdcp_stats_rx_bytes_tmp_w[mod][uid][i] = 0; + Pdcp_stats_rx_sn[mod][uid][i] = 0; + Pdcp_stats_rx_goodput_w[mod][uid][i] = 0; + Pdcp_stats_rx_aiat[mod][uid][i] = 0; + Pdcp_stats_rx_aiat_w[mod][uid][i] = 0; + Pdcp_stats_rx_aiat_tmp_w[mod][uid][i] = 0; + Pdcp_stats_rx_iat[mod][uid][i] = 0; + Pdcp_stats_rx_outoforder[mod][uid][i] = 0; + } +} + +void pdcp_add_UE(const protocol_ctxt_t *const ctxt_pP) { + int i, ue_flag=1; //, ret=-1; to be decied later + + for (i=0; i < MAX_MOBILES_PER_ENB; i++) { + if (pdcp_enb[ctxt_pP->module_id].rnti[i] == ctxt_pP->rnti) { + ue_flag=-1; + break; + } + } + + if (ue_flag == 1 ) { + for (i=0; i < MAX_MOBILES_PER_ENB ; i++) { + if (pdcp_enb[ctxt_pP->module_id].rnti[i] == 0 ) { + pdcp_enb[ctxt_pP->module_id].rnti[i]=ctxt_pP->rnti; + pdcp_enb[ctxt_pP->module_id].uid[i]=i; + pdcp_enb[ctxt_pP->module_id].num_ues++; + printf("add new uid is %d %x\n\n", i, ctxt_pP->rnti); + pdcp_init_stats_UE(ctxt_pP->module_id, i); + // ret=1; + break; + } + } + } + + //return ret; +} + +//----------------------------------------------------------------------------- +boolean_t +pdcp_remove_UE( + const protocol_ctxt_t *const ctxt_pP +) +//----------------------------------------------------------------------------- +{ + LTE_DRB_Identity_t srb_id = 0; + LTE_DRB_Identity_t drb_id = 0; + hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_rc; + int i; + // check and remove SRBs first + + for(int i = 0; i<MAX_MOBILES_PER_ENB; i++) { + if(pdcp_eNB_UE_instance_to_rnti[i] == ctxt_pP->rnti) { + pdcp_eNB_UE_instance_to_rnti[i] = NOT_A_RNTI; + break; + } + } + + for (srb_id=1; srb_id<3; srb_id++) { + key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); + h_rc = hashtable_remove(pdcp_coll_p, key); + } + + for (drb_id=0; drb_id<LTE_maxDRB; drb_id++) { + key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); + h_rc = hashtable_remove(pdcp_coll_p, key); + } + + (void)h_rc; /* remove gcc warning "set but not used" */ + + // remove ue for pdcp enb inst + for (i=0; i < MAX_MOBILES_PER_ENB; i++) { + if (pdcp_enb[ctxt_pP->module_id].rnti[i] == ctxt_pP->rnti ) { + LOG_I(PDCP, "remove uid is %d/%d %x\n", i, + pdcp_enb[ctxt_pP->module_id].uid[i], + pdcp_enb[ctxt_pP->module_id].rnti[i]); + pdcp_enb[ctxt_pP->module_id].uid[i]=0; + pdcp_enb[ctxt_pP->module_id].rnti[i]=0; + pdcp_enb[ctxt_pP->module_id].num_ues--; + break; + } + } + + return 1; +} + + +//----------------------------------------------------------------------------- +boolean_t +rrc_pdcp_config_asn1_req ( + const protocol_ctxt_t *const ctxt_pP, + LTE_SRB_ToAddModList_t *const srb2add_list_pP, + LTE_DRB_ToAddModList_t *const drb2add_list_pP, + LTE_DRB_ToReleaseList_t *const drb2release_list_pP, + const uint8_t security_modeP, + uint8_t *const kRRCenc_pP, + uint8_t *const kRRCint_pP, + uint8_t *const kUPenc_pP, + LTE_PMCH_InfoList_r9_t *const pmch_InfoList_r9_pP, + rb_id_t *const defaultDRB +) +//----------------------------------------------------------------------------- +{ + long int lc_id = 0; + LTE_DRB_Identity_t srb_id = 0; + long int mch_id = 0; + rlc_mode_t rlc_type = RLC_MODE_NONE; + LTE_DRB_Identity_t drb_id = 0; + LTE_DRB_Identity_t *pdrb_id_p = NULL; + uint8_t drb_sn = 12; + uint8_t srb_sn = 5; // fixed sn for SRBs + uint8_t drb_report = 0; + long int cnt = 0; + uint16_t header_compression_profile = 0; + config_action_t action = CONFIG_ACTION_ADD; + LTE_SRB_ToAddMod_t *srb_toaddmod_p = NULL; + LTE_DRB_ToAddMod_t *drb_toaddmod_p = NULL; + pdcp_t *pdcp_p = NULL; + hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_rc; + hash_key_t key_defaultDRB = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_defaultDRB_rc; + int i,j; + LTE_MBMS_SessionInfoList_r9_t *mbms_SessionInfoList_r9_p = NULL; + LTE_MBMS_SessionInfo_r9_t *MBMS_SessionInfo_p = NULL; + LOG_T(PDCP, PROTOCOL_CTXT_FMT" %s() SRB2ADD %p DRB2ADD %p DRB2RELEASE %p\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + __FUNCTION__, + srb2add_list_pP, + drb2add_list_pP, + drb2release_list_pP); + + // srb2add_list does not define pdcp config, we use rlc info to setup the pdcp dcch0 and dcch1 channels + + if (srb2add_list_pP != NULL) { + for (cnt=0; cnt<srb2add_list_pP->list.count; cnt++) { + srb_id = srb2add_list_pP->list.array[cnt]->srb_Identity; + srb_toaddmod_p = srb2add_list_pP->list.array[cnt]; + rlc_type = RLC_MODE_AM; + lc_id = srb_id; + key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, srb_id, SRB_FLAG_YES); + h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); + + if (h_rc == HASH_TABLE_OK) { + action = CONFIG_ACTION_MODIFY; + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_MODIFY key 0x%"PRIx64"\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + key); + } else { + action = CONFIG_ACTION_ADD; + pdcp_p = calloc(1, sizeof(pdcp_t)); + h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); + + if (h_rc != HASH_TABLE_OK) { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64" FAILED\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + key); + free(pdcp_p); + return TRUE; + } else { + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD key 0x%"PRIx64"\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + key); + } + } + + if (srb_toaddmod_p->rlc_Config) { + switch (srb_toaddmod_p->rlc_Config->present) { + case LTE_SRB_ToAddMod__rlc_Config_PR_NOTHING: + break; + + case LTE_SRB_ToAddMod__rlc_Config_PR_explicitValue: + switch (srb_toaddmod_p->rlc_Config->choice.explicitValue.present) { + case LTE_RLC_Config_PR_NOTHING: + break; + + default: + pdcp_config_req_asn1 ( + ctxt_pP, + pdcp_p, + SRB_FLAG_YES, + rlc_type, + action, + lc_id, + mch_id, + srb_id, + srb_sn, + 0, // drb_report + 0, // header compression + security_modeP, + kRRCenc_pP, + kRRCint_pP, + kUPenc_pP); + break; + } + + break; + + case LTE_SRB_ToAddMod__rlc_Config_PR_defaultValue: + pdcp_config_req_asn1 ( + ctxt_pP, + pdcp_p, + SRB_FLAG_YES, + rlc_type, + action, + lc_id, + mch_id, + srb_id, + srb_sn, + 0, // drb_report + 0, // header compression + security_modeP, + kRRCenc_pP, + kRRCint_pP, + kUPenc_pP); + // already the default values + break; + + default: + DevParam(srb_toaddmod_p->rlc_Config->present, ctxt_pP->module_id, ctxt_pP->rnti); + break; + } + } + } + } + + // reset the action + + if (drb2add_list_pP != NULL) { + for (cnt=0; cnt<drb2add_list_pP->list.count; cnt++) { + drb_toaddmod_p = drb2add_list_pP->list.array[cnt]; + drb_id = drb_toaddmod_p->drb_Identity;// + drb_id_offset; + + if (drb_toaddmod_p->logicalChannelIdentity) { + lc_id = *(drb_toaddmod_p->logicalChannelIdentity); + } else { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" logicalChannelIdentity is missing in DRB-ToAddMod information element!\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); + continue; + } + + if (lc_id == 1 || lc_id == 2) { + LOG_E(RLC, PROTOCOL_CTXT_FMT" logicalChannelIdentity = %ld is invalid in RRC message when adding DRB!\n", PROTOCOL_CTXT_ARGS(ctxt_pP), lc_id); + continue; + } + + DevCheck4(drb_id < LTE_maxDRB, drb_id, LTE_maxDRB, ctxt_pP->module_id, ctxt_pP->rnti); + key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); + h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); + + if (h_rc == HASH_TABLE_OK) { + action = CONFIG_ACTION_MODIFY; + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_MODIFY key 0x%"PRIx64"\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + key); + } else { + action = CONFIG_ACTION_ADD; + pdcp_p = calloc(1, sizeof(pdcp_t)); + h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); + + // save the first configured DRB-ID as the default DRB-ID + if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { + key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); + h_defaultDRB_rc = hashtable_insert(pdcp_coll_p, key_defaultDRB, pdcp_p); + } else { + h_defaultDRB_rc = HASH_TABLE_OK; // do not trigger any error handling if this is not a default DRB + } + + if (h_defaultDRB_rc != HASH_TABLE_OK) { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD default DRB key 0x%"PRIx64" FAILED\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + key_defaultDRB); + free(pdcp_p); + return TRUE; + } else if (h_rc != HASH_TABLE_OK) { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64" FAILED\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + key); + free(pdcp_p); + return TRUE; + } else { + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_ADD ADD key 0x%"PRIx64"\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p), + key); + } + } + + if (drb_toaddmod_p->pdcp_Config) { + if (drb_toaddmod_p->pdcp_Config->discardTimer) { + // set the value of the timer + } + + if (drb_toaddmod_p->pdcp_Config->rlc_AM) { + drb_report = drb_toaddmod_p->pdcp_Config->rlc_AM->statusReportRequired; + drb_sn = LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits; // default SN size + rlc_type = RLC_MODE_AM; + } + + if (drb_toaddmod_p->pdcp_Config->rlc_UM) { + drb_sn = drb_toaddmod_p->pdcp_Config->rlc_UM->pdcp_SN_Size; + rlc_type =RLC_MODE_UM; + } + + switch (drb_toaddmod_p->pdcp_Config->headerCompression.present) { + case LTE_PDCP_Config__headerCompression_PR_NOTHING: + case LTE_PDCP_Config__headerCompression_PR_notUsed: + header_compression_profile=0x0; + break; + + case LTE_PDCP_Config__headerCompression_PR_rohc: + + // parse the struc and get the rohc profile + if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0001) { + header_compression_profile=0x0001; + } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0002) { + header_compression_profile=0x0002; + } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0003) { + header_compression_profile=0x0003; + } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0004) { + header_compression_profile=0x0004; + } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0006) { + header_compression_profile=0x0006; + } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0101) { + header_compression_profile=0x0101; + } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0102) { + header_compression_profile=0x0102; + } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0103) { + header_compression_profile=0x0103; + } else if(drb_toaddmod_p->pdcp_Config->headerCompression.choice.rohc.profiles.profile0x0104) { + header_compression_profile=0x0104; + } else { + header_compression_profile=0x0; + LOG_W(PDCP,"unknown header compresion profile\n"); + } + + // set the applicable profile + break; + + default: + LOG_W(PDCP,PROTOCOL_PDCP_CTXT_FMT"[RB %ld] unknown drb_toaddmod->PDCP_Config->headerCompression->present \n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), drb_id); + break; + } + + pdcp_config_req_asn1 ( + ctxt_pP, + pdcp_p, + SRB_FLAG_NO, + rlc_type, + action, + lc_id, + mch_id, + drb_id, + drb_sn, + drb_report, + header_compression_profile, + security_modeP, + kRRCenc_pP, + kRRCint_pP, + kUPenc_pP); + } + } + } + + if (drb2release_list_pP != NULL) { + for (cnt=0; cnt<drb2release_list_pP->list.count; cnt++) { + pdrb_id_p = drb2release_list_pP->list.array[cnt]; + drb_id = *pdrb_id_p; + key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, drb_id, SRB_FLAG_NO); + h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); + + if (h_rc != HASH_TABLE_OK) { + LOG_E(PDCP, PROTOCOL_CTXT_FMT" PDCP REMOVE FAILED drb_id %ld\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + drb_id); + continue; + } + + lc_id = pdcp_p->lcid; + action = CONFIG_ACTION_REMOVE; + pdcp_config_req_asn1 ( + ctxt_pP, + pdcp_p, + SRB_FLAG_NO, + rlc_type, + action, + lc_id, + mch_id, + drb_id, + 0, + 0, + 0, + security_modeP, + kRRCenc_pP, + kRRCint_pP, + kUPenc_pP); + h_rc = hashtable_remove(pdcp_coll_p, key); + + if ((defaultDRB != NULL) && (*defaultDRB == drb_id)) { + // default DRB being removed. nevertheless this shouldn't happen as removing default DRB is not allowed in standard + key_defaultDRB = PDCP_COLL_KEY_DEFAULT_DRB_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag); + h_defaultDRB_rc = hashtable_get(pdcp_coll_p, key_defaultDRB, (void **)&pdcp_p); + + if (h_defaultDRB_rc == HASH_TABLE_OK) { + h_defaultDRB_rc = hashtable_remove(pdcp_coll_p, key_defaultDRB); + } else { + LOG_E(PDCP, PROTOCOL_CTXT_FMT" PDCP REMOVE FAILED default DRB\n", PROTOCOL_CTXT_ARGS(ctxt_pP)); + } + } else { + key_defaultDRB = HASH_TABLE_OK; // do not trigger any error handling if this is not a default DRB + } + } + } + + if (pmch_InfoList_r9_pP != NULL) { + for (i=0; i<pmch_InfoList_r9_pP->list.count; i++) { + mbms_SessionInfoList_r9_p = &(pmch_InfoList_r9_pP->list.array[i]->mbms_SessionInfoList_r9); + + for (j=0; j<mbms_SessionInfoList_r9_p->list.count; j++) { + MBMS_SessionInfo_p = mbms_SessionInfoList_r9_p->list.array[j]; + + if (MBMS_SessionInfo_p->sessionId_r9) + lc_id = MBMS_SessionInfo_p->sessionId_r9->buf[0]; + else + lc_id = MBMS_SessionInfo_p->logicalChannelIdentity_r9; + + mch_id = MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[2]; //serviceId is 3-octet string + // mch_id = j; + + // can set the mch_id = i + if (ctxt_pP->enb_flag) { + drb_id = (mch_id * LTE_maxSessionPerPMCH ) + lc_id ;//+ (LTE_maxDRB + 3)*MAX_MOBILES_PER_ENB; // 1 + + if (pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == TRUE) { + action = CONFIG_ACTION_MBMS_MODIFY; + } else { + action = CONFIG_ACTION_MBMS_ADD; + } + } else { + drb_id = (mch_id * LTE_maxSessionPerPMCH ) + lc_id; // + (LTE_maxDRB + 3); // 15 + + if (pdcp_mbms_array_ue[ctxt_pP->module_id][mch_id][lc_id].instanciated_instance == TRUE) { + action = CONFIG_ACTION_MBMS_MODIFY; + } else { + action = CONFIG_ACTION_MBMS_ADD; + } + } + + LOG_D(PDCP, "lc_id (%02ld) mch_id(%02x,%02x,%02x) drb_id(%ld) action(%d)\n", + lc_id, + MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[0], + MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[1], + MBMS_SessionInfo_p->tmgi_r9.serviceId_r9.buf[2], + drb_id, + action); + pdcp_config_req_asn1 ( + ctxt_pP, + NULL, // unused for MBMS + SRB_FLAG_NO, + RLC_MODE_NONE, + action, + lc_id, + mch_id, + drb_id, + 0, // unused for MBMS + 0, // unused for MBMS + 0, // unused for MBMS + 0, // unused for MBMS + NULL, // unused for MBMS + NULL, // unused for MBMS + NULL); // unused for MBMS + } + } + } + + return 0; +} + +//----------------------------------------------------------------------------- +boolean_t +pdcp_config_req_asn1 ( + const protocol_ctxt_t *const ctxt_pP, + pdcp_t *const pdcp_pP, + const srb_flag_t srb_flagP, + const rlc_mode_t rlc_modeP, + const config_action_t actionP, + const uint16_t lc_idP, + const uint16_t mch_idP, + const rb_id_t rb_idP, + const uint8_t rb_snP, + const uint8_t rb_reportP, + const uint16_t header_compression_profileP, + const uint8_t security_modeP, + uint8_t *const kRRCenc_pP, + uint8_t *const kRRCint_pP, + uint8_t *const kUPenc_pP) +//----------------------------------------------------------------------------- +{ + switch (actionP) { + case CONFIG_ACTION_ADD: + DevAssert(pdcp_pP != NULL); + + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + pdcp_pP->is_ue = FALSE; + pdcp_add_UE(ctxt_pP); + + //pdcp_eNB_UE_instance_to_rnti[ctxtP->module_id] = ctxt_pP->rnti; + // pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; + if( srb_flagP == SRB_FLAG_NO ) { + for(int i = 0; i<MAX_MOBILES_PER_ENB; i++) { + if(pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] == NOT_A_RNTI) { + break; + } + + pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; + } + + pdcp_eNB_UE_instance_to_rnti[pdcp_eNB_UE_instance_to_rnti_index] = ctxt_pP->rnti; + pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; + } + + //pdcp_eNB_UE_instance_to_rnti_index = (pdcp_eNB_UE_instance_to_rnti_index + 1) % MAX_MOBILES_PER_ENB; + } else { + pdcp_pP->is_ue = TRUE; + pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; + } + + pdcp_pP->is_srb = (srb_flagP == SRB_FLAG_YES) ? TRUE : FALSE; + pdcp_pP->lcid = lc_idP; + pdcp_pP->rb_id = rb_idP; + pdcp_pP->header_compression_profile = header_compression_profileP; + pdcp_pP->status_report = rb_reportP; + + if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits) { + pdcp_pP->seq_num_size = 12; + pdcp_pP->maximum_pdcp_rx_sn = (1 << 12) - 1; + } else if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) { + pdcp_pP->seq_num_size = 7; + pdcp_pP->maximum_pdcp_rx_sn = (1 << 7) - 1; + } else { + pdcp_pP->seq_num_size = 5; + pdcp_pP->maximum_pdcp_rx_sn = (1 << 5) - 1; + } + + pdcp_pP->rlc_mode = rlc_modeP; + pdcp_pP->next_pdcp_tx_sn = 0; + pdcp_pP->next_pdcp_rx_sn = 0; + pdcp_pP->tx_hfn = 0; + pdcp_pP->rx_hfn = 0; + pdcp_pP->last_submitted_pdcp_rx_sn = 4095; + pdcp_pP->first_missing_pdu = -1; + LOG_I(PDCP, PROTOCOL_PDCP_CTXT_FMT" Action ADD LCID %d (%s id %d) " + "configured with SN size %d bits and RLC %s\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), + lc_idP, + (srb_flagP == SRB_FLAG_YES) ? "SRB" : "DRB", + rb_idP, + pdcp_pP->seq_num_size, + (rlc_modeP == RLC_MODE_AM ) ? "AM" : (rlc_modeP == RLC_MODE_TM) ? "TM" : "UM"); + + /* Setup security */ + if (security_modeP != 0xff) { + pdcp_config_set_security( + ctxt_pP, + pdcp_pP, + rb_idP, + lc_idP, + security_modeP, + kRRCenc_pP, + kRRCint_pP, + kUPenc_pP); + } + + break; + + case CONFIG_ACTION_MODIFY: + DevAssert(pdcp_pP != NULL); + pdcp_pP->header_compression_profile=header_compression_profileP; + pdcp_pP->status_report = rb_reportP; + pdcp_pP->rlc_mode = rlc_modeP; + + /* Setup security */ + if (security_modeP != 0xff) { + pdcp_config_set_security( + ctxt_pP, + pdcp_pP, + rb_idP, + lc_idP, + security_modeP, + kRRCenc_pP, + kRRCint_pP, + kUPenc_pP); + } + + if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len7bits) { + pdcp_pP->seq_num_size = 7; + } else if (rb_snP == LTE_PDCP_Config__rlc_UM__pdcp_SN_Size_len12bits) { + pdcp_pP->seq_num_size = 12; + } else { + pdcp_pP->seq_num_size=5; + } + + LOG_I(PDCP,PROTOCOL_PDCP_CTXT_FMT" Action MODIFY LCID %d " + "RB id %d reconfigured with SN size %d and RLC %s \n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), + lc_idP, + rb_idP, + rb_snP, + (rlc_modeP == RLC_MODE_AM) ? "AM" : (rlc_modeP == RLC_MODE_TM) ? "TM" : "UM"); + break; + + case CONFIG_ACTION_REMOVE: + DevAssert(pdcp_pP != NULL); + //#warning "TODO pdcp_module_id_to_rnti" + //pdcp_module_id_to_rnti[ctxt_pP.module_id ][dst_id] = NOT_A_RNTI; + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_REMOVE LCID %d RBID %d configured\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), + lc_idP, + rb_idP); + + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + // pdcp_remove_UE(ctxt_pP); + } + + /* Security keys */ + if (pdcp_pP->kUPenc != NULL) { + free(pdcp_pP->kUPenc); + } + + if (pdcp_pP->kRRCint != NULL) { + free(pdcp_pP->kRRCint); + } + + if (pdcp_pP->kRRCenc != NULL) { + free(pdcp_pP->kRRCenc); + } + + memset(pdcp_pP, 0, sizeof(pdcp_t)); + break; + + case CONFIG_ACTION_MBMS_ADD: + case CONFIG_ACTION_MBMS_MODIFY: + LOG_D(PDCP," %s service_id/mch index %d, session_id/lcid %d, rbid %d configured\n", + //PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), + actionP == CONFIG_ACTION_MBMS_ADD ? "CONFIG_ACTION_MBMS_ADD" : "CONFIG_ACTION_MBMS_MODIFY", + mch_idP, + lc_idP, + rb_idP); + + if (ctxt_pP->enb_flag == ENB_FLAG_YES) { + pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = TRUE ; + pdcp_mbms_array_eNB[ctxt_pP->module_id][mch_idP][lc_idP].rb_id = rb_idP; + } else { + pdcp_mbms_array_ue[ctxt_pP->module_id][mch_idP][lc_idP].instanciated_instance = TRUE ; + pdcp_mbms_array_ue[ctxt_pP->module_id][mch_idP][lc_idP].rb_id = rb_idP; + } + + break; + + case CONFIG_ACTION_SET_SECURITY_MODE: + pdcp_config_set_security( + ctxt_pP, + pdcp_pP, + rb_idP, + lc_idP, + security_modeP, + kRRCenc_pP, + kRRCint_pP, + kUPenc_pP); + break; + + default: + DevParam(actionP, ctxt_pP->module_id, ctxt_pP->rnti); + break; + } + + return 0; +} + +//----------------------------------------------------------------------------- +void +pdcp_config_set_security( + const protocol_ctxt_t *const ctxt_pP, + pdcp_t *const pdcp_pP, + const rb_id_t rb_idP, + const uint16_t lc_idP, + const uint8_t security_modeP, + uint8_t *const kRRCenc, + uint8_t *const kRRCint, + uint8_t *const kUPenc) +//----------------------------------------------------------------------------- +{ + DevAssert(pdcp_pP != NULL); + + if ((security_modeP >= 0) && (security_modeP <= 0x77)) { + pdcp_pP->cipheringAlgorithm = security_modeP & 0x0f; + pdcp_pP->integrityProtAlgorithm = (security_modeP>>4) & 0xf; + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_SET_SECURITY_MODE: cipheringAlgorithm %d integrityProtAlgorithm %d\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), + pdcp_pP->cipheringAlgorithm, + pdcp_pP->integrityProtAlgorithm); + pdcp_pP->kRRCenc = kRRCenc; + pdcp_pP->kRRCint = kRRCint; + pdcp_pP->kUPenc = kUPenc; + /* Activate security */ + pdcp_pP->security_activated = 1; + + MSC_LOG_EVENT( + (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, + "0 Set security ciph %X integ %x UE %"PRIx16" ", + pdcp_pP->cipheringAlgorithm, + pdcp_pP->integrityProtAlgorithm, + ctxt_pP->rnti); + } + /*]SecurityModeFailure*/ + else if(security_modeP == -1){ + // in this way in pdcp_data_req_NB_IoT function you never call "pdcp_apply_security" + // and we never call pdcp_validate_security in NB_pdcp_data_indi + pdcp_pP->security_activated = 0; + pdcp_pP->cipheringAlgorithm = 0; + pdcp_pP->integrityProtAlgorithm = 0; + } + else { + MSC_LOG_EVENT( + (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE, + "0 Set security failed UE %"PRIx16" ", + ctxt_pP->rnti); + LOG_E(PDCP,PROTOCOL_PDCP_CTXT_FMT" bad security mode %d", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_pP), + security_modeP); + } +} + +//----------------------------------------------------------------------------- +// MP: seems to be no more used (old code) +void +rrc_pdcp_config_req ( + const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const uint32_t actionP, + const rb_id_t rb_idP, + const uint8_t security_modeP) +//----------------------------------------------------------------------------- +{ + pdcp_t *pdcp_p = NULL; + hash_key_t key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); + hashtable_rc_t h_rc; + h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); + + if (h_rc == HASH_TABLE_OK) { + /* + * Initialize sequence number state variables of relevant PDCP entity + */ + switch (actionP) { + case CONFIG_ACTION_ADD: + pdcp_p->is_srb = srb_flagP; + pdcp_p->rb_id = rb_idP; + + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + pdcp_p->is_ue = TRUE; + pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; + } else { + pdcp_p->is_ue = FALSE; + } + + pdcp_p->next_pdcp_tx_sn = 0; + pdcp_p->next_pdcp_rx_sn = 0; + pdcp_p->tx_hfn = 0; + pdcp_p->rx_hfn = 0; + /* SN of the last PDCP SDU delivered to upper layers */ + pdcp_p->last_submitted_pdcp_rx_sn = 4095; + + if (rb_idP < DTCH) { // SRB + pdcp_p->seq_num_size = 5; + } else { // DRB + pdcp_p->seq_num_size = 12; + } + + pdcp_p->first_missing_pdu = -1; + LOG_D(PDCP,PROTOCOL_PDCP_CTXT_FMT" Config request : Action ADD: radio bearer id %d (already added) configured\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), + rb_idP); + break; + + case CONFIG_ACTION_MODIFY: + break; + + case CONFIG_ACTION_REMOVE: + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_REMOVE: radio bearer id %d configured\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), + rb_idP); + pdcp_p->next_pdcp_tx_sn = 0; + pdcp_p->next_pdcp_rx_sn = 0; + pdcp_p->tx_hfn = 0; + pdcp_p->rx_hfn = 0; + pdcp_p->last_submitted_pdcp_rx_sn = 4095; + pdcp_p->seq_num_size = 0; + pdcp_p->first_missing_pdu = -1; + pdcp_p->security_activated = 0; + h_rc = hashtable_remove(pdcp_coll_p, key); + break; + + case CONFIG_ACTION_SET_SECURITY_MODE: + if ((security_modeP >= 0) && (security_modeP <= 0x77)) { + pdcp_p->cipheringAlgorithm= security_modeP & 0x0f; + pdcp_p->integrityProtAlgorithm = (security_modeP>>4) & 0xf; + LOG_D(PDCP, PROTOCOL_PDCP_CTXT_FMT" CONFIG_ACTION_SET_SECURITY_MODE: cipheringAlgorithm %d integrityProtAlgorithm %d\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), + pdcp_p->cipheringAlgorithm, + pdcp_p->integrityProtAlgorithm ); + } else { + LOG_W(PDCP,PROTOCOL_PDCP_CTXT_FMT" bad security mode %d", PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), security_modeP); + } + + break; + + default: + DevParam(actionP, ctxt_pP->module_id, ctxt_pP->rnti); + break; + } + } else { + switch (actionP) { + case CONFIG_ACTION_ADD: + pdcp_p = calloc(1, sizeof(pdcp_t)); + h_rc = hashtable_insert(pdcp_coll_p, key, pdcp_p); + + if (h_rc != HASH_TABLE_OK) { + LOG_E(PDCP, PROTOCOL_PDCP_CTXT_FMT" PDCP ADD FAILED\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP, pdcp_p)); + free(pdcp_p); + } else { + pdcp_p->is_srb = srb_flagP; + pdcp_p->rb_id = rb_idP; + + if (ctxt_pP->enb_flag == ENB_FLAG_NO) { + pdcp_p->is_ue = TRUE; + pdcp_UE_UE_module_id_to_rnti[ctxt_pP->module_id] = ctxt_pP->rnti; + } else { + pdcp_p->is_ue = FALSE; + } + + pdcp_p->next_pdcp_tx_sn = 0; + pdcp_p->next_pdcp_rx_sn = 0; + pdcp_p->tx_hfn = 0; + pdcp_p->rx_hfn = 0; + /* SN of the last PDCP SDU delivered to upper layers */ + pdcp_p->last_submitted_pdcp_rx_sn = 4095; + + if (rb_idP < DTCH) { // SRB + pdcp_p->seq_num_size = 5; + } else { // DRB + pdcp_p->seq_num_size = 12; + } + + pdcp_p->first_missing_pdu = -1; + LOG_D(PDCP,PROTOCOL_PDCP_CTXT_FMT" Inserting PDCP instance in collection key 0x%"PRIx64"\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), key); + LOG_D(PDCP,PROTOCOL_PDCP_CTXT_FMT" Config request : Action ADD: radio bearer id %d configured\n", + PROTOCOL_PDCP_CTXT_ARGS(ctxt_pP,pdcp_p), + rb_idP); + } + + break; + + case CONFIG_ACTION_REMOVE: + LOG_D(PDCP, PROTOCOL_CTXT_FMT" CONFIG_REQ PDCP CONFIG_ACTION_REMOVE PDCP instance not found\n", + PROTOCOL_CTXT_ARGS(ctxt_pP)); + break; + + default: + LOG_E(PDCP, PROTOCOL_CTXT_FMT" CONFIG_REQ PDCP NOT FOUND\n", + PROTOCOL_CTXT_ARGS(ctxt_pP)); + } + } +} + +pdcp_data_ind_func_t get_pdcp_data_ind_func() { + return pdcp_params.pdcp_data_ind_func; +} + +void pdcp_set_rlc_data_req_func(send_rlc_data_req_func_t send_rlc_data_req) { + pdcp_params.send_rlc_data_req_func = send_rlc_data_req; +} + +void pdcp_set_pdcp_data_ind_func(pdcp_data_ind_func_t pdcp_data_ind) { + pdcp_params.pdcp_data_ind_func = pdcp_data_ind; +} + +uint64_t pdcp_module_init( uint64_t pdcp_optmask ) { + /* temporary enforce netlink when UE_NAS_USE_TUN is set, + this is while switching from noS1 as build option + to noS1 as config option */ + if ( pdcp_optmask & UE_NAS_USE_TUN_BIT) { + pdcp_params.optmask = pdcp_params.optmask | PDCP_USE_NETLINK_BIT ; + } + + pdcp_params.optmask = pdcp_params.optmask | pdcp_optmask ; + LOG_I(PDCP, "pdcp init,%s %s\n", + ((LINK_ENB_PDCP_TO_GTPV1U)?"usegtp":""), + ((PDCP_USE_NETLINK)?"usenetlink":"")); + + if (PDCP_USE_NETLINK) { + nas_getparams(); + + if(UE_NAS_USE_TUN) { + int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 )?MAX_NUMBER_NETIF:1; + netlink_init_tun("ue",num_if); + LOG_I(PDCP, "UE pdcp will use tun interface\n"); + } else if(ENB_NAS_USE_TUN) { + netlink_init_tun("enb",1); + nas_config(1, 1, 1, "enb"); + LOG_I(PDCP, "ENB pdcp will use tun interface\n"); + } else { + LOG_I(PDCP, "pdcp will use kernel modules\n"); + netlink_init(); + } + } + return pdcp_params.optmask ; +} + + +//----------------------------------------------------------------------------- +void +pdcp_free ( + void *pdcp_pP +) +//----------------------------------------------------------------------------- +{ + pdcp_t *pdcp_p = (pdcp_t *)pdcp_pP; + + if (pdcp_p != NULL) { + if (pdcp_p->kUPenc != NULL) { + free(pdcp_p->kUPenc); + } + + if (pdcp_p->kRRCint != NULL) { + free(pdcp_p->kRRCint); + } + + if (pdcp_p->kRRCenc != NULL) { + free(pdcp_p->kRRCenc); + } + + memset(pdcp_pP, 0, sizeof(pdcp_t)); + free(pdcp_pP); + } +} + +//----------------------------------------------------------------------------- +void pdcp_module_cleanup (void) +//----------------------------------------------------------------------------- +{ +} + +//----------------------------------------------------------------------------- +void pdcp_layer_init(void) +//----------------------------------------------------------------------------- +{ + module_id_t instance; + int i,j; + mbms_session_id_t session_id; + mbms_service_id_t service_id; + /* + * Initialize SDU list + */ + list_init(&pdcp_sdu_list, NULL); + pdcp_coll_p = hashtable_create ((LTE_maxDRB + 2) * NUMBER_OF_UE_MAX, NULL, pdcp_free); + AssertFatal(pdcp_coll_p != NULL, "UNRECOVERABLE error, PDCP hashtable_create failed"); + + for (instance = 0; instance < MAX_MOBILES_PER_ENB; instance++) { + for (service_id = 0; service_id < LTE_maxServiceCount; service_id++) { + for (session_id = 0; session_id < LTE_maxSessionPerPMCH; session_id++) { + memset(&pdcp_mbms_array_ue[instance][service_id][session_id], 0, sizeof(pdcp_mbms_t)); + } + } + + pdcp_eNB_UE_instance_to_rnti[instance] = NOT_A_RNTI; + } + + pdcp_eNB_UE_instance_to_rnti_index = 0; + + for (instance = 0; instance < NUMBER_OF_eNB_MAX; instance++) { + for (service_id = 0; service_id < LTE_maxServiceCount; service_id++) { + for (session_id = 0; session_id < LTE_maxSessionPerPMCH; session_id++) { + memset(&pdcp_mbms_array_eNB[instance][service_id][session_id], 0, sizeof(pdcp_mbms_t)); + } + } + } + +#ifdef MBMS_MULTICAST_OUT + mbms_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + + if (mbms_socket == -1) + LOG_W(PDCP, "Could not create RAW socket, MBMS packets will not be put to the network\n"); + +#endif + LOG_I(PDCP, "PDCP layer has been initialized\n"); + pdcp_output_sdu_bytes_to_write=0; + pdcp_output_header_bytes_to_write=0; + pdcp_input_sdu_remaining_size_to_read=0; + memset(pdcp_enb, 0, sizeof(pdcp_enb_t)); + memset(Pdcp_stats_tx_window_ms, 0, sizeof(Pdcp_stats_tx_window_ms)); + memset(Pdcp_stats_rx_window_ms, 0, sizeof(Pdcp_stats_rx_window_ms)); + + for (i = 0; i < MAX_eNB; i++) { + for (j = 0; j < MAX_MOBILES_PER_ENB; j++) { + Pdcp_stats_tx_window_ms[i][j]=100; + Pdcp_stats_rx_window_ms[i][j]=100; + } + } + + memset(Pdcp_stats_tx, 0, sizeof(Pdcp_stats_tx)); + memset(Pdcp_stats_tx_w, 0, sizeof(Pdcp_stats_tx_w)); + memset(Pdcp_stats_tx_tmp_w, 0, sizeof(Pdcp_stats_tx_tmp_w)); + memset(Pdcp_stats_tx_bytes, 0, sizeof(Pdcp_stats_tx_bytes)); + memset(Pdcp_stats_tx_bytes_w, 0, sizeof(Pdcp_stats_tx_bytes_w)); + memset(Pdcp_stats_tx_bytes_tmp_w, 0, sizeof(Pdcp_stats_tx_bytes_tmp_w)); + memset(Pdcp_stats_tx_sn, 0, sizeof(Pdcp_stats_tx_sn)); + memset(Pdcp_stats_tx_throughput_w, 0, sizeof(Pdcp_stats_tx_throughput_w)); + memset(Pdcp_stats_tx_aiat, 0, sizeof(Pdcp_stats_tx_aiat)); + memset(Pdcp_stats_tx_iat, 0, sizeof(Pdcp_stats_tx_iat)); + memset(Pdcp_stats_rx, 0, sizeof(Pdcp_stats_rx)); + memset(Pdcp_stats_rx_w, 0, sizeof(Pdcp_stats_rx_w)); + memset(Pdcp_stats_rx_tmp_w, 0, sizeof(Pdcp_stats_rx_tmp_w)); + memset(Pdcp_stats_rx_bytes, 0, sizeof(Pdcp_stats_rx_bytes)); + memset(Pdcp_stats_rx_bytes_w, 0, sizeof(Pdcp_stats_rx_bytes_w)); + memset(Pdcp_stats_rx_bytes_tmp_w, 0, sizeof(Pdcp_stats_rx_bytes_tmp_w)); + memset(Pdcp_stats_rx_sn, 0, sizeof(Pdcp_stats_rx_sn)); + memset(Pdcp_stats_rx_goodput_w, 0, sizeof(Pdcp_stats_rx_goodput_w)); + memset(Pdcp_stats_rx_aiat, 0, sizeof(Pdcp_stats_rx_aiat)); + memset(Pdcp_stats_rx_iat, 0, sizeof(Pdcp_stats_rx_iat)); + memset(Pdcp_stats_rx_outoforder, 0, sizeof(Pdcp_stats_rx_outoforder)); +} + + +//----------------------------------------------------------------------------- +void pdcp_layer_cleanup (void) +//----------------------------------------------------------------------------- +{ + list_free (&pdcp_sdu_list); + hashtable_destroy(&pdcp_coll_p); +#ifdef MBMS_MULTICAST_OUT + + if(mbms_socket != -1) { + close(mbms_socket); + mbms_socket = -1; + } + +#endif +} diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 96d405ff4cec31dfb89373c1f3c6242ccfd09a11..f5f3826f27c23dcca8601e7c9205d7ad99084d2f 100755 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -1,561 +1,563 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file LAYER2/PDCP_v10.1.0/pdcp.h -* \brief pdcp interface with RLC, RRC -* \author Lionel GAUTHIER and Navid Nikaein -* \date 2009-2012 -* \version 1.0 -*/ - -/** @defgroup _pdcp PDCP -* @ingroup _oai2 -* @{ -*/ - -#ifndef __PDCP_H__ -# define __PDCP_H__ -//----------------------------------------------------------------------------- -#ifndef NON_ACCESS_STRATUM - #include "UTIL/MEM/mem_block.h" - #include "UTIL/LISTS/list.h" -#endif //NON_ACCESS_STRATUM -//----------------------------------------------------------------------------- -#include "RRC/LTE/rrc_defs.h" -#include "COMMON/platform_constants.h" -#include "COMMON/platform_types.h" -#include "LTE_DRB-ToAddMod.h" -#include "LTE_DRB-ToAddModList.h" -#include "LTE_SRB-ToAddMod.h" -#include "LTE_SRB-ToAddModList.h" -#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) - #include "LTE_MBMS-SessionInfoList-r9.h" - #include "LTE_PMCH-InfoList-r9.h" -#endif - -typedef rlc_op_status_t (*send_rlc_data_req_func_t)(const protocol_ctxt_t *const, - const srb_flag_t, const MBMS_flag_t, - const rb_id_t, const mui_t, - confirm_t, sdu_size_t, mem_block_t *,const uint32_t *const, const uint32_t *const); -typedef boolean_t (*pdcp_data_ind_func_t)( const protocol_ctxt_t *, const srb_flag_t, - const MBMS_flag_t, const rb_id_t, const sdu_size_t, - mem_block_t *,const uint32_t *const, const uint32_t *const); -/* maximum number of tun interfaces that will be created to emulates UEs */ -/* UEs beyond that will be multiplexed on the same tun */ -#define MAX_NUMBER_NETIF 16 - -#define PDCP_USE_NETLINK_BIT (1<< 11) -#define LINK_ENB_PDCP_TO_IP_DRIVER_BIT (1<< 13) -#define LINK_ENB_PDCP_TO_GTPV1U_BIT (1<< 14) -#define UE_NAS_USE_TUN_BIT (1<< 15) -#define ENB_NAS_USE_TUN_BIT (1<< 16) -typedef struct { - uint64_t optmask; - send_rlc_data_req_func_t send_rlc_data_req_func; - pdcp_data_ind_func_t pdcp_data_ind_func; -} pdcp_params_t; - - - -#define PDCP_USE_NETLINK ( get_pdcp_optmask() & PDCP_USE_NETLINK_BIT) -#define LINK_ENB_PDCP_TO_IP_DRIVER ( get_pdcp_optmask() & LINK_ENB_PDCP_TO_IP_DRIVER_BIT) -#define LINK_ENB_PDCP_TO_GTPV1U ( get_pdcp_optmask() & LINK_ENB_PDCP_TO_GTPV1U_BIT) -#define UE_NAS_USE_TUN ( get_pdcp_optmask() & UE_NAS_USE_TUN_BIT) -#define ENB_NAS_USE_TUN ( get_pdcp_optmask() & ENB_NAS_USE_TUN_BIT) -uint64_t get_pdcp_optmask(void); - -extern pthread_t pdcp_thread; -extern pthread_attr_t pdcp_thread_attr; -extern pthread_mutex_t pdcp_mutex; -extern pthread_cond_t pdcp_cond; -extern int pdcp_instance_cnt; - -#define PROTOCOL_PDCP_CTXT_FMT PROTOCOL_CTXT_FMT"[%s %02u] " - -#define PROTOCOL_PDCP_CTXT_ARGS(CTXT_Pp, pDCP_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp),\ - (pDCP_Pp->is_srb) ? "SRB" : "DRB",\ - pDCP_Pp->rb_id -int init_pdcp_thread(void); -void cleanup_pdcp_thread(void); - -uint32_t Pdcp_stats_tx_window_ms[MAX_eNB][MAX_MOBILES_PER_ENB]; -uint32_t Pdcp_stats_tx_bytes[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_bytes_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_bytes_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_sn[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_throughput_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_aiat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_aiat_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_aiat_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_tx_iat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; - -uint32_t Pdcp_stats_rx_window_ms[MAX_eNB][MAX_MOBILES_PER_ENB]; -uint32_t Pdcp_stats_rx[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_bytes[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_bytes_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_bytes_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_sn[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_goodput_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_aiat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_aiat_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_aiat_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_iat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; -uint32_t Pdcp_stats_rx_outoforder[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; - -void pdcp_update_perioidical_stats(const protocol_ctxt_t *const ctxt_pP); - - -/*Packet Probing for agent PDCP*/ -//uint64_t *pdcp_packet_counter; -//uint64_t *pdcp_size_packet; -typedef struct pdcp_enb_s { - // used for eNB stats generation - uint16_t uid[MAX_MOBILES_PER_ENB]; - rnti_t rnti[MAX_MOBILES_PER_ENB]; - uint16_t num_ues; - - uint64_t sfn; - frame_t frame; - sub_frame_t subframe; - -} pdcp_enb_t; - -pdcp_enb_t pdcp_enb[MAX_NUM_CCs]; - -typedef struct pdcp_stats_s { - time_stats_t pdcp_run; - time_stats_t data_req; - time_stats_t data_ind; - time_stats_t apply_security; // - time_stats_t validate_security; - time_stats_t pdcp_ip; - time_stats_t ip_pdcp; // separte thread -} pdcp_stats_t; // common to eNB and UE - - -typedef struct pdcp_s { - //boolean_t instanciated_instance; - uint16_t header_compression_profile; - - /* SR: added this flag to distinguish UE/eNB instance as pdcp_run for virtual - * mode can receive data on NETLINK for eNB while eNB_flag = 0 and for UE when eNB_flag = 1 - */ - boolean_t is_ue; - boolean_t is_srb; - - /* Configured security algorithms */ - uint8_t cipheringAlgorithm; - uint8_t integrityProtAlgorithm; - - /* User-Plane encryption key - * Control-Plane RRC encryption key - * Control-Plane RRC integrity key - * These keys are configured by RRC layer - */ - uint8_t *kUPenc; - uint8_t *kRRCint; - uint8_t *kRRCenc; - - uint8_t security_activated; - - rlc_mode_t rlc_mode; - uint8_t status_report; - uint8_t seq_num_size; - - logical_chan_id_t lcid; - rb_id_t rb_id; - /* - * Sequence number state variables - * - * TX and RX window - */ - pdcp_sn_t next_pdcp_tx_sn; - pdcp_sn_t next_pdcp_rx_sn; - pdcp_sn_t maximum_pdcp_rx_sn; - /* - * TX and RX Hyper Frame Numbers - */ - pdcp_hfn_t tx_hfn; - pdcp_hfn_t rx_hfn; - - /* - * SN of the last PDCP SDU delivered to upper layers - */ - pdcp_sn_t last_submitted_pdcp_rx_sn; - - /* - * Following array is used as a bitmap holding missing sequence - * numbers to generate a PDCP Control PDU for PDCP status - * report (see 6.2.6) - */ - uint8_t missing_pdu_bitmap[512]; - /* - * This is intentionally signed since we need a 'NULL' value - * which is not also a valid sequence number - */ - short int first_missing_pdu; - -} pdcp_t; - -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) -typedef struct pdcp_mbms_s { - boolean_t instanciated_instance; - rb_id_t rb_id; -} pdcp_mbms_t; -#endif -/* - * Following symbolic constant alters the behaviour of PDCP - * and makes it linked to PDCP test code under targets/TEST/PDCP/ - * - * For the version at SVN repository this should be UNDEFINED! - * XXX And later this should be configured through the Makefile - * under targets/TEST/PDCP/ - */ - -/*! \fn boolean_t pdcp_data_req(const protocol_ctxt_t* const , srb_flag_t , rb_id_t , mui_t , confirm_t ,sdu_size_t , unsigned char* , pdcp_transmission_mode_t ) -* \brief This functions handles data transfer requests coming either from RRC or from IP -* \param[in] ctxt_pP Running context. -* \param[in] rab_id Radio Bearer ID -* \param[in] muiP -* \param[in] confirmP -* \param[in] sdu_buffer_size Size of incoming SDU in bytes -* \param[in] sdu_buffer Buffer carrying SDU -* \param[in] mode flag to indicate whether the userplane data belong to the control plane or data plane or transparent -* \return TRUE on success, FALSE otherwise -* \note None -* @ingroup _pdcp -*/ -boolean_t pdcp_data_req( - protocol_ctxt_t *ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_id, - const mui_t muiP, - const confirm_t confirmP, \ - const sdu_size_t sdu_buffer_size, - unsigned char *const sdu_buffer, - const pdcp_transmission_mode_t mode -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - ,const uint32_t *const sourceL2Id - ,const uint32_t *const destinationL2Id -#endif -); - -/*! \fn boolean_t pdcp_data_ind(const protocol_ctxt_t* const, srb_flag_t, MBMS_flag_t, rb_id_t, sdu_size_t, mem_block_t*, boolean_t) -* \brief This functions handles data transfer indications coming from RLC -* \param[in] ctxt_pP Running context. -* \param[in] Shows if rb is SRB -* \param[in] Tells if MBMS traffic -* \param[in] rab_id Radio Bearer ID -* \param[in] sdu_buffer_size Size of incoming SDU in bytes -* \param[in] sdu_buffer Buffer carrying SDU -* \param[in] is_data_plane flag to indicate whether the userplane data belong to the control plane or data plane -* \return TRUE on success, FALSE otherwise -* \note None -* @ingroup _pdcp -*/ -boolean_t pdcp_data_ind( - const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const MBMS_flag_t MBMS_flagP, - const rb_id_t rb_id, - const sdu_size_t sdu_buffer_size, - mem_block_t *const sdu_buffer); - -/*! \fn void rrc_pdcp_config_req(const protocol_ctxt_t* const ,uint32_t,rb_id_t,uint8_t) -* \brief This functions initializes relevant PDCP entity -* \param[in] ctxt_pP Running context. -* \param[in] actionP flag for action: add, remove , modify -* \param[in] rb_idP Radio Bearer ID of relevant PDCP entity -* \param[in] security_modeP Radio Bearer ID of relevant PDCP entity -* \return none -* \note None -* @ingroup _pdcp -*/ -void rrc_pdcp_config_req ( - const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const uint32_t actionP, - const rb_id_t rb_idP, - const uint8_t security_modeP); - -/*! \fn bool rrc_pdcp_config_asn1_req (const protocol_ctxt_t* const , SRB_ToAddModList_t* srb2add_list, DRB_ToAddModList_t* drb2add_list, DRB_ToReleaseList_t* drb2release_list) -* \brief Function for RRC to configure a Radio Bearer. -* \param[in] ctxt_pP Running context. -* \param[in] index index of UE or eNB depending on the eNB_flag -* \param[in] srb2add_list SRB configuration list to be created. -* \param[in] drb2add_list DRB configuration list to be created. -* \param[in] drb2release_list DRB configuration list to be released. -* \param[in] security_mode Security algorithm to apply for integrity/ciphering -* \param[in] kRRCenc RRC encryption key -* \param[in] kRRCint RRC integrity key -* \param[in] kUPenc User-Plane encryption key -* \param[in] defaultDRB Default DRB ID -* \return A status about the processing, OK or error code. -*/ -boolean_t rrc_pdcp_config_asn1_req ( - const protocol_ctxt_t *const ctxt_pP, - LTE_SRB_ToAddModList_t *const srb2add_list, - LTE_DRB_ToAddModList_t *const drb2add_list, - LTE_DRB_ToReleaseList_t *const drb2release_list, - const uint8_t security_modeP, - uint8_t *const kRRCenc, - uint8_t *const kRRCint, - uint8_t *const kUPenc -#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) - ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 -#endif - ,rb_id_t *const defaultDRB -); - -/*! \fn boolean_t pdcp_config_req_asn1 (const protocol_ctxt_t* const ctxt_pP, srb_flag_t srb_flagP, uint32_t action, rb_id_t rb_id, uint8_t rb_sn, uint8_t rb_report, uint16_t header_compression_profile, uint8_t security_mode) -* \brief Function for RRC to configure a Radio Bearer. -* \param[in] ctxt_pP Running context. -* \param[in] pdcp_pP Pointer on PDCP structure. -* \param[in] enb_mod_idP Virtualized enb module identifier, Not used if eNB_flagP = 0. -* \param[in] ue_mod_idP Virtualized ue module identifier. -* \param[in] frame Frame index. -* \param[in] eNB_flag Flag to indicate eNB (1) or UE (0) -* \param[in] srb_flagP Flag to indicate SRB (1) or DRB (0) -* \param[in] action add, remove, modify a RB -* \param[in] rb_id radio bearer id -* \param[in] rb_sn sequence number for this radio bearer -* \param[in] drb_report set a pdcp report for this drb -* \param[in] header_compression set the rohc profile -* \param[in] security_mode set the integrity and ciphering algs -* \param[in] kRRCenc RRC encryption key -* \param[in] kRRCint RRC integrity key -* \param[in] kUPenc User-Plane encryption key -* \return A status about the processing, OK or error code. -*/ -boolean_t pdcp_config_req_asn1 ( - const protocol_ctxt_t *const ctxt_pP, - pdcp_t *const pdcp_pP, - const srb_flag_t srb_flagP, - const rlc_mode_t rlc_mode, - const uint32_t action, - const uint16_t lc_id, - const uint16_t mch_id, - const rb_id_t rb_id, - const uint8_t rb_sn, - const uint8_t rb_report, - const uint16_t header_compression_profile, - const uint8_t security_mode, - uint8_t *const kRRCenc, - uint8_t *const kRRCint, - uint8_t *const kUPenc); - -/*! \fn void pdcp_add_UE(const protocol_ctxt_t* const ctxt_pP) -* \brief Function (for RRC) to add a new UE in PDCP module -* \param[in] ctxt_pP Running context. -* \return A status about the processing, OK or error code. -*/ -void pdcp_add_UE(const protocol_ctxt_t *const ctxt_pP); - -/*! \fn boolean_t pdcp_remove_UE(const protocol_ctxt_t* const ctxt_pP) -* \brief Function for RRC to remove UE from PDCP module hashtable -* \param[in] ctxt_pP Running context. -* \return A status about the processing, OK or error code. -*/ -boolean_t pdcp_remove_UE( - const protocol_ctxt_t *const ctxt_pP); - -/*! \fn void rrc_pdcp_config_release( const protocol_ctxt_t* const, rb_id_t) -* \brief This functions is unused -* \param[in] ctxt_pP Running context. -* \param[in] rab_id Radio Bearer ID of relevant PDCP entity -* \return none -* \note None -* @ingroup _pdcp -*/ -//void rrc_pdcp_config_release ( const protocol_ctxt_t* const ctxt_pP, rb_id_t); - -/*! \fn void pdcp_run(const protocol_ctxt_t* const ctxt_pP) -* \brief Runs PDCP entity to let it handle incoming/outgoing SDUs -* \param[in] ctxt_pP Running context. -* \return none -* \note None -* @ingroup _pdcp -*/ -void pdcp_run ( - const protocol_ctxt_t *const ctxt_pP); -uint64_t pdcp_module_init (uint64_t pdcp_optmask); -void pdcp_module_cleanup (void); -void pdcp_layer_init (void); -void pdcp_layer_cleanup (void); -#define PDCP2NW_DRIVER_FIFO 21 -#define NW_DRIVER2PDCP_FIFO 22 - -int pdcp_fifo_flush_sdus ( const protocol_ctxt_t *const ctxt_pP); -int pdcp_fifo_read_input_sdus_remaining_bytes ( const protocol_ctxt_t *const ctxt_pP); -int pdcp_fifo_read_input_sdus ( const protocol_ctxt_t *const ctxt_pP); -void pdcp_fifo_read_input_sdus_from_otg ( const protocol_ctxt_t *const ctxt_pP); -void pdcp_set_rlc_data_req_func(send_rlc_data_req_func_t send_rlc_data_req); -void pdcp_set_pdcp_data_ind_func(pdcp_data_ind_func_t pdcp_data_ind); -pdcp_data_ind_func_t get_pdcp_data_ind_func(void); - -//----------------------------------------------------------------------------- - -/* - * Following two types are utilized between NAS driver and PDCP - */ - - -typedef struct pdcp_data_req_header_s { - rb_id_t rb_id; - sdu_size_t data_size; - signed int inst; - ip_traffic_type_t traffic_type; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - uint32_t sourceL2Id; - uint32_t destinationL2Id; -#endif -} pdcp_data_req_header_t; - -typedef struct pdcp_data_ind_header_s { - rb_id_t rb_id; - sdu_size_t data_size; - signed int inst; - ip_traffic_type_t dummy_traffic_type; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - uint32_t sourceL2Id; - uint32_t destinationL2Id; -#endif -} pdcp_data_ind_header_t; - -struct pdcp_netlink_element_s { - pdcp_data_req_header_t pdcp_read_header; - - /* Data part of the message */ - uint8_t *data; -}; - -//TTN for D2D (PC5S) -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) -#define PDCP_SOCKET_PORT_NO 9999 //temporary value -#define PC5_SIGNALLING_PAYLOAD_SIZE 100 //should be updated with a correct value -int pdcp_pc5_sockfd; -struct sockaddr_in prose_ctrl_addr; -struct sockaddr_in prose_pdcp_addr; -struct sockaddr_in pdcp_sin; -void pdcp_pc5_socket_init(void); - -typedef struct { - rb_id_t rb_id; - sdu_size_t data_size; - signed int inst; - ip_traffic_type_t traffic_type; - uint32_t sourceL2Id; - uint32_t destinationL2Id; -} __attribute__((__packed__)) pc5s_header_t; - -//new PC5S-message -typedef struct { - unsigned char bytes[PC5_SIGNALLING_PAYLOAD_SIZE]; -} __attribute__((__packed__)) PC5SignallingMessage ; - -//example of PC5-S messages -typedef struct { - pc5s_header_t pc5s_header; - union { - uint8_t status; - PC5SignallingMessage pc5_signalling_message; - } pc5sPrimitive; -} __attribute__((__packed__)) sidelink_pc5s_element; - - -#endif - -/* - * PDCP limit values - */ -#define PDCP_MAX_SDU_SIZE 8188 // octets, see 4.3.1 Services provided to upper layers -#define PDCP_MAX_SN_5BIT 31 // 2^5-1 -#define PDCP_MAX_SN_7BIT 127 // 2^7-1 -#define PDCP_MAX_SN_12BIT 4095 // 2^12-1 - -/* - * Reordering_Window: half of the PDCP SN space - */ -#define REORDERING_WINDOW_SN_5BIT 16 -#define REORDERING_WINDOW_SN_7BIT 64 -#define REORDERING_WINDOW_SN_12BIT 2048 - -signed int pdcp_2_nas_irq; -pdcp_stats_t UE_pdcp_stats[MAX_MOBILES_PER_ENB]; -pdcp_stats_t eNB_pdcp_stats[NUMBER_OF_eNB_MAX]; - - -// for UE code conly -rnti_t pdcp_UE_UE_module_id_to_rnti[MAX_MOBILES_PER_ENB]; -rnti_t pdcp_eNB_UE_instance_to_rnti[MAX_MOBILES_PER_ENB]; // for noS1 mode -unsigned int pdcp_eNB_UE_instance_to_rnti_index; -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) - pdcp_mbms_t pdcp_mbms_array_ue[MAX_MOBILES_PER_ENB][LTE_maxServiceCount][LTE_maxSessionPerPMCH]; // some constants from openair2/RRC/LTE/MESSAGES/asn1_constants.h - pdcp_mbms_t pdcp_mbms_array_eNB[NUMBER_OF_eNB_MAX][LTE_maxServiceCount][LTE_maxSessionPerPMCH]; // some constants from openair2/RRC/LTE/MESSAGES/asn1_constants.h -#endif -sdu_size_t pdcp_output_sdu_bytes_to_write; -sdu_size_t pdcp_output_header_bytes_to_write; -list_t pdcp_sdu_list; -int pdcp_sent_a_sdu; -pdcp_data_req_header_t pdcp_input_header; -unsigned char pdcp_input_sdu_buffer[MAX_IP_PACKET_SIZE]; -sdu_size_t pdcp_input_index_header; -sdu_size_t pdcp_input_sdu_size_read; -sdu_size_t pdcp_input_sdu_remaining_size_to_read; - -#define PDCP_COLL_KEY_VALUE(mODULE_iD, rNTI, iS_eNB, rB_iD, iS_sRB) \ - ((hash_key_t)mODULE_iD | \ - (((hash_key_t)(rNTI)) << 8) | \ - (((hash_key_t)(iS_eNB)) << 24) | \ - (((hash_key_t)(rB_iD)) << 25) | \ - (((hash_key_t)(iS_sRB)) << 33) | \ - (((hash_key_t)(0x55)) << 34)) - -// hash key to the same PDCP as indexed by PDCP_COLL_KEY_VALUE(... rB_iD, iS_sRB=0) where rB_iD -// is the default DRB ID. The hidden code 0x55 indicates the key is indexed by (rB_iD,is_sRB) -// whereas the hidden code 0xaa indicates the key is for default DRB only -#define PDCP_COLL_KEY_DEFAULT_DRB_VALUE(mODULE_iD, rNTI, iS_eNB) \ - ((hash_key_t)mODULE_iD | \ - (((hash_key_t)(rNTI)) << 8) | \ - (((hash_key_t)(iS_eNB)) << 24) | \ - (((hash_key_t)(0xff)) << 25) | \ - (((hash_key_t)(0x00)) << 33) | \ - (((hash_key_t)(0xaa)) << 34)) - -// service id max val is maxServiceCount = 16 (asn1_constants.h) - -#define PDCP_COLL_KEY_MBMS_VALUE(mODULE_iD, rNTI, iS_eNB, sERVICE_ID, sESSION_ID) \ - ((hash_key_t)mODULE_iD | \ - (((hash_key_t)(rNTI)) << 8) | \ - (((hash_key_t)(iS_eNB)) << 24) | \ - (((hash_key_t)(sERVICE_ID)) << 32) | \ - (((hash_key_t)(sESSION_ID)) << 37) | \ - (((hash_key_t)(0x0000000000000001)) << 63)) - -extern hash_table_t *pdcp_coll_p; - -#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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file LAYER2/PDCP_v10.1.0/pdcp.h +* \brief pdcp interface with RLC, RRC +* \author Lionel GAUTHIER and Navid Nikaein +* \date 2009-2012 +* \version 1.0 +*/ + +/** @defgroup _pdcp PDCP +* @ingroup _oai2 +* @{ +*/ + +#ifndef __PDCP_H__ +# define __PDCP_H__ +//----------------------------------------------------------------------------- +#ifndef NON_ACCESS_STRATUM + #include "UTIL/MEM/mem_block.h" + #include "UTIL/LISTS/list.h" +#endif //NON_ACCESS_STRATUM +//----------------------------------------------------------------------------- +#include "RRC/LTE/rrc_defs.h" +#include "COMMON/platform_constants.h" +#include "COMMON/platform_types.h" +#include "LTE_DRB-ToAddMod.h" +#include "LTE_DRB-ToAddModList.h" +#include "LTE_SRB-ToAddMod.h" +#include "LTE_SRB-ToAddModList.h" +#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) + #include "LTE_MBMS-SessionInfoList-r9.h" + #include "LTE_PMCH-InfoList-r9.h" +#endif + +typedef rlc_op_status_t (*send_rlc_data_req_func_t)(const protocol_ctxt_t *const, + const srb_flag_t, const MBMS_flag_t, + const rb_id_t, const mui_t, + confirm_t, sdu_size_t, mem_block_t *,const uint32_t *const, const uint32_t *const); +typedef boolean_t (*pdcp_data_ind_func_t)( const protocol_ctxt_t *, const srb_flag_t, + const MBMS_flag_t, const rb_id_t, const sdu_size_t, + mem_block_t *,const uint32_t *const, const uint32_t *const); +/* maximum number of tun interfaces that will be created to emulates UEs */ +/* UEs beyond that will be multiplexed on the same tun */ +#define MAX_NUMBER_NETIF 16 + +#define PDCP_USE_NETLINK_BIT (1<< 11) +#define LINK_ENB_PDCP_TO_IP_DRIVER_BIT (1<< 13) +#define LINK_ENB_PDCP_TO_GTPV1U_BIT (1<< 14) +#define UE_NAS_USE_TUN_BIT (1<< 15) +#define ENB_NAS_USE_TUN_BIT (1<< 16) +typedef struct { + uint64_t optmask; + send_rlc_data_req_func_t send_rlc_data_req_func; + pdcp_data_ind_func_t pdcp_data_ind_func; +} pdcp_params_t; + + + +#define PDCP_USE_NETLINK ( get_pdcp_optmask() & PDCP_USE_NETLINK_BIT) +#define LINK_ENB_PDCP_TO_IP_DRIVER ( get_pdcp_optmask() & LINK_ENB_PDCP_TO_IP_DRIVER_BIT) +#define LINK_ENB_PDCP_TO_GTPV1U ( get_pdcp_optmask() & LINK_ENB_PDCP_TO_GTPV1U_BIT) +#define UE_NAS_USE_TUN ( get_pdcp_optmask() & UE_NAS_USE_TUN_BIT) +#define ENB_NAS_USE_TUN ( get_pdcp_optmask() & ENB_NAS_USE_TUN_BIT) +uint64_t get_pdcp_optmask(void); + +extern pthread_t pdcp_thread; +extern pthread_attr_t pdcp_thread_attr; +extern pthread_mutex_t pdcp_mutex; +extern pthread_cond_t pdcp_cond; +extern int pdcp_instance_cnt; + +#define PROTOCOL_PDCP_CTXT_FMT PROTOCOL_CTXT_FMT"[%s %02u] " + +#define PROTOCOL_PDCP_CTXT_ARGS(CTXT_Pp, pDCP_Pp) PROTOCOL_CTXT_ARGS(CTXT_Pp),\ + (pDCP_Pp->is_srb) ? "SRB" : "DRB",\ + pDCP_Pp->rb_id +int init_pdcp_thread(void); +void cleanup_pdcp_thread(void); + +uint32_t Pdcp_stats_tx_window_ms[MAX_eNB][MAX_MOBILES_PER_ENB]; +uint32_t Pdcp_stats_tx_bytes[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_bytes_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_bytes_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_sn[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_throughput_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_aiat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_aiat_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_aiat_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_tx_iat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; + +uint32_t Pdcp_stats_rx_window_ms[MAX_eNB][MAX_MOBILES_PER_ENB]; +uint32_t Pdcp_stats_rx[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_bytes[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_bytes_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_bytes_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_sn[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_goodput_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_aiat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_aiat_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_aiat_tmp_w[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_iat[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; +uint32_t Pdcp_stats_rx_outoforder[MAX_eNB][MAX_MOBILES_PER_ENB][NB_RB_MAX]; + +void pdcp_update_perioidical_stats(const protocol_ctxt_t *const ctxt_pP); + + +/*Packet Probing for agent PDCP*/ +//uint64_t *pdcp_packet_counter; +//uint64_t *pdcp_size_packet; +typedef struct pdcp_enb_s { + // used for eNB stats generation + uint16_t uid[MAX_MOBILES_PER_ENB]; + rnti_t rnti[MAX_MOBILES_PER_ENB]; + uint16_t num_ues; + + uint64_t sfn; + frame_t frame; + sub_frame_t subframe; + +} pdcp_enb_t; + +pdcp_enb_t pdcp_enb[MAX_NUM_CCs]; + +typedef struct pdcp_stats_s { + time_stats_t pdcp_run; + time_stats_t data_req; + time_stats_t data_ind; + time_stats_t apply_security; // + time_stats_t validate_security; + time_stats_t pdcp_ip; + time_stats_t ip_pdcp; // separte thread +} pdcp_stats_t; // common to eNB and UE + + +typedef struct pdcp_s { + //boolean_t instanciated_instance; + uint16_t header_compression_profile; + + /* SR: added this flag to distinguish UE/eNB instance as pdcp_run for virtual + * mode can receive data on NETLINK for eNB while eNB_flag = 0 and for UE when eNB_flag = 1 + */ + boolean_t is_ue; + boolean_t is_srb; + + /* Configured security algorithms */ + uint8_t cipheringAlgorithm; + uint8_t integrityProtAlgorithm; + + /* User-Plane encryption key + * Control-Plane RRC encryption key + * Control-Plane RRC integrity key + * These keys are configured by RRC layer + */ + uint8_t *kUPenc; + uint8_t *kRRCint; + uint8_t *kRRCenc; + + uint8_t security_activated; + + rlc_mode_t rlc_mode; + uint8_t status_report; + uint8_t seq_num_size; + + logical_chan_id_t lcid; + rb_id_t rb_id; + /* + * Sequence number state variables + * + * TX and RX window + */ + pdcp_sn_t next_pdcp_tx_sn; + pdcp_sn_t next_pdcp_rx_sn; + pdcp_sn_t maximum_pdcp_rx_sn; + /* + * TX and RX Hyper Frame Numbers + */ + pdcp_hfn_t tx_hfn; + pdcp_hfn_t rx_hfn; + + /* + * SN of the last PDCP SDU delivered to upper layers + */ + pdcp_sn_t last_submitted_pdcp_rx_sn; + + /* + * Following array is used as a bitmap holding missing sequence + * numbers to generate a PDCP Control PDU for PDCP status + * report (see 6.2.6) + */ + uint8_t missing_pdu_bitmap[512]; + /* + * This is intentionally signed since we need a 'NULL' value + * which is not also a valid sequence number + */ + short int first_missing_pdu; + +} pdcp_t; + +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) +typedef struct pdcp_mbms_s { + boolean_t instanciated_instance; + rb_id_t rb_id; +} pdcp_mbms_t; +#endif +/* + * Following symbolic constant alters the behaviour of PDCP + * and makes it linked to PDCP test code under targets/TEST/PDCP/ + * + * For the version at SVN repository this should be UNDEFINED! + * XXX And later this should be configured through the Makefile + * under targets/TEST/PDCP/ + */ + +/*! \fn boolean_t pdcp_data_req(const protocol_ctxt_t* const , srb_flag_t , rb_id_t , mui_t , confirm_t ,sdu_size_t , unsigned char* , pdcp_transmission_mode_t ) +* \brief This functions handles data transfer requests coming either from RRC or from IP +* \param[in] ctxt_pP Running context. +* \param[in] rab_id Radio Bearer ID +* \param[in] muiP +* \param[in] confirmP +* \param[in] sdu_buffer_size Size of incoming SDU in bytes +* \param[in] sdu_buffer Buffer carrying SDU +* \param[in] mode flag to indicate whether the userplane data belong to the control plane or data plane or transparent +* \return TRUE on success, FALSE otherwise +* \note None +* @ingroup _pdcp +*/ +boolean_t pdcp_data_req( + protocol_ctxt_t *ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_id, + const mui_t muiP, + const confirm_t confirmP, \ + const sdu_size_t sdu_buffer_size, + unsigned char *const sdu_buffer, + const pdcp_transmission_mode_t mode +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,const uint32_t *const sourceL2Id + ,const uint32_t *const destinationL2Id +#endif +); + +/*! \fn boolean_t pdcp_data_ind(const protocol_ctxt_t* const, srb_flag_t, MBMS_flag_t, rb_id_t, sdu_size_t, mem_block_t*, boolean_t) +* \brief This functions handles data transfer indications coming from RLC +* \param[in] ctxt_pP Running context. +* \param[in] Shows if rb is SRB +* \param[in] Tells if MBMS traffic +* \param[in] rab_id Radio Bearer ID +* \param[in] sdu_buffer_size Size of incoming SDU in bytes +* \param[in] sdu_buffer Buffer carrying SDU +* \param[in] is_data_plane flag to indicate whether the userplane data belong to the control plane or data plane +* \return TRUE on success, FALSE otherwise +* \note None +* @ingroup _pdcp +*/ +boolean_t pdcp_data_ind( + const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_id, + const sdu_size_t sdu_buffer_size, + mem_block_t *const sdu_buffer); + +/*! \fn void rrc_pdcp_config_req(const protocol_ctxt_t* const ,uint32_t,rb_id_t,uint8_t) +* \brief This functions initializes relevant PDCP entity +* \param[in] ctxt_pP Running context. +* \param[in] actionP flag for action: add, remove , modify +* \param[in] rb_idP Radio Bearer ID of relevant PDCP entity +* \param[in] security_modeP Radio Bearer ID of relevant PDCP entity +* \return none +* \note None +* @ingroup _pdcp +*/ +void rrc_pdcp_config_req ( + const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const uint32_t actionP, + const rb_id_t rb_idP, + const uint8_t security_modeP); + +/*! \fn bool rrc_pdcp_config_asn1_req (const protocol_ctxt_t* const , SRB_ToAddModList_t* srb2add_list, DRB_ToAddModList_t* drb2add_list, DRB_ToReleaseList_t* drb2release_list) +* \brief Function for RRC to configure a Radio Bearer. +* \param[in] ctxt_pP Running context. +* \param[in] index index of UE or eNB depending on the eNB_flag +* \param[in] srb2add_list SRB configuration list to be created. +* \param[in] drb2add_list DRB configuration list to be created. +* \param[in] drb2release_list DRB configuration list to be released. +* \param[in] security_mode Security algorithm to apply for integrity/ciphering +* \param[in] kRRCenc RRC encryption key +* \param[in] kRRCint RRC integrity key +* \param[in] kUPenc User-Plane encryption key +* \param[in] defaultDRB Default DRB ID +* \return A status about the processing, OK or error code. +*/ +boolean_t rrc_pdcp_config_asn1_req ( + const protocol_ctxt_t *const ctxt_pP, + LTE_SRB_ToAddModList_t *const srb2add_list, + LTE_DRB_ToAddModList_t *const drb2add_list, + LTE_DRB_ToReleaseList_t *const drb2release_list, + const uint8_t security_modeP, + uint8_t *const kRRCenc, + uint8_t *const kRRCint, + uint8_t *const kUPenc +#if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) + ,LTE_PMCH_InfoList_r9_t *pmch_InfoList_r9 +#endif + ,rb_id_t *const defaultDRB +); + +/*! \fn boolean_t pdcp_config_req_asn1 (const protocol_ctxt_t* const ctxt_pP, srb_flag_t srb_flagP, uint32_t action, rb_id_t rb_id, uint8_t rb_sn, uint8_t rb_report, uint16_t header_compression_profile, uint8_t security_mode) +* \brief Function for RRC to configure a Radio Bearer. +* \param[in] ctxt_pP Running context. +* \param[in] pdcp_pP Pointer on PDCP structure. +* \param[in] enb_mod_idP Virtualized enb module identifier, Not used if eNB_flagP = 0. +* \param[in] ue_mod_idP Virtualized ue module identifier. +* \param[in] frame Frame index. +* \param[in] eNB_flag Flag to indicate eNB (1) or UE (0) +* \param[in] srb_flagP Flag to indicate SRB (1) or DRB (0) +* \param[in] action add, remove, modify a RB +* \param[in] rb_id radio bearer id +* \param[in] rb_sn sequence number for this radio bearer +* \param[in] drb_report set a pdcp report for this drb +* \param[in] header_compression set the rohc profile +* \param[in] security_mode set the integrity and ciphering algs +* \param[in] kRRCenc RRC encryption key +* \param[in] kRRCint RRC integrity key +* \param[in] kUPenc User-Plane encryption key +* \return A status about the processing, OK or error code. +*/ +boolean_t pdcp_config_req_asn1 ( + const protocol_ctxt_t *const ctxt_pP, + pdcp_t *const pdcp_pP, + const srb_flag_t srb_flagP, + const rlc_mode_t rlc_mode, + const uint32_t action, + const uint16_t lc_id, + const uint16_t mch_id, + const rb_id_t rb_id, + const uint8_t rb_sn, + const uint8_t rb_report, + const uint16_t header_compression_profile, + const uint8_t security_mode, + uint8_t *const kRRCenc, + uint8_t *const kRRCint, + uint8_t *const kUPenc); + +/*! \fn void pdcp_add_UE(const protocol_ctxt_t* const ctxt_pP) +* \brief Function (for RRC) to add a new UE in PDCP module +* \param[in] ctxt_pP Running context. +* \return A status about the processing, OK or error code. +*/ +void pdcp_add_UE(const protocol_ctxt_t *const ctxt_pP); + +/*! \fn boolean_t pdcp_remove_UE(const protocol_ctxt_t* const ctxt_pP) +* \brief Function for RRC to remove UE from PDCP module hashtable +* \param[in] ctxt_pP Running context. +* \return A status about the processing, OK or error code. +*/ +boolean_t pdcp_remove_UE( + const protocol_ctxt_t *const ctxt_pP); + +/*! \fn void rrc_pdcp_config_release( const protocol_ctxt_t* const, rb_id_t) +* \brief This functions is unused +* \param[in] ctxt_pP Running context. +* \param[in] rab_id Radio Bearer ID of relevant PDCP entity +* \return none +* \note None +* @ingroup _pdcp +*/ +//void rrc_pdcp_config_release ( const protocol_ctxt_t* const ctxt_pP, rb_id_t); + +/*! \fn void pdcp_run(const protocol_ctxt_t* const ctxt_pP) +* \brief Runs PDCP entity to let it handle incoming/outgoing SDUs +* \param[in] ctxt_pP Running context. +* \return none +* \note None +* @ingroup _pdcp +*/ +void pdcp_run ( + const protocol_ctxt_t *const ctxt_pP); +uint64_t pdcp_module_init (uint64_t pdcp_optmask); +void pdcp_module_cleanup (void); +void pdcp_layer_init (void); +void pdcp_layer_cleanup (void); +#define PDCP2NW_DRIVER_FIFO 21 +#define NW_DRIVER2PDCP_FIFO 22 + +int pdcp_fifo_flush_sdus ( const protocol_ctxt_t *const ctxt_pP); +int pdcp_fifo_read_input_sdus_remaining_bytes ( const protocol_ctxt_t *const ctxt_pP); +int pdcp_fifo_read_input_sdus ( const protocol_ctxt_t *const ctxt_pP); +void pdcp_fifo_read_input_sdus_from_otg ( const protocol_ctxt_t *const ctxt_pP); +void pdcp_set_rlc_data_req_func(send_rlc_data_req_func_t send_rlc_data_req); +void pdcp_set_pdcp_data_ind_func(pdcp_data_ind_func_t pdcp_data_ind); +pdcp_data_ind_func_t get_pdcp_data_ind_func(void); +//NB-IoT +void pdcp_layer_init_NB_IoT(void); + +//----------------------------------------------------------------------------- + +/* + * Following two types are utilized between NAS driver and PDCP + */ + + +typedef struct pdcp_data_req_header_s { + rb_id_t rb_id; + sdu_size_t data_size; + signed int inst; + ip_traffic_type_t traffic_type; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + uint32_t sourceL2Id; + uint32_t destinationL2Id; +#endif +} pdcp_data_req_header_t; + +typedef struct pdcp_data_ind_header_s { + rb_id_t rb_id; + sdu_size_t data_size; + signed int inst; + ip_traffic_type_t dummy_traffic_type; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + uint32_t sourceL2Id; + uint32_t destinationL2Id; +#endif +} pdcp_data_ind_header_t; + +struct pdcp_netlink_element_s { + pdcp_data_req_header_t pdcp_read_header; + + /* Data part of the message */ + uint8_t *data; +}; + +//TTN for D2D (PC5S) +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) +#define PDCP_SOCKET_PORT_NO 9999 //temporary value +#define PC5_SIGNALLING_PAYLOAD_SIZE 100 //should be updated with a correct value +int pdcp_pc5_sockfd; +struct sockaddr_in prose_ctrl_addr; +struct sockaddr_in prose_pdcp_addr; +struct sockaddr_in pdcp_sin; +void pdcp_pc5_socket_init(void); + +typedef struct { + rb_id_t rb_id; + sdu_size_t data_size; + signed int inst; + ip_traffic_type_t traffic_type; + uint32_t sourceL2Id; + uint32_t destinationL2Id; +} __attribute__((__packed__)) pc5s_header_t; + +//new PC5S-message +typedef struct { + unsigned char bytes[PC5_SIGNALLING_PAYLOAD_SIZE]; +} __attribute__((__packed__)) PC5SignallingMessage ; + +//example of PC5-S messages +typedef struct { + pc5s_header_t pc5s_header; + union { + uint8_t status; + PC5SignallingMessage pc5_signalling_message; + } pc5sPrimitive; +} __attribute__((__packed__)) sidelink_pc5s_element; + + +#endif + +/* + * PDCP limit values + */ +#define PDCP_MAX_SDU_SIZE 8188 // octets, see 4.3.1 Services provided to upper layers +#define PDCP_MAX_SN_5BIT 31 // 2^5-1 +#define PDCP_MAX_SN_7BIT 127 // 2^7-1 +#define PDCP_MAX_SN_12BIT 4095 // 2^12-1 + +/* + * Reordering_Window: half of the PDCP SN space + */ +#define REORDERING_WINDOW_SN_5BIT 16 +#define REORDERING_WINDOW_SN_7BIT 64 +#define REORDERING_WINDOW_SN_12BIT 2048 + +signed int pdcp_2_nas_irq; +pdcp_stats_t UE_pdcp_stats[MAX_MOBILES_PER_ENB]; +pdcp_stats_t eNB_pdcp_stats[NUMBER_OF_eNB_MAX]; + + +// for UE code conly +rnti_t pdcp_UE_UE_module_id_to_rnti[MAX_MOBILES_PER_ENB]; +rnti_t pdcp_eNB_UE_instance_to_rnti[MAX_MOBILES_PER_ENB]; // for noS1 mode +unsigned int pdcp_eNB_UE_instance_to_rnti_index; +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) + pdcp_mbms_t pdcp_mbms_array_ue[MAX_MOBILES_PER_ENB][LTE_maxServiceCount][LTE_maxSessionPerPMCH]; // some constants from openair2/RRC/LTE/MESSAGES/asn1_constants.h + pdcp_mbms_t pdcp_mbms_array_eNB[NUMBER_OF_eNB_MAX][LTE_maxServiceCount][LTE_maxSessionPerPMCH]; // some constants from openair2/RRC/LTE/MESSAGES/asn1_constants.h +#endif +sdu_size_t pdcp_output_sdu_bytes_to_write; +sdu_size_t pdcp_output_header_bytes_to_write; +list_t pdcp_sdu_list; +int pdcp_sent_a_sdu; +pdcp_data_req_header_t pdcp_input_header; +unsigned char pdcp_input_sdu_buffer[MAX_IP_PACKET_SIZE]; +sdu_size_t pdcp_input_index_header; +sdu_size_t pdcp_input_sdu_size_read; +sdu_size_t pdcp_input_sdu_remaining_size_to_read; + +#define PDCP_COLL_KEY_VALUE(mODULE_iD, rNTI, iS_eNB, rB_iD, iS_sRB) \ + ((hash_key_t)mODULE_iD | \ + (((hash_key_t)(rNTI)) << 8) | \ + (((hash_key_t)(iS_eNB)) << 24) | \ + (((hash_key_t)(rB_iD)) << 25) | \ + (((hash_key_t)(iS_sRB)) << 33) | \ + (((hash_key_t)(0x55)) << 34)) + +// hash key to the same PDCP as indexed by PDCP_COLL_KEY_VALUE(... rB_iD, iS_sRB=0) where rB_iD +// is the default DRB ID. The hidden code 0x55 indicates the key is indexed by (rB_iD,is_sRB) +// whereas the hidden code 0xaa indicates the key is for default DRB only +#define PDCP_COLL_KEY_DEFAULT_DRB_VALUE(mODULE_iD, rNTI, iS_eNB) \ + ((hash_key_t)mODULE_iD | \ + (((hash_key_t)(rNTI)) << 8) | \ + (((hash_key_t)(iS_eNB)) << 24) | \ + (((hash_key_t)(0xff)) << 25) | \ + (((hash_key_t)(0x00)) << 33) | \ + (((hash_key_t)(0xaa)) << 34)) + +// service id max val is maxServiceCount = 16 (asn1_constants.h) + +#define PDCP_COLL_KEY_MBMS_VALUE(mODULE_iD, rNTI, iS_eNB, sERVICE_ID, sESSION_ID) \ + ((hash_key_t)mODULE_iD | \ + (((hash_key_t)(rNTI)) << 8) | \ + (((hash_key_t)(iS_eNB)) << 24) | \ + (((hash_key_t)(sERVICE_ID)) << 32) | \ + (((hash_key_t)(sESSION_ID)) << 37) | \ + (((hash_key_t)(0x0000000000000001)) << 63)) + +extern hash_table_t *pdcp_coll_p; + +#endif +/*@}*/ diff --git a/openair2/LAYER2/RLC/rlc.c b/openair2/LAYER2/RLC/rlc.c index 21dd8863a2ba36d52a09ff7f603f6c0d5aa630ac..a77f974551d732df155f89fc92872b06ae9f6027 100755 --- a/openair2/LAYER2/RLC/rlc.c +++ b/openair2/LAYER2/RLC/rlc.c @@ -1,732 +1,732 @@ -/* - * 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 - */ - -/* - rlc.c - ------------------- - AUTHOR : Lionel GAUTHIER - COMPANY : EURECOM - EMAIL : Lionel.Gauthier at eurecom dot fr -*/ -#define RLC_C -#include "rlc.h" -#include "mem_block.h" -#include "../MAC/mac_extern.h" -#include "LAYER2/RLC/UM_v9.3.0/rlc_um.h" -#include "common/utils/LOG/log.h" -#include "UTIL/OCG/OCG_vars.h" -#include "common/utils/LOG/vcd_signal_dumper.h" -#include "targets/COMMON/openairinterface5g_limits.h" -#include "assertions.h" - -#include "common/ran_context.h" -extern RAN_CONTEXT_t RC; - - -extern boolean_t pdcp_data_ind( - const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const MBMS_flag_t MBMS_flagP, - const rb_id_t rb_idP, - const sdu_size_t sdu_buffer_sizeP, - mem_block_t *const sdu_buffer_pP); - -#define DEBUG_RLC_PDCP_INTERFACE 1 -//#define TRACE_RLC_PAYLOAD 1 -#define DEBUG_RLC_DATA_REQ 1 - -#ifdef NB_IOT -#include "openair2/RRC/LITE/proto_NB_IoT.h" -#undef maxDRB -#define maxDRB maxDRB_NB_r13 -#endif - - -//----------------------------------------------------------------------------- -void rlc_util_print_hex_octets(comp_name_t componentP, unsigned char *dataP, const signed long sizeP) -//----------------------------------------------------------------------------- -{ - unsigned long octet_index = 0; - - if (dataP == NULL) { - return; - } - - LOG_T(componentP, "+-----+-------------------------------------------------+\n"); - LOG_T(componentP, "| | 0 1 2 3 4 5 6 7 8 9 a b c d e f |\n"); - LOG_T(componentP, "+-----+-------------------------------------------------+\n"); - - for (octet_index = 0; octet_index < sizeP; octet_index++) { - if ((octet_index % 16) == 0) { - if (octet_index != 0) { - LOG_T(componentP, " |\n"); - } - - LOG_T(componentP, " %04lu |", octet_index); - } - - /* - * Print every single octet in hexadecimal form - */ - LOG_T(componentP, " %02x", dataP[octet_index]); - /* - * Align newline and pipes according to the octets in groups of 2 - */ - } - - /* - * Append enough spaces and put final pipe - */ - unsigned char index; - - for (index = octet_index; index < 16; ++index) { - LOG_T(componentP, " "); - } - - LOG_T(componentP, " |\n"); -} - -//----------------------------------------------------------------------------- -rlc_op_status_t rlc_stat_req ( - const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - unsigned int *stat_rlc_mode, - unsigned int *stat_tx_pdcp_sdu, - unsigned int *stat_tx_pdcp_bytes, - unsigned int *stat_tx_pdcp_sdu_discarded, - unsigned int *stat_tx_pdcp_bytes_discarded, - unsigned int *stat_tx_data_pdu, - unsigned int *stat_tx_data_bytes, - unsigned int *stat_tx_retransmit_pdu_by_status, - unsigned int *stat_tx_retransmit_bytes_by_status, - unsigned int *stat_tx_retransmit_pdu, - unsigned int *stat_tx_retransmit_bytes, - unsigned int *stat_tx_control_pdu, - unsigned int *stat_tx_control_bytes, - unsigned int *stat_rx_pdcp_sdu, - unsigned int *stat_rx_pdcp_bytes, - unsigned int *stat_rx_data_pdus_duplicate, - unsigned int *stat_rx_data_bytes_duplicate, - unsigned int *stat_rx_data_pdu, - unsigned int *stat_rx_data_bytes, - unsigned int *stat_rx_data_pdu_dropped, - unsigned int *stat_rx_data_bytes_dropped, - unsigned int *stat_rx_data_pdu_out_of_window, - unsigned int *stat_rx_data_bytes_out_of_window, - unsigned int *stat_rx_control_pdu, - unsigned int *stat_rx_control_bytes, - unsigned int *stat_timer_reordering_timed_out, - unsigned int *stat_timer_poll_retransmit_timed_out, - unsigned int *stat_timer_status_prohibit_timed_out) { - //----------------------------------------------------------------------------- - rlc_mode_t rlc_mode = RLC_MODE_NONE; - rlc_union_t *rlc_union_p = NULL; - hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; - hashtable_rc_t h_rc; - - //AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); - if(rb_idP >= NB_RB_MAX) { - LOG_E(RLC, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); - return RLC_OP_STATUS_BAD_PARAMETER; - } - - key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); - h_rc = hashtable_get(rlc_coll_p, key, (void **)&rlc_union_p); - - if (h_rc == HASH_TABLE_OK) { - rlc_mode = rlc_union_p->mode; - } - - *stat_rlc_mode = rlc_mode; - - switch (rlc_mode) { - case RLC_MODE_NONE: - *stat_tx_pdcp_sdu = 0; - *stat_tx_pdcp_bytes = 0; - *stat_tx_pdcp_sdu_discarded = 0; - *stat_tx_pdcp_bytes_discarded = 0; - *stat_tx_data_pdu = 0; - *stat_tx_data_bytes = 0; - *stat_tx_retransmit_pdu_by_status = 0; - *stat_tx_retransmit_bytes_by_status = 0; - *stat_tx_retransmit_pdu = 0; - *stat_tx_retransmit_bytes = 0; - *stat_tx_control_pdu = 0; - *stat_tx_control_bytes = 0; - *stat_rx_pdcp_sdu = 0; - *stat_rx_pdcp_bytes = 0; - *stat_rx_data_pdus_duplicate = 0; - *stat_rx_data_bytes_duplicate = 0; - *stat_rx_data_pdu = 0; - *stat_rx_data_bytes = 0; - *stat_rx_data_pdu_dropped = 0; - *stat_rx_data_bytes_dropped = 0; - *stat_rx_data_pdu_out_of_window = 0; - *stat_rx_data_bytes_out_of_window = 0; - *stat_rx_control_pdu = 0; - *stat_rx_control_bytes = 0; - *stat_timer_reordering_timed_out = 0; - *stat_timer_poll_retransmit_timed_out = 0; - *stat_timer_status_prohibit_timed_out = 0; - return RLC_OP_STATUS_BAD_PARAMETER; - break; - - case RLC_MODE_AM: - rlc_am_stat_req(ctxt_pP, - &rlc_union_p->rlc.am, - stat_tx_pdcp_sdu, - stat_tx_pdcp_bytes, - stat_tx_pdcp_sdu_discarded, - stat_tx_pdcp_bytes_discarded, - stat_tx_data_pdu, - stat_tx_data_bytes, - stat_tx_retransmit_pdu_by_status, - stat_tx_retransmit_bytes_by_status, - stat_tx_retransmit_pdu, - stat_tx_retransmit_bytes, - stat_tx_control_pdu, - stat_tx_control_bytes, - stat_rx_pdcp_sdu, - stat_rx_pdcp_bytes, - stat_rx_data_pdus_duplicate, - stat_rx_data_bytes_duplicate, - stat_rx_data_pdu, - stat_rx_data_bytes, - stat_rx_data_pdu_dropped, - stat_rx_data_bytes_dropped, - stat_rx_data_pdu_out_of_window, - stat_rx_data_bytes_out_of_window, - stat_rx_control_pdu, - stat_rx_control_bytes, - stat_timer_reordering_timed_out, - stat_timer_poll_retransmit_timed_out, - stat_timer_status_prohibit_timed_out); - return RLC_OP_STATUS_OK; - break; - - case RLC_MODE_UM: - *stat_tx_retransmit_pdu_by_status = 0; - *stat_tx_retransmit_bytes_by_status = 0; - *stat_tx_retransmit_pdu = 0; - *stat_tx_retransmit_bytes = 0; - *stat_tx_control_pdu = 0; - *stat_tx_control_bytes = 0; - *stat_rx_data_pdu_dropped = 0; - *stat_rx_data_bytes_dropped = 0; - *stat_rx_data_pdu_out_of_window = 0; - *stat_rx_data_bytes_out_of_window = 0; - *stat_timer_poll_retransmit_timed_out = 0; - *stat_timer_status_prohibit_timed_out = 0; - rlc_um_stat_req (&rlc_union_p->rlc.um, - stat_tx_pdcp_sdu, - stat_tx_pdcp_bytes, - stat_tx_pdcp_sdu_discarded, - stat_tx_pdcp_bytes_discarded, - stat_tx_data_pdu, - stat_tx_data_bytes, - stat_rx_pdcp_sdu, - stat_rx_pdcp_bytes, - stat_rx_data_pdus_duplicate, - stat_rx_data_bytes_duplicate, - stat_rx_data_pdu, - stat_rx_data_bytes, - stat_rx_data_pdu_dropped, - stat_rx_data_bytes_dropped, - stat_rx_data_pdu_out_of_window, - stat_rx_data_bytes_out_of_window, - stat_timer_reordering_timed_out); - return RLC_OP_STATUS_OK; - break; - - case RLC_MODE_TM: - *stat_tx_pdcp_sdu = 0; - *stat_tx_pdcp_bytes = 0; - *stat_tx_pdcp_sdu_discarded = 0; - *stat_tx_pdcp_bytes_discarded = 0; - *stat_tx_data_pdu = 0; - *stat_tx_data_bytes = 0; - *stat_tx_retransmit_pdu_by_status = 0; - *stat_tx_retransmit_bytes_by_status = 0; - *stat_tx_retransmit_pdu = 0; - *stat_tx_retransmit_bytes = 0; - *stat_tx_control_pdu = 0; - *stat_tx_control_bytes = 0; - *stat_rx_pdcp_sdu = 0; - *stat_rx_pdcp_bytes = 0; - *stat_rx_data_pdus_duplicate = 0; - *stat_rx_data_bytes_duplicate = 0; - *stat_rx_data_pdu = 0; - *stat_rx_data_bytes = 0; - *stat_rx_data_pdu_dropped = 0; - *stat_rx_data_bytes_dropped = 0; - *stat_rx_data_pdu_out_of_window = 0; - *stat_rx_data_bytes_out_of_window = 0; - *stat_rx_control_pdu = 0; - *stat_rx_control_bytes = 0; - *stat_timer_reordering_timed_out = 0; - *stat_timer_poll_retransmit_timed_out = 0; - *stat_timer_status_prohibit_timed_out = 0; - return RLC_OP_STATUS_BAD_PARAMETER; - break; - - default: - *stat_tx_pdcp_sdu = 0; - *stat_tx_pdcp_bytes = 0; - *stat_tx_pdcp_sdu_discarded = 0; - *stat_tx_pdcp_bytes_discarded = 0; - *stat_tx_data_pdu = 0; - *stat_tx_data_bytes = 0; - *stat_tx_retransmit_pdu_by_status = 0; - *stat_tx_retransmit_bytes_by_status = 0; - *stat_tx_retransmit_pdu = 0; - *stat_tx_retransmit_bytes = 0; - *stat_tx_control_pdu = 0; - *stat_tx_control_bytes = 0; - *stat_rx_pdcp_sdu = 0; - *stat_rx_pdcp_bytes = 0; - *stat_rx_data_pdus_duplicate = 0; - *stat_rx_data_bytes_duplicate = 0; - *stat_rx_data_pdu = 0; - *stat_rx_data_bytes = 0; - *stat_rx_data_pdu_dropped = 0; - *stat_rx_data_bytes_dropped = 0; - *stat_rx_data_pdu_out_of_window = 0; - *stat_rx_data_bytes_out_of_window = 0; - *stat_rx_control_pdu = 0; - *stat_rx_control_bytes = 0; - *stat_timer_poll_retransmit_timed_out = 0; - *stat_timer_status_prohibit_timed_out = 0; - return RLC_OP_STATUS_BAD_PARAMETER; - } -} - -//----------------------------------------------------------------------------- -rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const MBMS_flag_t MBMS_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - confirm_t confirmP, - sdu_size_t sdu_sizeP, - mem_block_t *sdu_pP -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - ,const uint32_t *const sourceL2Id - ,const uint32_t *const destinationL2Id -#endif - ) { - //----------------------------------------------------------------------------- - mem_block_t *new_sdu_p = NULL; - rlc_mode_t rlc_mode = RLC_MODE_NONE; - rlc_union_t *rlc_union_p = NULL; - hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; - hashtable_rc_t h_rc; -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) - rlc_mbms_id_t *mbms_id_p = NULL; - logical_chan_id_t log_ch_id = 0; -#endif -#ifdef DEBUG_RLC_DATA_REQ - LOG_D(RLC,PROTOCOL_CTXT_FMT"rlc_data_req: rb_id %u (MAX %d), muip %d, confirmP %d, sdu_sizeP %d, sdu_pP %p\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - rb_idP, - NB_RAB_MAX, - muiP, - confirmP, - sdu_sizeP, - sdu_pP); -#endif -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) -#else - AssertFatal(MBMS_flagP == 0, "MBMS_flagP %u", MBMS_flagP); -#endif -#if T_TRACER - - if (ctxt_pP->enb_flag) - T(T_ENB_RLC_DL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_sizeP)); - -#endif - - if (MBMS_flagP) { - //AssertFatal (rb_idP < NB_RB_MBMS_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MBMS_MAX); - if(rb_idP >= NB_RB_MBMS_MAX) { - LOG_E(RLC, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MBMS_MAX); - return RLC_OP_STATUS_BAD_PARAMETER; - } - } else { - //AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); - if(rb_idP >= NB_RB_MAX) { - LOG_E(RLC, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); - return RLC_OP_STATUS_BAD_PARAMETER; - } - } - - //DevAssert(sdu_pP != NULL); - if(sdu_pP == NULL) { - LOG_E(RLC, "sdu_pP == NULL\n"); - return RLC_OP_STATUS_BAD_PARAMETER; - } - - //DevCheck(sdu_sizeP > 0, sdu_sizeP, 0, 0); - if(sdu_sizeP <= 0) { - LOG_E(RLC, "sdu_sizeP %d, file %s, line %d\n", sdu_sizeP, __FILE__,__LINE__); - return RLC_OP_STATUS_BAD_PARAMETER; - } - -#if (LTE_RRC_VERSION < MAKE_VERSION(10, 0, 0)) - DevCheck(MBMS_flagP == 0, MBMS_flagP, 0, 0); -#endif - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_IN); -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) - - if (MBMS_flagP == TRUE) { - if (ctxt_pP->enb_flag) { - log_ch_id = rlc_mbms_enb_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP); - mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][log_ch_id]; - } else { - log_ch_id = rlc_mbms_ue_get_lcid_by_rb_id(ctxt_pP->rnti,rb_idP); - mbms_id_p = &rlc_mbms_lcid2service_session_id_ue[ctxt_pP->rnti][log_ch_id]; - } - - key = RLC_COLL_KEY_MBMS_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, mbms_id_p->service_id, mbms_id_p->session_id); - }else - - if (sourceL2Id && destinationL2Id) { - LOG_D (RLC, "RLC_COLL_KEY_VALUE: ctxt_pP->module_id: %d, ctxt_pP->rnti: %d, ctxt_pP->enb_flag: %d, rb_idP:%d, srb_flagP: %d \n \n", ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, - srb_flagP); - key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); - //Thinh's line originally uncommented - //key = RLC_COLL_KEY_SOURCE_DEST_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, *sourceL2Id, *destinationL2Id, srb_flagP); - //key_lcid = RLC_COLL_KEY_LCID_SOURCE_DEST_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, chan_idP, *sourceL2Id, *destinationL2Id, srb_flagP); - } else -#endif - { - LOG_D (RLC, "RLC_COLL_KEY_VALUE: ctxt_pP->module_id: %d, ctxt_pP->rnti: %d, ctxt_pP->enb_flag: %d, rb_idP:%d, srb_flagP: %d \n \n", ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, - srb_flagP); - key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); - } - - h_rc = hashtable_get(rlc_coll_p, key, (void **)&rlc_union_p); - - if (h_rc == HASH_TABLE_OK) { - rlc_mode = rlc_union_p->mode; - } else { - rlc_mode = RLC_MODE_NONE; - //AssertFatal (0 , "RLC not configured key %ju\n", key); - LOG_E(RLC, "not configured key %lu\n", key); - return RLC_OP_STATUS_OUT_OF_RESSOURCES; - } - - if (MBMS_flagP == 0) { - LOG_D(RLC, PROTOCOL_CTXT_FMT"[RB %u] Display of rlc_data_req:\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - rb_idP); -#if defined(TRACE_RLC_PAYLOAD) - rlc_util_print_hex_octets(RLC, (unsigned char *)sdu_pP->data, sdu_sizeP); -#endif -#ifdef DEBUG_RLC_DATA_REQ - LOG_D(RLC,"RLC_TYPE : %d\n", rlc_mode); -#endif - - switch (rlc_mode) { - case RLC_MODE_NONE: - free_mem_block(sdu_pP, __func__); - LOG_E(RLC, PROTOCOL_CTXT_FMT" Received RLC_MODE_NONE as rlc_type for rb_id %u\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - rb_idP); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - return RLC_OP_STATUS_BAD_PARAMETER; - - case RLC_MODE_AM: -#ifdef DEBUG_RLC_DATA_REQ - LOG_D(RLC,"RLC_MODE_AM\n"); -#endif - new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_am_data_req_alloc), __func__); - - if (new_sdu_p != NULL) { - // PROCESS OF COMPRESSION HERE: - memset (new_sdu_p->data, 0, sizeof (struct rlc_am_data_req_alloc)); - memcpy (&new_sdu_p->data[sizeof (struct rlc_am_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP); - ((struct rlc_am_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP; - ((struct rlc_am_data_req *) (new_sdu_p->data))->conf = confirmP; - ((struct rlc_am_data_req *) (new_sdu_p->data))->mui = muiP; - ((struct rlc_am_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_am_data_req_alloc); - free_mem_block(sdu_pP, __func__); - rlc_am_data_req(ctxt_pP, &rlc_union_p->rlc.am, new_sdu_p); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - return RLC_OP_STATUS_OK; - } else { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - free_mem_block(sdu_pP, __func__); - return RLC_OP_STATUS_INTERNAL_ERROR; - } - - break; - - case RLC_MODE_UM: - - /* TODO: this is a hack, needs better solution. Let's not use too - * much memory and store at maximum 5 millions bytes. - */ - /* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */ - if (rlc_um_get_buffer_occupancy(&rlc_union_p->rlc.um) > 5000000) { - free_mem_block(sdu_pP, __func__); - return RLC_OP_STATUS_OUT_OF_RESSOURCES; - } - - new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_um_data_req_alloc), __func__); - - if (new_sdu_p != NULL) { - // PROCESS OF COMPRESSION HERE: - memset (new_sdu_p->data, 0, sizeof (struct rlc_um_data_req_alloc)); - memcpy (&new_sdu_p->data[sizeof (struct rlc_um_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP); - ((struct rlc_um_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP; - ((struct rlc_um_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_um_data_req_alloc); - free_mem_block(sdu_pP, __func__); - rlc_um_data_req(ctxt_pP, &rlc_union_p->rlc.um, new_sdu_p); - //free_mem_block(new_sdu, __func__); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - return RLC_OP_STATUS_OK; - } else { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - free_mem_block(sdu_pP, __func__); - return RLC_OP_STATUS_INTERNAL_ERROR; - } - - break; - - case RLC_MODE_TM: - new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_tm_data_req_alloc), __func__); - - if (new_sdu_p != NULL) { - // PROCESS OF COMPRESSION HERE: - memset (new_sdu_p->data, 0, sizeof (struct rlc_tm_data_req_alloc)); - memcpy (&new_sdu_p->data[sizeof (struct rlc_tm_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP); - ((struct rlc_tm_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP; - ((struct rlc_tm_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_tm_data_req_alloc); - free_mem_block(sdu_pP, __func__); - rlc_tm_data_req(ctxt_pP, &rlc_union_p->rlc.tm, new_sdu_p); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - return RLC_OP_STATUS_OK; - } else { - //handle_event(ERROR,"FILE %s FONCTION rlc_data_req() LINE %s : out of memory\n", __FILE__, __LINE__); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - free_mem_block(sdu_pP, __func__); - return RLC_OP_STATUS_INTERNAL_ERROR; - } - - break; - - default: - free_mem_block(sdu_pP, __func__); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - return RLC_OP_STATUS_INTERNAL_ERROR; - } - -#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) - } else { /* MBMS_flag != 0 */ - // LOG_I(RLC,"DUY rlc_data_req: mbms_rb_id in RLC instant is: %d\n", mbms_rb_id); - if (sdu_pP != NULL) { - if (sdu_sizeP > 0) { - LOG_I(RLC,"received a packet with size %d for MBMS \n", sdu_sizeP); - new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_um_data_req_alloc), __func__); - - if (new_sdu_p != NULL) { - // PROCESS OF COMPRESSION HERE: - memset (new_sdu_p->data, 0, sizeof (struct rlc_um_data_req_alloc)); - memcpy (&new_sdu_p->data[sizeof (struct rlc_um_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP); - ((struct rlc_um_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP; - ((struct rlc_um_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_um_data_req_alloc); - free_mem_block(sdu_pP, __func__); - rlc_um_data_req(ctxt_pP, &rlc_union_p->rlc.um, new_sdu_p); - //free_mem_block(new_sdu, __func__); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - return RLC_OP_STATUS_OK; - } else { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - free_mem_block(sdu_pP, __func__); - return RLC_OP_STATUS_BAD_PARAMETER; - } - } else { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - return RLC_OP_STATUS_BAD_PARAMETER; - } - } else { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - return RLC_OP_STATUS_BAD_PARAMETER; - } - } - -#else - } else { /* MBMS_flag != 0 */ - free_mem_block(sdu_pP, __func__); - LOG_E(RLC, "MBMS_flag != 0 while Rel10/Rel14 is not defined...\n"); - //handle_event(ERROR,"FILE %s FONCTION rlc_data_req() LINE %s : parameter module_id out of bounds :%d\n", __FILE__, __LINE__, module_idP); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); - return RLC_OP_STATUS_BAD_PARAMETER; - } - -#endif -} - -//----------------------------------------------------------------------------- -void rlc_data_ind ( - const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const MBMS_flag_t MBMS_flagP, - const rb_id_t rb_idP, - const sdu_size_t sdu_sizeP, - mem_block_t *sdu_pP) { - //----------------------------------------------------------------------------- - LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u] Display of rlc_data_ind: size %u\n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - (srb_flagP) ? "SRB" : "DRB", - rb_idP, - sdu_sizeP); - rlc_util_print_hex_octets(RLC, (unsigned char *)sdu_pP->data, sdu_sizeP); - - if (ctxt_pP->enb_flag) { -#if T_TRACER - T(T_ENB_RLC_UL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_sizeP)); -#endif - const ngran_node_t type = RC.rrc[ctxt_pP->module_id]->node_type; - AssertFatal(type != ngran_eNB_CU && type != ngran_ng_eNB_CU && type != ngran_gNB_CU, - "Can't be CU, bad node type %d\n", type); - - if (NODE_IS_DU(type) && srb_flagP == 1) { - MessageDef *msg = itti_alloc_new_message(TASK_RLC_ENB, F1AP_UL_RRC_MESSAGE); - F1AP_UL_RRC_MESSAGE(msg).rnti = ctxt_pP->rnti; - F1AP_UL_RRC_MESSAGE(msg).srb_id = rb_idP; - F1AP_UL_RRC_MESSAGE(msg).rrc_container = sdu_pP->data; - F1AP_UL_RRC_MESSAGE(msg).rrc_container_length = sdu_sizeP; - itti_send_msg_to_task(TASK_DU_F1, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), msg); - return; - } - } // case monolithic eNodeB or UE - -/*************************For SRB1bis (RLC->RRC)*****************************/ - if (rb_idP == 3){ - - rrc_data_ind( - ctxt_pP, - rb_idP, - 51, - (uint8_t*)&sdu_pP->data[0]); - -/***************************************************************************/ - - -/* - pdcp_data_ind ( - ctxt_pP, - srb_flagP, - MBMS_flagP, - rb_idP, - sdu_sizeP, - sdu_pP); -*/ - } - else{ - get_pdcp_data_ind_func()(ctxt_pP, srb_flagP, MBMS_flagP, rb_idP, sdu_sizeP, sdu_pP, NULL, NULL); - } -} - -//----------------------------------------------------------------------------- -void rlc_data_conf (const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - const rlc_tx_status_t statusP) { - //----------------------------------------------------------------------------- - if (srb_flagP) { - if (rlc_rrc_data_conf != NULL) { - rlc_rrc_data_conf (ctxt_pP, rb_idP, muiP, statusP); - } - } -} -//----------------------------------------------------------------------------- -int -rlc_module_init (void) { - //----------------------------------------------------------------------------- - int k; - module_id_t module_id1; - /* for no gcc warnings */ - (void)k; - LOG_D(RLC, "MODULE INIT\n"); - rlc_rrc_data_ind = NULL; - rlc_rrc_data_conf = NULL; - -#ifdef NB_IOT - //MP: change variable maxDRB for NB-IoT --> see ifdef at the beginning - rlc_rrc_data_ind_NB_IoT = NULL; -#endif - - rlc_coll_p = hashtable_create ((LTE_maxDRB + 2) * NUMBER_OF_UE_MAX, NULL, rb_free_rlc_union); - - //AssertFatal(rlc_coll_p != NULL, "UNRECOVERABLE error, RLC hashtable_create failed"); - if(rlc_coll_p == NULL) { - LOG_E(RLC, "UNRECOVERABLE error, RLC hashtable_create failed\n"); - return -1; - } - - for (module_id1=0; module_id1 < MAX_MOBILES_PER_ENB; module_id1++) { - for (k=0; k < RLC_MAX_MBMS_LC; k++) { - rlc_mbms_lcid2service_session_id_ue[module_id1][k].service_id = 0; - rlc_mbms_lcid2service_session_id_ue[module_id1][k].session_id = 0; - } - - for (k=0; k < NB_RB_MBMS_MAX; k++) { - rlc_mbms_rbid2lcid_ue[module_id1][k] = RLC_LC_UNALLOCATED; - } - } - - for (k=0; k < RLC_MAX_MBMS_LC; k++) { - rlc_mbms_lcid2service_session_id_eNB[0][k].service_id = 0; - rlc_mbms_lcid2service_session_id_eNB[0][k].session_id = 0; - } - - for (k=0; k < NB_RB_MBMS_MAX; k++) { - rlc_mbms_rbid2lcid_eNB[0][k] = RLC_LC_UNALLOCATED; - } - - pool_buffer_init(); - return(0); -} -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -void -rlc_module_cleanup (void) -//----------------------------------------------------------------------------- -{ - hashtable_destroy(&rlc_coll_p); -} -//----------------------------------------------------------------------------- -void -rlc_layer_init (void) { - //----------------------------------------------------------------------------- -} -//----------------------------------------------------------------------------- -void -rlc_layer_cleanup (void) -//----------------------------------------------------------------------------- -{ -} - +/* + * 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 + */ + +/* + rlc.c + ------------------- + AUTHOR : Lionel GAUTHIER + COMPANY : EURECOM + EMAIL : Lionel.Gauthier at eurecom dot fr +*/ +#define RLC_C +#include "rlc.h" +#include "mem_block.h" +#include "../MAC/mac_extern.h" +#include "LAYER2/RLC/UM_v9.3.0/rlc_um.h" +#include "common/utils/LOG/log.h" +#include "UTIL/OCG/OCG_vars.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "targets/COMMON/openairinterface5g_limits.h" +#include "assertions.h" + +#include "common/ran_context.h" +extern RAN_CONTEXT_t RC; + + +extern boolean_t pdcp_data_ind( + const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_idP, + const sdu_size_t sdu_buffer_sizeP, + mem_block_t *const sdu_buffer_pP); + +#define DEBUG_RLC_PDCP_INTERFACE 1 +//#define TRACE_RLC_PAYLOAD 1 +#define DEBUG_RLC_DATA_REQ 1 + +#ifdef NB_IOT +#include "openair2/RRC/LITE/proto_NB_IoT.h" +#undef maxDRB +#define maxDRB maxDRB_NB_r13 +#endif + + +//----------------------------------------------------------------------------- +void rlc_util_print_hex_octets(comp_name_t componentP, unsigned char *dataP, const signed long sizeP) +//----------------------------------------------------------------------------- +{ + unsigned long octet_index = 0; + + if (dataP == NULL) { + return; + } + + LOG_T(componentP, "+-----+-------------------------------------------------+\n"); + LOG_T(componentP, "| | 0 1 2 3 4 5 6 7 8 9 a b c d e f |\n"); + LOG_T(componentP, "+-----+-------------------------------------------------+\n"); + + for (octet_index = 0; octet_index < sizeP; octet_index++) { + if ((octet_index % 16) == 0) { + if (octet_index != 0) { + LOG_T(componentP, " |\n"); + } + + LOG_T(componentP, " %04lu |", octet_index); + } + + /* + * Print every single octet in hexadecimal form + */ + LOG_T(componentP, " %02x", dataP[octet_index]); + /* + * Align newline and pipes according to the octets in groups of 2 + */ + } + + /* + * Append enough spaces and put final pipe + */ + unsigned char index; + + for (index = octet_index; index < 16; ++index) { + LOG_T(componentP, " "); + } + + LOG_T(componentP, " |\n"); +} + +//----------------------------------------------------------------------------- +rlc_op_status_t rlc_stat_req ( + const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + unsigned int *stat_rlc_mode, + unsigned int *stat_tx_pdcp_sdu, + unsigned int *stat_tx_pdcp_bytes, + unsigned int *stat_tx_pdcp_sdu_discarded, + unsigned int *stat_tx_pdcp_bytes_discarded, + unsigned int *stat_tx_data_pdu, + unsigned int *stat_tx_data_bytes, + unsigned int *stat_tx_retransmit_pdu_by_status, + unsigned int *stat_tx_retransmit_bytes_by_status, + unsigned int *stat_tx_retransmit_pdu, + unsigned int *stat_tx_retransmit_bytes, + unsigned int *stat_tx_control_pdu, + unsigned int *stat_tx_control_bytes, + unsigned int *stat_rx_pdcp_sdu, + unsigned int *stat_rx_pdcp_bytes, + unsigned int *stat_rx_data_pdus_duplicate, + unsigned int *stat_rx_data_bytes_duplicate, + unsigned int *stat_rx_data_pdu, + unsigned int *stat_rx_data_bytes, + unsigned int *stat_rx_data_pdu_dropped, + unsigned int *stat_rx_data_bytes_dropped, + unsigned int *stat_rx_data_pdu_out_of_window, + unsigned int *stat_rx_data_bytes_out_of_window, + unsigned int *stat_rx_control_pdu, + unsigned int *stat_rx_control_bytes, + unsigned int *stat_timer_reordering_timed_out, + unsigned int *stat_timer_poll_retransmit_timed_out, + unsigned int *stat_timer_status_prohibit_timed_out) { + //----------------------------------------------------------------------------- + rlc_mode_t rlc_mode = RLC_MODE_NONE; + rlc_union_t *rlc_union_p = NULL; + hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_rc; + + //AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); + if(rb_idP >= NB_RB_MAX) { + LOG_E(RLC, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); + return RLC_OP_STATUS_BAD_PARAMETER; + } + + key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); + h_rc = hashtable_get(rlc_coll_p, key, (void **)&rlc_union_p); + + if (h_rc == HASH_TABLE_OK) { + rlc_mode = rlc_union_p->mode; + } + + *stat_rlc_mode = rlc_mode; + + switch (rlc_mode) { + case RLC_MODE_NONE: + *stat_tx_pdcp_sdu = 0; + *stat_tx_pdcp_bytes = 0; + *stat_tx_pdcp_sdu_discarded = 0; + *stat_tx_pdcp_bytes_discarded = 0; + *stat_tx_data_pdu = 0; + *stat_tx_data_bytes = 0; + *stat_tx_retransmit_pdu_by_status = 0; + *stat_tx_retransmit_bytes_by_status = 0; + *stat_tx_retransmit_pdu = 0; + *stat_tx_retransmit_bytes = 0; + *stat_tx_control_pdu = 0; + *stat_tx_control_bytes = 0; + *stat_rx_pdcp_sdu = 0; + *stat_rx_pdcp_bytes = 0; + *stat_rx_data_pdus_duplicate = 0; + *stat_rx_data_bytes_duplicate = 0; + *stat_rx_data_pdu = 0; + *stat_rx_data_bytes = 0; + *stat_rx_data_pdu_dropped = 0; + *stat_rx_data_bytes_dropped = 0; + *stat_rx_data_pdu_out_of_window = 0; + *stat_rx_data_bytes_out_of_window = 0; + *stat_rx_control_pdu = 0; + *stat_rx_control_bytes = 0; + *stat_timer_reordering_timed_out = 0; + *stat_timer_poll_retransmit_timed_out = 0; + *stat_timer_status_prohibit_timed_out = 0; + return RLC_OP_STATUS_BAD_PARAMETER; + break; + + case RLC_MODE_AM: + rlc_am_stat_req(ctxt_pP, + &rlc_union_p->rlc.am, + stat_tx_pdcp_sdu, + stat_tx_pdcp_bytes, + stat_tx_pdcp_sdu_discarded, + stat_tx_pdcp_bytes_discarded, + stat_tx_data_pdu, + stat_tx_data_bytes, + stat_tx_retransmit_pdu_by_status, + stat_tx_retransmit_bytes_by_status, + stat_tx_retransmit_pdu, + stat_tx_retransmit_bytes, + stat_tx_control_pdu, + stat_tx_control_bytes, + stat_rx_pdcp_sdu, + stat_rx_pdcp_bytes, + stat_rx_data_pdus_duplicate, + stat_rx_data_bytes_duplicate, + stat_rx_data_pdu, + stat_rx_data_bytes, + stat_rx_data_pdu_dropped, + stat_rx_data_bytes_dropped, + stat_rx_data_pdu_out_of_window, + stat_rx_data_bytes_out_of_window, + stat_rx_control_pdu, + stat_rx_control_bytes, + stat_timer_reordering_timed_out, + stat_timer_poll_retransmit_timed_out, + stat_timer_status_prohibit_timed_out); + return RLC_OP_STATUS_OK; + break; + + case RLC_MODE_UM: + *stat_tx_retransmit_pdu_by_status = 0; + *stat_tx_retransmit_bytes_by_status = 0; + *stat_tx_retransmit_pdu = 0; + *stat_tx_retransmit_bytes = 0; + *stat_tx_control_pdu = 0; + *stat_tx_control_bytes = 0; + *stat_rx_data_pdu_dropped = 0; + *stat_rx_data_bytes_dropped = 0; + *stat_rx_data_pdu_out_of_window = 0; + *stat_rx_data_bytes_out_of_window = 0; + *stat_timer_poll_retransmit_timed_out = 0; + *stat_timer_status_prohibit_timed_out = 0; + rlc_um_stat_req (&rlc_union_p->rlc.um, + stat_tx_pdcp_sdu, + stat_tx_pdcp_bytes, + stat_tx_pdcp_sdu_discarded, + stat_tx_pdcp_bytes_discarded, + stat_tx_data_pdu, + stat_tx_data_bytes, + stat_rx_pdcp_sdu, + stat_rx_pdcp_bytes, + stat_rx_data_pdus_duplicate, + stat_rx_data_bytes_duplicate, + stat_rx_data_pdu, + stat_rx_data_bytes, + stat_rx_data_pdu_dropped, + stat_rx_data_bytes_dropped, + stat_rx_data_pdu_out_of_window, + stat_rx_data_bytes_out_of_window, + stat_timer_reordering_timed_out); + return RLC_OP_STATUS_OK; + break; + + case RLC_MODE_TM: + *stat_tx_pdcp_sdu = 0; + *stat_tx_pdcp_bytes = 0; + *stat_tx_pdcp_sdu_discarded = 0; + *stat_tx_pdcp_bytes_discarded = 0; + *stat_tx_data_pdu = 0; + *stat_tx_data_bytes = 0; + *stat_tx_retransmit_pdu_by_status = 0; + *stat_tx_retransmit_bytes_by_status = 0; + *stat_tx_retransmit_pdu = 0; + *stat_tx_retransmit_bytes = 0; + *stat_tx_control_pdu = 0; + *stat_tx_control_bytes = 0; + *stat_rx_pdcp_sdu = 0; + *stat_rx_pdcp_bytes = 0; + *stat_rx_data_pdus_duplicate = 0; + *stat_rx_data_bytes_duplicate = 0; + *stat_rx_data_pdu = 0; + *stat_rx_data_bytes = 0; + *stat_rx_data_pdu_dropped = 0; + *stat_rx_data_bytes_dropped = 0; + *stat_rx_data_pdu_out_of_window = 0; + *stat_rx_data_bytes_out_of_window = 0; + *stat_rx_control_pdu = 0; + *stat_rx_control_bytes = 0; + *stat_timer_reordering_timed_out = 0; + *stat_timer_poll_retransmit_timed_out = 0; + *stat_timer_status_prohibit_timed_out = 0; + return RLC_OP_STATUS_BAD_PARAMETER; + break; + + default: + *stat_tx_pdcp_sdu = 0; + *stat_tx_pdcp_bytes = 0; + *stat_tx_pdcp_sdu_discarded = 0; + *stat_tx_pdcp_bytes_discarded = 0; + *stat_tx_data_pdu = 0; + *stat_tx_data_bytes = 0; + *stat_tx_retransmit_pdu_by_status = 0; + *stat_tx_retransmit_bytes_by_status = 0; + *stat_tx_retransmit_pdu = 0; + *stat_tx_retransmit_bytes = 0; + *stat_tx_control_pdu = 0; + *stat_tx_control_bytes = 0; + *stat_rx_pdcp_sdu = 0; + *stat_rx_pdcp_bytes = 0; + *stat_rx_data_pdus_duplicate = 0; + *stat_rx_data_bytes_duplicate = 0; + *stat_rx_data_pdu = 0; + *stat_rx_data_bytes = 0; + *stat_rx_data_pdu_dropped = 0; + *stat_rx_data_bytes_dropped = 0; + *stat_rx_data_pdu_out_of_window = 0; + *stat_rx_data_bytes_out_of_window = 0; + *stat_rx_control_pdu = 0; + *stat_rx_control_bytes = 0; + *stat_timer_poll_retransmit_timed_out = 0; + *stat_timer_status_prohibit_timed_out = 0; + return RLC_OP_STATUS_BAD_PARAMETER; + } +} + +//----------------------------------------------------------------------------- +rlc_op_status_t rlc_data_req (const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + confirm_t confirmP, + sdu_size_t sdu_sizeP, + mem_block_t *sdu_pP +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,const uint32_t *const sourceL2Id + ,const uint32_t *const destinationL2Id +#endif + ) { + //----------------------------------------------------------------------------- + mem_block_t *new_sdu_p = NULL; + rlc_mode_t rlc_mode = RLC_MODE_NONE; + rlc_union_t *rlc_union_p = NULL; + hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_rc; +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) + rlc_mbms_id_t *mbms_id_p = NULL; + logical_chan_id_t log_ch_id = 0; +#endif +#ifdef DEBUG_RLC_DATA_REQ + LOG_D(RLC,PROTOCOL_CTXT_FMT"rlc_data_req: rb_id %u (MAX %d), muip %d, confirmP %d, sdu_sizeP %d, sdu_pP %p\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + rb_idP, + NB_RAB_MAX, + muiP, + confirmP, + sdu_sizeP, + sdu_pP); +#endif +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) +#else + AssertFatal(MBMS_flagP == 0, "MBMS_flagP %u", MBMS_flagP); +#endif +#if T_TRACER + + if (ctxt_pP->enb_flag) + T(T_ENB_RLC_DL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_sizeP)); + +#endif + + if (MBMS_flagP) { + //AssertFatal (rb_idP < NB_RB_MBMS_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MBMS_MAX); + if(rb_idP >= NB_RB_MBMS_MAX) { + LOG_E(RLC, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MBMS_MAX); + return RLC_OP_STATUS_BAD_PARAMETER; + } + } else { + //AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); + if(rb_idP >= NB_RB_MAX) { + LOG_E(RLC, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX); + return RLC_OP_STATUS_BAD_PARAMETER; + } + } + + //DevAssert(sdu_pP != NULL); + if(sdu_pP == NULL) { + LOG_E(RLC, "sdu_pP == NULL\n"); + return RLC_OP_STATUS_BAD_PARAMETER; + } + + //DevCheck(sdu_sizeP > 0, sdu_sizeP, 0, 0); + if(sdu_sizeP <= 0) { + LOG_E(RLC, "sdu_sizeP %d, file %s, line %d\n", sdu_sizeP, __FILE__,__LINE__); + return RLC_OP_STATUS_BAD_PARAMETER; + } + +#if (LTE_RRC_VERSION < MAKE_VERSION(10, 0, 0)) + DevCheck(MBMS_flagP == 0, MBMS_flagP, 0, 0); +#endif + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_IN); +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) + + if (MBMS_flagP == TRUE) { + if (ctxt_pP->enb_flag) { + log_ch_id = rlc_mbms_enb_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP); + mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][log_ch_id]; + } else { + log_ch_id = rlc_mbms_ue_get_lcid_by_rb_id(ctxt_pP->rnti,rb_idP); + mbms_id_p = &rlc_mbms_lcid2service_session_id_ue[ctxt_pP->rnti][log_ch_id]; + } + + key = RLC_COLL_KEY_MBMS_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, mbms_id_p->service_id, mbms_id_p->session_id); + }else + + if (sourceL2Id && destinationL2Id) { + LOG_D (RLC, "RLC_COLL_KEY_VALUE: ctxt_pP->module_id: %d, ctxt_pP->rnti: %d, ctxt_pP->enb_flag: %d, rb_idP:%d, srb_flagP: %d \n \n", ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, + srb_flagP); + key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); + //Thinh's line originally uncommented + //key = RLC_COLL_KEY_SOURCE_DEST_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, *sourceL2Id, *destinationL2Id, srb_flagP); + //key_lcid = RLC_COLL_KEY_LCID_SOURCE_DEST_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, chan_idP, *sourceL2Id, *destinationL2Id, srb_flagP); + } else +#endif + { + LOG_D (RLC, "RLC_COLL_KEY_VALUE: ctxt_pP->module_id: %d, ctxt_pP->rnti: %d, ctxt_pP->enb_flag: %d, rb_idP:%d, srb_flagP: %d \n \n", ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, + srb_flagP); + key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP); + } + + h_rc = hashtable_get(rlc_coll_p, key, (void **)&rlc_union_p); + + if (h_rc == HASH_TABLE_OK) { + rlc_mode = rlc_union_p->mode; + } else { + rlc_mode = RLC_MODE_NONE; + //AssertFatal (0 , "RLC not configured key %ju\n", key); + LOG_E(RLC, "not configured key %lu\n", key); + return RLC_OP_STATUS_OUT_OF_RESSOURCES; + } + + if (MBMS_flagP == 0) { + LOG_D(RLC, PROTOCOL_CTXT_FMT"[RB %u] Display of rlc_data_req:\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + rb_idP); +#if defined(TRACE_RLC_PAYLOAD) + rlc_util_print_hex_octets(RLC, (unsigned char *)sdu_pP->data, sdu_sizeP); +#endif +#ifdef DEBUG_RLC_DATA_REQ + LOG_D(RLC,"RLC_TYPE : %d\n", rlc_mode); +#endif + + switch (rlc_mode) { + case RLC_MODE_NONE: + free_mem_block(sdu_pP, __func__); + LOG_E(RLC, PROTOCOL_CTXT_FMT" Received RLC_MODE_NONE as rlc_type for rb_id %u\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + rb_idP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + return RLC_OP_STATUS_BAD_PARAMETER; + + case RLC_MODE_AM: +#ifdef DEBUG_RLC_DATA_REQ + LOG_D(RLC,"RLC_MODE_AM\n"); +#endif + new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_am_data_req_alloc), __func__); + + if (new_sdu_p != NULL) { + // PROCESS OF COMPRESSION HERE: + memset (new_sdu_p->data, 0, sizeof (struct rlc_am_data_req_alloc)); + memcpy (&new_sdu_p->data[sizeof (struct rlc_am_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP); + ((struct rlc_am_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP; + ((struct rlc_am_data_req *) (new_sdu_p->data))->conf = confirmP; + ((struct rlc_am_data_req *) (new_sdu_p->data))->mui = muiP; + ((struct rlc_am_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_am_data_req_alloc); + free_mem_block(sdu_pP, __func__); + rlc_am_data_req(ctxt_pP, &rlc_union_p->rlc.am, new_sdu_p); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + return RLC_OP_STATUS_OK; + } else { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + free_mem_block(sdu_pP, __func__); + return RLC_OP_STATUS_INTERNAL_ERROR; + } + + break; + + case RLC_MODE_UM: + + /* TODO: this is a hack, needs better solution. Let's not use too + * much memory and store at maximum 5 millions bytes. + */ + /* look for HACK_RLC_UM_LIMIT for others places related to the hack. Please do not remove this comment. */ + if (rlc_um_get_buffer_occupancy(&rlc_union_p->rlc.um) > 5000000) { + free_mem_block(sdu_pP, __func__); + return RLC_OP_STATUS_OUT_OF_RESSOURCES; + } + + new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_um_data_req_alloc), __func__); + + if (new_sdu_p != NULL) { + // PROCESS OF COMPRESSION HERE: + memset (new_sdu_p->data, 0, sizeof (struct rlc_um_data_req_alloc)); + memcpy (&new_sdu_p->data[sizeof (struct rlc_um_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP); + ((struct rlc_um_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP; + ((struct rlc_um_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_um_data_req_alloc); + free_mem_block(sdu_pP, __func__); + rlc_um_data_req(ctxt_pP, &rlc_union_p->rlc.um, new_sdu_p); + //free_mem_block(new_sdu, __func__); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + return RLC_OP_STATUS_OK; + } else { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + free_mem_block(sdu_pP, __func__); + return RLC_OP_STATUS_INTERNAL_ERROR; + } + + break; + + case RLC_MODE_TM: + new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_tm_data_req_alloc), __func__); + + if (new_sdu_p != NULL) { + // PROCESS OF COMPRESSION HERE: + memset (new_sdu_p->data, 0, sizeof (struct rlc_tm_data_req_alloc)); + memcpy (&new_sdu_p->data[sizeof (struct rlc_tm_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP); + ((struct rlc_tm_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP; + ((struct rlc_tm_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_tm_data_req_alloc); + free_mem_block(sdu_pP, __func__); + rlc_tm_data_req(ctxt_pP, &rlc_union_p->rlc.tm, new_sdu_p); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + return RLC_OP_STATUS_OK; + } else { + //handle_event(ERROR,"FILE %s FONCTION rlc_data_req() LINE %s : out of memory\n", __FILE__, __LINE__); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + free_mem_block(sdu_pP, __func__); + return RLC_OP_STATUS_INTERNAL_ERROR; + } + + break; + + default: + free_mem_block(sdu_pP, __func__); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + return RLC_OP_STATUS_INTERNAL_ERROR; + } + +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) + } else { /* MBMS_flag != 0 */ + // LOG_I(RLC,"DUY rlc_data_req: mbms_rb_id in RLC instant is: %d\n", mbms_rb_id); + if (sdu_pP != NULL) { + if (sdu_sizeP > 0) { + LOG_I(RLC,"received a packet with size %d for MBMS \n", sdu_sizeP); + new_sdu_p = get_free_mem_block (sdu_sizeP + sizeof (struct rlc_um_data_req_alloc), __func__); + + if (new_sdu_p != NULL) { + // PROCESS OF COMPRESSION HERE: + memset (new_sdu_p->data, 0, sizeof (struct rlc_um_data_req_alloc)); + memcpy (&new_sdu_p->data[sizeof (struct rlc_um_data_req_alloc)], &sdu_pP->data[0], sdu_sizeP); + ((struct rlc_um_data_req *) (new_sdu_p->data))->data_size = sdu_sizeP; + ((struct rlc_um_data_req *) (new_sdu_p->data))->data_offset = sizeof (struct rlc_um_data_req_alloc); + free_mem_block(sdu_pP, __func__); + rlc_um_data_req(ctxt_pP, &rlc_union_p->rlc.um, new_sdu_p); + //free_mem_block(new_sdu, __func__); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + return RLC_OP_STATUS_OK; + } else { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + free_mem_block(sdu_pP, __func__); + return RLC_OP_STATUS_BAD_PARAMETER; + } + } else { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + return RLC_OP_STATUS_BAD_PARAMETER; + } + } else { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + return RLC_OP_STATUS_BAD_PARAMETER; + } + } + +#else + } else { /* MBMS_flag != 0 */ + free_mem_block(sdu_pP, __func__); + LOG_E(RLC, "MBMS_flag != 0 while Rel10/Rel14 is not defined...\n"); + //handle_event(ERROR,"FILE %s FONCTION rlc_data_req() LINE %s : parameter module_id out of bounds :%d\n", __FILE__, __LINE__, module_idP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_DATA_REQ,VCD_FUNCTION_OUT); + return RLC_OP_STATUS_BAD_PARAMETER; + } + +#endif +} + +//----------------------------------------------------------------------------- +void rlc_data_ind ( + const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const MBMS_flag_t MBMS_flagP, + const rb_id_t rb_idP, + const sdu_size_t sdu_sizeP, + mem_block_t *sdu_pP) { + //----------------------------------------------------------------------------- + LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u] Display of rlc_data_ind: size %u\n", + PROTOCOL_CTXT_ARGS(ctxt_pP), + (srb_flagP) ? "SRB" : "DRB", + rb_idP, + sdu_sizeP); + rlc_util_print_hex_octets(RLC, (unsigned char *)sdu_pP->data, sdu_sizeP); + + if (ctxt_pP->enb_flag) { +#if T_TRACER + T(T_ENB_RLC_UL, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->rnti), T_INT(rb_idP), T_INT(sdu_sizeP)); +#endif + const ngran_node_t type = RC.rrc[ctxt_pP->module_id]->node_type; + AssertFatal(type != ngran_eNB_CU && type != ngran_ng_eNB_CU && type != ngran_gNB_CU, + "Can't be CU, bad node type %d\n", type); + + if (NODE_IS_DU(type) && srb_flagP == 1) { + MessageDef *msg = itti_alloc_new_message(TASK_RLC_ENB, F1AP_UL_RRC_MESSAGE); + F1AP_UL_RRC_MESSAGE(msg).rnti = ctxt_pP->rnti; + F1AP_UL_RRC_MESSAGE(msg).srb_id = rb_idP; + F1AP_UL_RRC_MESSAGE(msg).rrc_container = sdu_pP->data; + F1AP_UL_RRC_MESSAGE(msg).rrc_container_length = sdu_sizeP; + itti_send_msg_to_task(TASK_DU_F1, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), msg); + return; + } + } // case monolithic eNodeB or UE + +/*************************For SRB1bis (RLC->RRC)*****************************/ + if (rb_idP == 3){ + + rrc_data_ind( + ctxt_pP, + rb_idP, + 51, + (uint8_t*)&sdu_pP->data[0]); + +/***************************************************************************/ + + +/* + pdcp_data_ind ( + ctxt_pP, + srb_flagP, + MBMS_flagP, + rb_idP, + sdu_sizeP, + sdu_pP); +*/ + } + else{ + get_pdcp_data_ind_func()(ctxt_pP, srb_flagP, MBMS_flagP, rb_idP, sdu_sizeP, sdu_pP, NULL, NULL); + } +} + +//----------------------------------------------------------------------------- +void rlc_data_conf (const protocol_ctxt_t *const ctxt_pP, + const srb_flag_t srb_flagP, + const rb_id_t rb_idP, + const mui_t muiP, + const rlc_tx_status_t statusP) { + //----------------------------------------------------------------------------- + if (srb_flagP) { + if (rlc_rrc_data_conf != NULL) { + rlc_rrc_data_conf (ctxt_pP, rb_idP, muiP, statusP); + } + } +} +//----------------------------------------------------------------------------- +int +rlc_module_init (void) { + //----------------------------------------------------------------------------- + int k; + module_id_t module_id1; + /* for no gcc warnings */ + (void)k; + LOG_D(RLC, "MODULE INIT\n"); + rlc_rrc_data_ind = NULL; + rlc_rrc_data_conf = NULL; + +#ifdef NB_IOT + //MP: change variable maxDRB for NB-IoT --> see ifdef at the beginning + rlc_rrc_data_ind_NB_IoT = NULL; +#endif + + rlc_coll_p = hashtable_create ((LTE_maxDRB + 2) * NUMBER_OF_UE_MAX, NULL, rb_free_rlc_union); + + //AssertFatal(rlc_coll_p != NULL, "UNRECOVERABLE error, RLC hashtable_create failed"); + if(rlc_coll_p == NULL) { + LOG_E(RLC, "UNRECOVERABLE error, RLC hashtable_create failed\n"); + return -1; + } + + for (module_id1=0; module_id1 < MAX_MOBILES_PER_ENB; module_id1++) { + for (k=0; k < RLC_MAX_MBMS_LC; k++) { + rlc_mbms_lcid2service_session_id_ue[module_id1][k].service_id = 0; + rlc_mbms_lcid2service_session_id_ue[module_id1][k].session_id = 0; + } + + for (k=0; k < NB_RB_MBMS_MAX; k++) { + rlc_mbms_rbid2lcid_ue[module_id1][k] = RLC_LC_UNALLOCATED; + } + } + + for (k=0; k < RLC_MAX_MBMS_LC; k++) { + rlc_mbms_lcid2service_session_id_eNB[0][k].service_id = 0; + rlc_mbms_lcid2service_session_id_eNB[0][k].session_id = 0; + } + + for (k=0; k < NB_RB_MBMS_MAX; k++) { + rlc_mbms_rbid2lcid_eNB[0][k] = RLC_LC_UNALLOCATED; + } + + pool_buffer_init(); + return(0); +} +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +void +rlc_module_cleanup (void) +//----------------------------------------------------------------------------- +{ + hashtable_destroy(&rlc_coll_p); +} +//----------------------------------------------------------------------------- +void +rlc_layer_init (void) { + //----------------------------------------------------------------------------- +} +//----------------------------------------------------------------------------- +void +rlc_layer_cleanup (void) +//----------------------------------------------------------------------------- +{ +} + diff --git a/openair2/LAYER2/RLC/rlc_rrc.c b/openair2/LAYER2/RLC/rlc_rrc.c index a1d04e241cec53031f73e576dabd71559718919c..4cb7c59b5ffb1c0cc1c96c1cc86c0e17785200d4 100644 --- a/openair2/LAYER2/RLC/rlc_rrc.c +++ b/openair2/LAYER2/RLC/rlc_rrc.c @@ -42,9 +42,10 @@ #if (LTE_RRC_VERSION >= MAKE_VERSION(9, 0, 0)) #include "LTE_PMCH-InfoList-r9.h" #endif - +#include "ENB_APP/enb_paramdef_NB_IoT.h" #include "LAYER2/MAC/mac_extern.h" #include "assertions.h" +#include "RRC/LITE/proto_NB_IoT.h" //----------------------------------------------------------------------------- rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP, const LTE_SRB_ToAddModList_t * const srb2add_listP, @@ -105,36 +106,36 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP case LTE_RLC_Config_PR_NOTHING: break; - case RLC_Config_PR_am: +// case RLC_Config_PR_am: /****************************************config srb1********************************************/ - if (rrc_rlc_add_rlc (ctxt_pP, SRB_FLAG_YES, MBMS_FLAG_NO, rb_id, lc_id, RLC_MODE_AM) != NULL) { - config_req_rlc_am_asn1 ( - ctxt_pP, - SRB_FLAG_YES, - &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.am, - rb_id, lc_id); - } else { - LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - rb_id); - } +// if (rrc_rlc_add_rlc (ctxt_pP, SRB_FLAG_YES, MBMS_FLAG_NO, rb_id, lc_id, RLC_MODE_AM) != NULL) { +// config_req_rlc_am_asn1 ( +// ctxt_pP, +// SRB_FLAG_YES, +// &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.am, +// rb_id, lc_id); +// } else { +// LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", +// PROTOCOL_CTXT_ARGS(ctxt_pP), +// rb_id); +// } /***********************************************************************************************/ /****************************************config srb1bis********************************************/ - if (rrc_rlc_add_rlc (ctxt_pP, SRB_FLAG_YES, MBMS_FLAG_NO, 3, 3, RLC_MODE_AM) != NULL) { - config_req_rlc_am_asn1 ( - ctxt_pP, - SRB_FLAG_YES, - &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.am, - 3, 3); - } else { - LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", - PROTOCOL_CTXT_ARGS(ctxt_pP), - rb_id); - } +// if (rrc_rlc_add_rlc (ctxt_pP, SRB_FLAG_YES, MBMS_FLAG_NO, 3, 3, RLC_MODE_AM) != NULL) { +// config_req_rlc_am_asn1 ( +// ctxt_pP, +// SRB_FLAG_YES, +// &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.am, +// 3, 3); +// } else { +// LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", +// PROTOCOL_CTXT_ARGS(ctxt_pP), +// rb_id); +// } /***************************************************************************************************/ - break; +// break; case LTE_RLC_Config_PR_am: if (rrc_rlc_add_rlc (ctxt_pP, SRB_FLAG_YES, MBMS_FLAG_NO, rb_id, lc_id, RLC_MODE_AM @@ -148,7 +149,20 @@ rlc_op_status_t rrc_rlc_config_asn1_req (const protocol_ctxt_t * const ctxt_pP SRB_FLAG_YES, &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.am, rb_id, lc_id); - } else { + } + /****************************************config srb1bis for NB-IoT********************************************/ + else if(NBconfig.NB_IoT_configured > 0) + { + if (rrc_rlc_add_rlc (ctxt_pP, SRB_FLAG_YES, MBMS_FLAG_NO, 3, 3, RLC_MODE_AM) != NULL) { + config_req_rlc_am_asn1 ( + ctxt_pP, + SRB_FLAG_YES, + &srb_toaddmod_p->rlc_Config->choice.explicitValue.choice.am, + 3, 3); + } + } + /************************************************************************************************************/ + else { LOG_E(RLC, PROTOCOL_CTXT_FMT" ERROR IN ALLOCATING SRB %d \n", PROTOCOL_CTXT_ARGS(ctxt_pP), rb_id); @@ -599,7 +613,7 @@ rlc_op_status_t rrc_rlc_remove_rlc ( #endif -#if defined(Rel10) || defined(Rel14) +#if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0)) rlc_mbms_id_t *mbms_id_p = NULL; #endif rrc_rlc_remove_rlc #ifdef OAI_EMU diff --git a/openair2/RRC/LITE/L2_interface.c b/openair2/RRC/NBIOT/L2_interface.c similarity index 100% rename from openair2/RRC/LITE/L2_interface.c rename to openair2/RRC/NBIOT/L2_interface.c diff --git a/openair2/RRC/LITE/L2_interface_NB_IoT.c b/openair2/RRC/NBIOT/L2_interface_NB_IoT.c similarity index 100% rename from openair2/RRC/LITE/L2_interface_NB_IoT.c rename to openair2/RRC/NBIOT/L2_interface_NB_IoT.c diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c b/openair2/RRC/NBIOT/MESSAGES/asn1_msg_NB_IoT.c similarity index 100% rename from openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.c rename to openair2/RRC/NBIOT/MESSAGES/asn1_msg_NB_IoT.c diff --git a/openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h b/openair2/RRC/NBIOT/MESSAGES/asn1_msg_NB_IoT.h similarity index 100% rename from openair2/RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h rename to openair2/RRC/NBIOT/MESSAGES/asn1_msg_NB_IoT.h diff --git a/openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e30.asn b/openair2/RRC/NBIOT/MESSAGES/asn1c/ASN1_files/RRC-e30.asn similarity index 100% rename from openair2/RRC/LITE/MESSAGES/asn1c/ASN1_files/RRC-e30.asn rename to openair2/RRC/NBIOT/MESSAGES/asn1c/ASN1_files/RRC-e30.asn diff --git a/openair2/RRC/LITE/defs_NB_IoT.h b/openair2/RRC/NBIOT/defs_NB_IoT.h similarity index 96% rename from openair2/RRC/LITE/defs_NB_IoT.h rename to openair2/RRC/NBIOT/defs_NB_IoT.h index d150e6a3b24ceb0ecdc9fb7aadff7f1099a9bf76..67801f522ff508eff4e3ea21400d8970efd958ed 100644 --- a/openair2/RRC/LITE/defs_NB_IoT.h +++ b/openair2/RRC/NBIOT/defs_NB_IoT.h @@ -443,7 +443,7 @@ typedef struct eNB_RRC_INST_NB_IoT_s { hash_table_t *s1ap_id2_s1ap_ids ; // key is content is rrc_ue_s1ap_ids_t //RRC configuration - RrcConfigurationReq configuration; //rrc_messages_types.h + NbIoTRrcConfigurationReq configuration; //rrc_messages_types.h // other PLMN parameters /// Mobile country code diff --git a/openair2/RRC/LITE/extern_NB_IoT.h b/openair2/RRC/NBIOT/extern_NB_IoT.h similarity index 100% rename from openair2/RRC/LITE/extern_NB_IoT.h rename to openair2/RRC/NBIOT/extern_NB_IoT.h diff --git a/openair2/RRC/LITE/proto_NB_IoT.h b/openair2/RRC/NBIOT/proto_NB_IoT.h similarity index 96% rename from openair2/RRC/LITE/proto_NB_IoT.h rename to openair2/RRC/NBIOT/proto_NB_IoT.h index 1e2197d019d2975a5698bfdcd4d9521f76d5fb76..cfb13b43c6bb1f52878d0f37cd7d5b85ee1d8cb5 100644 --- a/openair2/RRC/LITE/proto_NB_IoT.h +++ b/openair2/RRC/NBIOT/proto_NB_IoT.h @@ -68,7 +68,7 @@ uint8_t get_NB_IoT_SIB23_size(void); long *get_NB_IoT_SIB1_eutracontrolregionsize(void); -void init_testing_NB_IoT(uint8_t Mod_id, int CC_id, rrc_eNB_carrier_data_NB_IoT_t *carrier, RrcConfigurationReq *configuration, uint32_t frame, uint32_t hyper_frame); +void init_testing_NB_IoT(uint8_t Mod_id, int CC_id, rrc_eNB_carrier_data_NB_IoT_t *carrier, NbIoTRrcConfigurationReq *configuration, uint32_t frame, uint32_t hyper_frame); /*------------------------common_nb_iot.c----------------------------------------*/ @@ -414,7 +414,7 @@ void rrc_config_buffer_NB_IoT( char openair_rrc_eNB_configuration_NB_IoT( const module_id_t enb_mod_idP, - RrcConfigurationReq* configuration + NbIoTRrcConfigurationReq* configuration ); //----------------------------- diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/NBIOT/rrc_UE.c similarity index 100% rename from openair2/RRC/LITE/rrc_UE.c rename to openair2/RRC/NBIOT/rrc_UE.c diff --git a/openair2/RRC/LITE/rrc_common.c b/openair2/RRC/NBIOT/rrc_common.c similarity index 100% rename from openair2/RRC/LITE/rrc_common.c rename to openair2/RRC/NBIOT/rrc_common.c diff --git a/openair2/RRC/LITE/rrc_common_NB_IoT.c b/openair2/RRC/NBIOT/rrc_common_NB_IoT.c similarity index 100% rename from openair2/RRC/LITE/rrc_common_NB_IoT.c rename to openair2/RRC/NBIOT/rrc_common_NB_IoT.c diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/NBIOT/rrc_eNB.c similarity index 100% rename from openair2/RRC/LITE/rrc_eNB.c rename to openair2/RRC/NBIOT/rrc_eNB.c diff --git a/openair2/RRC/LITE/rrc_eNB_NB_IoT.c b/openair2/RRC/NBIOT/rrc_eNB_NB_IoT.c old mode 100644 new mode 100755 similarity index 75% rename from openair2/RRC/LITE/rrc_eNB_NB_IoT.c rename to openair2/RRC/NBIOT/rrc_eNB_NB_IoT.c index 5329e8da5c791340da1ae5c59c9c57993ca60990..87e2982619268e03495a84bd5553e6ab2da65dde --- a/openair2/RRC/LITE/rrc_eNB_NB_IoT.c +++ b/openair2/RRC/NBIOT/rrc_eNB_NB_IoT.c @@ -34,6 +34,12 @@ #include "LAYER2/MAC/extern_NB_IoT.h" //#include "RRC/LITE/proto_NB_IoT.h" #include "defs_NB_IoT.h" +/**************/ +#include "vars_NB_IoT.h" +#include "extern.h" +#include "extern_NB_IoT.h" +#include "LAYER2/MAC/proto_NB_IoT.h" +/**************/ #include "openair1/SCHED/defs_NB_IoT.h" #include "RRC/LITE/MESSAGES/asn1_msg_NB_IoT.h" #include "RRCConnectionRequest-NB.h" @@ -46,19 +52,17 @@ #include "SRB-ToAddMod-NB-r13.h" #include "common/utils/collection/tree.h" -//#include "extern.h" -#include "extern_NB_IoT.h" #include "assertions.h" #include "asn1_conversions.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "LAYER2/RLC/rlc.h" -//#include "LAYER2/MAC/proto.h" +#include "LAYER2/MAC/proto.h" // For NB-IoT branch #include "LAYER2/MAC/proto_NB_IoT.h" #include "UTIL/LOG/log.h" #include "COMMON/mac_rrc_primitives.h" #include "rlc.h" #include "SIMULATION/ETH_TRANSPORT/extern.h" -#include "rrc_eNB_UE_context_NB_IoT.h" +#include "rrc_eNB_UE_context.h" // used by NB-IoT branch #include "platform_types.h" #include "msc.h" #include "T.h" @@ -104,6 +108,9 @@ extern EMULATION_VARS *Emul_vars; #endif +extern eNB_MAC_INST *eNB_mac_inst; // For NB-IoT branch +extern UE_MAC_INST *UE_mac_inst; // For NB-IoT branch + #ifdef BIGPHYSAREA extern void* bigphys_malloc(int); #endif @@ -115,6 +122,291 @@ extern void* bigphys_malloc(int); mui_t rrc_eNB_mui_NB_IoT = 0; +//***********************************************For NB-IoT*****************************************************************// +uint8_t* generate_msg4_NB_IoT(rrc_eNB_carrier_data_NB_IoT_t *carrier) +{ + LOG_D(RRC,"start the RRC connection setup PDU\n"); + + rrc_eNB_ue_context_NB_IoT_t* ue_context_pP_NB_IoT; + + ue_context_pP_NB_IoT = (rrc_eNB_ue_context_NB_IoT_t*)malloc(sizeof(rrc_eNB_ue_context_NB_IoT_t)); + + SRB_ToAddModList_NB_r13_t **SRB_configList_NB_IoT; + + SRB_configList_NB_IoT = &ue_context_pP_NB_IoT->ue_context.SRB_configList; + + carrier[0].Srb0.Tx_buffer.payload_size = do_RRCConnectionSetup_NB_IoT(ue_context_pP_NB_IoT, + 0, + carrier[0].Srb0.Tx_buffer.Payload, + 0, + SRB_configList_NB_IoT, + &ue_context_pP_NB_IoT->ue_context.physicalConfigDedicated_NB_IoT); + + LOG_I(RRC,"[MSG] RRC Connection Setup NB-IoT: "); + + int cnt; + + for (cnt = 0; cnt < carrier[0].Srb0.Tx_buffer.payload_size; cnt++) + { + printf("%02x ", carrier[0].Srb0.Tx_buffer.Payload[cnt]); + } + printf("\n"); + + return carrier[0].Srb0.Tx_buffer.Payload; +} + +uint8_t* mac_rrc_msg3_ind_NB_IoT(uint8_t *payload_ptr, uint16_t rnti, uint32_t length) +{ + LOG_D(RRC,"recieve MSG3 CCCH SDU from MAC\n"); + asn_dec_rval_t dec_rval; + struct rrc_eNB_ue_context_NB_IoT_s *ue_context_p = NULL; + uint8_t* msg4_rrc_sdu = NULL; + SRB_INFO_NB_IoT *srb_info = NULL; + srb_info = &eNB_rrc_inst_NB_IoT->carrier[0].Srb0; + memcpy(srb_info->Rx_buffer.Payload,payload_ptr,length); + srb_info->Rx_buffer.payload_size = length; + LOG_D(RRC,"Decoding UL CCCH %x.%x.%x.%x.%x.%x.%x.%x.%x (%p)\n", + ((uint8_t *) srb_info->Rx_buffer.Payload)[0], + ((uint8_t *) srb_info->Rx_buffer.Payload)[1], + ((uint8_t *) srb_info->Rx_buffer.Payload)[2], + ((uint8_t *) srb_info->Rx_buffer.Payload)[3], + ((uint8_t *) srb_info->Rx_buffer.Payload)[4], + ((uint8_t *) srb_info->Rx_buffer.Payload)[5], + ((uint8_t *) srb_info->Rx_buffer.Payload)[6], + ((uint8_t *) srb_info->Rx_buffer.Payload)[7], + ((uint8_t *) srb_info->Rx_buffer.Payload)[8], + (uint8_t *) srb_info->Rx_buffer.Payload); + + RRCConnectionRequest_NB_r13_IEs_t* rrcConnectionRequest_NB = NULL; + UL_CCCH_Message_NB_t* ul_ccch_msg_NB = NULL; + dec_rval = uper_decode( + NULL, + &asn_DEF_UL_CCCH_Message_NB, + (void**)&ul_ccch_msg_NB, + payload_ptr, + 100, + 0, + 0); + if (ul_ccch_msg_NB->message.choice.c1.present==UL_CCCH_MessageType_NB__c1_PR_rrcConnectionRequest_r13) + { + LOG_I(RRC,"The decode CCH MSG is RRC connection Request NB\n"); + rrcConnectionRequest_NB = &ul_ccch_msg_NB->message.choice.c1.choice.rrcConnectionRequest_r13.criticalExtensions.choice.rrcConnectionRequest_r13; + if (rrcConnectionRequest_NB->ue_Identity_r13.present == InitialUE_Identity_PR_randomValue) + { + uint8_t *da = rrcConnectionRequest_NB->ue_Identity_r13.choice.randomValue.buf; /* BIT STRING body */ + int length = rrcConnectionRequest_NB->ue_Identity_r13.choice.randomValue.size; /* Size of the above buffer */ + printf("Random Value: "); + for(int a = 0; a<length;a++) + printf("%02x ",da[a]); + printf("\n"); + }else if (rrcConnectionRequest_NB->ue_Identity_r13.present == InitialUE_Identity_PR_s_TMSI) + { + uint8_t *da = rrcConnectionRequest_NB->ue_Identity_r13.choice.s_TMSI.m_TMSI.buf; /* BIT STRING body */ + int length = rrcConnectionRequest_NB->ue_Identity_r13.choice.s_TMSI.m_TMSI.size; /* Size of the above buffer */ + + printf("TMSI: "); + for(int a = 0; a<length;a++) + printf("%02x ",da[a]); + printf("\n"); + } + else + { + LOG_E(RRC,"unknown TMSI or Random Value format in RRC connection request NB\n"); + } + msg4_rrc_sdu = generate_msg4_NB_IoT(&eNB_rrc_inst_NB_IoT->carrier[0]); + } + else + LOG_E(RRC,"unknown MSG3 format for NB-IoT for current test\n"); + return msg4_rrc_sdu; +} + +uint8_t *get_NB_IoT_MIB( + rrc_eNB_carrier_data_NB_IoT_t *carrier, + uint16_t N_RB_DL,//may not needed--> for NB_IoT only 1 PRB is used + uint32_t subframe, + uint32_t frame, + uint32_t hyper_frame) +{ + + if(frame%64==0 && subframe ==0) + {//printf("dooooo MIB"); + + + do_MIB_NB_IoT(carrier,N_RB_DL,frame,hyper_frame); + /* for(int i = 0; i<5;i++) + printf("%02X ",eNB_rrc_inst_NB_IoT->carrier[0].MIB_NB_IoT[i]); + printf("\n");*/ + } + // CC_ID=0 + return eNB_rrc_inst_NB_IoT->carrier[0].MIB_NB_IoT; +} + + +uint8_t get_NB_IoT_MIB_size(void) +{ + // CC_ID=0 + return eNB_rrc_inst_NB_IoT->carrier[0].sizeof_MIB_NB_IoT; +} + +uint8_t *get_NB_IoT_SIB1(uint8_t Mod_id, int CC_id, + rrc_eNB_carrier_data_NB_IoT_t *carrier, + uint16_t mcc, //208 + uint16_t mnc, //92 + uint16_t tac, //1 + uint32_t cell_identity, //3584 + uint16_t band, // 7 + uint16_t mnc_digit_length, + uint32_t subframe, + uint32_t frame, + uint32_t hyper_frame) +{ + + + //if(frame%64==1 && subframe ==0) + //{ + do_SIB1_NB_IoT_x(Mod_id,CC_id,carrier,mcc,mnc,tac,cell_identity,band,mnc_digit_length,hyper_frame); + //} + + + + return eNB_rrc_inst_NB_IoT->carrier[0].SIB1_NB_IoT; +} + +uint8_t get_NB_IoT_SIB1_size(void) +{ + return eNB_rrc_inst_NB_IoT->carrier[0].sizeof_SIB1_NB_IoT; +} + +uint8_t *get_NB_IoT_SIB23(void) +{ + return eNB_rrc_inst_NB_IoT->carrier[0].SIB23_NB_IoT; +} + +uint8_t get_NB_IoT_SIB23_size(void) +{ + return eNB_rrc_inst_NB_IoT->carrier[0].sizeof_SIB23_NB_IoT; +} + + +long *get_NB_IoT_SIB1_eutracontrolregionsize(void) +{ + return eNB_rrc_inst_NB_IoT->carrier[0].sib1_NB_IoT->eutraControlRegionSize_r13; +} + +void init_testing_NB_IoT(uint8_t Mod_id, int CC_id, rrc_eNB_carrier_data_NB_IoT_t *carrier, NbIoTRrcConfigurationReq *configuration, uint32_t frame, uint32_t hyper_frame) +{ + + //copy basic parameters + carrier[CC_id].physCellId = configuration->Nid_cell[CC_id]; + carrier[CC_id].p_rx_eNB = 1; + carrier[CC_id].Ncp = configuration->prefix_type[CC_id]; //DL Cyclic prefix + carrier[CC_id].Ncp_UL = configuration->prefix_type_UL[CC_id];//UL cyclic prefix + carrier[CC_id].dl_CarrierFreq = configuration->downlink_frequency[CC_id]; + carrier[CC_id].ul_CarrierFreq = configuration->downlink_frequency[CC_id]+ configuration->uplink_frequency_offset[CC_id]; + + + //TODO: verify who allocate memory for sib1_NB_IoT, sib2_NB_IoT, sib3_NB and mib_nb in the carrier before being passed as parameter + + carrier[CC_id].sizeof_SIB1_NB_IoT = 0; + carrier[CC_id].sizeof_SIB23_NB_IoT = 0; + carrier[CC_id].sizeof_MIB_NB_IoT = 0; + + //MIB + carrier[CC_id].MIB_NB_IoT = (uint8_t*) malloc16(32); //MIB is 34 bits=5bytes needed + + + if (carrier[CC_id].MIB_NB_IoT) + { + carrier[CC_id].sizeof_MIB_NB_IoT = + do_MIB_NB_IoT(carrier, + configuration->N_RB_DL[CC_id], + 0, //frame + 0// hyper sfn + ); + } + else { + LOG_E(RRC, " init_SI: FATAL, no memory for MIB_NB_IoT allocated\n"); + //exit here + } + + + if (carrier[CC_id].sizeof_MIB_NB_IoT == 255) { + // exit here + } + + //SIB1_NB_IoT + carrier[CC_id].SIB1_NB_IoT = (uint8_t*) malloc16(32);//allocation of buffer memory for SIB1_NB_IOT + + if (carrier[CC_id].SIB1_NB_IoT) + carrier[CC_id].sizeof_SIB1_NB_IoT = do_SIB1_NB_IoT( //follow the new implementation + Mod_id, + CC_id, + carrier, + configuration, + 0 //FIXME is correct to pass frame = 0?? + ); + + else { + LOG_E(RRC, " init_SI: FATAL, no memory for SIB1_NB_IoT allocated\n"); + //exit here + } + + if (carrier[CC_id].sizeof_SIB1_NB_IoT == 255) { + //exit here + } + + //dump SIB1_NB_IoT + + LOG_I(RRC,"Dump SIB1 NB-IoT content\n"); + + for(int i = 0; i<32;i++) + printf("%02X ",carrier[CC_id].SIB1_NB_IoT[i]); + printf("\n"); + + //SIB23_NB_IoT + carrier[CC_id].SIB23_NB_IoT = (uint8_t*) malloc16(64); + + if (carrier[CC_id].SIB23_NB_IoT) { + carrier[CC_id].sizeof_SIB23_NB_IoT = do_SIB23_NB_IoT( + Mod_id, + CC_id, + carrier, + configuration + ); + + if (carrier[CC_id].sizeof_SIB23_NB_IoT == 255) { + //exit here + } + + + //Configure MAC + + + + + rrc_mac_config_req_NB_IoT(Mod_id, + CC_id, + 0, + carrier, + (SystemInformationBlockType1_NB_t*) carrier[CC_id].sib1_NB_IoT, + (RadioResourceConfigCommonSIB_NB_r13_t *) &carrier[CC_id].sib2_NB_IoT->radioResourceConfigCommon_r13, + (struct PhysicalConfigDedicated_NB_r13 *)NULL, + (struct LogicalChannelConfig_NB_r13 *)NULL, + 0, + 0 + ); + + LOG_I(MAC,"testing_NB_IoT config done\n"); + } else { + LOG_E(RRC, " init_SI: FATAL, no memory for SIB23_NB_IoT allocated\n"); + //exit here + } +} + +//********************************************************************************************************************// + + + // should be called when UE is lost by eNB void rrc_eNB_free_UE_NB_IoT(const module_id_t enb_mod_idP,const struct rrc_eNB_ue_context_NB_IoT_s* const ue_context_pP) @@ -392,6 +684,58 @@ rrc_eNB_get_next_free_ue_context_NB_IoT( } } +/******************************************Add for NB-IoT**********************************************/ +#if !defined(ENABLE_USE_MME) +void rrc_eNB_emulation_notify_ue_module_id_NB_IoT( + const module_id_t ue_module_idP, + const rnti_t rntiP, + const uint8_t cell_identity_byte0P, + const uint8_t cell_identity_byte1P, + const uint8_t cell_identity_byte2P, + const uint8_t cell_identity_byte3P) +{ + module_id_t enb_module_id; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + int CC_id; + + // find enb_module_id + for (enb_module_id = 0; enb_module_id < NUMBER_OF_eNB_MAX; enb_module_id++) { + if(enb_module_id>0){ /*FIX LATER*/ + return; + } + for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + if (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1 != NULL) { + if ( + (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[0] == cell_identity_byte0P) && + (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[1] == cell_identity_byte1P) && + (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[2] == cell_identity_byte2P) && + (eNB_rrc_inst[enb_module_id].carrier[CC_id].sib1->cellAccessRelatedInfo.cellIdentity.buf[3] == cell_identity_byte3P) + ) { + ue_context_p = rrc_eNB_get_ue_context( + &eNB_rrc_inst[enb_module_id], + rntiP + ); + + if (NULL != ue_context_p) { + oai_emulation.info.eNB_ue_local_uid_to_ue_module_id[enb_module_id][ue_context_p->local_uid] = ue_module_idP; + } + + //return; + } + } + } + oai_emulation.info.eNB_ue_module_id_to_rnti[enb_module_id][ue_module_idP] = rntiP; + } + + AssertFatal(enb_module_id == NUMBER_OF_eNB_MAX, + "Cell identity not found for ue module id %u rnti %x", + ue_module_idP, rntiP); +} +#endif + +/***************************************************************************************************/ + + //----------------------------------------------------------------------------- // return the ue context if there is already an UE with the same S-TMSI(MMEC+M-TMSI), NULL otherwise static struct rrc_eNB_ue_context_NB_IoT_s* @@ -1134,6 +1478,7 @@ rrc_eNB_generate_dedicatedRRCConnectionReconfiguration_NB_IoT( } +/****************************MSG5 For NB-IoT********************************************/ //----------------------------------------------------------------------------- void rrc_eNB_process_RRCConnectionSetupComplete_NB_IoT( const protocol_ctxt_t* const ctxt_pP, @@ -1155,21 +1500,27 @@ void rrc_eNB_process_RRCConnectionSetupComplete_NB_IoT( #if defined(ENABLE_USE_MME) if (EPC_MODE_ENABLED == 1) { - // Forward message to S1AP layer we don't have S1 AP functions for the moment - /*rrc_eNB_send_S1AP_NAS_FIRST_REQ( - ctxt_pP, - ue_context_pP, - rrcConnectionSetupComplete_NB);*/ + // Forward message to S1AP layer we don't have S1AP functions for the moment + //printf("*********************Get into S1AP*********************\n"); + //rrc_eNB_send_S1AP_NAS_FIRST_REQ( + // ctxt_pP, + // ue_context_pP, + // rrcConnectionSetupComplete_NB); + } else #endif { + /* // RRC loop back (no S1AP), send SecurityModeCommand to UE - rrc_eNB_generate_SecurityModeCommand_NB_IoT( + rrc_eNB_generate_SecurityModeCommand( ctxt_pP, - ue_context_pP); + ue_context_pP); + */ } } +/********************************************************************************/ + //----------------------------------------------------------------------------- void rrc_eNB_generate_SecurityModeCommand_NB_IoT( const protocol_ctxt_t* const ctxt_pP, @@ -1800,130 +2151,57 @@ while ( eNB_rrc_inst_NB_IoT == NULL ) { /*-----------------STATE MACHINE---------------*/ -//----------------------------------------------------------------------------- -int rrc_eNB_decode_ccch_NB_IoT( +/*********************************Decode CCCH For NB-IoT******************************************/ +/*------------------------------------------------------------------------------*/ +int +rrc_eNB_decode_ccch_NB_IoT( protocol_ctxt_t* const ctxt_pP, - const SRB_INFO_NB_IoT* const Srb_info, //SRB0 + const SRB_INFO_NB_IoT* const Srb_info, const int CC_id ) //----------------------------------------------------------------------------- { + LOG_D(RRC,"recieve MSG3 CCCH SDU from MAC\n"); asn_dec_rval_t dec_rval; - UL_CCCH_Message_NB_t *ul_ccch_msg_NB_IoT = NULL; - RRCConnectionRequest_NB_r13_IEs_t *rrcConnectionRequest_NB_IoT = NULL; - RRCConnectionReestablishmentRequest_NB_r13_IEs_t* rrcConnectionReestablishmentRequest_NB_IoT = NULL; - RRCConnectionResumeRequest_NB_r13_IEs_t *rrcConnectionResumeRequest_NB_IoT= NULL; - int i, rval; - struct rrc_eNB_ue_context_NB_IoT_s* ue_context_p = NULL; - uint64_t random_value = 0; - int stmsi_received = 0; - - T(T_ENB_RRC_UL_CCCH_DATA_IN, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - - //memset(ul_ccch_msg,0,sizeof(UL_CCCH_Message_t)); - LOG_D(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Decoding UL CCCH %x.%x.%x.%x.%x.%x (%p)\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - ((uint8_t*) Srb_info->Rx_buffer.Payload)[0], + LOG_D(RRC,"Decoding UL CCCH %x.%x.%x.%x.%x.%x.%x.%x.%x (%p)\n", + ((uint8_t *) Srb_info->Rx_buffer.Payload)[0], ((uint8_t *) Srb_info->Rx_buffer.Payload)[1], ((uint8_t *) Srb_info->Rx_buffer.Payload)[2], ((uint8_t *) Srb_info->Rx_buffer.Payload)[3], ((uint8_t *) Srb_info->Rx_buffer.Payload)[4], - ((uint8_t *) Srb_info->Rx_buffer.Payload)[5], (uint8_t *) Srb_info->Rx_buffer.Payload); - + ((uint8_t *) Srb_info->Rx_buffer.Payload)[5], + ((uint8_t *) Srb_info->Rx_buffer.Payload)[6], + ((uint8_t *) Srb_info->Rx_buffer.Payload)[7], + ((uint8_t *) Srb_info->Rx_buffer.Payload)[8], + (uint8_t *) Srb_info->Rx_buffer.Payload); + + RRCConnectionRequest_NB_r13_IEs_t* rrcConnectionRequest_NB = NULL; + UL_CCCH_Message_NB_t* ul_ccch_msg_NB = NULL; dec_rval = uper_decode( NULL, &asn_DEF_UL_CCCH_Message_NB, - (void**)&ul_ccch_msg_NB_IoT, + (void**)&ul_ccch_msg_NB, (uint8_t*) Srb_info->Rx_buffer.Payload, 100, 0, 0); + module_id_t Idx; + int i, rval; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; + uint64_t random_value = 0; + int stmsi_received = 0; -//#if defined(ENABLE_ITTI).... -//# if defined(DISABLE_ITTI_XER_PRINT)... - - - for (i = 0; i < 8; i++) { //MP: FIXME why 8? - LOG_T(RRC, "%x.", ((uint8_t *) & ul_ccch_msg_NB_IoT)[i]); - } - - if (dec_rval.consumed == 0) { - LOG_E(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" FATAL Error in receiving CCCH\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); - return -1; - } - - if (ul_ccch_msg_NB_IoT->message.present == UL_CCCH_MessageType_NB_PR_c1) { - - switch (ul_ccch_msg_NB_IoT->message.choice.c1.present) { - - case UL_CCCH_MessageType_NB__c1_PR_NOTHING: - LOG_I(RRC, - PROTOCOL_RRC_CTXT_FMT" Received PR_NOTHING on UL-CCCH-Message-NB\n", - PROTOCOL_RRC_CTXT_ARGS(ctxt_pP)); - break; - - case UL_CCCH_MessageType_NB__c1_PR_rrcConnectionReestablishmentRequest_r13: - T(T_ENB_RRC_CONNECTION_REESTABLISHMENT_REQUEST, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - -#ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRCConnectionReestablishementRequest-NB\n"); - - for (i = 0; i < Srb_info->Rx_buffer.payload_size; i++) { - LOG_F(RRC,"%02x ", ((uint8_t*)Srb_info->Rx_buffer.Payload)[i]); - } - - LOG_F(RRC,"\n"); -#endif - LOG_D(RRC, - PROTOCOL_RRC_CTXT_UE_FMT"MAC_eNB--- MAC_DATA_IND (rrcConnectionReestablishmentRequest-NB on SRB0) --> RRC_eNB\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); - rrcConnectionReestablishmentRequest_NB_IoT = - &ul_ccch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionReestablishmentRequest_r13.criticalExtensions.choice.rrcConnectionReestablishmentRequest_r13; - - //for NB-IoT only "reconfiguration Failure" and "other failure" are allowed as reestablishment cause - LOG_I(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionReestablishmentRequest-NB cause %s\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - ((rrcConnectionReestablishmentRequest_NB_IoT->reestablishmentCause_r13 == ReestablishmentCause_NB_r13_otherFailure) ? "Other Failure" : - "reconfigurationFailure")); - - - //TODO:connection reestablishment to be implemented - /*{ - uint64_t c_rnti = 0; - - memcpy(((uint8_t *) & c_rnti) + 3, rrcConnectionReestablishmentRequest.UE_identity.c_RNTI.buf, - rrcConnectionReestablishmentRequest.UE_identity.c_RNTI.size); - ue_mod_id = rrc_eNB_get_UE_index(enb_mod_idP, c_rnti); - } - - if ((eNB_rrc_inst_NB_IoT[enb_mod_idP].phyCellId == rrcConnectionReestablishmentRequest.UE_identity.physCellId) && - (ue_mod_id != UE_INDEX_INVALID)){ - rrc_eNB_generate_RRCConnectionReestablishment(enb_mod_idP, frameP, ue_mod_id); - }else { - rrc_eNB_generate_RRCConnectionReestablishmentReject(enb_mod_idP, frameP, ue_mod_id); - } - */ - /* reject all reestablishment attempts for the moment */ - - //MP:for the moment we only reject - rrc_eNB_generate_RRCConnectionReestablishmentReject_NB_IoT(ctxt_pP, - rrc_eNB_get_ue_context_NB_IoT(&eNB_rrc_inst_NB_IoT[ctxt_pP->module_id], ctxt_pP->rnti), - CC_id); - - break; - - case UL_CCCH_MessageType_NB__c1_PR_rrcConnectionRequest_r13: //MSG3 - T(T_ENB_RRC_CONNECTION_REQUEST, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), + if (ul_ccch_msg_NB->message.present == UL_CCCH_MessageType_PR_c1) + { + switch (ul_ccch_msg_NB->message.choice.c1.present) + { + case UL_CCCH_MessageType_NB__c1_PR_rrcConnectionRequest_r13: + T(T_ENB_RRC_CONNECTION_REQUEST, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); #ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRCConnectionRequest-NB\n"); + LOG_F(RRC,"[MSG] RRC Connection Request\n"); for (i = 0; i < Srb_info->Rx_buffer.payload_size; i++) { LOG_F(RRC,"%02x ", ((uint8_t*)Srb_info->Rx_buffer.Payload)[i]); @@ -1932,87 +2210,76 @@ int rrc_eNB_decode_ccch_NB_IoT( LOG_F(RRC,"\n"); #endif LOG_D(RRC, - PROTOCOL_RRC_CTXT_UE_FMT"MAC_eNB --- MAC_DATA_IND (rrcConnectionRequest-NB on SRB0) --> RRC_eNB\n", + PROTOCOL_RRC_CTXT_UE_FMT"MAC_eNB --- MAC_DATA_IND (rrcConnectionRequest on SRB0) --> RRC_eNB\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); - - ue_context_p = rrc_eNB_get_ue_context_NB_IoT( //XXX define new function in rrc_eNB_UE_context - &eNB_rrc_inst_NB_IoT[ctxt_pP->module_id], + ue_context_p = rrc_eNB_get_ue_context( + &eNB_rrc_inst[ctxt_pP->module_id], ctxt_pP->rnti); - if (ue_context_p != NULL) { //MP: i receive a ConnectionRequest from a UE which have already a context + if (ue_context_p != NULL) { // erase content - rrc_eNB_free_mem_UE_context_NB_IoT(ctxt_pP, ue_context_p); + rrc_eNB_free_mem_UE_context(ctxt_pP, ue_context_p); MSC_LOG_RX_DISCARDED_MESSAGE( MSC_RRC_ENB, MSC_RRC_UE, Srb_info->Rx_buffer.Payload, dec_rval.consumed, - MSC_AS_TIME_FMT" RRCConnectionRequest-NB UE %x size %u (UE already in context)", + MSC_AS_TIME_FMT" RRCConnectionRequest UE %x size %u (UE already in context)", MSC_AS_TIME_ARGS(ctxt_pP), ue_context_p->ue_context.rnti, dec_rval.consumed); - } - else { - rrcConnectionRequest_NB_IoT = &ul_ccch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionRequest_r13.criticalExtensions.choice.rrcConnectionRequest_r13; + } else { + rrcConnectionRequest_NB = &ul_ccch_msg_NB->message.choice.c1.choice.rrcConnectionRequest_r13.criticalExtensions.choice.rrcConnectionRequest_r13; { - if (InitialUE_Identity_PR_randomValue == rrcConnectionRequest_NB_IoT->ue_Identity_r13.present) { - - //InitialUE-Identity randomValue size should be 40bits = 5 byte - AssertFatal(rrcConnectionRequest_NB_IoT->ue_Identity_r13.choice.randomValue.size == 5, + if (InitialUE_Identity_PR_randomValue == rrcConnectionRequest_NB->ue_Identity_r13.present) { + AssertFatal(rrcConnectionRequest_NB->ue_Identity_r13.choice.randomValue.size == 5, "wrong InitialUE-Identity randomValue size, expected 5, provided %d", - rrcConnectionRequest_NB_IoT->ue_Identity_r13.choice.randomValue.size); - + rrcConnectionRequest_NB->ue_Identity_r13.choice.randomValue.size); memcpy(((uint8_t*) & random_value) + 3, - rrcConnectionRequest_NB_IoT->ue_Identity_r13.choice.randomValue.buf, - rrcConnectionRequest_NB_IoT->ue_Identity_r13.choice.randomValue.size); - + rrcConnectionRequest_NB->ue_Identity_r13.choice.randomValue.buf, + rrcConnectionRequest_NB->ue_Identity_r13.choice.randomValue.size); /* if there is already a registered UE (with another RNTI) with this random_value, * the current one must be removed from MAC/PHY (zombie UE) */ - if ((ue_context_p = rrc_eNB_ue_context_random_exist_NB_IoT(ctxt_pP, random_value))) { + if ((ue_context_p = rrc_eNB_ue_context_random_exist(ctxt_pP, random_value))) { LOG_W(RRC, "new UE rnti %x (coming with random value) is already there as UE %x, removing %x from MAC/PHY\n", ctxt_pP->rnti, ue_context_p->ue_context.rnti, ctxt_pP->rnti); - - //rrc_mac_remove_ue_NB_IoT(ctxt_pP->module_id, ctxt_pP->rnti); + rrc_mac_remove_ue(ctxt_pP->module_id, ctxt_pP->rnti); ue_context_p = NULL; return 0; } else { - ue_context_p = rrc_eNB_get_next_free_ue_context_NB_IoT(ctxt_pP, random_value); + ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP, random_value); } - } else if (InitialUE_Identity_PR_s_TMSI == rrcConnectionRequest_NB_IoT->ue_Identity_r13.present) { + } else if (InitialUE_Identity_PR_s_TMSI == rrcConnectionRequest_NB->ue_Identity_r13.present) { /* Save s-TMSI */ - S_TMSI_t s_TMSI = rrcConnectionRequest_NB_IoT->ue_Identity_r13.choice.s_TMSI; + S_TMSI_t s_TMSI = rrcConnectionRequest_NB->ue_Identity_r13.choice.s_TMSI; mme_code_t mme_code = BIT_STRING_to_uint8(&s_TMSI.mmec); m_tmsi_t m_tmsi = BIT_STRING_to_uint32(&s_TMSI.m_TMSI); random_value = (((uint64_t)mme_code) << 32) | m_tmsi; - - if ((ue_context_p = rrc_eNB_ue_context_stmsi_exist_NB(ctxt_pP, mme_code, m_tmsi))) { - LOG_I(RRC," S-TMSI exists, ue_context_p %p, old rnti %x => %x\n",ue_context_p,ue_context_p->ue_context.rnti,ctxt_pP->rnti); - //rrc_mac_remove_ue_NB_IoT(ctxt_pP->module_id, ue_context_p->ue_context.rnti); - stmsi_received=1; - + if ((ue_context_p = rrc_eNB_ue_context_stmsi_exist(ctxt_pP, mme_code, m_tmsi))) { + LOG_I(RRC," S-TMSI exists, ue_context_p %p, old rnti %x => %x\n",ue_context_p,ue_context_p->ue_context.rnti,ctxt_pP->rnti); + rrc_mac_remove_ue(ctxt_pP->module_id, ue_context_p->ue_context.rnti); + stmsi_received=1; /* replace rnti in the context */ /* for that, remove the context from the RB tree */ - - ///FIXME MP: warning --> implicit declaration because I insert the new type "rrc_ue_tree_NB_IoT_s" - RB_REMOVE(rrc_ue_tree_NB_IoT_s, &eNB_rrc_inst_NB_IoT[ctxt_pP->module_id].rrc_ue_head, ue_context_p); + RB_REMOVE(rrc_ue_tree_s, &eNB_rrc_inst[ctxt_pP->module_id].rrc_ue_head, ue_context_p); /* and insert again, after changing rnti everywhere it has to be changed */ ue_context_p->ue_id_rnti = ctxt_pP->rnti; - ue_context_p->ue_context.rnti = ctxt_pP->rnti; - RB_INSERT(rrc_ue_tree_NB_IoT_s, &eNB_rrc_inst_NB_IoT[ctxt_pP->module_id].rrc_ue_head, ue_context_p); + ue_context_p->ue_context.rnti = ctxt_pP->rnti; + RB_INSERT(rrc_ue_tree_s, &eNB_rrc_inst[ctxt_pP->module_id].rrc_ue_head, ue_context_p); /* reset timers */ ue_context_p->ue_context.ul_failure_timer = 0; ue_context_p->ue_context.ue_release_timer = 0; } else { - LOG_I(RRC," S-TMSI doesn't exist, setting Initialue_identity_s_TMSI.m_tmsi to %p => %x\n",ue_context_p,m_tmsi); - ue_context_p = rrc_eNB_get_next_free_ue_context_NB_IoT(ctxt_pP, NOT_A_RANDOM_UE_IDENTITY); + LOG_I(RRC," S-TMSI doesn't exist, setting Initialue_identity_s_TMSI.m_tmsi to %p => %x\n",ue_context_p,m_tmsi); + ue_context_p = rrc_eNB_get_next_free_ue_context(ctxt_pP, NOT_A_RANDOM_UE_IDENTITY); if (ue_context_p == NULL) - LOG_E(RRC, "%s:%d:%s: rrc_eNB_get_next_free_ue_context_NB_IoT returned NULL\n", __FILE__, __LINE__, __FUNCTION__); + LOG_E(RRC, "%s:%d:%s: rrc_eNB_get_next_free_ue_context returned NULL\n", __FILE__, __LINE__, __FUNCTION__); if (ue_context_p != NULL) { - ue_context_p->ue_context.Initialue_identity_s_TMSI.presence = TRUE; - ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code = mme_code; - ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi = m_tmsi; + ue_context_p->ue_context.Initialue_identity_s_TMSI.presence = TRUE; + ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code = mme_code; + ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi = m_tmsi; } else { /* TODO: do we have to break here? */ //break; @@ -2024,7 +2291,7 @@ int rrc_eNB_decode_ccch_NB_IoT( MSC_RRC_UE, Srb_info->Rx_buffer.Payload, dec_rval.consumed, - MSC_AS_TIME_FMT" RRCConnectionRequest-NB UE %x size %u (s-TMSI mmec %u m_TMSI %u random UE id (0x%" PRIx64 ")", + MSC_AS_TIME_FMT" RRCConnectionRequest UE %x size %u (s-TMSI mmec %u m_TMSI %u random UE id (0x%" PRIx64 ")", MSC_AS_TIME_ARGS(ctxt_pP), ue_context_p->ue_context.rnti, dec_rval.consumed, @@ -2033,11 +2300,10 @@ int rrc_eNB_decode_ccch_NB_IoT( ue_context_p->ue_context.random_ue_identity); } else { LOG_E(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionRequest-NB without random UE identity or S-TMSI not supported, let's reject the UE\n", + PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionRequest without random UE identity or S-TMSI not supported, let's reject the UE\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); - - rrc_eNB_generate_RRCConnectionReject_NB_IoT(ctxt_pP, - rrc_eNB_get_ue_context_NB_IoT(&eNB_rrc_inst_NB_IoT[ctxt_pP->module_id], ctxt_pP->rnti), + rrc_eNB_generate_RRCConnectionReject(ctxt_pP, + rrc_eNB_get_ue_context(&eNB_rrc_inst[ctxt_pP->module_id], ctxt_pP->rnti), CC_id); break; } @@ -2051,58 +2317,71 @@ int rrc_eNB_decode_ccch_NB_IoT( if (ue_context_p != NULL) { -//#if defined(ENABLE_ITTI) - ue_context_p->ue_context.establishment_cause_NB_IoT = rrcConnectionRequest_NB_IoT->establishmentCause_r13; - if (stmsi_received==0){ - LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection from UE random UE identity (0x%" PRIx64 ") MME code %u TMSI %u cause %ld\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - ue_context_p->ue_context.random_ue_identity, - ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code, - ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, - ue_context_p->ue_context.establishment_cause_NB_IoT); - } - else{ - LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection from UE MME code %u TMSI %u cause %ld\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code, - ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, - ue_context_p->ue_context.establishment_cause_NB_IoT); - } -//#else -// LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection for UE random UE identity (0x%" PRIx64 ")\n", -// PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), -// ue_context_p->ue_context.random_ue_identity); -//#endif +#if defined(ENABLE_ITTI) + ue_context_p->ue_context.establishment_cause = rrcConnectionRequest_NB->establishmentCause_r13; + if (stmsi_received==0) + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection from UE random UE identity (0x%" PRIx64 ") MME code %u TMSI %u cause %ld\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_p->ue_context.random_ue_identity, + ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code, + ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, + ue_context_p->ue_context.establishment_cause); + else + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection from UE MME code %u TMSI %u cause %ld\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_p->ue_context.Initialue_identity_s_TMSI.mme_code, + ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi, + ue_context_p->ue_context.establishment_cause); +#else + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Accept new connection for UE random UE identity (0x%" PRIx64 ")\n", + PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), + ue_context_p->ue_context.random_ue_identity); +#endif if (stmsi_received == 0) - eNB_rrc_inst_NB_IoT[ctxt_pP->module_id].Nb_ue++; + eNB_rrc_inst[ctxt_pP->module_id].Nb_ue++; } else { // no context available LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Can't create new context for UE random UE identity (0x%" PRIx64 ")\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), random_value); - //rrc_mac_remove_ue_NB_IoT(ctxt_pP->module_id,ctxt_pP->rnti); + rrc_mac_remove_ue(ctxt_pP->module_id,ctxt_pP->rnti); return -1; } } -//MP: RRM not used -//#ifndef NO_RRM -// send_msg(&S_rrc, msg_rrc_MR_attach_ind(ctxt_pP->module_id, Mac_id)); -//#else +#ifndef NO_RRM + send_msg(&S_rrc, msg_rrc_MR_attach_ind(ctxt_pP->module_id, Mac_id)); +#else ue_context_p->ue_context.primaryCC_id = CC_id; - // SRB1bis (LCID = 3 = DCCH0) - ue_context_p->ue_context.Srb1bis.Active = 1; - ue_context_p->ue_context.Srb1bis.Srb_info.Srb_id = DCCH0_NB_IoT; - - //generate RRCConnectionSetup-NB - rrc_eNB_generate_RRCConnectionSetup_NB_IoT(ctxt_pP, ue_context_p, CC_id); - - LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT"CALLING RLC CONFIG SRB1bis and SRB1 (rbid %d, rbid %d)\n", + //LG COMMENT Idx = (ue_mod_idP * NB_RB_MAX) + DCCH; + Idx = DCCH; + // SRB1 + ue_context_p->ue_context.Srb1.Active = 1; + ue_context_p->ue_context.Srb1.Srb_info.Srb_id = Idx; //module_id + memcpy(&ue_context_p->ue_context.Srb1.Srb_info.Lchan_desc[0], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + memcpy(&ue_context_p->ue_context.Srb1.Srb_info.Lchan_desc[1], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + + // SRB2: set it to go through SRB1 with id 1 (DCCH) ???? + ue_context_p->ue_context.Srb2.Active = 1; + ue_context_p->ue_context.Srb2.Srb_info.Srb_id = Idx; + memcpy(&ue_context_p->ue_context.Srb2.Srb_info.Lchan_desc[0], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + memcpy(&ue_context_p->ue_context.Srb2.Srb_info.Lchan_desc[1], + &DCCH_LCHAN_DESC, + LCHAN_DESC_SIZE); + + rrc_eNB_generate_RRCConnectionSetup(ctxt_pP, ue_context_p, CC_id); + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT"CALLING RLC CONFIG SRB1 (rbid %d)\n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH0_NB_IoT, DCCH1_NB_IoT); + Idx); MSC_LOG_TX_MESSAGE( MSC_RRC_ENB, @@ -2113,8 +2392,7 @@ int rrc_eNB_decode_ccch_NB_IoT( MSC_AS_TIME_ARGS(ctxt_pP), ue_context_p->ue_context.rnti); - //MP: we should not configure PDCP for SRB1bis but only for SRB1 - rrc_pdcp_config_asn1_req_NB_IoT(ctxt_pP, + rrc_pdcp_config_asn1_req_NB_IoT(ctxt_pP, ue_context_p->ue_context.SRB_configList, //contain SRB1bis but used as SRB1 (DRB_ToAddModList_NB_r13_t *) NULL, (DRB_ToReleaseList_NB_r13_t*) NULL, @@ -2123,65 +2401,23 @@ int rrc_eNB_decode_ccch_NB_IoT( NULL, NULL, NULL, - DCCH1_NB_IoT); - - ///MP: Configure RLC for SRB1bis + DCCH1_NB_IoT); + //Configure RLC for SRB1bis rrc_rlc_config_asn1_req_NB_IoT(ctxt_pP, ue_context_p->ue_context.SRB_configList, (DRB_ToAddModList_NB_r13_t*) NULL, (DRB_ToReleaseList_NB_r13_t*) NULL, - SRB1BIS_FLAG_YES + SRB1BIS_FLAG_YES ); - //MP: Configure RLC for SRB1 - rrc_rlc_config_asn1_req_NB_IoT(ctxt_pP, + //Configure RLC for SRB1 + rrc_rlc_config_asn1_req_NB_IoT(ctxt_pP, ue_context_p->ue_context.SRB_configList, (DRB_ToAddModList_NB_r13_t*) NULL, (DRB_ToReleaseList_NB_r13_t*) NULL, - SRB1BIS_FLAG_NO - ); -//#endif //NO_RRM - - break; //RRCConnectionSetup-NB - - case UL_CCCH_MessageType_NB__c1_PR_rrcConnectionResumeRequest_r13: - // TS 36.331 accept the resume, or switch back to a Connection setup or reject the request - - T(T_ENB_RRC_CONNECTION_RESUME_REQUEST, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - - #ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRCConnectionResumeRequest-NB\n"); - - for (i = 0; i < Srb_info->Rx_buffer.payload_size; i++) { - LOG_F(RRC,"%02x ", ((uint8_t*)Srb_info->Rx_buffer.Payload)[i]); - } - - LOG_F(RRC,"\n"); - #endif - - LOG_D(RRC, PROTOCOL_RRC_CTXT_UE_FMT"MAC_eNB--- MAC_DATA_IND (rrcConnectionResumeRequest-NB on SRB0) --> RRC_eNB\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); - rrcConnectionResumeRequest_NB_IoT= - &ul_ccch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionResumeRequest_r13.criticalExtensions.choice.rrcConnectionResumeRequest_r13; - - LOG_I(RRC,PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionResumeRequest-NB cause %s\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - ((rrcConnectionResumeRequest_NB_IoT->resumeCause_r13 == EstablishmentCause_NB_r13_mt_Access) ? "mt Access" : - (rrcConnectionResumeRequest_NB_IoT->resumeCause_r13 == EstablishmentCause_NB_r13_mo_Signalling) ? "mo Signalling" : - (rrcConnectionResumeRequest_NB_IoT->resumeCause_r13 == EstablishmentCause_NB_r13_mo_Data) ? "mo Data": - (rrcConnectionResumeRequest_NB_IoT->resumeCause_r13 == EstablishmentCause_NB_r13_mo_ExceptionData) ? "mo Exception data" : - "delay tollerant Access v1330")); - - //MP: only reject for now - rrc_eNB_generate_RRCConnectionReject_NB_IoT(ctxt_pP, - rrc_eNB_get_ue_context_NB_IoT(&eNB_rrc_inst_NB_IoT[ctxt_pP->module_id], ctxt_pP->rnti), - CC_id); - break; + SRB1BIS_FLAG_NO + ); +#endif //NO_RRM - default: - LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Unknown message\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); - rval = -1; break; } @@ -2195,6 +2431,11 @@ int rrc_eNB_decode_ccch_NB_IoT( return rval; } +/**************************************************************************************************/ + + + +/************************************Decode DCCH for NB_IoT*****************************************/ //----------------------------------------------------------------------------- int rrc_eNB_decode_dcch_NB_IoT( const protocol_ctxt_t* const ctxt_pP, @@ -2204,12 +2445,13 @@ int rrc_eNB_decode_dcch_NB_IoT( ) //----------------------------------------------------------------------------- { - + + asn_dec_rval_t dec_rval; UL_DCCH_Message_NB_t *ul_dcch_msg_NB_IoT = NULL; UE_Capability_NB_r13_t *UE_Capability_NB = NULL; int i; - struct rrc_eNB_ue_context_NB_IoT_s* ue_context_p = NULL; + struct rrc_eNB_ue_context_s* ue_context_p = NULL; int dedicated_DRB=0; @@ -2236,17 +2478,23 @@ int rrc_eNB_decode_dcch_NB_IoT( sdu_sizeP, 0, 0); +/* + printf("....after uper_decode....\n"); + printf("Rx_sdu : %d\n",Rx_sdu); + printf("sdu_sizeP : %d\n", sdu_sizeP); +*/ //#if defined(ENABLE_ITTI) //# if defined(DISABLE_ITTI_XER_PRINT) - { + for (i = 0; i < sdu_sizeP; i++) { - LOG_T(RRC, "%x.", Rx_sdu[i]); + printf("%02x ", Rx_sdu[i]); } - LOG_T(RRC, "\n"); - } + printf("\n"); + + if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { LOG_E(RRC, PROTOCOL_RRC_CTXT_UE_FMT" Failed to decode UL-DCCH (%zu bytes)\n", @@ -2255,128 +2503,16 @@ int rrc_eNB_decode_dcch_NB_IoT( return -1; } - ue_context_p = rrc_eNB_get_ue_context_NB_IoT( - &eNB_rrc_inst_NB_IoT[ctxt_pP->module_id], + ue_context_p = rrc_eNB_get_ue_context( + &eNB_rrc_inst[ctxt_pP->module_id], ctxt_pP->rnti); if (ul_dcch_msg_NB_IoT->message.present == UL_DCCH_MessageType_NB_PR_c1) { switch (ul_dcch_msg_NB_IoT->message.choice.c1.present) { - case UL_DCCH_MessageType_NB__c1_PR_NOTHING: /* No components present */ - break; - - //no measurement reports - - case UL_DCCH_MessageType_NB__c1_PR_rrcConnectionReconfigurationComplete_r13: - -#ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRCConnectionReconfigurationComplete-NB\n"); - - for (i = 0; i < sdu_sizeP; i++) { - LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); - } - - LOG_F(RRC,"\n"); -#endif - MSC_LOG_RX_MESSAGE( - MSC_RRC_ENB, - MSC_RRC_UE, - Rx_sdu, - sdu_sizeP, - MSC_AS_TIME_FMT" RRCConnectionReconfigurationComplete-NB UE %x size %u", - MSC_AS_TIME_ARGS(ctxt_pP), - ue_context_p->ue_context.rnti, - sdu_sizeP); - - LOG_D(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " - "(RRCConnectionReconfigurationComplete-NB) ---> RRC_eNB]\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH1_NB_IoT, //through SRB1 - sdu_sizeP); - - if (ul_dcch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionReconfigurationComplete_r13.criticalExtensions. - present == RRCConnectionReconfigurationComplete_NB__criticalExtensions_PR_rrcConnectionReconfigurationComplete_r13) { - /*NN: revise the condition */ - - //MP: RRC_RECONFIGURED_NB_IoT indicate if the default/dedicated bearer has been/not established - - if (ue_context_p->ue_context.Status == RRC_RECONFIGURED_NB_IoT){ // a dedicated bearers has been established - dedicated_DRB = 1; - LOG_I(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_RECONFIGURED_NB_IoT (dedicated DRB, xid %ld)\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),ul_dcch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionReconfigurationComplete_r13.rrc_TransactionIdentifier); - }else { //a default bearer has been established - dedicated_DRB = 0; - ue_context_p->ue_context.Status = RRC_RECONFIGURED_NB_IoT; - LOG_I(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_RECONFIGURED_NB_IoT (default DRB, xid %ld)\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),ul_dcch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionReconfigurationComplete_r13.rrc_TransactionIdentifier); - } - rrc_eNB_process_RRCConnectionReconfigurationComplete_NB_IoT( - ctxt_pP, - ue_context_p, - ul_dcch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionReconfigurationComplete_r13.rrc_TransactionIdentifier); - - } - -//#if defined(ENABLE_ITTI)... -#if defined(ENABLE_USE_MME) - if (EPC_MODE_ENABLED == 1) { - if (dedicated_DRB == 1){ - rrc_eNB_send_S1AP_E_RAB_SETUP_RESP(ctxt_pP, - ue_context_p, - ul_dcch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionReconfigurationComplete_r13.rrc_TransactionIdentifier); - }else { - rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP(ctxt_pP, - ue_context_p); - } - } -#else // MP: not use of MME - //dedicated bearer in the absence of EPC - if (dedicated_DRB == 0 ) { - rrc_eNB_reconfigure_DRBs_NB_IoT(ctxt_pP,ue_context_p); //MP: establish a dedicated DRB - } -#endif - - break; - - case UL_DCCH_MessageType_NB__c1_PR_rrcConnectionReestablishmentComplete_r13: - //for the moment will be not possible since we reject any connectionReestablishmentRequest - - T(T_ENB_RRC_CONNECTION_REESTABLISHMENT_COMPLETE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - -#ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRCConnectionReestablishmentComplete-NB \n"); - - for (i = 0; i < sdu_sizeP; i++) { - LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); - } - - LOG_F(RRC,"\n"); -#endif - - MSC_LOG_RX_MESSAGE( - MSC_RRC_ENB, - MSC_RRC_UE, - Rx_sdu, - sdu_sizeP, - MSC_AS_TIME_FMT" rrcConnectionReestablishmentComplete-NB UE %x size %u", - MSC_AS_TIME_ARGS(ctxt_pP), - ue_context_p->ue_context.rnti, - sdu_sizeP); - - LOG_I(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " - "(rrcConnectionReestablishmentComplete-NB) ---> RRC_eNB\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH0_NB_IoT, - sdu_sizeP); - break; case UL_DCCH_MessageType_NB__c1_PR_rrcConnectionSetupComplete_r13: - //MP: Ts 36.331 V14.2.1 RRCConnectionSetupComplete is transmitted over SRB1bis (pag 585) + //MP: Ts 36.331 V14.2.1 RRCConnectionSetupComplete is transmitted over SRB1bis (pag 585) #ifdef RRC_MSG_PRINT LOG_F(RRC,"[MSG] RRCConnectionSetupComplete-NB\n"); @@ -2406,310 +2542,28 @@ int rrc_eNB_decode_dcch_NB_IoT( sdu_sizeP); if (ul_dcch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionSetupComplete_r13.criticalExtensions.present == - RRCConnectionSetupComplete_NB__criticalExtensions_PR_rrcConnectionSetupComplete_r13) { + RRCConnectionSetupComplete_NB__criticalExtensions_PR_rrcConnectionSetupComplete_r13) { + + LOG_I(RRC,"selectedPLMN_Identity_r13 : %ld\n",ul_dcch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionSetupComplete_r13.criticalExtensions.choice.rrcConnectionSetupComplete_r13.selectedPLMN_Identity_r13); + + LOG_I(RRC,"dedicatedInfoNAS_r13 : %02x\n",ul_dcch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionSetupComplete_r13.criticalExtensions.choice.rrcConnectionSetupComplete_r13.dedicatedInfoNAS_r13); rrc_eNB_process_RRCConnectionSetupComplete_NB_IoT( ctxt_pP, ue_context_p, &ul_dcch_msg_NB_IoT->message.choice.c1.choice.rrcConnectionSetupComplete_r13.criticalExtensions.choice.rrcConnectionSetupComplete_r13); - - //set Ue status CONNECTED - ue_context_p->ue_context.Status = RRC_CONNECTED_NB_IoT; - - LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_CONNECTED_NB_IoT \n", + //set Ue status CONNECTED + ue_context_p->ue_context.Status = RRC_CONNECTED_NB_IoT; + LOG_I(RRC, PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_CONNECTED_NB_IoT \n", PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP)); - - } ue_context_p->ue_context.ue_release_timer=0; break; - case UL_DCCH_MessageType_NB__c1_PR_securityModeComplete_r13: - - /* R2-163262 3GPP NB-IOT Ad-hoc Meeting #2 - * After receiving the SMC and performing the security activation, the UE shall use the SRB1. - */ - - T(T_ENB_RRC_SECURITY_MODE_COMPLETE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - -#ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRC SecurityModeComplete-NB\n"); - - for (i = 0; i < sdu_sizeP; i++) eNB->pusch_vars[UE_id]{ - LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); - } - - LOG_F(RRC,"\n"); -#endif - - MSC_LOG_RX_MESSAGE( - MSC_RRC_ENB, - MSC_RRC_UE, - Rx_sdu, - sdu_sizeP, - MSC_AS_TIME_FMT" securityModeComplete UE %x size %u", - MSC_AS_TIME_ARGS(ctxt_pP), - ue_context_p->ue_context.rnti, - sdu_sizeP); - - LOG_I(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" received securityModeComplete-NB on UL-DCCH %d from UE\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH0_NB_IoT); - LOG_D(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " - "(securityModeComplete-NB) ---> RRC_eNB\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH0_NB_IoT,//through SRB1bis - sdu_sizeP); -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_UL_DCCH_Message_NB, (void *)ul_dcch_msg_NB_IoT); -#endif - - - - //MP: this is OPTIONAL - ue_context_p->ue_context.Srb1bis.Active=0; - - - rrc_eNB_generate_UECapabilityEnquiry_NB_IoT(ctxt_pP, ue_context_p); - - break; - - case UL_DCCH_MessageType_NB__c1_PR_securityModeFailure_r13: - - //MP: Security Mode failure should be received over SRB1bis since the security activation fails - /*(see R2-163262) - The SRB1-bis (no PDCP) is used for SecurityModeCommand and SecurityModeFailure messages, - The SRB1 (full PDCP) is used for SecurityModeComplete message.*/ - - /* - * Furthermore from TS 36.331 ch:5.3.4.3 Reception of the SecurityModeCommand by the UE - * if the SecurityModeCommand message passes the integrity protection check - * .... - * else - * 2> continue using the configuration used prior to the reception of the SecurityModeCommand message, - * i.e. neither apply integrity protection nor ciphering. - * 2> submit the SecurityModeFailure message to lower layers for transmission, upon which the procedure ends - */ - - T(T_ENB_RRC_SECURITY_MODE_FAILURE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - -#ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRC SecurityModeFailure-NB\n"); - - for (i = 0; i < sdu_sizeP; i++) { - LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); - } - - LOG_F(RRC,"\n"); -#endif - - MSC_LOG_RX_MESSAGE( - MSC_RRC_ENB, - MSC_RRC_UE, - Rx_sdu, - sdu_sizeP, - MSC_AS_TIME_FMT" securityModeFailure-NB UE %x size %u", - MSC_AS_TIME_ARGS(ctxt_pP), - ue_context_p->ue_context.rnti, - sdu_sizeP); - - LOG_W(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " - "(securityModeFailure-NB) ---> RRC_eNB\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH0_NB_IoT, - sdu_sizeP); - -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_UL_DCCH_Message_NB, (void *)ul_dcch_msg_NB_IoT); -#endif - - -//MP: After reception of SecurityModeFailure we should configure no security -//therefore setting securityActivated=0 for the corresponding PDCP entity in the PDCP but still start the usage of SRB1 - - - // pdcp_pP-> security_activated modified (=1) by pdcp_config_set_security in pdcp_config_req_asn1_NB_IoT at configuration time - // we now create a particular case for pdcp_config_set_securityy function in which for a particular securityMode (= -1) we deactivate security. - // we first invoke the rrc_pdcp_config_asn1_req_NB_IoT that with the particular case of securityMode = -1 will disable security through the pdcp_config_set_security - - -//MP: the integrity protection is still not used in OAI --> MAC-I is padded always to 0 so no need to modify it - - rrc_pdcp_config_asn1_req_NB_IoT( - ctxt_pP, - ue_context_p->ue_context.SRB_configList, - (DRB_ToAddModList_NB_r13_t *)NULL, - (DRB_ToReleaseList_NB_r13_t*)NULL, - -1, //security_modeP particular case - NULL, - NULL, - NULL, - NULL, - DCCH1_NB_IoT//its only for check purposes (if correctly called could be deleted) - ); - - rrc_eNB_generate_UECapabilityEnquiry_NB_IoT(ctxt_pP, ue_context_p); - - break; - - case UL_DCCH_MessageType_NB__c1_PR_ueCapabilityInformation_r13: - - //MP: received over SRB1 - - T(T_ENB_RRC_UE_CAPABILITY_INFORMATION, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - -#ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRC UECapablilityInformation-NB \n"); - - for (i = 0; i < sdu_sizeP; i++) { - LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); - } - - LOG_F(RRC,"\n"); -#endif - - MSC_LOG_RX_MESSAGE( - MSC_RRC_ENB, - MSC_RRC_UE, - Rx_sdu, - sdu_sizeP, - MSC_AS_TIME_FMT" ueCapabilityInformation-NB UE %x size %u", - MSC_AS_TIME_ARGS(ctxt_pP), - ue_context_p->ue_context.rnti, - sdu_sizeP); - - LOG_I(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" received ueCapabilityInformation-NB on UL-DCCH %d from UE\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH1_NB_IoT); - LOG_D(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " - "(UECapabilityInformation) ---> RRC_eNB\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH1_NB_IoT, - sdu_sizeP); -#ifdef XER_PRINT - xer_fprint(stdout, &asn_DEF_UL_DCCH_Message_NB, (void *)ul_dcch_msg); -#endif - LOG_I(RRC, "got UE capabilities for UE %x\n", ctxt_pP->rnti); - - - //FIXME MP: ueCapabilityInformation different w.r.t LTE --> how to decode it? - dec_rval = uper_decode(NULL, - &asn_DEF_UE_Capability_NB_r13, - (void **)&UE_Capability_NB, - Rx_sdu, //*buffer//FIXME may this is not the best way (may incorrect) - sdu_sizeP,//*size //FIXME may this is not the best way (may incorrect) - 0, //skip bits - 0); //unused bits - -#if defined(ENABLE_USE_MME) - - if (EPC_MODE_ENABLED == 1) { - rrc_eNB_send_S1AP_UE_CAPABILITIES_IND(ctxt_pP, - ue_context_p, - ul_dcch_msg_NB_IoT); - } -#else - ue_context_p->ue_context.nb_of_e_rabs = 1; - //FIXME may no more present in NB_IoT or different parameter to set - for (i = 0; i < ue_context_p->ue_context.nb_of_e_rabs; i++){ - ue_context_p->ue_context.e_rab[i].status = E_RAB_STATUS_NEW_NB_IoT; - ue_context_p->ue_context.e_rab[i].param.e_rab_id = 1+i; - ue_context_p->ue_context.e_rab[i].param.qos.qci=9; //Non-GBR - } - ue_context_p->ue_context.setup_e_rabs =ue_context_p->ue_context.nb_of_e_rabs; -#endif - - rrc_eNB_generate_defaultRRCConnectionReconfiguration_NB_IoT(ctxt_pP, ue_context_p);//no HO_FLAG - - break; - - ///no ULHandoverPreparationTransfer - - case UL_DCCH_MessageType_NB__c1_PR_ulInformationTransfer_r13: - T(T_ENB_RRC_UL_INFORMATION_TRANSFER, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - -#ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRC ULInformationTransfer-NB \n"); - - for (i = 0; i < sdu_sizeP; i++) { - LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); - } - - LOG_F(RRC,"\n"); -#endif - - - MSC_LOG_RX_MESSAGE( - MSC_RRC_ENB, - MSC_RRC_UE, - Rx_sdu, - sdu_sizeP, - MSC_AS_TIME_FMT" ulInformationTransfer-NB UE %x size %u", - MSC_AS_TIME_ARGS(ctxt_pP), - ue_context_p->ue_context.rnti, - sdu_sizeP); - -#if defined(ENABLE_USE_MME) - - if (EPC_MODE_ENABLED == 1) { - rrc_eNB_send_S1AP_UPLINK_NAS(ctxt_pP, - ue_context_p, - ul_dcch_msg_NB_IoT); - } - -#endif - break; - - ///no CounterCheckResponse - - case UL_DCCH_MessageType_NB__c1_PR_rrcConnectionResumeComplete_r13: - - //will be not possible because for the moment we reject any ConnectionResumeRequest - - T(T_ENB_RRC_CONNECTION_RESUME_COMPLETE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), - T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); - - #ifdef RRC_MSG_PRINT - LOG_F(RRC,"[MSG] RRCConnectionResumeComplete-NB \n"); - - for (i = 0; i < sdu_sizeP; i++) { - LOG_F(RRC,"%02x ", ((uint8_t*)Rx_sdu)[i]); - } - - LOG_F(RRC,"\n"); - #endif - - MSC_LOG_RX_MESSAGE( - MSC_RRC_ENB, - MSC_RRC_UE, - Rx_sdu, - sdu_sizeP, - MSC_AS_TIME_FMT" rrcConnectionResumeComplete-NB UE %x size %u", - MSC_AS_TIME_ARGS(ctxt_pP), - ue_context_p->ue_context.rnti, - sdu_sizeP); - - LOG_I(RRC, - PROTOCOL_RRC_CTXT_UE_FMT" RLC RB %02d --- RLC_DATA_IND %d bytes " - "(rrcConnectionResumeComplete-NB) ---> RRC_eNB\n", - PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), - DCCH0_NB_IoT, //check - sdu_sizeP); - - break; - - default: + + default: T(T_ENB_RRC_UNKNOW_MESSAGE, T_INT(ctxt_pP->module_id), T_INT(ctxt_pP->frame), T_INT(ctxt_pP->subframe), T_INT(ctxt_pP->rnti)); @@ -2718,6 +2572,8 @@ int rrc_eNB_decode_dcch_NB_IoT( PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP), __FILE__, __LINE__); return -1; + + } return 0; @@ -2730,6 +2586,9 @@ int rrc_eNB_decode_dcch_NB_IoT( } +/*******************************************************************************************/ + + //----------------------------------------------------------------------------- //put out from the ITTI FIXME is completely based on ITTI--> must be changed (msg_p, itti_receive_msg ecc...) void* rrc_enb_task_NB_IoT( diff --git a/openair2/RRC/LITE/rrc_eNB_UE_context_NB_IoT.c b/openair2/RRC/NBIOT/rrc_eNB_UE_context_NB_IoT.c similarity index 100% rename from openair2/RRC/LITE/rrc_eNB_UE_context_NB_IoT.c rename to openair2/RRC/NBIOT/rrc_eNB_UE_context_NB_IoT.c diff --git a/openair2/RRC/LITE/rrc_eNB_UE_context_NB_IoT.h b/openair2/RRC/NBIOT/rrc_eNB_UE_context_NB_IoT.h similarity index 100% rename from openair2/RRC/LITE/rrc_eNB_UE_context_NB_IoT.h rename to openair2/RRC/NBIOT/rrc_eNB_UE_context_NB_IoT.h diff --git a/openair2/RRC/LITE/rrc_types_NB_IoT.h b/openair2/RRC/NBIOT/rrc_types_NB_IoT.h similarity index 100% rename from openair2/RRC/LITE/rrc_types_NB_IoT.h rename to openair2/RRC/NBIOT/rrc_types_NB_IoT.h diff --git a/openair2/RRC/LITE/vars_NB_IoT.h b/openair2/RRC/NBIOT/vars_NB_IoT.h similarity index 100% rename from openair2/RRC/LITE/vars_NB_IoT.h rename to openair2/RRC/NBIOT/vars_NB_IoT.h diff --git a/targets/RT/USER/lte-enb-nbiot.c b/targets/RT/USER/lte-enb-nbiot.c new file mode 100755 index 0000000000000000000000000000000000000000..c513783de1a53af808766700a053424a54f3af6c --- /dev/null +++ b/targets/RT/USER/lte-enb-nbiot.c @@ -0,0 +1,434 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file lte-enb.c + * \brief Top-level threads for eNodeB + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sched.h> +#include <linux/sched.h> +#include <signal.h> +#include <execinfo.h> +#include <getopt.h> +#include <sys/sysinfo.h> +#include "rt_wrapper.h" + +#include "time_utils.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "assertions.h" +#include "msc.h" + +#include "PHY/types.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "../../ARCH/COMMON/common_lib.h" + +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/LTE_TRANSPORT/if5_tools.h" + +#include "PHY/extern.h" +#include "SCHED/extern.h" + +#include "../../SIMU/USER/init_lte.h" + +//NB-IoT +#include "PHY/defs.h" +#include "PHY/defs_NB_IoT.h" +//#include "PHY/defs_L1_NB_IoT.h" +#include "SCHED/defs_NB_IoT.h" +#include "SCHED/sched_common.h" // for calling prach_procedures_NB_IoT() +#include "PHY_INTERFACE/IF_Module_NB_IoT.h" +#include "LAYER2/MAC/extern_NB_IoT.h" +#include "PHY/extern_NB_IoT.h" +#include "LAYER2/MAC/defs.h" +#include "PHY_INTERFACE/extern.h" + +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" +//#include "PHY/TOOLS/time_meas.h" + +#ifndef OPENAIR2 +#include "UTIL/OTG/otg_extern.h" +#endif + +#if defined(ENABLE_ITTI) +# if defined(ENABLE_USE_MME) +# include "s1ap_eNB.h" +#ifdef PDCP_USE_NETLINK +# include "SIMULATION/ETH_TRANSPORT/proto.h" +#endif +# endif +#endif + +#include "T.h" + +void init_eNB_NB_IoT(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst,eth_params_t *,int,int); +extern void do_prach(PHY_VARS_eNB *eNB,int frame,int subframe); + + + +//Modify for NB-IoT merge +static inline int rxtx_NB_IoT(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) { + ///start_meas(&softmodem_stats_rxtx_sf); + + // **************************************** + // Common RX procedures subframe n + + + if ((eNB->do_prach)&&((eNB->node_function != NGFI_RCC_IF4p5))) + eNB->do_prach(eNB,proc->frame_rx,proc->subframe_rx); + phy_procedures_eNB_common_RX(eNB,proc); + + // UE-specific RX processing for subframe n + ///////////////////////////////////// for NB-IoT testing //////////////////////// + // for NB-IoT testing // activating only TX part + if (eNB->proc_uespec_rx) eNB->proc_uespec_rx(eNB, proc, no_relay ); + ////////////////////////////////////END/////////////////////// + + //npusch_procedures(eNB,proc,data_or_control); + //fill_rx_indication(eNB,i,frame,subframe); + //////////////////////////////////// for IF Module/scheduler testing + + 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->UL_INFO.hypersfn = proc->HFN; + + eNB->if_inst->UL_indication(&eNB->UL_INFO); + + pthread_mutex_unlock(&eNB->UL_INFO_mutex); + + //LOG_I(PHY,"After UL_indication\n"); + // ***************************************** + // TX processing for subframe n+4 + // run PHY TX procedures the one after the other for all CCs to avoid race conditions + // (may be relaxed in the future for performance reasons) + // ***************************************** + //if (wait_CCs(proc)<0) return(-1); + + if (oai_exit) return(-1); + + if (eNB->proc_tx) eNB->proc_tx(eNB, proc, no_relay, NULL ); + + if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) return(-1); + + /// stop_meas( &softmodem_stats_rxtx_sf ); + + return(0); +} + + + +/*! + * \brief The prach receive thread of eNB. + * \param param is a \ref eNB_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ +static void* eNB_thread_prach_NB_IoT( void* param ) { + static int eNB_thread_prach_status; + + PHY_VARS_eNB *eNB= (PHY_VARS_eNB *)param; + L1_proc_t *proc = &eNB->proc; + + // set default return value + eNB_thread_prach_status = 0; + + thread_top_init("eNB_thread_prach",1,500000L,1000000L,20000000L); + + while (!oai_exit) { + + if (oai_exit) break; + + if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break; + + //prach_procedures(eNB); + + ////// NB_IoT testing /////// + prach_procedures_NB_IoT(eNB); + ///////////////////////////// + + if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break; + } + + printf( "Exiting eNB thread PRACH\n"); + + eNB_thread_prach_status = 0; + return &eNB_thread_prach_status; +} + + + +///Modify to NB-IoT merge +void init_eNB_NB_IoT(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst,eth_params_t *eth_params,int single_thread_flag,int wait_for_sync) { + + int CC_id; + int inst; + PHY_VARS_eNB *eNB; + int ret; + + for (inst=0;inst<nb_inst;inst++) { + for (CC_id=0;CC_id<MAX_NUM_CCs;CC_id++) { + eNB = PHY_vars_eNB_g[inst][CC_id]; + eNB->node_function = node_function[CC_id]; + eNB->node_timing = node_timing[CC_id]; + eNB->eth_params = eth_params+CC_id; + eNB->abstraction_flag = 0; + eNB->single_thread_flag = single_thread_flag; + eNB->ts_offset = 0; + eNB->in_synch = 0; + eNB->is_slave = (wait_for_sync>0) ? 1 : 0; + + /////// IF-Module initialization /////////////// + + LOG_I(PHY,"Registering with MAC interface module start\n"); + AssertFatal((eNB->if_inst = IF_Module_init_NB_IoT(inst))!=NULL,"Cannot register interface"); + eNB->if_inst->schedule_response = schedule_response_NB_IoT; + eNB->if_inst->PHY_config_req = PHY_config_req_NB_IoT; + LOG_I(PHY,"Registering with MAC interface module sucessfully\n"); + + +#ifndef OCP_FRAMEWORK + LOG_I(PHY,"Initializing eNB %d CC_id %d : (%s,%s)\n",inst,CC_id,eNB_functions[node_function[CC_id]],eNB_timing[node_timing[CC_id]]); +#endif + + switch (node_function[CC_id]) { + case NGFI_RRU_IF5: + eNB->do_prach = NULL; + eNB->do_precoding = 0; + eNB->fep = eNB_fep_rru_if5; + eNB->td = NULL; + eNB->te = NULL; + eNB->proc_uespec_rx = NULL; + eNB->proc_tx = NULL; + eNB->tx_fh = NULL; + eNB->rx_fh = rx_rf; + eNB->start_rf = start_rf; + eNB->start_if = start_if; + eNB->fh_asynch = fh_if5_asynch_DL; + if (oaisim_flag == 0) { + ret = openair0_device_load(&eNB->rfdevice, &openair0_cfg[CC_id]); + if (ret<0) { + printf("Exiting, cannot initialize rf device\n"); + exit(-1); + } + } + eNB->rfdevice.host_type = RRH_HOST; + eNB->ifdevice.host_type = RRH_HOST; + ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], eNB->eth_params); + printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + malloc_IF5_buffer(eNB); + break; + case NGFI_RRU_IF4p5: + eNB->do_precoding = 0; + eNB->do_prach = do_prach; + eNB->fep = eNB_fep_full;//(single_thread_flag==1) ? eNB_fep_full_2thread : eNB_fep_full; + eNB->td = NULL; + eNB->te = NULL; + eNB->proc_uespec_rx = NULL; + eNB->proc_tx = NULL;//proc_tx_rru_if4p5; + eNB->tx_fh = NULL; + eNB->rx_fh = rx_rf; + eNB->fh_asynch = fh_if4p5_asynch_DL; + eNB->start_rf = start_rf; + eNB->start_if = start_if; + if (oaisim_flag == 0) { + ret = openair0_device_load(&eNB->rfdevice, &openair0_cfg[CC_id]); + if (ret<0) { + printf("Exiting, cannot initialize rf device\n"); + exit(-1); + } + } + eNB->rfdevice.host_type = RRH_HOST; + eNB->ifdevice.host_type = RRH_HOST; + printf("loading transport interface ...\n"); + ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], eNB->eth_params); + printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + + malloc_IF4p5_buffer(eNB); + + break; + case eNodeB_3GPP: + eNB->do_precoding = eNB->frame_parms.nb_antennas_tx!=eNB->frame_parms.nb_antenna_ports_eNB; + eNB->do_prach = do_prach; + eNB->fep = eNB_fep_full;//(single_thread_flag==1) ? eNB_fep_full_2thread : eNB_fep_full; + eNB->td = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data; + eNB->te = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding; + ////////////////////// NB-IoT testing //////////////////// + //eNB->proc_uespec_rx = phy_procedures_eNB_uespec_RX; + eNB->proc_uespec_rx = phy_procedures_eNB_uespec_RX_NB_IoT; + + eNB->proc_tx = proc_tx_full; + eNB->tx_fh = NULL; + eNB->rx_fh = rx_rf; + eNB->start_rf = start_rf; + eNB->start_if = NULL; + eNB->fh_asynch = NULL; + if (oaisim_flag == 0) { + ret = openair0_device_load(&eNB->rfdevice, &openair0_cfg[CC_id]); + if (ret<0) { + printf("Exiting, cannot initialize rf device\n"); + exit(-1); + } + } + eNB->rfdevice.host_type = BBU_HOST; + eNB->ifdevice.host_type = BBU_HOST; + break; + case eNodeB_3GPP_BBU: + eNB->do_precoding = eNB->frame_parms.nb_antennas_tx!=eNB->frame_parms.nb_antenna_ports_eNB; + eNB->do_prach = do_prach; + eNB->fep = eNB_fep_full;//(single_thread_flag==1) ? eNB_fep_full_2thread : eNB_fep_full; + eNB->td = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data; + eNB->te = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding; + eNB->proc_uespec_rx = phy_procedures_eNB_uespec_RX; + eNB->proc_tx = proc_tx_full; + if (eNB->node_timing == synch_to_other) { + eNB->tx_fh = tx_fh_if5_mobipass; + eNB->rx_fh = rx_fh_slave; + eNB->fh_asynch = fh_if5_asynch_UL; + + } + else { + eNB->tx_fh = tx_fh_if5; + eNB->rx_fh = rx_fh_if5; + eNB->fh_asynch = NULL; + } + + eNB->start_rf = NULL; + eNB->start_if = start_if; + eNB->rfdevice.host_type = BBU_HOST; + + eNB->ifdevice.host_type = BBU_HOST; + + ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], eNB->eth_params); + printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + malloc_IF5_buffer(eNB); + break; + case NGFI_RCC_IF4p5: + eNB->do_precoding = 0; + eNB->do_prach = do_prach; + eNB->fep = NULL; + eNB->td = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data; + eNB->te = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding; + eNB->proc_uespec_rx = phy_procedures_eNB_uespec_RX; + eNB->proc_tx = proc_tx_high; + eNB->tx_fh = tx_fh_if4p5; + eNB->rx_fh = rx_fh_if4p5; + eNB->start_rf = NULL; + eNB->start_if = start_if; + eNB->fh_asynch = (eNB->node_timing == synch_to_other) ? fh_if4p5_asynch_UL : NULL; + eNB->rfdevice.host_type = BBU_HOST; + eNB->ifdevice.host_type = BBU_HOST; + ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], eNB->eth_params); + printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + malloc_IF4p5_buffer(eNB); + + break; + case NGFI_RAU_IF4p5: + eNB->do_precoding = 0; + eNB->do_prach = do_prach; + eNB->fep = NULL; + + eNB->td = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data; + eNB->te = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding; + eNB->proc_uespec_rx = phy_procedures_eNB_uespec_RX; + eNB->proc_tx = proc_tx_high; + eNB->tx_fh = tx_fh_if4p5; + eNB->rx_fh = rx_fh_if4p5; + eNB->fh_asynch = (eNB->node_timing == synch_to_other) ? fh_if4p5_asynch_UL : NULL; + eNB->start_rf = NULL; + eNB->start_if = start_if; + + eNB->rfdevice.host_type = BBU_HOST; + eNB->ifdevice.host_type = BBU_HOST; + ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], eNB->eth_params); + printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id); + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + break; + malloc_IF4p5_buffer(eNB); + + } + + if (setup_eNB_buffers(PHY_vars_eNB_g[inst],&openair0_cfg[CC_id])!=0) { + printf("Exiting, cannot initialize eNodeB Buffers\n"); + exit(-1); + } + } + + init_eNB_proc(inst); + } + + sleep(1); + LOG_D(HW,"[lte-softmodem.c] eNB threads created\n"); + + +} + diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c index 0195478ebb3ad0ba2e43939a7e582a3d28b830c9..6bf4dc733f3955aff010a18f8936e526dae6c6ab 100755 --- a/targets/RT/USER/lte-enb.c +++ b/targets/RT/USER/lte-enb.c @@ -1,1329 +1,1423 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file lte-enb.c - * \brief Top-level threads for eNodeB - * \author R. Knopp, F. Kaltenberger, Navid Nikaein - * \date 2012 - * \version 0.1 - * \company Eurecom - * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr - * \note - * \warning - */ - -/*! \function wakeup_txfh - * \brief Implementation of creating multiple RU threads for beamforming emulation - * \author TH Wang(Judy), TY Hsu, SY Yeh(fdragon) - * \date 2018 - * \version 0.1 - * \company Eurecom and ISIP@NCTU - * \email: Tsu-Han.Wang@eurecom.fr,tyhsu@cs.nctu.edu.tw,fdragon.cs96g@g2.nctu.edu.tw - * \note - * \warning - */ - - -#define _GNU_SOURCE -#include <pthread.h> - - -#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all - -#include "rt_wrapper.h" - -#include "assertions.h" - - -#include "PHY/types.h" - -#include "PHY/INIT/phy_init.h" - -#include "PHY/defs_eNB.h" -#include "SCHED/sched_eNB.h" -#include "PHY/LTE_TRANSPORT/transport_proto.h" -#include "nfapi/oai_integration/vendor_ext.h" -#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all -//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all - -#include "../../ARCH/COMMON/common_lib.h" - -//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all - -#include "PHY/LTE_TRANSPORT/if4_tools.h" -#include "PHY/LTE_TRANSPORT/if5_tools.h" - -#include "PHY/phy_extern.h" - - -//NB-IoT -#include "PHY/defs_NB_IoT.h" -#include "SCHED/defs_NB_IoT.h" -#include "PHY_INTERFACE/IF_Module_NB_IoT.h" -#include "LAYER2/MAC/extern_NB_IoT.h" -#include "PHY/extern_NB_IoT.h" -#include "LAYER2/MAC/defs.h" -#include "PHY_INTERFACE/extern.h" - -#ifdef SMBV -#include "PHY/TOOLS/smbv.h" -unsigned short config_frames[4] = {2,9,11,13}; -#endif - -//develop branch -#include "LAYER2/MAC/mac.h" -#include "LAYER2/MAC/mac_extern.h" -#include "LAYER2/MAC/mac_proto.h" -#include "RRC/LTE/rrc_extern.h" -#include "PHY_INTERFACE/phy_interface.h" -#include "common/utils/LOG/log.h" -#include "UTIL/OTG/otg_tx.h" -#include "UTIL/OTG/otg_externs.h" -#include "UTIL/MATH/oml.h" -#include "common/utils/LOG/vcd_signal_dumper.h" -#include "UTIL/OPT/opt.h" -#include "enb_config.h" - - -#ifndef OPENAIR2 - #include "UTIL/OTG/otg_extern.h" -#endif - -#include "s1ap_eNB.h" -#include "SIMULATION/ETH_TRANSPORT/proto.h" - -#include "T.h" - -//#define DEBUG_THREADS 1 - -//#define USRP_DEBUG 1 -struct timing_info_t { - //unsigned int frame, hw_slot, last_slot, next_slot; - RTIME time_min, time_max, time_avg, time_last, time_now; - //unsigned int mbox0, mbox1, mbox2, mbox_target; - unsigned int n_samples; -} timing_info; - -// Fix per CC openair rf/if device update -// extern openair0_device openair0; - -extern volatile int oai_exit; - -extern int transmission_mode; - -extern int oaisim_flag; - -//uint16_t sf_ahead=4; -extern uint16_t sf_ahead; - - -//pthread_t main_eNB_thread; - -time_stats_t softmodem_stats_mt; // main thread -time_stats_t softmodem_stats_hw; // hw acquisition -time_stats_t softmodem_stats_rxtx_sf; // total tx time -time_stats_t nfapi_meas; // total tx time -time_stats_t softmodem_stats_rx_sf; // total rx time - -/* mutex, cond and variable to serialize phy proc TX calls - * (this mechanism may be relaxed in the future for better - * performances) - */ -static struct { - pthread_mutex_t mutex_phy_proc_tx; - pthread_cond_t cond_phy_proc_tx; - volatile uint8_t phy_proc_CC_id; -} sync_phy_proc; - -extern double cpuf; - - -void init_eNB(int,int); -void stop_eNB(int nb_inst); - -int wakeup_tx(PHY_VARS_eNB *eNB ,int frame_rx,int subframe_rx,int frame_tx,int subframe_tx,uint64_t timestamp_tx); -int wakeup_txfh(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc,int frame_tx,int subframe_tx,uint64_t timestamp_tx); -void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe); -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe); -#endif - - -extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); -extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset); - -//#define TICK_TO_US(ts) (ts.diff) -#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials) - - -static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) { - int ret; - start_meas(&softmodem_stats_rxtx_sf); - - //L1_rxtx_proc_t *L1_proc_tx = &eNB->proc.L1_proc_tx; - // ******************************************************************* -#if defined(PRE_SCD_THREAD) - RU_t *ru = RC.ru[0]; -#endif - - if (eNB ==NULL) { - LOG_D(PHY,"%s:%d: rxtx invalid argument, eNB pointer is NULL",__FILE__,__LINE__); - return -1; - } - - if (NFAPI_MODE==NFAPI_MODE_PNF) { - // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick - uint16_t frame = proc->frame_rx; - uint16_t subframe = proc->subframe_rx; - //add_subframe(&frame, &subframe, 4); - //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); - //LOG_D(PHY, "oai_subframe_ind(frame:%u, subframe:%d) - NOT CALLED ********\n", frame, subframe); - start_meas(&nfapi_meas); - oai_subframe_ind(frame, subframe); - stop_meas(&nfapi_meas); - - if (eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus|| - eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs || - eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs || - eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles || - eNB->UL_INFO.cqi_ind.number_of_cqis - ) { - LOG_D(PHY, "UL_info[rx_ind:%05d:%d harqs:%05d:%d crcs:%05d:%d preambles:%05d:%d cqis:%d] RX:%04d%d TX:%04d%d num_pdcch_symbols:%d\n", - NFAPI_SFNSF2DEC(eNB->UL_INFO.rx_ind.sfn_sf), eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus, - NFAPI_SFNSF2DEC(eNB->UL_INFO.harq_ind.sfn_sf), eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs, - NFAPI_SFNSF2DEC(eNB->UL_INFO.crc_ind.sfn_sf), eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, - NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles, - eNB->UL_INFO.cqi_ind.number_of_cqis, - proc->frame_rx, proc->subframe_rx, - proc->frame_tx, proc->subframe_tx, eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols); - } - } - - if (NFAPI_MODE==NFAPI_MODE_PNF && eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0) { - LOG_E(PHY, "eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0"); - return 0; - } - - // **************************************** - // Common RX procedures subframe n - T(T_ENB_PHY_DL_TICK, T_INT(eNB->Mod_id), T_INT(proc->frame_tx), T_INT(proc->subframe_tx)); - - // if this is IF5 or 3GPP_eNB - if (eNB->RU_list && eNB->RU_list[0] && eNB->RU_list[0]->function < NGFI_RAU_IF4p5) { - wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); -#endif - } - - 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); - } - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, 1 ); -#if defined(PRE_SCD_THREAD) - - if (NFAPI_MODE==NFAPI_MODE_VNF) { - new_dlsch_ue_select_tbl_in_use = dlsch_ue_select_tbl_in_use; - dlsch_ue_select_tbl_in_use = !dlsch_ue_select_tbl_in_use; - // L2-emulator can work only one eNB. - // memcpy(&pre_scd_eNB_UE_stats,&RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); - // memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX); - memcpy(&pre_scd_eNB_UE_stats,&RC.mac[0]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); - memcpy(&pre_scd_activeUE, &RC.mac[0]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX); - - AssertFatal((ret= pthread_mutex_lock(&ru->proc.mutex_pre_scd))==0,"[eNB] error locking proc mutex for eNB pre scd, return %d\n",ret); - - ru->proc.instance_pre_scd++; - - if (ru->proc.instance_pre_scd == 0) { - if (pthread_cond_signal(&ru->proc.cond_pre_scd) != 0) { - LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB pre scd\n" ); - exit_fun( "ERROR pthread_cond_signal cond_pre_scd" ); - } - } else { - LOG_E( PHY, "[eNB] frame %d subframe %d rxtx busy instance_pre_scd %d\n", - proc->frame_rx,proc->subframe_rx,ru->proc.instance_pre_scd ); - } - - AssertFatal((ret= pthread_mutex_unlock(&ru->proc.mutex_pre_scd))==0,"[eNB] error unlocking proc mutex for eNB pre scd, return %d\n",ret); - - } - -#endif - AssertFatal((ret= pthread_mutex_lock(&eNB->UL_INFO_mutex))==0,"error locking UL_INFO_mutex, return %d\n",ret); - 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); - AssertFatal((ret= pthread_mutex_unlock(&eNB->UL_INFO_mutex))==0,"error unlocking UL_INFO_mutex, return %d\n",ret); - - /* this conflict resolution may be totally wrong, to be tested */ - /* CONFLICT RESOLUTION: BEGIN */ - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, 0 ); - - if(oai_exit) return(-1); - - if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) { -#ifndef PHY_TX_THREAD - phy_procedures_eNB_TX(eNB, proc, 1); -#endif - } - - /* CONFLICT RESOLUTION: what about this release_thread call, has it to be done? if yes, where? */ - //if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) return(-1); - /* CONFLICT RESOLUTION: END */ - stop_meas( &softmodem_stats_rxtx_sf ); - - LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, proc->frame_rx, proc->subframe_rx, proc->frame_tx, proc->subframe_tx); - LOG_D(PHY, "rxtx:%lld nfapi:%lld tx:%lld rx:%lld prach:%lld ofdm:%lld ", - softmodem_stats_rxtx_sf.p_time, nfapi_meas.p_time, - TICK_TO_US(eNB->phy_proc_tx), - TICK_TO_US(eNB->phy_proc_rx), - TICK_TO_US(eNB->rx_prach), - TICK_TO_US(eNB->ofdm_mod_stats) - ); - - LOG_D(PHY, - "dlsch[enc:%lld mod:%lld scr:%lld rm:%lld t:%lld i:%lld] rx_dft:%lld ", - TICK_TO_US(eNB->dlsch_encoding_stats), - TICK_TO_US(eNB->dlsch_modulation_stats), - TICK_TO_US(eNB->dlsch_scrambling_stats), - TICK_TO_US(eNB->dlsch_rate_matching_stats), - TICK_TO_US(eNB->dlsch_turbo_encoding_stats), - TICK_TO_US(eNB->dlsch_interleaving_stats), - TICK_TO_US(eNB->rx_dft_stats)); - LOG_D(PHY," ulsch[ch:%lld freq:%lld dec:%lld demod:%lld ru:%lld ", - TICK_TO_US(eNB->ulsch_channel_estimation_stats), - TICK_TO_US(eNB->ulsch_freq_offset_estimation_stats), - TICK_TO_US(eNB->ulsch_decoding_stats), - TICK_TO_US(eNB->ulsch_demodulation_stats), - TICK_TO_US(eNB->ulsch_rate_unmatching_stats)); - LOG_D(PHY, "td:%lld dei:%lld dem:%lld llr:%lld tci:%lld ", - TICK_TO_US(eNB->ulsch_turbo_decoding_stats), - TICK_TO_US(eNB->ulsch_deinterleaving_stats), - TICK_TO_US(eNB->ulsch_demultiplexing_stats), - TICK_TO_US(eNB->ulsch_llr_stats), - TICK_TO_US(eNB->ulsch_tc_init_stats)); - LOG_D(PHY, "tca:%lld tcb:%lld tcg:%lld tce:%lld l1:%lld l2:%lld]\n\n", - TICK_TO_US(eNB->ulsch_tc_alpha_stats), - TICK_TO_US(eNB->ulsch_tc_beta_stats), - TICK_TO_US(eNB->ulsch_tc_gamma_stats), - TICK_TO_US(eNB->ulsch_tc_ext_stats), - TICK_TO_US(eNB->ulsch_tc_intl1_stats), - TICK_TO_US(eNB->ulsch_tc_intl2_stats) - ); - return(0); -} - - -static void *L1_thread_tx(void *param) { - L1_proc_t *eNB_proc = (L1_proc_t *)param; - L1_rxtx_proc_t *proc = &eNB_proc->L1_proc_tx; - PHY_VARS_eNB *eNB = RC.eNB[0][proc->CC_id]; - char thread_name[100]; - sprintf(thread_name,"TXnp4_%d\n",&eNB->proc.L1_proc == proc ? 0 : 1); - thread_top_init(thread_name,1,470000,500000,500000); - int ret; - - //wait_sync("tx_thread"); - - - while (!oai_exit) { - LOG_D(PHY,"Waiting for TX (IC %d)\n",proc->instance_cnt); - if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break; - - if (oai_exit) break; - - LOG_D(PHY,"L1_thread_tx: Running for %d.%d\n",proc->frame_tx,proc->subframe_tx); - // ***************************************** - // TX processing for subframe n+4 - // run PHY TX procedures the one after the other for all CCs to avoid race conditions - // (may be relaxed in the future for performance reasons) - // ***************************************** - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX1_ENB,proc->subframe_tx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX1_ENB,proc->subframe_rx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_ENB,proc->frame_tx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_ENB,proc->frame_rx); - LOG_D(PHY,"L1 TX processing %d.%d\n",proc->frame_tx,proc->subframe_tx); - phy_procedures_eNB_TX(eNB, proc, 1); - AssertFatal((ret= pthread_mutex_lock( &proc->mutex ))==0,"error locking L1_proc_tx mutex, return %d\n",ret); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_L1_PROC_TX_IC,proc->instance_cnt); - - int subframe_tx = proc->subframe_tx; - int frame_tx = proc->frame_tx; - uint64_t timestamp_tx = proc->timestamp_tx; - - proc->instance_cnt = -1; - - LOG_D(PHY,"L1 TX signaling done for %d.%d\n",proc->frame_tx,proc->subframe_tx); - // the thread can now be woken up - LOG_D(PHY,"L1_thread_tx: signaling completion in %d.%d\n",proc->frame_tx,proc->subframe_tx); - if (pthread_cond_signal(&proc->cond) != 0) { - LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n"); - exit_fun( "ERROR pthread_cond_signal" ); - } - - AssertFatal((ret= pthread_mutex_unlock( &proc->mutex ))==0,"error unlocking L1_proc_tx mutex, return %d\n",ret); - wakeup_txfh(eNB,proc,frame_tx,subframe_tx,timestamp_tx); - } - - return 0; -} - -/*! - * \brief The RX UE-specific and TX thread of eNB. - * \param param is a \ref L1_proc_t structure which contains the info what to process. - * \returns a pointer to an int. The storage is not on the heap and must not be freed. - */ - -static void *L1_thread( void *param ) { - static int eNB_thread_rxtx_status; - L1_rxtx_proc_t *proc; - // Working - if(NFAPI_MODE==NFAPI_MODE_VNF) { - proc = (L1_rxtx_proc_t *)param; - } else { - L1_proc_t *eNB_proc = (L1_proc_t *)param; - proc = &eNB_proc->L1_proc; - } - - PHY_VARS_eNB *eNB = RC.eNB[0][proc->CC_id]; - char thread_name[100]; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - // set default return value - eNB_thread_rxtx_status = 0; - sprintf(thread_name,"RXn_TXnp4_%d\n",&eNB->proc.L1_proc == proc ? 0 : 1); - thread_top_init(thread_name,1,470000,500000,500000); - pthread_setname_np( pthread_self(),"rxtx processing"); - LOG_I(PHY,"thread rxtx created id=%ld\n", syscall(__NR_gettid)); - - while (!oai_exit) { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); - T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx)); - - LOG_D(PHY,"L1RX waiting for RU RX\n"); - if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break; - - LOG_D(PHY,"L1RX starting in %d.%d\n",proc->frame_rx,proc->subframe_rx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_CPUID_ENB_THREAD_RXTX,sched_getcpu()); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 ); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_ENB,proc->subframe_tx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_ENB,proc->subframe_rx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_ENB,proc->frame_tx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_ENB,proc->frame_rx); - - - if (oai_exit) break; - - if (eNB->CC_id==0) { - if (rxtx(eNB,proc,thread_name) < 0) break; - } - - LOG_D(PHY,"L1 RX %d.%d done\n",proc->frame_rx,proc->subframe_rx); - - if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) phy_procedures_eNB_TX(eNB, proc, 1); - - - if (NFAPI_MODE!=NFAPI_MODE_VNF) { - if(get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) wakeup_tx(eNB,proc->frame_rx,proc->subframe_rx,proc->frame_tx,proc->subframe_tx,proc->timestamp_tx); - else if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) wakeup_txfh(eNB,proc,proc->frame_tx,proc->subframe_tx,proc->timestamp_tx); - } - - if (release_thread(&proc->mutex,&proc->instance_cnt,thread_name)<0) break; - - - } // while !oai_exit - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); - LOG_D(PHY, " *** Exiting eNB thread RXn_TXnp4\n"); - eNB_thread_rxtx_status = 0; - return &eNB_thread_rxtx_status; -} - -void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) { - L1_proc_t *proc = &eNB->proc; - L1_rxtx_proc_t *L1_proc = &proc->L1_proc; - LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; - RU_proc_t *ru_proc=&ru->proc; - proc->frame_rx = frame_rx; - proc->subframe_rx = subframe_rx; - - if (!oai_exit) { - T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx)); - L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); - L1_proc->frame_rx = ru_proc->frame_rx; - L1_proc->subframe_rx = ru_proc->subframe_rx; - L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; - L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; - - if (rxtx(eNB,L1_proc,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); - - ru_proc->timestamp_tx = L1_proc->timestamp_tx; - ru_proc->subframe_tx = L1_proc->subframe_tx; - ru_proc->frame_tx = L1_proc->frame_tx; - } -} - -int wakeup_txfh(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc,int frame_tx,int subframe_tx,uint64_t timestamp_tx) { - - RU_t *ru; - RU_proc_t *ru_proc; - LTE_DL_FRAME_PARMS *fp; - int waitret,ret; - - LOG_D(PHY,"L1 TX Waking up TX FH %d.%d (IC RU TX %d)\n",frame_tx,subframe_tx,proc->instance_cnt_RUs); - - // grab the information for the RU due to the following wait - - waitret=timedwait_on_condition(&proc->mutex_RUs,&proc->cond_RUs,&proc->instance_cnt_RUs,"wakeup_txfh",1000000); - - AssertFatal(release_thread(&proc->mutex_RUs,&proc->instance_cnt_RUs,"wakeup_txfh")==0, "error releaseing eNB lock on RUs\n"); - - if (waitret == ETIMEDOUT) { - LOG_W(PHY,"Dropping TX slot (%d.%d) because FH is blocked more than 1 subframe times (1ms)\n",frame_tx,subframe_tx); - - AssertFatal((ret=pthread_mutex_lock(&eNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); - eNB->proc.RU_mask_tx = 0; - AssertFatal((ret=pthread_mutex_unlock(&eNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RUs))==0,"mutex_lock returns %d\n",ret); - proc->instance_cnt_RUs = 0; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE,proc->instance_cnt_RUs); - AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RUs))==0,"mutex_unlock returns %d\n",ret); - return(-1); - } - - for(int ru_id=0; ru_id<eNB->num_RU; ru_id++){ - ru = eNB->RU_list[ru_id]; - ru_proc = &ru->proc; - fp = &ru->frame_parms; - if (((fp->frame_type == TDD) && (subframe_select(fp,proc->subframe_tx)==SF_UL))|| - (eNB->RU_list[ru_id]->state == RU_SYNC)|| - (eNB->RU_list[ru_id]->wait_cnt>0)){ - AssertFatal((pthread_mutex_lock(&proc->mutex_RUs))==0, "mutex_lock returns %d\n",ret); - proc->instance_cnt_RUs = 0; - AssertFatal((pthread_mutex_unlock(&proc->mutex_RUs))==0, "mutex_unlock returns %d\n",ret); - continue;//hacking only works when all RU_tx works on the same subframe #TODO: adding mask stuff - } - - AssertFatal((ret = pthread_mutex_lock(&ru_proc->mutex_eNBs))==0,"ERROR pthread_mutex_lock failed on mutex_eNBs L1_thread_tx with ret=%d\n",ret); - - if (ru_proc->instance_cnt_eNBs == 0) { - LOG_E(PHY,"Frame %d, subframe %d: TX FH thread busy, dropping Frame %d, subframe %d\n", ru_proc->frame_tx, ru_proc->subframe_tx, proc->frame_rx, proc->subframe_rx); - AssertFatal((ret=pthread_mutex_lock(&eNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); - eNB->proc.RU_mask_tx = 0; - AssertFatal((ret=pthread_mutex_unlock(&eNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); - AssertFatal((ret=pthread_mutex_unlock( &ru_proc->mutex_eNBs ))==0,"mutex_unlock return %d\n",ret); - return(-1); - } - - ru_proc->instance_cnt_eNBs = 0; - ru_proc->timestamp_tx = timestamp_tx; - ru_proc->subframe_tx = subframe_tx; - ru_proc->frame_tx = frame_tx; - - LOG_D(PHY,"L1 TX Waking up TX FH (2) %d.%d\n",frame_tx,subframe_tx); - // the thread can now be woken up - AssertFatal(pthread_cond_signal(&ru_proc->cond_eNBs) == 0, - "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n"); - AssertFatal((ret=pthread_mutex_unlock(&ru_proc->mutex_eNBs))==0,"mutex_unlock returned %d\n",ret); - } - return(0); -} - -int wakeup_tx(PHY_VARS_eNB *eNB, int frame_rx,int subframe_rx,int frame_tx,int subframe_tx,uint64_t timestamp_tx) { - - L1_rxtx_proc_t *L1_proc = &eNB->proc.L1_proc; - L1_rxtx_proc_t *L1_proc_tx = &eNB->proc.L1_proc_tx; - - int ret; - - LOG_D(PHY,"ENTERED wakeup_tx (IC %d)\n",L1_proc_tx->instance_cnt); - - AssertFatal((ret = pthread_mutex_lock(&L1_proc_tx->mutex))==0,"mutex_lock returns %d\n",ret); - - LOG_D(PHY,"L1 RX %d.%d Waiting to wake up L1 TX %d.%d (IC L1TX %d)\n",L1_proc->frame_rx,L1_proc->subframe_rx,L1_proc->frame_tx,L1_proc->subframe_tx,L1_proc_tx->instance_cnt); - - while(L1_proc_tx->instance_cnt == 0) { - pthread_cond_wait(&L1_proc_tx->cond,&L1_proc_tx->mutex); - } - - LOG_D(PHY,"L1 RX Got signal that TX %d.%d is done\n",L1_proc_tx->frame_tx,L1_proc_tx->subframe_tx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_L1_PROC_TX_IC,L1_proc_tx->instance_cnt); - L1_proc_tx->instance_cnt = 0; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_L1_PROC_TX_IC,L1_proc_tx->instance_cnt); - L1_proc_tx->subframe_rx = subframe_rx; - L1_proc_tx->frame_rx = frame_rx; - L1_proc_tx->subframe_tx = subframe_tx; - L1_proc_tx->frame_tx = frame_tx; - L1_proc_tx->timestamp_tx = timestamp_tx; - - // the thread can now be woken up - LOG_D(PHY,"L1 RX Waking up L1 TX %d.%d\n",L1_proc->frame_tx,L1_proc->subframe_tx); - AssertFatal(pthread_cond_signal(&L1_proc_tx->cond) == 0, "ERROR pthread_cond_signal for eNB L1 thread tx\n"); - - AssertFatal((ret=pthread_mutex_unlock(&L1_proc_tx->mutex))==0,"mutex_unlock returns %d\n",ret); - return(0); -} - -int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { - L1_proc_t *proc=&eNB->proc; - RU_proc_t *ru_proc=&ru->proc; - L1_rxtx_proc_t *L1_proc=&proc->L1_proc; - LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; - int ret; - - LOG_D(PHY,"ENTERED wakeup_rxtx, %d.%d\n",ru_proc->frame_rx,ru_proc->subframe_rx); - - // wake up TX for subframe n+sl_ahead - // lock the TX mutex and make sure the thread is ready - AssertFatal((ret=pthread_mutex_lock(&L1_proc->mutex)) == 0,"mutex_lock returns %d\n", ret); - - if (L1_proc->instance_cnt == 0) { // L1_thread is busy so abort the subframe - AssertFatal((ret=pthread_mutex_unlock( &L1_proc->mutex))==0,"mutex_unlock return %d\n",ret); - LOG_W(PHY,"L1_thread isn't ready in %d.%d, aborting RX processing\n",ru_proc->frame_rx,ru_proc->subframe_rx); - return(0); - } - - - ++L1_proc->instance_cnt; - // We have just received and processed the common part of a subframe, say n. - // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired - // transmitted timestamp of the next TX slot (first). - // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, - // we want to generate subframe (n+sf_ahead), so TS_tx = TX_rx+sf_ahead*samples_per_tti, - // and proc->subframe_tx = proc->subframe_rx+sf_ahead - L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); - L1_proc->frame_rx = ru_proc->frame_rx; - L1_proc->subframe_rx = ru_proc->subframe_rx; - L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; - L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; - - LOG_D(PHY,"wakeup_rxtx: L1_proc->subframe_rx %d, L1_proc->subframe_tx %d, RU %d\n",L1_proc->subframe_rx,L1_proc->subframe_tx,ru->idx); - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_RXTX_RX_RU+ru->idx, L1_proc->frame_rx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_RXTX_RX_RU+ru->idx, L1_proc->subframe_rx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_RXTX_TX_RU+ru->idx, L1_proc->frame_tx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_RXTX_TX_RU+ru->idx, L1_proc->subframe_tx); - - // the thread can now be woken up - if (pthread_cond_signal(&L1_proc->cond) != 0) { - LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB RXn-TXnp4 thread\n"); - exit_fun( "ERROR pthread_cond_signal" ); - return(-1); - } - - AssertFatal((ret=pthread_mutex_unlock( &L1_proc->mutex))==0,"mutex_unlock return %d\n",ret); - - return(0); -} - -void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - L1_proc_t *proc = &eNB->proc; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - int i,ret; - - if (ru!=NULL) { - - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RU_PRACH))==0,"mutex_lock return %d\n",ret); - for (i=0; i<eNB->num_RU; i++) { - if (ru == eNB->RU_list[i]) { - LOG_D(PHY,"frame %d, subframe %d: RU %d for eNB %d signals PRACH (mask %x, num_RU %d)\n",frame,subframe,i,eNB->Mod_id,proc->RU_mask_prach,eNB->num_RU); - - if ((proc->RU_mask_prach&(1<<i)) > 0) - LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information (PRACH) from RU %d (num_RU %d, mask %x) has not been served yet!\n", - eNB->Mod_id,frame,subframe,ru->idx,eNB->num_RU,proc->RU_mask_prach); - - proc->RU_mask_prach |= (1<<i); - } - } - - if (proc->RU_mask_prach != (1<<eNB->num_RU)-1) { // not all RUs have provided their information so return - AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU_PRACH))==0,"mutex_unlock return %d\n",ret); - return; - } else { // all RUs have provided their information so continue on and wakeup eNB processing - proc->RU_mask_prach = 0; - AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU_PRACH))==0,"mutex_unlock return %d\n",ret); - } - } - - // check if we have to detect PRACH first - if (is_prach_subframe(fp,frame,subframe)>0) { - LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe); - - if (proc->instance_cnt_prach == 0) { - LOG_W(PHY,"[eNB] Frame %d Subframe %d, dropping PRACH\n", frame,subframe); - return; - } - - // wake up thread for PRACH RX - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_prach))==0,"[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach); - - ++proc->instance_cnt_prach; - // set timing for prach thread - proc->frame_prach = frame; - proc->subframe_prach = subframe; - - // the thread can now be woken up - if (pthread_cond_signal(&proc->cond_prach) != 0) { - LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH thread %d\n", proc->thread_index); - exit_fun( "ERROR pthread_cond_signal" ); - return; - } - - AssertFatal((ret=pthread_mutex_unlock( &proc->mutex_prach))==0,"mutex_unlock return %d\n",ret); - } -} - -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) -void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { - L1_proc_t *proc = &eNB->proc; - LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; - int i,ret; - - if (ru!=NULL) { - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RU_PRACH_br))==0,"mutex_lock return %d\n",ret); - - for (i=0; i<eNB->num_RU; i++) { - if (ru == eNB->RU_list[i]) { - LOG_D(PHY,"frame %d, subframe %d: RU %d for eNB %d signals PRACH BR (mask %x, num_RU %d)\n",frame,subframe,i,eNB->Mod_id,proc->RU_mask_prach_br,eNB->num_RU); - - if ((proc->RU_mask_prach_br&(1<<i)) > 0) - LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information (PRACH BR) from RU %d (num_RU %d, mask %x) has not been served yet!\n", - eNB->Mod_id,frame,subframe,ru->idx,eNB->num_RU,proc->RU_mask_prach_br); - - proc->RU_mask_prach_br |= (1<<i); - } - } - - if (proc->RU_mask_prach_br != (1<<eNB->num_RU)-1) { // not all RUs have provided their information so return - AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU_PRACH_br))==0,"mutex_unlock return %d\n",ret); - return; - } else { // all RUs have provided their information so continue on and wakeup eNB processing - proc->RU_mask_prach_br = 0; - AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU_PRACH_br))==0,"mutex_unlock return %d\n",ret); - } - } - - // check if we have to detect PRACH first - if (is_prach_subframe(fp,frame,subframe)>0) { - LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe); - - if (proc->instance_cnt_prach_br == 0) { - LOG_W(PHY,"[eNB] Frame %d Subframe %d, dropping PRACH BR\n", frame,subframe); - return; - } - - // wake up thread for PRACH RX - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_prach_br))==0,"[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach_br); - - ++proc->instance_cnt_prach_br; - // set timing for prach thread - proc->frame_prach_br = frame; - proc->subframe_prach_br = subframe; - - // the thread can now be woken up - if (pthread_cond_signal(&proc->cond_prach_br) != 0) { - LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH BR thread %d\n", proc->thread_index); - exit_fun( "ERROR pthread_cond_signal" ); - return; - } - - AssertFatal((ret=pthread_mutex_unlock( &proc->mutex_prach_br))==0,"mutex_unlock return %d\n",ret); - } -} -#endif - - -/*! - * \brief The prach receive thread of eNB. - * \param param is a \ref L1_proc_t structure which contains the info what to process. - * \returns a pointer to an int. The storage is not on the heap and must not be freed. - */ -static void *eNB_thread_prach( void *param ) { - static int eNB_thread_prach_status; - PHY_VARS_eNB *eNB= (PHY_VARS_eNB *)param; - L1_proc_t *proc = &eNB->proc; - // set default return value - eNB_thread_prach_status = 0; - thread_top_init("eNB_thread_prach",1,500000,1000000,20000000); - - //wait_sync("eNB_thread_prach"); - - while (!oai_exit) { - if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break; - - if (oai_exit) break; - - LOG_D(PHY,"Running eNB prach procedures\n"); - prach_procedures(eNB -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - ,0 -#endif - ); - - if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break; - } - - LOG_I(PHY, "Exiting eNB thread PRACH\n"); - eNB_thread_prach_status = 0; - return &eNB_thread_prach_status; -} - -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) -/*! - * \brief The prach receive thread of eNB for BL/CE UEs. - * \param param is a \ref L1_proc_t structure which contains the info what to process. - * \returns a pointer to an int. The storage is not on the heap and must not be freed. - */ -static void *eNB_thread_prach_br( void *param ) { - static int eNB_thread_prach_status; - PHY_VARS_eNB *eNB= (PHY_VARS_eNB *)param; - L1_proc_t *proc = &eNB->proc; - // set default return value - eNB_thread_prach_status = 0; - thread_top_init("eNB_thread_prach_br",1,500000,1000000,20000000); - - while (!oai_exit) { - if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break; - - if (oai_exit) break; - - LOG_D(PHY,"Running eNB prach procedures for BL/CE UEs\n"); - prach_procedures(eNB,1); - - if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break; - } - - LOG_I(PHY, "Exiting eNB thread PRACH BR\n"); - eNB_thread_prach_status = 0; - return &eNB_thread_prach_status; -} - -#endif - - - -extern void init_td_thread(PHY_VARS_eNB *); -extern void init_te_thread(PHY_VARS_eNB *); -extern void kill_td_thread(PHY_VARS_eNB *); -extern void kill_te_thread(PHY_VARS_eNB *); - -static void *process_stats_thread(void *param) { - PHY_VARS_eNB *eNB = (PHY_VARS_eNB *)param; - wait_sync("process_stats_thread"); - - while (!oai_exit) { - sleep(1); - - if (opp_enabled == 1) { - if ( eNB->ulsch_decoding_stats.trials>0) - print_meas(&eNB->ulsch_decoding_stats,"ulsch_decoding",NULL,NULL); - - if (eNB->dlsch_encoding_stats.trials >0) { - print_meas(&eNB->dlsch_turbo_encoding_preperation_stats,"dlsch_coding_crc",NULL,NULL); - print_meas(&eNB->dlsch_turbo_encoding_segmentation_stats,"dlsch_segmentation",NULL,NULL); - print_meas(&eNB->dlsch_encoding_stats,"dlsch_encoding",NULL,NULL); - print_meas(&eNB->dlsch_turbo_encoding_signal_stats,"coding_signal",NULL,NULL); - print_meas(&eNB->dlsch_turbo_encoding_main_stats,"coding_main",NULL,NULL); - print_meas(&eNB->dlsch_turbo_encoding_stats,"turbo_encoding",NULL,NULL); - print_meas(&eNB->dlsch_interleaving_stats,"turbo_interleaving",NULL,NULL); - print_meas(&eNB->dlsch_rate_matching_stats,"turbo_rate_matching",NULL,NULL); - print_meas(&eNB->dlsch_turbo_encoding_waiting_stats,"coding_wait",NULL,NULL); - print_meas(&eNB->dlsch_turbo_encoding_wakeup_stats0,"coding_worker_0",NULL,NULL); - print_meas(&eNB->dlsch_turbo_encoding_wakeup_stats1,"coding_worker_1",NULL,NULL); - } - - print_meas(&eNB->dlsch_modulation_stats,"dlsch_modulation",NULL,NULL); - } - } - - return(NULL); -} - -void init_eNB_proc(int inst) { - /*int i=0;*/ - int CC_id; - PHY_VARS_eNB *eNB; - L1_proc_t *proc; - L1_rxtx_proc_t *L1_proc, *L1_proc_tx; - pthread_attr_t *attr0=NULL,*attr1=NULL,*attr_prach=NULL; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - pthread_attr_t *attr_prach_br=NULL; -#endif - LOG_I(PHY,"%s(inst:%d) RC.nb_CC[inst]:%d \n",__FUNCTION__,inst,RC.nb_CC[inst]); - - for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) { - eNB = RC.eNB[inst][CC_id]; -#ifndef OCP_FRAMEWORK - LOG_I(PHY,"Initializing eNB processes instance:%d CC_id %d \n",inst,CC_id); -#endif - proc = &eNB->proc; - L1_proc = &proc->L1_proc; - L1_proc_tx = &proc->L1_proc_tx; - L1_proc->instance_cnt = -1; - L1_proc_tx->instance_cnt = -1; - L1_proc->instance_cnt_RUs = 0; - L1_proc_tx->instance_cnt_RUs = 0; - proc->instance_cnt_prach = -1; - proc->instance_cnt_asynch_rxtx = -1; - proc->instance_cnt_synch = -1; - proc->CC_id = CC_id; - proc->first_rx =1; - proc->first_tx =1; - proc->RU_mask_tx = (1<<eNB->num_RU)-1; - memset((void*)proc->RU_mask,0,10*sizeof(proc->RU_mask[0])); - proc->RU_mask_prach =0; - pthread_mutex_init( &eNB->UL_INFO_mutex, NULL); - pthread_mutex_init( &L1_proc->mutex, NULL); - pthread_mutex_init( &L1_proc_tx->mutex, NULL); - pthread_cond_init( &L1_proc->cond, NULL); - pthread_cond_init( &L1_proc_tx->cond, NULL); - pthread_mutex_init( &L1_proc->mutex_RUs, NULL); - pthread_mutex_init( &L1_proc_tx->mutex_RUs, NULL); - pthread_cond_init( &L1_proc->cond_RUs, NULL); - pthread_cond_init( &L1_proc_tx->cond_RUs, NULL); - pthread_mutex_init( &proc->mutex_prach, NULL); - pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); - pthread_mutex_init( &proc->mutex_RU,NULL); - pthread_mutex_init( &proc->mutex_RU_tx,NULL); - pthread_mutex_init( &proc->mutex_RU_PRACH,NULL); - pthread_cond_init( &proc->cond_prach, NULL); - pthread_cond_init( &proc->cond_asynch_rxtx, NULL); - pthread_attr_init( &proc->attr_prach); - pthread_attr_init( &proc->attr_asynch_rxtx); - pthread_attr_init( &L1_proc->attr); - pthread_attr_init( &L1_proc_tx->attr); -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - proc->instance_cnt_prach_br = -1; - proc->RU_mask_prach_br=0; - pthread_mutex_init( &proc->mutex_prach_br, NULL); - pthread_mutex_init( &proc->mutex_RU_PRACH_br,NULL); - pthread_cond_init( &proc->cond_prach_br, NULL); - pthread_attr_init( &proc->attr_prach_br); -#endif -#ifndef DEADLINE_SCHEDULER - attr0 = &L1_proc->attr; - attr1 = &L1_proc_tx->attr; - attr_prach = &proc->attr_prach; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - attr_prach_br = &proc->attr_prach_br; -#endif - // attr_td = &proc->attr_td; - // attr_te = &proc->attr_te; -#endif - - if(get_thread_worker_conf() == WORKER_ENABLE) { - init_te_thread(eNB); - init_td_thread(eNB); - } - - LOG_I(PHY,"eNB->single_thread_flag:%d\n", eNB->single_thread_flag); - - if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) { - pthread_create( &L1_proc->pthread, attr0, L1_thread, proc ); - pthread_create( &L1_proc_tx->pthread, attr1, L1_thread_tx, proc); - } else if (NFAPI_MODE==NFAPI_MODE_VNF) { // this is neccesary in VNF or L2 FAPI simulator. - // Original Code from Fujitsu w/ old structure/field name - //pthread_create( &proc_rxtx[0].pthread_rxtx, attr0, eNB_thread_rxtx, &proc_rxtx[0] ); - //pthread_create( &proc_rxtx[1].pthread_rxtx, attr1, eNB_thread_rxtx, &proc_rxtx[1] ); - pthread_create( &L1_proc->pthread, attr0, L1_thread, L1_proc ); - pthread_create( &L1_proc_tx->pthread, attr1, L1_thread, L1_proc_tx); - } - - pthread_create( &proc->pthread_prach, attr_prach, eNB_thread_prach, eNB ); -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - pthread_create( &proc->pthread_prach_br, attr_prach_br, eNB_thread_prach_br, eNB ); -#endif - AssertFatal(proc->instance_cnt_prach == -1,"instance_cnt_prach = %d\n",proc->instance_cnt_prach); - - if (opp_enabled == 1) pthread_create(&proc->process_stats_thread,NULL,process_stats_thread,(void *)eNB); - } - - //for multiple CCs: setup master and slaves - /* - for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { - eNB = PHY_vars_eNB_g[inst][CC_id]; - - if (eNB->node_timing == synch_to_ext_device) { //master - eNB->proc.num_slaves = MAX_NUM_CCs-1; - eNB->proc.slave_proc = (L1_proc_t**)malloc(eNB->proc.num_slaves*sizeof(L1_proc_t*)); - - for (i=0; i< eNB->proc.num_slaves; i++) { - if (i < CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i]->proc); - if (i >= CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i+1]->proc); - } - } - } - */ - /* setup PHY proc TX sync mechanism */ - pthread_mutex_init(&sync_phy_proc.mutex_phy_proc_tx, NULL); - pthread_cond_init(&sync_phy_proc.cond_phy_proc_tx, NULL); - sync_phy_proc.phy_proc_CC_id = 0; -} - - - -/*! - * \brief Terminate eNB TX and RX threads. - */ -void kill_eNB_proc(int inst) { - int *status; - PHY_VARS_eNB *eNB; - L1_proc_t *proc; - L1_rxtx_proc_t *L1_proc, *L1_proc_tx; - int ret; - - for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { - eNB=RC.eNB[inst][CC_id]; - proc = &eNB->proc; - L1_proc = &proc->L1_proc; - L1_proc_tx = &proc->L1_proc_tx; - - if(get_thread_worker_conf() == WORKER_ENABLE) { - kill_td_thread(eNB); - kill_te_thread(eNB); - } - - LOG_I(PHY, "Killing TX CC_id %d inst %d\n", CC_id, inst ); - - if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) { - AssertFatal((ret=pthread_mutex_lock(&L1_proc->mutex))==0,"mutex_lock return %d\n",ret); - L1_proc->instance_cnt = 0; - pthread_cond_signal(&L1_proc->cond); - AssertFatal((ret=pthread_mutex_unlock(&L1_proc->mutex))==0,"mutex_unlock return %d\n",ret); - AssertFatal((ret=pthread_mutex_lock(&L1_proc_tx->mutex))==0,"mutex_lock return %d\n",ret); - L1_proc_tx->instance_cnt = 0; - pthread_cond_signal(&L1_proc_tx->cond); - AssertFatal((ret=pthread_mutex_unlock(&L1_proc_tx->mutex))==0,"muex_unlock return %d\n",ret); - } - - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_prach))==0,"mutex_lock return %d\n",ret); - proc->instance_cnt_prach = 0; - pthread_cond_signal( &proc->cond_prach ); - AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_prach))==0,"mutex_unlock return %d\n",ret); - pthread_cond_signal( &proc->cond_asynch_rxtx ); - pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx); - LOG_D(PHY, "joining pthread_prach\n"); - pthread_join( proc->pthread_prach, (void **)&status ); - LOG_I(PHY, "Destroying prach mutex/cond\n"); - pthread_mutex_destroy( &proc->mutex_prach); - pthread_cond_destroy( &proc->cond_prach ); -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - proc->instance_cnt_prach_br = 0; - pthread_cond_signal( &proc->cond_prach_br ); - pthread_join( proc->pthread_prach_br, (void **)&status ); - pthread_mutex_destroy( &proc->mutex_prach_br); - pthread_cond_destroy( &proc->cond_prach_br ); -#endif - LOG_I(PHY, "Destroying UL_INFO mutex\n"); - pthread_mutex_destroy(&eNB->UL_INFO_mutex); - - if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) { - LOG_I(PHY, "Joining L1_proc mutex/cond\n"); - pthread_join( L1_proc->pthread, (void **)&status ); - LOG_I(PHY, "Joining L1_proc_tx mutex/cond\n"); - pthread_join( L1_proc_tx->pthread, (void **)&status ); - } - - LOG_I(PHY, "Destroying L1_proc mutex/cond\n"); - pthread_mutex_destroy( &L1_proc->mutex ); - pthread_cond_destroy( &L1_proc->cond ); - pthread_mutex_destroy( &L1_proc->mutex_RUs ); - pthread_cond_destroy( &L1_proc->cond_RUs ); - LOG_I(PHY, "Destroying L1_proc_tx mutex/cond\n"); - pthread_mutex_destroy( &L1_proc_tx->mutex ); - pthread_cond_destroy( &L1_proc_tx->cond ); - pthread_mutex_destroy( &L1_proc_tx->mutex_RUs ); - pthread_cond_destroy( &L1_proc_tx->cond_RUs ); - pthread_attr_destroy(&proc->attr_prach); - pthread_attr_destroy(&proc->attr_asynch_rxtx); - pthread_attr_destroy(&L1_proc->attr); - pthread_attr_destroy(&L1_proc_tx->attr); -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - pthread_mutex_destroy(&proc->mutex_RU_PRACH_br); - pthread_attr_destroy(&proc->attr_prach_br); -#endif - } -} - - - - -void reset_opp_meas(void) { - int sfn; - reset_meas(&softmodem_stats_mt); - reset_meas(&softmodem_stats_hw); - - for (sfn=0; sfn < 10; sfn++) { - reset_meas(&softmodem_stats_rxtx_sf); - reset_meas(&softmodem_stats_rx_sf); - } -} - - -void print_opp_meas(void) { - int sfn=0; - print_meas(&softmodem_stats_mt, "Main ENB Thread", NULL, NULL); - print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL); - - for (sfn=0; sfn < 10; sfn++) { - print_meas(&softmodem_stats_rxtx_sf,"[eNB][total_phy_proc_rxtx]",NULL, NULL); - print_meas(&softmodem_stats_rx_sf,"[eNB][total_phy_proc_rx]",NULL,NULL); - } -} - -void free_transport(PHY_VARS_eNB *eNB) { - int i; - int j; - - for (i=0; i<NUMBER_OF_UE_MAX; i++) { - LOG_D(PHY, "Freeing Transport Channel Buffers for DLSCH, UE %d\n",i); - - for (j=0; j<2; j++) free_eNB_dlsch(eNB->dlsch[i][j]); - - LOG_D(PHY, "Freeing Transport Channel Buffer for ULSCH, UE %d\n",i); - free_eNB_ulsch(eNB->ulsch[1+i]); - } - - free_eNB_ulsch(eNB->ulsch[0]); -} - -void init_transport(PHY_VARS_eNB *eNB) { - int i; - int j; - LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; - LOG_I(PHY, "Initialise transport\n"); - - for (i=0; i<NUMBER_OF_UE_MAX; i++) { - LOG_D(PHY,"Allocating Transport Channel Buffers for DLSCH, UE %d\n",i); - - for (j=0; j<2; j++) { - eNB->dlsch[i][j] = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL,0,fp); - - if (!eNB->dlsch[i][j]) { - LOG_E(PHY,"Can't get eNB dlsch structures for UE %d \n", i); - exit(-1); - } else { - 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); - } - } - - LOG_D(PHY,"Allocating Transport Channel Buffer for ULSCH, UE %d\n",i); - eNB->ulsch[1+i] = new_eNB_ulsch(MAX_TURBO_ITERATIONS,fp->N_RB_UL, 0); - - if (!eNB->ulsch[1+i]) { - LOG_E(PHY,"Can't get eNB ulsch structures\n"); - exit(-1); - } - - // 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 - eNB->ulsch[0] = new_eNB_ulsch(MAX_TURBO_ITERATIONS, fp->N_RB_UL, 0); - - if (!eNB->ulsch[0]) { - LOG_E(PHY,"Can't get eNB ulsch structures\n"); - exit(-1); - } - - 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(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; -} - -void init_eNB_afterRU(void) { - int inst,CC_id,ru_id,i,aa; - PHY_VARS_eNB *eNB; - LOG_I(PHY,"%s() RC.nb_inst:%d\n", __FUNCTION__, RC.nb_inst); - - for (inst=0; inst<RC.nb_inst; inst++) { - LOG_I(PHY,"RC.nb_CC[inst]:%d\n", RC.nb_CC[inst]); - - - /////// IF-Module initialization /////////////// - - LOG_I(PHY,"Registering with MAC interface module start\n"); - AssertFatal((eNB->if_inst = IF_Module_init_NB_IoT(inst))!=NULL,"Cannot register interface"); - eNB->if_inst->schedule_response = schedule_response_NB_IoT; - eNB->if_inst->PHY_config_req = PHY_config_req_NB_IoT; - LOG_I(PHY,"Registering with MAC interface module sucessfully\n"); - - for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) { - LOG_I(PHY,"RC.nb_CC[inst:%d][CC_id:%d]:%p\n", inst, CC_id, RC.eNB[inst][CC_id]); - eNB = RC.eNB[inst][CC_id]; - phy_init_lte_eNB(eNB,0,0); - - // map antennas and PRACH signals to eNB RX - if (0) AssertFatal(eNB->num_RU>0,"Number of RU attached to eNB %d is zero\n",eNB->Mod_id); - - LOG_I(PHY,"Mapping RX ports from %d RUs to eNB %d\n",eNB->num_RU,eNB->Mod_id); - eNB->frame_parms.nb_antennas_rx = 0; - LOG_I(PHY,"Overwriting eNB->prach_vars.rxsigF[0]:%p\n", eNB->prach_vars.rxsigF[0]); - eNB->prach_vars.rxsigF[0] = (int16_t **)malloc16(64*sizeof(int16_t *)); -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - - for (int ce_level=0; ce_level<4; ce_level++) { - LOG_I(PHY,"Overwriting eNB->prach_vars_br.rxsigF.rxsigF[0]:%p\n", eNB->prach_vars_br.rxsigF[ce_level]); - eNB->prach_vars_br.rxsigF[ce_level] = (int16_t **)malloc16(64*sizeof(int16_t *)); - } - -#endif - LOG_I(PHY,"eNB->num_RU:%d\n", eNB->num_RU); - - for (ru_id=0,aa=0; ru_id<eNB->num_RU; ru_id++) { - eNB->frame_parms.nb_antennas_rx += eNB->RU_list[ru_id]->nb_rx; - AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL, - "RU %d : common.rxdataF is NULL\n", - eNB->RU_list[ru_id]->idx); - AssertFatal(eNB->RU_list[ru_id]->prach_rxsigF!=NULL, - "RU %d : prach_rxsigF is NULL\n", - eNB->RU_list[ru_id]->idx); - - for (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[i]; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - - 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]; - -#endif - eNB->common_vars.rxdataF[aa] = eNB->RU_list[ru_id]->common.rxdataF[i]; - } - } - - /* TODO: review this code, there is something wrong. - * In monolithic mode, we come here with nb_antennas_rx == 0 - * (not tested in other modes). - */ - if (eNB->frame_parms.nb_antennas_rx < 1) { - LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_rx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_rx); - eNB->frame_parms.nb_antennas_rx = 1; - } else { - //LOG_I(PHY," Delete code\n"); - } - - if (eNB->frame_parms.nb_antennas_tx < 1) { - LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_tx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_tx); - eNB->frame_parms.nb_antennas_tx = 1; - } else { - //LOG_I(PHY," Delete code\n"); - } - - AssertFatal(eNB->frame_parms.nb_antennas_rx >0, - "inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); - 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]); - } - - init_eNB_proc(inst); - } - - for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { - AssertFatal(RC.ru[ru_id]!=NULL,"ru_id %d is null\n",ru_id); - RC.ru[ru_id]->wakeup_rxtx = wakeup_rxtx; - RC.ru[ru_id]->wakeup_prach_eNB = wakeup_prach_eNB; -#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) - RC.ru[ru_id]->wakeup_prach_eNB_br = wakeup_prach_eNB_br; -#endif - RC.ru[ru_id]->eNB_top = eNB_top; - } -} - -void init_eNB(int single_thread_flag,int wait_for_sync) { - int CC_id; - int inst; - PHY_VARS_eNB *eNB; - LOG_I(PHY,"[lte-softmodem.c] eNB structure about to allocated RC.nb_L1_inst:%d RC.nb_L1_CC[0]:%d\n",RC.nb_L1_inst,RC.nb_L1_CC[0]); - - if (RC.eNB == NULL) RC.eNB = (PHY_VARS_eNB ** *) malloc(RC.nb_L1_inst*sizeof(PHY_VARS_eNB **)); - - LOG_I(PHY,"[lte-softmodem.c] eNB structure RC.eNB allocated\n"); - - for (inst=0; inst<RC.nb_L1_inst; inst++) { - if (RC.eNB[inst] == NULL) RC.eNB[inst] = (PHY_VARS_eNB **) malloc(RC.nb_CC[inst]*sizeof(PHY_VARS_eNB *)); - - for (CC_id=0; CC_id<RC.nb_L1_CC[inst]; CC_id++) { - if (RC.eNB[inst][CC_id] == NULL) RC.eNB[inst][CC_id] = (PHY_VARS_eNB *) malloc(sizeof(PHY_VARS_eNB)); - - eNB = RC.eNB[inst][CC_id]; - eNB->abstraction_flag = 0; - eNB->single_thread_flag = single_thread_flag; - LOG_I(PHY,"Initializing eNB %d CC_id %d single_thread_flag:%d\n",inst,CC_id,single_thread_flag); -#ifndef OCP_FRAMEWORK - LOG_I(PHY,"Initializing eNB %d CC_id %d\n",inst,CC_id); -#endif - LOG_I(PHY,"Registering with MAC interface module\n"); - 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)); - 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_pdu_list = eNB->cqi_pdu_list; - eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list; - eNB->prach_energy_counter = 0; - } - } - - - LOG_I(PHY,"[lte-softmodem.c] eNB structure allocated\n"); - - - -} - - -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); - } -} +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file lte-enb.c + * \brief Top-level threads for eNodeB + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ + +/*! \function wakeup_txfh + * \brief Implementation of creating multiple RU threads for beamforming emulation + * \author TH Wang(Judy), TY Hsu, SY Yeh(fdragon) + * \date 2018 + * \version 0.1 + * \company Eurecom and ISIP@NCTU + * \email: Tsu-Han.Wang@eurecom.fr,tyhsu@cs.nctu.edu.tw,fdragon.cs96g@g2.nctu.edu.tw + * \note + * \warning + */ + + +#define _GNU_SOURCE +#include <pthread.h> + + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "rt_wrapper.h" + +#include "assertions.h" + + +#include "PHY/types.h" + +#include "PHY/INIT/phy_init.h" + +#include "PHY/defs_eNB.h" +#include "SCHED/sched_eNB.h" +#include "PHY/LTE_TRANSPORT/transport_proto.h" +#include "nfapi/oai_integration/vendor_ext.h" +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "../../ARCH/COMMON/common_lib.h" + +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/LTE_TRANSPORT/if5_tools.h" + +#include "PHY/phy_extern.h" + + +//NB-IoT +#include "PHY/defs_NB_IoT.h" +#include "SCHED/defs_NB_IoT.h" +#include "PHY_INTERFACE/IF_Module_NB_IoT.h" +#include "LAYER2/MAC/extern_NB_IoT.h" +#include "PHY/extern_NB_IoT.h" +#include "LAYER2/MAC/defs.h" +#include "PHY_INTERFACE/extern.h" + +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif + +//develop branch +#include "LAYER2/MAC/mac.h" +#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/MAC/mac_proto.h" +#include "RRC/LTE/rrc_extern.h" +#include "PHY_INTERFACE/phy_interface.h" +#include "common/utils/LOG/log.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" + + +#ifndef OPENAIR2 + #include "UTIL/OTG/otg_extern.h" +#endif + +#include "s1ap_eNB.h" +#include "SIMULATION/ETH_TRANSPORT/proto.h" + +#include "T.h" + +//#define DEBUG_THREADS 1 + +//#define USRP_DEBUG 1 +struct timing_info_t { + //unsigned int frame, hw_slot, last_slot, next_slot; + RTIME time_min, time_max, time_avg, time_last, time_now; + //unsigned int mbox0, mbox1, mbox2, mbox_target; + unsigned int n_samples; +} timing_info; + +// Fix per CC openair rf/if device update +// extern openair0_device openair0; + +extern volatile int oai_exit; + +extern int transmission_mode; + +extern int oaisim_flag; + +//uint16_t sf_ahead=4; +extern uint16_t sf_ahead; + + +//pthread_t main_eNB_thread; + +time_stats_t softmodem_stats_mt; // main thread +time_stats_t softmodem_stats_hw; // hw acquisition +time_stats_t softmodem_stats_rxtx_sf; // total tx time +time_stats_t nfapi_meas; // total tx time +time_stats_t softmodem_stats_rx_sf; // total rx time + +/* mutex, cond and variable to serialize phy proc TX calls + * (this mechanism may be relaxed in the future for better + * performances) + */ +static struct { + pthread_mutex_t mutex_phy_proc_tx; + pthread_cond_t cond_phy_proc_tx; + volatile uint8_t phy_proc_CC_id; +} sync_phy_proc; + +extern double cpuf; + + +void init_eNB(int,int); +void stop_eNB(int nb_inst); + +int wakeup_tx(PHY_VARS_eNB *eNB ,int frame_rx,int subframe_rx,int frame_tx,int subframe_tx,uint64_t timestamp_tx); +int wakeup_txfh(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc,int frame_tx,int subframe_tx,uint64_t timestamp_tx); +void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe); +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe); +#endif + + +extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); +extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset); + +//#define TICK_TO_US(ts) (ts.diff) +#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials) + + +static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name) { + int ret; + start_meas(&softmodem_stats_rxtx_sf); + + //L1_rxtx_proc_t *L1_proc_tx = &eNB->proc.L1_proc_tx; + // ******************************************************************* +#if defined(PRE_SCD_THREAD) + RU_t *ru = RC.ru[0]; +#endif + + if (eNB ==NULL) { + LOG_D(PHY,"%s:%d: rxtx invalid argument, eNB pointer is NULL",__FILE__,__LINE__); + return -1; + } + + if (NFAPI_MODE==NFAPI_MODE_PNF) { + // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick + uint16_t frame = proc->frame_rx; + uint16_t subframe = proc->subframe_rx; + //add_subframe(&frame, &subframe, 4); + //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); + //LOG_D(PHY, "oai_subframe_ind(frame:%u, subframe:%d) - NOT CALLED ********\n", frame, subframe); + start_meas(&nfapi_meas); + oai_subframe_ind(frame, subframe); + stop_meas(&nfapi_meas); + + if (eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus|| + eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs || + eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs || + eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles || + eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis + ) { + LOG_D(PHY, "UL_info[rx_ind:%05d:%d harqs:%05d:%d crcs:%05d:%d preambles:%05d:%d cqis:%d] RX:%04d%d TX:%04d%d num_pdcch_symbols:%d\n", + NFAPI_SFNSF2DEC(eNB->UL_INFO.rx_ind.sfn_sf), eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus, + NFAPI_SFNSF2DEC(eNB->UL_INFO.harq_ind.sfn_sf), eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs, + NFAPI_SFNSF2DEC(eNB->UL_INFO.crc_ind.sfn_sf), eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, + NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles, + eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis, + proc->frame_rx, proc->subframe_rx, + proc->frame_tx, proc->subframe_tx, eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols); + } + } + + if (NFAPI_MODE==NFAPI_MODE_PNF && eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0) { + LOG_E(PHY, "eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols == 0"); + return 0; + } + + // **************************************** + // Common RX procedures subframe n + T(T_ENB_PHY_DL_TICK, T_INT(eNB->Mod_id), T_INT(proc->frame_tx), T_INT(proc->subframe_tx)); + + // if this is IF5 or 3GPP_eNB + if (eNB->RU_list && eNB->RU_list[0] && eNB->RU_list[0]->function < NGFI_RAU_IF4p5) { + wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx); +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx); +#endif + } + if (NFAPI_MODE!=NFAPI_MODE_PNF) { + release_UE_in_freeList(eNB->Mod_id); + } else { + release_rnti_of_phy(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); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, 1 ); +#if defined(PRE_SCD_THREAD) + + if (NFAPI_MODE==NFAPI_MODE_VNF) { + new_dlsch_ue_select_tbl_in_use = dlsch_ue_select_tbl_in_use; + dlsch_ue_select_tbl_in_use = !dlsch_ue_select_tbl_in_use; + // L2-emulator can work only one eNB. + // memcpy(&pre_scd_eNB_UE_stats,&RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); + // memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX); + memcpy(&pre_scd_eNB_UE_stats,&RC.mac[0]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX); + memcpy(&pre_scd_activeUE, &RC.mac[0]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX); + + AssertFatal((ret= pthread_mutex_lock(&ru->proc.mutex_pre_scd))==0,"[eNB] error locking proc mutex for eNB pre scd, return %d\n",ret); + + ru->proc.instance_pre_scd++; + + if (ru->proc.instance_pre_scd == 0) { + if (pthread_cond_signal(&ru->proc.cond_pre_scd) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB pre scd\n" ); + exit_fun( "ERROR pthread_cond_signal cond_pre_scd" ); + } + } else { + LOG_E( PHY, "[eNB] frame %d subframe %d rxtx busy instance_pre_scd %d\n", + proc->frame_rx,proc->subframe_rx,ru->proc.instance_pre_scd ); + } + + AssertFatal((ret= pthread_mutex_unlock(&ru->proc.mutex_pre_scd))==0,"[eNB] error unlocking proc mutex for eNB pre scd, return %d\n",ret); + + } + +#endif + AssertFatal((ret= pthread_mutex_lock(&eNB->UL_INFO_mutex))==0,"error locking UL_INFO_mutex, return %d\n",ret); + 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); + AssertFatal((ret= pthread_mutex_unlock(&eNB->UL_INFO_mutex))==0,"error unlocking UL_INFO_mutex, return %d\n",ret); + + /* this conflict resolution may be totally wrong, to be tested */ + /* CONFLICT RESOLUTION: BEGIN */ + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, 0 ); + + if(oai_exit) return(-1); + + if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) { +#ifndef PHY_TX_THREAD + phy_procedures_eNB_TX(eNB, proc, 1); +#endif + } + + /* CONFLICT RESOLUTION: what about this release_thread call, has it to be done? if yes, where? */ + //if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) return(-1); + /* CONFLICT RESOLUTION: END */ + stop_meas( &softmodem_stats_rxtx_sf ); + + LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, proc->frame_rx, proc->subframe_rx, proc->frame_tx, proc->subframe_tx); + LOG_D(PHY, "rxtx:%lld nfapi:%lld tx:%lld rx:%lld prach:%lld ofdm:%lld ", + softmodem_stats_rxtx_sf.p_time, nfapi_meas.p_time, + TICK_TO_US(eNB->phy_proc_tx), + TICK_TO_US(eNB->phy_proc_rx), + TICK_TO_US(eNB->rx_prach), + TICK_TO_US(eNB->ofdm_mod_stats) + ); + + LOG_D(PHY, + "dlsch[enc:%lld mod:%lld scr:%lld rm:%lld t:%lld i:%lld] rx_dft:%lld ", + TICK_TO_US(eNB->dlsch_encoding_stats), + TICK_TO_US(eNB->dlsch_modulation_stats), + TICK_TO_US(eNB->dlsch_scrambling_stats), + TICK_TO_US(eNB->dlsch_rate_matching_stats), + TICK_TO_US(eNB->dlsch_turbo_encoding_stats), + TICK_TO_US(eNB->dlsch_interleaving_stats), + TICK_TO_US(eNB->rx_dft_stats)); + LOG_D(PHY," ulsch[ch:%lld freq:%lld dec:%lld demod:%lld ru:%lld ", + TICK_TO_US(eNB->ulsch_channel_estimation_stats), + TICK_TO_US(eNB->ulsch_freq_offset_estimation_stats), + TICK_TO_US(eNB->ulsch_decoding_stats), + TICK_TO_US(eNB->ulsch_demodulation_stats), + TICK_TO_US(eNB->ulsch_rate_unmatching_stats)); + LOG_D(PHY, "td:%lld dei:%lld dem:%lld llr:%lld tci:%lld ", + TICK_TO_US(eNB->ulsch_turbo_decoding_stats), + TICK_TO_US(eNB->ulsch_deinterleaving_stats), + TICK_TO_US(eNB->ulsch_demultiplexing_stats), + TICK_TO_US(eNB->ulsch_llr_stats), + TICK_TO_US(eNB->ulsch_tc_init_stats)); + LOG_D(PHY, "tca:%lld tcb:%lld tcg:%lld tce:%lld l1:%lld l2:%lld]\n\n", + TICK_TO_US(eNB->ulsch_tc_alpha_stats), + TICK_TO_US(eNB->ulsch_tc_beta_stats), + TICK_TO_US(eNB->ulsch_tc_gamma_stats), + TICK_TO_US(eNB->ulsch_tc_ext_stats), + TICK_TO_US(eNB->ulsch_tc_intl1_stats), + TICK_TO_US(eNB->ulsch_tc_intl2_stats) + ); + return(0); +} + + +static void *L1_thread_tx(void *param) { + L1_proc_t *eNB_proc = (L1_proc_t *)param; + L1_rxtx_proc_t *proc = &eNB_proc->L1_proc_tx; + PHY_VARS_eNB *eNB = RC.eNB[0][proc->CC_id]; + char thread_name[100]; + sprintf(thread_name,"TXnp4_%d\n",&eNB->proc.L1_proc == proc ? 0 : 1); + thread_top_init(thread_name,1,470000,500000,500000); + int ret; + + //wait_sync("tx_thread"); + + + while (!oai_exit) { + LOG_D(PHY,"Waiting for TX (IC %d)\n",proc->instance_cnt); + if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break; + + if (oai_exit) break; + + LOG_D(PHY,"L1_thread_tx: Running for %d.%d\n",proc->frame_tx,proc->subframe_tx); + // ***************************************** + // TX processing for subframe n+4 + // run PHY TX procedures the one after the other for all CCs to avoid race conditions + // (may be relaxed in the future for performance reasons) + // ***************************************** + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX1_ENB,proc->subframe_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX1_ENB,proc->subframe_rx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_ENB,proc->frame_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_ENB,proc->frame_rx); + LOG_D(PHY,"L1 TX processing %d.%d\n",proc->frame_tx,proc->subframe_tx); + phy_procedures_eNB_TX(eNB, proc, 1); + AssertFatal((ret= pthread_mutex_lock( &proc->mutex ))==0,"error locking L1_proc_tx mutex, return %d\n",ret); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_L1_PROC_TX_IC,proc->instance_cnt); + + int subframe_tx = proc->subframe_tx; + int frame_tx = proc->frame_tx; + uint64_t timestamp_tx = proc->timestamp_tx; + + proc->instance_cnt = -1; + + LOG_D(PHY,"L1 TX signaling done for %d.%d\n",proc->frame_tx,proc->subframe_tx); + // the thread can now be woken up + LOG_D(PHY,"L1_thread_tx: signaling completion in %d.%d\n",proc->frame_tx,proc->subframe_tx); + if (pthread_cond_signal(&proc->cond) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + } + + AssertFatal((ret= pthread_mutex_unlock( &proc->mutex ))==0,"error unlocking L1_proc_tx mutex, return %d\n",ret); + wakeup_txfh(eNB,proc,frame_tx,subframe_tx,timestamp_tx); + } + + return 0; +} + +/*! + * \brief The RX UE-specific and TX thread of eNB. + * \param param is a \ref L1_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ + +static void *L1_thread( void *param ) { + static int eNB_thread_rxtx_status; + L1_rxtx_proc_t *proc; + // Working + if(NFAPI_MODE==NFAPI_MODE_VNF) { + proc = (L1_rxtx_proc_t *)param; + } else { + L1_proc_t *eNB_proc = (L1_proc_t *)param; + proc = &eNB_proc->L1_proc; + } + + PHY_VARS_eNB *eNB = RC.eNB[0][proc->CC_id]; + char thread_name[100]; + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + // set default return value + eNB_thread_rxtx_status = 0; + sprintf(thread_name,"RXn_TXnp4_%d\n",&eNB->proc.L1_proc == proc ? 0 : 1); + thread_top_init(thread_name,1,470000,500000,500000); + pthread_setname_np( pthread_self(),"rxtx processing"); + LOG_I(PHY,"thread rxtx created id=%ld\n", syscall(__NR_gettid)); + + while (!oai_exit) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); + T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx)); + + LOG_D(PHY,"L1RX waiting for RU RX\n"); + if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break; + + LOG_D(PHY,"L1RX starting in %d.%d\n",proc->frame_rx,proc->subframe_rx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_CPUID_ENB_THREAD_RXTX,sched_getcpu()); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_ENB,proc->subframe_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_ENB,proc->subframe_rx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_ENB,proc->frame_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_ENB,proc->frame_rx); + + + if (oai_exit) break; + + if (eNB->CC_id==0) { + if (rxtx_NB_IoT(eNB,proc,thread_name) < 0) break; // Call rxtx_NB_IoT + } + + LOG_D(PHY,"L1 RX %d.%d done\n",proc->frame_rx,proc->subframe_rx); + + if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) phy_procedures_eNB_TX(eNB, proc, 1); + + + if (NFAPI_MODE!=NFAPI_MODE_VNF) { + if(get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) wakeup_tx(eNB,proc->frame_rx,proc->subframe_rx,proc->frame_tx,proc->subframe_tx,proc->timestamp_tx); + else if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) wakeup_txfh(eNB,proc,proc->frame_tx,proc->subframe_tx,proc->timestamp_tx); + } + + if (release_thread(&proc->mutex,&proc->instance_cnt,thread_name)<0) break; + + + } // while !oai_exit + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 ); + LOG_D(PHY, " *** Exiting eNB thread RXn_TXnp4\n"); + eNB_thread_rxtx_status = 0; + return &eNB_thread_rxtx_status; +} + +void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string,RU_t *ru) { + L1_proc_t *proc = &eNB->proc; + L1_rxtx_proc_t *L1_proc = &proc->L1_proc; + LTE_DL_FRAME_PARMS *fp = &ru->frame_parms; + RU_proc_t *ru_proc=&ru->proc; + proc->frame_rx = frame_rx; + proc->subframe_rx = subframe_rx; + + if (!oai_exit) { + T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx)); + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); + L1_proc->frame_rx = ru_proc->frame_rx; + L1_proc->subframe_rx = ru_proc->subframe_rx; + L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; + + if (rxtx_NB_IoT(eNB,L1_proc,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id); //Call rxtx_NB_IoT + + ru_proc->timestamp_tx = L1_proc->timestamp_tx; + ru_proc->subframe_tx = L1_proc->subframe_tx; + ru_proc->frame_tx = L1_proc->frame_tx; + } +} + +int wakeup_txfh(PHY_VARS_eNB *eNB, L1_rxtx_proc_t *proc,int frame_tx,int subframe_tx,uint64_t timestamp_tx) { + + RU_t *ru; + RU_proc_t *ru_proc; + LTE_DL_FRAME_PARMS *fp; + int waitret,ret; + + LOG_D(PHY,"L1 TX Waking up TX FH %d.%d (IC RU TX %d)\n",frame_tx,subframe_tx,proc->instance_cnt_RUs); + + // grab the information for the RU due to the following wait + + waitret=timedwait_on_condition(&proc->mutex_RUs,&proc->cond_RUs,&proc->instance_cnt_RUs,"wakeup_txfh",1000000); + + AssertFatal(release_thread(&proc->mutex_RUs,&proc->instance_cnt_RUs,"wakeup_txfh")==0, "error releaseing eNB lock on RUs\n"); + + if (waitret == ETIMEDOUT) { + LOG_W(PHY,"Dropping TX slot (%d.%d) because FH is blocked more than 1 subframe times (1ms)\n",frame_tx,subframe_tx); + + AssertFatal((ret=pthread_mutex_lock(&eNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); + eNB->proc.RU_mask_tx = 0; + AssertFatal((ret=pthread_mutex_unlock(&eNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); + AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RUs))==0,"mutex_lock returns %d\n",ret); + proc->instance_cnt_RUs = 0; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE,proc->instance_cnt_RUs); + AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RUs))==0,"mutex_unlock returns %d\n",ret); + return(-1); + } + + for(int ru_id=0; ru_id<eNB->num_RU; ru_id++){ + ru = eNB->RU_list[ru_id]; + ru_proc = &ru->proc; + fp = &ru->frame_parms; + if (((fp->frame_type == TDD) && (subframe_select(fp,proc->subframe_tx)==SF_UL))|| + (eNB->RU_list[ru_id]->state == RU_SYNC)|| + (eNB->RU_list[ru_id]->wait_cnt>0)){ + AssertFatal((pthread_mutex_lock(&proc->mutex_RUs))==0, "mutex_lock returns %d\n",ret); + proc->instance_cnt_RUs = 0; + AssertFatal((pthread_mutex_unlock(&proc->mutex_RUs))==0, "mutex_unlock returns %d\n",ret); + continue;//hacking only works when all RU_tx works on the same subframe #TODO: adding mask stuff + } + + AssertFatal((ret = pthread_mutex_lock(&ru_proc->mutex_eNBs))==0,"ERROR pthread_mutex_lock failed on mutex_eNBs L1_thread_tx with ret=%d\n",ret); + + if (ru_proc->instance_cnt_eNBs == 0) { + LOG_E(PHY,"Frame %d, subframe %d: TX FH thread busy, dropping Frame %d, subframe %d\n", ru_proc->frame_tx, ru_proc->subframe_tx, proc->frame_rx, proc->subframe_rx); + AssertFatal((ret=pthread_mutex_lock(&eNB->proc.mutex_RU_tx))==0,"mutex_lock returns %d\n",ret); + eNB->proc.RU_mask_tx = 0; + AssertFatal((ret=pthread_mutex_unlock(&eNB->proc.mutex_RU_tx))==0,"mutex_unlock returns %d\n",ret); + AssertFatal((ret=pthread_mutex_unlock( &ru_proc->mutex_eNBs ))==0,"mutex_unlock return %d\n",ret); + return(-1); + } + + ru_proc->instance_cnt_eNBs = 0; + ru_proc->timestamp_tx = timestamp_tx; + ru_proc->subframe_tx = subframe_tx; + ru_proc->frame_tx = frame_tx; + + LOG_D(PHY,"L1 TX Waking up TX FH (2) %d.%d\n",frame_tx,subframe_tx); + // the thread can now be woken up + AssertFatal(pthread_cond_signal(&ru_proc->cond_eNBs) == 0, + "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n"); + AssertFatal((ret=pthread_mutex_unlock(&ru_proc->mutex_eNBs))==0,"mutex_unlock returned %d\n",ret); + } + return(0); +} + +int wakeup_tx(PHY_VARS_eNB *eNB, int frame_rx,int subframe_rx,int frame_tx,int subframe_tx,uint64_t timestamp_tx) { + + L1_rxtx_proc_t *L1_proc = &eNB->proc.L1_proc; + L1_rxtx_proc_t *L1_proc_tx = &eNB->proc.L1_proc_tx; + + int ret; + + LOG_D(PHY,"ENTERED wakeup_tx (IC %d)\n",L1_proc_tx->instance_cnt); + + AssertFatal((ret = pthread_mutex_lock(&L1_proc_tx->mutex))==0,"mutex_lock returns %d\n",ret); + + LOG_D(PHY,"L1 RX %d.%d Waiting to wake up L1 TX %d.%d (IC L1TX %d)\n",L1_proc->frame_rx,L1_proc->subframe_rx,L1_proc->frame_tx,L1_proc->subframe_tx,L1_proc_tx->instance_cnt); + + while(L1_proc_tx->instance_cnt == 0) { + pthread_cond_wait(&L1_proc_tx->cond,&L1_proc_tx->mutex); + } + + LOG_D(PHY,"L1 RX Got signal that TX %d.%d is done\n",L1_proc_tx->frame_tx,L1_proc_tx->subframe_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_L1_PROC_TX_IC,L1_proc_tx->instance_cnt); + L1_proc_tx->instance_cnt = 0; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_L1_PROC_TX_IC,L1_proc_tx->instance_cnt); + L1_proc_tx->subframe_rx = subframe_rx; + L1_proc_tx->frame_rx = frame_rx; + L1_proc_tx->subframe_tx = subframe_tx; + L1_proc_tx->frame_tx = frame_tx; + L1_proc_tx->timestamp_tx = timestamp_tx; + + // the thread can now be woken up + LOG_D(PHY,"L1 RX Waking up L1 TX %d.%d\n",L1_proc->frame_tx,L1_proc->subframe_tx); + AssertFatal(pthread_cond_signal(&L1_proc_tx->cond) == 0, "ERROR pthread_cond_signal for eNB L1 thread tx\n"); + + AssertFatal((ret=pthread_mutex_unlock(&L1_proc_tx->mutex))==0,"mutex_unlock returns %d\n",ret); + return(0); +} + +int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) { + L1_proc_t *proc=&eNB->proc; + RU_proc_t *ru_proc=&ru->proc; + L1_rxtx_proc_t *L1_proc=&proc->L1_proc; + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + int ret; + + LOG_D(PHY,"ENTERED wakeup_rxtx, %d.%d\n",ru_proc->frame_rx,ru_proc->subframe_rx); + + // wake up TX for subframe n+sl_ahead + // lock the TX mutex and make sure the thread is ready + AssertFatal((ret=pthread_mutex_lock(&L1_proc->mutex)) == 0,"mutex_lock returns %d\n", ret); + + if (L1_proc->instance_cnt == 0) { // L1_thread is busy so abort the subframe + AssertFatal((ret=pthread_mutex_unlock( &L1_proc->mutex))==0,"mutex_unlock return %d\n",ret); + LOG_W(PHY,"L1_thread isn't ready in %d.%d, aborting RX processing\n",ru_proc->frame_rx,ru_proc->subframe_rx); + return(0); + } + + + ++L1_proc->instance_cnt; + // We have just received and processed the common part of a subframe, say n. + // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired + // transmitted timestamp of the next TX slot (first). + // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, + // we want to generate subframe (n+sf_ahead), so TS_tx = TX_rx+sf_ahead*samples_per_tti, + // and proc->subframe_tx = proc->subframe_rx+sf_ahead + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sf_ahead*fp->samples_per_tti); + L1_proc->frame_rx = ru_proc->frame_rx; + L1_proc->subframe_rx = ru_proc->subframe_rx; + L1_proc->frame_tx = (L1_proc->subframe_rx > (9-sf_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead)%10; + + LOG_D(PHY,"wakeup_rxtx: L1_proc->subframe_rx %d, L1_proc->subframe_tx %d, RU %d\n",L1_proc->subframe_rx,L1_proc->subframe_tx,ru->idx); + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_RXTX_RX_RU+ru->idx, L1_proc->frame_rx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_RXTX_RX_RU+ru->idx, L1_proc->subframe_rx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_WAKEUP_RXTX_TX_RU+ru->idx, L1_proc->frame_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_WAKEUP_RXTX_TX_RU+ru->idx, L1_proc->subframe_tx); + + // the thread can now be woken up + if (pthread_cond_signal(&L1_proc->cond) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB RXn-TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + AssertFatal((ret=pthread_mutex_unlock( &L1_proc->mutex))==0,"mutex_unlock return %d\n",ret); + + return(0); +} + +void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { + L1_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + int i,ret; + + if (ru!=NULL) { + + AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RU_PRACH))==0,"mutex_lock return %d\n",ret); + for (i=0; i<eNB->num_RU; i++) { + if (ru == eNB->RU_list[i]) { + LOG_D(PHY,"frame %d, subframe %d: RU %d for eNB %d signals PRACH (mask %x, num_RU %d)\n",frame,subframe,i,eNB->Mod_id,proc->RU_mask_prach,eNB->num_RU); + + if ((proc->RU_mask_prach&(1<<i)) > 0) + LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information (PRACH) from RU %d (num_RU %d, mask %x) has not been served yet!\n", + eNB->Mod_id,frame,subframe,ru->idx,eNB->num_RU,proc->RU_mask_prach); + + proc->RU_mask_prach |= (1<<i); + } + } + + if (proc->RU_mask_prach != (1<<eNB->num_RU)-1) { // not all RUs have provided their information so return + AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU_PRACH))==0,"mutex_unlock return %d\n",ret); + return; + } else { // all RUs have provided their information so continue on and wakeup eNB processing + proc->RU_mask_prach = 0; + AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU_PRACH))==0,"mutex_unlock return %d\n",ret); + } + } + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe); + + if (proc->instance_cnt_prach == 0) { + LOG_W(PHY,"[eNB] Frame %d Subframe %d, dropping PRACH\n", frame,subframe); + return; + } + + // wake up thread for PRACH RX + AssertFatal((ret=pthread_mutex_lock(&proc->mutex_prach))==0,"[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach); + + ++proc->instance_cnt_prach; + // set timing for prach thread + proc->frame_prach = frame; + proc->subframe_prach = subframe; + + // the thread can now be woken up + if (pthread_cond_signal(&proc->cond_prach) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH thread %d\n", proc->thread_index); + exit_fun( "ERROR pthread_cond_signal" ); + return; + } + + AssertFatal((ret=pthread_mutex_unlock( &proc->mutex_prach))==0,"mutex_unlock return %d\n",ret); + } +} + +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) +void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) { + L1_proc_t *proc = &eNB->proc; + LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms; + int i,ret; + + if (ru!=NULL) { + AssertFatal((ret=pthread_mutex_lock(&proc->mutex_RU_PRACH_br))==0,"mutex_lock return %d\n",ret); + + for (i=0; i<eNB->num_RU; i++) { + if (ru == eNB->RU_list[i]) { + LOG_D(PHY,"frame %d, subframe %d: RU %d for eNB %d signals PRACH BR (mask %x, num_RU %d)\n",frame,subframe,i,eNB->Mod_id,proc->RU_mask_prach_br,eNB->num_RU); + + if ((proc->RU_mask_prach_br&(1<<i)) > 0) + LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information (PRACH BR) from RU %d (num_RU %d, mask %x) has not been served yet!\n", + eNB->Mod_id,frame,subframe,ru->idx,eNB->num_RU,proc->RU_mask_prach_br); + + proc->RU_mask_prach_br |= (1<<i); + } + } + + if (proc->RU_mask_prach_br != (1<<eNB->num_RU)-1) { // not all RUs have provided their information so return + AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU_PRACH_br))==0,"mutex_unlock return %d\n",ret); + return; + } else { // all RUs have provided their information so continue on and wakeup eNB processing + proc->RU_mask_prach_br = 0; + AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_RU_PRACH_br))==0,"mutex_unlock return %d\n",ret); + } + } + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe); + + if (proc->instance_cnt_prach_br == 0) { + LOG_W(PHY,"[eNB] Frame %d Subframe %d, dropping PRACH BR\n", frame,subframe); + return; + } + + // wake up thread for PRACH RX + AssertFatal((ret=pthread_mutex_lock(&proc->mutex_prach_br))==0,"[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach_br); + + ++proc->instance_cnt_prach_br; + // set timing for prach thread + proc->frame_prach_br = frame; + proc->subframe_prach_br = subframe; + + // the thread can now be woken up + if (pthread_cond_signal(&proc->cond_prach_br) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH BR thread %d\n", proc->thread_index); + exit_fun( "ERROR pthread_cond_signal" ); + return; + } + + AssertFatal((ret=pthread_mutex_unlock( &proc->mutex_prach_br))==0,"mutex_unlock return %d\n",ret); + } +} +#endif + + +/*! + * \brief The prach receive thread of eNB. + * \param param is a \ref L1_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ +static void *eNB_thread_prach( void *param ) { + static int eNB_thread_prach_status; + PHY_VARS_eNB *eNB= (PHY_VARS_eNB *)param; + L1_proc_t *proc = &eNB->proc; + // set default return value + eNB_thread_prach_status = 0; + thread_top_init("eNB_thread_prach",1,500000,1000000,20000000); + + //wait_sync("eNB_thread_prach"); + + while (!oai_exit) { + if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break; + + if (oai_exit) break; + + LOG_D(PHY,"Running eNB prach procedures\n"); + prach_procedures(eNB +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,0 +#endif + ); + + if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break; + } + + LOG_I(PHY, "Exiting eNB thread PRACH\n"); + eNB_thread_prach_status = 0; + return &eNB_thread_prach_status; +} + +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) +/*! + * \brief The prach receive thread of eNB for BL/CE UEs. + * \param param is a \ref L1_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ +static void *eNB_thread_prach_br( void *param ) { + static int eNB_thread_prach_status; + PHY_VARS_eNB *eNB= (PHY_VARS_eNB *)param; + L1_proc_t *proc = &eNB->proc; + // set default return value + eNB_thread_prach_status = 0; + thread_top_init("eNB_thread_prach_br",1,500000,1000000,20000000); + + while (!oai_exit) { + if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break; + + if (oai_exit) break; + + LOG_D(PHY,"Running eNB prach procedures for BL/CE UEs\n"); + prach_procedures(eNB,1); + + if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break; + } + + LOG_I(PHY, "Exiting eNB thread PRACH BR\n"); + eNB_thread_prach_status = 0; + return &eNB_thread_prach_status; +} + +#endif + + + +extern void init_td_thread(PHY_VARS_eNB *); +extern void init_te_thread(PHY_VARS_eNB *); +extern void kill_td_thread(PHY_VARS_eNB *); +extern void kill_te_thread(PHY_VARS_eNB *); + +static void *process_stats_thread(void *param) { + PHY_VARS_eNB *eNB = (PHY_VARS_eNB *)param; + wait_sync("process_stats_thread"); + + while (!oai_exit) { + sleep(1); + + if (opp_enabled == 1) { + if ( eNB->ulsch_decoding_stats.trials>0) + print_meas(&eNB->ulsch_decoding_stats,"ulsch_decoding",NULL,NULL); + + if (eNB->dlsch_encoding_stats.trials >0) { + print_meas(&eNB->dlsch_turbo_encoding_preperation_stats,"dlsch_coding_crc",NULL,NULL); + print_meas(&eNB->dlsch_turbo_encoding_segmentation_stats,"dlsch_segmentation",NULL,NULL); + print_meas(&eNB->dlsch_encoding_stats,"dlsch_encoding",NULL,NULL); + print_meas(&eNB->dlsch_turbo_encoding_signal_stats,"coding_signal",NULL,NULL); + print_meas(&eNB->dlsch_turbo_encoding_main_stats,"coding_main",NULL,NULL); + print_meas(&eNB->dlsch_turbo_encoding_stats,"turbo_encoding",NULL,NULL); + print_meas(&eNB->dlsch_interleaving_stats,"turbo_interleaving",NULL,NULL); + print_meas(&eNB->dlsch_rate_matching_stats,"turbo_rate_matching",NULL,NULL); + print_meas(&eNB->dlsch_turbo_encoding_waiting_stats,"coding_wait",NULL,NULL); + print_meas(&eNB->dlsch_turbo_encoding_wakeup_stats0,"coding_worker_0",NULL,NULL); + print_meas(&eNB->dlsch_turbo_encoding_wakeup_stats1,"coding_worker_1",NULL,NULL); + } + + print_meas(&eNB->dlsch_modulation_stats,"dlsch_modulation",NULL,NULL); + } + } + + return(NULL); +} + +void init_eNB_proc(int inst) { + /*int i=0;*/ + int CC_id; + PHY_VARS_eNB *eNB; + L1_proc_t *proc; + L1_rxtx_proc_t *L1_proc, *L1_proc_tx; + pthread_attr_t *attr0=NULL,*attr1=NULL,*attr_prach=NULL; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + pthread_attr_t *attr_prach_br=NULL; +#endif + LOG_I(PHY,"%s(inst:%d) RC.nb_CC[inst]:%d \n",__FUNCTION__,inst,RC.nb_CC[inst]); + + for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) { + eNB = RC.eNB[inst][CC_id]; +#ifndef OCP_FRAMEWORK + LOG_I(PHY,"Initializing eNB processes instance:%d CC_id %d \n",inst,CC_id); +#endif + proc = &eNB->proc; + L1_proc = &proc->L1_proc; + L1_proc_tx = &proc->L1_proc_tx; + L1_proc->instance_cnt = -1; + L1_proc_tx->instance_cnt = -1; + L1_proc->instance_cnt_RUs = 0; + L1_proc_tx->instance_cnt_RUs = 0; + proc->instance_cnt_prach = -1; + proc->instance_cnt_asynch_rxtx = -1; + proc->instance_cnt_synch = -1; + proc->CC_id = CC_id; + proc->first_rx =1; + proc->first_tx =1; + proc->RU_mask_tx = (1<<eNB->num_RU)-1; + memset((void*)proc->RU_mask,0,10*sizeof(proc->RU_mask[0])); + proc->RU_mask_prach =0; + pthread_mutex_init( &eNB->UL_INFO_mutex, NULL); + pthread_mutex_init( &L1_proc->mutex, NULL); + pthread_mutex_init( &L1_proc_tx->mutex, NULL); + pthread_cond_init( &L1_proc->cond, NULL); + pthread_cond_init( &L1_proc_tx->cond, NULL); + pthread_mutex_init( &L1_proc->mutex_RUs, NULL); + pthread_mutex_init( &L1_proc_tx->mutex_RUs, NULL); + pthread_cond_init( &L1_proc->cond_RUs, NULL); + pthread_cond_init( &L1_proc_tx->cond_RUs, NULL); + pthread_mutex_init( &proc->mutex_prach, NULL); + pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); + pthread_mutex_init( &proc->mutex_RU,NULL); + pthread_mutex_init( &proc->mutex_RU_tx,NULL); + pthread_mutex_init( &proc->mutex_RU_PRACH,NULL); + pthread_cond_init( &proc->cond_prach, NULL); + pthread_cond_init( &proc->cond_asynch_rxtx, NULL); + pthread_attr_init( &proc->attr_prach); + pthread_attr_init( &proc->attr_asynch_rxtx); + pthread_attr_init( &L1_proc->attr); + pthread_attr_init( &L1_proc_tx->attr); +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + proc->instance_cnt_prach_br = -1; + proc->RU_mask_prach_br=0; + pthread_mutex_init( &proc->mutex_prach_br, NULL); + pthread_mutex_init( &proc->mutex_RU_PRACH_br,NULL); + pthread_cond_init( &proc->cond_prach_br, NULL); + pthread_attr_init( &proc->attr_prach_br); +#endif +#ifndef DEADLINE_SCHEDULER + attr0 = &L1_proc->attr; + attr1 = &L1_proc_tx->attr; + attr_prach = &proc->attr_prach; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + attr_prach_br = &proc->attr_prach_br; +#endif + // attr_td = &proc->attr_td; + // attr_te = &proc->attr_te; +#endif + + if(get_thread_worker_conf() == WORKER_ENABLE) { + init_te_thread(eNB); + init_td_thread(eNB); + } + + LOG_I(PHY,"eNB->single_thread_flag:%d\n", eNB->single_thread_flag); + + if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) { + pthread_create( &L1_proc->pthread, attr0, L1_thread, proc ); + pthread_create( &L1_proc_tx->pthread, attr1, L1_thread_tx, proc); + } else if (NFAPI_MODE==NFAPI_MODE_VNF) { // this is neccesary in VNF or L2 FAPI simulator. + // Original Code from Fujitsu w/ old structure/field name + //pthread_create( &proc_rxtx[0].pthread_rxtx, attr0, eNB_thread_rxtx, &proc_rxtx[0] ); + //pthread_create( &proc_rxtx[1].pthread_rxtx, attr1, eNB_thread_rxtx, &proc_rxtx[1] ); + pthread_create( &L1_proc->pthread, attr0, L1_thread, L1_proc ); + pthread_create( &L1_proc_tx->pthread, attr1, L1_thread, L1_proc_tx); + } + + pthread_create( &proc->pthread_prach, attr_prach, eNB_thread_prach_NB_IoT, eNB ); // Call eNB_thread_prach_NB_IoT +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + pthread_create( &proc->pthread_prach_br, attr_prach_br, eNB_thread_prach_br, eNB ); +#endif + AssertFatal(proc->instance_cnt_prach == -1,"instance_cnt_prach = %d\n",proc->instance_cnt_prach); + + if (opp_enabled == 1) pthread_create(&proc->process_stats_thread,NULL,process_stats_thread,(void *)eNB); + } + + //for multiple CCs: setup master and slaves + /* + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + eNB = PHY_vars_eNB_g[inst][CC_id]; + + if (eNB->node_timing == synch_to_ext_device) { //master + eNB->proc.num_slaves = MAX_NUM_CCs-1; + eNB->proc.slave_proc = (L1_proc_t**)malloc(eNB->proc.num_slaves*sizeof(L1_proc_t*)); + + for (i=0; i< eNB->proc.num_slaves; i++) { + if (i < CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i]->proc); + if (i >= CC_id) eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i+1]->proc); + } + } + } + */ + /* setup PHY proc TX sync mechanism */ + pthread_mutex_init(&sync_phy_proc.mutex_phy_proc_tx, NULL); + pthread_cond_init(&sync_phy_proc.cond_phy_proc_tx, NULL); + sync_phy_proc.phy_proc_CC_id = 0; +} + + + +/*! + * \brief Terminate eNB TX and RX threads. + */ +void kill_eNB_proc(int inst) { + int *status; + PHY_VARS_eNB *eNB; + L1_proc_t *proc; + L1_rxtx_proc_t *L1_proc, *L1_proc_tx; + int ret; + + for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + eNB=RC.eNB[inst][CC_id]; + proc = &eNB->proc; + L1_proc = &proc->L1_proc; + L1_proc_tx = &proc->L1_proc_tx; + + if(get_thread_worker_conf() == WORKER_ENABLE) { + kill_td_thread(eNB); + kill_te_thread(eNB); + } + + LOG_I(PHY, "Killing TX CC_id %d inst %d\n", CC_id, inst ); + + if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) { + AssertFatal((ret=pthread_mutex_lock(&L1_proc->mutex))==0,"mutex_lock return %d\n",ret); + L1_proc->instance_cnt = 0; + pthread_cond_signal(&L1_proc->cond); + AssertFatal((ret=pthread_mutex_unlock(&L1_proc->mutex))==0,"mutex_unlock return %d\n",ret); + AssertFatal((ret=pthread_mutex_lock(&L1_proc_tx->mutex))==0,"mutex_lock return %d\n",ret); + L1_proc_tx->instance_cnt = 0; + pthread_cond_signal(&L1_proc_tx->cond); + AssertFatal((ret=pthread_mutex_unlock(&L1_proc_tx->mutex))==0,"muex_unlock return %d\n",ret); + } + + AssertFatal((ret=pthread_mutex_lock(&proc->mutex_prach))==0,"mutex_lock return %d\n",ret); + proc->instance_cnt_prach = 0; + pthread_cond_signal( &proc->cond_prach ); + AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_prach))==0,"mutex_unlock return %d\n",ret); + pthread_cond_signal( &proc->cond_asynch_rxtx ); + pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx); + LOG_D(PHY, "joining pthread_prach\n"); + pthread_join( proc->pthread_prach, (void **)&status ); + LOG_I(PHY, "Destroying prach mutex/cond\n"); + pthread_mutex_destroy( &proc->mutex_prach); + pthread_cond_destroy( &proc->cond_prach ); +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + proc->instance_cnt_prach_br = 0; + pthread_cond_signal( &proc->cond_prach_br ); + pthread_join( proc->pthread_prach_br, (void **)&status ); + pthread_mutex_destroy( &proc->mutex_prach_br); + pthread_cond_destroy( &proc->cond_prach_br ); +#endif + LOG_I(PHY, "Destroying UL_INFO mutex\n"); + pthread_mutex_destroy(&eNB->UL_INFO_mutex); + + if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) { + LOG_I(PHY, "Joining L1_proc mutex/cond\n"); + pthread_join( L1_proc->pthread, (void **)&status ); + LOG_I(PHY, "Joining L1_proc_tx mutex/cond\n"); + pthread_join( L1_proc_tx->pthread, (void **)&status ); + } + + LOG_I(PHY, "Destroying L1_proc mutex/cond\n"); + pthread_mutex_destroy( &L1_proc->mutex ); + pthread_cond_destroy( &L1_proc->cond ); + pthread_mutex_destroy( &L1_proc->mutex_RUs ); + pthread_cond_destroy( &L1_proc->cond_RUs ); + LOG_I(PHY, "Destroying L1_proc_tx mutex/cond\n"); + pthread_mutex_destroy( &L1_proc_tx->mutex ); + pthread_cond_destroy( &L1_proc_tx->cond ); + pthread_mutex_destroy( &L1_proc_tx->mutex_RUs ); + pthread_cond_destroy( &L1_proc_tx->cond_RUs ); + pthread_attr_destroy(&proc->attr_prach); + pthread_attr_destroy(&proc->attr_asynch_rxtx); + pthread_attr_destroy(&L1_proc->attr); + pthread_attr_destroy(&L1_proc_tx->attr); +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + pthread_mutex_destroy(&proc->mutex_RU_PRACH_br); + pthread_attr_destroy(&proc->attr_prach_br); +#endif + } +} + + +/******************************************Define in original NB-IoT branch*************************************************/ + +/* this function maps the phy_vars_eNB 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 CC, on which rf chain the mapping should start. Multiple + antennas are mapped to successive RF chains on the same card. */ +int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg) { + + int i,j; + int CC_id,card,ant; + + //uint16_t N_TA_offset = 0; + + LTE_DL_FRAME_PARMS *frame_parms; + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + if (phy_vars_eNB[CC_id]) { + frame_parms = &(phy_vars_eNB[CC_id]->frame_parms); + printf("setup_eNB_buffers: frame_parms = %p\n",frame_parms); + } else { + printf("phy_vars_eNB[%d] not initialized\n", CC_id); + return(-1); + } + + /* + if (frame_parms->frame_type == TDD) { + if (frame_parms->N_RB_DL == 100) + N_TA_offset = 624; + else if (frame_parms->N_RB_DL == 50) + N_TA_offset = 624/2; + else if (frame_parms->N_RB_DL == 25) + N_TA_offset = 624/4; + } + */ + + + if (openair0_cfg[CC_id].mmapped_dma == 1) { + // replace RX signal buffers with mmaped HW versions + + for (i=0; i<frame_parms->nb_antennas_rx; i++) { + card = i/4; + ant = i%4; + printf("Mapping eNB CC_id %d, rx_ant %d, on card %d, chain %d\n",CC_id,i,phy_vars_eNB[CC_id]->rf_map.card+card, phy_vars_eNB[CC_id]->rf_map.chain+ant); + free(phy_vars_eNB[CC_id]->common_vars.rxdata[0][i]); + phy_vars_eNB[CC_id]->common_vars.rxdata[0][i] = openair0_cfg[phy_vars_eNB[CC_id]->rf_map.card+card].rxbase[phy_vars_eNB[CC_id]->rf_map.chain+ant]; + + printf("rxdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->common_vars.rxdata[0][i]); + for (j=0; j<16; j++) { + printf("rxbuffer %d: %x\n",j,phy_vars_eNB[CC_id]->common_vars.rxdata[0][i][j]); + phy_vars_eNB[CC_id]->common_vars.rxdata[0][i][j] = 16-j; + } + } + + for (i=0; i<frame_parms->nb_antennas_tx; i++) { + card = i/4; + ant = i%4; + printf("Mapping eNB CC_id %d, tx_ant %d, on card %d, chain %d\n",CC_id,i,phy_vars_eNB[CC_id]->rf_map.card+card, phy_vars_eNB[CC_id]->rf_map.chain+ant); + free(phy_vars_eNB[CC_id]->common_vars.txdata[0][i]); + phy_vars_eNB[CC_id]->common_vars.txdata[0][i] = openair0_cfg[phy_vars_eNB[CC_id]->rf_map.card+card].txbase[phy_vars_eNB[CC_id]->rf_map.chain+ant]; + + printf("txdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->common_vars.txdata[0][i]); + + for (j=0; j<16; j++) { + printf("txbuffer %d: %x\n",j,phy_vars_eNB[CC_id]->common_vars.txdata[0][i][j]); + phy_vars_eNB[CC_id]->common_vars.txdata[0][i][j] = 16-j; + } + } + } + else { // not memory-mapped DMA + //nothing to do, everything already allocated in lte_init + /* + rxdata = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*)); + txdata = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*)); + + for (i=0; i<frame_parms->nb_antennas_rx; i++) { + free(phy_vars_eNB[CC_id]->common_vars.rxdata[0][i]); + rxdata[i] = (int32_t*)(32 + malloc16(32+frame_parms->samples_per_tti*10*sizeof(int32_t))); // FIXME broken memory allocation + phy_vars_eNB[CC_id]->common_vars.rxdata[0][i] = rxdata[i]; //-N_TA_offset; // N_TA offset for TDD FIXME! N_TA_offset > 16 => access of unallocated memory + memset(rxdata[i], 0, frame_parms->samples_per_tti*10*sizeof(int32_t)); + printf("rxdata[%d] @ %p (%p) (N_TA_OFFSET %d)\n", i, phy_vars_eNB[CC_id]->common_vars.rxdata[0][i],rxdata[i],N_TA_offset); + } + + for (i=0; i<frame_parms->nb_antennas_tx; i++) { + free(phy_vars_eNB[CC_id]->common_vars.txdata[0][i]); + txdata[i] = (int32_t*)(32 + malloc16(32 + frame_parms->samples_per_tti*10*sizeof(int32_t))); // FIXME broken memory allocation + phy_vars_eNB[CC_id]->common_vars.txdata[0][i] = txdata[i]; + memset(txdata[i],0, frame_parms->samples_per_tti*10*sizeof(int32_t)); + printf("txdata[%d] @ %p\n", i, phy_vars_eNB[CC_id]->common_vars.txdata[0][i]); + } + */ + } + } + + return(0); +} + +/**************************************************************************************************************************/ + + + +void reset_opp_meas(void) { + int sfn; + reset_meas(&softmodem_stats_mt); + reset_meas(&softmodem_stats_hw); + + for (sfn=0; sfn < 10; sfn++) { + reset_meas(&softmodem_stats_rxtx_sf); + reset_meas(&softmodem_stats_rx_sf); + } +} + + +void print_opp_meas(void) { + int sfn=0; + print_meas(&softmodem_stats_mt, "Main ENB Thread", NULL, NULL); + print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL); + + for (sfn=0; sfn < 10; sfn++) { + print_meas(&softmodem_stats_rxtx_sf,"[eNB][total_phy_proc_rxtx]",NULL, NULL); + print_meas(&softmodem_stats_rx_sf,"[eNB][total_phy_proc_rx]",NULL,NULL); + } +} + +void free_transport(PHY_VARS_eNB *eNB) { + int i; + int j; + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + LOG_D(PHY, "Freeing Transport Channel Buffers for DLSCH, UE %d\n",i); + + for (j=0; j<2; j++) free_eNB_dlsch(eNB->dlsch[i][j]); + + LOG_D(PHY, "Freeing Transport Channel Buffer for ULSCH, UE %d\n",i); + free_eNB_ulsch(eNB->ulsch[1+i]); + } + + free_eNB_ulsch(eNB->ulsch[0]); +} + +void init_transport(PHY_VARS_eNB *eNB) { + int i; + int j; + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + LOG_I(PHY, "Initialise transport\n"); + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + LOG_D(PHY,"Allocating Transport Channel Buffers for DLSCH, UE %d\n",i); + + for (j=0; j<2; j++) { + eNB->dlsch[i][j] = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL,0,fp); + + if (!eNB->dlsch[i][j]) { + LOG_E(PHY,"Can't get eNB dlsch structures for UE %d \n", i); + exit(-1); + } else { + 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); + } + } + + LOG_D(PHY,"Allocating Transport Channel Buffer for ULSCH, UE %d\n",i); + eNB->ulsch[1+i] = new_eNB_ulsch(MAX_TURBO_ITERATIONS,fp->N_RB_UL, 0); + + if (!eNB->ulsch[1+i]) { + LOG_E(PHY,"Can't get eNB ulsch structures\n"); + exit(-1); + } + + // 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 + eNB->ulsch[0] = new_eNB_ulsch(MAX_TURBO_ITERATIONS, fp->N_RB_UL, 0); + + if (!eNB->ulsch[0]) { + LOG_E(PHY,"Can't get eNB ulsch structures\n"); + exit(-1); + } + + 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(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; +} + +void init_eNB_afterRU(void) { + int inst,CC_id,ru_id,i,aa; + PHY_VARS_eNB *eNB; + LOG_I(PHY,"%s() RC.nb_inst:%d\n", __FUNCTION__, RC.nb_inst); + + for (inst=0; inst<RC.nb_inst; inst++) { + LOG_I(PHY,"RC.nb_CC[inst]:%d\n", RC.nb_CC[inst]); + + + + for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) { + LOG_I(PHY,"RC.nb_CC[inst:%d][CC_id:%d]:%p\n", inst, CC_id, RC.eNB[inst][CC_id]); + eNB = RC.eNB[inst][CC_id]; + phy_init_lte_eNB(eNB,0,0); + + // map antennas and PRACH signals to eNB RX + if (0) AssertFatal(eNB->num_RU>0,"Number of RU attached to eNB %d is zero\n",eNB->Mod_id); + + LOG_I(PHY,"Mapping RX ports from %d RUs to eNB %d\n",eNB->num_RU,eNB->Mod_id); + eNB->frame_parms.nb_antennas_rx = 0; + LOG_I(PHY,"Overwriting eNB->prach_vars.rxsigF[0]:%p\n", eNB->prach_vars.rxsigF[0]); + eNB->prach_vars.rxsigF[0] = (int16_t **)malloc16(64*sizeof(int16_t *)); +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + + for (int ce_level=0; ce_level<4; ce_level++) { + LOG_I(PHY,"Overwriting eNB->prach_vars_br.rxsigF.rxsigF[0]:%p\n", eNB->prach_vars_br.rxsigF[ce_level]); + eNB->prach_vars_br.rxsigF[ce_level] = (int16_t **)malloc16(64*sizeof(int16_t *)); + } + +#endif + LOG_I(PHY,"eNB->num_RU:%d\n", eNB->num_RU); + + for (ru_id=0,aa=0; ru_id<eNB->num_RU; ru_id++) { + eNB->frame_parms.nb_antennas_rx += eNB->RU_list[ru_id]->nb_rx; + AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL, + "RU %d : common.rxdataF is NULL\n", + eNB->RU_list[ru_id]->idx); + AssertFatal(eNB->RU_list[ru_id]->prach_rxsigF!=NULL, + "RU %d : prach_rxsigF is NULL\n", + eNB->RU_list[ru_id]->idx); + + for (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[i]; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + + 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]; + +#endif + eNB->common_vars.rxdataF[aa] = eNB->RU_list[ru_id]->common.rxdataF[i]; + } + } + + /* TODO: review this code, there is something wrong. + * In monolithic mode, we come here with nb_antennas_rx == 0 + * (not tested in other modes). + */ + if (eNB->frame_parms.nb_antennas_rx < 1) { + LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_rx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_rx); + eNB->frame_parms.nb_antennas_rx = 1; + } else { + //LOG_I(PHY," Delete code\n"); + } + + if (eNB->frame_parms.nb_antennas_tx < 1) { + LOG_I(PHY, "%s() ************* DJP ***** eNB->frame_parms.nb_antennas_tx:%d - GOING TO HARD CODE TO 1", __FUNCTION__, eNB->frame_parms.nb_antennas_tx); + eNB->frame_parms.nb_antennas_tx = 1; + } else { + //LOG_I(PHY," Delete code\n"); + } + + AssertFatal(eNB->frame_parms.nb_antennas_rx >0, + "inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx); + 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]); + } + + init_eNB_proc(inst); + } + + for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { + AssertFatal(RC.ru[ru_id]!=NULL,"ru_id %d is null\n",ru_id); + RC.ru[ru_id]->wakeup_rxtx = wakeup_rxtx; + RC.ru[ru_id]->wakeup_prach_eNB = wakeup_prach_eNB; +#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + RC.ru[ru_id]->wakeup_prach_eNB_br = wakeup_prach_eNB_br; +#endif + RC.ru[ru_id]->eNB_top = eNB_top; + } +} + +void init_eNB(int single_thread_flag,int wait_for_sync) { + int CC_id; + int inst; + PHY_VARS_eNB *eNB; + LOG_I(PHY,"[lte-softmodem.c] eNB structure about to allocated RC.nb_L1_inst:%d RC.nb_L1_CC[0]:%d\n",RC.nb_L1_inst,RC.nb_L1_CC[0]); + + if (RC.eNB == NULL) RC.eNB = (PHY_VARS_eNB ** *) malloc(RC.nb_L1_inst*sizeof(PHY_VARS_eNB **)); + + LOG_I(PHY,"[lte-softmodem.c] eNB structure RC.eNB allocated\n"); + + for (inst=0; inst<RC.nb_L1_inst; inst++) { + if (RC.eNB[inst] == NULL) RC.eNB[inst] = (PHY_VARS_eNB **) malloc(RC.nb_CC[inst]*sizeof(PHY_VARS_eNB *)); + + for (CC_id=0; CC_id<RC.nb_L1_CC[inst]; CC_id++) { + if (RC.eNB[inst][CC_id] == NULL) RC.eNB[inst][CC_id] = (PHY_VARS_eNB *) malloc(sizeof(PHY_VARS_eNB)); + + eNB = RC.eNB[inst][CC_id]; + eNB->abstraction_flag = 0; + eNB->single_thread_flag = single_thread_flag; + LOG_I(PHY,"Initializing eNB %d CC_id %d single_thread_flag:%d\n",inst,CC_id,single_thread_flag); +#ifndef OCP_FRAMEWORK + LOG_I(PHY,"Initializing eNB %d CC_id %d\n",inst,CC_id); +#endif + LOG_I(PHY,"Registering with MAC interface module\n"); + 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)); + 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; + } + } + + + LOG_I(PHY,"[lte-softmodem.c] eNB structure allocated\n"); + + + +} + + + +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); + } +} diff --git a/targets/RT/USER/lte-softmodem_NB_IoT.c b/targets/RT/USER/lte-softmodem_NB_IoT.c new file mode 100755 index 0000000000000000000000000000000000000000..4f332ada63aa2b47e541cf9863515eb112ade875 --- /dev/null +++ b/targets/RT/USER/lte-softmodem_NB_IoT.c @@ -0,0 +1,2200 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.0 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file lte-enb.c + * \brief Top-level threads for eNodeB + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ + +#include "lte-softmodem.h" + +#include "T.h" + +#include "rt_wrapper.h" + +#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h" + +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "PHY/vars.h" +#include "SCHED/vars.h" +#include "LAYER2/MAC/vars.h" + +#include "../../SIMU/USER/init_lte.h" + +#include "LAYER2/MAC/defs.h" +#include "LAYER2/MAC/vars.h" +#include "LAYER2/MAC/proto.h" + +#include "RRC/LITE/vars.h" +#include "PHY_INTERFACE/vars.h" +#include "PHY_INTERFACE/defs.h" + +/////////////////////////////NB-IoT Parameters here//////////////////////////////////////// + +#include "PHY/vars_NB_IoT.h" + +#include "LAYER2/MAC/proto_NB_IoT.h" + +//#include "LAYER2/MAC/defs_NB_IoT.h" +//#include "LAYER2/MAC/vars_NB_IoT.h" + +///////////////////////////////////////END///////////////////////////////////////////////// + +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif +#include "UTIL/LOG/log_extern.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "UTIL/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" +//#include "PHY/TOOLS/time_meas.h" + +#ifndef OPENAIR2 +#include "UTIL/OTG/otg_vars.h" +#endif + +#if defined(ENABLE_ITTI) +#include "intertask_interface_init.h" +#include "create_tasks.h" +#endif + +#include "system.h" + +#ifdef XFORMS +#include "PHY/TOOLS/lte_phy_scope.h" +#include "stats.h" +// current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0) +// at eNB 0, an UL scope for every UE +FD_lte_phy_scope_ue *form_ue[NUMBER_OF_UE_MAX]; +FD_lte_phy_scope_enb *form_enb[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +FD_stats_form *form_stats=NULL,*form_stats_l2=NULL; +char title[255]; +unsigned char scope_enb_num_ue = 2; +static pthread_t forms_thread; //xforms +#endif //XFORMS + +pthread_cond_t sync_cond; +pthread_mutex_t sync_mutex; +int sync_var=-1; //!< protected by mutex \ref sync_mutex. + +uint16_t runtime_phy_rx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] +uint16_t runtime_phy_tx[29][6]; // SISO [MCS 0-28][RBs 0-5 : 6, 15, 25, 50, 75, 100] + +#if defined(ENABLE_ITTI) +volatile int start_eNB = 0; +volatile int start_UE = 0; +#endif +volatile int oai_exit = 0; + +static clock_source_t clock_source = internal; +static int wait_for_sync = 0; + +static char UE_flag=0; +unsigned int mmapped_dma=0; +int single_thread_flag=1; + +static char threequarter_fs=0; + +uint32_t downlink_frequency[MAX_NUM_CCs][4]; +int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; + + +static char *conf_config_file_name = NULL; +#if defined(ENABLE_ITTI) +static char *itti_dump_file = NULL; +#endif + +int UE_scan = 1; +int UE_scan_carrier = 0; +runmode_t mode = normal_txrx; + +FILE *input_fd=NULL; + + +#if MAX_NUM_CCs == 1 +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}}; +#else +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}}; +#endif + +double rx_gain_off = 0.0; + +double sample_rate=30.72e6; +double bw = 10.0e6; + +static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/; + +char rf_config_file[1024]; + +int chain_offset=0; +int phy_test = 0; +uint8_t usim_test = 0; + +uint8_t nb_antenna_tx = 1; +uint8_t nb_antenna_rx = 1; + +char ref[128] = "internal"; +char channels[128] = "0"; + +int rx_input_level_dBm; +static int online_log_messages=0; +#ifdef XFORMS +extern int otg_enabled; +static char do_forms=0; +#else +int otg_enabled; +#endif +//int number_of_cards = 1; + +static LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; + +eNB_func_t node_function[MAX_NUM_CCs]; +eNB_timing_t node_timing[MAX_NUM_CCs]; + +////////////////////////////////////// NB-IoT ////////////////////////////////////////////// +static NB_IoT_DL_FRAME_PARMS *frame_parms_NB_IoT[MAX_NUM_CCs]; // this will be still inside the PHY_VARS of LTE + +eNB_func_NB_IoT_t node_function_NB_IoT[MAX_NUM_CCs]; +eNB_timing_NB_IoT_t node_timing_NB_IoT[MAX_NUM_CCs]; + +/////////////////////////////////////////END///////////////////////////////////////////////// + +int16_t node_synch_ref[MAX_NUM_CCs]; + +uint32_t target_dl_mcs = 28; //maximum allowed mcs +uint32_t target_ul_mcs = 20; +uint32_t timing_advance = 0; +uint8_t exit_missed_slots=1; +uint64_t num_missed_slots=0; // counter for the number of missed slots + +int transmission_mode=1; + +int16_t glog_level = LOG_INFO; +int16_t glog_verbosity = LOG_MED; +int16_t hw_log_level = LOG_INFO; +int16_t hw_log_verbosity = LOG_MED; +int16_t phy_log_level = LOG_INFO; +int16_t phy_log_verbosity = LOG_MED; +int16_t mac_log_level = LOG_INFO; +int16_t mac_log_verbosity = LOG_MED; +int16_t rlc_log_level = LOG_INFO; +int16_t rlc_log_verbosity = LOG_MED; +int16_t pdcp_log_level = LOG_INFO; +int16_t pdcp_log_verbosity = LOG_MED; +int16_t rrc_log_level = LOG_INFO; +int16_t rrc_log_verbosity = LOG_MED; +int16_t opt_log_level = LOG_INFO; +int16_t opt_log_verbosity = LOG_MED; + +# if defined(ENABLE_USE_MME) +int16_t gtpu_log_level = LOG_DEBUG; +int16_t gtpu_log_verbosity = LOG_MED; +int16_t udp_log_level = LOG_DEBUG; +int16_t udp_log_verbosity = LOG_MED; +#endif +#if defined (ENABLE_SECURITY) +int16_t osa_log_level = LOG_INFO; +int16_t osa_log_verbosity = LOG_MED; +#endif + +char *rrh_UE_ip = "127.0.0.1"; +int rrh_UE_port = 51000; + +/* flag set by eNB conf file to specify if the radio head is local or remote (default option is local) */ +uint8_t local_remote_radio = BBU_LOCAL_RADIO_HEAD; +/* struct for ethernet specific parameters given in eNB conf file */ +eth_params_t *eth_params; + +openair0_config_t openair0_cfg[MAX_CARDS]; + +double cpuf; + +char uecap_xer[1024],uecap_xer_in=0; + +int oaisim_flag=0; +threads_t threads= {-1,-1,-1}; + +/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed + * this is very hackish - find a proper solution + */ +uint8_t abstraction_flag=0; + +/*---------------------BMC: timespec helpers -----------------------------*/ + +struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; +struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + +struct timespec clock_difftime(struct timespec start, struct timespec end) { + struct timespec temp; + if ((end.tv_nsec-start.tv_nsec)<0) { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } else { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + return temp; +} + +void print_difftimes(void) { +#ifdef DEBUG + printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#else + LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#endif +} + +void update_difftimes(struct timespec start, struct timespec end) { + struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + int changed = 0; + diff_time = clock_difftime(start, end); + if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { + min_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { + max_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } +#if 1 + if (changed) print_difftimes(); +#endif +} + +/*------------------------------------------------------------------------*/ + +unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { + return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); +} +unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { + return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); +} + +#if !defined(ENABLE_ITTI) +void signal_handler(int sig) { + void *array[10]; + size_t size; + + if (sig==SIGSEGV) { + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, 2); + exit(-1); + } else { + printf("trying to exit gracefully...\n"); + oai_exit = 1; + } +} +#endif +#define KNRM "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KBLU "\x1B[34m" +#define RESET "\033[0m" + +void help (void) { + printf (KGRN "Usage:\n"); + printf(" sudo -E lte-softmodem [options]\n"); + printf(" sudo -E ./lte-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.exmimo2.openEPC.conf -S -V -m 26 -t 16 -x 1 --ulsch-max-errors 100 -W\n\n"); + printf("Options:\n"); + printf(" --rf-config-file Configuration file for front-end (e.g. LMS7002M)\n"); + printf(" --ulsch-max-errors set the max ULSCH erros\n"); + printf(" --calib-ue-rx set UE RX calibration\n"); + printf(" --calib-ue-rx-med \n"); + printf(" --calib-ue-rxbyp\n"); + printf(" --debug-ue-prach run normal prach power ramping, but don't continue random-access\n"); + printf(" --calib-prach-tx run normal prach with maximum power, but don't continue random-access\n"); + printf(" --no-L2-connect bypass L2 and upper layers\n"); + printf(" --ue-rxgain set UE RX gain\n"); + printf(" --ue-rxgain-off external UE amplifier offset\n"); + printf(" --ue-txgain set UE TX gain\n"); + printf(" --ue-nb-ant-rx set UE number of rx antennas\n"); + printf(" --ue-scan-carrier set UE to scan around carrier\n"); + printf(" --dlsch-demod-shift dynamic shift for LLR compuation for TM3/4 (default 0)\n"); + printf(" --loop-memory get softmodem (UE) to loop through memory instead of acquiring from HW\n"); + printf(" --mmapped-dma sets flag for improved EXMIMO UE performance\n"); + printf(" --external-clock tells hardware to use an external clock reference\n"); + printf(" --usim-test use XOR autentication algo in case of test usim mode\n"); + printf(" --single-thread-disable. Disables single-thread mode in lte-softmodem\n"); + printf(" -A Set timing_advance\n"); + printf(" -C Set the downlink frequency for all component carriers\n"); + printf(" -d Enable soft scope and L1 and L2 stats (Xforms)\n"); + printf(" -F Calibrate the EXMIMO borad, available files: exmimo2_2arxg.lime exmimo2_2brxg.lime \n"); + printf(" -g Set the global log level, valide options: (9:trace, 8/7:debug, 6:info, 4:warn, 3:error)\n"); + printf(" -G Set the global log verbosity \n"); + printf(" -h provides this help message!\n"); + printf(" -K Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n"); + printf(" -m Set the maximum downlink MCS\n"); + printf(" -O eNB configuration file (located in targets/PROJECTS/GENERIC-LTE-EPC/CONF\n"); + printf(" -q Enable processing timing measurement of lte softmodem on per subframe basis \n"); + printf(" -r Set the PRB, valid values: 6, 25, 50, 100 \n"); + printf(" -S Skip the missed slots/subframes \n"); + printf(" -t Set the maximum uplink MCS\n"); + printf(" -T Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n"); + printf(" -U Set the lte softmodem as a UE\n"); + printf(" -W Enable L2 wireshark messages on localhost \n"); + printf(" -V Enable VCD (generated file will be located atopenair_dump_eNB.vcd, read it with target/RT/USER/eNB.gtkw\n"); + printf(" -x Set the transmission mode, valid options: 1 \n"); + printf(" -E Apply three-quarter of sampling frequency, 23.04 Msps to reduce the data rate on USB/PCIe transfers (only valid for 20 MHz)\n"); +#if T_TRACER + printf(" --T_port [port] use given port\n"); + printf(" --T_nowait don't wait for tracer, start immediately\n"); + printf(" --T_dont_fork to ease debugging with gdb\n"); +#endif + printf(RESET); + fflush(stdout); +} + +void exit_fun(const char* s) { + int CC_id; + + if (s != NULL) { + printf("%s %s() Exiting OAI softmodem: %s\n",__FILE__, __FUNCTION__, s); + } + + oai_exit = 1; + + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + if (UE_flag == 0) { + if (PHY_vars_eNB_g[0][CC_id]->rfdevice.trx_end_func) + PHY_vars_eNB_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_eNB_g[0][CC_id]->rfdevice); + if (PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_end_func) + PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_end_func(&PHY_vars_eNB_g[0][CC_id]->ifdevice); + } else { + if (PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func) + PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][CC_id]->rfdevice); + } + } + +#if defined(ENABLE_ITTI) + sleep(1); //allow lte-softmodem threads to exit first + itti_terminate_tasks (TASK_UNKNOWN); +#endif + +} + + +#ifdef XFORMS + +void reset_stats(FL_OBJECT *button, long arg) { + int i,j,k; + PHY_VARS_eNB *phy_vars_eNB = PHY_vars_eNB_g[0][0]; + + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + for (k=0; k<8; k++) { //harq_processes + for (j=0; j<phy_vars_eNB->dlsch[i][0]->Mlimit; j++) { + phy_vars_eNB->UE_stats[i].dlsch_NAK[k][j]=0; + phy_vars_eNB->UE_stats[i].dlsch_ACK[k][j]=0; + phy_vars_eNB->UE_stats[i].dlsch_trials[k][j]=0; + } + + phy_vars_eNB->UE_stats[i].dlsch_l2_errors[k]=0; + phy_vars_eNB->UE_stats[i].ulsch_errors[k]=0; + phy_vars_eNB->UE_stats[i].ulsch_consecutive_errors=0; + + for (j=0; j<phy_vars_eNB->ulsch[i]->Mlimit; j++) { + phy_vars_eNB->UE_stats[i].ulsch_decoding_attempts[k][j]=0; + phy_vars_eNB->UE_stats[i].ulsch_decoding_attempts_last[k][j]=0; + phy_vars_eNB->UE_stats[i].ulsch_round_errors[k][j]=0; + phy_vars_eNB->UE_stats[i].ulsch_round_fer[k][j]=0; + } + } + + phy_vars_eNB->UE_stats[i].dlsch_sliding_cnt=0; + phy_vars_eNB->UE_stats[i].dlsch_NAK_round0=0; + phy_vars_eNB->UE_stats[i].dlsch_mcs_offset=0; + } +} + +static void *scope_thread(void *arg) { + char stats_buffer[16384]; +# ifdef ENABLE_XFORMS_WRITE_STATS + FILE *UE_stats, *eNB_stats; +# endif + int len = 0; + struct sched_param sched_param; + int UE_id, CC_id; + int ue_cnt=0; + + sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; + sched_setscheduler(0, SCHED_FIFO,&sched_param); + + printf("Scope thread has priority %d\n",sched_param.sched_priority); + +# ifdef ENABLE_XFORMS_WRITE_STATS + + if (UE_flag==1) + UE_stats = fopen("UE_stats.txt", "w"); + else + eNB_stats = fopen("eNB_stats.txt", "w"); + +#endif + + while (!oai_exit) { + if (UE_flag==1) { + len = dump_ue_stats (PHY_vars_UE_g[0][0], &PHY_vars_UE_g[0][0]->proc.proc_rxtx[0],stats_buffer, 0, mode,rx_input_level_dBm); + //fl_set_object_label(form_stats->stats_text, stats_buffer); + fl_clear_browser(form_stats->stats_text); + fl_add_browser_line(form_stats->stats_text, stats_buffer); + + phy_scope_UE(form_ue[0], + PHY_vars_UE_g[0][0], + 0, + 0,7); + + } else { + if (PHY_vars_eNB_g[0][0]->mac_enabled==1) { + len = dump_eNB_l2_stats (stats_buffer, 0); + //fl_set_object_label(form_stats_l2->stats_text, stats_buffer); + fl_clear_browser(form_stats_l2->stats_text); + fl_add_browser_line(form_stats_l2->stats_text, stats_buffer); + } + len = dump_eNB_stats (PHY_vars_eNB_g[0][0], stats_buffer, 0); + + if (MAX_NUM_CCs>1) + len += dump_eNB_stats (PHY_vars_eNB_g[0][1], &stats_buffer[len], 0); + + //fl_set_object_label(form_stats->stats_text, stats_buffer); + fl_clear_browser(form_stats->stats_text); + fl_add_browser_line(form_stats->stats_text, stats_buffer); + + ue_cnt=0; + for(UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + // if ((PHY_vars_eNB_g[0][CC_id]->dlsch[UE_id][0]->rnti>0) && (ue_cnt<scope_enb_num_ue)) { + if ((ue_cnt<scope_enb_num_ue)) { + phy_scope_eNB(form_enb[CC_id][ue_cnt], + PHY_vars_eNB_g[0][CC_id], + UE_id); + ue_cnt++; + } + } + } + + } + + //printf("doing forms\n"); + //usleep(100000); // 100 ms + sleep(1); + } + + // printf("%s",stats_buffer); + +# ifdef ENABLE_XFORMS_WRITE_STATS + + if (UE_flag==1) { + if (UE_stats) { + rewind (UE_stats); + fwrite (stats_buffer, 1, len, UE_stats); + fclose (UE_stats); + } + } else { + if (eNB_stats) { + rewind (eNB_stats); + fwrite (stats_buffer, 1, len, eNB_stats); + fclose (eNB_stats); + } + } + +# endif + + pthread_exit((void*)arg); +} +#endif + + + + +#if defined(ENABLE_ITTI) +void *l2l1_task(void *arg) { + MessageDef *message_p = NULL; + int result; + + itti_set_task_real_time(TASK_L2L1); + itti_mark_task_ready(TASK_L2L1); + + if (UE_flag == 0) { + /* Wait for the initialize message */ + printf("Wait for the ITTI initialize message\n"); + do { + if (message_p != NULL) { + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } + + itti_receive_msg (TASK_L2L1, &message_p); + + switch (ITTI_MSG_ID(message_p)) { + case INITIALIZE_MESSAGE: + /* Start eNB thread */ + LOG_D(EMU, "L2L1 TASK received %s\n", ITTI_MSG_NAME(message_p)); + start_eNB = 1; + break; + + case TERMINATE_MESSAGE: + printf("received terminate message\n"); + oai_exit=1; + itti_exit_task (); + break; + + default: + LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); + break; + } + } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE); + + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } + + do { + // Wait for a message + itti_receive_msg (TASK_L2L1, &message_p); + + switch (ITTI_MSG_ID(message_p)) { + case TERMINATE_MESSAGE: + oai_exit=1; + itti_exit_task (); + break; + + case ACTIVATE_MESSAGE: + start_UE = 1; + break; + + case DEACTIVATE_MESSAGE: + start_UE = 0; + break; + + case MESSAGE_TEST: + LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p)); + break; + + default: + LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } while(!oai_exit); + + return NULL; +} +#endif + + + + +static void get_options (int argc, char **argv) { + int c; + // char line[1000]; + // int l; + int k,i;//,j,k; +#if defined(OAI_USRP) || defined(CPRIGW) + int clock_src; +#endif + int CC_id; + + + const Enb_properties_array_t *enb_properties; + + enum long_option_e { + LONG_OPTION_START = 0x100, /* Start after regular single char options */ + LONG_OPTION_RF_CONFIG_FILE, + LONG_OPTION_ULSCH_MAX_CONSECUTIVE_ERRORS, + LONG_OPTION_CALIB_UE_RX, + LONG_OPTION_CALIB_UE_RX_MED, + LONG_OPTION_CALIB_UE_RX_BYP, + LONG_OPTION_DEBUG_UE_PRACH, + LONG_OPTION_NO_L2_CONNECT, + LONG_OPTION_CALIB_PRACH_TX, + LONG_OPTION_RXGAIN, + LONG_OPTION_RXGAINOFF, + LONG_OPTION_TXGAIN, + LONG_OPTION_NBRXANT, + LONG_OPTION_NBTXANT, + LONG_OPTION_SCANCARRIER, + LONG_OPTION_MAXPOWER, + LONG_OPTION_DUMP_FRAME, + LONG_OPTION_LOOPMEMORY, + LONG_OPTION_PHYTEST, + LONG_OPTION_USIMTEST, + LONG_OPTION_MMAPPED_DMA, + LONG_OPTION_EXTERNAL_CLOCK, + LONG_OPTION_WAIT_FOR_SYNC, + LONG_OPTION_SINGLE_THREAD_DISABLE, + LONG_OPTION_THREADIQ, + LONG_OPTION_THREADODDSUBFRAME, + LONG_OPTION_THREADEVENSUBFRAME, + LONG_OPTION_DEMOD_SHIFT, +#if T_TRACER + LONG_OPTION_T_PORT, + LONG_OPTION_T_NOWAIT, + LONG_OPTION_T_DONT_FORK, +#endif + + }; + + static const struct option long_options[] = { + {"rf-config-file",required_argument, NULL, LONG_OPTION_RF_CONFIG_FILE}, + {"ulsch-max-errors",required_argument, NULL, LONG_OPTION_ULSCH_MAX_CONSECUTIVE_ERRORS}, + {"calib-ue-rx", required_argument, NULL, LONG_OPTION_CALIB_UE_RX}, + {"calib-ue-rx-med", required_argument, NULL, LONG_OPTION_CALIB_UE_RX_MED}, + {"calib-ue-rx-byp", required_argument, NULL, LONG_OPTION_CALIB_UE_RX_BYP}, + {"debug-ue-prach", no_argument, NULL, LONG_OPTION_DEBUG_UE_PRACH}, + {"no-L2-connect", no_argument, NULL, LONG_OPTION_NO_L2_CONNECT}, + {"calib-prach-tx", no_argument, NULL, LONG_OPTION_CALIB_PRACH_TX}, + {"ue-rxgain", required_argument, NULL, LONG_OPTION_RXGAIN}, + {"ue-rxgain-off", required_argument, NULL, LONG_OPTION_RXGAINOFF}, + {"ue-txgain", required_argument, NULL, LONG_OPTION_TXGAIN}, + {"ue-nb-ant-rx", required_argument, NULL, LONG_OPTION_NBRXANT}, + {"ue-nb-ant-tx", required_argument, NULL, LONG_OPTION_NBTXANT}, + {"ue-scan-carrier", no_argument, NULL, LONG_OPTION_SCANCARRIER}, + {"ue-max-power", required_argument, NULL, LONG_OPTION_MAXPOWER}, + {"ue-dump-frame", no_argument, NULL, LONG_OPTION_DUMP_FRAME}, + {"loop-memory", required_argument, NULL, LONG_OPTION_LOOPMEMORY}, + {"phy-test", no_argument, NULL, LONG_OPTION_PHYTEST}, + {"usim-test", no_argument, NULL, LONG_OPTION_USIMTEST}, + {"mmapped-dma", no_argument, NULL, LONG_OPTION_MMAPPED_DMA}, + {"external-clock", no_argument, NULL, LONG_OPTION_EXTERNAL_CLOCK}, + {"wait-for-sync", no_argument, NULL, LONG_OPTION_WAIT_FOR_SYNC}, + {"single-thread-disable", no_argument, NULL, LONG_OPTION_SINGLE_THREAD_DISABLE}, + {"threadIQ", required_argument, NULL, LONG_OPTION_THREADIQ}, + {"threadOddSubframe", required_argument, NULL, LONG_OPTION_THREADODDSUBFRAME}, + {"threadEvenSubframe", required_argument, NULL, LONG_OPTION_THREADEVENSUBFRAME}, + {"dlsch-demod-shift", required_argument, NULL, LONG_OPTION_DEMOD_SHIFT}, +#if T_TRACER + {"T_port", required_argument, 0, LONG_OPTION_T_PORT}, + {"T_nowait", no_argument, 0, LONG_OPTION_T_NOWAIT}, + {"T_dont_fork", no_argument, 0, LONG_OPTION_T_DONT_FORK}, +#endif + {NULL, 0, NULL, 0} + }; + + while ((c = getopt_long (argc, argv, "A:a:C:dEK:g:F:G:hqO:m:SUVRM:r:P:Ws:t:Tx:",long_options,NULL)) != -1) { + switch (c) { + case LONG_OPTION_RF_CONFIG_FILE: + if ((strcmp("null", optarg) == 0) || (strcmp("NULL", optarg) == 0)) { + printf("no configuration filename is provided\n"); + } + else if (strlen(optarg)<=1024){ + strcpy(rf_config_file,optarg); + }else { + printf("Configuration filename is too long\n"); + exit(-1); + } + break; + case LONG_OPTION_MAXPOWER: + tx_max_power[0]=atoi(optarg); + for (CC_id=1;CC_id<MAX_NUM_CCs;CC_id++) + tx_max_power[CC_id]=tx_max_power[0]; + break; + case LONG_OPTION_ULSCH_MAX_CONSECUTIVE_ERRORS: + ULSCH_max_consecutive_errors = atoi(optarg); + printf("Set ULSCH_max_consecutive_errors = %d\n",ULSCH_max_consecutive_errors); + break; + + case LONG_OPTION_CALIB_UE_RX: + mode = rx_calib_ue; + rx_input_level_dBm = atoi(optarg); + printf("Running with UE calibration on (LNA max), input level %d dBm\n",rx_input_level_dBm); + break; + + case LONG_OPTION_CALIB_UE_RX_MED: + mode = rx_calib_ue_med; + rx_input_level_dBm = atoi(optarg); + printf("Running with UE calibration on (LNA med), input level %d dBm\n",rx_input_level_dBm); + break; + + case LONG_OPTION_CALIB_UE_RX_BYP: + mode = rx_calib_ue_byp; + rx_input_level_dBm = atoi(optarg); + printf("Running with UE calibration on (LNA byp), input level %d dBm\n",rx_input_level_dBm); + break; + + case LONG_OPTION_DEBUG_UE_PRACH: + mode = debug_prach; + break; + + case LONG_OPTION_NO_L2_CONNECT: + mode = no_L2_connect; + break; + + case LONG_OPTION_CALIB_PRACH_TX: + mode = calib_prach_tx; + printf("Setting mode to calib_prach_tx (%d)\n",mode); + break; + + case LONG_OPTION_RXGAIN: + for (i=0; i<4; i++) + rx_gain[0][i] = atof(optarg); + + break; + + case LONG_OPTION_RXGAINOFF: + rx_gain_off = atof(optarg); + break; + + case LONG_OPTION_TXGAIN: + for (i=0; i<4; i++) + tx_gain[0][i] = atof(optarg); + + break; + case LONG_OPTION_NBRXANT: + nb_antenna_rx = atof(optarg); + break; + case LONG_OPTION_NBTXANT: + nb_antenna_tx = atof(optarg); + break; + case LONG_OPTION_SCANCARRIER: + UE_scan_carrier=1; + + break; + + case LONG_OPTION_LOOPMEMORY: + mode=loop_through_memory; + input_fd = fopen(optarg,"r"); + AssertFatal(input_fd != NULL,"Please provide an input file\n"); + break; + + case LONG_OPTION_DUMP_FRAME: + mode = rx_dump_frame; + break; + + case LONG_OPTION_PHYTEST: + phy_test = 1; + break; + + case LONG_OPTION_USIMTEST: + usim_test = 1; + break; + case LONG_OPTION_MMAPPED_DMA: + mmapped_dma = 1; + break; + + case LONG_OPTION_SINGLE_THREAD_DISABLE: + single_thread_flag = 0; + break; + + case LONG_OPTION_EXTERNAL_CLOCK: + clock_source = external; + break; + + case LONG_OPTION_WAIT_FOR_SYNC: + wait_for_sync = 1; + break; + + case LONG_OPTION_THREADIQ: + threads.iq=atoi(optarg); + break; + case LONG_OPTION_THREADODDSUBFRAME: + threads.odd=atoi(optarg); + break; + case LONG_OPTION_THREADEVENSUBFRAME: + threads.even=atoi(optarg); + break; + case LONG_OPTION_DEMOD_SHIFT: { + extern int16_t dlsch_demod_shift; + dlsch_demod_shift = atof(optarg); + break; + } +#if T_TRACER + case LONG_OPTION_T_PORT: { + extern int T_port; + if (optarg == NULL) abort(); /* should not happen */ + T_port = atoi(optarg); + break; + } + + case LONG_OPTION_T_NOWAIT: { + extern int T_wait; + T_wait = 0; + break; + } + + case LONG_OPTION_T_DONT_FORK: { + extern int T_dont_fork; + T_dont_fork = 1; + break; + } +#endif + + case 'A': + timing_advance = atoi (optarg); + break; + + case 'C': + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + downlink_frequency[CC_id][0] = atof(optarg); // 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]); + } + + UE_scan=0; + + break; + + case 'a': + chain_offset = atoi(optarg); + break; + + case 'd': +#ifdef XFORMS + do_forms=1; + printf("Running with XFORMS!\n"); +#endif + break; + + case 'E': + threequarter_fs=1; + break; + + case 'K': +#if defined(ENABLE_ITTI) + itti_dump_file = strdup(optarg); +#else + printf("-K option is disabled when ENABLE_ITTI is not defined\n"); +#endif + break; + + case 'O': + conf_config_file_name = optarg; + break; + + case 'U': + UE_flag = 1; + break; + + case 'm': + target_dl_mcs = atoi (optarg); + break; + + case 't': + target_ul_mcs = atoi (optarg); + break; + + case 'W': + opt_enabled=1; + opt_type = OPT_WIRESHARK; + strncpy(in_ip, "127.0.0.1", sizeof(in_ip)); + in_ip[sizeof(in_ip) - 1] = 0; // terminate string + printf("Enabling OPT for wireshark for local interface"); + /* + if (optarg == NULL){ + in_ip[0] =NULL; + printf("Enabling OPT for wireshark for local interface"); + } else { + strncpy(in_ip, optarg, sizeof(in_ip)); + in_ip[sizeof(in_ip) - 1] = 0; // terminate string + printf("Enabling OPT for wireshark with %s \n",in_ip); + } + */ + break; + + case 'P': + opt_type = OPT_PCAP; + opt_enabled=1; + + if (optarg == NULL) { + strncpy(in_path, "/tmp/oai_opt.pcap", sizeof(in_path)); + in_path[sizeof(in_path) - 1] = 0; // terminate string + printf("Enabling OPT for PCAP with the following path /tmp/oai_opt.pcap"); + } else { + strncpy(in_path, optarg, sizeof(in_path)); + in_path[sizeof(in_path) - 1] = 0; // terminate string + printf("Enabling OPT for PCAP with the following file %s \n",in_path); + } + + break; + + case 'V': + ouput_vcd = 1; + break; + + case 'q': + opp_enabled = 1; + break; + + case 'R' : + online_log_messages =1; + break; + + case 'r': + UE_scan = 0; +///////////////////////////////////////////////////////////////// frame_parms for NB-IoT are added for test + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + switch(atoi(optarg)) { + case 6: + frame_parms[CC_id]->N_RB_DL=6; + frame_parms[CC_id]->N_RB_UL=6; + frame_parms_NB_IoT[CC_id]->N_RB_DL=6; + frame_parms_NB_IoT[CC_id]->N_RB_UL=6; + break; + + case 25: + frame_parms[CC_id]->N_RB_DL=25; + frame_parms[CC_id]->N_RB_UL=25; + frame_parms_NB_IoT[CC_id]->N_RB_DL=25; + frame_parms_NB_IoT[CC_id]->N_RB_UL=25; + break; + + case 50: + frame_parms[CC_id]->N_RB_DL=50; + frame_parms[CC_id]->N_RB_UL=50; + frame_parms_NB_IoT[CC_id]->N_RB_DL=50; + frame_parms_NB_IoT[CC_id]->N_RB_UL=50; + break; + + case 100: + frame_parms[CC_id]->N_RB_DL=100; + frame_parms[CC_id]->N_RB_UL=100; + frame_parms_NB_IoT[CC_id]->N_RB_DL=100; + frame_parms_NB_IoT[CC_id]->N_RB_UL=100; + break; + + default: + printf("Unknown N_RB_DL %d, switching to 25\n",atoi(optarg)); + break; + } + } + + break; + + case 's': +#if defined(OAI_USRP) || defined(CPRIGW) + + clock_src = atoi(optarg); + + if (clock_src == 0) { + // char ref[128] = "internal"; + //strncpy(uhd_ref, ref, strlen(ref)+1); + } else if (clock_src == 1) { + //char ref[128] = "external"; + //strncpy(uhd_ref, ref, strlen(ref)+1); + } + +#else + printf("Note: -s not defined for ExpressMIMO2\n"); +#endif + break; + + case 'S': + exit_missed_slots=0; + printf("Skip exit for missed slots\n"); + break; + + case 'g': + glog_level=atoi(optarg); // value between 1 - 9 + break; + + case 'F': + break; + + case 'G': + glog_verbosity=atoi(optarg);// value from 0, 0x5, 0x15, 0x35, 0x75 + break; + + case 'x': + printf("Transmission mode should be set in config file now\n"); + exit(-1); + /* + transmission_mode = atoi(optarg); + + if (transmission_mode > 7) { + printf("Transmission mode %d not supported for the moment\n",transmission_mode); + exit(-1); + } + */ + break; + + case 'T': + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) + frame_parms[CC_id]->frame_type = TDD; + break; + + case 'h': + help (); + exit (-1); + + default: + help (); + exit (-1); + break; + } + } + + if (UE_flag == 0) + AssertFatal(conf_config_file_name != NULL,"Please provide a configuration file\n"); + + if ((UE_flag == 0) && (conf_config_file_name != NULL)) { + int i,j; + + NB_eNB_INST = 1; + + /* Read eNB configuration file */ + // enb_properties = enb_config_init(conf_config_file_name); + + enb_properties = enb_config_init(conf_config_file_name); + + AssertFatal (NB_eNB_INST <= enb_properties->number, + "Number of eNB is greater than eNB defined in configuration file %s (%d/%d)!", + conf_config_file_name, NB_eNB_INST, enb_properties->number); + + /* Update some simulation parameters */ + for (i=0; i < enb_properties->number; i++) { + AssertFatal (MAX_NUM_CCs == enb_properties->properties[i]->nb_cc, + "lte-softmodem compiled with MAX_NUM_CCs=%d, but only %d CCs configured for eNB %d!", + MAX_NUM_CCs, enb_properties->properties[i]->nb_cc, i); + eth_params = (eth_params_t*)malloc(enb_properties->properties[i]->nb_rrh_gw * sizeof(eth_params_t)); + memset(eth_params, 0, enb_properties->properties[i]->nb_rrh_gw * sizeof(eth_params_t)); + + for (j=0; j<enb_properties->properties[i]->nb_rrh_gw; j++) { + + if (enb_properties->properties[i]->rrh_gw_config[j].active == 1 ) { + local_remote_radio = BBU_REMOTE_RADIO_HEAD; + (eth_params+j)->local_if_name = enb_properties->properties[i]->rrh_gw_config[j].rrh_gw_if_name; + (eth_params+j)->my_addr = enb_properties->properties[i]->rrh_gw_config[j].local_address; + (eth_params+j)->my_port = enb_properties->properties[i]->rrh_gw_config[j].local_port; + (eth_params+j)->remote_addr = enb_properties->properties[i]->rrh_gw_config[j].remote_address; + (eth_params+j)->remote_port = enb_properties->properties[i]->rrh_gw_config[j].remote_port; + + if (enb_properties->properties[i]->rrh_gw_config[j].raw == 1) { + (eth_params+j)->transp_preference = ETH_RAW_MODE; + } else if (enb_properties->properties[i]->rrh_gw_config[j].rawif4p5 == 1) { + (eth_params+j)->transp_preference = ETH_RAW_IF4p5_MODE; + } else if (enb_properties->properties[i]->rrh_gw_config[j].udpif4p5 == 1) { + (eth_params+j)->transp_preference = ETH_UDP_IF4p5_MODE; + } else if (enb_properties->properties[i]->rrh_gw_config[j].rawif5_mobipass == 1) { + (eth_params+j)->transp_preference = ETH_RAW_IF5_MOBIPASS; + } else { + (eth_params+j)->transp_preference = ETH_UDP_MODE; + } + + (eth_params+j)->iq_txshift = enb_properties->properties[i]->rrh_gw_config[j].iq_txshift; + (eth_params+j)->tx_sample_advance = enb_properties->properties[i]->rrh_gw_config[j].tx_sample_advance; + (eth_params+j)->tx_scheduling_advance = enb_properties->properties[i]->rrh_gw_config[j].tx_scheduling_advance; + if (enb_properties->properties[i]->rrh_gw_config[j].exmimo == 1) { + (eth_params+j)->rf_preference = EXMIMO_DEV; + } else if (enb_properties->properties[i]->rrh_gw_config[j].usrp_b200 == 1) { + (eth_params+j)->rf_preference = USRP_B200_DEV; + } else if (enb_properties->properties[i]->rrh_gw_config[j].usrp_x300 == 1) { + (eth_params+j)->rf_preference = USRP_X300_DEV; + } else if (enb_properties->properties[i]->rrh_gw_config[j].bladerf == 1) { + (eth_params+j)->rf_preference = BLADERF_DEV; + } else if (enb_properties->properties[i]->rrh_gw_config[j].lmssdr == 1) { + //(eth_params+j)->rf_preference = LMSSDR_DEV; + } else { + (eth_params+j)->rf_preference = 0; + } + (eth_params+j)->if_compress = enb_properties->properties[i]->rrh_gw_config[j].if_compress; + } else { + local_remote_radio = BBU_LOCAL_RADIO_HEAD; + } + + } + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + + + node_function[CC_id] = enb_properties->properties[i]->cc_node_function[CC_id]; + node_timing[CC_id] = enb_properties->properties[i]->cc_node_timing[CC_id]; + + node_function_NB_IoT[CC_id] = enb_properties->properties[i]->cc_node_function[CC_id]; + node_timing_NB_IoT[CC_id] = enb_properties->properties[i]->cc_node_timing[CC_id]; + + node_synch_ref[CC_id] = enb_properties->properties[i]->cc_node_synch_ref[CC_id]; + + frame_parms[CC_id]->frame_type = enb_properties->properties[i]->frame_type[CC_id]; + frame_parms[CC_id]->tdd_config = enb_properties->properties[i]->tdd_config[CC_id]; + frame_parms[CC_id]->tdd_config_S = enb_properties->properties[i]->tdd_config_s[CC_id]; + frame_parms[CC_id]->Ncp = enb_properties->properties[i]->prefix_type[CC_id]; + + frame_parms_NB_IoT[CC_id]->frame_type = enb_properties->properties[i]->frame_type[CC_id]; + frame_parms_NB_IoT[CC_id]->tdd_config = enb_properties->properties[i]->tdd_config[CC_id]; + frame_parms_NB_IoT[CC_id]->Ncp = enb_properties->properties[i]->prefix_type[CC_id]; + + //for (j=0; j < enb_properties->properties[i]->nb_cc; j++ ){ + frame_parms[CC_id]->Nid_cell = enb_properties->properties[i]->Nid_cell[CC_id]; + frame_parms[CC_id]->N_RB_DL = enb_properties->properties[i]->N_RB_DL[CC_id]; + frame_parms[CC_id]->N_RB_UL = enb_properties->properties[i]->N_RB_DL[CC_id]; + frame_parms[CC_id]->nb_antennas_tx = enb_properties->properties[i]->nb_antennas_tx[CC_id]; + frame_parms[CC_id]->nb_antenna_ports_eNB = enb_properties->properties[i]->nb_antenna_ports[CC_id]; + frame_parms[CC_id]->nb_antennas_rx = enb_properties->properties[i]->nb_antennas_rx[CC_id]; + + frame_parms_NB_IoT[CC_id]->Nid_cell = enb_properties->properties[i]->Nid_cell[CC_id]; // in case different CellID this value can be modified + frame_parms_NB_IoT[CC_id]->N_RB_DL = enb_properties->properties[i]->N_RB_DL[CC_id]; + frame_parms_NB_IoT[CC_id]->N_RB_UL = enb_properties->properties[i]->N_RB_DL[CC_id]; + frame_parms_NB_IoT[CC_id]->nb_antennas_tx = enb_properties->properties[i]->nb_antennas_tx[CC_id]; + frame_parms_NB_IoT[CC_id]->nb_antenna_ports_eNB = enb_properties->properties[i]->nb_antenna_ports[CC_id]; + frame_parms_NB_IoT[CC_id]->nb_antennas_rx = enb_properties->properties[i]->nb_antennas_rx[CC_id]; + + + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex = enb_properties->properties[i]->prach_config_index[CC_id]; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset = enb_properties->properties[i]->prach_freq_offset[CC_id]; + + frame_parms[CC_id]->mode1_flag = (frame_parms[CC_id]->nb_antenna_ports_eNB == 1) ? 1 : 0; + frame_parms[CC_id]->threequarter_fs = threequarter_fs; + + frame_parms_NB_IoT[CC_id]->threequarter_fs = threequarter_fs; + + + + frame_parms[CC_id]->nb_antennas_tx_NB_IoT = enb_properties->properties[i]->nb_antennas_tx[CC_id]; + frame_parms[CC_id]->control_region_size = 2; + //} // j + } + + + init_all_otg(0); + g_otg->seed = 0; + init_seeds(g_otg->seed); + + for (k=0; k<enb_properties->properties[i]->num_otg_elements; k++) { + j=enb_properties->properties[i]->otg_ue_id[k]; // ue_id + g_otg->application_idx[i][j] = 1; + //g_otg->packet_gen_type=SUBSTRACT_STRING; + g_otg->background[i][j][0] =enb_properties->properties[i]->otg_bg_traffic[k]; + g_otg->application_type[i][j][0] =enb_properties->properties[i]->otg_app_type[k];// BCBR; //MCBR, BCBR + + printf("[OTG] configuring traffic type %d for eNB %d UE %d (Background traffic is %s)\n", + g_otg->application_type[i][j][0], i, j,(g_otg->background[i][j][0]==1)?"Enabled":"Disabled"); + } + + init_predef_traffic(enb_properties->properties[i]->num_otg_elements, 1); + + + glog_level = enb_properties->properties[i]->glog_level; + glog_verbosity = enb_properties->properties[i]->glog_verbosity; + hw_log_level = enb_properties->properties[i]->hw_log_level; + hw_log_verbosity = enb_properties->properties[i]->hw_log_verbosity ; + phy_log_level = enb_properties->properties[i]->phy_log_level; + phy_log_verbosity = enb_properties->properties[i]->phy_log_verbosity; + mac_log_level = enb_properties->properties[i]->mac_log_level; + mac_log_verbosity = enb_properties->properties[i]->mac_log_verbosity; + rlc_log_level = enb_properties->properties[i]->rlc_log_level; + rlc_log_verbosity = enb_properties->properties[i]->rlc_log_verbosity; + pdcp_log_level = enb_properties->properties[i]->pdcp_log_level; + pdcp_log_verbosity = enb_properties->properties[i]->pdcp_log_verbosity; + rrc_log_level = enb_properties->properties[i]->rrc_log_level; + rrc_log_verbosity = enb_properties->properties[i]->rrc_log_verbosity; +# if defined(ENABLE_USE_MME) + gtpu_log_level = enb_properties->properties[i]->gtpu_log_level; + gtpu_log_verbosity = enb_properties->properties[i]->gtpu_log_verbosity; + udp_log_level = enb_properties->properties[i]->udp_log_level; + udp_log_verbosity = enb_properties->properties[i]->udp_log_verbosity; +#endif +#if defined (ENABLE_SECURITY) + osa_log_level = enb_properties->properties[i]->osa_log_level; + osa_log_verbosity = enb_properties->properties[i]->osa_log_verbosity; +#endif + + // adjust the log + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + for (k = 0 ; k < 4; k++) { + downlink_frequency[CC_id][k] = enb_properties->properties[i]->downlink_frequency[CC_id]; + uplink_frequency_offset[CC_id][k] = enb_properties->properties[i]->uplink_frequency_offset[CC_id]; + rx_gain[CC_id][k] = (double)enb_properties->properties[i]->rx_gain[CC_id]; + tx_gain[CC_id][k] = (double)enb_properties->properties[i]->tx_gain[CC_id]; + } + + printf("Downlink frequency/ uplink offset of CC_id %d set to %ju/%d\n", CC_id, + enb_properties->properties[i]->downlink_frequency[CC_id], + enb_properties->properties[i]->uplink_frequency_offset[CC_id]); + + } // CC_id + }// i + + //this is needed for phy-test option + transmission_mode = enb_properties->properties[0]->ue_TransmissionMode[0]+1; + + } else if (UE_flag == 1) { + if (conf_config_file_name != NULL) { + + // Here the configuration file is the XER encoded UE capabilities + // Read it in and store in asn1c data structures + strcpy(uecap_xer,conf_config_file_name); + uecap_xer_in=1; + } + } +} + +#if T_TRACER +int T_wait = 1; /* by default we wait for the tracer */ +int T_port = 2021; /* default port to listen to to wait for the tracer */ +int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */ +#endif + +void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); +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]->subcarrier_spacing = 1; + + 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; + + frame_parms[CC_id]->nb_antennas_tx_NB_IoT = 1; + frame_parms[CC_id]->control_region_size = 2; + + 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]); + + } + +} + +//NB_IoT------------------------------------------------- +void set_default_frame_parms_NB_IoT(NB_IoT_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); +void set_default_frame_parms_NB_IoT(NB_IoT_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] = (NB_IoT_DL_FRAME_PARMS*) malloc(sizeof(NB_IoT_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]->N_RB_DL = 100; + frame_parms[CC_id]->N_RB_UL = 100; + //XXX check if there are other parameters to be set + frame_parms[CC_id]->Ncp = NORMAL; + frame_parms[CC_id]->Ncp_UL = NORMAL; + frame_parms[CC_id]->Nid_cell = 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; + // UL RS Config + frame_parms[CC_id]->npusch_config_common.ul_ReferenceSignalsNPUSCH.groupHoppingEnabled = 0; + frame_parms[CC_id]->npusch_config_common.ul_ReferenceSignalsNPUSCH.groupAssignmentNPUSCH = 0; + + + //frame_parms[CC_id]->nprach_config_common.nprach_CP_Length + //frame_parms[CC_id]->nprach_config_common.nprach_ParametersList.list.array[CC_id] + //frame_parms[CC_id]->nprach_config_common.rsrp_ThresholdsPrachInfoList + 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]; + + //already initialized in the set_default_frame_parms function for LTE + +// 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]); + + } + +} + + + + +void init_openair0(void); + +void init_openair0() { + + int card; + int i; + + for (card=0; card<MAX_CARDS; card++) { + + openair0_cfg[card].mmapped_dma=mmapped_dma; + openair0_cfg[card].configFilename = NULL; + + if(frame_parms[0]->N_RB_DL == 100) { + if (frame_parms[0]->threequarter_fs) { + openair0_cfg[card].sample_rate=23.04e6; + openair0_cfg[card].samples_per_frame = 230400; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } else { + openair0_cfg[card].sample_rate=30.72e6; + openair0_cfg[card].samples_per_frame = 307200; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } + } else if(frame_parms[0]->N_RB_DL == 50) { + openair0_cfg[card].sample_rate=15.36e6; + openair0_cfg[card].samples_per_frame = 153600; + openair0_cfg[card].tx_bw = 5e6; + openair0_cfg[card].rx_bw = 5e6; + } else if (frame_parms[0]->N_RB_DL == 25) { + openair0_cfg[card].sample_rate=7.68e6; + openair0_cfg[card].samples_per_frame = 76800; + openair0_cfg[card].tx_bw = 2.5e6; + openair0_cfg[card].rx_bw = 2.5e6; + } else if (frame_parms[0]->N_RB_DL == 6) { + openair0_cfg[card].sample_rate=1.92e6; + openair0_cfg[card].samples_per_frame = 19200; + openair0_cfg[card].tx_bw = 1.5e6; + openair0_cfg[card].rx_bw = 1.5e6; + } + + + + + if (frame_parms[0]->frame_type==TDD) + openair0_cfg[card].duplex_mode = duplex_mode_TDD; + else //FDD + openair0_cfg[card].duplex_mode = duplex_mode_FDD; + + + if (local_remote_radio == BBU_REMOTE_RADIO_HEAD) { + openair0_cfg[card].remote_addr = (eth_params+card)->remote_addr; + openair0_cfg[card].remote_port = (eth_params+card)->remote_port; + openair0_cfg[card].my_addr = (eth_params+card)->my_addr; + openair0_cfg[card].my_port = (eth_params+card)->my_port; + } + + printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card, + ((UE_flag==0) ? PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_tx), + ((UE_flag==0) ? PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_rx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx)); + openair0_cfg[card].Mod_id = 0; + + if (UE_flag) { + printf("ETHERNET: Configuring UE ETH for %s:%d\n",rrh_UE_ip,rrh_UE_port); + openair0_cfg[card].remote_addr = &rrh_UE_ip[0]; + openair0_cfg[card].remote_port = rrh_UE_port; + } + + openair0_cfg[card].num_rb_dl=frame_parms[0]->N_RB_DL; + + openair0_cfg[card].clock_source = clock_source; + + openair0_cfg[card].tx_num_channels=min(2,((UE_flag==0) ? PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_tx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx)); + openair0_cfg[card].rx_num_channels=min(2,((UE_flag==0) ? PHY_vars_eNB_g[0][0]->frame_parms.nb_antennas_rx : PHY_vars_UE_g[0][0]->frame_parms.nb_antennas_rx)); + + for (i=0; i<4; i++) { + + if (i<openair0_cfg[card].tx_num_channels) + openair0_cfg[card].tx_freq[i] = (UE_flag==0) ? downlink_frequency[0][i] : downlink_frequency[0][i]+uplink_frequency_offset[0][i]; + else + openair0_cfg[card].tx_freq[i]=0.0; + + if (i<openair0_cfg[card].rx_num_channels) + openair0_cfg[card].rx_freq[i] = (UE_flag==0) ? downlink_frequency[0][i] + uplink_frequency_offset[0][i] : downlink_frequency[0][i]; + else + openair0_cfg[card].rx_freq[i]=0.0; + + openair0_cfg[card].autocal[i] = 1; + openair0_cfg[card].tx_gain[i] = tx_gain[0][i]; + if (UE_flag == 0) { + openair0_cfg[card].rx_gain[i] = PHY_vars_eNB_g[0][0]->rx_total_gain_dB; + } + else { + openair0_cfg[card].rx_gain[i] = PHY_vars_UE_g[0][0]->rx_total_gain_dB - rx_gain_off; + } + + openair0_cfg[card].configFilename = rf_config_file; + printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", + card,i, openair0_cfg[card].tx_gain[i], + openair0_cfg[card].rx_gain[i], + openair0_cfg[card].tx_freq[i], + openair0_cfg[card].rx_freq[i]); + } + } +} + +int main( int argc, char **argv ) { + int i,j,k,aa,re; +#if defined (XFORMS) + void *status; +#endif + + int CC_id; + uint8_t abstraction_flag=0; + uint8_t beta_ACK=0,beta_RI=0,beta_CQI=2; + +#if defined (XFORMS) + int ret; +#endif + + start_background_system(); + +#ifdef DEBUG_CONSOLE + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + + PHY_VARS_UE *UE[MAX_NUM_CCs]; + + mode = normal_txrx; + memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS); + + memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs); + + set_latency_target(); + + // set default parameters + set_default_frame_parms(frame_parms); + + set_default_frame_parms_NB_IoT(frame_parms_NB_IoT); + + + + // initialize logging + logInit(); + + // get options and fill parameters from configuration file + get_options (argc, argv); //Command-line options, enb_properties + + + + + +#if T_TRACER + T_init(T_port, T_wait, T_dont_fork); +#endif + + // initialize the log (see log.h for details) + set_glog(glog_level, glog_verbosity); + + //randominit (0); + set_taus_seed (0); + + if (UE_flag==1) { + printf("configuring for UE\n"); + + set_comp_log(HW, LOG_DEBUG, LOG_HIGH, 1); + set_comp_log(PHY, LOG_DEBUG, LOG_HIGH, 1); + set_comp_log(MAC, LOG_INFO, LOG_HIGH, 1); + set_comp_log(RLC, LOG_INFO, LOG_HIGH | FLAG_THREAD, 1); + set_comp_log(PDCP, LOG_INFO, LOG_HIGH, 1); + set_comp_log(OTG, LOG_INFO, LOG_HIGH, 1); + set_comp_log(RRC, LOG_INFO, LOG_HIGH, 1); +#if defined(ENABLE_ITTI) + set_comp_log(EMU, LOG_INFO, LOG_MED, 1); +# if defined(ENABLE_USE_MME) + set_comp_log(NAS, LOG_INFO, LOG_HIGH, 1); +# endif +#endif + } else { + printf("configuring for eNB\n"); + + set_comp_log(HW, hw_log_level, hw_log_verbosity, 1); + set_comp_log(PHY, phy_log_level, phy_log_verbosity, 1); + if (opt_enabled == 1 ) + set_comp_log(OPT, opt_log_level, opt_log_verbosity, 1); + set_comp_log(MAC, mac_log_level, mac_log_verbosity, 1); + set_comp_log(RLC, rlc_log_level, rlc_log_verbosity, 1); + set_comp_log(PDCP, pdcp_log_level, pdcp_log_verbosity, 1); + set_comp_log(RRC, rrc_log_level, rrc_log_verbosity, 1); +#if defined(ENABLE_ITTI) + set_comp_log(EMU, LOG_INFO, LOG_MED, 1); +# if defined(ENABLE_USE_MME) + set_comp_log(UDP_, udp_log_level, udp_log_verbosity, 1); + set_comp_log(GTPU, gtpu_log_level, gtpu_log_verbosity, 1); + set_comp_log(S1AP, LOG_DEBUG, LOG_HIGH, 1); + set_comp_log(SCTP, LOG_INFO, LOG_HIGH, 1); +# endif +#if defined(ENABLE_SECURITY) + set_comp_log(OSA, osa_log_level, osa_log_verbosity, 1); +#endif +#endif +#ifdef LOCALIZATION + set_comp_log(LOCALIZE, LOG_DEBUG, LOG_LOW, 1); + set_component_filelog(LOCALIZE); +#endif + set_comp_log(ENB_APP, LOG_INFO, LOG_HIGH, 1); + set_comp_log(OTG, LOG_INFO, LOG_HIGH, 1); + + if (online_log_messages == 1) { + set_component_filelog(RRC); + set_component_filelog(PDCP); + } + } + + if (ouput_vcd) { + if (UE_flag==1) + VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_UE.vcd"); + else + VCD_SIGNAL_DUMPER_INIT("/tmp/openair_dump_eNB.vcd"); + } + + if (opp_enabled ==1) { + reset_opp_meas(); + } + cpuf=get_cpu_freq_GHz(); + +#if defined(ENABLE_ITTI) + + if (UE_flag == 1) { + log_set_instance_type (LOG_INSTANCE_UE); + } else { + log_set_instance_type (LOG_INSTANCE_ENB); + } + + itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info, messages_definition_xml, itti_dump_file); + + // initialize mscgen log after ITTI + MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); +#endif + + if (opt_type != OPT_NONE) { + radio_type_t radio_type; + + if (frame_parms[0]->frame_type == FDD) + radio_type = RADIO_TYPE_FDD; + else + radio_type = RADIO_TYPE_TDD; + + if (init_opt(in_path, in_ip, NULL, radio_type) == -1) + LOG_E(OPT,"failed to run OPT \n"); + } + +#ifdef PDCP_USE_NETLINK + netlink_init(); +#if defined(PDCP_USE_NETLINK_QUEUES) + pdcp_netlink_init(); +#endif +#endif + +#if !defined(ENABLE_ITTI) + // to make a graceful exit when ctrl-c is pressed + signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); +#endif + + + check_clock(); + +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" +#endif + + LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); + + // init the parameters + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + + if (UE_flag==1) { + frame_parms[CC_id]->nb_antennas_tx = nb_antenna_tx; + frame_parms[CC_id]->nb_antennas_rx = nb_antenna_rx; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; //initial value overwritten by initial sync later + + LOG_I(PHY,"Set nb_rx_antenna %d , nb_tx_antenna %d \n",frame_parms[CC_id]->nb_antennas_rx, frame_parms[CC_id]->nb_antennas_tx); + +//#ifdef NB_IOT /////////////// for NB-IoT testing /////////////////////////// + frame_parms_NB_IoT[CC_id]->nb_antennas_tx = nb_antenna_tx; + frame_parms_NB_IoT[CC_id]->nb_antennas_rx = nb_antenna_rx; + frame_parms_NB_IoT[CC_id]->nb_antenna_ports_eNB = 1; //initial value overwritten by initial sync later + + LOG_I(PHY,"[NB-IoT] Set nb_rx_antenna %d , nb_tx_antenna %d \n",frame_parms_NB_IoT[CC_id]->nb_antennas_rx, frame_parms_NB_IoT[CC_id]->nb_antennas_tx); + +//#endif //////////////////////////// END ////////////////////////////////// + } + + + //XXXX we need to modify it for NB-IoT???? + init_ul_hopping(frame_parms[CC_id]); + init_frame_parms(frame_parms[CC_id],1); + // phy_init_top(frame_parms[CC_id]); + phy_init_lte_top(frame_parms[CC_id]); + + + // for testing + //XXXX we need to modify it for NB-IoT???? + //init_ul_hopping(frame_parms[CC_id]); + + /////////////////////////////////////////////////////// NB-IoT //////////////////////////////////////////////////////// + init_frame_parms_NB_IoT(frame_parms_NB_IoT[CC_id],1); + // phy_init_top(frame_parms[CC_id]); + phy_init_lte_top_NB_IoT(frame_parms_NB_IoT[CC_id]); + /////////////////////////////////////////////////////// END ////////////////////////////////////////////////////////// + + } + + + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + //init prach for openair1 test + + // prach_fmt = get_prach_fmt(frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex, frame_parms->frame_type); + // N_ZC = (prach_fmt <4)?839:139; + } + + if (UE_flag==1) { + NB_UE_INST=1; + NB_INST=1; + + PHY_vars_UE_g = malloc(sizeof(PHY_VARS_UE**)); + PHY_vars_UE_g[0] = malloc(sizeof(PHY_VARS_UE*)*MAX_NUM_CCs); + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + + PHY_vars_UE_g[0][CC_id] = init_lte_UE(frame_parms[CC_id], 0,abstraction_flag); + UE[CC_id] = PHY_vars_UE_g[0][CC_id]; + printf("PHY_vars_UE_g[0][%d] = %p\n",CC_id,UE[CC_id]); + + if (phy_test==1) + UE[CC_id]->mac_enabled = 0; + else + UE[CC_id]->mac_enabled = 1; + + if (UE[CC_id]->mac_enabled == 0) { //set default UL parameters for testing mode + for (i=0; i<NUMBER_OF_CONNECTED_eNB_MAX; i++) { + UE[CC_id]->pusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; + UE[CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; + UE[CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; + + UE[CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = 0; + UE[CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(0%3); + UE[CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4; + } + } + + UE[CC_id]->UE_scan = UE_scan; + UE[CC_id]->UE_scan_carrier = UE_scan_carrier; + UE[CC_id]->mode = mode; + printf("UE[%d]->mode = %d\n",CC_id,mode); + + compute_prach_seq(&UE[CC_id]->frame_parms.prach_config_common, + UE[CC_id]->frame_parms.frame_type, + UE[CC_id]->X_u); + + if (UE[CC_id]->mac_enabled == 1) + { + UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1234; + UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1234; + } + else + { + UE[CC_id]->pdcch_vars[0][0]->crnti = 0x1235; + UE[CC_id]->pdcch_vars[1][0]->crnti = 0x1235; + } + + UE[CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0] + rx_gain_off; + UE[CC_id]->tx_power_max_dBm = tx_max_power[CC_id]; + + if (frame_parms[CC_id]->frame_type==FDD) { + UE[CC_id]->N_TA_offset = 0; + } else { + if (frame_parms[CC_id]->N_RB_DL == 100) + UE[CC_id]->N_TA_offset = 624; + else if (frame_parms[CC_id]->N_RB_DL == 50) + UE[CC_id]->N_TA_offset = 624/2; + else if (frame_parms[CC_id]->N_RB_DL == 25) + UE[CC_id]->N_TA_offset = 624/4; + } + + } + + // printf("tx_max_power = %d -> amp %d\n",tx_max_power,get_tx_amp(tx_max_poHwer,tx_max_power)); + } else { + /////////////////////////////////////////////////// this is eNB ///////////////////////////////////////////////////////////// + PHY_vars_eNB_g = malloc(sizeof(PHY_VARS_eNB**)); //global PHY_vars --> is a matrix + PHY_vars_eNB_g[0] = malloc(sizeof(PHY_VARS_eNB*)); + + ///////////////////////// for NB-IoT testing //////////////////////// + PHY_vars_eNB_NB_IoT_g = malloc(sizeof(PHY_VARS_eNB_NB_IoT**)); //global PHY_vars --> is a matrix + PHY_vars_eNB_NB_IoT_g[0] = malloc(sizeof(PHY_VARS_eNB_NB_IoT*)); + ///////////////////////////// END ////////////////////////////////// + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + //we initialiaze DL/UL buffer and HARQ (inside the LTE_eNB_DLSCH) + + PHY_vars_eNB_g[0][CC_id] = init_lte_eNB(frame_parms[CC_id],0,frame_parms[CC_id]->Nid_cell,node_function[CC_id],abstraction_flag); + + // for NB-IoT testing + PHY_vars_eNB_NB_IoT_g[0][CC_id] = init_lte_eNB_NB_IoT(frame_parms_NB_IoT[CC_id],0,frame_parms_NB_IoT[CC_id]->Nid_cell,node_function_NB_IoT[CC_id],abstraction_flag); + + //this is a complementary function for just initialize manage NB_ioT stuff inside the PHY_Vars +#ifdef NB_IOT + //init_lte_eNB_NB(PHY_vars_eNB_g[0][CC_id],frame_parms_NB_IoT[CC_id], 0, frame_parms_NB_IoT[CC_id]->Nid_cell,node_function[CC_id],abstraction_flag); +#endif + + PHY_vars_eNB_g[0][CC_id]->ue_dl_rb_alloc=0x1fff; + PHY_vars_eNB_g[0][CC_id]->target_ue_dl_mcs=target_dl_mcs; + PHY_vars_eNB_g[0][CC_id]->ue_ul_nb_rb=6; + PHY_vars_eNB_g[0][CC_id]->target_ue_ul_mcs=target_ul_mcs; + // initialization for phy-test + for (k=0; k<NUMBER_OF_UE_MAX; k++) { + PHY_vars_eNB_g[0][CC_id]->transmission_mode[k] = transmission_mode; + if (transmission_mode==7) + lte_gold_ue_spec_port5(PHY_vars_eNB_g[0][CC_id]->lte_gold_uespec_port5_table[k],frame_parms[CC_id]->Nid_cell,0x1235+k); + } + if ((transmission_mode==1) || (transmission_mode==7)) { + for (j=0; j<frame_parms[CC_id]->nb_antennas_tx; j++) + for (re=0; re<frame_parms[CC_id]->ofdm_symbol_size; re++) + PHY_vars_eNB_g[0][CC_id]->common_vars.beam_weights[0][0][j][re] = 0x00007fff/frame_parms[CC_id]->nb_antennas_tx; + } + + if (phy_test==1) PHY_vars_eNB_g[0][CC_id]->mac_enabled = 0; + else PHY_vars_eNB_g[0][CC_id]->mac_enabled = 1; + + if (PHY_vars_eNB_g[0][CC_id]->mac_enabled == 0) { //set default parameters for testing mode + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; + PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; + PHY_vars_eNB_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; + + PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = i; + PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(i%3); + PHY_vars_eNB_g[0][CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4; + } + } + + // for NB-IoT testing + + if (phy_test==1) PHY_vars_eNB_NB_IoT_g[0][CC_id]->mac_enabled = 0; + else PHY_vars_eNB_NB_IoT_g[0][CC_id]->mac_enabled = 1; + + if (PHY_vars_eNB_NB_IoT_g[0][CC_id]->mac_enabled == 0) { //set default parameters for testing mode + for (i=0; i<NUMBER_OF_UE_MAX; i++) { + PHY_vars_eNB_NB_IoT_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_ACK_Index = beta_ACK; + PHY_vars_eNB_NB_IoT_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_RI_Index = beta_RI; + PHY_vars_eNB_NB_IoT_g[0][CC_id]->pusch_config_dedicated[i].betaOffset_CQI_Index = beta_CQI; + + PHY_vars_eNB_NB_IoT_g[0][CC_id]->scheduling_request_config[i].sr_PUCCH_ResourceIndex = i; + PHY_vars_eNB_NB_IoT_g[0][CC_id]->scheduling_request_config[i].sr_ConfigIndex = 7+(i%3); + PHY_vars_eNB_NB_IoT_g[0][CC_id]->scheduling_request_config[i].dsr_TransMax = sr_n4; + } + } + + // No need to do for NB-IoT + compute_prach_seq(&PHY_vars_eNB_g[0][CC_id]->frame_parms.prach_config_common, + PHY_vars_eNB_g[0][CC_id]->frame_parms.frame_type, + PHY_vars_eNB_g[0][CC_id]->X_u); + + + PHY_vars_eNB_g[0][CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0]; + + if (frame_parms[CC_id]->frame_type==FDD) { + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 0; + } else { + if (frame_parms[CC_id]->N_RB_DL == 100) + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624; + else if (frame_parms[CC_id]->N_RB_DL == 50) + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/2; + else if (frame_parms[CC_id]->N_RB_DL == 25) + PHY_vars_eNB_g[0][CC_id]->N_TA_offset = 624/4; + } + + // for NB-IoT testing + + PHY_vars_eNB_NB_IoT_g[0][CC_id]->rx_total_gain_dB = (int)rx_gain[CC_id][0]; + + if (frame_parms_NB_IoT[CC_id]->frame_type==FDD) { + PHY_vars_eNB_NB_IoT_g[0][CC_id]->N_TA_offset = 0; + } else { + if (frame_parms_NB_IoT[CC_id]->N_RB_DL == 100) + PHY_vars_eNB_NB_IoT_g[0][CC_id]->N_TA_offset = 624; + else if (frame_parms_NB_IoT[CC_id]->N_RB_DL == 50) + PHY_vars_eNB_NB_IoT_g[0][CC_id]->N_TA_offset = 624/2; + else if (frame_parms_NB_IoT[CC_id]->N_RB_DL == 25) + PHY_vars_eNB_NB_IoT_g[0][CC_id]->N_TA_offset = 624/4; + } + + } + + + NB_eNB_INST=1; + NB_INST=1; + + } + + fill_modeled_runtime_table(runtime_phy_rx,runtime_phy_tx); + cpuf=get_cpu_freq_GHz(); + + + dump_frame_parms(frame_parms[0]); + + init_openair0(); + + + +#ifndef DEADLINE_SCHEDULER + + /* Currently we set affinity for UHD to CPU 0 for eNB/UE and only if number of CPUS >2 */ + + cpu_set_t cpuset; + int s; + char cpu_affinity[1024]; + CPU_ZERO(&cpuset); +#ifdef CPU_AFFINITY + if (get_nprocs() > 2) { + CPU_SET(0, &cpuset); + s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_setaffinity_np"); + exit_fun("Error setting processor affinity"); + } + LOG_I(HW, "Setting the affinity of main function to CPU 0, for device library to use CPU 0 only!\n"); + } +#endif + + /* Check the actual affinity mask assigned to the thread */ + s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) { + perror( "pthread_getaffinity_np"); + exit_fun("Error getting processor affinity "); + } + memset(cpu_affinity, 0 , sizeof(cpu_affinity)); + for (int j = 0; j < CPU_SETSIZE; j++) { + if (CPU_ISSET(j, &cpuset)) { + char temp[1024]; + sprintf(temp, " CPU_%d ", j); + strcat(cpu_affinity, temp); + } + } + LOG_I(HW, "CPU Affinity of main() function is... %s\n", cpu_affinity); +#endif + + openair0_cfg[0].log_level = glog_level; + + + + + int eMBMS_active=0; + if (node_function[0] <= NGFI_RAU_IF4p5) { // don't initialize L2 for RRU + + // MP, Nick: Initialization of IF module for NB-IoT should be here + + // if_inst = malloc(sizeof(IF_Module_t)); + // LOG_I(PHY,"Allocate IF-Module for NB-IoT\n"); + + + //--------------------------- + + LOG_I(PHY,"Intializing L2\n"); + + mac_xface = malloc(sizeof(MAC_xface)); + l2_init(frame_parms[0],eMBMS_active,(uecap_xer_in==1)?uecap_xer:NULL, + 0,// cba_group_active + 0); // HO flag + +//initialize L2 for NB-IoT stuff (complementary to legacy OAI initialization) + + l2_init_eNB_NB_IoT(); + + + mac_xface->macphy_exit = &exit_fun; + } else if (node_function[0] == NGFI_RRU_IF4p5) { // Initialize PRACH in this case + + } + + + +#if defined(ENABLE_ITTI) + + if ((UE_flag == 1)|| + ((node_function[0]<NGFI_RAU_IF4p5)&&(phy_test==0))) + // don't create if node doesn't connect to RRC/S1/GTP + if (create_tasks(UE_flag ? 0 : 1, UE_flag ? 1 : 0) < 0) { + printf("cannot create ITTI tasks\n"); + exit(-1); // need a softer mode + } + + printf("ITTI tasks created\n"); +#endif + + if (phy_test==0) { + if (UE_flag==1) { + printf("Filling UE band info\n"); + fill_ue_band_info(); + mac_xface->dl_phy_sync_success (0, 0, 0, 1); + } else if (node_function[0]>NGFI_RRU_IF4p5) + mac_xface->mrbch_phy_sync_failure (0, 0, 0); + } + + + + mlockall(MCL_CURRENT | MCL_FUTURE); + + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); + +#ifdef XFORMS + int UE_id; + + if (do_forms==1) { + fl_initialize (&argc, argv, NULL, 0, 0); + + if (UE_flag==0) { + form_stats_l2 = create_form_stats_form(); + fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats"); + form_stats = create_form_stats_form(); + fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); + + for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + form_enb[CC_id][UE_id] = create_lte_phy_scope_enb(); + sprintf (title, "LTE UL SCOPE eNB for CC_id %d, UE %d",CC_id,UE_id); + fl_show_form (form_enb[CC_id][UE_id]->lte_phy_scope_enb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); + + if (otg_enabled) { + fl_set_button(form_enb[CC_id][UE_id]->button_0,1); + fl_set_object_label(form_enb[CC_id][UE_id]->button_0,"DL Traffic ON"); + } else { + fl_set_button(form_enb[CC_id][UE_id]->button_0,0); + fl_set_object_label(form_enb[CC_id][UE_id]->button_0,"DL Traffic OFF"); + } + } // CC_id + } // UE_id + } else { + form_stats = create_form_stats_form(); + fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); + UE_id = 0; + form_ue[UE_id] = create_lte_phy_scope_ue(); + sprintf (title, "LTE DL SCOPE UE"); + fl_show_form (form_ue[UE_id]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); + + /* + if (openair_daq_vars.use_ia_receiver) { + fl_set_button(form_ue[UE_id]->button_0,1); + fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver ON"); + } else { + fl_set_button(form_ue[UE_id]->button_0,0); + fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); + }*/ + fl_set_button(form_ue[UE_id]->button_0,0); + fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); + } + + ret = pthread_create(&forms_thread, NULL, scope_thread, NULL); + + if (ret == 0) + pthread_setname_np( forms_thread, "xforms" ); + + printf("Scope thread created, ret=%d\n",ret); + } + +#endif + + rt_sleep_ns(10*100000000ULL); + + + + // start the main thread + if (UE_flag == 1) { + init_UE(1); + number_of_cards = 1; + + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + PHY_vars_UE_g[0][CC_id]->rf_map.card=0; + PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+chain_offset; + } + } else { + +#ifdef NB_IOT + //printf("Initializing IF Module in PHY layer\n"); + //register function + //IF_Module_init_L1(); +#endif + + printf("Initializing eNB threads\n"); + init_eNB(node_function,node_timing,1,eth_params,single_thread_flag,wait_for_sync); + + number_of_cards = 1; + + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + PHY_vars_eNB_g[0][CC_id]->rf_map.card=0; + PHY_vars_eNB_g[0][CC_id]->rf_map.chain=CC_id+chain_offset; + } + } + + // connect the TX/RX buffers + if (UE_flag==1) { + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + + +#ifdef OAI_USRP + UE[CC_id]->hw_timing_advance = timing_advance; +#else + UE[CC_id]->hw_timing_advance = 160; +#endif + } + if (setup_ue_buffers(UE,&openair0_cfg[0])!=0) { + printf("Error setting up eNB buffer\n"); + exit(-1); + } + + + + if (input_fd) { + printf("Reading in from file to antenna buffer %d\n",0); + if (fread(UE[0]->common_vars.rxdata[0], + sizeof(int32_t), + frame_parms[0]->samples_per_tti*10, + input_fd) != frame_parms[0]->samples_per_tti*10) + printf("error reading from file\n"); + } + //p_exmimo_config->framing.tdd_config = TXRXSWITCH_TESTRX; + } else { + + + + + + printf("Setting eNB buffer to all-RX\n"); + + // Set LSBs for antenna switch (ExpressMIMO) + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + PHY_vars_eNB_g[0][CC_id]->hw_timing_advance = 0; + for (i=0; i<frame_parms[CC_id]->samples_per_tti*10; i++) + for (aa=0; aa<frame_parms[CC_id]->nb_antennas_tx; aa++) + PHY_vars_eNB_g[0][CC_id]->common_vars.txdata[0][aa][i] = 0x00010001; + } + } + sleep(3); + + + printf("Sending sync to all threads\n"); + + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + + // wait for end of program + printf("TYPE <CTRL-C> TO TERMINATE\n"); + //getchar(); + +#if defined(ENABLE_ITTI) + printf("Entering ITTI signals handler\n"); + itti_wait_tasks_end(); + oai_exit=1; +#else + + while (oai_exit==0) + rt_sleep_ns(100000000ULL); + +#endif + + // stop threads +#ifdef XFORMS + printf("waiting for XFORMS thread\n"); + + if (do_forms==1) { + pthread_join(forms_thread,&status); + fl_hide_form(form_stats->stats_form); + fl_free_form(form_stats->stats_form); + + if (UE_flag==1) { + fl_hide_form(form_ue[0]->lte_phy_scope_ue); + fl_free_form(form_ue[0]->lte_phy_scope_ue); + } else { + fl_hide_form(form_stats_l2->stats_form); + fl_free_form(form_stats_l2->stats_form); + + for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + fl_hide_form(form_enb[CC_id][UE_id]->lte_phy_scope_enb); + fl_free_form(form_enb[CC_id][UE_id]->lte_phy_scope_enb); + } + } + } + } + +#endif + + printf("stopping MODEM threads\n"); + + // cleanup + if (UE_flag == 1) { + } else { + stop_eNB(1); + } + + + pthread_cond_destroy(&sync_cond); + pthread_mutex_destroy(&sync_mutex); + + + // *** Handle per CC_id openair0 + if (UE_flag==1) { + if (PHY_vars_UE_g[0][0]->rfdevice.trx_end_func) + PHY_vars_UE_g[0][0]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][0]->rfdevice); + } else { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + if (PHY_vars_eNB_g[0][CC_id]->rfdevice.trx_end_func) + PHY_vars_eNB_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_eNB_g[0][CC_id]->rfdevice); + if (PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_end_func) + PHY_vars_eNB_g[0][CC_id]->ifdevice.trx_end_func(&PHY_vars_eNB_g[0][CC_id]->ifdevice); + } + } + if (ouput_vcd) + VCD_SIGNAL_DUMPER_CLOSE(); + + if (opt_enabled == 1) + terminate_opt(); + + logClean(); + + return 0; +}